GTK+ app development: avahi service browsing and Gtk+ main loop problem

Andrei Macavei <[email protected]> Tue, 17 Jun 2014 10:51:21 +0300
Newsgroups gmane.comp.gnome.lib.gtk+.devel.apps,gmane.comp.gnome.love
Message-ID <[email protected]>
Hi,

I am resending the code examples in plain text as the first message 
contained some html part which made the code un-copy-paste-able.

The problem description can be summarized as : when using gtk's main 
loop ( Gtk.main() ) how to deal with gobject.MainLoop.().run() which is 
used by avahi client.

There are 3 classes involved:

- ServicePublisher : this class publishes the service on network using avahi
- ServiceDiscover : this discovers other services of the same type using 
avahi
- MainWindow : the main window class for the GTK+ 3 applicaiton

Below I posted the code which gives the following error: "RuntimeError: 
To make asynchronous calls, receive signals or export objects, D-Bus 
connections must be attached to a main loop by passing mainloop=... to 
the constructor or calling dbus.set_default_main_loop(...)"


**** MainWindow.py ****
from gi.repository import Gtk
from AvahiPublisher import ServicePublisher
from AvahiDiscover import ServiceDiscover

class MainWindow(Gtk.Window):

     def __init__(self):
         Gtk.Window.__init__(self, title="Geysigning")
         self.set_border_width(10)

         # create notebook container
         notebook = Gtk.Notebook()
         self.add(notebook)

         # setup signals
         self.connect("delete-event", Gtk.main_quit)

         # setup avahi publisher
         service_publisher = ServicePublisher(name="GeysignService", 
port=9999)
         service_publisher.publish()

         # setup avahi discover
         service_discover = ServiceDiscover(stype='_http._tcp')
         service_discover.discover()

if __name__ == "__main__":
     window = MainWindow()
     window.show_all()
     Gtk.main()


**** AvahiDiscover.py ****
import avahi
import dbus
import gobject
from dbus.mainloop.glib import DBusGMainLoop

class ServiceDiscover:

     def __init__(self, stype='_http._tcp'):
         self.domain = ""
         self.stype = stype

     def discover(self):

         loop = DBusGMainLoop()

         self.bus = dbus.SystemBus(mainloop=loop)
         self.server = dbus.Interface( 
self.bus.get_object(avahi.DBUS_NAME, '/'), 'org.freedesktop.Avahi.Server')

         self.sbrowser = 
dbus.Interface(self.bus.get_object(avahi.DBUS_NAME, 
self.server.ServiceBrowserNew(avahi.IF_UNSPEC, avahi.PROTO_UNSPEC, 
self.stype, 'local', dbus.UInt32(0))), avahi.DBUS_INTERFACE_SERVICE_BROWSER)

         gobject.MainLoop().run()


**** AvahiPublisher.py ****
import avahi
import dbus
import gobject
from dbus.mainloop.glib import DBusGMainLoop

class ServicePublisher:

     def __init__(self, name, port, stype="_http._tcp",
                  domain="", host="", text=""):
         self.name = name
         self.stype = stype
         self.domain = domain
         self.host = host
         self.port = port
         self.text = text

     def publish(self):
         bus = dbus.SystemBus()
         server = dbus.Interface(bus.get_object(
                                     avahi.DBUS_NAME,
                                     avahi.DBUS_PATH_SERVER),
                                 avahi.DBUS_INTERFACE_SERVER)

         group = dbus.Interface(
                     bus.get_object(avahi.DBUS_NAME,
                                    server.EntryGroupNew()),
                     avahi.DBUS_INTERFACE_ENTRY_GROUP)

         group.AddService(avahi.IF_UNSPEC, 
avahi.PROTO_UNSPEC,dbus.UInt32(0),
                      self.name, self.stype, self.domain, self.host,
                      dbus.UInt16(self.port), self.text)

         group.Commit()
         self.group = group