X-Git-Url: http://git.hcoop.net/bpt/emacs.git/blobdiff_plain/b03f96dc5a6651d1dc84b81b2a15cad6908b9809..55033558b53324f4a63b6887ea50d8a2f235f7aa:/doc/misc/dbus.texi diff --git a/doc/misc/dbus.texi b/doc/misc/dbus.texi index 392f9a85da..c012647144 100644 --- a/doc/misc/dbus.texi +++ b/doc/misc/dbus.texi @@ -6,25 +6,19 @@ @c %**end of header @copying -Copyright @copyright{} 2007, 2008 Free Software Foundation, Inc. +Copyright @copyright{} 2007, 2008, 2009 Free Software Foundation, Inc. @quotation Permission is granted to copy, distribute and/or modify this document -under the terms of the GNU Free Documentation License, Version 1.2 or +under the terms of the GNU Free Documentation License, Version 1.3 or any later version published by the Free Software Foundation; with no -Invariant Sections, with the Front-Cover texts being ``A GNU -Manual'', and with the Back-Cover Texts as in (a) below. A copy of the -license is included in the section entitled ``GNU Free Documentation -License'' in the Emacs manual. - -(a) The FSF's Back-Cover Text is: ``You have freedom to copy and modify -this GNU Manual, like GNU software. Copies published by the Free -Software Foundation raise funds for GNU development.'' - -This document is part of a collection distributed under the GNU Free -Documentation License. If you want to distribute this document -separately from the collection, you can do so by adding a copy of the -license to the document, as described in section 6 of the license. +Invariant Sections, with the Front-Cover texts being ``A GNU Manual'', +and with the Back-Cover Texts as in (a) below. A copy of the license +is included in the section entitled ``GNU Free Documentation License''. + +(a) The FSF's Back-Cover Text is: ``You have the freedom to copy and +modify this GNU manual. Buying copies from the FSF supports it in +developing GNU and promoting software freedom.'' @end quotation @end copying @@ -33,6 +27,7 @@ license to the document, as described in section 6 of the license. * D-Bus: (dbus). Using D-Bus in Emacs. @end direntry + @node Top, Overview, (dir), (dir) @top D-Bus integration in Emacs @@ -47,15 +42,17 @@ be found at @uref{http://dbus.freedesktop.org/}. @menu * Overview:: An overview of D-Bus. -* Inspection:: Inspection of the bus names. +* Inspection:: Inspection of D-Bus services. * Type Conversion:: Mapping Lisp types and D-Bus types. * Synchronous Methods:: Calling methods in a blocking way. +* Asynchronous Methods:: Calling methods non-blocking. * Receiving Method Calls:: Offering own methods. * Signals:: Sending and receiving signals. * Errors and Events:: Errors and events. * GNU Free Documentation License:: The license for this documentation. @end menu + @node Overview @chapter An overview of D-Bus @cindex overview @@ -107,9 +104,22 @@ name could be @samp{org.gnu.Emacs.TextEditor} or @node Inspection -@chapter Inspection of the bus names. +@chapter Inspection of D-Bus services. @cindex inspection +@menu +* Bus names:: Discovering D-Bus names. +* Introspection:: Knowing the details of D-Bus services. +* Nodes and Interfaces:: Detecting object paths and interfaces. +* Methods and Signal:: Applying the functionality. +* Properties and Annotations:: What else to know about interfaces. +* Arguments and Signatures:: The final details. +@end menu + + +@node Bus names +@section Bus names. + There are several basic functions which inspect the buses for registered names. Internally they use the basic interface @samp{org.freedesktop.DBus}, which is supported by all objects of a bus. @@ -193,16 +203,126 @@ is returned as string. @code{:session}. @end defun + +@node Introspection +@section Knowing the details of D-Bus services. + +D-Bus services publish their interfaces. This can be retrieved and +analyzed during runtime, in order to understand the used +implementation. + +The resulting introspection data are in XML format. The root +introspection element is always a @code{node} element. It might have +a @code{name} attribute, which denotes the (absolute) object path an +interface is introspected. + +The root @code{node} element may have @code{node} and @code{interface} +children. A child @code{node} element must have a @code{name} +attribute, this case it is the relative object path to the root +@code{node} element. + +An @code{interface} element has just one attribute, @code{name}, which +is the full name of that interface. The default interface +@samp{org.freedesktop.DBus.Introspectable} is always present. Example: + +@example + + + @dots{} + + + @dots{} + + + @dots{} + + + @dots{} + + + + + + +@end example + +Children of an @code{interface} element can be @code{method}, +@code{signal} and @code{property} elements. A @code{method} element +stands for a D-Bus method of the surrounding interface. The element +itself has a @code{name} attribute, showing the method name. Children +elements @code{arg} stand for the arguments of a method. Example: + +@example + + + + + + + + + + + + + +@end example + +@code{arg} elements can have the attributes @code{name}, @code{type} +and @code{direction}. The @code{name} attribute is optional. The +@code{type} attribute stands for the @dfn{signature} of the argument +in D-Bus. For a discussion of D-Bus types and their Lisp +representation see @ref{Type Conversion}.@footnote{D-Bus signatures +are explained in the D-Bus specification +@uref{http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures}.} +The @code{direction} attribute of an @code{arg} element can be only +@samp{in} or @samp{out}; in case it is omitted, it defaults to +@samp{in}. + +A @code{signal} element of an @code{interface} has a similar +structure. The @code{direction} attribute of an @code{arg} child +element can be only @samp{out} here; which is also the default value. +Example: + +@example + + + + +@end example + +A @code{property} element has no @code{arg} child +element. It just has the attributes @code{name}, @code{type} and +@code{access}, which are all mandatory. The @code{access} attribute +allows the values @samp{readwrite}, @samp{read}, and @samp{write}. +Example: + +@example + +@end example + +@code{annotation} elements can be children of @code{interface}, +@code{method}, @code{signal}, and @code{property} elements. Unlike +properties, which can change their values during lifetime of a D-Bus +object, annotations are static. Often they are used for code +generators of D-Bus langugae bindings. Example: + +@example + +@end example + +Annotations have just @code{name} and @code{value} attributes, both +must be strings. + @defun dbus-introspect bus service path -Objects can publish there interfaces to the D-Bus. This function -returns all interfaces of @var{service}, registered at object path -@var{path} at bus @var{bus}. +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 @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 -format. Example: +format. Example: @lisp (dbus-introspect @@ -210,45 +330,506 @@ format. Example: "/org/freedesktop/Hal/devices/computer") @result{} " + "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" + "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> - - - + + + @dots{} - - - + + + @dots{} " @end lisp -This example informs us, that the service @code{org.freedesktop.Hal} -at object path @code{/org/freedesktop/Hal/devices/computer} offers the -interface @code{org.freedesktop.Hal.Device} (and 2 other interfaces +This example informs us, that the service @samp{org.freedesktop.Hal} +at object path @samp{/org/freedesktop/Hal/devices/computer} offers the +interface @samp{org.freedesktop.Hal.Device} (and 2 other interfaces not documented here). This interface contains the method -@code{GetAllProperties}, which needs no input parameters, but returns +@samp{GetAllProperties}, which needs no input parameters, but returns as output parameter an array of dictionary entries (key-value pairs). Every dictionary entry has a string as key, and a variant as value. The interface offers also a signal, which returns 2 parameters: an integer, and an array consisting of elements which are a struct of a -string and 2 boolean values. - -Such type descriptions are called @dfn{signature} in D-Bus. For a -discussion of D-Bus types and their Lisp representation see @ref{Type -Conversion}.@footnote{D-Bus signatures are explained in the D-Bus -specification -@uref{http://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-signatures}. -The interfaces of the service @code{org.freedesktop.Hal} are described -at +string and 2 boolean values.@footnote{ The interfaces of the service +@samp{org.freedesktop.Hal} are described at @uref{http://people.freedesktop.org/~david/hal-spec/hal-spec.html#interfaces}.} @end defun +@defun dbus-introspect-xml bus service path +This function has the same intention as function +@code{dbus-introspect}. The returned value is a parsed XML tree, +which can be used for further analysis. Example: + +@lisp +(dbus-introspect-xml + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main") + +@result{} (node ((name . "/org/freedesktop/xesam/searcher/main")) + (interface ((name . "org.freedesktop.xesam.Search")) + (method ((name . "GetHitData")) + (arg ((name . "search") (type . "s") (direction . "in"))) + (arg ((name . "hit_ids") (type . "au") (direction . "in"))) + (arg ((name . "fields") (type . "as") (direction . "in"))) + (arg ((name . "hit_data") (type . "aav") (direction . "out"))) + ) + @dots{} + (signal ((name . "HitsAdded")) + (arg ((name . "search") (type . "s"))) + (arg ((name . "count") (type . "u"))) + ) + ) + @dots{} + ) +@end lisp +@end defun + +@defun dbus-introspect-get-attribute object attribute +It returns the @var{attribute} value of a D-Bus introspection +@var{object}. @var{object} can be every subtree of a parsed XML tree +as retrieved with @code{dbus-introspect-xml}. @var{attribute} must be +a string according to the attribute names in the D-Bus specification. +Example: + +@lisp +(dbus-introspect-get-attribute + (dbus-introspect-xml :system "org.freedesktop.SystemToolsBackends" + "/org/freedesktop/SystemToolsBackends/UsersConfig") + "name") + +@result{} "/org/freedesktop/SystemToolsBackends/UsersConfig" +@end lisp + +If @var{object} has no @var{attribute}, the function returns nil. +@end defun + + +@node Nodes and Interfaces +@section Detecting object paths and interfaces. + +The first elements, to be introspected for a D-Bus object, are further +object paths and interfaces. + +@defun dbus-introspect-get-node-names bus service path +All node names of @var{service} in D-Bus @var{bus} at object path +@var{path} are returned as list of strings. Example: + +@lisp +(dbus-introspect-get-node-names + :session "org.gnome.seahorse" "/org/gnome/seahorse") + +@result{} ("crypto" "keys") +@end lisp + +The node names stand for further object paths of the D-Bus +@var{service}, relative to @var{path}. In the example, +@samp{/org/gnome/seahorse/crypto} and @samp{/org/gnome/seahorse/keys} +are also object paths of the D-Bus service @samp{org.gnome.seahorse}. +@end defun + +@defun dbus-introspect-get-all-nodes bus service path +This function returns all node names of @var{service} in D-Bus +@var{bus} at object path @var{path}. It returns a list of strings +with all object paths of @var{service}, starting at @var{path}. +Example: + +@lisp +(dbus-introspect-get-all-nodes :session "org.gnome.seahorse" "/") + +@result{} ("/" "/org" "/org/gnome" "/org/gnome/seahorse" + "/org/gnome/seahorse/crypto" + "/org/gnome/seahorse/keys" + "/org/gnome/seahorse/keys/openpgp" + "/org/gnome/seahorse/keys/openpgp/local" + "/org/gnome/seahorse/keys/openssh" + "/org/gnome/seahorse/keys/openssh/local") +@end lisp +@end defun + +@defun dbus-introspect-get-interface-names bus service path +There will be returned a list strings of all interface names of +@var{service} in D-Bus @var{bus} at object path @var{path}. This list +will contain the default interface @samp{org.freedesktop.DBus.Introspectable}. + +Another default interface is @samp{org.freedesktop.DBus.Properties}. +If present, @code{interface} elements can also have @code{property} +children. Example: + +@lisp +(dbus-introspect-get-interface-names + :system "org.freedesktop.Hal" + "/org/freedesktop/Hal/devices/computer") + +@result{} ("org.freedesktop.DBus.Introspectable" + "org.freedesktop.Hal.Device" + "org.freedesktop.Hal.Device.SystemPowerManagement" + "org.freedesktop.Hal.Device.CPUFreq") +@end lisp +@end defun + +@defun dbus-introspect-get-interface bus service path interface +Return @var{interface} of @var{service} in D-Bus @var{bus} at object +path @var{path}. The return value is an XML element. @var{interface} +must be a string, element of the list returned by +@code{dbus-introspect-get-interface-names}. Example: + +@lisp +(dbus-introspect-get-interface + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search") + +@result{} (interface ((name . "org.freedesktop.xesam.Search")) + (method ((name . "GetHitData")) + (arg ((name . "search") (type . "s") (direction . "in"))) + (arg ((name . "hit_ids") (type . "au") (direction . "in"))) + (arg ((name . "fields") (type . "as") (direction . "in"))) + (arg ((name . "hit_data") (type . "aav") (direction . "out"))) + ) + @dots{} + (signal ((name . "HitsAdded")) + (arg ((name . "search") (type . "s"))) + (arg ((name . "count") (type . "u"))) + ) + ) +@end lisp +@end defun + +@noindent +With these functions, it is possible to retrieve all introspection +data from a running system: + +@lisp +(with-current-buffer (switch-to-buffer "*introspect*") + (erase-buffer) + (dolist (service (dbus-list-known-names :session)) + (dolist (path (dbus-introspect-get-all-nodes :session service "/")) + ;; We want to introspect only elements, which have more than + ;; the default interface "org.freedesktop.DBus.Introspectable". + (when (delete + "org.freedesktop.DBus.Introspectable" + (dbus-introspect-get-interface-names :session service path)) + (insert (message "\nservice: \"%s\" path: \"%s\"\n" service path) + (dbus-introspect :session service path)) + (redisplay t))))) +@end lisp + + +@node Methods and Signal +@section Applying the functionality. + +Methods and signals are the communicatione means to D-Bus. The +following functions return their specifications. + +@defun dbus-introspect-get-method-names bus service path interface +Return a list of strings of all method names of @var{interface} of +@var{service} in D-Bus @var{bus} at object path @var{path}. Example: + +@lisp +(dbus-introspect-get-method-names + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search") + +@result{} ("GetState" "StartSearch" "GetHitCount" "GetHits" "NewSession" + "CloseSession" "GetHitData" "SetProperty" "NewSearch" + "GetProperty" "CloseSearch") +@end lisp +@end defun + +@defun dbus-introspect-get-method bus service path interface method +This function returns @var{method} of @var{interface} as XML element. +It must be located at @var{service} in D-Bus @var{bus} at object path +@var{path}. @var{method} must be a string, element of the list +returned by @code{dbus-introspect-get-method-names}. Example: + +@lisp +(dbus-introspect-get-method + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search" "GetHitData") + +@result{} (method ((name . "GetHitData")) + (arg ((name . "search") (type . "s") (direction . "in"))) + (arg ((name . "hit_ids") (type . "au") (direction . "in"))) + (arg ((name . "fields") (type . "as") (direction . "in"))) + (arg ((name . "hit_data") (type . "aav") (direction . "out"))) + ) +@end lisp +@end defun + +@defun dbus-introspect-get-signal-names bus service path interface +Return a list of strings of all signal names of @var{interface} of +@var{service} in D-Bus @var{bus} at object path @var{path}. Example: + +@lisp +(dbus-introspect-get-signal-names + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search") + +@result{} ("StateChanged" "SearchDone" "HitsModified" + "HitsRemoved" "HitsAdded") +@end lisp +@end defun + +@defun dbus-introspect-get-signal bus service path interface signal +This function returns @var{signal} of @var{interface} as XML element. +It must be located at @var{service} in D-Bus @var{bus} at object path +@var{path}. @var{signal} must be a string, element of the list +returned by @code{dbus-introspect-get-signal-names}. Example: + +@lisp +(dbus-introspect-get-signal + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search" "HitsAdded") + +@result{} (signal ((name . "HitsAdded")) + (arg ((name . "search") (type . "s"))) + (arg ((name . "count") (type . "u"))) + ) +@end lisp +@end defun + + +@node Properties and Annotations +@section What else to know about interfaces. + +Interfaces can have properties. These can be exposed via the +@samp{org.freedesktop.DBus.Properties} interface@footnote{See +@uref{http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties}}. +That is, properties can be retrieved and changed during lifetime of an +element. + +Annotations, on the other hand, are static values for an element. +Often, they are used to instruct generators, how to generate code from +the interface for a given language binding. + +@defun dbus-introspect-get-property-names bus service path interface +Return a list of strings with all property names of @var{interface} of +@var{service} in D-Bus @var{bus} at object path @var{path}. Example: + +@lisp +(dbus-introspect-get-property-names + :session "org.kde.kded" "/modules/networkstatus" + "org.kde.Solid.Networking.Client") + +@result{} ("Status") +@end lisp + +If an interface declares properties, the corresponding element supports +also the @samp{org.freedesktop.DBus.Properties} interface. +@end defun + +@defun dbus-introspect-get-property bus service path interface property +This function returns @var{property} of @var{interface} as XML element. +It must be located at @var{service} in D-Bus @var{bus} at object path +@var{path}. @var{property} must be a string, element of the list +returned by @code{dbus-introspect-get-property-names}. + +A @var{property} value can be retrieved by the function +@code{dbus-introspect-get-attribute}. Example: + +@lisp +(dbus-introspect-get-property + :session "org.kde.kded" "/modules/networkstatus" + "org.kde.Solid.Networking.Client" "Status") + +@result{} (property ((access . "read") (type . "u") (name . "Status"))) + +(dbus-introspect-get-attribute + (dbus-introspect-get-property + :session "org.kde.kded" "/modules/networkstatus" + "org.kde.Solid.Networking.Client" "Status") + "access") + +@result{} "read" +@end lisp +@end defun + +@defun dbus-get-property bus service path interface property +This function returns the value of @var{property} of @var{interface}. +It will be checked at @var{bus}, @var{service}, @var{path}. The +result can be any valid D-Bus value, or nil if there is no +@var{property}. Example: + +@lisp +(dbus-get-property + :session "org.kde.kded" "/modules/networkstatus" + "org.kde.Solid.Networking.Client" "Status") + +@result{} 4 +@end lisp +@end defun + +@defun dbus-set-property bus service path interface property value +Set value of @var{property} of @var{interface} to @var{value}. It +will be checked at @var{bus}, @var{service}, @var{path}. When the +value has been set successful, the result is @var{value}. Otherwise, +@code{nil} is returned. Example: + +@lisp +(dbus-set-property + :session "org.kde.kaccess" "/MainApplication" + "com.trolltech.Qt.QApplication" "doubleClickInterval" 500) + +@result{} 500 +@end lisp +@end defun + +@defun dbus-get-all-properties bus service path interface +This function returns all properties of @var{interface}. It will be +checked at @var{bus}, @var{service}, @var{path}. The result is a list +of cons. Every cons contains the name of the property, and its value. +If there are no properties, @code{nil} is returned. Example: + +@lisp +(dbus-get-all-properties + :session "org.kde.kaccess" "/MainApplication" + "com.trolltech.Qt.QApplication") + +@result{} (("cursorFlashTime" . 1000) ("doubleClickInterval" . 500) + ("keyboardInputInterval" . 400) ("wheelScrollLines" . 3) + ("globalStrut" 0 0) ("startDragTime" . 500) + ("startDragDistance" . 4) ("quitOnLastWindowClosed" . t) + ("styleSheet" . "")) +@end lisp +@end defun + +@defun dbus-introspect-get-annotation-names bus service path interface &optional name +Return a list of all annotation names as list of strings. If +@var{name} is @code{nil}, the annotations are children of +@var{interface}, otherwise @var{name} must be a @code{method}, +@code{signal}, or @code{property} XML element, where the annotations +belong to. Example: + +@lisp +(dbus-introspect-get-annotation-names + :session "de.berlios.Pinot" "/de/berlios/Pinot" + "de.berlios.Pinot" "GetStatistics") + +@result{} ("de.berlios.Pinot.GetStatistics") +@end lisp + +Default annotation names@footnote{See +@uref{http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format}} +are + +@table @samp +@item org.freedesktop.DBus.Deprecated +Whether or not the entity is deprecated; defaults to @code{nil} + +@item org.freedesktop.DBus.GLib.CSymbol +The C symbol; may be used for @code{methods} and @code{interfaces} + +@item org.freedesktop.DBus.Method.NoReply +If set, don't expect a reply to the @code{method} call; defaults to @code{nil} +@end table +@end defun + +@defun dbus-introspect-get-annotation bus service path interface name annotation +Return annotation @var{ANNOTATION} as XML object. If @var{name} is +@code{nil}, @var{ANNOTATION} is a child of @var{interface}, otherwise +@var{name} must be the name of a @code{method}, @code{signal}, or +@code{property} XML element, where the @var{ANNOTATION} belongs to. + +An attribute value can be retrieved by +@code{dbus-introspect-get-attribute}. Example: + +@lisp +(dbus-introspect-get-annotation + :session "de.berlios.Pinot" "/de/berlios/Pinot" + "de.berlios.Pinot" "GetStatistics" + "de.berlios.Pinot.GetStatistics") + +@result{} (annotation ((name . "de.berlios.Pinot.GetStatistics") + (value . "pinotDBus"))) + +(dbus-introspect-get-attribute + (dbus-introspect-get-annotation + :session "de.berlios.Pinot" "/de/berlios/Pinot" + "de.berlios.Pinot" "GetStatistics" + "de.berlios.Pinot.GetStatistics") + "value") + +@result{} "pinotDBus" +@end lisp +@end defun + + +@node Arguments and Signatures +@section The final details. + +Methods and signals have arguments. They are described in the +@code{arg} XML elements. + +@defun dbus-introspect-get-argument-names bus service path interface name +Return a list of all argument names as list of strings. @var{name} +must be a @code{method} or @code{signal} XML element. Example: + +@lisp +(dbus-introspect-get-argument-names + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search" "GetHitData") + +@result{} ("search" "hit_ids" "fields" "hit_data") +@end lisp + +Argument names are optional; the function can return @code{nil} +therefore, even if the method or signal has arguments. +@end defun + +@defun dbus-introspect-get-argument bus service path interface name arg +Return argument @var{ARG} as XML object. @var{name} +must be a @code{method} or @code{signal} XML element. Example: + +@lisp +(dbus-introspect-get-argument + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search" "GetHitData" "search") + +@result{} (arg ((name . "search") (type . "s") (direction . "in"))) +@end lisp +@end defun + +@defun dbus-introspect-get-signature bus service path interface name &optional direction +Return signature of a @code{method} or @code{signal}, represented by +@var{name}, as string. + +If @var{name} is a @code{method}, @var{direction} can be either +@samp{in} or @samp{out}. If @var{direction} is @code{nil}, @samp{in} +is assumed. + +If @var{name} is a @code{signal}, and @var{direction} is +non-@code{nil}, @var{direction} must be @samp{out}. Example: + +@lisp +(dbus-introspect-get-signature + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search" "GetHitData" "in") + +@result{} "sauas" + +(dbus-introspect-get-signature + :session "org.freedesktop.xesam.searcher" + "/org/freedesktop/xesam/searcher/main" + "org.freedesktop.xesam.Search" "HitsAdded") + +@result{} "su" +@end lisp +@end defun + @node Type Conversion @chapter Mapping Lisp types and D-Bus types. @@ -364,6 +945,37 @@ elements of this array. Example: @result{} 3 @end lisp +@defun dbus-string-to-byte-array string +Sometimes, D-Bus methods require as input parameter an array of bytes, +instead of a string. If it is guaranteed, that @var{string} is an +UTF8 string, this function performs the conversion. Example: + +@lisp +(dbus-string-to-byte-array "/etc/hosts") + +@result{} (:array :byte 47 :byte 101 :byte 116 :byte 99 :byte 47 + :byte 104 :byte 111 :byte 115 :byte 116 :byte 115) +@end lisp +@end defun + +@defun dbus-escape-as-identifier string +Escape an arbitrary @var{string} so it follows the rules for a C +identifier. The escaped string can be used as object path component, +interface element component, bus name component or member name in +D-Bus. + +The escaping consists of replacing all non-alphanumerics, and the +first character if it's a digit, with an underscore and two +lower-case hex digits. As a special case, "" is escaped to +"_". Example: + +@lisp +(dbus-escape-as-identifier "0123abc_xyz\x01\xff") + +@result{} "_30123abc_5fxyz_01_ff" +@end lisp +@end defun + @section Output parameters. @@ -410,6 +1022,30 @@ The signal @code{PropertyModified}, discussed as example in (@var{NUMBER} ((@var{STRING} @var{BOOL} @var{BOOL}) (@var{STRING} @var{BOOL} @var{BOOL}) @dots{})) @end lisp +@defun dbus-byte-array-to-string byte-array +If a D-Bus method or signal returns an array of bytes, which are known +to represent an UTF8 string, this function converts @var{byte-array} +to the corresponding string. Example: + +@lisp +(dbus-byte-array-to-string '(47 101 116 99 47 104 111 115 116 115)) + +@result{} "/etc/hosts" +@end lisp +@end defun + +@defun dbus-unescape-from-identifier string +Retrieve the original string from the encoded @var{string}. +@var{string} must have been coded with +@code{dbus-escape-as-identifier}. Example: + +@lisp +(dbus-unescape-from-identifier "_30123abc_5fxyz_01_ff") + +@result{} "0123abc_xyzÿ" +@end lisp +@end defun + @node Synchronous Methods @chapter Calling methods in a blocking way. @@ -417,15 +1053,14 @@ The signal @code{PropertyModified}, discussed as example in @cindex synchronous method calls Methods can be called synchronously (@dfn{blocking}) or asynchronously -(@dfn{non-blocking}). Currently, just synchronous methods are -implemented. +(@dfn{non-blocking}). At D-Bus level, a method call consist of two messages: one message which carries the input parameters to the object owning the method to be called, and a reply message returning the resulting output parameters from the object. -@defun dbus-call-method bus service path interface method &rest args +@defun dbus-call-method bus service path interface method &optional :timeout timeout &rest args This function calls @var{method} on the D-Bus @var{bus}. @var{bus} is either the symbol @code{:system} or the symbol @code{:session}. @@ -433,6 +1068,12 @@ either the symbol @code{:system} or the symbol @code{:session}. D-Bus object path, @var{service} is registered at. @var{interface} is an interface offered by @var{service}. It must provide @var{method}. +If the parameter @code{:timeout} is given, the following integer +@var{timeout} specifies the maximum number of milliseconds the method +call must return. The default value is 25.000. If the method call +doesn't return in time, a D-Bus error is raised (@pxref{Errors and +Events}). + All other arguments args are passed to @var{method} as arguments. They are converted into D-Bus types as described in @ref{Type Conversion}. @@ -506,6 +1147,70 @@ emulate the @code{lshal} command on GNU/Linux systems: @end lisp @end defun +@defun dbus-call-method-non-blocking bus service path interface method &optional :timeout timeout &rest args +Call @var{method} on the D-Bus @var{bus}, but don't block the event queue. +This is necessary for communicating to registered D-Bus methods, +which are running in the same Emacs process. + +The arguments are the same as in @code{dbus-call-method}. Example: + +@lisp +(dbus-call-method-non-blocking + :system "org.freedesktop.Hal" + "/org/freedesktop/Hal/devices/computer" + "org.freedesktop.Hal.Device" "GetPropertyString" + "system.kernel.machine") + +@result{} "i686" +@end lisp +@end defun + + +@node Asynchronous Methods +@chapter Calling methods non-blocking. +@cindex method calls, asynchronous +@cindex asynchronous method calls + +@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}. + +@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 +an interface offered by @var{service}. It must provide @var{method}. + +@var{handler} is a Lisp function, which is called when the +corresponding return message has arrived. + +If the parameter @code{:timeout} is given, the following integer +@var{timeout} specifies the maximum number of milliseconds a reply +message must arrive. The default value is 25.000. If there is no +reply message in time, a D-Bus error is raised (@pxref{Errors and +Events}). + +All other arguments args are passed to @var{method} as arguments. +They are converted into D-Bus types as described in @ref{Type +Conversion}. + +The function returns a key into the hash table +@code{dbus-registered-functions-table}. The corresponding entry in +the hash table is removed, when the return message has been arrived, +and @var{handler} is called. Example: + +@lisp +(dbus-call-method-asynchronously + :system "org.freedesktop.Hal" + "/org/freedesktop/Hal/devices/computer" + "org.freedesktop.Hal.Device" "GetPropertyString" 'message + "system.kernel.machine") + +@result{} (:system 2) + +@print{} i686 +@end lisp +@end defun + @node Receiving Method Calls @chapter Offering own methods. @@ -514,15 +1219,25 @@ emulate the @code{lshal} command on GNU/Linux systems: Emacs can also offer own methods, which can be called by other applications. These methods could be an implementation of an -interface of a well known service, like @code{org.freedesktop.TextEditor}. +interface of a well known service, like @samp{org.freedesktop.TextEditor}. It could be also an implementation of an own interface. In this case, -the service name must be @code{org.gnu.Emacs}. The object path shall -begin with @code{/org/gnu/Emacs/@strong{Application}/}, and the +the service name must be @samp{org.gnu.Emacs}. The object path shall +begin with @samp{/org/gnu/Emacs/@strong{Application}/}, and the interface name shall be @code{org.gnu.Emacs.@strong{Application}}. -@code{@strong{Application}} is the name of the application which +@samp{@strong{Application}} is the name of the application which provides the interface. +@deffn Constant dbus-service-emacs +The well known service name of Emacs. +@end deffn + +@deffn Constant dbus-path-emacs +The object path head "/org/gnu/Emacs" used by Emacs. All object +paths, used by offered methods or signals, shall start with this +string. +@end deffn + @defun dbus-register-method bus service path interface method handler With this function, an application registers @var{method} on the D-Bus @var{bus}. @@ -539,13 +1254,23 @@ registered. @var{interface} is the interface offered by @var{service}. It must provide @var{method}. -@var{handler} is a Lisp function to be called when when a @var{method} -call is is received. It must accept as arguments the input arguments -of @var{method}. @var{handler} must return a list, which elements are -used as arguments for the reply message of @var{method}. This list -can be composed like the input parameters in @ref{Type Conversion}. +@var{handler} is a Lisp function to be called when a @var{method} call +is received. It must accept as arguments the input arguments of +@var{method}. @var{handler} should return a list, whose elements are +to be used as arguments for the reply message of @var{method}. This +list can be composed like the input parameters in @ref{Type +Conversion}. + +If @var{handler} wants to return just one Lisp object and it is not a +cons cell, @var{handler} can return this object directly, instead of +returning a list containing the object. -@code{dbus-register-method} returns a Lisp symbol, which can be used +The default D-Bus timeout when waiting for a message reply is 25 +seconds. This value could be even smaller, depending on the calling +client. Therefore, @var{handler} shall not last longer than +absolutely necessary. + +@code{dbus-register-method} returns a Lisp object, which can be used as argument in @code{dbus-unregister-object} for removing the registration for @var{method}. Example: @@ -564,12 +1289,12 @@ registration for @var{method}. Example: "org.freedesktop.TextEditor" "OpenFile" 'my-dbus-method-handler) -@result{} ((:system "org.freedesktop.TextEditor" "OpenFile") +@result{} ((:session "org.freedesktop.TextEditor" "OpenFile") ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" - my-method-handler)) + my-dbus-method-handler)) @end lisp -If you invoke the method @code{org.freedesktop.TextEditor.OpenFile} +If you invoke the method @samp{org.freedesktop.TextEditor.OpenFile} from another D-Bus application with a filename as parameter, the file is opened in Emacs, and the method returns either @var{true} or @var{false}, indicating the success if the method. As test tool one @@ -582,7 +1307,35 @@ could use the command line tool @code{dbus-send} in a shell: "org.freedesktop.TextEditor.OpenFile" string:"/etc/hosts" @print{} method return sender=:1.22 -> dest=:1.23 reply_serial=2 - boolean true + boolean true +@end example + +You can indicate an error by raising the Emacs signal +@code{dbus-error}. The handler above could be changed like this: + +@lisp +(defun my-dbus-method-handler (&rest args) + (unless (and (= (length args) 1) (stringp (car args))) + (signal 'dbus-error (list (format "Wrong argument list: %S" args)))) + (condition-case err + (find-file (car args)) + (error (signal 'dbus-error (cdr err)))) + t) + +@result{} my-dbus-method-handler +@end lisp + +The test runs then + +@example +# dbus-send --session --print-reply \ + --dest="org.freedesktop.TextEditor" \ + "/org/freedesktop/TextEditor" \ + "org.freedesktop.TextEditor.OpenFile" \ + string:"/etc/hosts" string:"/etc/passwd" + +@print{} Error org.freedesktop.DBus.Error.Failed: + Wrong argument list: ("/etc/hosts" "/etc/passwd") @end example @end defun @@ -613,12 +1366,13 @@ Conversion}. Example: @lisp (dbus-send-signal - :session "org.gnu.Emacs" "/org/gnu/Emacs" - "org.gnu.Emacs.FileManager" "FileModified" "/home/albinus/.emacs") + :session dbus-service-emacs dbus-path-emacs + (concat dbus-service-emacs ".FileManager") "FileModified" + "/home/albinus/.emacs") @end lisp @end defun -@defun dbus-register-signal bus service path interface signal handler +@defun dbus-register-signal bus service path interface signal handler &rest args With this function, an application registers for @var{signal} on the D-Bus @var{bus}. @@ -643,7 +1397,16 @@ provide @var{signal}. @var{handler} is a Lisp function to be called when the @var{signal} is received. It must accept as arguments the output parameters -@var{signal} is sending. Example: +@var{signal} is sending. + +All other arguments @var{args}, if specified, must be strings. They +stand for the respective arguments of @var{signal} in their order, and +are used for filtering as well. A @code{nil} argument might be used +to preserve the order. + +@code{dbus-register-signal} returns a Lisp object, which can be used +as argument in @code{dbus-unregister-object} for removing the +registration for @var{signal}. Example: @lisp (defun my-dbus-signal-handler (device) @@ -661,17 +1424,13 @@ received. It must accept as arguments the output parameters my-signal-handler)) @end lisp -As we know from the inspection data of interface -@code{org.freedesktop.Hal.Manager}, the signal @code{DeviceAdded} +As we know from the introspection data of interface +@samp{org.freedesktop.Hal.Manager}, the signal @samp{DeviceAdded} provides one single parameter, which is mapped into a Lisp string. The callback function @code{my-dbus-signal-handler} must define one single string argument therefore. Plugging an USB device to your -machine, when registered for signal @code{DeviceAdded}, will show you +machine, when registered for signal @samp{DeviceAdded}, will show you which objects the GNU/Linux @code{hal} daemon adds. - -@code{dbus-register-signal} returns a Lisp symbol, which can be used -as argument in @code{dbus-unregister-object} for removing the -registration for @var{signal}. @end defun @defun dbus-unregister-object object @@ -687,7 +1446,9 @@ has been unregistered, @code{nil} otherwise. @cindex errors @cindex events -Input parameters of @code{dbus-call-method} and +Input parameters of @code{dbus-call-method}, +@code{dbus-call-method-non-blocking}, +@code{dbus-call-method-asynchronously}, and @code{dbus-register-signal} are checked for correct D-Bus types. If there is a type mismatch, the Lisp error @code{wrong-type-argument} @code{D-Bus ARG} is raised. @@ -707,14 +1468,19 @@ Incoming D-Bus messages are handled as Emacs events (see @pxref{Misc Events, , , elisp}). The generated event has this form: @lisp -(dbus-event @var{bus} @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{path} @var{interface} @var{member} @var{handler} + &rest @var{args}) @end lisp -@var{bus} identifies the D-Bus the signal is coming from. It is +@var{bus} identifies the D-Bus the message is coming from. It is either the symbol @code{:system} or the symbol @code{:session}. -@var{serial} is the serial number of the received D-Bus message if it -is a method call, or @code{nil}. +@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{service} and @var{path} are the unique name and the object path of the D-Bus object emitting the message. @var{interface} and @@ -740,10 +1506,14 @@ Returns the bus name @var{event} is coming from. The result is either the symbol @code{:system} or the symbol @code{:session}. @end defun +@defun dbus-event-message-type event +Returns the message type of the corresponding D-Bus message. The +result is a number. +@end defun + @defun dbus-event-serial-number event Returns the serial number of the corresponding D-Bus message. -The result is a number in case the D-Bus message is a method -call, or @code{nil} for all other mesage types. +The result is a number. @end defun @defun dbus-event-service-name event @@ -755,17 +1525,42 @@ Returns the object path of the D-Bus object @var{event} is coming from. @end defun @defun dbus-event-interface-name event -Returns the interface name of of the D-Bus object @var{event} is coming from. +Returns the interface name of the D-Bus object @var{event} is coming from. @end defun @defun dbus-event-member-name event -Returns the member name of of the D-Bus object @var{event} is coming +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 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 @code{t}. +setting the variable @code{dbus-debug} to @code{t}. They can also be +handled by a hook function. + +@defvar dbus-event-error-hooks +This hook variable keeps a list of functions, which are called when a +D-Bus error happens in the event handler. Every function must accept +two arguments, the event and the error variable catched in +@code{condition-case} by @code{dbus-error}. + +Such functions can be used the adapt the error signal to be raised. +Example: + +@lisp +(defun my-dbus-event-error-handler (event error) + (when (string-equal (concat dbus-service-emacs ".FileManager") + (dbus-event-interface-name event)) + (message "my-dbus-event-error-handler: %S %S" event error) + (signal 'file-error (cdr error)))) + +(add-hook 'dbus-event-error-hooks 'my-dbus-event-error-handler) +@end lisp +@end defvar + +Hook functions shall take into account, that there might be other +D-Bus applications running. Therefore, they shall check carefully, +whether a given D-Bus error is related to them. @node GNU Free Documentation License