summaryrefslogtreecommitdiff
path: root/lisp/net/dbus.el
diff options
context:
space:
mode:
authorMichael Albinus <michael.albinus@gmx.de>2020-09-27 18:59:04 +0200
committerMichael Albinus <michael.albinus@gmx.de>2020-09-27 18:59:04 +0200
commit4155ca273ade47bc7e19fe4af1f41c4e764a59ba (patch)
tree27cb915a5768177b297966f083718d2c76b1a58d /lisp/net/dbus.el
parentf2a6bbefa919c0fcde66c0a8fb54aa5fb499de65 (diff)
downloademacs-4155ca273ade47bc7e19fe4af1f41c4e764a59ba.tar.gz
Document D-Bus monitoring
* doc/misc/dbus.texi: Replace "symbol" by "keyword" where appropriate. (Alternative Buses): Adapt dbus-init-bus description. (Errors and Events): Adapt dbus-event structure. New defuns dbus-event-destination-name, dbus-event-handler and dbus-event-arguments. (Monitoring Events): New node. * lisp/net/dbus.el: Replace "symbol" by "keyword" where appropriate. (cl-lib): Require. (dbus-register-monitor): Adapt the argument list. (dbus-monitor-handler): Extend. (dbus-init-bus): Adapt docstring. * test/lisp/net/dbus-tests.el (dbus-test01-compound-types): Skip if needed. Extend test.
Diffstat (limited to 'lisp/net/dbus.el')
-rw-r--r--lisp/net/dbus.el224
1 files changed, 122 insertions, 102 deletions
diff --git a/lisp/net/dbus.el b/lisp/net/dbus.el
index da47e5bc7f2..b1bea55d982 100644
--- a/lisp/net/dbus.el
+++ b/lisp/net/dbus.el
@@ -51,6 +51,7 @@
(unless (boundp 'dbus-debug)
(defvar dbus-debug nil))
+(require 'cl-lib)
(require 'seq)
(require 'subr-x)
(require 'xml)
@@ -245,7 +246,7 @@ caught in `condition-case' by `dbus-error'.")
(defvar dbus-return-values-table (make-hash-table :test #'equal)
"Hash table for temporarily storing arguments of reply messages.
A key in this hash table is a list (:serial BUS SERIAL), like in
-`dbus-registered-objects-table'. BUS is either a Lisp symbol,
+`dbus-registered-objects-table'. BUS is either a Lisp keyword,
`:system' or `:session', or a string denoting the bus address.
SERIAL is the serial number of the reply message.
@@ -279,8 +280,8 @@ The result will be made available in `dbus-return-values-table'."
(defun dbus-call-method (bus service path interface method &rest args)
"Call METHOD on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
SERVICE is the D-Bus service name to be used. PATH is the D-Bus
object path SERVICE is registered at. INTERFACE is an interface
@@ -301,8 +302,8 @@ converted into D-Bus types via the following rules:
string => DBUS_TYPE_STRING
list => DBUS_TYPE_ARRAY
-All arguments can be preceded by a type symbol. For details about
-type symbols, see Info node `(dbus)Type Conversion'.
+All arguments can be preceded by a type keyword. For details
+about type keywords, see Info node `(dbus)Type Conversion'.
`dbus-call-method' returns the resulting values of METHOD as a list of
Lisp objects. The type conversion happens the other direction as for
@@ -405,8 +406,8 @@ object is returned instead of a list containing this single Lisp object.
(bus service path interface method handler &rest args)
"Call METHOD on the D-Bus BUS asynchronously.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
SERVICE is the D-Bus service name to be used. PATH is the D-Bus
object path SERVICE is registered at. INTERFACE is an interface
@@ -431,8 +432,8 @@ converted into D-Bus types via the following rules:
string => DBUS_TYPE_STRING
list => DBUS_TYPE_ARRAY
-All arguments can be preceded by a type symbol. For details about
-type symbols, see Info node `(dbus)Type Conversion'.
+All arguments can be preceded by a type keyword. For details
+about type keywords, see Info node `(dbus)Type Conversion'.
If HANDLER is a Lisp function, the function returns a key into the
hash table `dbus-registered-objects-table'. The corresponding entry
@@ -472,9 +473,9 @@ Example:
(defun dbus-send-signal (bus service path interface signal &rest args)
"Send signal SIGNAL on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address. The signal is sent from the D-Bus object
-Emacs is registered at BUS.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address. The signal is sent from the
+D-Bus object Emacs is registered at BUS.
SERVICE is the D-Bus name SIGNAL is sent to. It can be either a known
name or a unique name. If SERVICE is nil, the signal is sent as
@@ -492,8 +493,8 @@ converted into D-Bus types via the following rules:
string => DBUS_TYPE_STRING
list => DBUS_TYPE_ARRAY
-All arguments can be preceded by a type symbol. For details about
-type symbols, see Info node `(dbus)Type Conversion'.
+All arguments can be preceded by a type keyword. For details
+about type keywords, see Info node `(dbus)Type Conversion'.
Example:
@@ -586,8 +587,9 @@ hash table."
(defun dbus-setenv (bus variable value)
"Set the value of the BUS environment variable named VARIABLE to VALUE.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address. Both VARIABLE and VALUE should be strings.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address. Both VARIABLE and VALUE should
+be strings.
Normally, services inherit the environment of the BUS daemon. This
function adds to or modifies that environment when activating services.
@@ -601,8 +603,8 @@ Some bus instances, such as `:system', may disable setting the environment."
(defun dbus-register-service (bus service &rest flags)
"Register known name SERVICE on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
SERVICE is the D-Bus service name that should be registered. It must
be a known name.
@@ -663,8 +665,9 @@ placed in the queue.
(defun dbus-unregister-service (bus service)
"Unregister all objects related to SERVICE from D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address. SERVICE must be a known service name.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address. SERVICE must be a known service
+name.
The function returns a keyword, indicating the result of the
operation. One of the following keywords is returned:
@@ -699,8 +702,8 @@ queue of this service."
(bus service path interface signal handler &rest args)
"Register for a signal on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
SERVICE is the D-Bus service name used by the sending D-Bus object.
It can be either a known name or the unique name of the D-Bus object
@@ -854,8 +857,8 @@ Example:
(bus service path interface method handler &optional dont-register-service)
"Register METHOD on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
SERVICE is the D-Bus service name of the D-Bus object METHOD is
registered for. It must be a known name (see discussion of
@@ -869,7 +872,7 @@ HANDLER is a Lisp function to be called when a method call is
received. It must accept the input arguments of METHOD. The
return value of HANDLER is used for composing the returning D-Bus
message. If HANDLER returns a reply message with an empty
-argument list, HANDLER must return the symbol `:ignore' in order
+argument list, HANDLER must return the keyword `:ignore' in order
to distinguish it from nil (the boolean false).
If HANDLER detects an error, it shall return the list `(:error
@@ -1039,7 +1042,7 @@ EVENT is a list which starts with symbol `dbus-event':
INTERFACE MEMBER HANDLER &rest ARGS)
BUS identifies the D-Bus the message is coming from. It is
-either a Lisp symbol, `:system', `:session', `:systemp-private'
+either a Lisp keyword, `:system', `:session', `:systemp-private'
or `:session-private', or a string denoting the bus address.
TYPE is the D-Bus message type which has caused the event, SERIAL
@@ -1048,7 +1051,7 @@ equal `dbus-message-type-method-return' or `dbus-message-type-error'.
SERVICE and PATH are the unique name and the object path of the
D-Bus object emitting the message. DESTINATION is the D-Bus name
-the message is dedicated to, or nil in case thje message is a
+the message is dedicated to, or nil in case the message is a
broadcast signal.
INTERFACE and MEMBER denote the message which has been sent.
@@ -1064,7 +1067,7 @@ formed."
(when dbus-debug (message "DBus-Event %s" event))
(unless (and (listp event)
(eq (car event) 'dbus-event)
- ;; Bus symbol.
+ ;; Bus keyword.
(or (keywordp (nth 1 event))
(stringp (nth 1 event)))
;; Type.
@@ -1181,8 +1184,8 @@ If the HANDLER returns a `dbus-error', it is propagated as return message."
(defun dbus-event-bus-name (event)
"Return the bus name the event is coming from.
-The result is either a Lisp symbol, `:system' or `:session', or a
-string denoting the bus address. EVENT is a D-Bus event, see
+The result is either a Lisp keyword, `:system' or `:session', or
+a string denoting the bus address. EVENT is a D-Bus event, see
`dbus-check-event'. This function signals a `dbus-error' if the
event is not well formed."
(dbus-check-event event)
@@ -1375,11 +1378,11 @@ It will be registered for all objects created by `dbus-register-service'."
"Return all interfaces and sub-nodes of SERVICE,
registered at object path PATH at bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address. SERVICE must be a known service name,
-and PATH must be a valid object path. The last two parameters
-are strings. The result, the introspection data, is a string in
-XML format."
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address. SERVICE must be a known service
+name, and PATH must be a valid object path. The last two
+parameters are strings. The result, the introspection data, is a
+string in XML format."
;; We don't want to raise errors.
(let (dbus-debug)
(dbus-ignore-errors
@@ -1596,7 +1599,7 @@ valid D-Bus value, or nil if there is no PROPERTY, or PROPERTY cannot be read."
(defun dbus-set-property (bus service path interface property &rest args)
"Set value of PROPERTY of INTERFACE to VALUE.
It will be checked at BUS, SERVICE, PATH. VALUE can be preceded
-by a TYPE symbol. When the value is successfully set, and the
+by a TYPE keyword. When the value is successfully set, and the
property's access type is not `:write', return VALUE. Otherwise,
return nil.
@@ -1651,8 +1654,8 @@ Filter out matching PATH."
(bus service path interface property access &rest args)
"Register PROPERTY on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
SERVICE is the D-Bus service name of the D-Bus. It must be a
known name (see discussion of DONT-REGISTER-SERVICE below).
@@ -1662,11 +1665,11 @@ discussion of DONT-REGISTER-SERVICE below). INTERFACE is the
name of the interface used at PATH, PROPERTY is the name of the
property of INTERFACE. ACCESS indicates, whether the property
can be changed by other services via D-Bus. It must be either
-the symbol `:read', `:write' or `:readwrite'.
+the keyword `:read', `:write' or `:readwrite'.
VALUE is the initial value of the property, it can be of any
valid type (see `dbus-call-method' for details). VALUE can be
-preceded by a TYPE symbol.
+preceded by a TYPE keyword.
If PROPERTY already exists on PATH, it will be overwritten. For
properties with access type `:read' this is the only way to
@@ -1688,7 +1691,7 @@ clients from discovering the still incomplete interface.
\(dbus-register-property BUS SERVICE PATH INTERFACE PROPERTY ACCESS \
[TYPE] VALUE &optional EMITS-SIGNAL DONT-REGISTER-SERVICE)"
- (let (;; Read basic type symbol.
+ (let (;; Read basic type keyword.
(type (when (keywordp (car args)) (pop args)))
(value (pop args))
(emits-signal (pop args))
@@ -1973,68 +1976,53 @@ It will be registered for all objects created by `dbus-register-service'."
result)
'(:signature "{oa{sa{sv}}}"))))))
-(defun dbus-register-monitor
- (bus &optional service path interface member handler &rest args)
+(cl-defun dbus-register-monitor
+ (bus &optional handler &key type sender destination path interface member)
"Register HANDLER for monitor events on the D-Bus BUS.
-BUS is either a Lisp symbol, `:system' or `:session', or a string
-denoting the bus address.
+BUS is either a Lisp keyword, `:system' or `:session', or a
+string denoting the bus address.
-SERVICE is the D-Bus service name of the D-Bus. It must be a
-known name (see discussion of DONT-REGISTER-SERVICE below).
+HANDLER is the function to be called when a monitor event
+arrives. It is called with the `args' slot of the monitor event,
+which are stripped off the type keywords. If HANDLER is nil, the
+default handler `dbus-monitor-handler' is applied.
-PATH is the D-Bus object path SERVICE is registered at (see
-discussion of DONT-REGISTER-SERVICE below). INTERFACE is the
-name of the interface used at PATH. MEMBER is either a method
-name, a signal name, or an error name.
+The other arguments are keyword-value pairs. `:type TYPE'
+defines the message type to be monitored. If given, it must be
+equal one of the strings \"method_call\", \"method_return\",
+\"error\" or \"signal\".
-HANDLER is the function to be called when a monitor event
-arrives. If nil, the default handler `dbus-monitor-handler' is
-applied. It is called with ARGS as arguments."
+`:sender SENDER' and `:destination DESTINATION' are D-Bus names.
+They can be unique names, or well-known service names.
+`:path PATH' is the D-Bus object to be monitored. `:interface
+INTERFACE' is the name of an interface, and `:member MEMBER' is
+either a method name, a signal name, or an error name."
(let ((bus-private (if (eq bus :system) :system-private
(if (eq bus :session) :session-private bus)))
- keyword type rule1 rule2 key key1 value)
+ rule key key1 value)
(unless handler (setq handler #'dbus-monitor-handler))
- ;; Read arguments.
- (while args
- (when (keywordp (setq keyword (pop args)))
- (cond
- ((eq :type keyword)
- ;; Must be "signal", "method_call", "method_return", or "error".
- (setq type (pop args))))))
- ;; Compose rules.
- (setq rule1
- (or
- (string-join
- (delq nil
- (list (when service (format "sender='%s'" service))
- (when path (format "path='%s'" path))
- (when interface (format "interface='%s'" interface))
- (when member (format "member='%s'" member))
- (when type (format "type='%s'" type))))
- ",")
- "")
- rule2
- (when service
- (string-join
- (delq nil
- (list (format "destination='%s'" service)
- (when path (format "path='%s'" path))
- (when interface (format "interface='%s'" interface))
- (when member (format "member='%s'" member))
- (when type (format "type='%s'" type))))
- ",")))
+ ;; Compose rule.
+ (setq rule
+ (string-join
+ (delq nil (mapcar
+ (lambda (item)
+ (when (cdr item)
+ (format "%s='%s'" (car item) (cdr item))))
+ `(("type" . ,type) ("sender" . ,sender)
+ ("destination" . ,destination) ("path" . ,path)
+ ("interface" . ,interface) ("member" . ,member))))
+ ",")
+ rule (or rule ""))
(unless (ignore-errors (dbus-get-unique-name bus-private))
(dbus-init-bus bus 'private))
(dbus-call-method
bus-private dbus-service-dbus dbus-path-dbus dbus-interface-monitoring
- "BecomeMonitor"
- (append `(:array :string ,rule1) (when rule2 `(:string ,rule2)))
- :uint32 0)
+ "BecomeMonitor" `(:array :string ,rule) :uint32 0)
- (when dbus-debug (message "Matching rule \"%s\" created" rule1))
+ (when dbus-debug (message "Matching rule \"%s\" created" rule))
;; Create a hash table entry.
(setq key (list :monitor bus-private)
@@ -2046,14 +2034,19 @@ applied. It is called with ARGS as arguments."
(when dbus-debug (message "%s" dbus-registered-objects-table))
;; Return the object.
- (list key (list service path handler))))
+ (list key key1)))
(defun dbus-monitor-handler (&rest _args)
"Default handler for the \"org.freedesktop.DBus.Monitoring.BecomeMonitor\" interface.
-It will be applied all objects created by `dbus-register-monitor'."
+It will be applied for all objects created by
+`dbus-register-monitor' which don't declare an own handler.."
(with-current-buffer (get-buffer-create "*D-Bus Monitor*")
(special-mode)
+ ;; Move forward and backward between messages.
+ (local-set-key [?n] #'forward-paragraph)
+ (local-set-key [?p] #'backward-paragraph)
(let* ((inhibit-read-only t)
+ (point (point))
(eobp (eobp))
(event last-input-event)
(type (dbus-event-message-type event))
@@ -2079,7 +2072,33 @@ It will be applied all objects created by `dbus-register-monitor'."
sender destination serial path interface member))
(dolist (arg arguments)
(pp (dbus-flatten-types arg) (current-buffer)))
- (insert "\n"))
+ (insert "\n")
+ ;; Show byte arrays as string.
+ (goto-char point)
+ (while (re-search-forward
+ "(:array\\( :byte [[:digit:]]+\\)+)" nil 'noerror)
+ (put-text-property
+ (match-beginning 0) (match-end 0)
+ 'help-echo (dbus-byte-array-to-string (read (match-string 0)))))
+ ;; Show fixed numbers.
+ (goto-char point)
+ (while (re-search-forward
+ (concat
+ (regexp-opt
+ '(":int16" ":uint16" ":int32" ":uint32" ":int64" ":uint64"))
+ " \\([-+[:digit:]]+\\)")
+ nil 'noerror)
+ (put-text-property
+ (match-beginning 1) (match-end 1)
+ 'help-echo
+ (format
+ "#o%o, #x%X" (read (match-string 1)) (read (match-string 1)))))
+ ;; Show floating numbers.
+ (goto-char point)
+ (while (re-search-forward ":double \\([-+.[:digit:]]+\\)" nil 'noerror)
+ (put-text-property
+ (match-beginning 1) (match-end 1)
+ 'help-echo (format "%e" (read (match-string 1))))))
(when eobp
(goto-char (point-max))))))
@@ -2115,10 +2134,11 @@ pending at the time of disconnect to fail."
(defun dbus-init-bus (bus &optional private)
"Establish the connection to D-Bus BUS.
-BUS can be either the symbol `:system' or the symbol `:session', or it
-can be a string denoting the address of the corresponding bus. For
-the system and session buses, this function is called when loading
-`dbus.el', there is no need to call it again.
+BUS can be either the keyword `:system' or the keyword
+`:session', or it can be a string denoting the address of the
+corresponding bus. For the system and session buses, this
+function is called when loading `dbus.el', there is no need to
+call it again.
The function returns the number of connections this Emacs session
has established to the BUS under the same unique name (see
@@ -2128,13 +2148,13 @@ example, if Emacs is linked with the GTK+ toolkit, and it runs in
a GTK+-aware environment like GNOME, another connection might
already be established.
-When PRIVATE is non-nil, a new connection is established instead of
-reusing an existing one. It results in a new unique name at the bus.
-This can be used, if it is necessary to distinguish from another
-connection used in the same Emacs process, like the one established by
-GTK+. It should be used with care for at least the `:system' and
-`:session' buses, because other Emacs Lisp packages might already use
-this connection to those buses."
+When PRIVATE is non-nil, a new connection is established instead
+of reusing an existing one. It results in a new unique name at
+the bus. This can be used, if it is necessary to distinguish
+from another connection used in the same Emacs process, like the
+one established by GTK+. If BUS is the keyword `:system' or the
+keyword `:session', the new connection is identified by the
+keywords `:system-private' or `:session-private', respectively."
(or (featurep 'dbusbind)
(signal 'dbus-error (list "Emacs not compiled with dbus support")))
(prog1