1 """Module for high-level communication over the FreeDesktop.org Bus (DBus)
3 DBus allows you to share and access remote objects between processes
4 running on the desktop, and also to access system services (such as
7 To use DBus, first get a Bus object, which provides a connection to one
8 of a few standard dbus-daemon instances that might be running. From the
9 Bus you can get a RemoteService. A service is provided by an application or
10 process connected to the Bus, and represents a set of objects. Once you
11 have a RemoteService you can get a RemoteObject that implements a specific interface
12 (an interface is just a standard group of member functions). Then you can call
13 those member functions directly.
15 You can think of a complete method call as looking something like::
17 Bus:SESSION -> Service:org.gnome.Evolution -> Object:/org/gnome/Evolution/Inbox -> Interface: org.gnome.Evolution.MailFolder -> Method: Forward('message1', 'seth@gnome.org')
19 This communicates over the SESSION Bus to the org.gnome.Evolution process to call the
20 Forward method of the /org/gnome/Evolution/Inbox object (which provides the
21 org.gnome.Evolution.MailFolder interface) with two string arguments.
23 For example, the dbus-daemon itself provides a service and some objects::
25 # Get a connection to the desktop-wide SESSION bus
26 bus = dbus.Bus(dbus.Bus.TYPE_SESSION)
28 # Get the service provided by the dbus-daemon named org.freedesktop.DBus
29 dbus_service = bus.get_service('org.freedesktop.DBus')
31 # Get a reference to the desktop bus' standard object, denoted
32 # by the path /org/freedesktop/DBus. The object /org/freedesktop/DBus
33 # implements the 'org.freedesktop.DBus' interface
34 dbus_object = dbus_service.get_object('/org/freedesktop/DBus',
35 'org.freedesktop.DBus')
37 # One of the member functions in the org.freedesktop.DBus interface
38 # is ListServices(), which provides a list of all the other services
39 # registered on this bus. Call it, and print the list.
40 print(dbus_object.ListServices())
43 __all__
= ('Bus', 'SystemBus', 'SessionBus', 'StarterBus', 'Interface')
44 __docformat__
= 'reStructuredText'
51 from exceptions
import *
52 from matchrules
import *
55 """A connection to a DBus daemon.
57 One of three possible standard buses, the SESSION, SYSTEM,
60 TYPE_SESSION
= _dbus_bindings
.BUS_SESSION
61 TYPE_SYSTEM
= _dbus_bindings
.BUS_SYSTEM
62 TYPE_STARTER
= _dbus_bindings
.BUS_STARTER
64 """bus_type=[Bus.TYPE_SESSION | Bus.TYPE_SYSTEM | Bus.TYPE_STARTER]
67 ProxyObjectClass
= ProxyObject
69 START_REPLY_SUCCESS
= _dbus_bindings
.DBUS_START_REPLY_SUCCESS
70 START_REPLY_ALREADY_RUNNING
= _dbus_bindings
.DBUS_START_REPLY_ALREADY_RUNNING
72 _shared_instances
= weakref
.WeakValueDictionary()
74 def __new__(cls
, bus_type
=TYPE_SESSION
, use_default_mainloop
=True, private
=False):
75 """Constructor, returning an existing instance where appropriate.
77 The returned instance is actually always an instance of `SessionBus`,
78 `SystemBus` or `StarterBus`.
81 `bus_type` : cls.TYPE_SESSION, cls.TYPE_SYSTEM or cls.TYPE_STARTER
82 Connect to the appropriate bus
83 `use_default_mainloop` : bool
84 If true (default), automatically register the new connection
85 to be polled by the default main loop, if any
87 If true, never return an existing shared instance, but instead
88 return a private connection
90 if (not private
and bus_type
in cls
._shared
_instances
):
91 return cls
._shared
_instances
[bus_type
]
93 # this is a bit odd, but we create instances of the subtypes
94 # so we can return the shared instances if someone tries to
95 # construct one of them (otherwise we'd eg try and return an
96 # instance of Bus from __new__ in SessionBus). why are there
97 # three ways to construct this class? we just don't know.
98 if bus_type
== cls
.TYPE_SESSION
:
100 elif bus_type
== cls
.TYPE_SYSTEM
:
102 elif bus_type
== cls
.TYPE_STARTER
:
103 subclass
= StarterBus
105 raise ValueError('invalid bus_type %s' % bus_type
)
107 bus
= object.__new
__(subclass
)
109 bus
._bus
_type
= bus_type
110 bus
._bus
_names
= weakref
.WeakValueDictionary()
111 bus
._match
_rule
_tree
= SignalMatchTree()
113 # FIXME: if you get a starter and a system/session bus connection
114 # in the same process, it's the same underlying connection that
115 # is returned by bus_get, but we initialise it twice
116 bus
._connection
= _dbus_bindings
.bus_get(bus_type
, private
)
117 bus
._connection
.add_filter(bus
._signal
_func
)
119 if use_default_mainloop
:
120 func
= getattr(dbus
, "_dbus_mainloop_setup_function", None)
125 cls
._shared
_instances
[bus_type
] = bus
129 def __init__(self
, *args
, **keywords
):
130 # do nothing here because this can get called multiple times on the
131 # same object if __new__ returns a shared instance
135 """Close the connection."""
136 self
._connection
.close()
138 def get_connection(self
):
139 """Return the underlying `_dbus_bindings.Connection`."""
140 return self
._connection
142 def get_session(private
=False):
143 """Static method that returns a connection to the session bus.
147 If true, do not return a shared connection.
149 return SessionBus(private
=private
)
151 get_session
= staticmethod(get_session
)
153 def get_system(private
=False):
154 """Static method that returns a connection to the system bus.
158 If true, do not return a shared connection.
160 return SystemBus(private
=private
)
162 get_system
= staticmethod(get_system
)
165 def get_starter(private
=False):
166 """Static method that returns a connection to the starter bus.
170 If true, do not return a shared connection.
172 return StarterBus(private
=private
)
174 get_starter
= staticmethod(get_starter
)
177 def get_object(self
, named_service
, object_path
):
178 """Get a proxy object to call over the bus"""
179 return self
.ProxyObjectClass(self
, named_service
, object_path
)
181 def _create_args_dict(self
, keywords
):
183 for (key
, value
) in keywords
.iteritems():
184 if key
.startswith('arg'):
192 args_dict
[num
] = value
194 raise TypeError("Invalid arg index %s"%snum
)
195 elif key
in ("sender_keyword", "path_keyword"):
198 raise TypeError("Unknown keyword %s"%(key))
202 def add_signal_receiver(self
, handler_function
,
208 """Arrange for the given function to be called when a signal matching
209 the parameters is emitted.
212 `handler_function` : callable
213 The function to be called.
215 The signal name; None (the default) matches all names
216 `dbus_interface` : str
217 The D-Bus interface name with which to qualify the signal;
218 None (the default) matches all interface names
219 `named_service` : str
220 A bus name for the sender, which will be resolved to a
221 unique name if it is not already; None (the default) matches
224 The object path of the object which must have emitted the
225 signal; None (the default) matches any object path
226 `sender_keyword` : str
227 If not None (the default), the handler function will receive
228 the unique name of the sending endpoint as a keyword
229 argument with this name
231 If not None (the default), the handler function will receive
232 the object-path of the sending object as a keyword argument
235 If there are additional keyword parameters of the form
236 ``arg``\ *n*, match only signals where the *n*\ th argument
237 is the value given for that keyword parameter
240 args_dict
= self
._create
_args
_dict
(keywords
)
242 if (named_service
and named_service
[0] != ':'):
243 bus_object
= self
.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
244 named_service
= bus_object
.GetNameOwner(named_service
, dbus_interface
='org.freedesktop.DBus')
246 match_rule
= SignalMatchRule(signal_name
, dbus_interface
, named_service
, path
)
248 for kw
in ("sender_keyword", "path_keyword"):
250 setattr(match_rule
, kw
, keywords
[kw
])
252 setattr(match_rule
, kw
, None)
255 match_rule
.add_args_match(args_dict
)
257 match_rule
.add_handler(handler_function
)
259 self
._match
_rule
_tree
.add(match_rule
)
261 _dbus_bindings
.bus_add_match(self
._connection
, repr(match_rule
))
263 def remove_signal_receiver(self
, handler_function
,
270 args_dict
= self
._create
_args
_dict
(keywords
)
272 if (named_service
and named_service
[0] != ':'):
273 bus_object
= self
.get_object('org.freedesktop.DBus', '/org/freedesktop/DBus')
274 named_service
= bus_object
.GetNameOwner(named_service
, dbus_interface
='org.freedesktop.DBus')
276 match_rule
= SignalMatchRule(signal_name
, dbus_interface
, named_service
, path
)
279 match_rule
.add_args_match(args_dict
)
281 if (handler_function
):
282 match_rule
.add_handler(handler_function
)
284 self
._match
_rule
_tree
.remove(match_rule
)
286 #TODO we leak match rules in the lower level bindings. We need to ref count them
288 def get_unix_user(self
, named_service
):
289 """Get the unix user for the given named_service on this Bus"""
290 return _dbus_bindings
.bus_get_unix_user(self
._connection
, named_service
)
292 def _signal_func(self
, connection
, message
):
293 if (message
.get_type() != _dbus_bindings
.MESSAGE_TYPE_SIGNAL
):
294 return _dbus_bindings
.HANDLER_RESULT_NOT_YET_HANDLED
296 dbus_interface
= message
.get_interface()
297 named_service
= message
.get_sender()
298 path
= message
.get_path()
299 signal_name
= message
.get_member()
301 match_rule
= SignalMatchRule(signal_name
, dbus_interface
, named_service
, path
)
303 self
._match
_rule
_tree
.exec_matches(match_rule
, message
)
305 def start_service_by_name(self
, named_service
):
306 """Start a service which will implement the given bus name on this
310 `named_service` : str
311 The well-known bus name for which an implementation is required
313 return _dbus_bindings
.bus_start_service_by_name(self
._connection
, named_service
)
316 if self
._bus
_type
== self
.TYPE_SESSION
:
318 elif self
._bus
_type
== self
.TYPE_SYSTEM
:
320 elif self
._bus
_type
== self
.TYPE_STARTER
:
323 assert False, 'Unable to represent unknown bus type.'
325 return '<dbus.Bus on %s at %#x>' % (name
, id(self
))
328 class SystemBus(Bus
):
329 """The system-wide message bus."""
330 def __new__(cls
, use_default_mainloop
=True, private
=False):
331 """Return a connection to the system bus.
334 `use_default_mainloop` : bool
335 If true (default), automatically register the new connection
336 to be polled by the default main loop, if any
338 If true, never return an existing shared instance, but instead
339 return a private connection.
341 return Bus
.__new
__(cls
, Bus
.TYPE_SYSTEM
, use_default_mainloop
, private
)
343 class SessionBus(Bus
):
344 """The session (current login) message bus."""
345 def __new__(cls
, use_default_mainloop
=True, private
=False):
346 """Return a connection to the session bus.
349 `use_default_mainloop` : bool
350 If true (default), automatically register the new connection
351 to be polled by the default main loop, if any
353 If true, never return an existing shared instance, but instead
354 return a private connection.
356 return Bus
.__new
__(cls
, Bus
.TYPE_SESSION
, use_default_mainloop
, private
)
358 class StarterBus(Bus
):
359 """The bus that activated this process (only valid if
360 this process was launched by DBus activation).
362 def __new__(cls
, use_default_mainloop
=True, private
=False):
363 """Return a connection to the bus that activated this process.
366 `use_default_mainloop` : bool
367 If true (default), automatically register the new connection
368 to be polled by the default main loop, if any
370 If true, never return an existing shared instance, but instead
371 return a private connection.
373 return Bus
.__new
__(cls
, Bus
.TYPE_STARTER
, use_default_mainloop
, private
)
376 """An interface into a remote object.
378 An Interface can be used to wrap ProxyObjects
379 so that calls can be routed to their correct
383 def __init__(self
, object, dbus_interface
):
384 """Construct a proxy for the given interface on the given object.
387 `object` : `dbus.proxies.ProxyObject`
389 `dbus_interface` : str
390 An interface the `object` implements
393 self
._dbus
_interface
= dbus_interface
395 def connect_to_signal(self
, signal_name
, handler_function
, dbus_interface
= None, **keywords
):
396 """Arrange for a function to be called when the given signal is
401 The name of the signal
402 `handler_function` : callable
403 A function to be called (FIXME arguments?) when the signal
404 is emitted by the remote object.
405 `dbus_interface` : str
406 Optional interface with which to qualify the signal name.
407 The default is to use the interface this Interface represents.
408 `sender_keyword` : str
409 If not None (the default), the handler function will receive
410 the unique name of the sending endpoint as a keyword
411 argument with this name
413 If not None (the default), the handler function will receive
414 the object-path of the sending object as a keyword argument
417 If there are additional keyword parameters of the form
418 ``arg``\ *n*, match only signals where the *n*\ th argument
419 is the value given for that keyword parameter
421 if not dbus_interface
:
422 dbus_interface
= self
._dbus
_interface
424 self
._obj
.connect_to_signal(signal_name
, handler_function
, dbus_interface
, **keywords
)
426 def __getattr__(self
, member
, **keywords
):
427 # FIXME: this syntax is bizarre.
428 if (keywords
.has_key('dbus_interface')):
429 _dbus_interface
= keywords
['dbus_interface']
431 _dbus_interface
= self
._dbus
_interface
433 if member
== '__call__':
434 return object.__call
__
436 ret
= self
._obj
.__getattr
__(member
, dbus_interface
=_dbus_interface
)
440 return '<Interface %r implementing %r at %#x>'%(
441 self
._obj
, self
._dbus
_interface
, id(self
))