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