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 """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_ACTIVATION]
58 def __init__(self, bus_type=TYPE_SESSION, glib_mainloop=True):
59 self._connection = dbus_bindings.bus_get(bus_type)
61 self._connection.add_filter(self._signal_func)
62 self._match_rule_to_receivers = { }
64 self._connection.setup_with_g_main()
66 def get_service(self, service_name="org.freedesktop.Broadcast"):
67 """Get one of the RemoteServices connected to this Bus. service_name
68 is just a string of the form 'com.widgetcorp.MyService'
70 return RemoteService(self._connection, service_name)
72 def add_signal_receiver(self, receiver, interface=None, service=None, path=None):
73 match_rule = self._get_match_rule(interface, service, path)
75 if (not self._match_rule_to_receivers.has_key(match_rule)):
76 self._match_rule_to_receivers[match_rule] = [ ]
77 self._match_rule_to_receivers[match_rule].append(receiver)
79 dbus_bindings.bus_add_match(self._connection, match_rule)
81 def remove_signal_receiver(self, receiver, interface=None, service=None, path=None):
82 match_rule = self._get_match_rule(interface, service, path)
84 if self._match_rule_to_receivers.has_key(match_rule):
85 if self._match_rule_to_receivers[match_rule].__contains__(receiver):
86 self._match_rule_to_receivers[match_rule].remove(receiver)
87 dbus_bindings.bus_remove_match(self._connection, match_rule)
89 def get_connection(self):
90 """Get the dbus_bindings.Connection object associated with this Bus"""
91 return self._connection
93 def _get_match_rule(self, interface, service, path):
95 ## match_rule = match_rule + ",interface='%s'" % (interface)
97 ## match_rule = match_rule + ",service='%s'" % (service)
99 ## match_rule = match_rule + ",path='%s'" % (path)
100 # FIXME: use the service here too!!!
101 return "type='signal',interface='%s',path='%s'" % (interface, path)
103 def _signal_func(self, connection, message):
104 if (message.get_type() != dbus_bindings.MESSAGE_TYPE_SIGNAL):
105 return dbus_bindings.HANDLER_RESULT_NOT_YET_HANDLED
107 interface = message.get_interface()
108 service = message.get_sender()
109 path = message.get_path()
110 member = message.get_member()
112 match_rule = self._get_match_rule(interface, service, path)
114 if (self._match_rule_to_receivers.has_key(match_rule)):
115 receivers = self._match_rule_to_receivers[match_rule]
116 args = [interface, member, service, path, message]
117 for receiver in receivers:
120 class SystemBus(Bus):
121 """The system-wide message bus
124 Bus.__init__(self, Bus.TYPE_SYSTEM)
126 class SessionBus(Bus):
127 """The session (current login) message bus
130 Bus.__init__(self, Bus.TYPE_SESSION)
132 class ActivationBus(Bus):
133 """The bus that activated this process (if
134 this process was launched by DBus activation)
137 Bus.__init__(self, Bus.TYPE_ACTIVATION)
143 A RemoteObject is provided by a RemoteService on a particular Bus. RemoteObjects
144 have member functions, and can be called like normal Python objects.
146 def __init__(self, connection, service_name, object_path, interface):
147 self._connection = connection
148 self._service_name = service_name
149 self._object_path = object_path
150 self._interface = interface
152 def __getattr__(self, member):
153 if member == '__call__':
154 return object.__call__
156 return RemoteMethod(self._connection, self._service_name,
157 self._object_path, self._interface, member)
163 Typically a member of a RemoteObject. Calls to the
164 method produce messages that travel over the Bus and are routed
165 to a specific Service.
167 def __init__(self, connection, service_name, object_path, interface, method_name):
168 self._connection = connection
169 self._service_name = service_name
170 self._object_path = object_path
171 self._interface = interface
172 self._method_name = method_name
174 def __call__(self, *args):
175 message = dbus_bindings.MethodCall(self._object_path, self._interface, self._method_name)
176 message.set_destination(self._service_name)
178 # Add the arguments to the function
179 iter = message.get_iter()
183 reply_message = self._connection.send_with_reply_and_block(message, 5000)
185 args_tuple = reply_message.get_args_list()
186 if len(args_tuple) == 0:
188 elif len(args_tuple) == 1:
194 """A base class for exporting your own Services across the Bus
196 Just inherit from Service, providing the name of your service
197 (e.g. org.designfu.SampleService).
199 def __init__(self, service_name, bus=None):
200 self._service_name = service_name
203 # Get the default bus
208 dbus_bindings.bus_acquire_service(self._bus.get_connection(), service_name)
211 """Get the Bus this Service is on"""
214 def get_service_name(self):
215 """Get the name of this service"""
216 return self._service_name
218 def _dispatch_dbus_method_call(target_method, argument_list, message):
219 """Calls method_to_call using argument_list, but handles
220 exceptions, etc, and generates a reply to the DBus Message message
223 retval = target_method(*argument_list)
225 if e.__module__ == '__main__':
226 # FIXME: is it right to use .__name__ here?
227 error_name = e.__class__.__name__
229 error_name = e.__module__ + '.' + str(e.__class__.__name__)
230 error_contents = str(e)
231 reply = dbus_bindings.Error(message, error_name, error_contents)
233 reply = dbus_bindings.MethodReturn(message)
235 iter = reply.get_iter()
240 def _build_method_dictionary(methods):
242 for method in methods:
243 if method_dict.has_key(method.__name__):
244 print ('WARNING: registering DBus Object methods, already have a method named %s' % (method.__name__))
245 method_dict[method.__name__] = method
249 """A base class for exporting your own Objects across the Bus.
251 Just inherit from Object and provide a list of methods to share
252 across the Bus. These will appear as member functions of your
255 def __init__(self, object_path, service, dbus_methods=[]):
256 # Reversed constructor argument order. Add a temporary
257 # check to help people get things straightened out with minimal pain.
258 if type(service) == list:
259 raise TypeError, "dbus.Object.__init__(): the order of the 'service' and 'dbus_methods' arguments has been reversed (for consistency with dbus.ObjectTree)."
261 self._object_path = object_path
262 self._service = service
263 self._bus = service.get_bus()
264 self._connection = self._bus.get_connection()
266 self._method_name_to_method = _build_method_dictionary(dbus_methods)
268 self._connection.register_object_path(object_path, self._unregister_cb, self._message_cb)
270 def broadcast_signal(self, interface, signal_name):
271 message = dbus_bindings.Signal(self._object_path, interface, signal_name)
272 #FIXME: need to set_sender, but it always disconnects when we do this
273 #message.set_sender(self._service.get_service_name())
274 self._connection.send(message)
276 def _unregister_cb(self, connection):
279 def _message_cb(self, connection, message):
280 target_method_name = message.get_member()
281 target_method = self._method_name_to_method[target_method_name]
282 args = message.get_args_list()
284 reply = _dispatch_dbus_method_call(target_method, args, message)
286 self._connection.send(reply)
291 """An object tree allows you to register a handler for a tree of object paths.
292 This means that literal Python objects do not need to be created for each object
293 over the bus, but you can have a virtual tree of objects handled by a single
294 Python object. There are two ways to handle method calls on virtual objects:
296 1) Pass a list of dbus_methods in to __init__. This works just like dbus.Object,
297 except an object_path is passed as the first argument to each method, denoting which
298 virtual object the call was made on. If all the objects in the tree support the same
299 methods, this is the best approach.
301 2) Override object_method_called. This allows you to define the valid methods dynamically
302 on an object by object basis. For example, if providing an object tree that represented
303 a filesystem heirarchy, you'd only want an ls method on directory objects, not file objects.
306 def __init__(self, base_path, service, dbus_methods=[]):
307 self._base_path = base_path
308 self._service = service
309 self._bus = service.get_bus()
310 self._connection = self._bus.get_connection()
312 self._method_name_to_method = _build_method_dictionary(dbus_methods)
314 self._connection.register_fallback(base_path, self._unregister_cb, self._message_cb)
316 def object_method_called(self, object_path, method_name, argument_list):
317 """Override this method. Called with, object_path, the relative path of the object
318 under the base_path, the name of the method invoked, and a list of arguments
320 raise NotImplementedException, "object_method_called() must be overriden"
322 def _unregister_cb(self, connection):
325 def _message_cb(self, connection, message):
326 target_object_full_path = message.get_path()
327 assert(self._base_path == target_object_full_path[:len(self._base_path)])
328 target_object_path = target_object_full_path[len(self._base_path):]
329 target_method_name = message.get_member()
330 message_args = message.get_args_list()
333 target_method = self._method_name_to_method[target_method_name]
334 args = [target_object_path] + message_args
336 target_method = self.object_method_called
337 args = [target_object_path, target_method_name, message_args]
339 reply = _dispatch_dbus_method_call(target_method, args, message)
341 self._connection.send(reply)
344 """A remote service providing objects.
346 A service is typically a process or application that provides
347 remote objects, but can also be the broadcast service that
348 receives signals from all applications on the Bus.
351 def __init__(self, connection, service_name):
352 self._connection = connection
353 self._service_name = service_name
355 def get_object(self, object_path, interface):
356 """Get an object provided by this Service that implements a
357 particular interface. object_path is a string of the form
358 '/com/widgetcorp/MyService/MyObject1'. interface looks a lot
359 like a service_name (they're often the same) and is of the form,
360 'com.widgetcorp.MyInterface', and mostly just defines the
361 set of member functions that will be present in the object.
363 return RemoteObject(self._connection, self._service_name, object_path, interface)