2 """Module for high-level communication over the FreeDesktop.org Bus (DBus)
4 DBus allows you to share and access remote objects between processes
5 running on the desktop, and also to access system services (such as
8 To use DBus, first get a Bus object, which provides a connection to one
9 of a few standard dbus-daemon instances that might be running. From the
10 Bus you can get a RemoteService. A service is provided by an application or
11 process connected to the Bus, and represents a set of objects. Once you
12 have a RemoteService you can get a RemoteObject that implements a specific interface
13 (an interface is just a standard group of member functions). Then you can call
14 those member functions directly.
16 You can think of a complete method call as looking something like:
18 Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
20 This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
21 Forward method of the /org/gnome/Evolution/Inbox object (which provides the
22 org.gnome.Evolution.MailFolder interface) with two string arguments.
24 For example, the dbus-daemon itself provides a service and some objects:
26 # Get a connection to the desktop-wide SESSION bus
27 bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
29 # Get the service provided by the dbus-daemon named org.freedesktop.DBus
30 dbus_service = bus.get_service('org.freedesktop.DBus')
32 # Get a reference to the desktop bus' standard object, denoted
33 # by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
34 # implements the 'org.freedesktop.DBus' interface
35 dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
36 'org.freedesktop.DBus')
38 # One of the member functions in the org.freedesktop.DBus interface
39 # is ListServices(), which provides a list of all the other services
40 # registered on this bus. Call it, and print the list.
41 print(dbus_object.ListServices())
47 """A connection to a DBus daemon.
49 One of three possible standard buses, the SESSION, SYSTEM,
52 TYPE_SESSION = dbus_bindings.BUS_SESSION
53 TYPE_SYSTEM = dbus_bindings.BUS_SYSTEM
54 TYPE_ACTIVATION = dbus_bindings.BUS_ACTIVATION
56 def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True):
57 self._connection = dbus_bindings.bus_get(bus_type)
59 self._connection.add_filter(self._signal_func)
60 self._match_rule_to_receivers = { }
62 self._connection.setup_with_g_main()
64 def get_service(self, service_name="org.freedesktop.Broadcast"):
65 """Get one of the RemoteServices connected to this Bus. service_name
66 is just a string of the form 'com.widgetcorp.MyService'
68 return RemoteService(self._connection, service_name)
70 def add_signal_receiver(self, receiver, interface=None, service=None, path=None):
71 match_rule = self._get_match_rule(interface, service, path)
73 if (not self._match_rule_to_receivers.has_key(match_rule)):
74 self._match_rule_to_receivers[match_rule] = [ ]
75 self._match_rule_to_receivers[match_rule].append(receiver)
77 dbus_bindings.bus_add_match(self._connection, match_rule)
79 def remove_signal_receiver(self, receiver, interface=None, service=None, path=None):
80 match_rule = self._get_match_rule(interface, service, path)
82 if self._match_rule_to_receivers.has_key(match_rule):
83 if self._match_rule_to_receivers[match_rule].__contains__(receiver):
84 self._match_rule_to_receivers[match_rule].remove(receiver)
85 dbus_bindings.bus_remove_match(self._connection, match_rule)
87 def get_connection(self):
88 """Get the dbus_bindings.Connection object associated with this Bus"""
89 return self._connection
91 def _get_match_rule(self, interface, service, path):
93 ## match_rule = match_rule + ",interface='%s'" % (interface)
95 ## match_rule = match_rule + ",service='%s'" % (service)
97 ## match_rule = match_rule + ",path='%s'" % (path)
98 # FIXME: use the service here too!!!
99 return "type='signal',interface='%s',path='%s'" % (interface, path)
101 def _signal_func(self, connection, message):
102 if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL):
105 interface = message.get_interface()
106 service = message.get_sender()
107 path = message.get_path()
108 member = message.get_member()
110 match_rule = self._get_match_rule(interface, service, path)
112 if (self._match_rule_to_receivers.has_key(match_rule)):
113 receivers = self._match_rule_to_receivers[match_rule]
114 args = [interface, member, service, path, message]
115 for receiver in receivers:
122 A RemoteObject is provided by a RemoteService on a particular Bus. RemoteObjects
123 have member functions, and can be called like normal Python objects.
125 def __init__(self, connection, service_name, object_path, interface):
126 self._connection = connection
127 self._service_name = service_name
128 self._object_path = object_path
129 self._interface = interface
131 def __getattr__(self, member):
132 if member == '__call__':
133 return object.__call__
135 return RemoteMethod(self._connection, self._service_name,
136 self._object_path, self._interface, member)
142 Typically a member of a RemoteObject. Calls to the
143 method produce messages that travel over the Bus and are routed
144 to a specific Service.
146 def __init__(self, connection, service_name, object_path, interface, method_name):
147 self._connection = connection
148 self._service_name = service_name
149 self._object_path = object_path
150 self._interface = interface
151 self._method_name = method_name
153 def __call__(self, *args):
154 message = dbus_bindings.MethodCall(self._object_path, self._interface, self._method_name)
155 message.set_destination(self._service_name)
157 # Add the arguments to the function
158 iter = message.get_iter()
162 reply_message = self._connection.send_with_reply_and_block(message, 5000)
164 args_tuple = reply_message.get_args_list()
165 if len(args_tuple) == 0:
167 elif len(args_tuple) == 1:
173 """A base class for exporting your own Services across the Bus
175 Just inherit from Service, providing the name of your service
176 (e.g. org.designfu.SampleService).
178 def __init__(self, service_name, bus=None):
179 self._service_name = service_name
182 # Get the default bus
187 dbus_bindings.bus_acquire_service(self._bus.get_connection(), service_name)
190 """Get the Bus this Service is on"""
193 def get_service_name(self):
194 """Get the name of this service"""
195 return self._service_name
198 """A base class for exporting your own Objects across the Bus.
200 Just inherit from Object and provide a list of methods to share
201 across the Bus. These will appear as member functions of your
204 def __init__(self, object_path, methods_to_share, service):
205 self._object_path = object_path
206 self._service = service
207 self._bus = service.get_bus()
208 self._connection = self._bus.get_connection()
210 self._method_name_to_method = self._build_method_dictionary(methods_to_share)
212 self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb)
214 def broadcast_signal(self, interface, signal_name):
215 message = dbus_bindings.Signal(self._object_path, interface, signal_name)
216 #FIXME: need to set_sender, but it always disconnects when we do this
217 #message.set_sender(self._service.get_service_name())
218 self._connection.send(message)
220 def _unregister_cb(self, connection):
223 def _message_cb(self, connection, message):
224 target_method_name = message.get_member()
225 target_method = self._method_name_to_method[target_method_name]
226 args = message.get_args_list()
229 retval = target_method(*args)
231 if e.__module__ == '__main__':
232 # FIXME: is it right to use .__name__ here?
233 error_name = e.__class__.__name__
235 error_name = e.__module__ + '.' + str(e.__class__.__name__)
236 error_contents = str(e)
237 reply = dbus_bindings.Error(message, error_name, error_contents)
239 reply = dbus_bindings.MethodReturn(message)
241 iter = reply.get_iter()
244 self._connection.send(reply)
246 def _build_method_dictionary(self, methods):
248 for method in methods:
249 if method_dict.has_key(method.__name__):
250 print ('WARNING: registering DBus Object methods, already have a method named %s' % (method.__name__))
251 method_dict[method.__name__] = method
255 """A remote service providing objects.
257 A service is typically a process or application that provides
258 remote objects, but can also be the broadcast service that
259 receives signals from all applications on the Bus.
262 def __init__(self, connection, service_name):
263 self._connection = connection
264 self._service_name = service_name
266 def get_object(self, object_path, interface):
267 """Get an object provided by this Service that implements a
268 particular interface. object_path is a string of the form
269 '/com/widgetcorp/MyService/MyObject1'. interface looks a lot
270 like a service_name (they're often the same) and is of the form,
271 'com.widgetcorp.MyInterface', and mostly just defines the
272 set of member functions that will be present in the object.
274 return RemoteObject(self._connection, self._service_name, object_path, interface)