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