Ecore DBus Mainloop integration

How to use the main loop

Python-EFL provide the necessary main loop integration to let python-dbus use the Ecore main loop to perform async stuff. The only function you need to use from the efl is: DBusEcoreMainLoop()

The function returns a NativeMainLoop to attach the Ecore main loop to D-Bus from within Python. In practice you just need to pass the NativeMainLoop as the ‘mainloop’ param when you connect to a bus.

This is how you connect to a dbus bus:

import dbus
from efl import ecore
from efl.dbus_mainloop import DBusEcoreMainLoop

# connect to the session bus
bus = dbus.SessionBus(mainloop=DBusEcoreMainLoop())
# or to the system bus
bus = dbus.SystemBus(mainloop=DBusEcoreMainLoop())

Once you have your bus connected you can just normally use all the python-dbus functionality. This is the reason why you will not find any docs about dbus here (except for some basic examples).

It’s therefore highly suggested to read the official python-dbus tutorial and to use the python-dbus reference, you will find all the links in the bottom of the page.

Proxy objects

In the dbus world to interact with an object you need to know:

  • the name of the service, ex: org.enlightenment.FileManager
  • the path to the object you are intrested, ex: /org/enlightenment/FileManager
  • the interface to interact with, ex: org.enlightenment.FileManager
obj = bus.get_object(named_service, object_path)
iface = dbus.Interface(obj, iface_name)

then, on the iface object, you can call methods, connect to signals and access properties.

Calling methods

There are at least two way to call methods on a remote object, the first example show how to do it the simple way, while the second show a much more complex but much powerfull async way. Note: using the sync way can make your app lag or halt forever if the remote keep too much time to respond.

Both the examples use the OpenDirectory(s) method of the Enlightenment file manager to open a new window in the /tmp directory.

# synchronous call

obj = bus.get_object('org.enlightenment.FileManager',
                     '/org/enlightenment/FileManager')
iface = dbus.Interface(obj, 'org.enlightenment.FileManager')
# directly
iface.OpenDirectory('/tmp')
# or using a method object
meth = iface.get_dbus_method('OpenDirectory')
meth('/tmp')
# asynchronous call

def reply_handler(*params):
   print("Method return: " + str(params))

def error_handler(*params):
    print("Method error")


obj = bus.get_object('org.enlightenment.FileManager',
                     '/org/enlightenment/FileManager')
iface = dbus.Interface(obj, 'org.enlightenment.FileManager')
iface.OpenDirectory('/tmp',
                    reply_handler=reply_handler,
                    error_handler=error_handler)

ecore.main_loop_begin()

Accessing properties

To access properties you need to use the standard org.freedesktop.DBus.Properties interface that all the objects provide. Methods on this iterface are:

  • Get(s interface, s propname) → (v value)
  • GetAll(s interface) → (a{sv} props)
  • Set(s interface, s propname, v value)

The example show how to get the value of the DaemonVersion prop of UDisks

bus = dbus.SystemBus(mainloop=DBusEcoreMainLoop())
obj = bus.get_object('org.freedesktop.UDisks',
                     '/org/freedesktop/UDisks')
props_iface = dbus.Interface(obj, 'org.freedesktop.DBus.Properties')
value = props_iface.Get('org.freedesktop.UDisks', 'DaemonVersion')

Connecting signals

#!/usr/bin/env python

import dbus
from efl import dbus_mainloop
from efl import ecore


def print_name_owner_changed(obj, old, new):
    print("Obj = '%s', Old = '%s', New = '%s'" % (obj, old, new))


dbus_ml = dbus_mainloop.DBusEcoreMainLoop()
bus = dbus.SystemBus(mainloop=dbus_ml)

bus.add_signal_receiver(print_name_owner_changed, "NameOwnerChanged")
ecore.main_loop_begin()

Introspection

To get information for a given proxy object you need to use the Introspect() method on the org.freedesktop.DBus.Introspectable interface. The introspection will return an XML string that describe all the interfaces available on the object, with all the methods, properties and signals info.

bus = dbus.SessionBus(mainloop=DBusEcoreMainLoop())
obj = bus.get_object('org.enlightenment.FileManager',
                     '/org/enlightenment/FileManager')
iface = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
xml_string = iface.Introspect()

This other example show how to do recursive introspection on a given service, starting from the root object path /

import dbus
import xml.etree.ElementTree as ElementTree
from efl import ecore
from efl.dbus_mainloop import DBusEcoreMainLoop

def recursive_introspect(bus, named_service, object_path):
    print('Introspecting obj "%s" on service "%s"' % \
          (object_path, named_service))

    # introspect
    obj = bus.get_object(named_service, object_path)
    iface = dbus.Interface(obj, 'org.freedesktop.DBus.Introspectable')
    xml_string = iface.Introspect()

    # parse
    for xml_node in ElementTree.fromstring(xml_string):
        # found an interface
        if xml_node.tag == 'interface':
            print('  Found interface: ' + xml_node.attrib['name'])

            for child in xml_node:
                if child.tag == 'property':
                    print('    Found property: ' + child.attrib['name'])

                if child.tag == 'method':
                    print('    Found method: ' + child.attrib['name'])

                if child.tag == 'signal':
                    print('    Found signal: ' + child.attrib['name'])

        # found another node, introspect it...
        if xml_node.tag == 'node':
            if object_path == '/':
                object_path = ''
            new_path = '/'.join((object_path, xml_node.attrib['name']))
            recursive_introspect(bus, named_service, new_path)

bus = dbus.SystemBus(mainloop=DBusEcoreMainLoop())
recursive_introspect(bus, 'org.freedesktop.UDisks', '/')