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.
This commit is contained in:
Michael Albinus 2020-09-27 18:59:04 +02:00
parent f2a6bbefa9
commit 4155ca273a
3 changed files with 251 additions and 149 deletions

View file

@ -63,6 +63,7 @@ another. An overview of D-Bus can be found at
* Signals:: Sending and receiving signals.
* Alternative Buses:: Alternative buses and environments.
* Errors and Events:: Errors and events.
* Monitoring Events:: Monitoring events.
* Index:: Index including concepts, functions, variables.
* GNU Free Documentation License:: The license for this documentation.
@ -162,12 +163,13 @@ registered names. Internally they use the basic interface
@defun dbus-list-activatable-names &optional bus
This function returns the D-Bus service names, which can be activated
for @var{bus}. It must be either the symbol @code{:system} (the
default) or the symbol @code{:session}. An activatable service is
for @var{bus}. It must be either the keyword @code{:system} (the
default) or the keyword @code{:session}. An activatable service is
described in a service registration file. Under GNU/Linux, such files
are located at @file{/usr/share/dbus-1/system-services/} (for the
@code{:system} bus) or @file{/usr/share/dbus-1/services/}. An
activatable service is not necessarily registered at @var{bus} already.
activatable service is not necessarily registered at @var{bus}
already.
The result is a list of strings, which is @code{nil} when there are no
activatable service names at all. Example:
@ -186,7 +188,7 @@ there are no registered service names at all. Well known names are
strings like @samp{org.freedesktop.DBus}. Names starting with
@samp{:} are unique names for services.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}.
@end defun
@ -196,7 +198,7 @@ known name in @var{bus}. A service has a known name if it doesn't
start with @samp{:}. The result is a list of strings, which is
@code{nil} when there are no known names at all.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}.
@end defun
@ -206,7 +208,7 @@ For a given service, registered at D-Bus @var{bus} under the name
result is a list of strings, or @code{nil} when there are no queued
names for @var{service} at all.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}. @var{service} must be a known service name as
string.
@end defun
@ -217,7 +219,7 @@ For a given service, registered at D-Bus @var{bus} under the name
owner. The result is a string, or @code{nil} when there is no name
owner of @var{service}.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}. @var{service} must be a known service name as
string.
@end defun
@ -228,7 +230,7 @@ registered at D-Bus @var{bus}. If @var{service} has not yet started,
it is autostarted if possible. The result is either @code{t} or
@code{nil}.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}. @var{service} must be a string. @var{timeout}, a
nonnegative integer, specifies the maximum number of milliseconds
before @code{dbus-ping} must return. The default value is 25,000.
@ -256,7 +258,7 @@ it, you can instead write:
This function returns the unique name, under which Emacs is registered
at D-Bus @var{bus}, as a string.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}.
@end defun
@ -375,7 +377,7 @@ must be strings.
This function returns all interfaces and sub-nodes of @var{service},
registered at object path @var{path} at bus @var{bus}.
@var{bus} must be either the symbol @code{:system} or the symbol
@var{bus} must be either the keyword @code{:system} or the keyword
@code{:session}. @var{service} must be a known service name, and
@var{path} must be a valid object path. The last two parameters are
strings. The result, the introspection data, is a string in XML
@ -747,8 +749,8 @@ or @var{property} cannot be read, an error is raised. Example:
@defun dbus-set-property bus service path interface property [type] value
This function sets the value of @var{property} of @var{interface} to
@var{value}. It will be checked at @var{bus}, @var{service},
@var{path}. @var{value} can be preceded by a @var{type} symbol. When
the value is successfully set, this function returns @var{value}.
@var{path}. @var{value} can be preceded by a @var{type} keyword.
When the value is successfully set, this function returns @var{value}.
Example:
@lisp
@ -999,8 +1001,8 @@ Other Lisp objects, like symbols or hash tables, are not accepted as
input parameters.
If it is necessary to use another D-Bus type, a corresponding type
symbol can be prepended to the corresponding Lisp object. Basic D-Bus
types are represented by the type symbols @code{:byte},
keyword can be prepended to the corresponding Lisp object. Basic
D-Bus types are represented by the type keywords @code{:byte},
@code{:boolean}, @code{:int16}, @code{:uint16}, @code{:int32},
@code{:uint32}, @code{:int64}, @code{:uint64}, @code{:double},
@code{:string}, @code{:object-path}, @code{:signature} and
@ -1040,7 +1042,7 @@ If typed explicitly, a non-@code{nil} boolean value like
@code{:boolean 'symbol} is handled like @code{t} or @code{:boolean t}.
A D-Bus compound type is always represented as a list. The @sc{car}
of this list can be the type symbol @code{:array}, @code{:variant},
of this list can be the type keyword @code{:array}, @code{:variant},
@code{:struct} or @code{:dict-entry}, which would result in a
corresponding D-Bus container. @code{:array} is optional, because
this is the default compound D-Bus type for a list.
@ -1215,7 +1217,7 @@ parameters from the object.
@defun dbus-call-method bus service path interface method &optional :timeout timeout &rest args
@anchor{dbus-call-method}
This function calls @var{method} on the D-Bus @var{bus}. @var{bus} is
either the symbol @code{:system} or the symbol @code{:session}.
either the keyword @code{:system} or the keyword @code{:session}.
@var{service} is the D-Bus service name to be used. @var{path} is the
D-Bus object path, @var{service} is registered at. @var{interface} is
@ -1308,8 +1310,8 @@ emulate the @code{lshal} command on GNU/Linux systems:
@defun dbus-call-method-asynchronously bus service path interface method handler &optional :timeout timeout &rest args
This function calls @var{method} on the D-Bus @var{bus}
asynchronously. @var{bus} is either the symbol @code{:system} or the
symbol @code{:session}.
asynchronously. @var{bus} is either the keyword @code{:system} or the
keyword @code{:session}.
@var{service} is the D-Bus service name to be used. @var{path} is the
D-Bus object path, @var{service} is registered at. @var{interface} is
@ -1369,7 +1371,7 @@ the following functions:
This function registers the known name @var{service} on D-Bus
@var{bus}.
@var{bus} is either the symbol @code{:system} or the symbol
@var{bus} is either the keyword @code{:system} or the keyword
@code{:session}.
@var{service} is the service name to be registered on the D-Bus. It
@ -1405,7 +1407,7 @@ We already are the primary owner.
This function unregisters all objects from D-Bus @var{bus}, that were
registered by Emacs for @var{service}.
@var{bus} is either the symbol @code{:system} or the symbol
@var{bus} is either the keyword @code{:system} or the keyword
@code{:session}.
@var{service} is the D-Bus service name of the D-Bus. It must be a
@ -1452,7 +1454,7 @@ The interface namespace @code{org.gnu.Emacs} used by Emacs.
With this function, an application registers @var{method} on the D-Bus
@var{bus}.
@var{bus} is either the symbol @code{:system} or the symbol
@var{bus} is either the keyword @code{:system} or the keyword
@code{:session}.
@var{service} is the D-Bus service name of the D-Bus object
@ -1477,8 +1479,8 @@ cons cell, @var{handler} can return this object directly, instead of
returning a list containing the object.
If @var{handler} returns a reply message with an empty argument list,
@var{handler} must return the symbol @code{:ignore} in order
to distinguish it from @code{nil} (the boolean false).
@var{handler} must return the keyword @code{:ignore} in order to
distinguish it from @code{nil} (the boolean false).
If @var{handler} detects an error, it shall return the list
@code{(:error @var{error-name} @var{error-message})}.
@ -1580,7 +1582,7 @@ The test then runs
With this function, an application declares a @var{property} on the D-Bus
@var{bus}.
@var{bus} is either the symbol @code{:system} or the symbol
@var{bus} is either the keyword @code{:system} or the keyword
@code{:session}.
@var{service} is the D-Bus service name of the D-Bus. It must be a
@ -1593,12 +1595,12 @@ discussion of @var{dont-register-service} below).
@var{property} is the name of the property of @var{interface}.
@var{access} indicates, whether the property can be changed by other
services via D-Bus. It must be either the symbol @code{:read},
services via D-Bus. It must be either the keyword @code{:read},
@code{:write} or @code{:readwrite}.
@var{value} is the initial value of the property, it can be of any
valid type (@xref{dbus-call-method}, for details). @var{value} can be
preceded by a @var{type} symbol.
preceded by a @var{type} keyword.
If @var{property} already exists on @var{path}, it will be
overwritten. For properties with access type @code{:read} this is the
@ -1707,7 +1709,7 @@ This function is similar to @code{dbus-call-method}. The difference
is, that there are no returning output parameters.
The function emits @var{signal} on the D-Bus @var{bus}. @var{bus} is
either the symbol @code{:system} or the symbol @code{:session}. It
either the keyword @code{:system} or the keyword @code{:session}. It
doesn't matter whether another object has registered for @var{signal}.
Signals can be unicast or broadcast messages. For broadcast messages,
@ -1735,7 +1737,7 @@ arguments. They are converted into D-Bus types as described in
With this function, an application registers for a signal on the D-Bus
@var{bus}.
@var{bus} is either the symbol @code{:system} or the symbol
@var{bus} is either the keyword @code{:system} or the keyword
@code{:session}.
@var{service} is the D-Bus service name used by the sending D-Bus
@ -1837,18 +1839,17 @@ Until now, we have spoken about the system and the session buses,
which are the default buses to be connected to. However, it is
possible to connect to any bus with a known address. This is a UNIX
domain or TCP/IP socket. Everywhere, where a @var{bus} is mentioned
as argument of a function (the symbol @code{:system} or the symbol
as argument of a function (the keyword @code{:system} or the keyword
@code{:session}), this address can be used instead. The connection to
this bus must be initialized first.
@defun dbus-init-bus bus &optional private
This function establishes the connection to D-Bus @var{bus}.
@var{bus} can be either the symbol @code{:system} or the symbol
@var{bus} can be either the keyword @code{:system} or the keyword
@code{: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 @file{dbus.el}, there is no need to call it
again.
corresponding bus. For the system and session buses, this function is
called when loading @file{dbus.el}, there is no need to call it again.
The function returns the number of connections this Emacs session has
established to the @var{bus} under the same unique name
@ -1860,11 +1861,12 @@ established.
When @var{private} is non-@code{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
@code{:system} and @code{:session} buses, because other Emacs Lisp
packages might already use this connection to those buses.
at the @var{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 @var{bus} is the keyword @code{:system} or
the keyword @code{:session}, the new private connection is identified
by the keywords @code{:system-private} or @code{:session-private},
respectively.
Example: You initialize a connection to the AT-SPI bus on your host:
@ -1907,7 +1909,7 @@ is supported depends on the bus daemon configuration, however.
This function sets the value of the @var{bus} environment
@var{variable} to @var{value}.
@var{bus} is either a Lisp symbol, @code{:system} or @code{:session},
@var{bus} is either a Lisp keyword, @code{:system} or @code{:session},
or a string denoting the bus address. Both @var{variable} and
@var{value} should be strings.
@ -1973,23 +1975,31 @@ Events, , , elisp}. They are retrieved only, when Emacs runs in
interactive mode. The generated event has this form:
@lisp
(dbus-event @var{bus} @var{type} @var{serial} @var{service} @var{path} @var{interface} @var{member} @var{handler}
&rest @var{args})
(dbus-event @var{bus} @var{type} @var{serial} @var{service} @var{destination} @var{path} @var{interface} @var{member}
@var{handler} &rest @var{args})
@end lisp
@var{bus} identifies the D-Bus the message is coming from. It is
either the symbol @code{:system} or the symbol @code{:session}.
either a Lisp keyword, @code{:system}, @code{:session},
@code{:system-private} or @code{:session-private}, or a string
denoting the bus address.
@var{type} is the D-Bus message type which has caused the event. It
can be @code{dbus-message-type-invalid},
@code{dbus-message-type-method-call},
@code{dbus-message-type-method-return},
@code{dbus-message-type-error}, or @code{dbus-message-type-signal}.
@var{serial} is the serial number of the received D-Bus message.
@var{serial} is the serial number of the received D-Bus message,
unless @var{type} is equal @code{dbus-message-type-error}.
@var{service} and @var{path} are the unique name and the object path
of the D-Bus object emitting the message. @var{interface} and
@var{member} denote the message which has been sent.
of the D-Bus object emitting the message. @var{destination} is the
D-Bus name the message is dedicated to, or @code{nil} in case the
message is a broadcast signal.
@var{interface} and @var{member} denote the message which has been
sent. When @var{type} is @code{dbus-message-type-error}, @var{member}
is the error name.
@var{handler} is the callback function which has been registered for
this message (@pxref{Signals}). @var{args} are the typed arguments as
@ -2010,7 +2020,7 @@ callback function in order to retrieve the information from the event.
@defun dbus-event-bus-name event
This function returns the bus name @var{event} is coming from. The
result is either the symbol @code{:system} or the symbol
result is either the keyword @code{:system} or the keyword
@code{:session}.
@end defun
@ -2029,6 +2039,11 @@ This function returns the unique name of the D-Bus object @var{event}
is coming from.
@end defun
@defun dbus-event-destination-name event
This function returns the unique name of the D-Bus object @var{event}
is dedicated to.
@end defun
@defun dbus-event-path-name event
This function returns the object path of the D-Bus object @var{event}
is coming from.
@ -2044,6 +2059,16 @@ This function returns the member name of the D-Bus object @var{event}
is coming from. It is either a signal name or a method name.
@end defun
@defun dbus-event-handler event
This function returns the handler the D-Bus object @var{event} is
applied with.
@end defun
@defun dbus-event-arguments event
This function returns the arguments the D-Bus object @var{event} is
carrying on.
@end defun
D-Bus errors are not propagated during event handling, because it is
usually not desired. D-Bus errors in events can be made visible by
setting the variable @code{dbus-debug} to non-@code{nil}. They can
@ -2074,6 +2099,54 @@ D-Bus applications running. They should therefore check carefully,
whether a given D-Bus error is related to them.
@node Monitoring Events
@chapter Monitoring events.
@cindex monitoring
@defun dbus-register-monitor bus &optional handler &key type sender destination path interface member
This function registers @var{handler} for monitor events on the D-Bus
@var{bus}.
@var{bus} is either a Lisp keyword, @code{:system} or @code{:session},
or a string denoting the bus address.
@findex dbus-monitor-handler
@var{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 @var{handler} is
@code{nil}, the default handler @code{dbus-monitor-handler} is
applied. This default handler behaves similar to the
@command{dbus-monitor} program.
The other arguments are keyword-value pairs. @code{:type @var{type}}
defines the message type to be monitored. If given, it must be equal
one of the strings @samp{method_call}, @samp{method_return},
@samp{error} or @samp{signal}.
@code{:sender @var{sender}} and @code{:destination @var{destination}}
are D-Bus names. They can be unique names, or well-known service
names.
@code{:path @var{path}} is the D-Bus object to be monitored.
@code{:interface @var{interface}} is the name of an interface, and
@code{:member @var{member}} is either a method name, a signal name, or
an error name.
The following form shows all D-Bus events on the session bus in buffer
@samp{*D-Bus Monitor*}:
@lisp
(dbus-register-monitor :session)
@end lisp
And this form restricts the monitoring on D-Bus errors:
@lisp
(dbus-register-monitor :session nil :type "error")
@end lisp
@end defun
@node Index
@unnumbered Index

View file

@ -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.
SERVICE is the D-Bus service name of the D-Bus. It must be a
known name (see discussion of DONT-REGISTER-SERVICE below).
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.
BUS is either a Lisp keyword, `:system' or `:session', or a
string denoting the bus address.
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."
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.
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\".
`: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

View file

@ -66,6 +66,7 @@
(ert-deftest dbus-test01-type-conversion ()
"Check type conversion functions."
(skip-unless dbus--test-enabled-session-bus)
(let ((ustr "0123abc_xyz\x01\xff")
(mstr "Grüß Göttin"))
(should
@ -97,6 +98,7 @@
(ert-deftest dbus-test01-basic-types ()
"Check basic D-Bus type arguments."
(skip-unless dbus--test-enabled-session-bus)
;; Unknown keyword.
(should-error
(dbus-check-arguments :session dbus--test-service :keyword)
@ -288,6 +290,8 @@
(ert-deftest dbus-test01-compound-types ()
"Check basic D-Bus type arguments."
(skip-unless dbus--test-enabled-session-bus)
;; `:array'. It contains several elements of the same type.
(should (dbus-check-arguments :session dbus--test-service '("string")))
(should (dbus-check-arguments :session dbus--test-service '(:array "string")))
@ -327,6 +331,11 @@
(dbus-check-arguments
:session dbus--test-service
'(:array (:dict-entry :string "string" :boolean t))))
;; This is an alternative syntax. FIXME: Shall this be supported?
(should
(dbus-check-arguments
:session dbus--test-service
'(:array :dict-entry (:string "string" :boolean t))))
;; The second element is `nil' (implicitly). FIXME: Is this right?
(should
(dbus-check-arguments