* erc.texi (Special Features): ERC is being maintained within Emacs
[bpt/emacs.git] / lisp / net / dbus.el
CommitLineData
3a993e3d
MA
1;;; dbus.el --- Elisp bindings for D-Bus.
2
ab422c4d 3;; Copyright (C) 2007-2013 Free Software Foundation, Inc.
3a993e3d
MA
4
5;; Author: Michael Albinus <michael.albinus@gmx.de>
6;; Keywords: comm, hardware
7
8;; This file is part of GNU Emacs.
9
874a927a 10;; GNU Emacs is free software: you can redistribute it and/or modify
3a993e3d 11;; it under the terms of the GNU General Public License as published by
874a927a
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
3a993e3d
MA
14
15;; GNU Emacs is distributed in the hope that it will be useful,
16;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18;; GNU General Public License for more details.
19
20;; You should have received a copy of the GNU General Public License
874a927a 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
3a993e3d
MA
22
23;;; Commentary:
24
25;; This package provides language bindings for the D-Bus API. D-Bus
26;; is a message bus system, a simple way for applications to talk to
27;; one another. See <http://dbus.freedesktop.org/> for details.
28
29;; Low-level language bindings are implemented in src/dbusbind.c.
30
dcbf5805
MA
31;; D-Bus support in the Emacs core can be disabled with configuration
32;; option "--without-dbus".
33
3a993e3d
MA
34;;; Code:
35
dcbf5805
MA
36;; Declare used subroutines and variables.
37(declare-function dbus-message-internal "dbusbind.c")
ba6f7d86 38(declare-function dbus-init-bus "dbusbind.c")
dcbf5805
MA
39(defvar dbus-message-type-invalid)
40(defvar dbus-message-type-method-call)
41(defvar dbus-message-type-method-return)
42(defvar dbus-message-type-error)
43(defvar dbus-message-type-signal)
6981d00a 44(defvar dbus-debug)
b172ed20 45(defvar dbus-registered-objects-table)
6981d00a
MA
46
47;; Pacify byte compiler.
f58e0fd5 48(eval-when-compile (require 'cl-lib))
7bb7efbd 49
3a993e3d
MA
50(require 'xml)
51
52(defconst dbus-service-dbus "org.freedesktop.DBus"
53 "The bus name used to talk to the bus itself.")
54
55(defconst dbus-path-dbus "/org/freedesktop/DBus"
56 "The object path used to talk to the bus itself.")
57
dcbf5805
MA
58;; Default D-Bus interfaces.
59
3a993e3d 60(defconst dbus-interface-dbus "org.freedesktop.DBus"
dcbf5805 61 "The interface exported by the service `dbus-service-dbus'.")
3a993e3d 62
4ba11bcb 63(defconst dbus-interface-peer (concat dbus-interface-dbus ".Peer")
dcbf5805
MA
64 "The interface for peer objects.
65See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer'.")
66
67;; <interface name="org.freedesktop.DBus.Peer">
68;; <method name="Ping">
69;; </method>
70;; <method name="GetMachineId">
71;; <arg name="machine_uuid" type="s" direction="out"/>
72;; </method>
73;; </interface>
4ba11bcb
MA
74
75(defconst dbus-interface-introspectable
76 (concat dbus-interface-dbus ".Introspectable")
dcbf5805
MA
77 "The interface supported by introspectable objects.
78See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable'.")
3a993e3d 79
dcbf5805
MA
80;; <interface name="org.freedesktop.DBus.Introspectable">
81;; <method name="Introspect">
82;; <arg name="data" type="s" direction="out"/>
83;; </method>
84;; </interface>
f636d3ca 85
dcbf5805
MA
86(defconst dbus-interface-properties (concat dbus-interface-dbus ".Properties")
87 "The interface for property objects.
88See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties'.")
89
90;; <interface name="org.freedesktop.DBus.Properties">
91;; <method name="Get">
92;; <arg name="interface" type="s" direction="in"/>
93;; <arg name="propname" type="s" direction="in"/>
94;; <arg name="value" type="v" direction="out"/>
95;; </method>
96;; <method name="Set">
97;; <arg name="interface" type="s" direction="in"/>
98;; <arg name="propname" type="s" direction="in"/>
99;; <arg name="value" type="v" direction="in"/>
100;; </method>
101;; <method name="GetAll">
102;; <arg name="interface" type="s" direction="in"/>
103;; <arg name="props" type="a{sv}" direction="out"/>
104;; </method>
105;; <signal name="PropertiesChanged">
106;; <arg name="interface" type="s"/>
107;; <arg name="changed_properties" type="a{sv}"/>
108;; <arg name="invalidated_properties" type="as"/>
109;; </signal>
110;; </interface>
111
112(defconst dbus-interface-objectmanager
113 (concat dbus-interface-dbus ".ObjectManager")
114 "The object manager interface.
115See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager'.")
116
117;; <interface name="org.freedesktop.DBus.ObjectManager">
118;; <method name="GetManagedObjects">
119;; <arg name="object_paths_interfaces_and_properties"
120;; type="a{oa{sa{sv}}}" direction="out"/>
121;; </method>
122;; <signal name="InterfacesAdded">
123;; <arg name="object_path" type="o"/>
124;; <arg name="interfaces_and_properties" type="a{sa{sv}}"/>
125;; </signal>
126;; <signal name="InterfacesRemoved">
127;; <arg name="object_path" type="o"/>
128;; <arg name="interfaces" type="as"/>
129;; </signal>
130;; </interface>
131
132;; Emacs defaults.
65b7cb2c
MA
133(defconst dbus-service-emacs "org.gnu.Emacs"
134 "The well known service name of Emacs.")
135
136(defconst dbus-path-emacs "/org/gnu/Emacs"
dcbf5805
MA
137 "The object path namespace used by Emacs.
138All object paths provided by the service `dbus-service-emacs'
139shall be subdirectories of this path.")
65b7cb2c 140
dcbf5805
MA
141(defconst dbus-interface-emacs "org.gnu.Emacs"
142 "The interface namespace used by Emacs.")
98c38bfc 143
dcbf5805 144;; D-Bus constants.
98c38bfc 145
246a286b
MA
146(defmacro dbus-ignore-errors (&rest body)
147 "Execute BODY; signal D-Bus error when `dbus-debug' is non-nil.
148Otherwise, return result of last form in BODY, or all other errors."
f291fe60 149 (declare (indent 0) (debug t))
246a286b
MA
150 `(condition-case err
151 (progn ,@body)
152 (dbus-error (when dbus-debug (signal (car err) (cdr err))))))
246a286b
MA
153(font-lock-add-keywords 'emacs-lisp-mode '("\\<dbus-ignore-errors\\>"))
154
d1069532
SM
155(define-obsolete-variable-alias 'dbus-event-error-hooks
156 'dbus-event-error-functions "24.3")
157(defvar dbus-event-error-functions nil
e12c189f 158 "Functions to be called when a D-Bus error happens in the event handler.
f213fc09 159Every function must accept two arguments, the event and the error variable
333f9019 160caught in `condition-case' by `dbus-error'.")
e12c189f 161
5363d8ea 162\f
dcbf5805 163;;; Basic D-Bus message functions.
5363d8ea 164
98c38bfc
MA
165(defvar dbus-return-values-table (make-hash-table :test 'equal)
166 "Hash table for temporary storing arguments of reply messages.
dcbf5805
MA
167A key in this hash table is a list (:serial BUS SERIAL), like in
168`dbus-registered-objects-table'. BUS is either a Lisp symbol,
169`:system' or `:session', or a string denoting the bus address.
170SERIAL is the serial number of the reply message.")
171
172(defun dbus-call-method-handler (&rest args)
173 "Handler for reply messages of asynchronous D-Bus message calls.
174It calls the function stored in `dbus-registered-objects-table'.
175The result will be made available in `dbus-return-values-table'."
176 (puthash (list :serial
177 (dbus-event-bus-name last-input-event)
178 (dbus-event-serial-number last-input-event))
179 (if (= (length args) 1) (car args) args)
180 dbus-return-values-table))
181
182(defun dbus-call-method (bus service path interface method &rest args)
183 "Call METHOD on the D-Bus BUS.
184
185BUS is either a Lisp symbol, `:system' or `:session', or a string
186denoting the bus address.
187
188SERVICE is the D-Bus service name to be used. PATH is the D-Bus
189object path SERVICE is registered at. INTERFACE is an interface
190offered by SERVICE. It must provide METHOD.
191
192If the parameter `:timeout' is given, the following integer TIMEOUT
193specifies the maximum number of milliseconds the method call must
194return. The default value is 25,000. If the method call doesn't
195return in time, a D-Bus error is raised.
196
197All other arguments ARGS are passed to METHOD as arguments. They are
198converted into D-Bus types via the following rules:
199
200 t and nil => DBUS_TYPE_BOOLEAN
201 number => DBUS_TYPE_UINT32
202 integer => DBUS_TYPE_INT32
203 float => DBUS_TYPE_DOUBLE
204 string => DBUS_TYPE_STRING
205 list => DBUS_TYPE_ARRAY
206
207All arguments can be preceded by a type symbol. For details about
208type symbols, see Info node `(dbus)Type Conversion'.
209
210`dbus-call-method' returns the resulting values of METHOD as a list of
211Lisp objects. The type conversion happens the other direction as for
212input arguments. It follows the mapping rules:
213
214 DBUS_TYPE_BOOLEAN => t or nil
215 DBUS_TYPE_BYTE => number
216 DBUS_TYPE_UINT16 => number
217 DBUS_TYPE_INT16 => integer
218 DBUS_TYPE_UINT32 => number or float
219 DBUS_TYPE_UNIX_FD => number or float
220 DBUS_TYPE_INT32 => integer or float
221 DBUS_TYPE_UINT64 => number or float
222 DBUS_TYPE_INT64 => integer or float
223 DBUS_TYPE_DOUBLE => float
224 DBUS_TYPE_STRING => string
225 DBUS_TYPE_OBJECT_PATH => string
226 DBUS_TYPE_SIGNATURE => string
227 DBUS_TYPE_ARRAY => list
228 DBUS_TYPE_VARIANT => list
229 DBUS_TYPE_STRUCT => list
230 DBUS_TYPE_DICT_ENTRY => list
231
232Example:
233
234\(dbus-call-method
235 :session \"org.gnome.seahorse\" \"/org/gnome/seahorse/keys/openpgp\"
236 \"org.gnome.seahorse.Keys\" \"GetKeyField\"
237 \"openpgp:657984B8C7A966DD\" \"simple-name\")
238
239 => (t (\"Philip R. Zimmermann\"))
240
241If the result of the METHOD call is just one value, the converted Lisp
242object is returned instead of a list containing this single Lisp object.
243
244\(dbus-call-method
245 :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/devices/computer\"
246 \"org.freedesktop.Hal.Device\" \"GetPropertyString\"
247 \"system.kernel.machine\")
248
249 => \"i686\""
250
251 (or (memq bus '(:system :session)) (stringp bus)
252 (signal 'wrong-type-argument (list 'keywordp bus)))
253 (or (stringp service)
254 (signal 'wrong-type-argument (list 'stringp service)))
255 (or (stringp path)
256 (signal 'wrong-type-argument (list 'stringp path)))
257 (or (stringp interface)
258 (signal 'wrong-type-argument (list 'stringp interface)))
259 (or (stringp method)
260 (signal 'wrong-type-argument (list 'stringp method)))
261
262 (let ((timeout (plist-get args :timeout))
263 (key
264 (apply
265 'dbus-message-internal dbus-message-type-method-call
266 bus service path interface method 'dbus-call-method-handler args)))
205a7391 267
dcbf5805
MA
268 ;; Wait until `dbus-call-method-handler' has put the result into
269 ;; `dbus-return-values-table'. If no timeout is given, use the
205a7391 270 ;; default 25". Events which are not from D-Bus must be restored.
dcbf5805
MA
271 (with-timeout ((if timeout (/ timeout 1000.0) 25))
272 (while (eq (gethash key dbus-return-values-table :ignore) :ignore)
dde84790
MA
273 (let ((event (let ((inhibit-redisplay t) unread-command-events)
274 (read-event nil nil 0.1))))
205a7391
MA
275 (when (and event (not (ignore-errors (dbus-check-event event))))
276 (setq unread-command-events
277 (append unread-command-events (list event)))))))
dcbf5805
MA
278
279 ;; Cleanup `dbus-return-values-table'. Return the result.
280 (prog1
281 (gethash key dbus-return-values-table)
282 (remhash key dbus-return-values-table))))
283
284;; `dbus-call-method' works non-blocking now.
285(defalias 'dbus-call-method-non-blocking 'dbus-call-method)
2a1e2476 286(make-obsolete 'dbus-call-method-non-blocking 'dbus-call-method "24.3")
dcbf5805
MA
287
288(defun dbus-call-method-asynchronously
289 (bus service path interface method handler &rest args)
290 "Call METHOD on the D-Bus BUS asynchronously.
291
292BUS is either a Lisp symbol, `:system' or `:session', or a string
293denoting the bus address.
294
295SERVICE is the D-Bus service name to be used. PATH is the D-Bus
296object path SERVICE is registered at. INTERFACE is an interface
297offered by SERVICE. It must provide METHOD.
298
299HANDLER is a Lisp function, which is called when the corresponding
300return message has arrived. If HANDLER is nil, no return message
301will be expected.
302
303If the parameter `:timeout' is given, the following integer TIMEOUT
304specifies the maximum number of milliseconds the method call must
305return. The default value is 25,000. If the method call doesn't
306return in time, a D-Bus error is raised.
307
308All other arguments ARGS are passed to METHOD as arguments. They are
309converted into D-Bus types via the following rules:
310
311 t and nil => DBUS_TYPE_BOOLEAN
312 number => DBUS_TYPE_UINT32
313 integer => DBUS_TYPE_INT32
314 float => DBUS_TYPE_DOUBLE
315 string => DBUS_TYPE_STRING
316 list => DBUS_TYPE_ARRAY
317
318All arguments can be preceded by a type symbol. For details about
319type symbols, see Info node `(dbus)Type Conversion'.
320
321If HANDLER is a Lisp function, the function returns a key into the
322hash table `dbus-registered-objects-table'. The corresponding entry
323in the hash table is removed, when the return message has been arrived,
324and HANDLER is called.
325
326Example:
327
328\(dbus-call-method-asynchronously
329 :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/devices/computer\"
330 \"org.freedesktop.Hal.Device\" \"GetPropertyString\" 'message
331 \"system.kernel.machine\")
332
333 => \(:serial :system 2)
334
335 -| i686"
336
337 (or (memq bus '(:system :session)) (stringp bus)
338 (signal 'wrong-type-argument (list 'keywordp bus)))
339 (or (stringp service)
340 (signal 'wrong-type-argument (list 'stringp service)))
341 (or (stringp path)
342 (signal 'wrong-type-argument (list 'stringp path)))
343 (or (stringp interface)
344 (signal 'wrong-type-argument (list 'stringp interface)))
345 (or (stringp method)
346 (signal 'wrong-type-argument (list 'stringp method)))
347 (or (null handler) (functionp handler)
348 (signal 'wrong-type-argument (list 'functionp handler)))
349
350 (apply 'dbus-message-internal dbus-message-type-method-call
351 bus service path interface method handler args))
352
353(defun dbus-send-signal (bus service path interface signal &rest args)
354 "Send signal SIGNAL on the D-Bus BUS.
355
356BUS is either a Lisp symbol, `:system' or `:session', or a string
357denoting the bus address. The signal is sent from the D-Bus object
358Emacs is registered at BUS.
359
360SERVICE is the D-Bus name SIGNAL is sent to. It can be either a known
361name or a unique name. If SERVICE is nil, the signal is sent as
362broadcast message. PATH is the D-Bus object path SIGNAL is sent from.
363INTERFACE is an interface available at PATH. It must provide signal
364SIGNAL.
365
366All other arguments ARGS are passed to SIGNAL as arguments. They are
367converted into D-Bus types via the following rules:
368
369 t and nil => DBUS_TYPE_BOOLEAN
370 number => DBUS_TYPE_UINT32
371 integer => DBUS_TYPE_INT32
372 float => DBUS_TYPE_DOUBLE
373 string => DBUS_TYPE_STRING
374 list => DBUS_TYPE_ARRAY
375
376All arguments can be preceded by a type symbol. For details about
377type symbols, see Info node `(dbus)Type Conversion'.
378
379Example:
380
381\(dbus-send-signal
382 :session nil \"/org/gnu/Emacs\" \"org.gnu.Emacs.FileManager\"
383 \"FileModified\" \"/home/albinus/.emacs\")"
384
385 (or (memq bus '(:system :session)) (stringp bus)
386 (signal 'wrong-type-argument (list 'keywordp bus)))
387 (or (null service) (stringp service)
388 (signal 'wrong-type-argument (list 'stringp service)))
389 (or (stringp path)
390 (signal 'wrong-type-argument (list 'stringp path)))
391 (or (stringp interface)
392 (signal 'wrong-type-argument (list 'stringp interface)))
393 (or (stringp signal)
394 (signal 'wrong-type-argument (list 'stringp signal)))
395
396 (apply 'dbus-message-internal dbus-message-type-signal
397 bus service path interface signal args))
398
399(defun dbus-method-return-internal (bus service serial &rest args)
400 "Return for message SERIAL on the D-Bus BUS.
401This is an internal function, it shall not be used outside dbus.el."
402
403 (or (memq bus '(:system :session)) (stringp bus)
404 (signal 'wrong-type-argument (list 'keywordp bus)))
405 (or (stringp service)
406 (signal 'wrong-type-argument (list 'stringp service)))
407 (or (natnump serial)
408 (signal 'wrong-type-argument (list 'natnump serial)))
409
410 (apply 'dbus-message-internal dbus-message-type-method-return
411 bus service serial args))
412
413(defun dbus-method-error-internal (bus service serial &rest args)
414 "Return error message for message SERIAL on the D-Bus BUS.
415This is an internal function, it shall not be used outside dbus.el."
416
417 (or (memq bus '(:system :session)) (stringp bus)
418 (signal 'wrong-type-argument (list 'keywordp bus)))
419 (or (stringp service)
420 (signal 'wrong-type-argument (list 'stringp service)))
421 (or (natnump serial)
422 (signal 'wrong-type-argument (list 'natnump serial)))
423
424 (apply 'dbus-message-internal dbus-message-type-error
425 bus service serial args))
426
427\f
428;;; Hash table of registered functions.
98c38bfc 429
ef6ce14c 430(defun dbus-list-hash-table ()
e49d337b 431 "Returns all registered member registrations to D-Bus.
ef6ce14c 432The return value is a list, with elements of kind (KEY . VALUE).
b172ed20 433See `dbus-registered-objects-table' for a description of the
ef6ce14c
MA
434hash table."
435 (let (result)
436 (maphash
4f91a816 437 (lambda (key value) (add-to-list 'result (cons key value) 'append))
b172ed20 438 dbus-registered-objects-table)
ef6ce14c
MA
439 result))
440
dcbf5805
MA
441(defun dbus-setenv (bus variable value)
442 "Set the value of the BUS environment variable named VARIABLE to VALUE.
b172ed20 443
dcbf5805
MA
444BUS is either a Lisp symbol, `:system' or `:session', or a string
445denoting the bus address. Both VARIABLE and VALUE should be strings.
246a286b 446
dcbf5805
MA
447Normally, services inherit the environment of the BUS daemon. This
448function adds to or modifies that environment when activating services.
b172ed20 449
dcbf5805
MA
450Some bus instances, such as `:system', may disable setting the environment."
451 (dbus-call-method
452 bus dbus-service-dbus dbus-path-dbus
453 dbus-interface-dbus "UpdateActivationEnvironment"
454 `(:array (:dict-entry ,variable ,value))))
455
456(defun dbus-register-service (bus service &rest flags)
457 "Register known name SERVICE on the D-Bus BUS.
458
459BUS is either a Lisp symbol, `:system' or `:session', or a string
460denoting the bus address.
461
462SERVICE is the D-Bus service name that should be registered. It must
463be a known name.
464
465FLAGS are keywords, which control how the service name is registered.
466The following keywords are recognized:
467
468`:allow-replacement': Allow another service to become the primary
469owner if requested.
470
471`:replace-existing': Request to replace the current primary owner.
472
473`:do-not-queue': If we can not become the primary owner do not place
474us in the queue.
475
476The function returns a keyword, indicating the result of the
477operation. One of the following keywords is returned:
478
479`:primary-owner': Service has become the primary owner of the
480requested name.
481
482`:in-queue': Service could not become the primary owner and has been
483placed in the queue.
484
485`:exists': Service is already in the queue.
486
487`:already-owner': Service is already the primary owner."
488
489 ;; Add ObjectManager handler.
490 (dbus-register-method
491 bus service nil dbus-interface-objectmanager "GetManagedObjects"
492 'dbus-managed-objects-handler 'dont-register)
493
494 (let ((arg 0)
495 reply)
496 (dolist (flag flags)
497 (setq arg
498 (+ arg
f58e0fd5 499 (pcase flag
dcbf5805
MA
500 (:allow-replacement 1)
501 (:replace-existing 2)
502 (:do-not-queue 4)
f58e0fd5 503 (_ (signal 'wrong-type-argument (list flag)))))))
dcbf5805
MA
504 (setq reply (dbus-call-method
505 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
506 "RequestName" service arg))
f58e0fd5 507 (pcase reply
dcbf5805
MA
508 (1 :primary-owner)
509 (2 :in-queue)
510 (3 :exists)
511 (4 :already-owner)
f58e0fd5 512 (_ (signal 'dbus-error (list "Could not register service" service))))))
246a286b 513
c0a39702
MA
514(defun dbus-unregister-service (bus service)
515 "Unregister all objects related to SERVICE from D-Bus BUS.
e73f184c 516BUS is either a Lisp symbol, `:system' or `:session', or a string
5c0b4070
MA
517denoting the bus address. SERVICE must be a known service name.
518
519The function returns a keyword, indicating the result of the
520operation. One of the following keywords is returned:
521
522`:released': Service has become the primary owner of the name.
523
524`:non-existent': Service name does not exist on this bus.
525
526`:not-owner': We are neither the primary owner nor waiting in the
527queue of this service."
528
c0a39702
MA
529 (maphash
530 (lambda (key value)
531 (dolist (elt value)
532 (ignore-errors
dcbf5805 533 (when (and (equal bus (cadr key)) (string-equal service (cadr elt)))
c0a39702
MA
534 (unless
535 (puthash key (delete elt value) dbus-registered-objects-table)
536 (remhash key dbus-registered-objects-table))))))
537 dbus-registered-objects-table)
0a203b61
MA
538 (let ((reply (dbus-call-method
539 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
540 "ReleaseName" service)))
f58e0fd5 541 (pcase reply
0a203b61
MA
542 (1 :released)
543 (2 :non-existent)
544 (3 :not-owner)
f58e0fd5 545 (_ (signal 'dbus-error (list "Could not unregister service" service))))))
c0a39702 546
dcbf5805
MA
547(defun dbus-register-signal
548 (bus service path interface signal handler &rest args)
549 "Register for a signal on the D-Bus BUS.
98c38bfc 550
dcbf5805
MA
551BUS is either a Lisp symbol, `:system' or `:session', or a string
552denoting the bus address.
98c38bfc 553
dcbf5805
MA
554SERVICE is the D-Bus service name used by the sending D-Bus object.
555It can be either a known name or the unique name of the D-Bus object
556sending the signal.
557
558PATH is the D-Bus object path SERVICE is registered. INTERFACE
559is an interface offered by SERVICE. It must provide SIGNAL.
560HANDLER is a Lisp function to be called when the signal is
561received. It must accept as arguments the values SIGNAL is
562sending.
563
564SERVICE, PATH, INTERFACE and SIGNAL can be nil. This is
565interpreted as a wildcard for the respective argument.
566
567The remaining arguments ARGS can be keywords or keyword string pairs.
568The meaning is as follows:
569
570`:argN' STRING:
571`:pathN' STRING: This stands for the Nth argument of the
572signal. `:pathN' arguments can be used for object path wildcard
0ba2624f 573matches as specified by D-Bus, while an `:argN' argument
dcbf5805
MA
574requires an exact match.
575
576`:arg-namespace' STRING: Register for the signals, which first
577argument defines the service or interface namespace STRING.
578
579`:path-namespace' STRING: Register for the object path namespace
580STRING. All signals sent from an object path, which has STRING as
581the preceding string, are matched. This requires PATH to be nil.
582
583`:eavesdrop': Register for unicast signals which are not directed
584to the D-Bus object Emacs is registered at D-Bus BUS, if the
585security policy of BUS allows this.
586
587Example:
588
589\(defun my-signal-handler (device)
590 (message \"Device %s added\" device))
591
592\(dbus-register-signal
593 :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\"
594 \"org.freedesktop.Hal.Manager\" \"DeviceAdded\" 'my-signal-handler)
595
596 => \(\(:signal :system \"org.freedesktop.Hal.Manager\" \"DeviceAdded\")
597 \(\"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\" my-signal-handler))
598
599`dbus-register-signal' returns an object, which can be used in
600`dbus-unregister-object' for removing the registration."
601
602 (let ((counter 0)
603 (rule "type='signal'")
604 uname key key1 value)
605
606 ;; Retrieve unique name of service. If service is a known name,
607 ;; we will register for the corresponding unique name, if any.
608 ;; Signals are sent always with the unique name as sender. Note:
609 ;; the unique name of `dbus-service-dbus' is that string itself.
610 (if (and (stringp service)
611 (not (zerop (length service)))
612 (not (string-equal service dbus-service-dbus))
613 (not (string-match "^:" service)))
614 (setq uname (dbus-get-name-owner bus service))
615 (setq uname service))
616
617 (setq rule (concat rule
618 (when uname (format ",sender='%s'" uname))
619 (when interface (format ",interface='%s'" interface))
620 (when signal (format ",member='%s'" signal))
621 (when path (format ",path='%s'" path))))
622
623 ;; Add arguments to the rule.
624 (if (or (stringp (car args)) (null (car args)))
625 ;; As backward compatibility option, we allow just strings.
626 (dolist (arg args)
627 (if (stringp arg)
628 (setq rule (concat rule (format ",arg%d='%s'" counter arg)))
629 (if arg (signal 'wrong-type-argument (list "Wrong argument" arg))))
630 (setq counter (1+ counter)))
631
632 ;; Parse keywords.
633 (while args
634 (setq
635 key (car args)
636 rule (concat
637 rule
638 (cond
639 ;; `:arg0' .. `:arg63', `:path0' .. `:path63'.
640 ((and (keywordp key)
641 (string-match
642 "^:\\(arg\\|path\\)\\([[:digit:]]+\\)$"
643 (symbol-name key)))
644 (setq counter (match-string 2 (symbol-name key))
645 args (cdr args)
646 value (car args))
647 (unless (and (<= counter 63) (stringp value))
648 (signal 'wrong-type-argument
649 (list "Wrong argument" key value)))
650 (format
651 ",arg%s%s='%s'"
652 counter
653 (if (string-equal (match-string 1 (symbol-name key)) "path")
654 "path" "")
655 value))
656 ;; `:arg-namespace', `:path-namespace'.
657 ((and (keywordp key)
658 (string-match
659 "^:\\(arg\\|path\\)-namespace$" (symbol-name key)))
660 (setq args (cdr args)
661 value (car args))
662 (unless (stringp value)
663 (signal 'wrong-type-argument
664 (list "Wrong argument" key value)))
665 (format
666 ",%s='%s'"
667 (if (string-equal (match-string 1 (symbol-name key)) "path")
668 "path_namespace" "arg0namespace")
669 value))
670 ;; `:eavesdrop'.
671 ((eq key :eavesdrop)
672 ",eavesdrop='true'")
673 (t (signal 'wrong-type-argument (list "Wrong argument" key)))))
674 args (cdr args))))
675
676 ;; Add the rule to the bus.
677 (condition-case err
678 (dbus-call-method
679 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
680 "AddMatch" rule)
681 (dbus-error
682 (if (not (string-match "eavesdrop" rule))
683 (signal (car err) (cdr err))
684 ;; The D-Bus spec says we shall fall back to a rule without eavesdrop.
685 (when dbus-debug (message "Removing eavesdrop from rule %s" rule))
686 (setq rule (replace-regexp-in-string ",eavesdrop='true'" "" rule))
687 (dbus-call-method
688 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
689 "AddMatch" rule))))
98c38bfc 690
dcbf5805 691 (when dbus-debug (message "Matching rule \"%s\" created" rule))
98c38bfc 692
dcbf5805
MA
693 ;; Create a hash table entry.
694 (setq key (list :signal bus interface signal)
695 key1 (list uname service path handler rule)
696 value (gethash key dbus-registered-objects-table))
697 (unless (member key1 value)
698 (puthash key (cons key1 value) dbus-registered-objects-table))
98c38bfc 699
dcbf5805
MA
700 ;; Return the object.
701 (list key (list service path handler))))
98c38bfc 702
dcbf5805
MA
703(defun dbus-register-method
704 (bus service path interface method handler &optional dont-register-service)
705 "Register for method METHOD on the D-Bus BUS.
706
707BUS is either a Lisp symbol, `:system' or `:session', or a string
708denoting the bus address.
709
710SERVICE is the D-Bus service name of the D-Bus object METHOD is
711registered for. It must be a known name (See discussion of
712DONT-REGISTER-SERVICE below).
713
714PATH is the D-Bus object path SERVICE is registered (See discussion of
715DONT-REGISTER-SERVICE below). INTERFACE is the interface offered by
716SERVICE. It must provide METHOD.
717
718HANDLER is a Lisp function to be called when a method call is
719received. It must accept the input arguments of METHOD. The return
720value of HANDLER is used for composing the returning D-Bus message.
721In case HANDLER shall return a reply message with an empty argument
722list, HANDLER must return the symbol `:ignore'.
723
724When DONT-REGISTER-SERVICE is non-nil, the known name SERVICE is not
725registered. This means that other D-Bus clients have no way of
726noticing the newly registered method. When interfaces are constructed
727incrementally by adding single methods or properties at a time,
728DONT-REGISTER-SERVICE can be used to prevent other clients from
729discovering the still incomplete interface."
730
731 ;; Register SERVICE.
732 (unless (or dont-register-service
733 (member service (dbus-list-names bus)))
734 (dbus-register-service bus service))
735
736 ;; Create a hash table entry. We use nil for the unique name,
737 ;; because the method might be called from anybody.
738 (let* ((key (list :method bus interface method))
739 (key1 (list nil service path handler))
740 (value (gethash key dbus-registered-objects-table)))
741
742 (unless (member key1 value)
743 (puthash key (cons key1 value) dbus-registered-objects-table))
744
745 ;; Return the object.
746 (list key (list service path handler))))
747
748(defun dbus-unregister-object (object)
749 "Unregister OBJECT from D-Bus.
750OBJECT must be the result of a preceding `dbus-register-method',
751`dbus-register-property' or `dbus-register-signal' call. It
752returns `t' if OBJECT has been unregistered, `nil' otherwise.
753
754When OBJECT identifies the last method or property, which is
755registered for the respective service, Emacs releases its
756association to the service from D-Bus."
757 ;; Check parameter.
758 (unless (and (consp object) (not (null (car object))) (consp (cdr object)))
759 (signal 'wrong-type-argument (list 'D-Bus object)))
760
761 ;; Find the corresponding entry in the hash table.
762 (let* ((key (car object))
763 (type (car key))
764 (bus (cadr key))
765 (value (cadr object))
766 (service (car value))
767 (entry (gethash key dbus-registered-objects-table))
768 ret)
769 ;; key has the structure (TYPE BUS INTERFACE MEMBER).
770 ;; value has the structure (SERVICE PATH [HANDLER]).
771 ;; entry has the structure ((UNAME SERVICE PATH MEMBER [RULE]) ...).
772 ;; MEMBER is either a string (the handler), or a cons cell (a
773 ;; property value). UNAME and property values are not taken into
774 ;; account for comparison.
775
776 ;; Loop over the registered functions.
777 (dolist (elt entry)
778 (when (equal
779 value
780 (butlast (cdr elt) (- (length (cdr elt)) (length value))))
781 (setq ret t)
782 ;; Compute new hash value. If it is empty, remove it from the
783 ;; hash table.
784 (unless (puthash key (delete elt entry) dbus-registered-objects-table)
785 (remhash key dbus-registered-objects-table))
786 ;; Remove match rule of signals.
787 (when (eq type :signal)
788 (dbus-call-method
789 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
790 "RemoveMatch" (nth 4 elt)))))
791
792 ;; Check, whether there is still a registered function or property
793 ;; for the given service. If not, unregister the service from the
794 ;; bus.
795 (when (and service (memq type '(:method :property))
796 (not (catch :found
797 (progn
798 (maphash
799 (lambda (k v)
800 (dolist (e v)
801 (ignore-errors
802 (and
803 ;; Bus.
804 (equal bus (cadr k))
805 ;; Service.
806 (string-equal service (cadr e))
807 ;; Non-empty object path.
f58e0fd5 808 (cl-caddr e)
dcbf5805
MA
809 (throw :found t)))))
810 dbus-registered-objects-table)
811 nil))))
812 (dbus-unregister-service bus service))
813 ;; Return.
814 ret))
ef6ce14c 815
5363d8ea 816\f
82697a45
MA
817;;; D-Bus type conversion.
818
819(defun dbus-string-to-byte-array (string)
820 "Transforms STRING to list (:array :byte c1 :byte c2 ...).
821STRING shall be UTF8 coded."
d665fff0
MA
822 (if (zerop (length string))
823 '(:array :signature "y")
824 (let (result)
825 (dolist (elt (string-to-list string) (append '(:array) result))
826 (setq result (append result (list :byte elt)))))))
82697a45
MA
827
828(defun dbus-byte-array-to-string (byte-array)
829 "Transforms BYTE-ARRAY into UTF8 coded string.
830BYTE-ARRAY must be a list of structure (c1 c2 ...)."
831 (apply 'string byte-array))
832
833(defun dbus-escape-as-identifier (string)
834 "Escape an arbitrary STRING so it follows the rules for a C identifier.
835The escaped string can be used as object path component, interface element
836component, bus name component or member name in D-Bus.
837
838The escaping consists of replacing all non-alphanumerics, and the
839first character if it's a digit, with an underscore and two
840lower-case hex digits:
841
842 \"0123abc_xyz\\x01\\xff\" -> \"_30123abc_5fxyz_01_ff\"
843
844i.e. similar to URI encoding, but with \"_\" taking the role of \"%\",
845and a smaller allowed set. As a special case, \"\" is escaped to
846\"_\".
847
848Returns the escaped string. Algorithm taken from
849telepathy-glib's `tp-escape-as-identifier'."
850 (if (zerop (length string))
851 "_"
852 (replace-regexp-in-string
853 "^[0-9]\\|[^A-Za-z0-9]"
854 (lambda (x) (format "_%2x" (aref x 0)))
855 string)))
856
857(defun dbus-unescape-from-identifier (string)
858 "Retrieve the original string from the encoded STRING.
859STRING must have been coded with `dbus-escape-as-identifier'"
860 (if (string-equal string "_")
861 ""
862 (replace-regexp-in-string
863 "_.."
864 (lambda (x) (format "%c" (string-to-number (substring x 1) 16)))
865 string)))
866
867\f
5363d8ea
MA
868;;; D-Bus events.
869
3a993e3d
MA
870(defun dbus-check-event (event)
871 "Checks whether EVENT is a well formed D-Bus event.
872EVENT is a list which starts with symbol `dbus-event':
873
98c38bfc 874 (dbus-event BUS TYPE SERIAL SERVICE PATH INTERFACE MEMBER HANDLER &rest ARGS)
3a993e3d 875
e49d337b 876BUS identifies the D-Bus the message is coming from. It is
e73f184c
MA
877either a Lisp symbol, `:system' or `:session', or a string
878denoting the bus address. TYPE is the D-Bus message type which
879has caused the event, SERIAL is the serial number of the received
880D-Bus message. SERVICE and PATH are the unique name and the
881object path of the D-Bus object emitting the message. INTERFACE
882and MEMBER denote the message which has been sent. HANDLER is
883the function which has been registered for this message. ARGS
884are the arguments passed to HANDLER, when it is called during
885event handling in `dbus-handle-event'.
3a993e3d
MA
886
887This function raises a `dbus-error' signal in case the event is
888not well formed."
889 (when dbus-debug (message "DBus-Event %s" event))
890 (unless (and (listp event)
891 (eq (car event) 'dbus-event)
5363d8ea 892 ;; Bus symbol.
e73f184c
MA
893 (or (symbolp (nth 1 event))
894 (stringp (nth 1 event)))
98c38bfc
MA
895 ;; Type.
896 (and (natnump (nth 2 event))
897 (< dbus-message-type-invalid (nth 2 event)))
e49d337b 898 ;; Serial.
98c38bfc 899 (natnump (nth 3 event))
5363d8ea 900 ;; Service.
98c38bfc 901 (or (= dbus-message-type-method-return (nth 2 event))
ba0b66b0 902 (= dbus-message-type-error (nth 2 event))
98c38bfc 903 (stringp (nth 4 event)))
e49d337b 904 ;; Object path.
98c38bfc 905 (or (= dbus-message-type-method-return (nth 2 event))
ba0b66b0 906 (= dbus-message-type-error (nth 2 event))
98c38bfc 907 (stringp (nth 5 event)))
e49d337b 908 ;; Interface.
98c38bfc 909 (or (= dbus-message-type-method-return (nth 2 event))
ba0b66b0 910 (= dbus-message-type-error (nth 2 event))
98c38bfc 911 (stringp (nth 6 event)))
e49d337b 912 ;; Member.
98c38bfc 913 (or (= dbus-message-type-method-return (nth 2 event))
ba0b66b0 914 (= dbus-message-type-error (nth 2 event))
98c38bfc 915 (stringp (nth 7 event)))
ef6ce14c 916 ;; Handler.
98c38bfc 917 (functionp (nth 8 event)))
3a993e3d
MA
918 (signal 'dbus-error (list "Not a valid D-Bus event" event))))
919
920;;;###autoload
921(defun dbus-handle-event (event)
922 "Handle events from the D-Bus.
5363d8ea 923EVENT is a D-Bus event, see `dbus-check-event'. HANDLER, being
98c38bfc 924part of the event, is called with arguments ARGS.
35b148ee 925If the HANDLER returns a `dbus-error', it is propagated as return message."
3a993e3d 926 (interactive "e")
98c38bfc
MA
927 (condition-case err
928 (let (result)
ba0b66b0 929 ;; We ignore not well-formed events.
98c38bfc 930 (dbus-check-event event)
ba0b66b0
MA
931 ;; Error messages must be propagated.
932 (when (= dbus-message-type-error (nth 2 event))
933 (signal 'dbus-error (nthcdr 9 event)))
934 ;; Apply the handler.
98c38bfc
MA
935 (setq result (apply (nth 8 event) (nthcdr 9 event)))
936 ;; Return a message when it is a message call.
937 (when (= dbus-message-type-method-call (nth 2 event))
938 (dbus-ignore-errors
3dec5c36
MA
939 (if (eq result :ignore)
940 (dbus-method-return-internal
dcbf5805 941 (nth 1 event) (nth 4 event) (nth 3 event))
3dec5c36 942 (apply 'dbus-method-return-internal
dcbf5805 943 (nth 1 event) (nth 4 event) (nth 3 event)
3dec5c36 944 (if (consp result) result (list result)))))))
98c38bfc
MA
945 ;; Error handling.
946 (dbus-error
947 ;; Return an error message when it is a message call.
948 (when (= dbus-message-type-method-call (nth 2 event))
949 (dbus-ignore-errors
950 (dbus-method-error-internal
dcbf5805 951 (nth 1 event) (nth 4 event) (nth 3 event) (cadr err))))
ba0b66b0 952 ;; Propagate D-Bus error messages.
d1069532 953 (run-hook-with-args 'dbus-event-error-functions event err)
ba0b66b0
MA
954 (when (or dbus-debug (= dbus-message-type-error (nth 2 event)))
955 (signal (car err) (cdr err))))))
3a993e3d
MA
956
957(defun dbus-event-bus-name (event)
958 "Return the bus name the event is coming from.
e73f184c
MA
959The result is either a Lisp symbol, `:system' or `:session', or a
960string denoting the bus address. EVENT is a D-Bus event, see
961`dbus-check-event'. This function raises a `dbus-error' signal
962in case the event is not well formed."
3a993e3d 963 (dbus-check-event event)
ef6ce14c 964 (nth 1 event))
3a993e3d 965
98c38bfc
MA
966(defun dbus-event-message-type (event)
967 "Return the message type of the corresponding D-Bus message.
968The result is a number. EVENT is a D-Bus event, see
969`dbus-check-event'. This function raises a `dbus-error' signal
970in case the event is not well formed."
971 (dbus-check-event event)
972 (nth 2 event))
973
e49d337b
MA
974(defun dbus-event-serial-number (event)
975 "Return the serial number of the corresponding D-Bus message.
98c38bfc
MA
976The result is a number. The serial number is needed for
977generating a reply message. EVENT is a D-Bus event, see
978`dbus-check-event'. This function raises a `dbus-error' signal
979in case the event is not well formed."
e49d337b 980 (dbus-check-event event)
98c38bfc 981 (nth 3 event))
e49d337b 982
3a993e3d 983(defun dbus-event-service-name (event)
5363d8ea 984 "Return the name of the D-Bus object the event is coming from.
3a993e3d
MA
985The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
986This function raises a `dbus-error' signal in case the event is
987not well formed."
988 (dbus-check-event event)
98c38bfc 989 (nth 4 event))
3a993e3d
MA
990
991(defun dbus-event-path-name (event)
992 "Return the object path of the D-Bus object the event is coming from.
993The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
994This function raises a `dbus-error' signal in case the event is
995not well formed."
996 (dbus-check-event event)
98c38bfc 997 (nth 5 event))
3a993e3d
MA
998
999(defun dbus-event-interface-name (event)
1000 "Return the interface name of the D-Bus object the event is coming from.
1001The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
1002This function raises a `dbus-error' signal in case the event is
1003not well formed."
1004 (dbus-check-event event)
98c38bfc 1005 (nth 6 event))
3a993e3d
MA
1006
1007(defun dbus-event-member-name (event)
1008 "Return the member name the event is coming from.
58179cce 1009It is either a signal name or a method name. The result is a
3a993e3d
MA
1010string. EVENT is a D-Bus event, see `dbus-check-event'. This
1011function raises a `dbus-error' signal in case the event is not
1012well formed."
1013 (dbus-check-event event)
98c38bfc 1014 (nth 7 event))
5363d8ea
MA
1015
1016\f
1017;;; D-Bus registered names.
3a993e3d 1018
07e52e08 1019(defun dbus-list-activatable-names (&optional bus)
3a993e3d 1020 "Return the D-Bus service names which can be activated as list.
07e52e08
MA
1021If BUS is left nil, `:system' is assumed. The result is a list
1022of strings, which is `nil' when there are no activatable service
1023names at all."
246a286b
MA
1024 (dbus-ignore-errors
1025 (dbus-call-method
07e52e08 1026 (or bus :system) dbus-service-dbus
246a286b 1027 dbus-path-dbus dbus-interface-dbus "ListActivatableNames")))
3a993e3d
MA
1028
1029(defun dbus-list-names (bus)
1030 "Return the service names registered at D-Bus BUS.
f636d3ca
MA
1031The result is a list of strings, which is `nil' when there are no
1032registered service names at all. Well known names are strings
1033like \"org.freedesktop.DBus\". Names starting with \":\" are
1034unique names for services."
246a286b
MA
1035 (dbus-ignore-errors
1036 (dbus-call-method
1037 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus "ListNames")))
3a993e3d
MA
1038
1039(defun dbus-list-known-names (bus)
1040 "Retrieve all services which correspond to a known name in BUS.
1041A service has a known name if it doesn't start with \":\"."
1042 (let (result)
1043 (dolist (name (dbus-list-names bus) result)
1044 (unless (string-equal ":" (substring name 0 1))
1045 (add-to-list 'result name 'append)))))
1046
1047(defun dbus-list-queued-owners (bus service)
f636d3ca
MA
1048 "Return the unique names registered at D-Bus BUS and queued for SERVICE.
1049The result is a list of strings, or `nil' when there are no
1050queued name owners service names at all."
246a286b
MA
1051 (dbus-ignore-errors
1052 (dbus-call-method
1053 bus dbus-service-dbus dbus-path-dbus
1054 dbus-interface-dbus "ListQueuedOwners" service)))
3a993e3d
MA
1055
1056(defun dbus-get-name-owner (bus service)
1057 "Return the name owner of SERVICE registered at D-Bus BUS.
f636d3ca 1058The result is either a string, or `nil' if there is no name owner."
246a286b
MA
1059 (dbus-ignore-errors
1060 (dbus-call-method
1061 bus dbus-service-dbus dbus-path-dbus
1062 dbus-interface-dbus "GetNameOwner" service)))
3a993e3d 1063
93fb0645
MA
1064(defun dbus-ping (bus service &optional timeout)
1065 "Check whether SERVICE is registered for D-Bus BUS.
1066TIMEOUT, a nonnegative integer, specifies the maximum number of
1067milliseconds `dbus-ping' must return. The default value is 25,000.
1068
1069Note, that this autoloads SERVICE if it is not running yet. If
1070it shall be checked whether SERVICE is already running, one shall
1071apply
1072
1073 \(member service \(dbus-list-known-names bus))"
4ba11bcb
MA
1074 ;; "Ping" raises a D-Bus error if SERVICE does not exist.
1075 ;; Otherwise, it returns silently with `nil'.
1076 (condition-case nil
1077 (not
93fb0645
MA
1078 (if (natnump timeout)
1079 (dbus-call-method
1080 bus service dbus-path-dbus dbus-interface-peer
1081 "Ping" :timeout timeout)
1082 (dbus-call-method
1083 bus service dbus-path-dbus dbus-interface-peer "Ping")))
4ba11bcb
MA
1084 (dbus-error nil)))
1085
f636d3ca
MA
1086\f
1087;;; D-Bus introspection.
3a993e3d 1088
f636d3ca 1089(defun dbus-introspect (bus service path)
35b148ee 1090 "Return all interfaces and sub-nodes of SERVICE,
f636d3ca
MA
1091registered at object path PATH at bus BUS.
1092
e73f184c
MA
1093BUS is either a Lisp symbol, `:system' or `:session', or a string
1094denoting the bus address. SERVICE must be a known service name,
1095and PATH must be a valid object path. The last two parameters
1096are strings. The result, the introspection data, is a string in
1097XML format."
205a7391 1098 ;; We don't want to raise errors.
246a286b 1099 (dbus-ignore-errors
dcbf5805
MA
1100 (dbus-call-method
1101 bus service path dbus-interface-introspectable "Introspect"
1102 :timeout 1000)))
3a993e3d 1103
f636d3ca
MA
1104(defun dbus-introspect-xml (bus service path)
1105 "Return the introspection data of SERVICE in D-Bus BUS at object path PATH.
1106The data are a parsed list. The root object is a \"node\",
1107representing the object path PATH. The root object can contain
1108\"interface\" and further \"node\" objects."
1109 ;; We don't want to raise errors.
1110 (xml-node-name
1111 (ignore-errors
1112 (with-temp-buffer
1113 (insert (dbus-introspect bus service path))
1114 (xml-parse-region (point-min) (point-max))))))
1115
1116(defun dbus-introspect-get-attribute (object attribute)
1117 "Return the ATTRIBUTE value of D-Bus introspection OBJECT.
1118ATTRIBUTE must be a string according to the attribute names in
1119the D-Bus specification."
1120 (xml-get-attribute-or-nil object (intern attribute)))
1121
1122(defun dbus-introspect-get-node-names (bus service path)
1123 "Return all node names of SERVICE in D-Bus BUS at object path PATH.
1124It returns a list of strings. The node names stand for further
1125object paths of the D-Bus service."
1126 (let ((object (dbus-introspect-xml bus service path))
1127 result)
1128 (dolist (elt (xml-get-children object 'node) result)
1129 (add-to-list
1130 'result (dbus-introspect-get-attribute elt "name") 'append))))
1131
1132(defun dbus-introspect-get-all-nodes (bus service path)
1133 "Return all node names of SERVICE in D-Bus BUS at object path PATH.
1134It returns a list of strings, which are further object paths of SERVICE."
1135 (let ((result (list path)))
1136 (dolist (elt
1137 (dbus-introspect-get-node-names bus service path)
1138 result)
1139 (setq elt (expand-file-name elt path))
1140 (setq result
1141 (append result (dbus-introspect-get-all-nodes bus service elt))))))
1142
1143(defun dbus-introspect-get-interface-names (bus service path)
1144 "Return all interface names of SERVICE in D-Bus BUS at object path PATH.
1145It returns a list of strings.
1146
1147There will be always the default interface
1148\"org.freedesktop.DBus.Introspectable\". Another default
1149interface is \"org.freedesktop.DBus.Properties\". If present,
1150\"interface\" objects can also have \"property\" objects as
1151children, beside \"method\" and \"signal\" objects."
1152 (let ((object (dbus-introspect-xml bus service path))
1153 result)
1154 (dolist (elt (xml-get-children object 'interface) result)
1155 (add-to-list
1156 'result (dbus-introspect-get-attribute elt "name") 'append))))
1157
1158(defun dbus-introspect-get-interface (bus service path interface)
1159 "Return the INTERFACE of SERVICE in D-Bus BUS at object path PATH.
1160The return value is an XML object. INTERFACE must be a string,
35b148ee
JB
1161element of the list returned by `dbus-introspect-get-interface-names'.
1162The resulting \"interface\" object can contain \"method\", \"signal\",
f636d3ca
MA
1163\"property\" and \"annotation\" children."
1164 (let ((elt (xml-get-children
1165 (dbus-introspect-xml bus service path) 'interface)))
1166 (while (and elt
1167 (not (string-equal
1168 interface
1169 (dbus-introspect-get-attribute (car elt) "name"))))
1170 (setq elt (cdr elt)))
1171 (car elt)))
1172
1173(defun dbus-introspect-get-method-names (bus service path interface)
1174 "Return a list of strings of all method names of INTERFACE.
1175SERVICE is a service of D-Bus BUS at object path PATH."
1176 (let ((object (dbus-introspect-get-interface bus service path interface))
1177 result)
1178 (dolist (elt (xml-get-children object 'method) result)
1179 (add-to-list
1180 'result (dbus-introspect-get-attribute elt "name") 'append))))
1181
1182(defun dbus-introspect-get-method (bus service path interface method)
1183 "Return method METHOD of interface INTERFACE as XML object.
1184It must be located at SERVICE in D-Bus BUS at object path PATH.
1185METHOD must be a string, element of the list returned by
1186`dbus-introspect-get-method-names'. The resulting \"method\"
1187object can contain \"arg\" and \"annotation\" children."
1188 (let ((elt (xml-get-children
1189 (dbus-introspect-get-interface bus service path interface)
1190 'method)))
1191 (while (and elt
1192 (not (string-equal
1193 method (dbus-introspect-get-attribute (car elt) "name"))))
1194 (setq elt (cdr elt)))
1195 (car elt)))
1196
1197(defun dbus-introspect-get-signal-names (bus service path interface)
1198 "Return a list of strings of all signal names of INTERFACE.
1199SERVICE is a service of D-Bus BUS at object path PATH."
1200 (let ((object (dbus-introspect-get-interface bus service path interface))
1201 result)
1202 (dolist (elt (xml-get-children object 'signal) result)
1203 (add-to-list
1204 'result (dbus-introspect-get-attribute elt "name") 'append))))
1205
1206(defun dbus-introspect-get-signal (bus service path interface signal)
1207 "Return signal SIGNAL of interface INTERFACE as XML object.
1208It must be located at SERVICE in D-Bus BUS at object path PATH.
1209SIGNAL must be a string, element of the list returned by
1210`dbus-introspect-get-signal-names'. The resulting \"signal\"
1211object can contain \"arg\" and \"annotation\" children."
1212 (let ((elt (xml-get-children
1213 (dbus-introspect-get-interface bus service path interface)
1214 'signal)))
1215 (while (and elt
1216 (not (string-equal
1217 signal (dbus-introspect-get-attribute (car elt) "name"))))
1218 (setq elt (cdr elt)))
1219 (car elt)))
1220
1221(defun dbus-introspect-get-property-names (bus service path interface)
1222 "Return a list of strings of all property names of INTERFACE.
1223SERVICE is a service of D-Bus BUS at object path PATH."
1224 (let ((object (dbus-introspect-get-interface bus service path interface))
1225 result)
1226 (dolist (elt (xml-get-children object 'property) result)
1227 (add-to-list
1228 'result (dbus-introspect-get-attribute elt "name") 'append))))
1229
1230(defun dbus-introspect-get-property (bus service path interface property)
1231 "This function returns PROPERTY of INTERFACE as XML object.
1232It must be located at SERVICE in D-Bus BUS at object path PATH.
1233PROPERTY must be a string, element of the list returned by
1234`dbus-introspect-get-property-names'. The resulting PROPERTY
1235object can contain \"annotation\" children."
1236 (let ((elt (xml-get-children
1237 (dbus-introspect-get-interface bus service path interface)
1238 'property)))
1239 (while (and elt
1240 (not (string-equal
1241 property
1242 (dbus-introspect-get-attribute (car elt) "name"))))
1243 (setq elt (cdr elt)))
1244 (car elt)))
1245
1246(defun dbus-introspect-get-annotation-names
1247 (bus service path interface &optional name)
1248 "Return all annotation names as list of strings.
1249If NAME is `nil', the annotations are children of INTERFACE,
1250otherwise NAME must be a \"method\", \"signal\", or \"property\"
1251object, where the annotations belong to."
1252 (let ((object
1253 (if name
1254 (or (dbus-introspect-get-method bus service path interface name)
1255 (dbus-introspect-get-signal bus service path interface name)
1256 (dbus-introspect-get-property bus service path interface name))
1257 (dbus-introspect-get-interface bus service path interface)))
1258 result)
1259 (dolist (elt (xml-get-children object 'annotation) result)
1260 (add-to-list
1261 'result (dbus-introspect-get-attribute elt "name") 'append))))
1262
1263(defun dbus-introspect-get-annotation
1264 (bus service path interface name annotation)
1265 "Return ANNOTATION as XML object.
1266If NAME is `nil', ANNOTATION is a child of INTERFACE, otherwise
1267NAME must be the name of a \"method\", \"signal\", or
1268\"property\" object, where the ANNOTATION belongs to."
1269 (let ((elt (xml-get-children
1270 (if name
1271 (or (dbus-introspect-get-method
1272 bus service path interface name)
1273 (dbus-introspect-get-signal
1274 bus service path interface name)
1275 (dbus-introspect-get-property
1276 bus service path interface name))
1277 (dbus-introspect-get-interface bus service path interface))
1278 'annotation)))
1279 (while (and elt
1280 (not (string-equal
1281 annotation
1282 (dbus-introspect-get-attribute (car elt) "name"))))
1283 (setq elt (cdr elt)))
1284 (car elt)))
1285
1286(defun dbus-introspect-get-argument-names (bus service path interface name)
1287 "Return a list of all argument names as list of strings.
1288NAME must be a \"method\" or \"signal\" object.
1289
1290Argument names are optional, the function can return `nil'
1291therefore, even if the method or signal has arguments."
1292 (let ((object
1293 (or (dbus-introspect-get-method bus service path interface name)
1294 (dbus-introspect-get-signal bus service path interface name)))
1295 result)
1296 (dolist (elt (xml-get-children object 'arg) result)
1297 (add-to-list
1298 'result (dbus-introspect-get-attribute elt "name") 'append))))
1299
1300(defun dbus-introspect-get-argument (bus service path interface name arg)
1301 "Return argument ARG as XML object.
35b148ee
JB
1302NAME must be a \"method\" or \"signal\" object. ARG must be a string,
1303element of the list returned by `dbus-introspect-get-argument-names'."
f636d3ca
MA
1304 (let ((elt (xml-get-children
1305 (or (dbus-introspect-get-method bus service path interface name)
1306 (dbus-introspect-get-signal bus service path interface name))
1307 'arg)))
1308 (while (and elt
1309 (not (string-equal
1310 arg (dbus-introspect-get-attribute (car elt) "name"))))
1311 (setq elt (cdr elt)))
1312 (car elt)))
1313
1314(defun dbus-introspect-get-signature
1315 (bus service path interface name &optional direction)
1316 "Return signature of a `method' or `signal', represented by NAME, as string.
1317If NAME is a `method', DIRECTION can be either \"in\" or \"out\".
1318If DIRECTION is `nil', \"in\" is assumed.
1319
1320If NAME is a `signal', and DIRECTION is non-`nil', DIRECTION must
1321be \"out\"."
1322 ;; For methods, we use "in" as default direction.
1323 (let ((object (or (dbus-introspect-get-method
1324 bus service path interface name)
1325 (dbus-introspect-get-signal
1326 bus service path interface name))))
1327 (when (and (string-equal
1328 "method" (dbus-introspect-get-attribute object "name"))
1329 (not (stringp direction)))
1330 (setq direction "in"))
1331 ;; In signals, no direction is given.
1332 (when (string-equal "signal" (dbus-introspect-get-attribute object "name"))
1333 (setq direction nil))
1334 ;; Collect the signatures.
1335 (mapconcat
4f91a816
SM
1336 (lambda (x)
1337 (let ((arg (dbus-introspect-get-argument
1338 bus service path interface name x)))
1339 (if (or (not (stringp direction))
1340 (string-equal
1341 direction
1342 (dbus-introspect-get-attribute arg "direction")))
1343 (dbus-introspect-get-attribute arg "type")
1344 "")))
f636d3ca
MA
1345 (dbus-introspect-get-argument-names bus service path interface name)
1346 "")))
3a993e3d 1347
f636d3ca
MA
1348\f
1349;;; D-Bus properties.
3a993e3d 1350
f636d3ca
MA
1351(defun dbus-get-property (bus service path interface property)
1352 "Return the value of PROPERTY of INTERFACE.
1353It will be checked at BUS, SERVICE, PATH. The result can be any
1354valid D-Bus value, or `nil' if there is no PROPERTY."
246a286b 1355 (dbus-ignore-errors
dcbf5805
MA
1356 ;; "Get" returns a variant, so we must use the `car'.
1357 (car
1358 (dbus-call-method
1359 bus service path dbus-interface-properties
1360 "Get" :timeout 500 interface property))))
f636d3ca
MA
1361
1362(defun dbus-set-property (bus service path interface property value)
1363 "Set value of PROPERTY of INTERFACE to VALUE.
1364It will be checked at BUS, SERVICE, PATH. When the value has
1365been set successful, the result is VALUE. Otherwise, `nil' is
1366returned."
1367 (dbus-ignore-errors
dcbf5805
MA
1368 ;; "Set" requires a variant.
1369 (dbus-call-method
1370 bus service path dbus-interface-properties
1371 "Set" :timeout 500 interface property (list :variant value))
1372 ;; Return VALUE.
1373 (dbus-get-property bus service path interface property)))
f636d3ca
MA
1374
1375(defun dbus-get-all-properties (bus service path interface)
1376 "Return all properties of INTERFACE at BUS, SERVICE, PATH.
1377The result is a list of entries. Every entry is a cons of the
1378name of the property, and its value. If there are no properties,
1379`nil' is returned."
f636d3ca 1380 (dbus-ignore-errors
b172ed20 1381 ;; "GetAll" returns "a{sv}".
f636d3ca 1382 (let (result)
b172ed20 1383 (dolist (dict
dcbf5805 1384 (dbus-call-method
b172ed20
MA
1385 bus service path dbus-interface-properties
1386 "GetAll" :timeout 500 interface)
f636d3ca 1387 result)
f58e0fd5 1388 (add-to-list 'result (cons (car dict) (cl-caadr dict)) 'append)))))
b172ed20
MA
1389
1390(defun dbus-register-property
6388924a
MA
1391 (bus service path interface property access value
1392 &optional emits-signal dont-register-service)
b172ed20
MA
1393 "Register property PROPERTY on the D-Bus BUS.
1394
e73f184c
MA
1395BUS is either a Lisp symbol, `:system' or `:session', or a string
1396denoting the bus address.
b172ed20
MA
1397
1398SERVICE is the D-Bus service name of the D-Bus. It must be a
6388924a
MA
1399known name (See discussion of DONT-REGISTER-SERVICE below).
1400
1401PATH is the D-Bus object path SERVICE is registered (See
1402discussion of DONT-REGISTER-SERVICE below). INTERFACE is the
1403name of the interface used at PATH, PROPERTY is the name of the
1404property of INTERFACE. ACCESS indicates, whether the property
1405can be changed by other services via D-Bus. It must be either
1406the symbol `:read' or `:readwrite'. VALUE is the initial value
1407of the property, it can be of any valid type (see
b172ed20
MA
1408`dbus-call-method' for details).
1409
1410If PROPERTY already exists on PATH, it will be overwritten. For
1411properties with access type `:read' this is the only way to
1412change their values. Properties with access type `:readwrite'
1413can be changed by `dbus-set-property'.
1414
1415The interface \"org.freedesktop.DBus.Properties\" is added to
1416PATH, including a default handler for the \"Get\", \"GetAll\" and
b1ce08da
MA
1417\"Set\" methods of this interface. When EMITS-SIGNAL is non-nil,
1418the signal \"PropertiesChanged\" is sent when the property is
6388924a
MA
1419changed by `dbus-set-property'.
1420
1421When DONT-REGISTER-SERVICE is non-nil, the known name SERVICE is
1422not registered. This means that other D-Bus clients have no way
1423of noticing the newly registered property. When interfaces are
1424constructed incrementally by adding single methods or properties
1425at a time, DONT-REGISTER-SERVICE can be used to prevent other
1426clients from discovering the still incomplete interface."
b172ed20 1427 (unless (member access '(:read :readwrite))
dcbf5805 1428 (signal 'wrong-type-argument (list "Access type invalid" access)))
b172ed20 1429
0a203b61 1430 ;; Add handlers for the three property-related methods.
b172ed20 1431 (dbus-register-method
0a203b61 1432 bus service path dbus-interface-properties "Get"
1a27c64e 1433 'dbus-property-handler 'dont-register)
b172ed20 1434 (dbus-register-method
1a27c64e
MA
1435 bus service path dbus-interface-properties "GetAll"
1436 'dbus-property-handler 'dont-register)
b172ed20 1437 (dbus-register-method
1a27c64e
MA
1438 bus service path dbus-interface-properties "Set"
1439 'dbus-property-handler 'dont-register)
0a203b61 1440
dcbf5805
MA
1441 ;; Register SERVICE.
1442 (unless (or dont-register-service (member service (dbus-list-names bus)))
0a203b61 1443 (dbus-register-service bus service))
b172ed20 1444
b1ce08da
MA
1445 ;; Send the PropertiesChanged signal.
1446 (when emits-signal
1447 (dbus-send-signal
1448 bus service path dbus-interface-properties "PropertiesChanged"
dcbf5805 1449 `((:dict-entry ,property (:variant ,value)))
b1ce08da
MA
1450 '(:array)))
1451
b172ed20
MA
1452 ;; Create a hash table entry. We use nil for the unique name,
1453 ;; because the property might be accessed from anybody.
dcbf5805 1454 (let ((key (list :property bus interface property))
b1ce08da
MA
1455 (val
1456 (list
1457 (list
1458 nil service path
1459 (cons
1460 (if emits-signal (list access :emits-signal) (list access))
1461 value)))))
b172ed20
MA
1462 (puthash key val dbus-registered-objects-table)
1463
1464 ;; Return the object.
1465 (list key (list service path))))
1466
1467(defun dbus-property-handler (&rest args)
35b148ee 1468 "Default handler for the \"org.freedesktop.DBus.Properties\" interface.
dcbf5805 1469It will be registered for all objects created by `dbus-register-property'."
b172ed20 1470 (let ((bus (dbus-event-bus-name last-input-event))
b1ce08da 1471 (service (dbus-event-service-name last-input-event))
b172ed20
MA
1472 (path (dbus-event-path-name last-input-event))
1473 (method (dbus-event-member-name last-input-event))
1474 (interface (car args))
1475 (property (cadr args)))
1476 (cond
1477 ;; "Get" returns a variant.
1478 ((string-equal method "Get")
dcbf5805 1479 (let ((entry (gethash (list :property bus interface property)
b1ce08da
MA
1480 dbus-registered-objects-table)))
1481 (when (string-equal path (nth 2 (car entry)))
dcbf5805 1482 `((:variant ,(cdar (last (car entry))))))))
b172ed20
MA
1483
1484 ;; "Set" expects a variant.
1485 ((string-equal method "Set")
b1ce08da 1486 (let* ((value (caar (cddr args)))
dcbf5805 1487 (entry (gethash (list :property bus interface property)
b1ce08da
MA
1488 dbus-registered-objects-table))
1489 ;; The value of the hash table is a list; in case of
1490 ;; properties it contains just one element (UNAME SERVICE
1491 ;; PATH OBJECT). OBJECT is a cons cell of a list, which
1492 ;; contains a list of annotations (like :read,
1493 ;; :read-write, :emits-signal), and the value of the
1494 ;; property.
1495 (object (car (last (car entry)))))
1496 (unless (consp object)
b172ed20
MA
1497 (signal 'dbus-error
1498 (list "Property not registered at path" property path)))
b1ce08da 1499 (unless (member :readwrite (car object))
b172ed20
MA
1500 (signal 'dbus-error
1501 (list "Property not writable at path" property path)))
dcbf5805 1502 (puthash (list :property bus interface property)
b1ce08da
MA
1503 (list (append (butlast (car entry))
1504 (list (cons (car object) value))))
b172ed20 1505 dbus-registered-objects-table)
b1ce08da
MA
1506 ;; Send the "PropertiesChanged" signal.
1507 (when (member :emits-signal (car object))
1508 (dbus-send-signal
1509 bus service path dbus-interface-properties "PropertiesChanged"
dcbf5805 1510 `((:dict-entry ,property (:variant ,value)))
b1ce08da
MA
1511 '(:array)))
1512 ;; Return empty reply.
b172ed20
MA
1513 :ignore))
1514
1515 ;; "GetAll" returns "a{sv}".
1516 ((string-equal method "GetAll")
1517 (let (result)
1518 (maphash
1519 (lambda (key val)
dcbf5805 1520 (when (and (equal (butlast key) (list :property bus interface))
b172ed20 1521 (string-equal path (nth 2 (car val)))
31bb373f 1522 (not (functionp (car (last (car val))))))
b172ed20
MA
1523 (add-to-list
1524 'result
1525 (list :dict-entry
1526 (car (last key))
1527 (list :variant (cdar (last (car val))))))))
1528 dbus-registered-objects-table)
052e28ac
MA
1529 ;; Return the result, or an empty array.
1530 (list :array (or result '(:signature "{sv}"))))))))
b172ed20 1531
dcbf5805
MA
1532\f
1533;;; D-Bus object manager.
1534
1535(defun dbus-get-all-managed-objects (bus service path)
1536 "Return all objects at BUS, SERVICE, PATH, and the children of PATH.
1537The result is a list of objects. Every object is a cons of an
1538existing path name, and the list of available interface objects.
1539An interface object is another cons, which car is the interface
1540name, and the cdr is the list of properties as returned by
205a7391 1541`dbus-get-all-properties' for that path and interface. Example:
dcbf5805
MA
1542
1543\(dbus-get-all-managed-objects :session \"org.gnome.SettingsDaemon\" \"/\")
1544
1545 => \(\(\"/org/gnome/SettingsDaemon/MediaKeys\"
1546 \(\"org.gnome.SettingsDaemon.MediaKeys\")
1547 \(\"org.freedesktop.DBus.Peer\")
1548 \(\"org.freedesktop.DBus.Introspectable\")
1549 \(\"org.freedesktop.DBus.Properties\")
1550 \(\"org.freedesktop.DBus.ObjectManager\"))
1551 \(\"/org/gnome/SettingsDaemon/Power\"
1552 \(\"org.gnome.SettingsDaemon.Power.Keyboard\")
1553 \(\"org.gnome.SettingsDaemon.Power.Screen\")
1554 \(\"org.gnome.SettingsDaemon.Power\"
1555 \(\"Icon\" . \". GThemedIcon battery-full-charged-symbolic \")
1556 \(\"Tooltip\" . \"Laptop battery is charged\"))
1557 \(\"org.freedesktop.DBus.Peer\")
1558 \(\"org.freedesktop.DBus.Introspectable\")
1559 \(\"org.freedesktop.DBus.Properties\")
1560 \(\"org.freedesktop.DBus.ObjectManager\"))
1561 ...)
1562
1563If possible, \"org.freedesktop.DBus.ObjectManager.GetManagedObjects\"
1564is used for retrieving the information. Otherwise, the information
1565is collected via \"org.freedesktop.DBus.Introspectable.Introspect\"
1566and \"org.freedesktop.DBus.Properties.GetAll\", which is slow."
1567 (let ((result
1568 ;; Direct call. Fails, if the target does not support the
1569 ;; object manager interface.
1570 (dbus-ignore-errors
1571 (dbus-call-method
1572 bus service path dbus-interface-objectmanager
1573 "GetManagedObjects" :timeout 1000))))
1574
1575 (if result
1576 ;; Massage the returned structure.
1577 (dolist (entry result result)
1578 ;; "a{oa{sa{sv}}}".
1579 (dolist (entry1 (cdr entry))
1580 ;; "a{sa{sv}}".
1581 (dolist (entry2 entry1)
1582 ;; "a{sv}".
1583 (if (cadr entry2)
1584 ;; "sv".
1585 (dolist (entry3 (cadr entry2))
f58e0fd5 1586 (setcdr entry3 (cl-caadr entry3)))
dcbf5805
MA
1587 (setcdr entry2 nil)))))
1588
1589 ;; Fallback: collect the information. Slooow!
1590 (dolist (object
1591 (dbus-introspect-get-all-nodes bus service path)
1592 result)
1593 (let (result1)
1594 (dolist
1595 (interface
1596 (dbus-introspect-get-interface-names bus service object)
1597 result1)
1598 (add-to-list
1599 'result1
1600 (cons interface
1601 (dbus-get-all-properties bus service object interface))))
1602 (when result1
1603 (add-to-list 'result (cons object result1))))))))
1604
1605(defun dbus-managed-objects-handler ()
1606 "Default handler for the \"org.freedesktop.DBus.ObjectManager\" interface.
1607It will be registered for all objects created by `dbus-register-method'."
1608 (let* ((last-input-event last-input-event)
1609 (bus (dbus-event-bus-name last-input-event))
1610 (service (dbus-event-service-name last-input-event))
1611 (path (dbus-event-path-name last-input-event)))
1612 ;; "GetManagedObjects" returns "a{oa{sa{sv}}}".
1613 (let (interfaces result)
1614
1615 ;; Check for object path wildcard interfaces.
1616 (maphash
1617 (lambda (key val)
1618 (when (and (equal (butlast key 2) (list :method bus))
1619 (null (nth 2 (car-safe val))))
1620 (add-to-list 'interfaces (nth 2 key))))
1621 dbus-registered-objects-table)
1622
1623 ;; Check all registered object paths.
1624 (maphash
1625 (lambda (key val)
1626 (let ((object (or (nth 2 (car-safe val)) ""))
1627 (interface (nth 2 key)))
1628 (when (and (equal (butlast key 2) (list :method bus))
1629 (string-prefix-p path object))
1630 (dolist (interface (cons (nth 2 key) interfaces))
1631 (unless (assoc object result)
1632 (add-to-list 'result (list object)))
1633 (unless (assoc interface (cdr (assoc object result)))
1634 (setcdr
1635 (assoc object result)
1636 (append
1637 (list (cons
1638 interface
1639 ;; We simulate "org.freedesktop.DBus.Properties.GetAll"
1640 ;; by using an appropriate D-Bus event.
1641 (let ((last-input-event
1642 (append
1643 (butlast last-input-event 4)
1644 (list object dbus-interface-properties
1645 "GetAll" 'dbus-property-handler))))
1646 (dbus-property-handler interface))))
1647 (cdr (assoc object result)))))))))
1648 dbus-registered-objects-table)
1649
1650 ;; Return the result, or an empty array.
1651 (list
1652 :array
1653 (or
1654 (mapcar
1655 (lambda (x)
1656 (list
1657 :dict-entry :object-path (car x)
1658 (cons :array (mapcar (lambda (y) (cons :dict-entry y)) (cdr x)))))
1659 result)
1660 '(:signature "{oa{sa{sv}}}"))))))
1661
b172ed20 1662 \f
dcbf5805 1663;; Initialize `:system' and `:session' buses. This adds their file
720c7cd6
MA
1664;; descriptors to input_wait_mask, in order to detect incoming
1665;; messages immediately.
9e846523
MA
1666(when (featurep 'dbusbind)
1667 (dbus-ignore-errors
dcbf5805
MA
1668 (dbus-init-bus :system))
1669 (dbus-ignore-errors
9e846523 1670 (dbus-init-bus :session)))
720c7cd6 1671
3a993e3d
MA
1672(provide 'dbus)
1673
dcbf5805
MA
1674;;; TODO:
1675
1676;; * Implement org.freedesktop.DBus.ObjectManager.InterfacesAdded and
1677;; org.freedesktop.DBus.ObjectManager.InterfacesRemoved.
1678
3a993e3d 1679;;; dbus.el ends here