1 # Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/>
3 # Licensed under the Academic Free License version 2.1
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU Lesser General Public License as published
7 # by the Free Software Foundation; either version 2.1 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program; if not, write to the Free Software
17 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 __all__
= ('BusConnection',)
20 __docformat__
= 'reStructuredText'
22 from _dbus_bindings
import validate_interface_name
, validate_member_name
,\
23 validate_bus_name
, validate_object_path
,\
26 BUS_SESSION
, BUS_STARTER
, BUS_SYSTEM
, \
27 BUS_DAEMON_NAME
, BUS_DAEMON_PATH
, BUS_DAEMON_IFACE
28 from dbus
.connection
import Connection
31 class BusConnection(Connection
):
32 """A connection to a D-Bus daemon that implements the
33 ``org.freedesktop.DBus`` pseudo-service.
36 TYPE_SESSION
= BUS_SESSION
37 """Represents a session bus (same as the global dbus.BUS_SESSION)"""
39 TYPE_SYSTEM
= BUS_SYSTEM
40 """Represents the system bus (same as the global dbus.BUS_SYSTEM)"""
42 TYPE_STARTER
= BUS_STARTER
43 """Represents the bus that started this service by activation (same as
44 the global dbus.BUS_STARTER)"""
46 def activate_name_owner(self
, bus_name
):
47 if (bus_name
is not None and bus_name
[:1] != ':'
48 and bus_name
!= BUS_DAEMON_NAME
):
50 return self
.get_name_owner(bus_name
)
51 except DBusException
, e
:
52 # FIXME: detect whether it's NameHasNoOwner, but properly
53 #if not str(e).startswith('org.freedesktop.DBus.Error.NameHasNoOwner:'):
55 # it might not exist: try to start it
56 self
.start_service_by_name(bus_name
)
57 return self
.get_name_owner(bus_name
)
62 def get_object(self
, named_service
, object_path
, introspect
=True,
63 follow_name_owner_changes
=False):
64 """Return a local proxy for the given remote object.
66 Method calls on the proxy are translated into method calls on the
71 A bus name (either the unique name or a well-known name)
72 of the application owning the object
74 The object path of the desired object
76 If true (default), attempt to introspect the remote
77 object to find out supported methods and their signatures
78 `follow_name_owner_changes` : bool
79 If the object path is a well-known name and this parameter
80 is false (default), resolve the well-known name to the unique
81 name of its current owner and bind to that instead; if the
82 ownership of the well-known name changes in future,
83 keep communicating with the original owner.
84 This is necessary if the D-Bus API used is stateful.
86 If the object path is a well-known name and this parameter
87 is true, whenever the well-known name changes ownership in
88 future, bind to the new owner, if any.
90 If the given object path is a unique name, this parameter
93 :Returns: a `dbus.proxies.ProxyObject`
94 :Raises `DBusException`: if resolving the well-known name to a
97 if follow_name_owner_changes
:
98 self
._require
_main
_loop
() # we don't get the signals otherwise
99 return self
.ProxyObjectClass(self
, named_service
, object_path
,
100 introspect
=introspect
,
101 follow_name_owner_changes
=follow_name_owner_changes
)
103 def get_unix_user(self
, bus_name
):
104 """Get the numeric uid of the process owning the given bus name.
108 A bus name, either unique or well-known
109 :Returns: a `dbus.UInt32`
111 validate_bus_name(bus_name
)
112 return self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
113 BUS_DAEMON_IFACE
, 'GetConnectionUnixUser',
116 def start_service_by_name(self
, bus_name
, flags
=0):
117 """Start a service which will implement the given bus name on this Bus.
121 The well-known bus name to be activated.
122 `flags` : dbus.UInt32
123 Flags to pass to StartServiceByName (currently none are
126 :Returns: A tuple of 2 elements. The first is always True, the
127 second is either START_REPLY_SUCCESS or
128 START_REPLY_ALREADY_RUNNING.
130 :Raises DBusException: if the service could not be started.
132 validate_bus_name(bus_name
)
133 return (True, self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
135 'StartServiceByName',
136 'su', (bus_name
, flags
)))
138 # XXX: it might be nice to signal IN_QUEUE, EXISTS by exception,
139 # but this would not be backwards-compatible
140 def request_name(self
, name
, flags
=0):
141 """Request a bus name.
145 The well-known name to be requested
146 `flags` : dbus.UInt32
147 A bitwise-OR of 0 or more of the flags
148 `DBUS_NAME_FLAG_ALLOW_REPLACEMENT`,
149 `DBUS_NAME_FLAG_REPLACE_EXISTING`
150 and `DBUS_NAME_FLAG_DO_NOT_QUEUE`
151 :Returns: `DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER`,
152 `DBUS_REQUEST_NAME_REPLY_IN_QUEUE`,
153 `DBUS_REQUEST_NAME_REPLY_EXISTS` or
154 `DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER`
155 :Raises DBusException: if the bus daemon cannot be contacted or
158 validate_bus_name(name
, allow_unique
=False)
159 return self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
160 BUS_DAEMON_IFACE
, 'RequestName',
163 def release_name(self
, name
):
164 """Release a bus name.
168 The well-known name to be released
169 :Returns: `DBUS_RELEASE_NAME_REPLY_RELEASED`,
170 `DBUS_RELEASE_NAME_REPLY_NON_EXISTENT`
171 or `DBUS_RELEASE_NAME_REPLY_NOT_OWNER`
172 :Raises DBusException: if the bus daemon cannot be contacted or
175 validate_bus_name(name
, allow_unique
=False)
176 return self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
177 BUS_DAEMON_IFACE
, 'ReleaseName',
180 def list_names(self
):
181 """Return a list of all currently-owned names on the bus.
183 :Returns: a dbus.Array of dbus.UTF8String
185 return self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
186 BUS_DAEMON_IFACE
, 'ListNames',
187 '', (), utf8_strings
=True)
189 def list_activatable_names(self
):
190 """Return a list of all names that can be activated on the bus.
192 :Returns: a dbus.Array of dbus.UTF8String
194 return self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
195 BUS_DAEMON_IFACE
, 'ListNames',
196 '', (), utf8_strings
=True)
198 def get_name_owner(self
, bus_name
):
199 """Return the unique connection name of the primary owner of the
202 :Raises DBusException: if the `bus_name` has no owner
204 validate_bus_name(bus_name
, allow_unique
=False)
205 return self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
206 BUS_DAEMON_IFACE
, 'GetNameOwner',
207 's', (bus_name
,), utf8_strings
=True)
209 def name_has_owner(self
, bus_name
):
210 """Return True iff the given bus name has an owner on this bus.
214 The bus name to look up
217 return bool(self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
218 BUS_DAEMON_IFACE
, 'NameHasOwner',
221 def add_match_string(self
, rule
):
222 """Arrange for this application to receive messages on the bus that
223 match the given rule. This version will block.
228 :Raises: `DBusException` on error.
230 self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
231 BUS_DAEMON_IFACE
, 'AddMatch', 's', (rule
,))
233 # FIXME: add an async success/error handler capability?
234 # (and the same for remove_...)
235 def add_match_string_non_blocking(self
, rule
):
236 """Arrange for this application to receive messages on the bus that
237 match the given rule. This version will not block, but any errors
244 :Raises: `DBusException` on error.
246 self
.call_async(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
247 BUS_DAEMON_IFACE
, 'AddMatch', 's', (rule
,),
250 def remove_match_string(self
, rule
):
251 """Arrange for this application to receive messages on the bus that
252 match the given rule. This version will block.
257 :Raises: `DBusException` on error.
259 self
.call_blocking(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
260 BUS_DAEMON_IFACE
, 'RemoveMatch', 's', (rule
,))
262 def remove_match_string_non_blocking(self
, rule
):
263 """Arrange for this application to receive messages on the bus that
264 match the given rule. This version will not block, but any errors
271 :Raises: `DBusException` on error.
273 self
.call_async(BUS_DAEMON_NAME
, BUS_DAEMON_PATH
,
274 BUS_DAEMON_IFACE
, 'RemoveMatch', 's', (rule
,),