diff options
| author | Michael Albinus | 2012-04-22 16:11:43 +0200 |
|---|---|---|
| committer | Michael Albinus | 2012-04-22 16:11:43 +0200 |
| commit | dcbf5805ac7ade7fc83f3d209e2d56f029918402 (patch) | |
| tree | ca2d664f76032c4cd39d798ae659e23a30f0b4f8 | |
| parent | cf20dee0248049a925275f54381cf63bb2017e35 (diff) | |
| download | emacs-dcbf5805ac7ade7fc83f3d209e2d56f029918402.tar.gz emacs-dcbf5805ac7ade7fc83f3d209e2d56f029918402.zip | |
Move functions from C to Lisp. Make non-blocking method calls
the default. Implement further D-Bus standard interfaces.
* configure.in (dbus_validate_bus_name, dbus_validate_path)
(dbus_validate_interface, dbus_validate_member): Check also for
these library functions
* dbusbind.c (DBUS_NUM_MESSAGE_TYPES): Declare.
(QCdbus_request_name_allow_replacement)
(QCdbus_request_name_replace_existing)
(QCdbus_request_name_do_not_queue)
(QCdbus_request_name_reply_primary_owner)
(QCdbus_request_name_reply_in_queue)
(QCdbus_request_name_reply_exists)
(QCdbus_request_name_reply_already_owner): Move to dbus.el.
(QCdbus_registered_serial, QCdbus_registered_method)
(QCdbus_registered_signal): New Lisp objects.
(XD_DEBUG_MESSAGE): Use sizeof.
(XD_MESSAGE_TYPE_TO_STRING, XD_OBJECT_TO_STRING)
(XD_DBUS_VALIDATE_BUS_ADDRESS, XD_DBUS_VALIDATE_OBJECT)
(XD_DBUS_VALIDATE_BUS_NAME, XD_DBUS_VALIDATE_PATH)
(XD_DBUS_VALIDATE_INTERFACE, XD_DBUS_VALIDATE_MEMBER): New macros.
(XD_CHECK_DBUS_SERIAL): Rename from CHECK_DBUS_SERIAL_GET_SERIAL.
(xd_signature, xd_append_arg): Allow float for integer types.
(xd_get_connection_references): New function.
(xd_get_connection_address): Rename from xd_initialize. Return
cached address.
(xd_remove_watch): Do not unset $DBUS_SESSION_BUS_ADDRESS.
(xd_close_bus): Rename from Fdbus_close_bus. Not needed on Lisp
level.
(Fdbus_init_bus): New optional arg PRIVATE. Cache address.
Return number of recounts.
(Fdbus_get_unique_name): Make stronger parameter check.
(Fdbus_message_internal): New defun.
(Fdbus_call_method, Fdbus_call_method_asynchronously)
(Fdbus_method_return_internal, Fdbus_method_error_internal)
(Fdbus_send_signal, Fdbus_register_service)
(Fdbus_register_signal, Fdbus_register_method): Move to dbus.el.
(xd_read_message_1): Obey new structure of Vdbus_registered_objects.
(xd_read_queued_messages): Obey new structure of Vdbus_registered_buses.
(Vdbus_compiled_version, Vdbus_runtime_version)
(Vdbus_message_type_invalid, Vdbus_message_type_method_call)
(Vdbus_message_type_method_return, Vdbus_message_type_error)
(Vdbus_message_type_signal): New defvars.
(Vdbus_registered_buses, Vdbus_registered_objects_table): Adapt
docstring.
* net/dbus.el (dbus-message-internal): Declare function. Remove
unneeded function declarations.
(defvar dbus-message-type-invalid, dbus-message-type-method-call)
(dbus-message-type-method-return, dbus-message-type-error)
(dbus-message-type-signal): Declare variables. Remove local
definitions.
(dbus-interface-dbus, dbus-interface-peer)
(dbus-interface-introspectable, dbus-interface-properties)
(dbus-path-emacs, dbus-interface-emacs, dbus-return-values-table):
Adapt docstring.
(dbus-interface-objectmanager): New defconst.
(dbus-call-method, dbus-call-method-asynchronously)
(dbus-send-signal, dbus-method-return-internal)
(dbus-method-error-internal, dbus-register-service)
(dbus-register-signal, dbus-register-method): New defuns, moved
from dbusbind.c
(dbus-call-method-handler, dbus-setenv)
(dbus-get-all-managed-objects, dbus-managed-objects-handler): New
defuns.
(dbus-call-method-non-blocking): Make it an obsolete function.
(dbus-unregister-object, dbus-unregister-service)
(dbus-handle-event, dbus-register-property)
(dbus-property-handler): Obey the new structure of
`bus-registered-objects'.
(dbus-introspect): Use `dbus-call-method'. Use a timeout.
(dbus-get-property, dbus-set-property, dbus-get-all-properties):
Use `dbus-call-method'.
* dbus.texi (Version): New node.
(Properties and Annotations): Mention the object manager
interface. Describe dbus-get-all-managed-objects.
(Type Conversion): Floating point numbers are allowed, if an
anteger does not fit Emacs's integer range.
(Synchronous Methods): Remove obsolete dbus-call-method-non-blocking.
(Asynchronous Methods): Fix description of
dbus-call-method-asynchronously.
(Receiving Method Calls): Fix some minor errors. Add
dbus-interface-emacs.
(Signals): Describe unicast signals and the new match rules.
(Alternative Buses): Add the PRIVATE optional argument to
dbus-init-bus. Describe its new return value. Add dbus-setenv.
| -rw-r--r-- | ChangeLog | 6 | ||||
| -rw-r--r-- | configure.in | 11 | ||||
| -rw-r--r-- | doc/misc/ChangeLog | 16 | ||||
| -rw-r--r-- | doc/misc/dbus.texi | 313 | ||||
| -rw-r--r-- | etc/NEWS | 30 | ||||
| -rw-r--r-- | lisp/ChangeLog | 33 | ||||
| -rw-r--r-- | lisp/net/dbus.el | 1065 | ||||
| -rw-r--r-- | src/ChangeLog | 45 | ||||
| -rw-r--r-- | src/dbusbind.c | 1732 |
9 files changed, 1797 insertions, 1454 deletions
| @@ -1,3 +1,9 @@ | |||
| 1 | 2012-04-22 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | * configure.in (dbus_validate_bus_name, dbus_validate_path) | ||
| 4 | (dbus_validate_interface, dbus_validate_member): Check also for | ||
| 5 | these library functions | ||
| 6 | |||
| 1 | 2012-04-22 Paul Eggert <eggert@cs.ucla.edu> | 7 | 2012-04-22 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 8 | ||
| 3 | * configure.in (doug_lea_malloc): Check for __malloc_initialize_hook. | 9 | * configure.in (doug_lea_malloc): Check for __malloc_initialize_hook. |
diff --git a/configure.in b/configure.in index e4e11bdf7b5..4c6f4e537c6 100644 --- a/configure.in +++ b/configure.in | |||
| @@ -2079,8 +2079,7 @@ if test "${HAVE_GTK}" = "yes"; then | |||
| 2079 | fi | 2079 | fi |
| 2080 | 2080 | ||
| 2081 | dnl D-Bus has been tested under GNU/Linux only. Must be adapted for | 2081 | dnl D-Bus has been tested under GNU/Linux only. Must be adapted for |
| 2082 | dnl other platforms. Support for higher D-Bus versions than 1.0 is | 2082 | dnl other platforms. |
| 2083 | dnl also not configured. | ||
| 2084 | HAVE_DBUS=no | 2083 | HAVE_DBUS=no |
| 2085 | DBUS_OBJ= | 2084 | DBUS_OBJ= |
| 2086 | if test "${with_dbus}" = "yes"; then | 2085 | if test "${with_dbus}" = "yes"; then |
| @@ -2088,7 +2087,13 @@ if test "${with_dbus}" = "yes"; then | |||
| 2088 | if test "$HAVE_DBUS" = yes; then | 2087 | if test "$HAVE_DBUS" = yes; then |
| 2089 | LIBS="$LIBS $DBUS_LIBS" | 2088 | LIBS="$LIBS $DBUS_LIBS" |
| 2090 | AC_DEFINE(HAVE_DBUS, 1, [Define to 1 if using D-Bus.]) | 2089 | AC_DEFINE(HAVE_DBUS, 1, [Define to 1 if using D-Bus.]) |
| 2091 | AC_CHECK_FUNCS([dbus_watch_get_unix_fd]) | 2090 | dnl dbus_watch_get_unix_fd has been introduced in D-Bus 1.1.1. |
| 2091 | dnl dbus_validate_* have been introduced in D-Bus 1.5.12. | ||
| 2092 | AC_CHECK_FUNCS(dbus_watch_get_unix_fd \ | ||
| 2093 | dbus_validate_bus_name \ | ||
| 2094 | dbus_validate_path \ | ||
| 2095 | dbus_validate_interface \ | ||
| 2096 | dbus_validate_member) | ||
| 2092 | DBUS_OBJ=dbusbind.o | 2097 | DBUS_OBJ=dbusbind.o |
| 2093 | fi | 2098 | fi |
| 2094 | fi | 2099 | fi |
diff --git a/doc/misc/ChangeLog b/doc/misc/ChangeLog index 14f389044bb..834a8f2c47f 100644 --- a/doc/misc/ChangeLog +++ b/doc/misc/ChangeLog | |||
| @@ -1,3 +1,19 @@ | |||
| 1 | 2012-04-22 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | * dbus.texi (Version): New node. | ||
| 4 | (Properties and Annotations): Mention the object manager | ||
| 5 | interface. Describe dbus-get-all-managed-objects. | ||
| 6 | (Type Conversion): Floating point numbers are allowed, if an | ||
| 7 | anteger does not fit Emacs's integer range. | ||
| 8 | (Synchronous Methods): Remove obsolete dbus-call-method-non-blocking. | ||
| 9 | (Asynchronous Methods): Fix description of | ||
| 10 | dbus-call-method-asynchronously. | ||
| 11 | (Receiving Method Calls): Fix some minor errors. Add | ||
| 12 | dbus-interface-emacs. | ||
| 13 | (Signals): Describe unicast signals and the new match rules. | ||
| 14 | (Alternative Buses): Add the PRIVATE optional argument to | ||
| 15 | dbus-init-bus. Describe its new return value. Add dbus-setenv. | ||
| 16 | |||
| 1 | 2012-04-20 Glenn Morris <rgm@gnu.org> | 17 | 2012-04-20 Glenn Morris <rgm@gnu.org> |
| 2 | 18 | ||
| 3 | * faq.texi (New in Emacs 24): New section. | 19 | * faq.texi (New in Emacs 24): New section. |
diff --git a/doc/misc/dbus.texi b/doc/misc/dbus.texi index 204afe7056e..e99e20b9aa0 100644 --- a/doc/misc/dbus.texi +++ b/doc/misc/dbus.texi | |||
| @@ -53,7 +53,7 @@ another. An overview of D-Bus can be found at | |||
| 53 | * Asynchronous Methods:: Calling methods non-blocking. | 53 | * Asynchronous Methods:: Calling methods non-blocking. |
| 54 | * Receiving Method Calls:: Offering own methods. | 54 | * Receiving Method Calls:: Offering own methods. |
| 55 | * Signals:: Sending and receiving signals. | 55 | * Signals:: Sending and receiving signals. |
| 56 | * Alternative Buses:: Alternative buses. | 56 | * Alternative Buses:: Alternative buses and environments. |
| 57 | * Errors and Events:: Errors and events. | 57 | * Errors and Events:: Errors and events. |
| 58 | * Index:: Index including concepts, functions, variables. | 58 | * Index:: Index including concepts, functions, variables. |
| 59 | 59 | ||
| @@ -116,6 +116,7 @@ name could be @samp{org.gnu.Emacs.TextEditor} or | |||
| 116 | @cindex inspection | 116 | @cindex inspection |
| 117 | 117 | ||
| 118 | @menu | 118 | @menu |
| 119 | * Version:: Determining the D-Bus version. | ||
| 119 | * Bus names:: Discovering D-Bus names. | 120 | * Bus names:: Discovering D-Bus names. |
| 120 | * Introspection:: Knowing the details of D-Bus services. | 121 | * Introspection:: Knowing the details of D-Bus services. |
| 121 | * Nodes and Interfaces:: Detecting object paths and interfaces. | 122 | * Nodes and Interfaces:: Detecting object paths and interfaces. |
| @@ -125,6 +126,25 @@ name could be @samp{org.gnu.Emacs.TextEditor} or | |||
| 125 | @end menu | 126 | @end menu |
| 126 | 127 | ||
| 127 | 128 | ||
| 129 | @node Version | ||
| 130 | @section D-Bus version. | ||
| 131 | |||
| 132 | D-Bus has evolved over the years. New features have been added with | ||
| 133 | new D-Bus versions. There are two variables, which allow to determine | ||
| 134 | the used D-Bus version. | ||
| 135 | |||
| 136 | @defvar dbus-compiled-version | ||
| 137 | This variable, a string, determines the version of D-Bus Emacs is | ||
| 138 | compiled against. If it cannot be determined the value is @code{nil}. | ||
| 139 | @end defvar | ||
| 140 | |||
| 141 | @defvar dbus-runtime-version | ||
| 142 | The other D-Bus version to be checked is the version of D-Bus Emacs | ||
| 143 | runs with. This string can be different from @code{dbus-compiled-version}. | ||
| 144 | It is also @code{nil}, if it cannot be determined at runtime. | ||
| 145 | @end defvar | ||
| 146 | |||
| 147 | |||
| 128 | @node Bus names | 148 | @node Bus names |
| 129 | @section Bus names. | 149 | @section Bus names. |
| 130 | 150 | ||
| @@ -149,7 +169,6 @@ activatable service names at all. Example: | |||
| 149 | (member "org.gnome.evince.Daemon" | 169 | (member "org.gnome.evince.Daemon" |
| 150 | (dbus-list-activatable-names :session)) | 170 | (dbus-list-activatable-names :session)) |
| 151 | @end lisp | 171 | @end lisp |
| 152 | |||
| 153 | @end defun | 172 | @end defun |
| 154 | 173 | ||
| 155 | @defun dbus-list-names bus | 174 | @defun dbus-list-names bus |
| @@ -637,6 +656,12 @@ Interfaces can have properties. These can be exposed via the | |||
| 637 | That is, properties can be retrieved and changed during lifetime of an | 656 | That is, properties can be retrieved and changed during lifetime of an |
| 638 | element. | 657 | element. |
| 639 | 658 | ||
| 659 | A generalized interface is | ||
| 660 | @samp{org.freedesktop.DBus.Objectmanager}@footnote{See | ||
| 661 | @uref{http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager}}, | ||
| 662 | which returns objects, their interfaces and properties for a given | ||
| 663 | service in just one call. | ||
| 664 | |||
| 640 | Annotations, on the other hand, are static values for an element. | 665 | Annotations, on the other hand, are static values for an element. |
| 641 | Often, they are used to instruct generators, how to generate code from | 666 | Often, they are used to instruct generators, how to generate code from |
| 642 | the interface for a given language binding. | 667 | the interface for a given language binding. |
| @@ -732,6 +757,61 @@ If there are no properties, @code{nil} is returned. Example: | |||
| 732 | @end lisp | 757 | @end lisp |
| 733 | @end defun | 758 | @end defun |
| 734 | 759 | ||
| 760 | @defun dbus-get-all-managed-objects bus service path | ||
| 761 | This functions returns all objects at @var{bus}, @var{service}, | ||
| 762 | @var{path}, and the children of @var{path}. The result is a list of | ||
| 763 | objects. Every object is a cons of an existing path name, and the | ||
| 764 | list of available interface objects. An interface object is another | ||
| 765 | cons, which car is the interface name, and the cdr is the list of | ||
| 766 | properties as returned by @code{dbus-get-all-properties} for that path | ||
| 767 | and interface. Example: | ||
| 768 | |||
| 769 | @lisp | ||
| 770 | (dbus-get-all-managed-objects | ||
| 771 | :session "org.gnome.SettingsDaemon" "/") | ||
| 772 | |||
| 773 | @result{} (("/org/gnome/SettingsDaemon/MediaKeys" | ||
| 774 | ("org.gnome.SettingsDaemon.MediaKeys") | ||
| 775 | ("org.freedesktop.DBus.Peer") | ||
| 776 | ("org.freedesktop.DBus.Introspectable") | ||
| 777 | ("org.freedesktop.DBus.Properties") | ||
| 778 | ("org.freedesktop.DBus.ObjectManager")) | ||
| 779 | ("/org/gnome/SettingsDaemon/Power" | ||
| 780 | ("org.gnome.SettingsDaemon.Power.Keyboard") | ||
| 781 | ("org.gnome.SettingsDaemon.Power.Screen") | ||
| 782 | ("org.gnome.SettingsDaemon.Power" | ||
| 783 | ("Icon" . ". GThemedIcon battery-full-charged-symbolic ") | ||
| 784 | ("Tooltip" . "Laptop battery is charged")) | ||
| 785 | ("org.freedesktop.DBus.Peer") | ||
| 786 | ("org.freedesktop.DBus.Introspectable") | ||
| 787 | ("org.freedesktop.DBus.Properties") | ||
| 788 | ("org.freedesktop.DBus.ObjectManager")) | ||
| 789 | @dots{}) | ||
| 790 | @end lisp | ||
| 791 | |||
| 792 | If possible, @samp{org.freedesktop.DBus.ObjectManager.GetManagedObjects} | ||
| 793 | is used for retrieving the information. Otherwise, the information | ||
| 794 | is collected via @samp{org.freedesktop.DBus.Introspectable.Introspect} | ||
| 795 | and @samp{org.freedesktop.DBus.Properties.GetAll}, which is slow. | ||
| 796 | |||
| 797 | An overview of all existing object paths, their interfaces and | ||
| 798 | properties could be retrieved by the following code: | ||
| 799 | |||
| 800 | @lisp | ||
| 801 | (with-current-buffer (switch-to-buffer "*objectmanager*") | ||
| 802 | (erase-buffer) | ||
| 803 | (let (result) | ||
| 804 | (dolist (service (dbus-list-known-names :session) result) | ||
| 805 | (message "%s" service) | ||
| 806 | (add-to-list | ||
| 807 | 'result | ||
| 808 | (cons service | ||
| 809 | (dbus-get-all-managed-objects :session service "/")))) | ||
| 810 | (insert (message "%s" (pp result))) | ||
| 811 | (redisplay t))) | ||
| 812 | @end lisp | ||
| 813 | @end defun | ||
| 814 | |||
| 735 | @defun dbus-introspect-get-annotation-names bus service path interface &optional name | 815 | @defun dbus-introspect-get-annotation-names bus service path interface &optional name |
| 736 | Return a list of all annotation names as list of strings. If | 816 | Return a list of all annotation names as list of strings. If |
| 737 | @var{name} is @code{nil}, the annotations are children of | 817 | @var{name} is @code{nil}, the annotations are children of |
| @@ -928,6 +1008,10 @@ represented outside this range are stripped of. For example, | |||
| 928 | @code{:byte ?x} is equal to @code{:byte ?\M-x}, but it is not equal to | 1008 | @code{:byte ?x} is equal to @code{:byte ?\M-x}, but it is not equal to |
| 929 | @code{:byte ?\C-x} or @code{:byte ?\M-\C-x}. | 1009 | @code{:byte ?\C-x} or @code{:byte ?\M-\C-x}. |
| 930 | 1010 | ||
| 1011 | Signed and unsigned integer D-Bus types expect a corresponding integer | ||
| 1012 | value. If the value does not fit Emacs's integer range, it is also | ||
| 1013 | possible to use an equivalent floating point number. | ||
| 1014 | |||
| 931 | A D-Bus compound type is always represented as a list. The @sc{car} | 1015 | A D-Bus compound type is always represented as a list. The @sc{car} |
| 932 | of this list can be the type symbol @code{:array}, @code{:variant}, | 1016 | of this list can be the type symbol @code{:array}, @code{:variant}, |
| 933 | @code{:struct} or @code{:dict-entry}, which would result in a | 1017 | @code{:struct} or @code{:dict-entry}, which would result in a |
| @@ -1182,24 +1266,6 @@ emulate the @code{lshal} command on GNU/Linux systems: | |||
| 1182 | @end lisp | 1266 | @end lisp |
| 1183 | @end defun | 1267 | @end defun |
| 1184 | 1268 | ||
| 1185 | @defun dbus-call-method-non-blocking bus service path interface method &optional :timeout timeout &rest args | ||
| 1186 | Call @var{method} on the D-Bus @var{bus}, but don't block the event queue. | ||
| 1187 | This is necessary for communicating to registered D-Bus methods, | ||
| 1188 | which are running in the same Emacs process. | ||
| 1189 | |||
| 1190 | The arguments are the same as in @code{dbus-call-method}. Example: | ||
| 1191 | |||
| 1192 | @lisp | ||
| 1193 | (dbus-call-method-non-blocking | ||
| 1194 | :system "org.freedesktop.Hal" | ||
| 1195 | "/org/freedesktop/Hal/devices/computer" | ||
| 1196 | "org.freedesktop.Hal.Device" "GetPropertyString" | ||
| 1197 | "system.kernel.machine") | ||
| 1198 | |||
| 1199 | @result{} "i686" | ||
| 1200 | @end lisp | ||
| 1201 | @end defun | ||
| 1202 | |||
| 1203 | 1269 | ||
| 1204 | @node Asynchronous Methods | 1270 | @node Asynchronous Methods |
| 1205 | @chapter Calling methods non-blocking. | 1271 | @chapter Calling methods non-blocking. |
| @@ -1229,7 +1295,7 @@ All other arguments args are passed to @var{method} as arguments. | |||
| 1229 | They are converted into D-Bus types as described in @ref{Type | 1295 | They are converted into D-Bus types as described in @ref{Type |
| 1230 | Conversion}. | 1296 | Conversion}. |
| 1231 | 1297 | ||
| 1232 | Unless @var{handler} is @code{nil}, the function returns a key into | 1298 | If @var{handler} is a Lisp function, the function returns a key into |
| 1233 | the hash table @code{dbus-registered-objects-table}. The | 1299 | the hash table @code{dbus-registered-objects-table}. The |
| 1234 | corresponding entry in the hash table is removed, when the return | 1300 | corresponding entry in the hash table is removed, when the return |
| 1235 | message has been arrived, and @var{handler} is called. Example: | 1301 | message has been arrived, and @var{handler} is called. Example: |
| @@ -1241,7 +1307,7 @@ message has been arrived, and @var{handler} is called. Example: | |||
| 1241 | "org.freedesktop.Hal.Device" "GetPropertyString" 'message | 1307 | "org.freedesktop.Hal.Device" "GetPropertyString" 'message |
| 1242 | "system.kernel.machine") | 1308 | "system.kernel.machine") |
| 1243 | 1309 | ||
| 1244 | @result{} (:system 2) | 1310 | @result{} (:serial :system 2) |
| 1245 | 1311 | ||
| 1246 | @print{} i686 | 1312 | @print{} i686 |
| 1247 | @end lisp | 1313 | @end lisp |
| @@ -1323,19 +1389,21 @@ implementation of an interface of a well known service, like | |||
| 1323 | 1389 | ||
| 1324 | It could be also an implementation of an own interface. In this case, | 1390 | It could be also an implementation of an own interface. In this case, |
| 1325 | the service name must be @samp{org.gnu.Emacs}. The object path shall | 1391 | the service name must be @samp{org.gnu.Emacs}. The object path shall |
| 1326 | begin with @samp{/org/gnu/Emacs/@strong{Application}/}, and the | 1392 | begin with @samp{/org/gnu/Emacs/@strong{Application}}, and the |
| 1327 | interface name shall be @code{org.gnu.Emacs.@strong{Application}}. | 1393 | interface name shall be @code{org.gnu.Emacs.@strong{Application}}. |
| 1328 | @samp{@strong{Application}} is the name of the application which | 1394 | @samp{@strong{Application}} is the name of the application which |
| 1329 | provides the interface. | 1395 | provides the interface. |
| 1330 | 1396 | ||
| 1331 | @deffn Constant dbus-service-emacs | 1397 | @deffn Constant dbus-service-emacs |
| 1332 | The well known service name of Emacs. | 1398 | The well known service name @samp{org.gnu.Emacs} of Emacs. |
| 1333 | @end deffn | 1399 | @end deffn |
| 1334 | 1400 | ||
| 1335 | @deffn Constant dbus-path-emacs | 1401 | @deffn Constant dbus-path-emacs |
| 1336 | The object path head "/org/gnu/Emacs" used by Emacs. All object | 1402 | The object path namespace @samp{/org/gnu/Emacs} used by Emacs. |
| 1337 | paths, used by offered methods or signals, shall start with this | 1403 | @end deffn |
| 1338 | string. | 1404 | |
| 1405 | @deffn Constant dbus-interface-emacs | ||
| 1406 | The interface namespace @code{org.gnu.Emacs} used by Emacs. | ||
| 1339 | @end deffn | 1407 | @end deffn |
| 1340 | 1408 | ||
| 1341 | @defun dbus-register-method bus service path interface method handler dont-register-service | 1409 | @defun dbus-register-method bus service path interface method handler dont-register-service |
| @@ -1400,7 +1468,7 @@ registration for @var{method}. Example: | |||
| 1400 | "org.freedesktop.TextEditor" "OpenFile" | 1468 | "org.freedesktop.TextEditor" "OpenFile" |
| 1401 | 'my-dbus-method-handler) | 1469 | 'my-dbus-method-handler) |
| 1402 | 1470 | ||
| 1403 | @result{} ((:session "org.freedesktop.TextEditor" "OpenFile") | 1471 | @result{} ((:method :session "org.freedesktop.TextEditor" "OpenFile") |
| 1404 | ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" | 1472 | ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" |
| 1405 | my-dbus-method-handler)) | 1473 | my-dbus-method-handler)) |
| 1406 | @end lisp | 1474 | @end lisp |
| @@ -1497,14 +1565,14 @@ clients from discovering the still incomplete interface. | |||
| 1497 | :session "org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" | 1565 | :session "org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" |
| 1498 | "org.freedesktop.TextEditor" "name" :read "GNU Emacs") | 1566 | "org.freedesktop.TextEditor" "name" :read "GNU Emacs") |
| 1499 | 1567 | ||
| 1500 | @result{} ((:session "org.freedesktop.TextEditor" "name") | 1568 | @result{} ((:property :session "org.freedesktop.TextEditor" "name") |
| 1501 | ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor")) | 1569 | ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor")) |
| 1502 | 1570 | ||
| 1503 | (dbus-register-property | 1571 | (dbus-register-property |
| 1504 | :session "org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" | 1572 | :session "org.freedesktop.TextEditor" "/org/freedesktop/TextEditor" |
| 1505 | "org.freedesktop.TextEditor" "version" :readwrite emacs-version t) | 1573 | "org.freedesktop.TextEditor" "version" :readwrite emacs-version t) |
| 1506 | 1574 | ||
| 1507 | @result{} ((:session "org.freedesktop.TextEditor" "version") | 1575 | @result{} ((:property :session "org.freedesktop.TextEditor" "version") |
| 1508 | ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor")) | 1576 | ("org.freedesktop.TextEditor" "/org/freedesktop/TextEditor")) |
| 1509 | @end lisp | 1577 | @end lisp |
| 1510 | 1578 | ||
| @@ -1569,8 +1637,8 @@ to the service from D-Bus. | |||
| 1569 | @chapter Sending and receiving signals. | 1637 | @chapter Sending and receiving signals. |
| 1570 | @cindex signals | 1638 | @cindex signals |
| 1571 | 1639 | ||
| 1572 | Signals are broadcast messages. They carry input parameters, which | 1640 | Signals are one way messages. They carry input parameters, which are |
| 1573 | are received by all objects which have registered for such a signal. | 1641 | received by all objects which have registered for such a signal. |
| 1574 | 1642 | ||
| 1575 | @defun dbus-send-signal bus service path interface signal &rest args | 1643 | @defun dbus-send-signal bus service path interface signal &rest args |
| 1576 | This function is similar to @code{dbus-call-method}. The difference | 1644 | This function is similar to @code{dbus-call-method}. The difference |
| @@ -1580,10 +1648,14 @@ The function emits @var{signal} on the D-Bus @var{bus}. @var{bus} is | |||
| 1580 | either the symbol @code{:system} or the symbol @code{:session}. It | 1648 | either the symbol @code{:system} or the symbol @code{:session}. It |
| 1581 | doesn't matter whether another object has registered for @var{signal}. | 1649 | doesn't matter whether another object has registered for @var{signal}. |
| 1582 | 1650 | ||
| 1583 | @var{service} is the D-Bus service name of the object the signal is | 1651 | Signals can be unicast or broadcast messages. For broadcast messages, |
| 1584 | emitted from. @var{path} is the corresponding D-Bus object path, | 1652 | @var{service} must be @code{nil}. Otherwise, @var{service} is the |
| 1585 | @var{service} is registered at. @var{interface} is an interface | 1653 | D-Bus service name the signal is sent to as unicast |
| 1586 | offered by @var{service}. It must provide @var{signal}. | 1654 | message.@footnote{For backward compatibility, a broadcast message is |
| 1655 | also emitted if @var{service} is the known or unique name Emacs is | ||
| 1656 | registered at D-Bus @var{bus}.} @var{path} is the D-Bus object path | ||
| 1657 | @var{signal} is sent from. @var{interface} is an interface available | ||
| 1658 | at @var{path}. It must provide @var{signal}. | ||
| 1587 | 1659 | ||
| 1588 | All other arguments args are passed to @var{signal} as arguments. | 1660 | All other arguments args are passed to @var{signal} as arguments. |
| 1589 | They are converted into D-Bus types as described in @ref{Type | 1661 | They are converted into D-Bus types as described in @ref{Type |
| @@ -1591,15 +1663,15 @@ Conversion}. Example: | |||
| 1591 | 1663 | ||
| 1592 | @lisp | 1664 | @lisp |
| 1593 | (dbus-send-signal | 1665 | (dbus-send-signal |
| 1594 | :session dbus-service-emacs dbus-path-emacs | 1666 | :session nil dbus-path-emacs |
| 1595 | (concat dbus-service-emacs ".FileManager") "FileModified" | 1667 | (concat dbus-interface-emacs ".FileManager") "FileModified" |
| 1596 | "/home/albinus/.emacs") | 1668 | "/home/albinus/.emacs") |
| 1597 | @end lisp | 1669 | @end lisp |
| 1598 | @end defun | 1670 | @end defun |
| 1599 | 1671 | ||
| 1600 | @defun dbus-register-signal bus service path interface signal handler &rest args | 1672 | @defun dbus-register-signal bus service path interface signal handler &rest args |
| 1601 | With this function, an application registers for @var{signal} on the | 1673 | With this function, an application registers for a signal on the D-Bus |
| 1602 | D-Bus @var{bus}. | 1674 | @var{bus}. |
| 1603 | 1675 | ||
| 1604 | @var{bus} is either the symbol @code{:system} or the symbol | 1676 | @var{bus} is either the symbol @code{:system} or the symbol |
| 1605 | @code{:session}. | 1677 | @code{:session}. |
| @@ -1611,24 +1683,46 @@ unique name of the object, owning @var{service} at registration time. | |||
| 1611 | When the corresponding D-Bus object disappears, signals won't be | 1683 | When the corresponding D-Bus object disappears, signals won't be |
| 1612 | received any longer. | 1684 | received any longer. |
| 1613 | 1685 | ||
| 1614 | When @var{service} is @code{nil}, related signals from all D-Bus | ||
| 1615 | objects shall be accepted. | ||
| 1616 | |||
| 1617 | @var{path} is the corresponding D-Bus object path, @var{service} is | 1686 | @var{path} is the corresponding D-Bus object path, @var{service} is |
| 1618 | registered at. It can also be @code{nil} if the path name of incoming | 1687 | registered at. @var{interface} is an interface offered by |
| 1619 | signals shall not be checked. | 1688 | @var{service}. It must provide @var{signal}. |
| 1620 | 1689 | ||
| 1621 | @var{interface} is an interface offered by @var{service}. It must | 1690 | @var{service}, @var{path}, @var{interface} and @var{signal} can be |
| 1622 | provide @var{signal}. | 1691 | @code{nil}. This is interpreted as a wildcard for the respective |
| 1692 | argument. | ||
| 1623 | 1693 | ||
| 1624 | @var{handler} is a Lisp function to be called when the @var{signal} is | 1694 | @var{handler} is a Lisp function to be called when the @var{signal} is |
| 1625 | received. It must accept as arguments the output parameters | 1695 | received. It must accept as arguments the output parameters |
| 1626 | @var{signal} is sending. | 1696 | @var{signal} is sending. |
| 1627 | 1697 | ||
| 1628 | All other arguments @var{args}, if specified, must be strings. They | 1698 | The remaining arguments @var{args} can be keywords or keyword string |
| 1629 | stand for the respective arguments of @var{signal} in their order, and | 1699 | pairs.@footnote{For backward compatibility, the arguments @var{args} |
| 1630 | are used for filtering as well. A @code{nil} argument might be used | 1700 | can also be just strings. They stand for the respective arguments of |
| 1631 | to preserve the order. | 1701 | @var{signal} in their order, and are used for filtering as well. A |
| 1702 | @code{nil} argument might be used to preserve the order.} The meaning | ||
| 1703 | is as follows: | ||
| 1704 | |||
| 1705 | @itemize | ||
| 1706 | @item @code{:argN} @var{string}:@* | ||
| 1707 | @code{:pathN} @var{string}:@* | ||
| 1708 | This stands for the Nth argument of the signal. @code{:pathN} | ||
| 1709 | arguments can be used for object path wildcard matches as specified by | ||
| 1710 | D-Bus, whilest an @code{:argN} argument requires an exact match. | ||
| 1711 | |||
| 1712 | @item @code{:arg-namespace} @var{string}:@* | ||
| 1713 | Register for the signals, which first argument defines the service or | ||
| 1714 | interface namespace @var{string}. | ||
| 1715 | |||
| 1716 | @item @code{:path-namespace} @var{string}:@* | ||
| 1717 | Register for the object path namespace @var{string}. All signals sent | ||
| 1718 | from an object path, which has @var{string} as the preceding string, | ||
| 1719 | are matched. This requires @var{path} to be @code{nil}. | ||
| 1720 | |||
| 1721 | @item @code{:eavesdrop}:@* | ||
| 1722 | Register for unicast signals which are not directed to the D-Bus | ||
| 1723 | object Emacs is registered at D-Bus BUS, if the security policy of BUS | ||
| 1724 | allows this. Otherwise, this argument is ignored. | ||
| 1725 | @end itemize | ||
| 1632 | 1726 | ||
| 1633 | @code{dbus-register-signal} returns a Lisp object, which can be used | 1727 | @code{dbus-register-signal} returns a Lisp object, which can be used |
| 1634 | as argument in @code{dbus-unregister-object} for removing the | 1728 | as argument in @code{dbus-unregister-object} for removing the |
| @@ -1645,7 +1739,7 @@ registration for @var{signal}. Example: | |||
| 1645 | "org.freedesktop.Hal.Manager" "DeviceAdded" | 1739 | "org.freedesktop.Hal.Manager" "DeviceAdded" |
| 1646 | 'my-dbus-signal-handler) | 1740 | 'my-dbus-signal-handler) |
| 1647 | 1741 | ||
| 1648 | @result{} ((:system "org.freedesktop.Hal.Manager" "DeviceAdded") | 1742 | @result{} ((:signal :system "org.freedesktop.Hal.Manager" "DeviceAdded") |
| 1649 | ("org.freedesktop.Hal" "/org/freedesktop/Hal/Manager" | 1743 | ("org.freedesktop.Hal" "/org/freedesktop/Hal/Manager" |
| 1650 | my-signal-handler)) | 1744 | my-signal-handler)) |
| 1651 | @end lisp | 1745 | @end lisp |
| @@ -1657,23 +1751,36 @@ The callback function @code{my-dbus-signal-handler} must define one | |||
| 1657 | single string argument therefore. Plugging an USB device to your | 1751 | single string argument therefore. Plugging an USB device to your |
| 1658 | machine, when registered for signal @samp{DeviceAdded}, will show you | 1752 | machine, when registered for signal @samp{DeviceAdded}, will show you |
| 1659 | which objects the GNU/Linux @code{hal} daemon adds. | 1753 | which objects the GNU/Linux @code{hal} daemon adds. |
| 1754 | |||
| 1755 | Some of the match rules have been added to a later version of D-Bus. | ||
| 1756 | In order to test the availability of such features, you could register | ||
| 1757 | for a dummy signal, and check the result: | ||
| 1758 | |||
| 1759 | @lisp | ||
| 1760 | (dbus-ignore-errors | ||
| 1761 | (dbus-register-signal | ||
| 1762 | :system nil nil nil nil 'ignore :path-namespace "/invalid/path")) | ||
| 1763 | |||
| 1764 | @result{} nil | ||
| 1765 | @end lisp | ||
| 1660 | @end defun | 1766 | @end defun |
| 1661 | 1767 | ||
| 1662 | 1768 | ||
| 1663 | @node Alternative Buses | 1769 | @node Alternative Buses |
| 1664 | @chapter Alternative buses. | 1770 | @chapter Alternative buses and environments. |
| 1665 | @cindex bus names | 1771 | @cindex bus names |
| 1666 | @cindex UNIX domain socket | 1772 | @cindex UNIX domain socket |
| 1773 | @cindex TCP/IP socket | ||
| 1667 | 1774 | ||
| 1668 | Until now, we have spoken about the system and the session buses, | 1775 | Until now, we have spoken about the system and the session buses, |
| 1669 | which are the default buses to be connected to. However, it is | 1776 | which are the default buses to be connected to. However, it is |
| 1670 | possible to connect to any bus, from which the address is known. This | 1777 | possible to connect to any bus, from which the address is known. This |
| 1671 | is a UNIX domain socket. Everywhere, where a @var{bus} is mentioned | 1778 | is a UNIX domain or TCP/IP socket. Everywhere, where a @var{bus} is |
| 1672 | as argument of a function (the symbol @code{:system} or the symbol | 1779 | mentioned as argument of a function (the symbol @code{:system} or the |
| 1673 | @code{:session}), this address can be used instead. The connection to | 1780 | symbol @code{:session}), this address can be used instead. The |
| 1674 | this bus must be initialized first. | 1781 | connection to this bus must be initialized first. |
| 1675 | 1782 | ||
| 1676 | @defun dbus-init-bus bus | 1783 | @defun dbus-init-bus bus &optional private |
| 1677 | Establish the connection to D-Bus @var{bus}. | 1784 | Establish the connection to D-Bus @var{bus}. |
| 1678 | 1785 | ||
| 1679 | @var{bus} can be either the symbol @code{:system} or the symbol | 1786 | @var{bus} can be either the symbol @code{:system} or the symbol |
| @@ -1682,30 +1789,90 @@ corresponding bus. For the system and session buses, this function | |||
| 1682 | is called when loading @file{dbus.el}, there is no need to call it | 1789 | is called when loading @file{dbus.el}, there is no need to call it |
| 1683 | again. | 1790 | again. |
| 1684 | 1791 | ||
| 1685 | Example: You open another session bus in a terminal window on your host: | 1792 | The function returns a number, which counts the connections this Emacs |
| 1793 | session has established to the @var{bus} under the same unique name | ||
| 1794 | (see @code{dbus-get-unique-name}). It depends on the libraries Emacs | ||
| 1795 | is linked with, and on the environment Emacs is running. For example, | ||
| 1796 | if Emacs is linked with the gtk toolkit, and it runs in a GTK-aware | ||
| 1797 | environment like Gnome, another connection might already be | ||
| 1798 | established. | ||
| 1686 | 1799 | ||
| 1687 | @example | 1800 | When @var{private} is non-@code{nil}, a new connection is established |
| 1688 | # eval `dbus-launch --auto-syntax` | 1801 | instead of reusing an existing one. It results in a new unique name |
| 1689 | # echo $DBUS_SESSION_BUS_ADDRESS | 1802 | at the bus. This can be used, if it is necessary to distinguish from |
| 1803 | another connection used in the same Emacs process, like the one | ||
| 1804 | established by GTK+. It should be used with care for at least the | ||
| 1805 | @code{:system} and @code{:session} buses, because other Emacs Lisp | ||
| 1806 | packages might already use this connection to those buses. | ||
| 1690 | 1807 | ||
| 1691 | @print{} unix:abstract=/tmp/dbus-JoFtAVG92w,guid=2f320a1ebe50b7ef58e | 1808 | Example: You initialize a connection to the AT-SPI bus on your host: |
| 1692 | @end example | ||
| 1693 | |||
| 1694 | In Emacs, you can access to this bus via its address: | ||
| 1695 | 1809 | ||
| 1696 | @lisp | 1810 | @lisp |
| 1697 | (setq my-bus | 1811 | (setq my-bus |
| 1698 | "unix:abstract=/tmp/dbus-JoFtAVG92w,guid=2f320a1ebe50b7ef58e") | 1812 | (dbus-call-method |
| 1813 | :session "org.a11y.Bus" "/org/a11y/bus" | ||
| 1814 | "org.a11y.Bus" "GetAddress")) | ||
| 1699 | 1815 | ||
| 1700 | @result{} "unix:abstract=/tmp/dbus-JoFtAVG92w,guid=2f320a1ebe50b7ef58e" | 1816 | @result{} "unix:abstract=/tmp/dbus-2yzWHOCdSD,guid=a490dd26625870ca1298b6e10000fd7f" |
| 1701 | 1817 | ||
| 1818 | ;; If Emacs is built with gtk support, and you run in a GTK enabled | ||
| 1819 | ;; environment (like a GNOME session), the initialization reuses the | ||
| 1820 | ;; connection established by GTK's atk bindings. | ||
| 1702 | (dbus-init-bus my-bus) | 1821 | (dbus-init-bus my-bus) |
| 1703 | 1822 | ||
| 1704 | @result{} nil | 1823 | @result{} 2 |
| 1705 | 1824 | ||
| 1706 | (dbus-get-unique-name my-bus) | 1825 | (dbus-get-unique-name my-bus) |
| 1707 | 1826 | ||
| 1708 | @result{} ":1.0" | 1827 | @result{} ":1.19" |
| 1828 | |||
| 1829 | ;; Open a new connection to the same bus. This obsoletes the | ||
| 1830 | ;; previous one. | ||
| 1831 | (dbus-init-bus my-bus 'private) | ||
| 1832 | |||
| 1833 | @result{} 1 | ||
| 1834 | |||
| 1835 | (dbus-get-unique-name my-bus) | ||
| 1836 | |||
| 1837 | @result{} ":1.20" | ||
| 1838 | @end lisp | ||
| 1839 | |||
| 1840 | D-Bus addresses can specify different transport. A possible address | ||
| 1841 | could be based on TCP/IP sockets, see next example. However, it | ||
| 1842 | depends on the bus daemon configuration, which transport is supported. | ||
| 1843 | @end defun | ||
| 1844 | |||
| 1845 | @defun dbus-setenv bus variable value | ||
| 1846 | Set the value of the @var{bus} environment variable @var{variable} to | ||
| 1847 | @var{value}. | ||
| 1848 | |||
| 1849 | @var{bus} is either a Lisp symbol, @code{:system} or @code{:session}, | ||
| 1850 | or a string denoting the bus address. Both @var{variable} and | ||
| 1851 | @var{value} should be strings. | ||
| 1852 | |||
| 1853 | Normally, services inherit the environment of the bus daemon. This | ||
| 1854 | function adds to or modifies that environment when activating services. | ||
| 1855 | |||
| 1856 | Some bus instances, such as @code{:system}, may disable setting the | ||
| 1857 | environment. In such cases, or if this feature is not available in | ||
| 1858 | older D-Bus versions, a @code{dbus-error} error is raised. | ||
| 1859 | |||
| 1860 | As an example, it might be desirable to start X11 enabled services on | ||
| 1861 | a remote host's bus on the same X11 server the local Emacs is | ||
| 1862 | running. This could be achieved by | ||
| 1863 | |||
| 1864 | @lisp | ||
| 1865 | (setq my-bus "unix:host=example.gnu.org,port=4711") | ||
| 1866 | |||
| 1867 | @result{} "unix:host=example.gnu.org,port=4711" | ||
| 1868 | |||
| 1869 | (dbus-init-bus my-bus) | ||
| 1870 | |||
| 1871 | @result{} 1 | ||
| 1872 | |||
| 1873 | (dbus-setenv my-bus "DISPLAY" (getenv "DISPLAY")) | ||
| 1874 | |||
| 1875 | @result{} nil | ||
| 1709 | @end lisp | 1876 | @end lisp |
| 1710 | @end defun | 1877 | @end defun |
| 1711 | 1878 | ||
| @@ -1723,8 +1890,8 @@ If this variable is non-@code{nil}, D-Bus specific debug messages are raised. | |||
| 1723 | @end defvar | 1890 | @end defvar |
| 1724 | 1891 | ||
| 1725 | Input parameters of @code{dbus-call-method}, | 1892 | Input parameters of @code{dbus-call-method}, |
| 1726 | @code{dbus-call-method-non-blocking}, | 1893 | @code{dbus-call-method-asynchronously}, @code{dbus-send-signal}, |
| 1727 | @code{dbus-call-method-asynchronously}, and | 1894 | @code{dbus-register-method}, @code{dbus-register-property} and |
| 1728 | @code{dbus-register-signal} are checked for correct D-Bus types. If | 1895 | @code{dbus-register-signal} are checked for correct D-Bus types. If |
| 1729 | there is a type mismatch, the Lisp error @code{wrong-type-argument} | 1896 | there is a type mismatch, the Lisp error @code{wrong-type-argument} |
| 1730 | @code{D-Bus ARG} is raised. | 1897 | @code{D-Bus ARG} is raised. |
| @@ -1825,7 +1992,7 @@ Example: | |||
| 1825 | 1992 | ||
| 1826 | @lisp | 1993 | @lisp |
| 1827 | (defun my-dbus-event-error-handler (event error) | 1994 | (defun my-dbus-event-error-handler (event error) |
| 1828 | (when (string-equal (concat dbus-service-emacs ".FileManager") | 1995 | (when (string-equal (concat dbus-interface-emacs ".FileManager") |
| 1829 | (dbus-event-interface-name event)) | 1996 | (dbus-event-interface-name event)) |
| 1830 | (message "my-dbus-event-error-handler: %S %S" event error) | 1997 | (message "my-dbus-event-error-handler: %S %S" event error) |
| 1831 | (signal 'file-error (cdr error)))) | 1998 | (signal 'file-error (cdr error)))) |
| @@ -91,6 +91,36 @@ closing brackets to be aligned with the line of the opening bracket. | |||
| 91 | 91 | ||
| 92 | ** which-function-mode now applies to all applicable major modes by default. | 92 | ** which-function-mode now applies to all applicable major modes by default. |
| 93 | 93 | ||
| 94 | ** D-Bus | ||
| 95 | |||
| 96 | +++ | ||
| 97 | *** New variables `dbus-compiled-version' and `dbus-runtime-version'. | ||
| 98 | |||
| 99 | +++ | ||
| 100 | *** The D-Bus object manager interface is implemented. | ||
| 101 | |||
| 102 | +++ | ||
| 103 | *** Variables of type :(u)int32 and :(u)int64 accept floating points, | ||
| 104 | if their value does not fit into Emacs's integer range. | ||
| 105 | |||
| 106 | +++ | ||
| 107 | *** The function `dbus-call-method' works non-blocking now, it can be | ||
| 108 | interrupted by C-g. `dbus-call-method-non-blocking' is obsolete. | ||
| 109 | |||
| 110 | +++ | ||
| 111 | *** Signals can be sent also as unicast message. | ||
| 112 | |||
| 113 | +++ | ||
| 114 | *** The argument list of `dbus-register-signal' has been extended, | ||
| 115 | according to the new match rule types of D-Bus. See the manual for | ||
| 116 | details. | ||
| 117 | |||
| 118 | +++ | ||
| 119 | *** `dbus-init-bus' supports private connections. | ||
| 120 | |||
| 121 | +++ | ||
| 122 | *** There is a new function `dbus-setenv'. | ||
| 123 | |||
| 94 | ** Obsolete packages: | 124 | ** Obsolete packages: |
| 95 | 125 | ||
| 96 | *** mailpost.el | 126 | *** mailpost.el |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 14a83de342a..334e34bb712 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,36 @@ | |||
| 1 | 2012-04-22 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | Move functions from C to Lisp. Make non-blocking method calls | ||
| 4 | the default. Implement further D-Bus standard interfaces. | ||
| 5 | |||
| 6 | * net/dbus.el (dbus-message-internal): Declare function. Remove | ||
| 7 | unneeded function declarations. | ||
| 8 | (defvar dbus-message-type-invalid, dbus-message-type-method-call) | ||
| 9 | (dbus-message-type-method-return, dbus-message-type-error) | ||
| 10 | (dbus-message-type-signal): Declare variables. Remove local | ||
| 11 | definitions. | ||
| 12 | (dbus-interface-dbus, dbus-interface-peer) | ||
| 13 | (dbus-interface-introspectable, dbus-interface-properties) | ||
| 14 | (dbus-path-emacs, dbus-interface-emacs, dbus-return-values-table): | ||
| 15 | Adapt docstring. | ||
| 16 | (dbus-interface-objectmanager): New defconst. | ||
| 17 | (dbus-call-method, dbus-call-method-asynchronously) | ||
| 18 | (dbus-send-signal, dbus-method-return-internal) | ||
| 19 | (dbus-method-error-internal, dbus-register-service) | ||
| 20 | (dbus-register-signal, dbus-register-method): New defuns, moved | ||
| 21 | from dbusbind.c | ||
| 22 | (dbus-call-method-handler, dbus-setenv) | ||
| 23 | (dbus-get-all-managed-objects, dbus-managed-objects-handler): New | ||
| 24 | defuns. | ||
| 25 | (dbus-call-method-non-blocking): Make it an obsolete function. | ||
| 26 | (dbus-unregister-object, dbus-unregister-service) | ||
| 27 | (dbus-handle-event, dbus-register-property) | ||
| 28 | (dbus-property-handler): Obey the new structure of | ||
| 29 | `bus-registered-objects'. | ||
| 30 | (dbus-introspect): Use `dbus-call-method'. Use a timeout. | ||
| 31 | (dbus-get-property, dbus-set-property, dbus-get-all-properties): | ||
| 32 | Use `dbus-call-method'. | ||
| 33 | |||
| 1 | 2012-04-22 Chong Yidong <cyd@gnu.org> | 34 | 2012-04-22 Chong Yidong <cyd@gnu.org> |
| 2 | 35 | ||
| 3 | * cus-edit.el (custom-commands, custom-reset-menu) | 36 | * cus-edit.el (custom-commands, custom-reset-menu) |
diff --git a/lisp/net/dbus.el b/lisp/net/dbus.el index e3144a53fab..ee2bdecb1ac 100644 --- a/lisp/net/dbus.el +++ b/lisp/net/dbus.el | |||
| @@ -28,19 +28,19 @@ | |||
| 28 | 28 | ||
| 29 | ;; Low-level language bindings are implemented in src/dbusbind.c. | 29 | ;; Low-level language bindings are implemented in src/dbusbind.c. |
| 30 | 30 | ||
| 31 | ;; D-Bus support in the Emacs core can be disabled with configuration | ||
| 32 | ;; option "--without-dbus". | ||
| 33 | |||
| 31 | ;;; Code: | 34 | ;;; Code: |
| 32 | 35 | ||
| 33 | ;; D-Bus support in the Emacs core can be disabled with configuration | 36 | ;; Declare used subroutines and variables. |
| 34 | ;; option "--without-dbus". Declare used subroutines and variables. | 37 | (declare-function dbus-message-internal "dbusbind.c") |
| 35 | (declare-function dbus-call-method "dbusbind.c") | ||
| 36 | (declare-function dbus-call-method-asynchronously "dbusbind.c") | ||
| 37 | (declare-function dbus-init-bus "dbusbind.c") | 38 | (declare-function dbus-init-bus "dbusbind.c") |
| 38 | (declare-function dbus-method-return-internal "dbusbind.c") | 39 | (defvar dbus-message-type-invalid) |
| 39 | (declare-function dbus-method-error-internal "dbusbind.c") | 40 | (defvar dbus-message-type-method-call) |
| 40 | (declare-function dbus-register-service "dbusbind.c") | 41 | (defvar dbus-message-type-method-return) |
| 41 | (declare-function dbus-register-signal "dbusbind.c") | 42 | (defvar dbus-message-type-error) |
| 42 | (declare-function dbus-register-method "dbusbind.c") | 43 | (defvar dbus-message-type-signal) |
| 43 | (declare-function dbus-send-signal "dbusbind.c") | ||
| 44 | (defvar dbus-debug) | 44 | (defvar dbus-debug) |
| 45 | (defvar dbus-registered-objects-table) | 45 | (defvar dbus-registered-objects-table) |
| 46 | 46 | ||
| @@ -56,39 +56,93 @@ | |||
| 56 | (defconst dbus-path-dbus "/org/freedesktop/DBus" | 56 | (defconst dbus-path-dbus "/org/freedesktop/DBus" |
| 57 | "The object path used to talk to the bus itself.") | 57 | "The object path used to talk to the bus itself.") |
| 58 | 58 | ||
| 59 | ;; Default D-Bus interfaces. | ||
| 60 | |||
| 59 | (defconst dbus-interface-dbus "org.freedesktop.DBus" | 61 | (defconst dbus-interface-dbus "org.freedesktop.DBus" |
| 60 | "The interface exported by the object with `dbus-service-dbus' and `dbus-path-dbus'.") | 62 | "The interface exported by the service `dbus-service-dbus'.") |
| 61 | 63 | ||
| 62 | (defconst dbus-interface-peer (concat dbus-interface-dbus ".Peer") | 64 | (defconst dbus-interface-peer (concat dbus-interface-dbus ".Peer") |
| 63 | "The interface for peer objects.") | 65 | "The interface for peer objects. |
| 66 | See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-peer'.") | ||
| 67 | |||
| 68 | ;; <interface name="org.freedesktop.DBus.Peer"> | ||
| 69 | ;; <method name="Ping"> | ||
| 70 | ;; </method> | ||
| 71 | ;; <method name="GetMachineId"> | ||
| 72 | ;; <arg name="machine_uuid" type="s" direction="out"/> | ||
| 73 | ;; </method> | ||
| 74 | ;; </interface> | ||
| 64 | 75 | ||
| 65 | (defconst dbus-interface-introspectable | 76 | (defconst dbus-interface-introspectable |
| 66 | (concat dbus-interface-dbus ".Introspectable") | 77 | (concat dbus-interface-dbus ".Introspectable") |
| 67 | "The interface supported by introspectable objects.") | 78 | "The interface supported by introspectable objects. |
| 79 | See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable'.") | ||
| 68 | 80 | ||
| 69 | (defconst dbus-interface-properties (concat dbus-interface-dbus ".Properties") | 81 | ;; <interface name="org.freedesktop.DBus.Introspectable"> |
| 70 | "The interface for property objects.") | 82 | ;; <method name="Introspect"> |
| 83 | ;; <arg name="data" type="s" direction="out"/> | ||
| 84 | ;; </method> | ||
| 85 | ;; </interface> | ||
| 71 | 86 | ||
| 87 | (defconst dbus-interface-properties (concat dbus-interface-dbus ".Properties") | ||
| 88 | "The interface for property objects. | ||
| 89 | See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties'.") | ||
| 90 | |||
| 91 | ;; <interface name="org.freedesktop.DBus.Properties"> | ||
| 92 | ;; <method name="Get"> | ||
| 93 | ;; <arg name="interface" type="s" direction="in"/> | ||
| 94 | ;; <arg name="propname" type="s" direction="in"/> | ||
| 95 | ;; <arg name="value" type="v" direction="out"/> | ||
| 96 | ;; </method> | ||
| 97 | ;; <method name="Set"> | ||
| 98 | ;; <arg name="interface" type="s" direction="in"/> | ||
| 99 | ;; <arg name="propname" type="s" direction="in"/> | ||
| 100 | ;; <arg name="value" type="v" direction="in"/> | ||
| 101 | ;; </method> | ||
| 102 | ;; <method name="GetAll"> | ||
| 103 | ;; <arg name="interface" type="s" direction="in"/> | ||
| 104 | ;; <arg name="props" type="a{sv}" direction="out"/> | ||
| 105 | ;; </method> | ||
| 106 | ;; <signal name="PropertiesChanged"> | ||
| 107 | ;; <arg name="interface" type="s"/> | ||
| 108 | ;; <arg name="changed_properties" type="a{sv}"/> | ||
| 109 | ;; <arg name="invalidated_properties" type="as"/> | ||
| 110 | ;; </signal> | ||
| 111 | ;; </interface> | ||
| 112 | |||
| 113 | (defconst dbus-interface-objectmanager | ||
| 114 | (concat dbus-interface-dbus ".ObjectManager") | ||
| 115 | "The object manager interface. | ||
| 116 | See URL `http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager'.") | ||
| 117 | |||
| 118 | ;; <interface name="org.freedesktop.DBus.ObjectManager"> | ||
| 119 | ;; <method name="GetManagedObjects"> | ||
| 120 | ;; <arg name="object_paths_interfaces_and_properties" | ||
| 121 | ;; type="a{oa{sa{sv}}}" direction="out"/> | ||
| 122 | ;; </method> | ||
| 123 | ;; <signal name="InterfacesAdded"> | ||
| 124 | ;; <arg name="object_path" type="o"/> | ||
| 125 | ;; <arg name="interfaces_and_properties" type="a{sa{sv}}"/> | ||
| 126 | ;; </signal> | ||
| 127 | ;; <signal name="InterfacesRemoved"> | ||
| 128 | ;; <arg name="object_path" type="o"/> | ||
| 129 | ;; <arg name="interfaces" type="as"/> | ||
| 130 | ;; </signal> | ||
| 131 | ;; </interface> | ||
| 132 | |||
| 133 | ;; Emacs defaults. | ||
| 72 | (defconst dbus-service-emacs "org.gnu.Emacs" | 134 | (defconst dbus-service-emacs "org.gnu.Emacs" |
| 73 | "The well known service name of Emacs.") | 135 | "The well known service name of Emacs.") |
| 74 | 136 | ||
| 75 | (defconst dbus-path-emacs "/org/gnu/Emacs" | 137 | (defconst dbus-path-emacs "/org/gnu/Emacs" |
| 76 | "The object path head used by Emacs.") | 138 | "The object path namespace used by Emacs. |
| 139 | All object paths provided by the service `dbus-service-emacs' | ||
| 140 | shall be subdirectories of this path.") | ||
| 77 | 141 | ||
| 78 | (defconst dbus-message-type-invalid 0 | 142 | (defconst dbus-interface-emacs "org.gnu.Emacs" |
| 79 | "This value is never a valid message type.") | 143 | "The interface namespace used by Emacs.") |
| 80 | 144 | ||
| 81 | (defconst dbus-message-type-method-call 1 | 145 | ;; D-Bus constants. |
| 82 | "Message type of a method call message.") | ||
| 83 | |||
| 84 | (defconst dbus-message-type-method-return 2 | ||
| 85 | "Message type of a method return message.") | ||
| 86 | |||
| 87 | (defconst dbus-message-type-error 3 | ||
| 88 | "Message type of an error reply message.") | ||
| 89 | |||
| 90 | (defconst dbus-message-type-signal 4 | ||
| 91 | "Message type of a signal message.") | ||
| 92 | 146 | ||
| 93 | (defmacro dbus-ignore-errors (&rest body) | 147 | (defmacro dbus-ignore-errors (&rest body) |
| 94 | "Execute BODY; signal D-Bus error when `dbus-debug' is non-nil. | 148 | "Execute BODY; signal D-Bus error when `dbus-debug' is non-nil. |
| @@ -105,15 +159,267 @@ Every function must accept two arguments, the event and the error variable | |||
| 105 | caught in `condition-case' by `dbus-error'.") | 159 | caught in `condition-case' by `dbus-error'.") |
| 106 | 160 | ||
| 107 | 161 | ||
| 108 | ;;; Hash table of registered functions. | 162 | ;;; Basic D-Bus message functions. |
| 109 | 163 | ||
| 110 | (defvar dbus-return-values-table (make-hash-table :test 'equal) | 164 | (defvar dbus-return-values-table (make-hash-table :test 'equal) |
| 111 | "Hash table for temporary storing arguments of reply messages. | 165 | "Hash table for temporary storing arguments of reply messages. |
| 112 | A key in this hash table is a list (BUS SERIAL). BUS is either a | 166 | A key in this hash table is a list (:serial BUS SERIAL), like in |
| 113 | Lisp symbol, `:system' or `:session', or a string denoting the | 167 | `dbus-registered-objects-table'. BUS is either a Lisp symbol, |
| 114 | bus address. SERIAL is the serial number of the reply message. | 168 | `:system' or `:session', or a string denoting the bus address. |
| 115 | See `dbus-call-method-non-blocking-handler' and | 169 | SERIAL is the serial number of the reply message.") |
| 116 | `dbus-call-method-non-blocking'.") | 170 | |
| 171 | (defun dbus-call-method-handler (&rest args) | ||
| 172 | "Handler for reply messages of asynchronous D-Bus message calls. | ||
| 173 | It calls the function stored in `dbus-registered-objects-table'. | ||
| 174 | The result will be made available in `dbus-return-values-table'." | ||
| 175 | (puthash (list :serial | ||
| 176 | (dbus-event-bus-name last-input-event) | ||
| 177 | (dbus-event-serial-number last-input-event)) | ||
| 178 | (if (= (length args) 1) (car args) args) | ||
| 179 | dbus-return-values-table)) | ||
| 180 | |||
| 181 | (defun dbus-call-method (bus service path interface method &rest args) | ||
| 182 | "Call METHOD on the D-Bus BUS. | ||
| 183 | |||
| 184 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 185 | denoting the bus address. | ||
| 186 | |||
| 187 | SERVICE is the D-Bus service name to be used. PATH is the D-Bus | ||
| 188 | object path SERVICE is registered at. INTERFACE is an interface | ||
| 189 | offered by SERVICE. It must provide METHOD. | ||
| 190 | |||
| 191 | If the parameter `:timeout' is given, the following integer TIMEOUT | ||
| 192 | specifies the maximum number of milliseconds the method call must | ||
| 193 | return. The default value is 25,000. If the method call doesn't | ||
| 194 | return in time, a D-Bus error is raised. | ||
| 195 | |||
| 196 | All other arguments ARGS are passed to METHOD as arguments. They are | ||
| 197 | converted into D-Bus types via the following rules: | ||
| 198 | |||
| 199 | t and nil => DBUS_TYPE_BOOLEAN | ||
| 200 | number => DBUS_TYPE_UINT32 | ||
| 201 | integer => DBUS_TYPE_INT32 | ||
| 202 | float => DBUS_TYPE_DOUBLE | ||
| 203 | string => DBUS_TYPE_STRING | ||
| 204 | list => DBUS_TYPE_ARRAY | ||
| 205 | |||
| 206 | All arguments can be preceded by a type symbol. For details about | ||
| 207 | type symbols, see Info node `(dbus)Type Conversion'. | ||
| 208 | |||
| 209 | `dbus-call-method' returns the resulting values of METHOD as a list of | ||
| 210 | Lisp objects. The type conversion happens the other direction as for | ||
| 211 | input arguments. It follows the mapping rules: | ||
| 212 | |||
| 213 | DBUS_TYPE_BOOLEAN => t or nil | ||
| 214 | DBUS_TYPE_BYTE => number | ||
| 215 | DBUS_TYPE_UINT16 => number | ||
| 216 | DBUS_TYPE_INT16 => integer | ||
| 217 | DBUS_TYPE_UINT32 => number or float | ||
| 218 | DBUS_TYPE_UNIX_FD => number or float | ||
| 219 | DBUS_TYPE_INT32 => integer or float | ||
| 220 | DBUS_TYPE_UINT64 => number or float | ||
| 221 | DBUS_TYPE_INT64 => integer or float | ||
| 222 | DBUS_TYPE_DOUBLE => float | ||
| 223 | DBUS_TYPE_STRING => string | ||
| 224 | DBUS_TYPE_OBJECT_PATH => string | ||
| 225 | DBUS_TYPE_SIGNATURE => string | ||
| 226 | DBUS_TYPE_ARRAY => list | ||
| 227 | DBUS_TYPE_VARIANT => list | ||
| 228 | DBUS_TYPE_STRUCT => list | ||
| 229 | DBUS_TYPE_DICT_ENTRY => list | ||
| 230 | |||
| 231 | Example: | ||
| 232 | |||
| 233 | \(dbus-call-method | ||
| 234 | :session \"org.gnome.seahorse\" \"/org/gnome/seahorse/keys/openpgp\" | ||
| 235 | \"org.gnome.seahorse.Keys\" \"GetKeyField\" | ||
| 236 | \"openpgp:657984B8C7A966DD\" \"simple-name\") | ||
| 237 | |||
| 238 | => (t (\"Philip R. Zimmermann\")) | ||
| 239 | |||
| 240 | If the result of the METHOD call is just one value, the converted Lisp | ||
| 241 | object is returned instead of a list containing this single Lisp object. | ||
| 242 | |||
| 243 | \(dbus-call-method | ||
| 244 | :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/devices/computer\" | ||
| 245 | \"org.freedesktop.Hal.Device\" \"GetPropertyString\" | ||
| 246 | \"system.kernel.machine\") | ||
| 247 | |||
| 248 | => \"i686\"" | ||
| 249 | |||
| 250 | (or (memq bus '(:system :session)) (stringp bus) | ||
| 251 | (signal 'wrong-type-argument (list 'keywordp bus))) | ||
| 252 | (or (stringp service) | ||
| 253 | (signal 'wrong-type-argument (list 'stringp service))) | ||
| 254 | (or (stringp path) | ||
| 255 | (signal 'wrong-type-argument (list 'stringp path))) | ||
| 256 | (or (stringp interface) | ||
| 257 | (signal 'wrong-type-argument (list 'stringp interface))) | ||
| 258 | (or (stringp method) | ||
| 259 | (signal 'wrong-type-argument (list 'stringp method))) | ||
| 260 | |||
| 261 | (let ((timeout (plist-get args :timeout)) | ||
| 262 | (key | ||
| 263 | (apply | ||
| 264 | 'dbus-message-internal dbus-message-type-method-call | ||
| 265 | bus service path interface method 'dbus-call-method-handler args))) | ||
| 266 | ;; Wait until `dbus-call-method-handler' has put the result into | ||
| 267 | ;; `dbus-return-values-table'. If no timeout is given, use the | ||
| 268 | ;; default 25". | ||
| 269 | (with-timeout ((if timeout (/ timeout 1000.0) 25)) | ||
| 270 | (while (eq (gethash key dbus-return-values-table :ignore) :ignore) | ||
| 271 | (read-event nil nil 0.1))) | ||
| 272 | |||
| 273 | ;; Cleanup `dbus-return-values-table'. Return the result. | ||
| 274 | (prog1 | ||
| 275 | (gethash key dbus-return-values-table) | ||
| 276 | (remhash key dbus-return-values-table)))) | ||
| 277 | |||
| 278 | ;; `dbus-call-method' works non-blocking now. | ||
| 279 | (defalias 'dbus-call-method-non-blocking 'dbus-call-method) | ||
| 280 | (make-obsolete 'dbus-call-method-non-blocking 'dbus-call-method "24.2") | ||
| 281 | |||
| 282 | (defun dbus-call-method-asynchronously | ||
| 283 | (bus service path interface method handler &rest args) | ||
| 284 | "Call METHOD on the D-Bus BUS asynchronously. | ||
| 285 | |||
| 286 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 287 | denoting the bus address. | ||
| 288 | |||
| 289 | SERVICE is the D-Bus service name to be used. PATH is the D-Bus | ||
| 290 | object path SERVICE is registered at. INTERFACE is an interface | ||
| 291 | offered by SERVICE. It must provide METHOD. | ||
| 292 | |||
| 293 | HANDLER is a Lisp function, which is called when the corresponding | ||
| 294 | return message has arrived. If HANDLER is nil, no return message | ||
| 295 | will be expected. | ||
| 296 | |||
| 297 | If the parameter `:timeout' is given, the following integer TIMEOUT | ||
| 298 | specifies the maximum number of milliseconds the method call must | ||
| 299 | return. The default value is 25,000. If the method call doesn't | ||
| 300 | return in time, a D-Bus error is raised. | ||
| 301 | |||
| 302 | All other arguments ARGS are passed to METHOD as arguments. They are | ||
| 303 | converted into D-Bus types via the following rules: | ||
| 304 | |||
| 305 | t and nil => DBUS_TYPE_BOOLEAN | ||
| 306 | number => DBUS_TYPE_UINT32 | ||
| 307 | integer => DBUS_TYPE_INT32 | ||
| 308 | float => DBUS_TYPE_DOUBLE | ||
| 309 | string => DBUS_TYPE_STRING | ||
| 310 | list => DBUS_TYPE_ARRAY | ||
| 311 | |||
| 312 | All arguments can be preceded by a type symbol. For details about | ||
| 313 | type symbols, see Info node `(dbus)Type Conversion'. | ||
| 314 | |||
| 315 | If HANDLER is a Lisp function, the function returns a key into the | ||
| 316 | hash table `dbus-registered-objects-table'. The corresponding entry | ||
| 317 | in the hash table is removed, when the return message has been arrived, | ||
| 318 | and HANDLER is called. | ||
| 319 | |||
| 320 | Example: | ||
| 321 | |||
| 322 | \(dbus-call-method-asynchronously | ||
| 323 | :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/devices/computer\" | ||
| 324 | \"org.freedesktop.Hal.Device\" \"GetPropertyString\" 'message | ||
| 325 | \"system.kernel.machine\") | ||
| 326 | |||
| 327 | => \(:serial :system 2) | ||
| 328 | |||
| 329 | -| i686" | ||
| 330 | |||
| 331 | (or (memq bus '(:system :session)) (stringp bus) | ||
| 332 | (signal 'wrong-type-argument (list 'keywordp bus))) | ||
| 333 | (or (stringp service) | ||
| 334 | (signal 'wrong-type-argument (list 'stringp service))) | ||
| 335 | (or (stringp path) | ||
| 336 | (signal 'wrong-type-argument (list 'stringp path))) | ||
| 337 | (or (stringp interface) | ||
| 338 | (signal 'wrong-type-argument (list 'stringp interface))) | ||
| 339 | (or (stringp method) | ||
| 340 | (signal 'wrong-type-argument (list 'stringp method))) | ||
| 341 | (or (null handler) (functionp handler) | ||
| 342 | (signal 'wrong-type-argument (list 'functionp handler))) | ||
| 343 | |||
| 344 | (apply 'dbus-message-internal dbus-message-type-method-call | ||
| 345 | bus service path interface method handler args)) | ||
| 346 | |||
| 347 | (defun dbus-send-signal (bus service path interface signal &rest args) | ||
| 348 | "Send signal SIGNAL on the D-Bus BUS. | ||
| 349 | |||
| 350 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 351 | denoting the bus address. The signal is sent from the D-Bus object | ||
| 352 | Emacs is registered at BUS. | ||
| 353 | |||
| 354 | SERVICE is the D-Bus name SIGNAL is sent to. It can be either a known | ||
| 355 | name or a unique name. If SERVICE is nil, the signal is sent as | ||
| 356 | broadcast message. PATH is the D-Bus object path SIGNAL is sent from. | ||
| 357 | INTERFACE is an interface available at PATH. It must provide signal | ||
| 358 | SIGNAL. | ||
| 359 | |||
| 360 | All other arguments ARGS are passed to SIGNAL as arguments. They are | ||
| 361 | converted into D-Bus types via the following rules: | ||
| 362 | |||
| 363 | t and nil => DBUS_TYPE_BOOLEAN | ||
| 364 | number => DBUS_TYPE_UINT32 | ||
| 365 | integer => DBUS_TYPE_INT32 | ||
| 366 | float => DBUS_TYPE_DOUBLE | ||
| 367 | string => DBUS_TYPE_STRING | ||
| 368 | list => DBUS_TYPE_ARRAY | ||
| 369 | |||
| 370 | All arguments can be preceded by a type symbol. For details about | ||
| 371 | type symbols, see Info node `(dbus)Type Conversion'. | ||
| 372 | |||
| 373 | Example: | ||
| 374 | |||
| 375 | \(dbus-send-signal | ||
| 376 | :session nil \"/org/gnu/Emacs\" \"org.gnu.Emacs.FileManager\" | ||
| 377 | \"FileModified\" \"/home/albinus/.emacs\")" | ||
| 378 | |||
| 379 | (or (memq bus '(:system :session)) (stringp bus) | ||
| 380 | (signal 'wrong-type-argument (list 'keywordp bus))) | ||
| 381 | (or (null service) (stringp service) | ||
| 382 | (signal 'wrong-type-argument (list 'stringp service))) | ||
| 383 | (or (stringp path) | ||
| 384 | (signal 'wrong-type-argument (list 'stringp path))) | ||
| 385 | (or (stringp interface) | ||
| 386 | (signal 'wrong-type-argument (list 'stringp interface))) | ||
| 387 | (or (stringp signal) | ||
| 388 | (signal 'wrong-type-argument (list 'stringp signal))) | ||
| 389 | |||
| 390 | (apply 'dbus-message-internal dbus-message-type-signal | ||
| 391 | bus service path interface signal args)) | ||
| 392 | |||
| 393 | (defun dbus-method-return-internal (bus service serial &rest args) | ||
| 394 | "Return for message SERIAL on the D-Bus BUS. | ||
| 395 | This is an internal function, it shall not be used outside dbus.el." | ||
| 396 | |||
| 397 | (or (memq bus '(:system :session)) (stringp bus) | ||
| 398 | (signal 'wrong-type-argument (list 'keywordp bus))) | ||
| 399 | (or (stringp service) | ||
| 400 | (signal 'wrong-type-argument (list 'stringp service))) | ||
| 401 | (or (natnump serial) | ||
| 402 | (signal 'wrong-type-argument (list 'natnump serial))) | ||
| 403 | |||
| 404 | (apply 'dbus-message-internal dbus-message-type-method-return | ||
| 405 | bus service serial args)) | ||
| 406 | |||
| 407 | (defun dbus-method-error-internal (bus service serial &rest args) | ||
| 408 | "Return error message for message SERIAL on the D-Bus BUS. | ||
| 409 | This is an internal function, it shall not be used outside dbus.el." | ||
| 410 | |||
| 411 | (or (memq bus '(:system :session)) (stringp bus) | ||
| 412 | (signal 'wrong-type-argument (list 'keywordp bus))) | ||
| 413 | (or (stringp service) | ||
| 414 | (signal 'wrong-type-argument (list 'stringp service))) | ||
| 415 | (or (natnump serial) | ||
| 416 | (signal 'wrong-type-argument (list 'natnump serial))) | ||
| 417 | |||
| 418 | (apply 'dbus-message-internal dbus-message-type-error | ||
| 419 | bus service serial args)) | ||
| 420 | |||
| 421 | |||
| 422 | ;;; Hash table of registered functions. | ||
| 117 | 423 | ||
| 118 | (defun dbus-list-hash-table () | 424 | (defun dbus-list-hash-table () |
| 119 | "Returns all registered member registrations to D-Bus. | 425 | "Returns all registered member registrations to D-Bus. |
| @@ -126,69 +432,78 @@ hash table." | |||
| 126 | dbus-registered-objects-table) | 432 | dbus-registered-objects-table) |
| 127 | result)) | 433 | result)) |
| 128 | 434 | ||
| 129 | (defun dbus-unregister-object (object) | 435 | (defun dbus-setenv (bus variable value) |
| 130 | "Unregister OBJECT from D-Bus. | 436 | "Set the value of the BUS environment variable named VARIABLE to VALUE. |
| 131 | OBJECT must be the result of a preceding `dbus-register-method', | ||
| 132 | `dbus-register-property' or `dbus-register-signal' call. It | ||
| 133 | returns `t' if OBJECT has been unregistered, `nil' otherwise. | ||
| 134 | 437 | ||
| 135 | When OBJECT identifies the last method or property, which is | 438 | BUS is either a Lisp symbol, `:system' or `:session', or a string |
| 136 | registered for the respective service, Emacs releases its | 439 | denoting the bus address. Both VARIABLE and VALUE should be strings. |
| 137 | association to the service from D-Bus." | ||
| 138 | ;; Check parameter. | ||
| 139 | (unless (and (consp object) (not (null (car object))) (consp (cdr object))) | ||
| 140 | (signal 'wrong-type-argument (list 'D-Bus object))) | ||
| 141 | 440 | ||
| 142 | ;; Find the corresponding entry in the hash table. | 441 | Normally, services inherit the environment of the BUS daemon. This |
| 143 | (let* ((key (car object)) | 442 | function adds to or modifies that environment when activating services. |
| 144 | (value (cadr object)) | ||
| 145 | (bus (car key)) | ||
| 146 | (service (car value)) | ||
| 147 | (entry (gethash key dbus-registered-objects-table)) | ||
| 148 | ret) | ||
| 149 | ;; key has the structure (BUS INTERFACE MEMBER). | ||
| 150 | ;; value has the structure (SERVICE PATH [HANDLER]). | ||
| 151 | ;; entry has the structure ((UNAME SERVICE PATH MEMBER [RULE]) ...). | ||
| 152 | ;; MEMBER is either a string (the handler), or a cons cell (a | ||
| 153 | ;; property value). UNAME and property values are not taken into | ||
| 154 | ;; account for comparison. | ||
| 155 | 443 | ||
| 156 | ;; Loop over the registered functions. | 444 | Some bus instances, such as `:system', may disable setting the environment." |
| 157 | (dolist (elt entry) | 445 | (dbus-call-method |
| 158 | (when (equal | 446 | bus dbus-service-dbus dbus-path-dbus |
| 159 | value | 447 | dbus-interface-dbus "UpdateActivationEnvironment" |
| 160 | (butlast (cdr elt) (- (length (cdr elt)) (length value)))) | 448 | `(:array (:dict-entry ,variable ,value)))) |
| 161 | (setq ret t) | 449 | |
| 162 | ;; Compute new hash value. If it is empty, remove it from the | 450 | (defun dbus-register-service (bus service &rest flags) |
| 163 | ;; hash table. | 451 | "Register known name SERVICE on the D-Bus BUS. |
| 164 | (unless (puthash key (delete elt entry) dbus-registered-objects-table) | 452 | |
| 165 | (remhash key dbus-registered-objects-table)) | 453 | BUS is either a Lisp symbol, `:system' or `:session', or a string |
| 166 | ;; Remove match rule of signals. | 454 | denoting the bus address. |
| 167 | (let ((rule (nth 4 elt))) | 455 | |
| 168 | (when (stringp rule) | 456 | SERVICE is the D-Bus service name that should be registered. It must |
| 169 | (setq service nil) ; We do not need to unregister the service. | 457 | be a known name. |
| 170 | (dbus-call-method | 458 | |
| 171 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | 459 | FLAGS are keywords, which control how the service name is registered. |
| 172 | "RemoveMatch" rule))))) | 460 | The following keywords are recognized: |
| 173 | ;; Check, whether there is still a registered function or property | 461 | |
| 174 | ;; for the given service. If not, unregister the service from the | 462 | `:allow-replacement': Allow another service to become the primary |
| 175 | ;; bus. | 463 | owner if requested. |
| 176 | (when service | 464 | |
| 177 | (dolist (elt entry) | 465 | `:replace-existing': Request to replace the current primary owner. |
| 178 | (let (found) | 466 | |
| 179 | (maphash | 467 | `:do-not-queue': If we can not become the primary owner do not place |
| 180 | (lambda (k v) | 468 | us in the queue. |
| 181 | (dolist (e v) | 469 | |
| 182 | (ignore-errors | 470 | The function returns a keyword, indicating the result of the |
| 183 | (when (and (equal bus (car k)) (string-equal service (cadr e))) | 471 | operation. One of the following keywords is returned: |
| 184 | (setq found t))))) | 472 | |
| 185 | dbus-registered-objects-table) | 473 | `:primary-owner': Service has become the primary owner of the |
| 186 | (unless found | 474 | requested name. |
| 187 | (dbus-call-method | 475 | |
| 188 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | 476 | `:in-queue': Service could not become the primary owner and has been |
| 189 | "ReleaseName" service))))) | 477 | placed in the queue. |
| 190 | ;; Return. | 478 | |
| 191 | ret)) | 479 | `:exists': Service is already in the queue. |
| 480 | |||
| 481 | `:already-owner': Service is already the primary owner." | ||
| 482 | |||
| 483 | ;; Add ObjectManager handler. | ||
| 484 | (dbus-register-method | ||
| 485 | bus service nil dbus-interface-objectmanager "GetManagedObjects" | ||
| 486 | 'dbus-managed-objects-handler 'dont-register) | ||
| 487 | |||
| 488 | (let ((arg 0) | ||
| 489 | reply) | ||
| 490 | (dolist (flag flags) | ||
| 491 | (setq arg | ||
| 492 | (+ arg | ||
| 493 | (case flag | ||
| 494 | (:allow-replacement 1) | ||
| 495 | (:replace-existing 2) | ||
| 496 | (:do-not-queue 4) | ||
| 497 | (t (signal 'wrong-type-argument (list flag))))))) | ||
| 498 | (setq reply (dbus-call-method | ||
| 499 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | ||
| 500 | "RequestName" service arg)) | ||
| 501 | (case reply | ||
| 502 | (1 :primary-owner) | ||
| 503 | (2 :in-queue) | ||
| 504 | (3 :exists) | ||
| 505 | (4 :already-owner) | ||
| 506 | (t (signal 'dbus-error (list "Could not register service" service)))))) | ||
| 192 | 507 | ||
| 193 | (defun dbus-unregister-service (bus service) | 508 | (defun dbus-unregister-service (bus service) |
| 194 | "Unregister all objects related to SERVICE from D-Bus BUS. | 509 | "Unregister all objects related to SERVICE from D-Bus BUS. |
| @@ -209,7 +524,7 @@ queue of this service." | |||
| 209 | (lambda (key value) | 524 | (lambda (key value) |
| 210 | (dolist (elt value) | 525 | (dolist (elt value) |
| 211 | (ignore-errors | 526 | (ignore-errors |
| 212 | (when (and (equal bus (car key)) (string-equal service (cadr elt))) | 527 | (when (and (equal bus (cadr key)) (string-equal service (cadr elt))) |
| 213 | (unless | 528 | (unless |
| 214 | (puthash key (delete elt value) dbus-registered-objects-table) | 529 | (puthash key (delete elt value) dbus-registered-objects-table) |
| 215 | (remhash key dbus-registered-objects-table)))))) | 530 | (remhash key dbus-registered-objects-table)))))) |
| @@ -223,94 +538,274 @@ queue of this service." | |||
| 223 | (3 :not-owner) | 538 | (3 :not-owner) |
| 224 | (t (signal 'dbus-error (list "Could not unregister service" service)))))) | 539 | (t (signal 'dbus-error (list "Could not unregister service" service)))))) |
| 225 | 540 | ||
| 226 | (defun dbus-call-method-non-blocking-handler (&rest args) | 541 | (defun dbus-register-signal |
| 227 | "Handler for reply messages of asynchronous D-Bus message calls. | 542 | (bus service path interface signal handler &rest args) |
| 228 | It calls the function stored in `dbus-registered-objects-table'. | 543 | "Register for a signal on the D-Bus BUS. |
| 229 | The result will be made available in `dbus-return-values-table'." | ||
| 230 | (puthash (list (dbus-event-bus-name last-input-event) | ||
| 231 | (dbus-event-serial-number last-input-event)) | ||
| 232 | (if (= (length args) 1) (car args) args) | ||
| 233 | dbus-return-values-table)) | ||
| 234 | 544 | ||
| 235 | (defun dbus-call-method-non-blocking | 545 | BUS is either a Lisp symbol, `:system' or `:session', or a string |
| 236 | (bus service path interface method &rest args) | 546 | denoting the bus address. |
| 237 | "Call METHOD on the D-Bus BUS, but don't block the event queue. | ||
| 238 | This is necessary for communicating to registered D-Bus methods, | ||
| 239 | which are running in the same Emacs process. | ||
| 240 | 547 | ||
| 241 | The arguments are the same as in `dbus-call-method'. | 548 | SERVICE is the D-Bus service name used by the sending D-Bus object. |
| 549 | It can be either a known name or the unique name of the D-Bus object | ||
| 550 | sending the signal. | ||
| 551 | |||
| 552 | PATH is the D-Bus object path SERVICE is registered. INTERFACE | ||
| 553 | is an interface offered by SERVICE. It must provide SIGNAL. | ||
| 554 | HANDLER is a Lisp function to be called when the signal is | ||
| 555 | received. It must accept as arguments the values SIGNAL is | ||
| 556 | sending. | ||
| 557 | |||
| 558 | SERVICE, PATH, INTERFACE and SIGNAL can be nil. This is | ||
| 559 | interpreted as a wildcard for the respective argument. | ||
| 560 | |||
| 561 | The remaining arguments ARGS can be keywords or keyword string pairs. | ||
| 562 | The meaning is as follows: | ||
| 563 | |||
| 564 | `:argN' STRING: | ||
| 565 | `:pathN' STRING: This stands for the Nth argument of the | ||
| 566 | signal. `:pathN' arguments can be used for object path wildcard | ||
| 567 | matches as specified by D-Bus, whilest an `:argN' argument | ||
| 568 | requires an exact match. | ||
| 569 | |||
| 570 | `:arg-namespace' STRING: Register for the signals, which first | ||
| 571 | argument defines the service or interface namespace STRING. | ||
| 572 | |||
| 573 | `:path-namespace' STRING: Register for the object path namespace | ||
| 574 | STRING. All signals sent from an object path, which has STRING as | ||
| 575 | the preceding string, are matched. This requires PATH to be nil. | ||
| 576 | |||
| 577 | `:eavesdrop': Register for unicast signals which are not directed | ||
| 578 | to the D-Bus object Emacs is registered at D-Bus BUS, if the | ||
| 579 | security policy of BUS allows this. | ||
| 580 | |||
| 581 | Example: | ||
| 582 | |||
| 583 | \(defun my-signal-handler (device) | ||
| 584 | (message \"Device %s added\" device)) | ||
| 585 | |||
| 586 | \(dbus-register-signal | ||
| 587 | :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\" | ||
| 588 | \"org.freedesktop.Hal.Manager\" \"DeviceAdded\" 'my-signal-handler) | ||
| 589 | |||
| 590 | => \(\(:signal :system \"org.freedesktop.Hal.Manager\" \"DeviceAdded\") | ||
| 591 | \(\"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\" my-signal-handler)) | ||
| 592 | |||
| 593 | `dbus-register-signal' returns an object, which can be used in | ||
| 594 | `dbus-unregister-object' for removing the registration." | ||
| 595 | |||
| 596 | (let ((counter 0) | ||
| 597 | (rule "type='signal'") | ||
| 598 | uname key key1 value) | ||
| 599 | |||
| 600 | ;; Retrieve unique name of service. If service is a known name, | ||
| 601 | ;; we will register for the corresponding unique name, if any. | ||
| 602 | ;; Signals are sent always with the unique name as sender. Note: | ||
| 603 | ;; the unique name of `dbus-service-dbus' is that string itself. | ||
| 604 | (if (and (stringp service) | ||
| 605 | (not (zerop (length service))) | ||
| 606 | (not (string-equal service dbus-service-dbus)) | ||
| 607 | (not (string-match "^:" service))) | ||
| 608 | (setq uname (dbus-get-name-owner bus service)) | ||
| 609 | (setq uname service)) | ||
| 610 | |||
| 611 | (setq rule (concat rule | ||
| 612 | (when uname (format ",sender='%s'" uname)) | ||
| 613 | (when interface (format ",interface='%s'" interface)) | ||
| 614 | (when signal (format ",member='%s'" signal)) | ||
| 615 | (when path (format ",path='%s'" path)))) | ||
| 616 | |||
| 617 | ;; Add arguments to the rule. | ||
| 618 | (if (or (stringp (car args)) (null (car args))) | ||
| 619 | ;; As backward compatibility option, we allow just strings. | ||
| 620 | (dolist (arg args) | ||
| 621 | (if (stringp arg) | ||
| 622 | (setq rule (concat rule (format ",arg%d='%s'" counter arg))) | ||
| 623 | (if arg (signal 'wrong-type-argument (list "Wrong argument" arg)))) | ||
| 624 | (setq counter (1+ counter))) | ||
| 625 | |||
| 626 | ;; Parse keywords. | ||
| 627 | (while args | ||
| 628 | (setq | ||
| 629 | key (car args) | ||
| 630 | rule (concat | ||
| 631 | rule | ||
| 632 | (cond | ||
| 633 | ;; `:arg0' .. `:arg63', `:path0' .. `:path63'. | ||
| 634 | ((and (keywordp key) | ||
| 635 | (string-match | ||
| 636 | "^:\\(arg\\|path\\)\\([[:digit:]]+\\)$" | ||
| 637 | (symbol-name key))) | ||
| 638 | (setq counter (match-string 2 (symbol-name key)) | ||
| 639 | args (cdr args) | ||
| 640 | value (car args)) | ||
| 641 | (unless (and (<= counter 63) (stringp value)) | ||
| 642 | (signal 'wrong-type-argument | ||
| 643 | (list "Wrong argument" key value))) | ||
| 644 | (format | ||
| 645 | ",arg%s%s='%s'" | ||
| 646 | counter | ||
| 647 | (if (string-equal (match-string 1 (symbol-name key)) "path") | ||
| 648 | "path" "") | ||
| 649 | value)) | ||
| 650 | ;; `:arg-namespace', `:path-namespace'. | ||
| 651 | ((and (keywordp key) | ||
| 652 | (string-match | ||
| 653 | "^:\\(arg\\|path\\)-namespace$" (symbol-name key))) | ||
| 654 | (setq args (cdr args) | ||
| 655 | value (car args)) | ||
| 656 | (unless (stringp value) | ||
| 657 | (signal 'wrong-type-argument | ||
| 658 | (list "Wrong argument" key value))) | ||
| 659 | (format | ||
| 660 | ",%s='%s'" | ||
| 661 | (if (string-equal (match-string 1 (symbol-name key)) "path") | ||
| 662 | "path_namespace" "arg0namespace") | ||
| 663 | value)) | ||
| 664 | ;; `:eavesdrop'. | ||
| 665 | ((eq key :eavesdrop) | ||
| 666 | ",eavesdrop='true'") | ||
| 667 | (t (signal 'wrong-type-argument (list "Wrong argument" key))))) | ||
| 668 | args (cdr args)))) | ||
| 669 | |||
| 670 | ;; Add the rule to the bus. | ||
| 671 | (condition-case err | ||
| 672 | (dbus-call-method | ||
| 673 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | ||
| 674 | "AddMatch" rule) | ||
| 675 | (dbus-error | ||
| 676 | (if (not (string-match "eavesdrop" rule)) | ||
| 677 | (signal (car err) (cdr err)) | ||
| 678 | ;; The D-Bus spec says we shall fall back to a rule without eavesdrop. | ||
| 679 | (when dbus-debug (message "Removing eavesdrop from rule %s" rule)) | ||
| 680 | (setq rule (replace-regexp-in-string ",eavesdrop='true'" "" rule)) | ||
| 681 | (dbus-call-method | ||
| 682 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | ||
| 683 | "AddMatch" rule)))) | ||
| 242 | 684 | ||
| 243 | usage: (dbus-call-method-non-blocking | 685 | (when dbus-debug (message "Matching rule \"%s\" created" rule)) |
| 244 | BUS SERVICE PATH INTERFACE METHOD | ||
| 245 | &optional :timeout TIMEOUT &rest ARGS)" | ||
| 246 | 686 | ||
| 247 | (let ((key | 687 | ;; Create a hash table entry. |
| 248 | (apply | 688 | (setq key (list :signal bus interface signal) |
| 249 | 'dbus-call-method-asynchronously | 689 | key1 (list uname service path handler rule) |
| 250 | bus service path interface method | 690 | value (gethash key dbus-registered-objects-table)) |
| 251 | 'dbus-call-method-non-blocking-handler args))) | 691 | (unless (member key1 value) |
| 252 | ;; Wait until `dbus-call-method-non-blocking-handler' has put the | 692 | (puthash key (cons key1 value) dbus-registered-objects-table)) |
| 253 | ;; result into `dbus-return-values-table'. | ||
| 254 | (while (eq (gethash key dbus-return-values-table :ignore) :ignore) | ||
| 255 | (read-event nil nil 0.1)) | ||
| 256 | 693 | ||
| 257 | ;; Cleanup `dbus-return-values-table'. Return the result. | 694 | ;; Return the object. |
| 258 | (prog1 | 695 | (list key (list service path handler)))) |
| 259 | (gethash key dbus-return-values-table nil) | ||
| 260 | (remhash key dbus-return-values-table)))) | ||
| 261 | 696 | ||
| 262 | (defun dbus-name-owner-changed-handler (&rest args) | 697 | (defun dbus-register-method |
| 263 | "Reapplies all member registrations to D-Bus. | 698 | (bus service path interface method handler &optional dont-register-service) |
| 264 | This handler is applied when a \"NameOwnerChanged\" signal has | 699 | "Register for method METHOD on the D-Bus BUS. |
| 265 | arrived. SERVICE is the object name for which the name owner has | 700 | |
| 266 | been changed. OLD-OWNER is the previous owner of SERVICE, or the | 701 | BUS is either a Lisp symbol, `:system' or `:session', or a string |
| 267 | empty string if SERVICE was not owned yet. NEW-OWNER is the new | 702 | denoting the bus address. |
| 268 | owner of SERVICE, or the empty string if SERVICE loses any name owner. | 703 | |
| 269 | 704 | SERVICE is the D-Bus service name of the D-Bus object METHOD is | |
| 270 | usage: (dbus-name-owner-changed-handler service old-owner new-owner)" | 705 | registered for. It must be a known name (See discussion of |
| 271 | (save-match-data | 706 | DONT-REGISTER-SERVICE below). |
| 272 | ;; Check the arguments. We should silently ignore it when they | 707 | |
| 273 | ;; are wrong. | 708 | PATH is the D-Bus object path SERVICE is registered (See discussion of |
| 274 | (if (and (= (length args) 3) | 709 | DONT-REGISTER-SERVICE below). INTERFACE is the interface offered by |
| 275 | (stringp (car args)) | 710 | SERVICE. It must provide METHOD. |
| 276 | (stringp (cadr args)) | 711 | |
| 277 | (stringp (caddr args))) | 712 | HANDLER is a Lisp function to be called when a method call is |
| 278 | (let ((service (car args)) | 713 | received. It must accept the input arguments of METHOD. The return |
| 279 | (old-owner (cadr args))) | 714 | value of HANDLER is used for composing the returning D-Bus message. |
| 280 | ;; Check whether SERVICE is a known name. | 715 | In case HANDLER shall return a reply message with an empty argument |
| 281 | (when (not (string-match "^:" service)) | 716 | list, HANDLER must return the symbol `:ignore'. |
| 282 | (maphash | 717 | |
| 283 | (lambda (key value) | 718 | When DONT-REGISTER-SERVICE is non-nil, the known name SERVICE is not |
| 284 | (dolist (elt value) | 719 | registered. This means that other D-Bus clients have no way of |
| 285 | ;; key has the structure (BUS INTERFACE MEMBER). | 720 | noticing the newly registered method. When interfaces are constructed |
| 286 | ;; elt has the structure (UNAME SERVICE PATH HANDLER). | 721 | incrementally by adding single methods or properties at a time, |
| 287 | (when (string-equal old-owner (car elt)) | 722 | DONT-REGISTER-SERVICE can be used to prevent other clients from |
| 288 | ;; Remove old key, and add new entry with changed name. | 723 | discovering the still incomplete interface." |
| 289 | (dbus-unregister-object (list key (cdr elt))) | 724 | |
| 290 | ;; Maybe we could arrange the lists a little bit better | 725 | ;; Register SERVICE. |
| 291 | ;; that we don't need to extract every single element? | 726 | (unless (or dont-register-service |
| 292 | (dbus-register-signal | 727 | (member service (dbus-list-names bus))) |
| 293 | ;; BUS SERVICE PATH | 728 | (dbus-register-service bus service)) |
| 294 | (nth 0 key) (nth 1 elt) (nth 2 elt) | 729 | |
| 295 | ;; INTERFACE MEMBER HANDLER | 730 | ;; Create a hash table entry. We use nil for the unique name, |
| 296 | (nth 1 key) (nth 2 key) (nth 3 elt))))) | 731 | ;; because the method might be called from anybody. |
| 297 | (copy-hash-table dbus-registered-objects-table)))) | 732 | (let* ((key (list :method bus interface method)) |
| 298 | ;; The error is reported only in debug mode. | 733 | (key1 (list nil service path handler)) |
| 299 | (when dbus-debug | 734 | (value (gethash key dbus-registered-objects-table))) |
| 300 | (signal | 735 | |
| 301 | 'dbus-error | 736 | (unless (member key1 value) |
| 302 | (cons | 737 | (puthash key (cons key1 value) dbus-registered-objects-table)) |
| 303 | (format "Wrong arguments of %s.NameOwnerChanged" dbus-interface-dbus) | 738 | |
| 304 | args)))))) | 739 | ;; Return the object. |
| 305 | 740 | (list key (list service path handler)))) | |
| 306 | ;; Register the handler. | 741 | |
| 307 | (when nil ;ignore-errors | 742 | (defun dbus-unregister-object (object) |
| 308 | (dbus-register-signal | 743 | "Unregister OBJECT from D-Bus. |
| 309 | :system dbus-service-dbus dbus-path-dbus dbus-interface-dbus | 744 | OBJECT must be the result of a preceding `dbus-register-method', |
| 310 | "NameOwnerChanged" 'dbus-name-owner-changed-handler) | 745 | `dbus-register-property' or `dbus-register-signal' call. It |
| 311 | (dbus-register-signal | 746 | returns `t' if OBJECT has been unregistered, `nil' otherwise. |
| 312 | :session dbus-service-dbus dbus-path-dbus dbus-interface-dbus | 747 | |
| 313 | "NameOwnerChanged" 'dbus-name-owner-changed-handler)) | 748 | When OBJECT identifies the last method or property, which is |
| 749 | registered for the respective service, Emacs releases its | ||
| 750 | association to the service from D-Bus." | ||
| 751 | ;; Check parameter. | ||
| 752 | (unless (and (consp object) (not (null (car object))) (consp (cdr object))) | ||
| 753 | (signal 'wrong-type-argument (list 'D-Bus object))) | ||
| 754 | |||
| 755 | ;; Find the corresponding entry in the hash table. | ||
| 756 | (let* ((key (car object)) | ||
| 757 | (type (car key)) | ||
| 758 | (bus (cadr key)) | ||
| 759 | (value (cadr object)) | ||
| 760 | (service (car value)) | ||
| 761 | (entry (gethash key dbus-registered-objects-table)) | ||
| 762 | ret) | ||
| 763 | ;; key has the structure (TYPE BUS INTERFACE MEMBER). | ||
| 764 | ;; value has the structure (SERVICE PATH [HANDLER]). | ||
| 765 | ;; entry has the structure ((UNAME SERVICE PATH MEMBER [RULE]) ...). | ||
| 766 | ;; MEMBER is either a string (the handler), or a cons cell (a | ||
| 767 | ;; property value). UNAME and property values are not taken into | ||
| 768 | ;; account for comparison. | ||
| 769 | |||
| 770 | ;; Loop over the registered functions. | ||
| 771 | (dolist (elt entry) | ||
| 772 | (when (equal | ||
| 773 | value | ||
| 774 | (butlast (cdr elt) (- (length (cdr elt)) (length value)))) | ||
| 775 | (setq ret t) | ||
| 776 | ;; Compute new hash value. If it is empty, remove it from the | ||
| 777 | ;; hash table. | ||
| 778 | (unless (puthash key (delete elt entry) dbus-registered-objects-table) | ||
| 779 | (remhash key dbus-registered-objects-table)) | ||
| 780 | ;; Remove match rule of signals. | ||
| 781 | (when (eq type :signal) | ||
| 782 | (dbus-call-method | ||
| 783 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | ||
| 784 | "RemoveMatch" (nth 4 elt))))) | ||
| 785 | |||
| 786 | ;; Check, whether there is still a registered function or property | ||
| 787 | ;; for the given service. If not, unregister the service from the | ||
| 788 | ;; bus. | ||
| 789 | (when (and service (memq type '(:method :property)) | ||
| 790 | (not (catch :found | ||
| 791 | (progn | ||
| 792 | (maphash | ||
| 793 | (lambda (k v) | ||
| 794 | (dolist (e v) | ||
| 795 | (ignore-errors | ||
| 796 | (and | ||
| 797 | ;; Bus. | ||
| 798 | (equal bus (cadr k)) | ||
| 799 | ;; Service. | ||
| 800 | (string-equal service (cadr e)) | ||
| 801 | ;; Non-empty object path. | ||
| 802 | (caddr e) | ||
| 803 | (throw :found t))))) | ||
| 804 | dbus-registered-objects-table) | ||
| 805 | nil)))) | ||
| 806 | (dbus-unregister-service bus service)) | ||
| 807 | ;; Return. | ||
| 808 | ret)) | ||
| 314 | 809 | ||
| 315 | 810 | ||
| 316 | ;;; D-Bus type conversion. | 811 | ;;; D-Bus type conversion. |
| @@ -437,9 +932,9 @@ If the HANDLER returns a `dbus-error', it is propagated as return message." | |||
| 437 | (dbus-ignore-errors | 932 | (dbus-ignore-errors |
| 438 | (if (eq result :ignore) | 933 | (if (eq result :ignore) |
| 439 | (dbus-method-return-internal | 934 | (dbus-method-return-internal |
| 440 | (nth 1 event) (nth 3 event) (nth 4 event)) | 935 | (nth 1 event) (nth 4 event) (nth 3 event)) |
| 441 | (apply 'dbus-method-return-internal | 936 | (apply 'dbus-method-return-internal |
| 442 | (nth 1 event) (nth 3 event) (nth 4 event) | 937 | (nth 1 event) (nth 4 event) (nth 3 event) |
| 443 | (if (consp result) result (list result))))))) | 938 | (if (consp result) result (list result))))))) |
| 444 | ;; Error handling. | 939 | ;; Error handling. |
| 445 | (dbus-error | 940 | (dbus-error |
| @@ -447,7 +942,7 @@ If the HANDLER returns a `dbus-error', it is propagated as return message." | |||
| 447 | (when (= dbus-message-type-method-call (nth 2 event)) | 942 | (when (= dbus-message-type-method-call (nth 2 event)) |
| 448 | (dbus-ignore-errors | 943 | (dbus-ignore-errors |
| 449 | (dbus-method-error-internal | 944 | (dbus-method-error-internal |
| 450 | (nth 1 event) (nth 3 event) (nth 4 event) (cadr err)))) | 945 | (nth 1 event) (nth 4 event) (nth 3 event) (cadr err)))) |
| 451 | ;; Propagate D-Bus error messages. | 946 | ;; Propagate D-Bus error messages. |
| 452 | (run-hook-with-args 'dbus-event-error-hooks event err) | 947 | (run-hook-with-args 'dbus-event-error-hooks event err) |
| 453 | (when (or dbus-debug (= dbus-message-type-error (nth 2 event))) | 948 | (when (or dbus-debug (= dbus-message-type-error (nth 2 event))) |
| @@ -596,11 +1091,11 @@ are strings. The result, the introspection data, is a string in | |||
| 596 | XML format." | 1091 | XML format." |
| 597 | ;; We don't want to raise errors. `dbus-call-method-non-blocking' | 1092 | ;; We don't want to raise errors. `dbus-call-method-non-blocking' |
| 598 | ;; is used, because the handler can be registered in our Emacs | 1093 | ;; is used, because the handler can be registered in our Emacs |
| 599 | ;; instance; caller an callee would block each other. | 1094 | ;; instance; caller and callee would block each other. |
| 600 | (dbus-ignore-errors | 1095 | (dbus-ignore-errors |
| 601 | (funcall | 1096 | (dbus-call-method |
| 602 | (if noninteractive 'dbus-call-method 'dbus-call-method-non-blocking) | 1097 | bus service path dbus-interface-introspectable "Introspect" |
| 603 | bus service path dbus-interface-introspectable "Introspect"))) | 1098 | :timeout 1000))) |
| 604 | 1099 | ||
| 605 | (defun dbus-introspect-xml (bus service path) | 1100 | (defun dbus-introspect-xml (bus service path) |
| 606 | "Return the introspection data of SERVICE in D-Bus BUS at object path PATH. | 1101 | "Return the introspection data of SERVICE in D-Bus BUS at object path PATH. |
| @@ -854,12 +1349,11 @@ be \"out\"." | |||
| 854 | It will be checked at BUS, SERVICE, PATH. The result can be any | 1349 | It will be checked at BUS, SERVICE, PATH. The result can be any |
| 855 | valid D-Bus value, or `nil' if there is no PROPERTY." | 1350 | valid D-Bus value, or `nil' if there is no PROPERTY." |
| 856 | (dbus-ignore-errors | 1351 | (dbus-ignore-errors |
| 857 | ;; "Get" returns a variant, so we must use the `car'. | 1352 | ;; "Get" returns a variant, so we must use the `car'. |
| 858 | (car | 1353 | (car |
| 859 | (funcall | 1354 | (dbus-call-method |
| 860 | (if noninteractive 'dbus-call-method 'dbus-call-method-non-blocking) | 1355 | bus service path dbus-interface-properties |
| 861 | bus service path dbus-interface-properties | 1356 | "Get" :timeout 500 interface property)))) |
| 862 | "Get" :timeout 500 interface property)))) | ||
| 863 | 1357 | ||
| 864 | (defun dbus-set-property (bus service path interface property value) | 1358 | (defun dbus-set-property (bus service path interface property value) |
| 865 | "Set value of PROPERTY of INTERFACE to VALUE. | 1359 | "Set value of PROPERTY of INTERFACE to VALUE. |
| @@ -867,13 +1361,12 @@ It will be checked at BUS, SERVICE, PATH. When the value has | |||
| 867 | been set successful, the result is VALUE. Otherwise, `nil' is | 1361 | been set successful, the result is VALUE. Otherwise, `nil' is |
| 868 | returned." | 1362 | returned." |
| 869 | (dbus-ignore-errors | 1363 | (dbus-ignore-errors |
| 870 | ;; "Set" requires a variant. | 1364 | ;; "Set" requires a variant. |
| 871 | (funcall | 1365 | (dbus-call-method |
| 872 | (if noninteractive 'dbus-call-method 'dbus-call-method-non-blocking) | 1366 | bus service path dbus-interface-properties |
| 873 | bus service path dbus-interface-properties | 1367 | "Set" :timeout 500 interface property (list :variant value)) |
| 874 | "Set" :timeout 500 interface property (list :variant value)) | 1368 | ;; Return VALUE. |
| 875 | ;; Return VALUE. | 1369 | (dbus-get-property bus service path interface property))) |
| 876 | (dbus-get-property bus service path interface property))) | ||
| 877 | 1370 | ||
| 878 | (defun dbus-get-all-properties (bus service path interface) | 1371 | (defun dbus-get-all-properties (bus service path interface) |
| 879 | "Return all properties of INTERFACE at BUS, SERVICE, PATH. | 1372 | "Return all properties of INTERFACE at BUS, SERVICE, PATH. |
| @@ -884,10 +1377,7 @@ name of the property, and its value. If there are no properties, | |||
| 884 | ;; "GetAll" returns "a{sv}". | 1377 | ;; "GetAll" returns "a{sv}". |
| 885 | (let (result) | 1378 | (let (result) |
| 886 | (dolist (dict | 1379 | (dolist (dict |
| 887 | (funcall | 1380 | (dbus-call-method |
| 888 | (if noninteractive | ||
| 889 | 'dbus-call-method | ||
| 890 | 'dbus-call-method-non-blocking) | ||
| 891 | bus service path dbus-interface-properties | 1381 | bus service path dbus-interface-properties |
| 892 | "GetAll" :timeout 500 interface) | 1382 | "GetAll" :timeout 500 interface) |
| 893 | result) | 1383 | result) |
| @@ -931,14 +1421,7 @@ constructed incrementally by adding single methods or properties | |||
| 931 | at a time, DONT-REGISTER-SERVICE can be used to prevent other | 1421 | at a time, DONT-REGISTER-SERVICE can be used to prevent other |
| 932 | clients from discovering the still incomplete interface." | 1422 | clients from discovering the still incomplete interface." |
| 933 | (unless (member access '(:read :readwrite)) | 1423 | (unless (member access '(:read :readwrite)) |
| 934 | (signal 'dbus-error (list "Access type invalid" access))) | 1424 | (signal 'wrong-type-argument (list "Access type invalid" access))) |
| 935 | |||
| 936 | ;; Register SERVICE. | ||
| 937 | (unless (or dont-register-service | ||
| 938 | (member service (dbus-list-names bus))) | ||
| 939 | (dbus-call-method | ||
| 940 | bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus | ||
| 941 | "RequestName" service 0)) | ||
| 942 | 1425 | ||
| 943 | ;; Add handlers for the three property-related methods. | 1426 | ;; Add handlers for the three property-related methods. |
| 944 | (dbus-register-method | 1427 | (dbus-register-method |
| @@ -951,20 +1434,20 @@ clients from discovering the still incomplete interface." | |||
| 951 | bus service path dbus-interface-properties "Set" | 1434 | bus service path dbus-interface-properties "Set" |
| 952 | 'dbus-property-handler 'dont-register) | 1435 | 'dbus-property-handler 'dont-register) |
| 953 | 1436 | ||
| 954 | ;; Register the name SERVICE with BUS. | 1437 | ;; Register SERVICE. |
| 955 | (unless dont-register-service | 1438 | (unless (or dont-register-service (member service (dbus-list-names bus))) |
| 956 | (dbus-register-service bus service)) | 1439 | (dbus-register-service bus service)) |
| 957 | 1440 | ||
| 958 | ;; Send the PropertiesChanged signal. | 1441 | ;; Send the PropertiesChanged signal. |
| 959 | (when emits-signal | 1442 | (when emits-signal |
| 960 | (dbus-send-signal | 1443 | (dbus-send-signal |
| 961 | bus service path dbus-interface-properties "PropertiesChanged" | 1444 | bus service path dbus-interface-properties "PropertiesChanged" |
| 962 | (list (list :dict-entry property (list :variant value))) | 1445 | `((:dict-entry ,property (:variant ,value))) |
| 963 | '(:array))) | 1446 | '(:array))) |
| 964 | 1447 | ||
| 965 | ;; Create a hash table entry. We use nil for the unique name, | 1448 | ;; Create a hash table entry. We use nil for the unique name, |
| 966 | ;; because the property might be accessed from anybody. | 1449 | ;; because the property might be accessed from anybody. |
| 967 | (let ((key (list bus interface property)) | 1450 | (let ((key (list :property bus interface property)) |
| 968 | (val | 1451 | (val |
| 969 | (list | 1452 | (list |
| 970 | (list | 1453 | (list |
| @@ -979,7 +1462,7 @@ clients from discovering the still incomplete interface." | |||
| 979 | 1462 | ||
| 980 | (defun dbus-property-handler (&rest args) | 1463 | (defun dbus-property-handler (&rest args) |
| 981 | "Default handler for the \"org.freedesktop.DBus.Properties\" interface. | 1464 | "Default handler for the \"org.freedesktop.DBus.Properties\" interface. |
| 982 | It will be registered for all objects created by `dbus-register-object'." | 1465 | It will be registered for all objects created by `dbus-register-property'." |
| 983 | (let ((bus (dbus-event-bus-name last-input-event)) | 1466 | (let ((bus (dbus-event-bus-name last-input-event)) |
| 984 | (service (dbus-event-service-name last-input-event)) | 1467 | (service (dbus-event-service-name last-input-event)) |
| 985 | (path (dbus-event-path-name last-input-event)) | 1468 | (path (dbus-event-path-name last-input-event)) |
| @@ -989,15 +1472,15 @@ It will be registered for all objects created by `dbus-register-object'." | |||
| 989 | (cond | 1472 | (cond |
| 990 | ;; "Get" returns a variant. | 1473 | ;; "Get" returns a variant. |
| 991 | ((string-equal method "Get") | 1474 | ((string-equal method "Get") |
| 992 | (let ((entry (gethash (list bus interface property) | 1475 | (let ((entry (gethash (list :property bus interface property) |
| 993 | dbus-registered-objects-table))) | 1476 | dbus-registered-objects-table))) |
| 994 | (when (string-equal path (nth 2 (car entry))) | 1477 | (when (string-equal path (nth 2 (car entry))) |
| 995 | (list (list :variant (cdar (last (car entry)))))))) | 1478 | `((:variant ,(cdar (last (car entry)))))))) |
| 996 | 1479 | ||
| 997 | ;; "Set" expects a variant. | 1480 | ;; "Set" expects a variant. |
| 998 | ((string-equal method "Set") | 1481 | ((string-equal method "Set") |
| 999 | (let* ((value (caar (cddr args))) | 1482 | (let* ((value (caar (cddr args))) |
| 1000 | (entry (gethash (list bus interface property) | 1483 | (entry (gethash (list :property bus interface property) |
| 1001 | dbus-registered-objects-table)) | 1484 | dbus-registered-objects-table)) |
| 1002 | ;; The value of the hash table is a list; in case of | 1485 | ;; The value of the hash table is a list; in case of |
| 1003 | ;; properties it contains just one element (UNAME SERVICE | 1486 | ;; properties it contains just one element (UNAME SERVICE |
| @@ -1012,7 +1495,7 @@ It will be registered for all objects created by `dbus-register-object'." | |||
| 1012 | (unless (member :readwrite (car object)) | 1495 | (unless (member :readwrite (car object)) |
| 1013 | (signal 'dbus-error | 1496 | (signal 'dbus-error |
| 1014 | (list "Property not writable at path" property path))) | 1497 | (list "Property not writable at path" property path))) |
| 1015 | (puthash (list bus interface property) | 1498 | (puthash (list :property bus interface property) |
| 1016 | (list (append (butlast (car entry)) | 1499 | (list (append (butlast (car entry)) |
| 1017 | (list (cons (car object) value)))) | 1500 | (list (cons (car object) value)))) |
| 1018 | dbus-registered-objects-table) | 1501 | dbus-registered-objects-table) |
| @@ -1020,7 +1503,7 @@ It will be registered for all objects created by `dbus-register-object'." | |||
| 1020 | (when (member :emits-signal (car object)) | 1503 | (when (member :emits-signal (car object)) |
| 1021 | (dbus-send-signal | 1504 | (dbus-send-signal |
| 1022 | bus service path dbus-interface-properties "PropertiesChanged" | 1505 | bus service path dbus-interface-properties "PropertiesChanged" |
| 1023 | (list (list :dict-entry property (list :variant value))) | 1506 | `((:dict-entry ,property (:variant ,value))) |
| 1024 | '(:array))) | 1507 | '(:array))) |
| 1025 | ;; Return empty reply. | 1508 | ;; Return empty reply. |
| 1026 | :ignore)) | 1509 | :ignore)) |
| @@ -1030,7 +1513,7 @@ It will be registered for all objects created by `dbus-register-object'." | |||
| 1030 | (let (result) | 1513 | (let (result) |
| 1031 | (maphash | 1514 | (maphash |
| 1032 | (lambda (key val) | 1515 | (lambda (key val) |
| 1033 | (when (and (equal (butlast key) (list bus interface)) | 1516 | (when (and (equal (butlast key) (list :property bus interface)) |
| 1034 | (string-equal path (nth 2 (car val))) | 1517 | (string-equal path (nth 2 (car val))) |
| 1035 | (not (functionp (car (last (car val)))))) | 1518 | (not (functionp (car (last (car val)))))) |
| 1036 | (add-to-list | 1519 | (add-to-list |
| @@ -1042,15 +1525,151 @@ It will be registered for all objects created by `dbus-register-object'." | |||
| 1042 | ;; Return the result, or an empty array. | 1525 | ;; Return the result, or an empty array. |
| 1043 | (list :array (or result '(:signature "{sv}")))))))) | 1526 | (list :array (or result '(:signature "{sv}")))))))) |
| 1044 | 1527 | ||
| 1528 | |||
| 1529 | ;;; D-Bus object manager. | ||
| 1530 | |||
| 1531 | (defun dbus-get-all-managed-objects (bus service path) | ||
| 1532 | "Return all objects at BUS, SERVICE, PATH, and the children of PATH. | ||
| 1533 | The result is a list of objects. Every object is a cons of an | ||
| 1534 | existing path name, and the list of available interface objects. | ||
| 1535 | An interface object is another cons, which car is the interface | ||
| 1536 | name, and the cdr is the list of properties as returned by | ||
| 1537 | `dbus-get-all-properties' for that path and interface. Example: | ||
| 1538 | |||
| 1539 | \(dbus-get-all-managed-objects :session \"org.gnome.SettingsDaemon\" \"/\") | ||
| 1540 | |||
| 1541 | => \(\(\"/org/gnome/SettingsDaemon/MediaKeys\" | ||
| 1542 | \(\"org.gnome.SettingsDaemon.MediaKeys\") | ||
| 1543 | \(\"org.freedesktop.DBus.Peer\") | ||
| 1544 | \(\"org.freedesktop.DBus.Introspectable\") | ||
| 1545 | \(\"org.freedesktop.DBus.Properties\") | ||
| 1546 | \(\"org.freedesktop.DBus.ObjectManager\")) | ||
| 1547 | \(\"/org/gnome/SettingsDaemon/Power\" | ||
| 1548 | \(\"org.gnome.SettingsDaemon.Power.Keyboard\") | ||
| 1549 | \(\"org.gnome.SettingsDaemon.Power.Screen\") | ||
| 1550 | \(\"org.gnome.SettingsDaemon.Power\" | ||
| 1551 | \(\"Icon\" . \". GThemedIcon battery-full-charged-symbolic \") | ||
| 1552 | \(\"Tooltip\" . \"Laptop battery is charged\")) | ||
| 1553 | \(\"org.freedesktop.DBus.Peer\") | ||
| 1554 | \(\"org.freedesktop.DBus.Introspectable\") | ||
| 1555 | \(\"org.freedesktop.DBus.Properties\") | ||
| 1556 | \(\"org.freedesktop.DBus.ObjectManager\")) | ||
| 1557 | ...) | ||
| 1558 | |||
| 1559 | If possible, \"org.freedesktop.DBus.ObjectManager.GetManagedObjects\" | ||
| 1560 | is used for retrieving the information. Otherwise, the information | ||
| 1561 | is collected via \"org.freedesktop.DBus.Introspectable.Introspect\" | ||
| 1562 | and \"org.freedesktop.DBus.Properties.GetAll\", which is slow." | ||
| 1563 | (let ((result | ||
| 1564 | ;; Direct call. Fails, if the target does not support the | ||
| 1565 | ;; object manager interface. | ||
| 1566 | (dbus-ignore-errors | ||
| 1567 | (dbus-call-method | ||
| 1568 | bus service path dbus-interface-objectmanager | ||
| 1569 | "GetManagedObjects" :timeout 1000)))) | ||
| 1570 | |||
| 1571 | (if result | ||
| 1572 | ;; Massage the returned structure. | ||
| 1573 | (dolist (entry result result) | ||
| 1574 | ;; "a{oa{sa{sv}}}". | ||
| 1575 | (dolist (entry1 (cdr entry)) | ||
| 1576 | ;; "a{sa{sv}}". | ||
| 1577 | (dolist (entry2 entry1) | ||
| 1578 | ;; "a{sv}". | ||
| 1579 | (if (cadr entry2) | ||
| 1580 | ;; "sv". | ||
| 1581 | (dolist (entry3 (cadr entry2)) | ||
| 1582 | (setcdr entry3 (caadr entry3))) | ||
| 1583 | (setcdr entry2 nil))))) | ||
| 1584 | |||
| 1585 | ;; Fallback: collect the information. Slooow! | ||
| 1586 | (dolist (object | ||
| 1587 | (dbus-introspect-get-all-nodes bus service path) | ||
| 1588 | result) | ||
| 1589 | (let (result1) | ||
| 1590 | (dolist | ||
| 1591 | (interface | ||
| 1592 | (dbus-introspect-get-interface-names bus service object) | ||
| 1593 | result1) | ||
| 1594 | (add-to-list | ||
| 1595 | 'result1 | ||
| 1596 | (cons interface | ||
| 1597 | (dbus-get-all-properties bus service object interface)))) | ||
| 1598 | (when result1 | ||
| 1599 | (add-to-list 'result (cons object result1)))))))) | ||
| 1600 | |||
| 1601 | (defun dbus-managed-objects-handler () | ||
| 1602 | "Default handler for the \"org.freedesktop.DBus.ObjectManager\" interface. | ||
| 1603 | It will be registered for all objects created by `dbus-register-method'." | ||
| 1604 | (let* ((last-input-event last-input-event) | ||
| 1605 | (bus (dbus-event-bus-name last-input-event)) | ||
| 1606 | (service (dbus-event-service-name last-input-event)) | ||
| 1607 | (path (dbus-event-path-name last-input-event))) | ||
| 1608 | ;; "GetManagedObjects" returns "a{oa{sa{sv}}}". | ||
| 1609 | (let (interfaces result) | ||
| 1610 | |||
| 1611 | ;; Check for object path wildcard interfaces. | ||
| 1612 | (maphash | ||
| 1613 | (lambda (key val) | ||
| 1614 | (when (and (equal (butlast key 2) (list :method bus)) | ||
| 1615 | (null (nth 2 (car-safe val)))) | ||
| 1616 | (add-to-list 'interfaces (nth 2 key)))) | ||
| 1617 | dbus-registered-objects-table) | ||
| 1618 | |||
| 1619 | ;; Check all registered object paths. | ||
| 1620 | (maphash | ||
| 1621 | (lambda (key val) | ||
| 1622 | (let ((object (or (nth 2 (car-safe val)) "")) | ||
| 1623 | (interface (nth 2 key))) | ||
| 1624 | (when (and (equal (butlast key 2) (list :method bus)) | ||
| 1625 | (string-prefix-p path object)) | ||
| 1626 | (dolist (interface (cons (nth 2 key) interfaces)) | ||
| 1627 | (unless (assoc object result) | ||
| 1628 | (add-to-list 'result (list object))) | ||
| 1629 | (unless (assoc interface (cdr (assoc object result))) | ||
| 1630 | (setcdr | ||
| 1631 | (assoc object result) | ||
| 1632 | (append | ||
| 1633 | (list (cons | ||
| 1634 | interface | ||
| 1635 | ;; We simulate "org.freedesktop.DBus.Properties.GetAll" | ||
| 1636 | ;; by using an appropriate D-Bus event. | ||
| 1637 | (let ((last-input-event | ||
| 1638 | (append | ||
| 1639 | (butlast last-input-event 4) | ||
| 1640 | (list object dbus-interface-properties | ||
| 1641 | "GetAll" 'dbus-property-handler)))) | ||
| 1642 | (dbus-property-handler interface)))) | ||
| 1643 | (cdr (assoc object result))))))))) | ||
| 1644 | dbus-registered-objects-table) | ||
| 1645 | |||
| 1646 | ;; Return the result, or an empty array. | ||
| 1647 | (list | ||
| 1648 | :array | ||
| 1649 | (or | ||
| 1650 | (mapcar | ||
| 1651 | (lambda (x) | ||
| 1652 | (list | ||
| 1653 | :dict-entry :object-path (car x) | ||
| 1654 | (cons :array (mapcar (lambda (y) (cons :dict-entry y)) (cdr x))))) | ||
| 1655 | result) | ||
| 1656 | '(:signature "{oa{sa{sv}}}")))))) | ||
| 1657 | |||
| 1045 | 1658 | ||
| 1046 | ;; Initialize :system and :session buses. This adds their file | 1659 | ;; Initialize `:system' and `:session' buses. This adds their file |
| 1047 | ;; descriptors to input_wait_mask, in order to detect incoming | 1660 | ;; descriptors to input_wait_mask, in order to detect incoming |
| 1048 | ;; messages immediately. | 1661 | ;; messages immediately. |
| 1049 | (when (featurep 'dbusbind) | 1662 | (when (featurep 'dbusbind) |
| 1050 | (dbus-ignore-errors | 1663 | (dbus-ignore-errors |
| 1051 | (dbus-init-bus :system) | 1664 | (dbus-init-bus :system)) |
| 1665 | (dbus-ignore-errors | ||
| 1052 | (dbus-init-bus :session))) | 1666 | (dbus-init-bus :session))) |
| 1053 | 1667 | ||
| 1054 | (provide 'dbus) | 1668 | (provide 'dbus) |
| 1055 | 1669 | ||
| 1670 | ;;; TODO: | ||
| 1671 | |||
| 1672 | ;; * Implement org.freedesktop.DBus.ObjectManager.InterfacesAdded and | ||
| 1673 | ;; org.freedesktop.DBus.ObjectManager.InterfacesRemoved. | ||
| 1674 | |||
| 1056 | ;;; dbus.el ends here | 1675 | ;;; dbus.el ends here |
diff --git a/src/ChangeLog b/src/ChangeLog index a1220aeaa7d..205728f91da 100644 --- a/src/ChangeLog +++ b/src/ChangeLog | |||
| @@ -1,3 +1,48 @@ | |||
| 1 | 2012-04-22 Michael Albinus <michael.albinus@gmx.de> | ||
| 2 | |||
| 3 | Move functions from C to Lisp. Make non-blocking method calls | ||
| 4 | the default. Implement further D-Bus standard interfaces. | ||
| 5 | |||
| 6 | * dbusbind.c (DBUS_NUM_MESSAGE_TYPES): Declare. | ||
| 7 | (QCdbus_request_name_allow_replacement) | ||
| 8 | (QCdbus_request_name_replace_existing) | ||
| 9 | (QCdbus_request_name_do_not_queue) | ||
| 10 | (QCdbus_request_name_reply_primary_owner) | ||
| 11 | (QCdbus_request_name_reply_in_queue) | ||
| 12 | (QCdbus_request_name_reply_exists) | ||
| 13 | (QCdbus_request_name_reply_already_owner): Move to dbus.el. | ||
| 14 | (QCdbus_registered_serial, QCdbus_registered_method) | ||
| 15 | (QCdbus_registered_signal): New Lisp objects. | ||
| 16 | (XD_DEBUG_MESSAGE): Use sizeof. | ||
| 17 | (XD_MESSAGE_TYPE_TO_STRING, XD_OBJECT_TO_STRING) | ||
| 18 | (XD_DBUS_VALIDATE_BUS_ADDRESS, XD_DBUS_VALIDATE_OBJECT) | ||
| 19 | (XD_DBUS_VALIDATE_BUS_NAME, XD_DBUS_VALIDATE_PATH) | ||
| 20 | (XD_DBUS_VALIDATE_INTERFACE, XD_DBUS_VALIDATE_MEMBER): New macros. | ||
| 21 | (XD_CHECK_DBUS_SERIAL): Rename from CHECK_DBUS_SERIAL_GET_SERIAL. | ||
| 22 | (xd_signature, xd_append_arg): Allow float for integer types. | ||
| 23 | (xd_get_connection_references): New function. | ||
| 24 | (xd_get_connection_address): Rename from xd_initialize. Return | ||
| 25 | cached address. | ||
| 26 | (xd_remove_watch): Do not unset $DBUS_SESSION_BUS_ADDRESS. | ||
| 27 | (xd_close_bus): Rename from Fdbus_close_bus. Not needed on Lisp | ||
| 28 | level. | ||
| 29 | (Fdbus_init_bus): New optional arg PRIVATE. Cache address. | ||
| 30 | Return number of recounts. | ||
| 31 | (Fdbus_get_unique_name): Make stronger parameter check. | ||
| 32 | (Fdbus_message_internal): New defun. | ||
| 33 | (Fdbus_call_method, Fdbus_call_method_asynchronously) | ||
| 34 | (Fdbus_method_return_internal, Fdbus_method_error_internal) | ||
| 35 | (Fdbus_send_signal, Fdbus_register_service) | ||
| 36 | (Fdbus_register_signal, Fdbus_register_method): Move to dbus.el. | ||
| 37 | (xd_read_message_1): Obey new structure of Vdbus_registered_objects. | ||
| 38 | (xd_read_queued_messages): Obey new structure of Vdbus_registered_buses. | ||
| 39 | (Vdbus_compiled_version, Vdbus_runtime_version) | ||
| 40 | (Vdbus_message_type_invalid, Vdbus_message_type_method_call) | ||
| 41 | (Vdbus_message_type_method_return, Vdbus_message_type_error) | ||
| 42 | (Vdbus_message_type_signal): New defvars. | ||
| 43 | (Vdbus_registered_buses, Vdbus_registered_objects_table): Adapt | ||
| 44 | docstring. | ||
| 45 | |||
| 1 | 2012-04-22 Paul Eggert <eggert@cs.ucla.edu> | 46 | 2012-04-22 Paul Eggert <eggert@cs.ucla.edu> |
| 2 | 47 | ||
| 3 | Fix GC_MALLOC_CHECK debugging output on 64-bit hosts. | 48 | Fix GC_MALLOC_CHECK debugging output on 64-bit hosts. |
diff --git a/src/dbusbind.c b/src/dbusbind.c index ad1a3f3cbe8..78e5c80baf3 100644 --- a/src/dbusbind.c +++ b/src/dbusbind.c | |||
| @@ -28,19 +28,15 @@ along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>. */ | |||
| 28 | #include "keyboard.h" | 28 | #include "keyboard.h" |
| 29 | #include "process.h" | 29 | #include "process.h" |
| 30 | 30 | ||
| 31 | #ifndef DBUS_NUM_MESSAGE_TYPES | ||
| 32 | #define DBUS_NUM_MESSAGE_TYPES 5 | ||
| 33 | #endif | ||
| 34 | |||
| 31 | 35 | ||
| 32 | /* Subroutines. */ | 36 | /* Subroutines. */ |
| 33 | static Lisp_Object Qdbus_init_bus; | 37 | static Lisp_Object Qdbus_init_bus; |
| 34 | static Lisp_Object Qdbus_close_bus; | ||
| 35 | static Lisp_Object Qdbus_get_unique_name; | 38 | static Lisp_Object Qdbus_get_unique_name; |
| 36 | static Lisp_Object Qdbus_call_method; | 39 | static Lisp_Object Qdbus_message_internal; |
| 37 | static Lisp_Object Qdbus_call_method_asynchronously; | ||
| 38 | static Lisp_Object Qdbus_method_return_internal; | ||
| 39 | static Lisp_Object Qdbus_method_error_internal; | ||
| 40 | static Lisp_Object Qdbus_send_signal; | ||
| 41 | static Lisp_Object Qdbus_register_service; | ||
| 42 | static Lisp_Object Qdbus_register_signal; | ||
| 43 | static Lisp_Object Qdbus_register_method; | ||
| 44 | 40 | ||
| 45 | /* D-Bus error symbol. */ | 41 | /* D-Bus error symbol. */ |
| 46 | static Lisp_Object Qdbus_error; | 42 | static Lisp_Object Qdbus_error; |
| @@ -51,17 +47,6 @@ static Lisp_Object QCdbus_system_bus, QCdbus_session_bus; | |||
| 51 | /* Lisp symbol for method call timeout. */ | 47 | /* Lisp symbol for method call timeout. */ |
| 52 | static Lisp_Object QCdbus_timeout; | 48 | static Lisp_Object QCdbus_timeout; |
| 53 | 49 | ||
| 54 | /* Lisp symbols for name request flags. */ | ||
| 55 | static Lisp_Object QCdbus_request_name_allow_replacement; | ||
| 56 | static Lisp_Object QCdbus_request_name_replace_existing; | ||
| 57 | static Lisp_Object QCdbus_request_name_do_not_queue; | ||
| 58 | |||
| 59 | /* Lisp symbols for name request replies. */ | ||
| 60 | static Lisp_Object QCdbus_request_name_reply_primary_owner; | ||
| 61 | static Lisp_Object QCdbus_request_name_reply_in_queue; | ||
| 62 | static Lisp_Object QCdbus_request_name_reply_exists; | ||
| 63 | static Lisp_Object QCdbus_request_name_reply_already_owner; | ||
| 64 | |||
| 65 | /* Lisp symbols of D-Bus types. */ | 50 | /* Lisp symbols of D-Bus types. */ |
| 66 | static Lisp_Object QCdbus_type_byte, QCdbus_type_boolean; | 51 | static Lisp_Object QCdbus_type_byte, QCdbus_type_boolean; |
| 67 | static Lisp_Object QCdbus_type_int16, QCdbus_type_uint16; | 52 | static Lisp_Object QCdbus_type_int16, QCdbus_type_uint16; |
| @@ -75,6 +60,10 @@ static Lisp_Object QCdbus_type_unix_fd; | |||
| 75 | static Lisp_Object QCdbus_type_array, QCdbus_type_variant; | 60 | static Lisp_Object QCdbus_type_array, QCdbus_type_variant; |
| 76 | static Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry; | 61 | static Lisp_Object QCdbus_type_struct, QCdbus_type_dict_entry; |
| 77 | 62 | ||
| 63 | /* Lisp symbols of objects in `dbus-registered-objects-table'. */ | ||
| 64 | static Lisp_Object QCdbus_registered_serial, QCdbus_registered_method; | ||
| 65 | static Lisp_Object QCdbus_registered_signal; | ||
| 66 | |||
| 78 | /* Whether we are reading a D-Bus event. */ | 67 | /* Whether we are reading a D-Bus event. */ |
| 79 | static int xd_in_read_queued_messages = 0; | 68 | static int xd_in_read_queued_messages = 0; |
| 80 | 69 | ||
| @@ -120,14 +109,14 @@ static int xd_in_read_queued_messages = 0; | |||
| 120 | } while (0) | 109 | } while (0) |
| 121 | 110 | ||
| 122 | /* Macros for debugging. In order to enable them, build with | 111 | /* Macros for debugging. In order to enable them, build with |
| 123 | "MYCPPFLAGS='-DDBUS_DEBUG -Wall' make". */ | 112 | "env MYCPPFLAGS='-DDBUS_DEBUG -Wall' make". */ |
| 124 | #ifdef DBUS_DEBUG | 113 | #ifdef DBUS_DEBUG |
| 125 | #define XD_DEBUG_MESSAGE(...) \ | 114 | #define XD_DEBUG_MESSAGE(...) \ |
| 126 | do { \ | 115 | do { \ |
| 127 | char s[1024]; \ | 116 | char s[1024]; \ |
| 128 | snprintf (s, sizeof s, __VA_ARGS__); \ | 117 | snprintf (s, sizeof s, __VA_ARGS__); \ |
| 129 | printf ("%s: %s\n", __func__, s); \ | 118 | printf ("%s: %s\n", __func__, s); \ |
| 130 | message ("%s: %s", __func__, s); \ | 119 | message ("%s: %s", __func__, s); \ |
| 131 | } while (0) | 120 | } while (0) |
| 132 | #define XD_DEBUG_VALID_LISP_OBJECT_P(object) \ | 121 | #define XD_DEBUG_VALID_LISP_OBJECT_P(object) \ |
| 133 | do { \ | 122 | do { \ |
| @@ -144,7 +133,7 @@ static int xd_in_read_queued_messages = 0; | |||
| 144 | if (!NILP (Vdbus_debug)) \ | 133 | if (!NILP (Vdbus_debug)) \ |
| 145 | { \ | 134 | { \ |
| 146 | char s[1024]; \ | 135 | char s[1024]; \ |
| 147 | snprintf (s, 1023, __VA_ARGS__); \ | 136 | snprintf (s, sizeof s, __VA_ARGS__); \ |
| 148 | message ("%s: %s", __func__, s); \ | 137 | message ("%s: %s", __func__, s); \ |
| 149 | } \ | 138 | } \ |
| 150 | } while (0) | 139 | } while (0) |
| @@ -241,23 +230,112 @@ xd_symbol_to_dbus_type (Lisp_Object object) | |||
| 241 | #define XD_NEXT_VALUE(object) \ | 230 | #define XD_NEXT_VALUE(object) \ |
| 242 | ((XD_DBUS_TYPE_P (CAR_SAFE (object))) ? CDR_SAFE (object) : object) | 231 | ((XD_DBUS_TYPE_P (CAR_SAFE (object))) ? CDR_SAFE (object) : object) |
| 243 | 232 | ||
| 233 | /* Transform the message type to its string representation for debug | ||
| 234 | messages. */ | ||
| 235 | #define XD_MESSAGE_TYPE_TO_STRING(mtype) \ | ||
| 236 | ((mtype == DBUS_MESSAGE_TYPE_INVALID) \ | ||
| 237 | ? "DBUS_MESSAGE_TYPE_INVALID" \ | ||
| 238 | : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) \ | ||
| 239 | ? "DBUS_MESSAGE_TYPE_METHOD_CALL" \ | ||
| 240 | : (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) \ | ||
| 241 | ? "DBUS_MESSAGE_TYPE_METHOD_RETURN" \ | ||
| 242 | : (mtype == DBUS_MESSAGE_TYPE_ERROR) \ | ||
| 243 | ? "DBUS_MESSAGE_TYPE_ERROR" \ | ||
| 244 | : "DBUS_MESSAGE_TYPE_SIGNAL") | ||
| 245 | |||
| 246 | /* Transform the object to its string representation for debug | ||
| 247 | messages. */ | ||
| 248 | #define XD_OBJECT_TO_STRING(object) \ | ||
| 249 | SDATA (format2 ("%s", object, Qnil)) | ||
| 250 | |||
| 244 | /* Check whether X is a valid dbus serial number. If valid, set | 251 | /* Check whether X is a valid dbus serial number. If valid, set |
| 245 | SERIAL to its value. Otherwise, signal an error. */ | 252 | SERIAL to its value. Otherwise, signal an error. */ |
| 246 | #define CHECK_DBUS_SERIAL_GET_SERIAL(x, serial) \ | 253 | #define XD_CHECK_DBUS_SERIAL(x, serial) \ |
| 247 | do \ | 254 | do { \ |
| 248 | { \ | 255 | dbus_uint32_t DBUS_SERIAL_MAX = -1; \ |
| 249 | dbus_uint32_t DBUS_SERIAL_MAX = -1; \ | 256 | if (NATNUMP (x) && XINT (x) <= DBUS_SERIAL_MAX) \ |
| 250 | if (NATNUMP (x) && XINT (x) <= DBUS_SERIAL_MAX) \ | 257 | serial = XINT (x); \ |
| 251 | serial = XINT (x); \ | 258 | else if (MOST_POSITIVE_FIXNUM < DBUS_SERIAL_MAX \ |
| 252 | else if (MOST_POSITIVE_FIXNUM < DBUS_SERIAL_MAX \ | 259 | && FLOATP (x) \ |
| 253 | && FLOATP (x) \ | 260 | && 0 <= XFLOAT_DATA (x) \ |
| 254 | && 0 <= XFLOAT_DATA (x) \ | 261 | && XFLOAT_DATA (x) <= DBUS_SERIAL_MAX) \ |
| 255 | && XFLOAT_DATA (x) <= DBUS_SERIAL_MAX) \ | 262 | serial = XFLOAT_DATA (x); \ |
| 256 | serial = XFLOAT_DATA (x); \ | 263 | else \ |
| 257 | else \ | 264 | XD_SIGNAL2 (build_string ("Invalid dbus serial"), x); \ |
| 258 | XD_SIGNAL2 (build_string ("Invalid dbus serial"), x); \ | 265 | } while (0) |
| 259 | } \ | 266 | |
| 260 | while (0) | 267 | #define XD_DBUS_VALIDATE_BUS_ADDRESS(bus) \ |
| 268 | do { \ | ||
| 269 | if (STRINGP (bus)) \ | ||
| 270 | { \ | ||
| 271 | DBusAddressEntry **entries; \ | ||
| 272 | int len; \ | ||
| 273 | DBusError derror; \ | ||
| 274 | dbus_error_init (&derror); \ | ||
| 275 | if (!dbus_parse_address (SSDATA (bus), &entries, &len, &derror)) \ | ||
| 276 | XD_ERROR (derror); \ | ||
| 277 | /* Cleanup. */ \ | ||
| 278 | dbus_error_free (&derror); \ | ||
| 279 | dbus_address_entries_free (entries); \ | ||
| 280 | } \ | ||
| 281 | \ | ||
| 282 | else \ | ||
| 283 | { \ | ||
| 284 | CHECK_SYMBOL (bus); \ | ||
| 285 | if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) \ | ||
| 286 | XD_SIGNAL2 (build_string ("Wrong bus name"), bus); \ | ||
| 287 | /* We do not want to have an autolaunch for the session bus. */ \ | ||
| 288 | if (EQ (bus, QCdbus_session_bus) \ | ||
| 289 | && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL) \ | ||
| 290 | XD_SIGNAL2 (build_string ("No connection to bus"), bus); \ | ||
| 291 | } \ | ||
| 292 | } while (0) | ||
| 293 | |||
| 294 | #define XD_DBUS_VALIDATE_OBJECT(object, func) \ | ||
| 295 | do { \ | ||
| 296 | if (!NILP (object)) \ | ||
| 297 | { \ | ||
| 298 | DBusError derror; \ | ||
| 299 | CHECK_STRING (object); \ | ||
| 300 | dbus_error_init (&derror); \ | ||
| 301 | if (!func (SSDATA (object), &derror)) \ | ||
| 302 | XD_ERROR (derror); \ | ||
| 303 | /* Cleanup. */ \ | ||
| 304 | dbus_error_free (&derror); \ | ||
| 305 | } \ | ||
| 306 | } while (0) | ||
| 307 | |||
| 308 | #if HAVE_DBUS_VALIDATE_BUS_NAME | ||
| 309 | #define XD_DBUS_VALIDATE_BUS_NAME(bus_name) \ | ||
| 310 | XD_DBUS_VALIDATE_OBJECT(bus_name, dbus_validate_bus_name); | ||
| 311 | #else | ||
| 312 | #define XD_DBUS_VALIDATE_BUS_NAME(bus_name) \ | ||
| 313 | if (!NILP (bus_name)) CHECK_STRING (bus_name); | ||
| 314 | #endif | ||
| 315 | |||
| 316 | #if HAVE_DBUS_VALIDATE_PATH | ||
| 317 | #define XD_DBUS_VALIDATE_PATH(path) \ | ||
| 318 | XD_DBUS_VALIDATE_OBJECT(path, dbus_validate_path); | ||
| 319 | #else | ||
| 320 | #define XD_DBUS_VALIDATE_PATH(path) \ | ||
| 321 | if (!NILP (path)) CHECK_STRING (path); | ||
| 322 | #endif | ||
| 323 | |||
| 324 | #if HAVE_DBUS_VALIDATE_INTERFACE | ||
| 325 | #define XD_DBUS_VALIDATE_INTERFACE(interface) \ | ||
| 326 | XD_DBUS_VALIDATE_OBJECT(interface, dbus_validate_interface); | ||
| 327 | #else | ||
| 328 | #define XD_DBUS_VALIDATE_INTERFACE(interface) \ | ||
| 329 | if (!NILP (interface)) CHECK_STRING (interface); | ||
| 330 | #endif | ||
| 331 | |||
| 332 | #if HAVE_DBUS_VALIDATE_MEMBER | ||
| 333 | #define XD_DBUS_VALIDATE_MEMBER(member) \ | ||
| 334 | XD_DBUS_VALIDATE_OBJECT(member, dbus_validate_member); | ||
| 335 | #else | ||
| 336 | #define XD_DBUS_VALIDATE_MEMBER(member) \ | ||
| 337 | if (!NILP (member)) CHECK_STRING (member); | ||
| 338 | #endif | ||
| 261 | 339 | ||
| 262 | /* Append to SIGNATURE a copy of X, making sure SIGNATURE does | 340 | /* Append to SIGNATURE a copy of X, making sure SIGNATURE does |
| 263 | not become too long. */ | 341 | not become too long. */ |
| @@ -293,11 +371,6 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis | |||
| 293 | { | 371 | { |
| 294 | case DBUS_TYPE_BYTE: | 372 | case DBUS_TYPE_BYTE: |
| 295 | case DBUS_TYPE_UINT16: | 373 | case DBUS_TYPE_UINT16: |
| 296 | case DBUS_TYPE_UINT32: | ||
| 297 | case DBUS_TYPE_UINT64: | ||
| 298 | #ifdef DBUS_TYPE_UNIX_FD | ||
| 299 | case DBUS_TYPE_UNIX_FD: | ||
| 300 | #endif | ||
| 301 | CHECK_NATNUM (object); | 374 | CHECK_NATNUM (object); |
| 302 | sprintf (signature, "%c", dtype); | 375 | sprintf (signature, "%c", dtype); |
| 303 | break; | 376 | break; |
| @@ -309,14 +382,19 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis | |||
| 309 | break; | 382 | break; |
| 310 | 383 | ||
| 311 | case DBUS_TYPE_INT16: | 384 | case DBUS_TYPE_INT16: |
| 312 | case DBUS_TYPE_INT32: | ||
| 313 | case DBUS_TYPE_INT64: | ||
| 314 | CHECK_NUMBER (object); | 385 | CHECK_NUMBER (object); |
| 315 | sprintf (signature, "%c", dtype); | 386 | sprintf (signature, "%c", dtype); |
| 316 | break; | 387 | break; |
| 317 | 388 | ||
| 389 | case DBUS_TYPE_UINT32: | ||
| 390 | case DBUS_TYPE_UINT64: | ||
| 391 | #ifdef DBUS_TYPE_UNIX_FD | ||
| 392 | case DBUS_TYPE_UNIX_FD: | ||
| 393 | #endif | ||
| 394 | case DBUS_TYPE_INT32: | ||
| 395 | case DBUS_TYPE_INT64: | ||
| 318 | case DBUS_TYPE_DOUBLE: | 396 | case DBUS_TYPE_DOUBLE: |
| 319 | CHECK_FLOAT (object); | 397 | CHECK_NUMBER_OR_FLOAT (object); |
| 320 | sprintf (signature, "%c", dtype); | 398 | sprintf (signature, "%c", dtype); |
| 321 | break; | 399 | break; |
| 322 | 400 | ||
| @@ -352,8 +430,8 @@ xd_signature (char *signature, unsigned int dtype, unsigned int parent_type, Lis | |||
| 352 | } | 430 | } |
| 353 | 431 | ||
| 354 | /* If the element type is DBUS_TYPE_SIGNATURE, and this is the | 432 | /* If the element type is DBUS_TYPE_SIGNATURE, and this is the |
| 355 | only element, the value of this element is used as he array's | 433 | only element, the value of this element is used as the |
| 356 | element signature. */ | 434 | array's element signature. */ |
| 357 | if ((subtype == DBUS_TYPE_SIGNATURE) | 435 | if ((subtype == DBUS_TYPE_SIGNATURE) |
| 358 | && STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt))) | 436 | && STRINGP (CAR_SAFE (XD_NEXT_VALUE (elt))) |
| 359 | && NILP (CDR_SAFE (XD_NEXT_VALUE (elt)))) | 437 | && NILP (CDR_SAFE (XD_NEXT_VALUE (elt)))) |
| @@ -505,9 +583,8 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 505 | } | 583 | } |
| 506 | 584 | ||
| 507 | case DBUS_TYPE_INT32: | 585 | case DBUS_TYPE_INT32: |
| 508 | CHECK_NUMBER (object); | ||
| 509 | { | 586 | { |
| 510 | dbus_int32_t val = XINT (object); | 587 | dbus_int32_t val = extract_float (object); |
| 511 | XD_DEBUG_MESSAGE ("%c %d", dtype, val); | 588 | XD_DEBUG_MESSAGE ("%c %d", dtype, val); |
| 512 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) | 589 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) |
| 513 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); | 590 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); |
| @@ -518,9 +595,8 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 518 | #ifdef DBUS_TYPE_UNIX_FD | 595 | #ifdef DBUS_TYPE_UNIX_FD |
| 519 | case DBUS_TYPE_UNIX_FD: | 596 | case DBUS_TYPE_UNIX_FD: |
| 520 | #endif | 597 | #endif |
| 521 | CHECK_NATNUM (object); | ||
| 522 | { | 598 | { |
| 523 | dbus_uint32_t val = XFASTINT (object); | 599 | dbus_uint32_t val = extract_float (object); |
| 524 | XD_DEBUG_MESSAGE ("%c %u", dtype, val); | 600 | XD_DEBUG_MESSAGE ("%c %u", dtype, val); |
| 525 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) | 601 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) |
| 526 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); | 602 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); |
| @@ -528,9 +604,8 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 528 | } | 604 | } |
| 529 | 605 | ||
| 530 | case DBUS_TYPE_INT64: | 606 | case DBUS_TYPE_INT64: |
| 531 | CHECK_NUMBER (object); | ||
| 532 | { | 607 | { |
| 533 | dbus_int64_t val = XINT (object); | 608 | dbus_int64_t val = extract_float (object); |
| 534 | XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val); | 609 | XD_DEBUG_MESSAGE ("%c %d", dtype, (int) val); |
| 535 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) | 610 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) |
| 536 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); | 611 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); |
| @@ -538,19 +613,17 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 538 | } | 613 | } |
| 539 | 614 | ||
| 540 | case DBUS_TYPE_UINT64: | 615 | case DBUS_TYPE_UINT64: |
| 541 | CHECK_NATNUM (object); | ||
| 542 | { | 616 | { |
| 543 | dbus_uint64_t val = XFASTINT (object); | 617 | dbus_uint64_t val = extract_float (object); |
| 544 | XD_DEBUG_MESSAGE ("%c %"pI"d", dtype, XFASTINT (object)); | 618 | XD_DEBUG_MESSAGE ("%c %"pI"d", dtype, val); |
| 545 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) | 619 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) |
| 546 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); | 620 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); |
| 547 | return; | 621 | return; |
| 548 | } | 622 | } |
| 549 | 623 | ||
| 550 | case DBUS_TYPE_DOUBLE: | 624 | case DBUS_TYPE_DOUBLE: |
| 551 | CHECK_FLOAT (object); | ||
| 552 | { | 625 | { |
| 553 | double val = XFLOAT_DATA (object); | 626 | double val = extract_float (object); |
| 554 | XD_DEBUG_MESSAGE ("%c %f", dtype, val); | 627 | XD_DEBUG_MESSAGE ("%c %f", dtype, val); |
| 555 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) | 628 | if (!dbus_message_iter_append_basic (iter, dtype, &val)) |
| 556 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); | 629 | XD_SIGNAL2 (build_string ("Unable to append argument"), object); |
| @@ -614,7 +687,7 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 614 | dtype, CAR_SAFE (XD_NEXT_VALUE (object))); | 687 | dtype, CAR_SAFE (XD_NEXT_VALUE (object))); |
| 615 | 688 | ||
| 616 | XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature, | 689 | XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature, |
| 617 | SDATA (format2 ("%s", object, Qnil))); | 690 | XD_OBJECT_TO_STRING (object)); |
| 618 | if (!dbus_message_iter_open_container (iter, dtype, | 691 | if (!dbus_message_iter_open_container (iter, dtype, |
| 619 | signature, &subiter)) | 692 | signature, &subiter)) |
| 620 | XD_SIGNAL3 (build_string ("Cannot open container"), | 693 | XD_SIGNAL3 (build_string ("Cannot open container"), |
| @@ -627,7 +700,7 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 627 | dtype, CAR_SAFE (XD_NEXT_VALUE (object))); | 700 | dtype, CAR_SAFE (XD_NEXT_VALUE (object))); |
| 628 | 701 | ||
| 629 | XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature, | 702 | XD_DEBUG_MESSAGE ("%c %s %s", dtype, signature, |
| 630 | SDATA (format2 ("%s", object, Qnil))); | 703 | XD_OBJECT_TO_STRING (object)); |
| 631 | if (!dbus_message_iter_open_container (iter, dtype, | 704 | if (!dbus_message_iter_open_container (iter, dtype, |
| 632 | signature, &subiter)) | 705 | signature, &subiter)) |
| 633 | XD_SIGNAL3 (build_string ("Cannot open container"), | 706 | XD_SIGNAL3 (build_string ("Cannot open container"), |
| @@ -637,8 +710,7 @@ xd_append_arg (unsigned int dtype, Lisp_Object object, DBusMessageIter *iter) | |||
| 637 | case DBUS_TYPE_STRUCT: | 710 | case DBUS_TYPE_STRUCT: |
| 638 | case DBUS_TYPE_DICT_ENTRY: | 711 | case DBUS_TYPE_DICT_ENTRY: |
| 639 | /* These containers do not require a signature. */ | 712 | /* These containers do not require a signature. */ |
| 640 | XD_DEBUG_MESSAGE ("%c %s", dtype, | 713 | XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (object)); |
| 641 | SDATA (format2 ("%s", object, Qnil))); | ||
| 642 | if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter)) | 714 | if (!dbus_message_iter_open_container (iter, dtype, NULL, &subiter)) |
| 643 | XD_SIGNAL2 (build_string ("Cannot open container"), | 715 | XD_SIGNAL2 (build_string ("Cannot open container"), |
| 644 | make_number (dtype)); | 716 | make_number (dtype)); |
| @@ -777,7 +849,7 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter) | |||
| 777 | result = Fcons (xd_retrieve_arg (subtype, &subiter), result); | 849 | result = Fcons (xd_retrieve_arg (subtype, &subiter), result); |
| 778 | dbus_message_iter_next (&subiter); | 850 | dbus_message_iter_next (&subiter); |
| 779 | } | 851 | } |
| 780 | XD_DEBUG_MESSAGE ("%c %s", dtype, SDATA (format2 ("%s", result, Qnil))); | 852 | XD_DEBUG_MESSAGE ("%c %s", dtype, XD_OBJECT_TO_STRING (result)); |
| 781 | RETURN_UNGCPRO (Fnreverse (result)); | 853 | RETURN_UNGCPRO (Fnreverse (result)); |
| 782 | } | 854 | } |
| 783 | 855 | ||
| @@ -787,85 +859,37 @@ xd_retrieve_arg (unsigned int dtype, DBusMessageIter *iter) | |||
| 787 | } | 859 | } |
| 788 | } | 860 | } |
| 789 | 861 | ||
| 790 | /* Initialize D-Bus connection. BUS is either a Lisp symbol, :system | 862 | /* Return the number of references of the shared CONNECTION. */ |
| 791 | or :session, or a string denoting the bus address. It tells which | 863 | static int |
| 792 | D-Bus to initialize. If RAISE_ERROR is non-zero, signal an error | 864 | xd_get_connection_references (DBusConnection *connection) |
| 793 | when the connection cannot be initialized. */ | 865 | { |
| 866 | ptrdiff_t *refcount; | ||
| 867 | |||
| 868 | /* We cannot access the DBusConnection structure, it is not public. | ||
| 869 | But we know, that the reference counter is the first field in | ||
| 870 | that structure. */ | ||
| 871 | refcount = (void *) &connection; | ||
| 872 | refcount = (void *) *refcount; | ||
| 873 | return *refcount; | ||
| 874 | } | ||
| 875 | |||
| 876 | /* Return D-Bus connection address. BUS is either a Lisp symbol, | ||
| 877 | :system or :session, or a string denoting the bus address. */ | ||
| 794 | static DBusConnection * | 878 | static DBusConnection * |
| 795 | xd_initialize (Lisp_Object bus, int raise_error) | 879 | xd_get_connection_address (Lisp_Object bus) |
| 796 | { | 880 | { |
| 797 | DBusConnection *connection; | 881 | DBusConnection *connection; |
| 798 | DBusError derror; | 882 | Lisp_Object val; |
| 799 | |||
| 800 | /* Parameter check. */ | ||
| 801 | if (!STRINGP (bus)) | ||
| 802 | { | ||
| 803 | CHECK_SYMBOL (bus); | ||
| 804 | if (!(EQ (bus, QCdbus_system_bus) || EQ (bus, QCdbus_session_bus))) | ||
| 805 | { | ||
| 806 | if (raise_error) | ||
| 807 | XD_SIGNAL2 (build_string ("Wrong bus name"), bus); | ||
| 808 | else | ||
| 809 | return NULL; | ||
| 810 | } | ||
| 811 | 883 | ||
| 812 | /* We do not want to have an autolaunch for the session bus. */ | 884 | val = CDR_SAFE (Fassoc (bus, Vdbus_registered_buses)); |
| 813 | if (EQ (bus, QCdbus_session_bus) | 885 | if (NILP (val)) |
| 814 | && getenv ("DBUS_SESSION_BUS_ADDRESS") == NULL) | 886 | XD_SIGNAL2 (build_string ("No connection to bus"), bus); |
| 815 | { | ||
| 816 | if (raise_error) | ||
| 817 | XD_SIGNAL2 (build_string ("No connection to bus"), bus); | ||
| 818 | else | ||
| 819 | return NULL; | ||
| 820 | } | ||
| 821 | } | ||
| 822 | |||
| 823 | /* Open a connection to the bus. */ | ||
| 824 | dbus_error_init (&derror); | ||
| 825 | |||
| 826 | if (STRINGP (bus)) | ||
| 827 | connection = dbus_connection_open (SSDATA (bus), &derror); | ||
| 828 | else | 887 | else |
| 829 | if (EQ (bus, QCdbus_system_bus)) | 888 | connection = (DBusConnection *) XFASTINT (val); |
| 830 | connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror); | ||
| 831 | else | ||
| 832 | connection = dbus_bus_get (DBUS_BUS_SESSION, &derror); | ||
| 833 | |||
| 834 | if (dbus_error_is_set (&derror)) | ||
| 835 | { | ||
| 836 | if (raise_error) | ||
| 837 | XD_ERROR (derror); | ||
| 838 | else | ||
| 839 | connection = NULL; | ||
| 840 | } | ||
| 841 | |||
| 842 | /* If it is not the system or session bus, we must register | ||
| 843 | ourselves. Otherwise, we have called dbus_bus_get, which has | ||
| 844 | configured us to exit if the connection closes - we undo this | ||
| 845 | setting. */ | ||
| 846 | if (connection != NULL) | ||
| 847 | { | ||
| 848 | if (STRINGP (bus)) | ||
| 849 | dbus_bus_register (connection, &derror); | ||
| 850 | else | ||
| 851 | dbus_connection_set_exit_on_disconnect (connection, FALSE); | ||
| 852 | } | ||
| 853 | |||
| 854 | if (dbus_error_is_set (&derror)) | ||
| 855 | { | ||
| 856 | if (raise_error) | ||
| 857 | XD_ERROR (derror); | ||
| 858 | else | ||
| 859 | connection = NULL; | ||
| 860 | } | ||
| 861 | 889 | ||
| 862 | if (connection == NULL && raise_error) | 890 | if (!dbus_connection_get_is_connected (connection)) |
| 863 | XD_SIGNAL2 (build_string ("No connection to bus"), bus); | 891 | XD_SIGNAL2 (build_string ("No connection to bus"), bus); |
| 864 | 892 | ||
| 865 | /* Cleanup. */ | ||
| 866 | dbus_error_free (&derror); | ||
| 867 | |||
| 868 | /* Return the result. */ | ||
| 869 | return connection; | 893 | return connection; |
| 870 | } | 894 | } |
| 871 | 895 | ||
| @@ -896,8 +920,8 @@ xd_add_watch (DBusWatch *watch, void *data) | |||
| 896 | int fd = xd_find_watch_fd (watch); | 920 | int fd = xd_find_watch_fd (watch); |
| 897 | 921 | ||
| 898 | XD_DEBUG_MESSAGE ("fd %d, write %d, enabled %d", | 922 | XD_DEBUG_MESSAGE ("fd %d, write %d, enabled %d", |
| 899 | fd, flags & DBUS_WATCH_WRITABLE, | 923 | fd, flags & DBUS_WATCH_WRITABLE, |
| 900 | dbus_watch_get_enabled (watch)); | 924 | dbus_watch_get_enabled (watch)); |
| 901 | 925 | ||
| 902 | if (fd == -1) | 926 | if (fd == -1) |
| 903 | return FALSE; | 927 | return FALSE; |
| @@ -929,8 +953,8 @@ xd_remove_watch (DBusWatch *watch, void *data) | |||
| 929 | /* Unset session environment. */ | 953 | /* Unset session environment. */ |
| 930 | if (XSYMBOL (QCdbus_session_bus) == data) | 954 | if (XSYMBOL (QCdbus_session_bus) == data) |
| 931 | { | 955 | { |
| 932 | XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); | 956 | // XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); |
| 933 | unsetenv ("DBUS_SESSION_BUS_ADDRESS"); | 957 | // unsetenv ("DBUS_SESSION_BUS_ADDRESS"); |
| 934 | } | 958 | } |
| 935 | 959 | ||
| 936 | if (flags & DBUS_WATCH_WRITABLE) | 960 | if (flags & DBUS_WATCH_WRITABLE) |
| @@ -949,23 +973,111 @@ xd_toggle_watch (DBusWatch *watch, void *data) | |||
| 949 | xd_remove_watch (watch, data); | 973 | xd_remove_watch (watch, data); |
| 950 | } | 974 | } |
| 951 | 975 | ||
| 952 | DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 1, 0, | 976 | /* Close connection to D-Bus BUS. */ |
| 953 | doc: /* Initialize connection to D-Bus BUS. */) | 977 | static void |
| 954 | (Lisp_Object bus) | 978 | xd_close_bus (Lisp_Object bus) |
| 979 | { | ||
| 980 | DBusConnection *connection; | ||
| 981 | Lisp_Object val; | ||
| 982 | |||
| 983 | /* Check whether we are connected. */ | ||
| 984 | val = Fassoc (bus, Vdbus_registered_buses); | ||
| 985 | if (NILP (val)) | ||
| 986 | return; | ||
| 987 | |||
| 988 | /* Retrieve bus address. */ | ||
| 989 | connection = xd_get_connection_address (bus); | ||
| 990 | |||
| 991 | /* Close connection, if there isn't another shared application. */ | ||
| 992 | if (xd_get_connection_references (connection) == 1) | ||
| 993 | { | ||
| 994 | XD_DEBUG_MESSAGE ("Close connection to bus %s", | ||
| 995 | XD_OBJECT_TO_STRING (bus)); | ||
| 996 | dbus_connection_close (connection); | ||
| 997 | } | ||
| 998 | |||
| 999 | /* Decrement reference count. */ | ||
| 1000 | dbus_connection_unref (connection); | ||
| 1001 | |||
| 1002 | /* Remove bus from list of registered buses. */ | ||
| 1003 | Vdbus_registered_buses = Fdelete (val, Vdbus_registered_buses); | ||
| 1004 | |||
| 1005 | /* Return. */ | ||
| 1006 | return; | ||
| 1007 | } | ||
| 1008 | |||
| 1009 | DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 2, 0, | ||
| 1010 | doc: /* Establish the connection to D-Bus BUS. | ||
| 1011 | |||
| 1012 | BUS can be either the symbol `:system' or the symbol `:session', or it | ||
| 1013 | can be a string denoting the address of the corresponding bus. For | ||
| 1014 | the system and session buses, this function is called when loading | ||
| 1015 | `dbus.el', there is no need to call it again. | ||
| 1016 | |||
| 1017 | The function returns a number, which counts the connections this Emacs | ||
| 1018 | session has established to the BUS under the same unique name (see | ||
| 1019 | `dbus-get-unique-name'). It depends on the libraries Emacs is linked | ||
| 1020 | with, and on the environment Emacs is running. For example, if Emacs | ||
| 1021 | is linked with the gtk toolkit, and it runs in a GTK-aware environment | ||
| 1022 | like Gnome, another connection might already be established. | ||
| 1023 | |||
| 1024 | When PRIVATE is non-nil, a new connection is established instead of | ||
| 1025 | reusing an existing one. It results in a new unique name at the bus. | ||
| 1026 | This can be used, if it is necessary to distinguish from another | ||
| 1027 | connection used in the same Emacs process, like the one established by | ||
| 1028 | GTK+. It should be used with care for at least the `:system' and | ||
| 1029 | `:session' buses, because other Emacs Lisp packages might already use | ||
| 1030 | this connection to those buses. */) | ||
| 1031 | (Lisp_Object bus, Lisp_Object private) | ||
| 955 | { | 1032 | { |
| 956 | DBusConnection *connection; | 1033 | DBusConnection *connection; |
| 957 | void *busp; | 1034 | DBusError derror; |
| 1035 | Lisp_Object val; | ||
| 1036 | int refcount; | ||
| 958 | 1037 | ||
| 959 | /* Check parameter. */ | 1038 | /* Check parameter. */ |
| 960 | if (SYMBOLP (bus)) | 1039 | XD_DBUS_VALIDATE_BUS_ADDRESS (bus); |
| 961 | busp = XSYMBOL (bus); | 1040 | |
| 962 | else if (STRINGP (bus)) | 1041 | /* Close bus if it is already open. */ |
| 963 | busp = XSTRING (bus); | 1042 | xd_close_bus (bus); |
| 1043 | |||
| 1044 | /* Initialize. */ | ||
| 1045 | dbus_error_init (&derror); | ||
| 1046 | |||
| 1047 | /* Open the connection. */ | ||
| 1048 | if (STRINGP (bus)) | ||
| 1049 | if (NILP (private)) | ||
| 1050 | connection = dbus_connection_open (SSDATA (bus), &derror); | ||
| 1051 | else | ||
| 1052 | connection = dbus_connection_open_private (SSDATA (bus), &derror); | ||
| 1053 | |||
| 964 | else | 1054 | else |
| 965 | wrong_type_argument (intern ("D-Bus"), bus); | 1055 | if (NILP (private)) |
| 1056 | connection = dbus_bus_get (EQ (bus, QCdbus_system_bus) | ||
| 1057 | ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, | ||
| 1058 | &derror); | ||
| 1059 | else | ||
| 1060 | connection = dbus_bus_get_private (EQ (bus, QCdbus_system_bus) | ||
| 1061 | ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION, | ||
| 1062 | &derror); | ||
| 1063 | |||
| 1064 | if (dbus_error_is_set (&derror)) | ||
| 1065 | XD_ERROR (derror); | ||
| 966 | 1066 | ||
| 967 | /* Open a connection to the bus. */ | 1067 | if (connection == NULL) |
| 968 | connection = xd_initialize (bus, TRUE); | 1068 | XD_SIGNAL2 (build_string ("No connection to bus"), bus); |
| 1069 | |||
| 1070 | /* If it is not the system or session bus, we must register | ||
| 1071 | ourselves. Otherwise, we have called dbus_bus_get, which has | ||
| 1072 | configured us to exit if the connection closes - we undo this | ||
| 1073 | setting. */ | ||
| 1074 | if (STRINGP (bus)) | ||
| 1075 | dbus_bus_register (connection, &derror); | ||
| 1076 | else | ||
| 1077 | dbus_connection_set_exit_on_disconnect (connection, FALSE); | ||
| 1078 | |||
| 1079 | if (dbus_error_is_set (&derror)) | ||
| 1080 | XD_ERROR (derror); | ||
| 969 | 1081 | ||
| 970 | /* Add the watch functions. We pass also the bus as data, in order | 1082 | /* Add the watch functions. We pass also the bus as data, in order |
| 971 | to distinguish between the buses in xd_remove_watch. */ | 1083 | to distinguish between the buses in xd_remove_watch. */ |
| @@ -973,36 +1085,27 @@ DEFUN ("dbus-init-bus", Fdbus_init_bus, Sdbus_init_bus, 1, 1, 0, | |||
| 973 | xd_add_watch, | 1085 | xd_add_watch, |
| 974 | xd_remove_watch, | 1086 | xd_remove_watch, |
| 975 | xd_toggle_watch, | 1087 | xd_toggle_watch, |
| 976 | busp, NULL)) | 1088 | SYMBOLP (bus) |
| 1089 | ? (void *) XSYMBOL (bus) | ||
| 1090 | : (void *) XSTRING (bus), | ||
| 1091 | NULL)) | ||
| 977 | XD_SIGNAL1 (build_string ("Cannot add watch functions")); | 1092 | XD_SIGNAL1 (build_string ("Cannot add watch functions")); |
| 978 | 1093 | ||
| 979 | /* Add bus to list of registered buses. */ | 1094 | /* Add bus to list of registered buses. */ |
| 980 | Vdbus_registered_buses = Fcons (bus, Vdbus_registered_buses); | 1095 | XSETFASTINT (val, connection); |
| 1096 | Vdbus_registered_buses = Fcons (Fcons (bus, val), Vdbus_registered_buses); | ||
| 981 | 1097 | ||
| 982 | /* We do not want to abort. */ | 1098 | /* We do not want to abort. */ |
| 983 | putenv ((char *) "DBUS_FATAL_WARNINGS=0"); | 1099 | putenv ((char *) "DBUS_FATAL_WARNINGS=0"); |
| 984 | 1100 | ||
| 985 | /* Return. */ | 1101 | /* Cleanup. */ |
| 986 | return Qnil; | 1102 | dbus_error_free (&derror); |
| 987 | } | ||
| 988 | |||
| 989 | DEFUN ("dbus-close-bus", Fdbus_close_bus, Sdbus_close_bus, 1, 1, 0, | ||
| 990 | doc: /* Close connection to D-Bus BUS. */) | ||
| 991 | (Lisp_Object bus) | ||
| 992 | { | ||
| 993 | DBusConnection *connection; | ||
| 994 | |||
| 995 | /* Open a connection to the bus. */ | ||
| 996 | connection = xd_initialize (bus, TRUE); | ||
| 997 | |||
| 998 | /* Decrement reference count to the bus. */ | ||
| 999 | dbus_connection_unref (connection); | ||
| 1000 | |||
| 1001 | /* Remove bus from list of registered buses. */ | ||
| 1002 | Vdbus_registered_buses = Fdelete (bus, Vdbus_registered_buses); | ||
| 1003 | 1103 | ||
| 1004 | /* Return. */ | 1104 | /* Return reference counter. */ |
| 1005 | return Qnil; | 1105 | refcount = xd_get_connection_references (connection); |
| 1106 | XD_DEBUG_MESSAGE ("Bus %s, Reference counter %d", | ||
| 1107 | XD_OBJECT_TO_STRING (bus), refcount); | ||
| 1108 | return make_number (refcount); | ||
| 1006 | } | 1109 | } |
| 1007 | 1110 | ||
| 1008 | DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name, | 1111 | DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name, |
| @@ -1013,8 +1116,11 @@ DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name, | |||
| 1013 | DBusConnection *connection; | 1116 | DBusConnection *connection; |
| 1014 | const char *name; | 1117 | const char *name; |
| 1015 | 1118 | ||
| 1016 | /* Open a connection to the bus. */ | 1119 | /* Check parameter. */ |
| 1017 | connection = xd_initialize (bus, TRUE); | 1120 | XD_DBUS_VALIDATE_BUS_ADDRESS (bus); |
| 1121 | |||
| 1122 | /* Retrieve bus address. */ | ||
| 1123 | connection = xd_get_connection_address (bus); | ||
| 1018 | 1124 | ||
| 1019 | /* Request the name. */ | 1125 | /* Request the name. */ |
| 1020 | name = dbus_bus_get_unique_name (connection); | 1126 | name = dbus_bus_get_unique_name (connection); |
| @@ -1025,341 +1131,241 @@ DEFUN ("dbus-get-unique-name", Fdbus_get_unique_name, Sdbus_get_unique_name, | |||
| 1025 | return build_string (name); | 1131 | return build_string (name); |
| 1026 | } | 1132 | } |
| 1027 | 1133 | ||
| 1028 | DEFUN ("dbus-call-method", Fdbus_call_method, Sdbus_call_method, 5, MANY, 0, | 1134 | DEFUN ("dbus-message-internal", Fdbus_message_internal, Sdbus_message_internal, |
| 1029 | doc: /* Call METHOD on the D-Bus BUS. | 1135 | 4, MANY, 0, |
| 1030 | 1136 | doc: /* Send a D-Bus message. | |
| 1031 | BUS is either a Lisp symbol, `:system' or `:session', or a string | 1137 | This is an internal function, it shall not be used outside dbus.el. |
| 1032 | denoting the bus address. | 1138 | |
| 1033 | 1139 | The following usages are expected: | |
| 1034 | SERVICE is the D-Bus service name to be used. PATH is the D-Bus | 1140 | |
| 1035 | object path SERVICE is registered at. INTERFACE is an interface | 1141 | `dbus-call-method', `dbus-call-method-asynchronously': |
| 1036 | offered by SERVICE. It must provide METHOD. | 1142 | \(dbus-message-internal |
| 1037 | 1143 | dbus-message-type-method-call BUS SERVICE PATH INTERFACE METHOD HANDLER | |
| 1038 | If the parameter `:timeout' is given, the following integer TIMEOUT | 1144 | &optional :timeout TIMEOUT &rest ARGS) |
| 1039 | specifies the maximum number of milliseconds the method call must | 1145 | |
| 1040 | return. The default value is 25,000. If the method call doesn't | 1146 | `dbus-send-signal': |
| 1041 | return in time, a D-Bus error is raised. | 1147 | \(dbus-message-internal |
| 1042 | 1148 | dbus-message-type-signal BUS SERVICE PATH INTERFACE SIGNAL &rest ARGS) | |
| 1043 | All other arguments ARGS are passed to METHOD as arguments. They are | 1149 | |
| 1044 | converted into D-Bus types via the following rules: | 1150 | `dbus-method-return-internal': |
| 1045 | 1151 | \(dbus-message-internal | |
| 1046 | t and nil => DBUS_TYPE_BOOLEAN | 1152 | dbus-message-type-method-return BUS SERVICE SERIAL &rest ARGS) |
| 1047 | number => DBUS_TYPE_UINT32 | 1153 | |
| 1048 | integer => DBUS_TYPE_INT32 | 1154 | `dbus-method-error-internal': |
| 1049 | float => DBUS_TYPE_DOUBLE | 1155 | \(dbus-message-internal |
| 1050 | string => DBUS_TYPE_STRING | 1156 | dbus-message-type-error BUS SERVICE SERIAL &rest ARGS) |
| 1051 | list => DBUS_TYPE_ARRAY | 1157 | |
| 1052 | 1158 | usage: (dbus-message-internal &rest REST) */) | |
| 1053 | All arguments can be preceded by a type symbol. For details about | ||
| 1054 | type symbols, see Info node `(dbus)Type Conversion'. | ||
| 1055 | |||
| 1056 | `dbus-call-method' returns the resulting values of METHOD as a list of | ||
| 1057 | Lisp objects. The type conversion happens the other direction as for | ||
| 1058 | input arguments. It follows the mapping rules: | ||
| 1059 | |||
| 1060 | DBUS_TYPE_BOOLEAN => t or nil | ||
| 1061 | DBUS_TYPE_BYTE => number | ||
| 1062 | DBUS_TYPE_UINT16 => number | ||
| 1063 | DBUS_TYPE_INT16 => integer | ||
| 1064 | DBUS_TYPE_UINT32 => number or float | ||
| 1065 | DBUS_TYPE_UNIX_FD => number or float | ||
| 1066 | DBUS_TYPE_INT32 => integer or float | ||
| 1067 | DBUS_TYPE_UINT64 => number or float | ||
| 1068 | DBUS_TYPE_INT64 => integer or float | ||
| 1069 | DBUS_TYPE_DOUBLE => float | ||
| 1070 | DBUS_TYPE_STRING => string | ||
| 1071 | DBUS_TYPE_OBJECT_PATH => string | ||
| 1072 | DBUS_TYPE_SIGNATURE => string | ||
| 1073 | DBUS_TYPE_ARRAY => list | ||
| 1074 | DBUS_TYPE_VARIANT => list | ||
| 1075 | DBUS_TYPE_STRUCT => list | ||
| 1076 | DBUS_TYPE_DICT_ENTRY => list | ||
| 1077 | |||
| 1078 | Example: | ||
| 1079 | |||
| 1080 | \(dbus-call-method | ||
| 1081 | :session "org.gnome.seahorse" "/org/gnome/seahorse/keys/openpgp" | ||
| 1082 | "org.gnome.seahorse.Keys" "GetKeyField" | ||
| 1083 | "openpgp:657984B8C7A966DD" "simple-name") | ||
| 1084 | |||
| 1085 | => (t ("Philip R. Zimmermann")) | ||
| 1086 | |||
| 1087 | If the result of the METHOD call is just one value, the converted Lisp | ||
| 1088 | object is returned instead of a list containing this single Lisp object. | ||
| 1089 | |||
| 1090 | \(dbus-call-method | ||
| 1091 | :system "org.freedesktop.Hal" "/org/freedesktop/Hal/devices/computer" | ||
| 1092 | "org.freedesktop.Hal.Device" "GetPropertyString" | ||
| 1093 | "system.kernel.machine") | ||
| 1094 | |||
| 1095 | => "i686" | ||
| 1096 | |||
| 1097 | usage: (dbus-call-method BUS SERVICE PATH INTERFACE METHOD &optional :timeout TIMEOUT &rest ARGS) */) | ||
| 1098 | (ptrdiff_t nargs, Lisp_Object *args) | 1159 | (ptrdiff_t nargs, Lisp_Object *args) |
| 1099 | { | 1160 | { |
| 1100 | Lisp_Object bus, service, path, interface, method; | 1161 | Lisp_Object message_type, bus, service, handler; |
| 1162 | Lisp_Object path = Qnil; | ||
| 1163 | Lisp_Object interface = Qnil; | ||
| 1164 | Lisp_Object member = Qnil; | ||
| 1101 | Lisp_Object result; | 1165 | Lisp_Object result; |
| 1102 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | 1166 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; |
| 1103 | DBusConnection *connection; | 1167 | DBusConnection *connection; |
| 1104 | DBusMessage *dmessage; | 1168 | DBusMessage *dmessage; |
| 1105 | DBusMessage *reply; | ||
| 1106 | DBusMessageIter iter; | 1169 | DBusMessageIter iter; |
| 1107 | DBusError derror; | ||
| 1108 | unsigned int dtype; | 1170 | unsigned int dtype; |
| 1171 | unsigned int mtype; | ||
| 1172 | dbus_uint32_t serial = 0; | ||
| 1109 | int timeout = -1; | 1173 | int timeout = -1; |
| 1110 | ptrdiff_t i = 5; | 1174 | ptrdiff_t count; |
| 1111 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; | 1175 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; |
| 1112 | 1176 | ||
| 1177 | /* Initialize parameters. */ | ||
| 1178 | message_type = args[0]; | ||
| 1179 | bus = args[1]; | ||
| 1180 | service = args[2]; | ||
| 1181 | handler = Qnil; | ||
| 1182 | |||
| 1183 | CHECK_NATNUM (message_type); | ||
| 1184 | mtype = XFASTINT (message_type); | ||
| 1185 | if ((mtype <= DBUS_MESSAGE_TYPE_INVALID) || (mtype >= DBUS_NUM_MESSAGE_TYPES)) | ||
| 1186 | XD_SIGNAL2 (build_string ("Invalid message type"), message_type); | ||
| 1187 | |||
| 1188 | if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) | ||
| 1189 | || (mtype == DBUS_MESSAGE_TYPE_SIGNAL)) | ||
| 1190 | { | ||
| 1191 | path = args[3]; | ||
| 1192 | interface = args[4]; | ||
| 1193 | member = args[5]; | ||
| 1194 | if (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) | ||
| 1195 | handler = args[6]; | ||
| 1196 | count = (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) ? 7 : 6; | ||
| 1197 | } | ||
| 1198 | else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */ | ||
| 1199 | { | ||
| 1200 | XD_CHECK_DBUS_SERIAL (args[3], serial); | ||
| 1201 | count = 4; | ||
| 1202 | } | ||
| 1203 | |||
| 1113 | /* Check parameters. */ | 1204 | /* Check parameters. */ |
| 1114 | bus = args[0]; | 1205 | XD_DBUS_VALIDATE_BUS_ADDRESS (bus); |
| 1115 | service = args[1]; | 1206 | XD_DBUS_VALIDATE_BUS_NAME (service); |
| 1116 | path = args[2]; | 1207 | if (nargs < count) |
| 1117 | interface = args[3]; | 1208 | xsignal2 (Qwrong_number_of_arguments, |
| 1118 | method = args[4]; | 1209 | Qdbus_message_internal, |
| 1119 | 1210 | make_number (nargs)); | |
| 1120 | CHECK_STRING (service); | 1211 | |
| 1121 | CHECK_STRING (path); | 1212 | if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) |
| 1122 | CHECK_STRING (interface); | 1213 | || (mtype == DBUS_MESSAGE_TYPE_SIGNAL)) |
| 1123 | CHECK_STRING (method); | 1214 | { |
| 1124 | GCPRO5 (bus, service, path, interface, method); | 1215 | XD_DBUS_VALIDATE_PATH (path); |
| 1125 | 1216 | XD_DBUS_VALIDATE_INTERFACE (interface); | |
| 1126 | XD_DEBUG_MESSAGE ("%s %s %s %s", | 1217 | XD_DBUS_VALIDATE_MEMBER (member); |
| 1127 | SDATA (service), | 1218 | if (!NILP (handler) && (!FUNCTIONP (handler))) |
| 1128 | SDATA (path), | 1219 | wrong_type_argument (Qinvalid_function, handler); |
| 1129 | SDATA (interface), | 1220 | } |
| 1130 | SDATA (method)); | ||
| 1131 | |||
| 1132 | /* Open a connection to the bus. */ | ||
| 1133 | connection = xd_initialize (bus, TRUE); | ||
| 1134 | |||
| 1135 | /* Create the message. */ | ||
| 1136 | dmessage = dbus_message_new_method_call (SSDATA (service), | ||
| 1137 | SSDATA (path), | ||
| 1138 | SSDATA (interface), | ||
| 1139 | SSDATA (method)); | ||
| 1140 | UNGCPRO; | ||
| 1141 | if (dmessage == NULL) | ||
| 1142 | XD_SIGNAL1 (build_string ("Unable to create a new message")); | ||
| 1143 | 1221 | ||
| 1144 | /* Check for timeout parameter. */ | 1222 | /* Protect Lisp variables. */ |
| 1145 | if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout))) | 1223 | GCPRO6 (bus, service, path, interface, member, handler); |
| 1224 | |||
| 1225 | /* Trace parameters. */ | ||
| 1226 | switch (mtype) | ||
| 1146 | { | 1227 | { |
| 1147 | CHECK_NATNUM (args[i+1]); | 1228 | case DBUS_MESSAGE_TYPE_METHOD_CALL: |
| 1148 | timeout = XFASTINT (args[i+1]); | 1229 | XD_DEBUG_MESSAGE ("%s %s %s %s %s %s %s", |
| 1149 | i = i+2; | 1230 | XD_MESSAGE_TYPE_TO_STRING (mtype), |
| 1231 | XD_OBJECT_TO_STRING (bus), | ||
| 1232 | XD_OBJECT_TO_STRING (service), | ||
| 1233 | XD_OBJECT_TO_STRING (path), | ||
| 1234 | XD_OBJECT_TO_STRING (interface), | ||
| 1235 | XD_OBJECT_TO_STRING (member), | ||
| 1236 | XD_OBJECT_TO_STRING (handler)); | ||
| 1237 | break; | ||
| 1238 | case DBUS_MESSAGE_TYPE_SIGNAL: | ||
| 1239 | XD_DEBUG_MESSAGE ("%s %s %s %s %s %s", | ||
| 1240 | XD_MESSAGE_TYPE_TO_STRING (mtype), | ||
| 1241 | XD_OBJECT_TO_STRING (bus), | ||
| 1242 | XD_OBJECT_TO_STRING (service), | ||
| 1243 | XD_OBJECT_TO_STRING (path), | ||
| 1244 | XD_OBJECT_TO_STRING (interface), | ||
| 1245 | XD_OBJECT_TO_STRING (member)); | ||
| 1246 | break; | ||
| 1247 | default: /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */ | ||
| 1248 | XD_DEBUG_MESSAGE ("%s %s %s %u", | ||
| 1249 | XD_MESSAGE_TYPE_TO_STRING (mtype), | ||
| 1250 | XD_OBJECT_TO_STRING (bus), | ||
| 1251 | XD_OBJECT_TO_STRING (service), | ||
| 1252 | serial); | ||
| 1150 | } | 1253 | } |
| 1151 | 1254 | ||
| 1152 | /* Initialize parameter list of message. */ | 1255 | /* Retrieve bus address. */ |
| 1153 | dbus_message_iter_init_append (dmessage, &iter); | 1256 | connection = xd_get_connection_address (bus); |
| 1154 | 1257 | ||
| 1155 | /* Append parameters to the message. */ | 1258 | /* Create the D-Bus message. */ |
| 1156 | for (; i < nargs; ++i) | 1259 | dmessage = dbus_message_new (mtype); |
| 1260 | if (dmessage == NULL) | ||
| 1157 | { | 1261 | { |
| 1158 | dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]); | 1262 | UNGCPRO; |
| 1159 | if (XD_DBUS_TYPE_P (args[i])) | 1263 | XD_SIGNAL1 (build_string ("Unable to create a new message")); |
| 1264 | } | ||
| 1265 | |||
| 1266 | if (STRINGP (service)) | ||
| 1267 | { | ||
| 1268 | if (mtype != DBUS_MESSAGE_TYPE_SIGNAL) | ||
| 1269 | /* Set destination. */ | ||
| 1160 | { | 1270 | { |
| 1161 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | 1271 | if (!dbus_message_set_destination (dmessage, SSDATA (service))) |
| 1162 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]); | 1272 | { |
| 1163 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", i - 4, | 1273 | UNGCPRO; |
| 1164 | SDATA (format2 ("%s", args[i], Qnil)), | 1274 | XD_SIGNAL2 (build_string ("Unable to set the destination"), |
| 1165 | SDATA (format2 ("%s", args[i+1], Qnil))); | 1275 | service); |
| 1166 | ++i; | 1276 | } |
| 1167 | } | 1277 | } |
| 1278 | |||
| 1168 | else | 1279 | else |
| 1280 | /* Set destination for unicast signals. */ | ||
| 1169 | { | 1281 | { |
| 1170 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | 1282 | Lisp_Object uname; |
| 1171 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", i - 4, | ||
| 1172 | SDATA (format2 ("%s", args[i], Qnil))); | ||
| 1173 | } | ||
| 1174 | 1283 | ||
| 1175 | /* Check for valid signature. We use DBUS_TYPE_INVALID as | 1284 | /* If it is the same unique name as we are registered at the |
| 1176 | indication that there is no parent type. */ | 1285 | bus or an unknown name, we regard it as broadcast message |
| 1177 | xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]); | 1286 | due to backward compatibility. */ |
| 1287 | if (dbus_bus_name_has_owner (connection, SSDATA (service), NULL)) | ||
| 1288 | uname = call2 (intern ("dbus-get-name-owner"), bus, service); | ||
| 1289 | else | ||
| 1290 | uname = Qnil; | ||
| 1178 | 1291 | ||
| 1179 | xd_append_arg (dtype, args[i], &iter); | 1292 | if (STRINGP (uname) |
| 1293 | && (strcmp (dbus_bus_get_unique_name (connection), SSDATA (uname)) | ||
| 1294 | != 0) | ||
| 1295 | && (!dbus_message_set_destination (dmessage, SSDATA (service)))) | ||
| 1296 | { | ||
| 1297 | UNGCPRO; | ||
| 1298 | XD_SIGNAL2 (build_string ("Unable to set signal destination"), | ||
| 1299 | service); | ||
| 1300 | } | ||
| 1301 | } | ||
| 1180 | } | 1302 | } |
| 1181 | 1303 | ||
| 1182 | /* Send the message. */ | 1304 | /* Set message parameters. */ |
| 1183 | dbus_error_init (&derror); | 1305 | if ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) |
| 1184 | reply = dbus_connection_send_with_reply_and_block (connection, | 1306 | || (mtype == DBUS_MESSAGE_TYPE_SIGNAL)) |
| 1185 | dmessage, | ||
| 1186 | timeout, | ||
| 1187 | &derror); | ||
| 1188 | |||
| 1189 | if (dbus_error_is_set (&derror)) | ||
| 1190 | XD_ERROR (derror); | ||
| 1191 | |||
| 1192 | if (reply == NULL) | ||
| 1193 | XD_SIGNAL1 (build_string ("No reply")); | ||
| 1194 | |||
| 1195 | XD_DEBUG_MESSAGE ("Message sent"); | ||
| 1196 | |||
| 1197 | /* Collect the results. */ | ||
| 1198 | result = Qnil; | ||
| 1199 | GCPRO1 (result); | ||
| 1200 | |||
| 1201 | if (dbus_message_iter_init (reply, &iter)) | ||
| 1202 | { | 1307 | { |
| 1203 | /* Loop over the parameters of the D-Bus reply message. Construct a | 1308 | if ((!dbus_message_set_path (dmessage, SSDATA (path))) |
| 1204 | Lisp list, which is returned by `dbus-call-method'. */ | 1309 | || (!dbus_message_set_interface (dmessage, SSDATA (interface))) |
| 1205 | while ((dtype = dbus_message_iter_get_arg_type (&iter)) | 1310 | || (!dbus_message_set_member (dmessage, SSDATA (member)))) |
| 1206 | != DBUS_TYPE_INVALID) | ||
| 1207 | { | 1311 | { |
| 1208 | result = Fcons (xd_retrieve_arg (dtype, &iter), result); | 1312 | UNGCPRO; |
| 1209 | dbus_message_iter_next (&iter); | 1313 | XD_SIGNAL1 (build_string ("Unable to set the message parameter")); |
| 1210 | } | 1314 | } |
| 1211 | } | 1315 | } |
| 1212 | else | ||
| 1213 | { | ||
| 1214 | /* No arguments: just return nil. */ | ||
| 1215 | } | ||
| 1216 | |||
| 1217 | /* Cleanup. */ | ||
| 1218 | dbus_error_free (&derror); | ||
| 1219 | dbus_message_unref (dmessage); | ||
| 1220 | dbus_message_unref (reply); | ||
| 1221 | |||
| 1222 | /* Return the result. If there is only one single Lisp object, | ||
| 1223 | return it as-it-is, otherwise return the reversed list. */ | ||
| 1224 | if (XFASTINT (Flength (result)) == 1) | ||
| 1225 | RETURN_UNGCPRO (CAR_SAFE (result)); | ||
| 1226 | else | ||
| 1227 | RETURN_UNGCPRO (Fnreverse (result)); | ||
| 1228 | } | ||
| 1229 | |||
| 1230 | DEFUN ("dbus-call-method-asynchronously", Fdbus_call_method_asynchronously, | ||
| 1231 | Sdbus_call_method_asynchronously, 6, MANY, 0, | ||
| 1232 | doc: /* Call METHOD on the D-Bus BUS asynchronously. | ||
| 1233 | |||
| 1234 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 1235 | denoting the bus address. | ||
| 1236 | |||
| 1237 | SERVICE is the D-Bus service name to be used. PATH is the D-Bus | ||
| 1238 | object path SERVICE is registered at. INTERFACE is an interface | ||
| 1239 | offered by SERVICE. It must provide METHOD. | ||
| 1240 | |||
| 1241 | HANDLER is a Lisp function, which is called when the corresponding | ||
| 1242 | return message has arrived. If HANDLER is nil, no return message will | ||
| 1243 | be expected. | ||
| 1244 | 1316 | ||
| 1245 | If the parameter `:timeout' is given, the following integer TIMEOUT | 1317 | else /* DBUS_MESSAGE_TYPE_METHOD_RETURN, DBUS_MESSAGE_TYPE_ERROR */ |
| 1246 | specifies the maximum number of milliseconds the method call must | 1318 | { |
| 1247 | return. The default value is 25,000. If the method call doesn't | 1319 | if (!dbus_message_set_reply_serial (dmessage, serial)) |
| 1248 | return in time, a D-Bus error is raised. | 1320 | { |
| 1249 | 1321 | UNGCPRO; | |
| 1250 | All other arguments ARGS are passed to METHOD as arguments. They are | 1322 | XD_SIGNAL1 (build_string ("Unable to create a return message")); |
| 1251 | converted into D-Bus types via the following rules: | 1323 | } |
| 1252 | |||
| 1253 | t and nil => DBUS_TYPE_BOOLEAN | ||
| 1254 | number => DBUS_TYPE_UINT32 | ||
| 1255 | integer => DBUS_TYPE_INT32 | ||
| 1256 | float => DBUS_TYPE_DOUBLE | ||
| 1257 | string => DBUS_TYPE_STRING | ||
| 1258 | list => DBUS_TYPE_ARRAY | ||
| 1259 | |||
| 1260 | All arguments can be preceded by a type symbol. For details about | ||
| 1261 | type symbols, see Info node `(dbus)Type Conversion'. | ||
| 1262 | |||
| 1263 | Unless HANDLER is nil, the function returns a key into the hash table | ||
| 1264 | `dbus-registered-objects-table'. The corresponding entry in the hash | ||
| 1265 | table is removed, when the return message has been arrived, and | ||
| 1266 | HANDLER is called. | ||
| 1267 | |||
| 1268 | Example: | ||
| 1269 | |||
| 1270 | \(dbus-call-method-asynchronously | ||
| 1271 | :system "org.freedesktop.Hal" "/org/freedesktop/Hal/devices/computer" | ||
| 1272 | "org.freedesktop.Hal.Device" "GetPropertyString" 'message | ||
| 1273 | "system.kernel.machine") | ||
| 1274 | |||
| 1275 | => (:system 2) | ||
| 1276 | |||
| 1277 | -| i686 | ||
| 1278 | |||
| 1279 | usage: (dbus-call-method-asynchronously BUS SERVICE PATH INTERFACE METHOD HANDLER &optional :timeout TIMEOUT &rest ARGS) */) | ||
| 1280 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 1281 | { | ||
| 1282 | Lisp_Object bus, service, path, interface, method, handler; | ||
| 1283 | Lisp_Object result; | ||
| 1284 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; | ||
| 1285 | DBusConnection *connection; | ||
| 1286 | DBusMessage *dmessage; | ||
| 1287 | DBusMessageIter iter; | ||
| 1288 | unsigned int dtype; | ||
| 1289 | dbus_uint32_t serial; | ||
| 1290 | int timeout = -1; | ||
| 1291 | ptrdiff_t i = 6; | ||
| 1292 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; | ||
| 1293 | 1324 | ||
| 1294 | /* Check parameters. */ | 1325 | if ((mtype == DBUS_MESSAGE_TYPE_ERROR) |
| 1295 | bus = args[0]; | 1326 | && (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED))) |
| 1296 | service = args[1]; | 1327 | { |
| 1297 | path = args[2]; | 1328 | UNGCPRO; |
| 1298 | interface = args[3]; | 1329 | XD_SIGNAL1 (build_string ("Unable to create a error message")); |
| 1299 | method = args[4]; | 1330 | } |
| 1300 | handler = args[5]; | 1331 | } |
| 1301 | |||
| 1302 | CHECK_STRING (service); | ||
| 1303 | CHECK_STRING (path); | ||
| 1304 | CHECK_STRING (interface); | ||
| 1305 | CHECK_STRING (method); | ||
| 1306 | if (!NILP (handler) && !FUNCTIONP (handler)) | ||
| 1307 | wrong_type_argument (Qinvalid_function, handler); | ||
| 1308 | GCPRO6 (bus, service, path, interface, method, handler); | ||
| 1309 | |||
| 1310 | XD_DEBUG_MESSAGE ("%s %s %s %s", | ||
| 1311 | SDATA (service), | ||
| 1312 | SDATA (path), | ||
| 1313 | SDATA (interface), | ||
| 1314 | SDATA (method)); | ||
| 1315 | |||
| 1316 | /* Open a connection to the bus. */ | ||
| 1317 | connection = xd_initialize (bus, TRUE); | ||
| 1318 | |||
| 1319 | /* Create the message. */ | ||
| 1320 | dmessage = dbus_message_new_method_call (SSDATA (service), | ||
| 1321 | SSDATA (path), | ||
| 1322 | SSDATA (interface), | ||
| 1323 | SSDATA (method)); | ||
| 1324 | if (dmessage == NULL) | ||
| 1325 | XD_SIGNAL1 (build_string ("Unable to create a new message")); | ||
| 1326 | 1332 | ||
| 1327 | /* Check for timeout parameter. */ | 1333 | /* Check for timeout parameter. */ |
| 1328 | if ((i+2 <= nargs) && (EQ ((args[i]), QCdbus_timeout))) | 1334 | if ((count+2 <= nargs) && (EQ ((args[count]), QCdbus_timeout))) |
| 1329 | { | 1335 | { |
| 1330 | CHECK_NATNUM (args[i+1]); | 1336 | CHECK_NATNUM (args[count+1]); |
| 1331 | timeout = XFASTINT (args[i+1]); | 1337 | timeout = XFASTINT (args[count+1]); |
| 1332 | i = i+2; | 1338 | count = count+2; |
| 1333 | } | 1339 | } |
| 1334 | 1340 | ||
| 1335 | /* Initialize parameter list of message. */ | 1341 | /* Initialize parameter list of message. */ |
| 1336 | dbus_message_iter_init_append (dmessage, &iter); | 1342 | dbus_message_iter_init_append (dmessage, &iter); |
| 1337 | 1343 | ||
| 1338 | /* Append parameters to the message. */ | 1344 | /* Append parameters to the message. */ |
| 1339 | for (; i < nargs; ++i) | 1345 | for (; count < nargs; ++count) |
| 1340 | { | 1346 | { |
| 1341 | dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]); | 1347 | dtype = XD_OBJECT_TO_DBUS_TYPE (args[count]); |
| 1342 | if (XD_DBUS_TYPE_P (args[i])) | 1348 | if (XD_DBUS_TYPE_P (args[count])) |
| 1343 | { | 1349 | { |
| 1344 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | 1350 | XD_DEBUG_VALID_LISP_OBJECT_P (args[count]); |
| 1345 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]); | 1351 | XD_DEBUG_VALID_LISP_OBJECT_P (args[count+1]); |
| 1346 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", i - 4, | 1352 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", count - 4, |
| 1347 | SDATA (format2 ("%s", args[i], Qnil)), | 1353 | XD_OBJECT_TO_STRING (args[count]), |
| 1348 | SDATA (format2 ("%s", args[i+1], Qnil))); | 1354 | XD_OBJECT_TO_STRING (args[count+1])); |
| 1349 | ++i; | 1355 | ++count; |
| 1350 | } | 1356 | } |
| 1351 | else | 1357 | else |
| 1352 | { | 1358 | { |
| 1353 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | 1359 | XD_DEBUG_VALID_LISP_OBJECT_P (args[count]); |
| 1354 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", i - 4, | 1360 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", count - 4, |
| 1355 | SDATA (format2 ("%s", args[i], Qnil))); | 1361 | XD_OBJECT_TO_STRING (args[count])); |
| 1356 | } | 1362 | } |
| 1357 | 1363 | ||
| 1358 | /* Check for valid signature. We use DBUS_TYPE_INVALID as | 1364 | /* Check for valid signature. We use DBUS_TYPE_INVALID as |
| 1359 | indication that there is no parent type. */ | 1365 | indication that there is no parent type. */ |
| 1360 | xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]); | 1366 | xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[count]); |
| 1361 | 1367 | ||
| 1362 | xd_append_arg (dtype, args[i], &iter); | 1368 | xd_append_arg (dtype, args[count], &iter); |
| 1363 | } | 1369 | } |
| 1364 | 1370 | ||
| 1365 | if (!NILP (handler)) | 1371 | if (!NILP (handler)) |
| @@ -1368,11 +1374,15 @@ usage: (dbus-call-method-asynchronously BUS SERVICE PATH INTERFACE METHOD HANDLE | |||
| 1368 | message queue. */ | 1374 | message queue. */ |
| 1369 | if (!dbus_connection_send_with_reply (connection, dmessage, | 1375 | if (!dbus_connection_send_with_reply (connection, dmessage, |
| 1370 | NULL, timeout)) | 1376 | NULL, timeout)) |
| 1371 | XD_SIGNAL1 (build_string ("Cannot send message")); | 1377 | { |
| 1378 | UNGCPRO; | ||
| 1379 | XD_SIGNAL1 (build_string ("Cannot send message")); | ||
| 1380 | } | ||
| 1372 | 1381 | ||
| 1373 | /* The result is the key in Vdbus_registered_objects_table. */ | 1382 | /* The result is the key in Vdbus_registered_objects_table. */ |
| 1374 | serial = dbus_message_get_serial (dmessage); | 1383 | serial = dbus_message_get_serial (dmessage); |
| 1375 | result = list2 (bus, make_fixnum_or_float (serial)); | 1384 | result = list3 (QCdbus_registered_serial, |
| 1385 | bus, make_fixnum_or_float (serial)); | ||
| 1376 | 1386 | ||
| 1377 | /* Create a hash table entry. */ | 1387 | /* Create a hash table entry. */ |
| 1378 | Fputhash (result, handler, Vdbus_registered_objects_table); | 1388 | Fputhash (result, handler, Vdbus_registered_objects_table); |
| @@ -1382,12 +1392,15 @@ usage: (dbus-call-method-asynchronously BUS SERVICE PATH INTERFACE METHOD HANDLE | |||
| 1382 | /* Send the message. The message is just added to the outgoing | 1392 | /* Send the message. The message is just added to the outgoing |
| 1383 | message queue. */ | 1393 | message queue. */ |
| 1384 | if (!dbus_connection_send (connection, dmessage, NULL)) | 1394 | if (!dbus_connection_send (connection, dmessage, NULL)) |
| 1385 | XD_SIGNAL1 (build_string ("Cannot send message")); | 1395 | { |
| 1396 | UNGCPRO; | ||
| 1397 | XD_SIGNAL1 (build_string ("Cannot send message")); | ||
| 1398 | } | ||
| 1386 | 1399 | ||
| 1387 | result = Qnil; | 1400 | result = Qnil; |
| 1388 | } | 1401 | } |
| 1389 | 1402 | ||
| 1390 | XD_DEBUG_MESSAGE ("Message sent"); | 1403 | XD_DEBUG_MESSAGE ("Message sent: %s", XD_OBJECT_TO_STRING (result)); |
| 1391 | 1404 | ||
| 1392 | /* Cleanup. */ | 1405 | /* Cleanup. */ |
| 1393 | dbus_message_unref (dmessage); | 1406 | dbus_message_unref (dmessage); |
| @@ -1396,300 +1409,6 @@ usage: (dbus-call-method-asynchronously BUS SERVICE PATH INTERFACE METHOD HANDLE | |||
| 1396 | RETURN_UNGCPRO (result); | 1409 | RETURN_UNGCPRO (result); |
| 1397 | } | 1410 | } |
| 1398 | 1411 | ||
| 1399 | DEFUN ("dbus-method-return-internal", Fdbus_method_return_internal, | ||
| 1400 | Sdbus_method_return_internal, | ||
| 1401 | 3, MANY, 0, | ||
| 1402 | doc: /* Return for message SERIAL on the D-Bus BUS. | ||
| 1403 | This is an internal function, it shall not be used outside dbus.el. | ||
| 1404 | |||
| 1405 | usage: (dbus-method-return-internal BUS SERIAL SERVICE &rest ARGS) */) | ||
| 1406 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 1407 | { | ||
| 1408 | Lisp_Object bus, service; | ||
| 1409 | struct gcpro gcpro1, gcpro2; | ||
| 1410 | DBusConnection *connection; | ||
| 1411 | DBusMessage *dmessage; | ||
| 1412 | DBusMessageIter iter; | ||
| 1413 | dbus_uint32_t serial; | ||
| 1414 | unsigned int ui_serial, dtype; | ||
| 1415 | ptrdiff_t i; | ||
| 1416 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; | ||
| 1417 | |||
| 1418 | /* Check parameters. */ | ||
| 1419 | bus = args[0]; | ||
| 1420 | service = args[2]; | ||
| 1421 | |||
| 1422 | CHECK_DBUS_SERIAL_GET_SERIAL (args[1], serial); | ||
| 1423 | CHECK_STRING (service); | ||
| 1424 | GCPRO2 (bus, service); | ||
| 1425 | |||
| 1426 | ui_serial = serial; | ||
| 1427 | XD_DEBUG_MESSAGE ("%u %s ", ui_serial, SSDATA (service)); | ||
| 1428 | |||
| 1429 | /* Open a connection to the bus. */ | ||
| 1430 | connection = xd_initialize (bus, TRUE); | ||
| 1431 | |||
| 1432 | /* Create the message. */ | ||
| 1433 | dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_RETURN); | ||
| 1434 | if ((dmessage == NULL) | ||
| 1435 | || (!dbus_message_set_reply_serial (dmessage, serial)) | ||
| 1436 | || (!dbus_message_set_destination (dmessage, SSDATA (service)))) | ||
| 1437 | { | ||
| 1438 | UNGCPRO; | ||
| 1439 | XD_SIGNAL1 (build_string ("Unable to create a return message")); | ||
| 1440 | } | ||
| 1441 | |||
| 1442 | UNGCPRO; | ||
| 1443 | |||
| 1444 | /* Initialize parameter list of message. */ | ||
| 1445 | dbus_message_iter_init_append (dmessage, &iter); | ||
| 1446 | |||
| 1447 | /* Append parameters to the message. */ | ||
| 1448 | for (i = 3; i < nargs; ++i) | ||
| 1449 | { | ||
| 1450 | dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]); | ||
| 1451 | if (XD_DBUS_TYPE_P (args[i])) | ||
| 1452 | { | ||
| 1453 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | ||
| 1454 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]); | ||
| 1455 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", i - 2, | ||
| 1456 | SDATA (format2 ("%s", args[i], Qnil)), | ||
| 1457 | SDATA (format2 ("%s", args[i+1], Qnil))); | ||
| 1458 | ++i; | ||
| 1459 | } | ||
| 1460 | else | ||
| 1461 | { | ||
| 1462 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | ||
| 1463 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", i - 2, | ||
| 1464 | SDATA (format2 ("%s", args[i], Qnil))); | ||
| 1465 | } | ||
| 1466 | |||
| 1467 | /* Check for valid signature. We use DBUS_TYPE_INVALID as | ||
| 1468 | indication that there is no parent type. */ | ||
| 1469 | xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]); | ||
| 1470 | |||
| 1471 | xd_append_arg (dtype, args[i], &iter); | ||
| 1472 | } | ||
| 1473 | |||
| 1474 | /* Send the message. The message is just added to the outgoing | ||
| 1475 | message queue. */ | ||
| 1476 | if (!dbus_connection_send (connection, dmessage, NULL)) | ||
| 1477 | XD_SIGNAL1 (build_string ("Cannot send message")); | ||
| 1478 | |||
| 1479 | XD_DEBUG_MESSAGE ("Message sent"); | ||
| 1480 | |||
| 1481 | /* Cleanup. */ | ||
| 1482 | dbus_message_unref (dmessage); | ||
| 1483 | |||
| 1484 | /* Return. */ | ||
| 1485 | return Qt; | ||
| 1486 | } | ||
| 1487 | |||
| 1488 | DEFUN ("dbus-method-error-internal", Fdbus_method_error_internal, | ||
| 1489 | Sdbus_method_error_internal, | ||
| 1490 | 3, MANY, 0, | ||
| 1491 | doc: /* Return error message for message SERIAL on the D-Bus BUS. | ||
| 1492 | This is an internal function, it shall not be used outside dbus.el. | ||
| 1493 | |||
| 1494 | usage: (dbus-method-error-internal BUS SERIAL SERVICE &rest ARGS) */) | ||
| 1495 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 1496 | { | ||
| 1497 | Lisp_Object bus, service; | ||
| 1498 | struct gcpro gcpro1, gcpro2; | ||
| 1499 | DBusConnection *connection; | ||
| 1500 | DBusMessage *dmessage; | ||
| 1501 | DBusMessageIter iter; | ||
| 1502 | dbus_uint32_t serial; | ||
| 1503 | unsigned int ui_serial, dtype; | ||
| 1504 | ptrdiff_t i; | ||
| 1505 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; | ||
| 1506 | |||
| 1507 | /* Check parameters. */ | ||
| 1508 | bus = args[0]; | ||
| 1509 | service = args[2]; | ||
| 1510 | |||
| 1511 | CHECK_DBUS_SERIAL_GET_SERIAL (args[1], serial); | ||
| 1512 | CHECK_STRING (service); | ||
| 1513 | GCPRO2 (bus, service); | ||
| 1514 | |||
| 1515 | ui_serial = serial; | ||
| 1516 | XD_DEBUG_MESSAGE ("%u %s ", ui_serial, SSDATA (service)); | ||
| 1517 | |||
| 1518 | /* Open a connection to the bus. */ | ||
| 1519 | connection = xd_initialize (bus, TRUE); | ||
| 1520 | |||
| 1521 | /* Create the message. */ | ||
| 1522 | dmessage = dbus_message_new (DBUS_MESSAGE_TYPE_ERROR); | ||
| 1523 | if ((dmessage == NULL) | ||
| 1524 | || (!dbus_message_set_error_name (dmessage, DBUS_ERROR_FAILED)) | ||
| 1525 | || (!dbus_message_set_reply_serial (dmessage, serial)) | ||
| 1526 | || (!dbus_message_set_destination (dmessage, SSDATA (service)))) | ||
| 1527 | { | ||
| 1528 | UNGCPRO; | ||
| 1529 | XD_SIGNAL1 (build_string ("Unable to create a error message")); | ||
| 1530 | } | ||
| 1531 | |||
| 1532 | UNGCPRO; | ||
| 1533 | |||
| 1534 | /* Initialize parameter list of message. */ | ||
| 1535 | dbus_message_iter_init_append (dmessage, &iter); | ||
| 1536 | |||
| 1537 | /* Append parameters to the message. */ | ||
| 1538 | for (i = 3; i < nargs; ++i) | ||
| 1539 | { | ||
| 1540 | dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]); | ||
| 1541 | if (XD_DBUS_TYPE_P (args[i])) | ||
| 1542 | { | ||
| 1543 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | ||
| 1544 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]); | ||
| 1545 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", i - 2, | ||
| 1546 | SDATA (format2 ("%s", args[i], Qnil)), | ||
| 1547 | SDATA (format2 ("%s", args[i+1], Qnil))); | ||
| 1548 | ++i; | ||
| 1549 | } | ||
| 1550 | else | ||
| 1551 | { | ||
| 1552 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | ||
| 1553 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", i - 2, | ||
| 1554 | SDATA (format2 ("%s", args[i], Qnil))); | ||
| 1555 | } | ||
| 1556 | |||
| 1557 | /* Check for valid signature. We use DBUS_TYPE_INVALID as | ||
| 1558 | indication that there is no parent type. */ | ||
| 1559 | xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]); | ||
| 1560 | |||
| 1561 | xd_append_arg (dtype, args[i], &iter); | ||
| 1562 | } | ||
| 1563 | |||
| 1564 | /* Send the message. The message is just added to the outgoing | ||
| 1565 | message queue. */ | ||
| 1566 | if (!dbus_connection_send (connection, dmessage, NULL)) | ||
| 1567 | XD_SIGNAL1 (build_string ("Cannot send message")); | ||
| 1568 | |||
| 1569 | XD_DEBUG_MESSAGE ("Message sent"); | ||
| 1570 | |||
| 1571 | /* Cleanup. */ | ||
| 1572 | dbus_message_unref (dmessage); | ||
| 1573 | |||
| 1574 | /* Return. */ | ||
| 1575 | return Qt; | ||
| 1576 | } | ||
| 1577 | |||
| 1578 | DEFUN ("dbus-send-signal", Fdbus_send_signal, Sdbus_send_signal, 5, MANY, 0, | ||
| 1579 | doc: /* Send signal SIGNAL on the D-Bus BUS. | ||
| 1580 | |||
| 1581 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 1582 | denoting the bus address. | ||
| 1583 | |||
| 1584 | SERVICE is the D-Bus service name SIGNAL is sent from. PATH is the | ||
| 1585 | D-Bus object path SERVICE is registered at. INTERFACE is an interface | ||
| 1586 | offered by SERVICE. It must provide signal SIGNAL. | ||
| 1587 | |||
| 1588 | All other arguments ARGS are passed to SIGNAL as arguments. They are | ||
| 1589 | converted into D-Bus types via the following rules: | ||
| 1590 | |||
| 1591 | t and nil => DBUS_TYPE_BOOLEAN | ||
| 1592 | number => DBUS_TYPE_UINT32 | ||
| 1593 | integer => DBUS_TYPE_INT32 | ||
| 1594 | float => DBUS_TYPE_DOUBLE | ||
| 1595 | string => DBUS_TYPE_STRING | ||
| 1596 | list => DBUS_TYPE_ARRAY | ||
| 1597 | |||
| 1598 | All arguments can be preceded by a type symbol. For details about | ||
| 1599 | type symbols, see Info node `(dbus)Type Conversion'. | ||
| 1600 | |||
| 1601 | Example: | ||
| 1602 | |||
| 1603 | \(dbus-send-signal | ||
| 1604 | :session "org.gnu.Emacs" "/org/gnu/Emacs" | ||
| 1605 | "org.gnu.Emacs.FileManager" "FileModified" "/home/albinus/.emacs") | ||
| 1606 | |||
| 1607 | usage: (dbus-send-signal BUS SERVICE PATH INTERFACE SIGNAL &rest ARGS) */) | ||
| 1608 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 1609 | { | ||
| 1610 | Lisp_Object bus, service, path, interface, signal; | ||
| 1611 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5; | ||
| 1612 | DBusConnection *connection; | ||
| 1613 | DBusMessage *dmessage; | ||
| 1614 | DBusMessageIter iter; | ||
| 1615 | unsigned int dtype; | ||
| 1616 | ptrdiff_t i; | ||
| 1617 | char signature[DBUS_MAXIMUM_SIGNATURE_LENGTH]; | ||
| 1618 | |||
| 1619 | /* Check parameters. */ | ||
| 1620 | bus = args[0]; | ||
| 1621 | service = args[1]; | ||
| 1622 | path = args[2]; | ||
| 1623 | interface = args[3]; | ||
| 1624 | signal = args[4]; | ||
| 1625 | |||
| 1626 | CHECK_STRING (service); | ||
| 1627 | CHECK_STRING (path); | ||
| 1628 | CHECK_STRING (interface); | ||
| 1629 | CHECK_STRING (signal); | ||
| 1630 | GCPRO5 (bus, service, path, interface, signal); | ||
| 1631 | |||
| 1632 | XD_DEBUG_MESSAGE ("%s %s %s %s", | ||
| 1633 | SDATA (service), | ||
| 1634 | SDATA (path), | ||
| 1635 | SDATA (interface), | ||
| 1636 | SDATA (signal)); | ||
| 1637 | |||
| 1638 | /* Open a connection to the bus. */ | ||
| 1639 | connection = xd_initialize (bus, TRUE); | ||
| 1640 | |||
| 1641 | /* Create the message. */ | ||
| 1642 | dmessage = dbus_message_new_signal (SSDATA (path), | ||
| 1643 | SSDATA (interface), | ||
| 1644 | SSDATA (signal)); | ||
| 1645 | UNGCPRO; | ||
| 1646 | if (dmessage == NULL) | ||
| 1647 | XD_SIGNAL1 (build_string ("Unable to create a new message")); | ||
| 1648 | |||
| 1649 | /* Initialize parameter list of message. */ | ||
| 1650 | dbus_message_iter_init_append (dmessage, &iter); | ||
| 1651 | |||
| 1652 | /* Append parameters to the message. */ | ||
| 1653 | for (i = 5; i < nargs; ++i) | ||
| 1654 | { | ||
| 1655 | dtype = XD_OBJECT_TO_DBUS_TYPE (args[i]); | ||
| 1656 | if (XD_DBUS_TYPE_P (args[i])) | ||
| 1657 | { | ||
| 1658 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | ||
| 1659 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i+1]); | ||
| 1660 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s %s", i - 4, | ||
| 1661 | SDATA (format2 ("%s", args[i], Qnil)), | ||
| 1662 | SDATA (format2 ("%s", args[i+1], Qnil))); | ||
| 1663 | ++i; | ||
| 1664 | } | ||
| 1665 | else | ||
| 1666 | { | ||
| 1667 | XD_DEBUG_VALID_LISP_OBJECT_P (args[i]); | ||
| 1668 | XD_DEBUG_MESSAGE ("Parameter%"pD"d %s", i - 4, | ||
| 1669 | SDATA (format2 ("%s", args[i], Qnil))); | ||
| 1670 | } | ||
| 1671 | |||
| 1672 | /* Check for valid signature. We use DBUS_TYPE_INVALID as | ||
| 1673 | indication that there is no parent type. */ | ||
| 1674 | xd_signature (signature, dtype, DBUS_TYPE_INVALID, args[i]); | ||
| 1675 | |||
| 1676 | xd_append_arg (dtype, args[i], &iter); | ||
| 1677 | } | ||
| 1678 | |||
| 1679 | /* Send the message. The message is just added to the outgoing | ||
| 1680 | message queue. */ | ||
| 1681 | if (!dbus_connection_send (connection, dmessage, NULL)) | ||
| 1682 | XD_SIGNAL1 (build_string ("Cannot send message")); | ||
| 1683 | |||
| 1684 | XD_DEBUG_MESSAGE ("Signal sent"); | ||
| 1685 | |||
| 1686 | /* Cleanup. */ | ||
| 1687 | dbus_message_unref (dmessage); | ||
| 1688 | |||
| 1689 | /* Return. */ | ||
| 1690 | return Qt; | ||
| 1691 | } | ||
| 1692 | |||
| 1693 | /* Read one queued incoming message of the D-Bus BUS. | 1412 | /* Read one queued incoming message of the D-Bus BUS. |
| 1694 | BUS is either a Lisp symbol, :system or :session, or a string denoting | 1413 | BUS is either a Lisp symbol, :system or :session, or a string denoting |
| 1695 | the bus address. */ | 1414 | the bus address. */ |
| @@ -1702,7 +1421,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1702 | DBusMessage *dmessage; | 1421 | DBusMessage *dmessage; |
| 1703 | DBusMessageIter iter; | 1422 | DBusMessageIter iter; |
| 1704 | unsigned int dtype; | 1423 | unsigned int dtype; |
| 1705 | int mtype; | 1424 | unsigned int mtype; |
| 1706 | dbus_uint32_t serial; | 1425 | dbus_uint32_t serial; |
| 1707 | unsigned int ui_serial; | 1426 | unsigned int ui_serial; |
| 1708 | const char *uname, *path, *interface, *member; | 1427 | const char *uname, *path, *interface, *member; |
| @@ -1744,23 +1463,19 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1744 | member = dbus_message_get_member (dmessage); | 1463 | member = dbus_message_get_member (dmessage); |
| 1745 | 1464 | ||
| 1746 | XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s", | 1465 | XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s", |
| 1747 | (mtype == DBUS_MESSAGE_TYPE_INVALID) | 1466 | XD_MESSAGE_TYPE_TO_STRING (mtype), |
| 1748 | ? "DBUS_MESSAGE_TYPE_INVALID" | ||
| 1749 | : (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) | ||
| 1750 | ? "DBUS_MESSAGE_TYPE_METHOD_CALL" | ||
| 1751 | : (mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) | ||
| 1752 | ? "DBUS_MESSAGE_TYPE_METHOD_RETURN" | ||
| 1753 | : (mtype == DBUS_MESSAGE_TYPE_ERROR) | ||
| 1754 | ? "DBUS_MESSAGE_TYPE_ERROR" | ||
| 1755 | : "DBUS_MESSAGE_TYPE_SIGNAL", | ||
| 1756 | ui_serial, uname, path, interface, member, | 1467 | ui_serial, uname, path, interface, member, |
| 1757 | SDATA (format2 ("%s", args, Qnil))); | 1468 | XD_OBJECT_TO_STRING (args)); |
| 1469 | |||
| 1470 | if (mtype == DBUS_MESSAGE_TYPE_INVALID) | ||
| 1471 | goto cleanup; | ||
| 1758 | 1472 | ||
| 1759 | if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) | 1473 | else if ((mtype == DBUS_MESSAGE_TYPE_METHOD_RETURN) |
| 1760 | || (mtype == DBUS_MESSAGE_TYPE_ERROR)) | 1474 | || (mtype == DBUS_MESSAGE_TYPE_ERROR)) |
| 1761 | { | 1475 | { |
| 1762 | /* Search for a registered function of the message. */ | 1476 | /* Search for a registered function of the message. */ |
| 1763 | key = list2 (bus, make_fixnum_or_float (serial)); | 1477 | key = list3 (QCdbus_registered_serial, bus, |
| 1478 | make_fixnum_or_float (serial)); | ||
| 1764 | value = Fgethash (key, Vdbus_registered_objects_table, Qnil); | 1479 | value = Fgethash (key, Vdbus_registered_objects_table, Qnil); |
| 1765 | 1480 | ||
| 1766 | /* There shall be exactly one entry. Construct an event. */ | 1481 | /* There shall be exactly one entry. Construct an event. */ |
| @@ -1777,7 +1492,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1777 | event.arg = Fcons (value, args); | 1492 | event.arg = Fcons (value, args); |
| 1778 | } | 1493 | } |
| 1779 | 1494 | ||
| 1780 | else /* (mtype != DBUS_MESSAGE_TYPE_METHOD_RETURN) */ | 1495 | else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */ |
| 1781 | { | 1496 | { |
| 1782 | /* Vdbus_registered_objects_table requires non-nil interface and | 1497 | /* Vdbus_registered_objects_table requires non-nil interface and |
| 1783 | member. */ | 1498 | member. */ |
| @@ -1785,7 +1500,10 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1785 | goto cleanup; | 1500 | goto cleanup; |
| 1786 | 1501 | ||
| 1787 | /* Search for a registered function of the message. */ | 1502 | /* Search for a registered function of the message. */ |
| 1788 | key = list3 (bus, build_string (interface), build_string (member)); | 1503 | key = list4 ((mtype == DBUS_MESSAGE_TYPE_METHOD_CALL) |
| 1504 | ? QCdbus_registered_method | ||
| 1505 | : QCdbus_registered_signal, | ||
| 1506 | bus, build_string (interface), build_string (member)); | ||
| 1789 | value = Fgethash (key, Vdbus_registered_objects_table, Qnil); | 1507 | value = Fgethash (key, Vdbus_registered_objects_table, Qnil); |
| 1790 | 1508 | ||
| 1791 | /* Loop over the registered functions. Construct an event. */ | 1509 | /* Loop over the registered functions. Construct an event. */ |
| @@ -1835,8 +1553,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1835 | /* Store it into the input event queue. */ | 1553 | /* Store it into the input event queue. */ |
| 1836 | kbd_buffer_store_event (&event); | 1554 | kbd_buffer_store_event (&event); |
| 1837 | 1555 | ||
| 1838 | XD_DEBUG_MESSAGE ("Event stored: %s", | 1556 | XD_DEBUG_MESSAGE ("Event stored: %s", XD_OBJECT_TO_STRING (event.arg)); |
| 1839 | SDATA (format2 ("%s", event.arg, Qnil))); | ||
| 1840 | 1557 | ||
| 1841 | /* Cleanup. */ | 1558 | /* Cleanup. */ |
| 1842 | cleanup: | 1559 | cleanup: |
| @@ -1851,8 +1568,8 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) | |||
| 1851 | static Lisp_Object | 1568 | static Lisp_Object |
| 1852 | xd_read_message (Lisp_Object bus) | 1569 | xd_read_message (Lisp_Object bus) |
| 1853 | { | 1570 | { |
| 1854 | /* Open a connection to the bus. */ | 1571 | /* Retrieve bus address. */ |
| 1855 | DBusConnection *connection = xd_initialize (bus, TRUE); | 1572 | DBusConnection *connection = xd_get_connection_address (bus); |
| 1856 | 1573 | ||
| 1857 | /* Non blocking read of the next available message. */ | 1574 | /* Non blocking read of the next available message. */ |
| 1858 | dbus_connection_read_write (connection, 0); | 1575 | dbus_connection_read_write (connection, 0); |
| @@ -1869,14 +1586,16 @@ xd_read_queued_messages (int fd, void *data, int for_read) | |||
| 1869 | { | 1586 | { |
| 1870 | Lisp_Object busp = Vdbus_registered_buses; | 1587 | Lisp_Object busp = Vdbus_registered_buses; |
| 1871 | Lisp_Object bus = Qnil; | 1588 | Lisp_Object bus = Qnil; |
| 1589 | Lisp_Object key; | ||
| 1872 | 1590 | ||
| 1873 | /* Find bus related to fd. */ | 1591 | /* Find bus related to fd. */ |
| 1874 | if (data != NULL) | 1592 | if (data != NULL) |
| 1875 | while (!NILP (busp)) | 1593 | while (!NILP (busp)) |
| 1876 | { | 1594 | { |
| 1877 | if ((SYMBOLP (CAR_SAFE (busp)) && XSYMBOL (CAR_SAFE (busp)) == data) | 1595 | key = CAR_SAFE (CAR_SAFE (busp)); |
| 1878 | || (STRINGP (CAR_SAFE (busp)) && XSTRING (CAR_SAFE (busp)) == data)) | 1596 | if ((SYMBOLP (key) && XSYMBOL (key) == data) |
| 1879 | bus = CAR_SAFE (busp); | 1597 | || (STRINGP (key) && XSTRING (key) == data)) |
| 1598 | bus = key; | ||
| 1880 | busp = CDR_SAFE (busp); | 1599 | busp = CDR_SAFE (busp); |
| 1881 | } | 1600 | } |
| 1882 | 1601 | ||
| @@ -1889,327 +1608,6 @@ xd_read_queued_messages (int fd, void *data, int for_read) | |||
| 1889 | xd_in_read_queued_messages = 0; | 1608 | xd_in_read_queued_messages = 0; |
| 1890 | } | 1609 | } |
| 1891 | 1610 | ||
| 1892 | DEFUN ("dbus-register-service", Fdbus_register_service, Sdbus_register_service, | ||
| 1893 | 2, MANY, 0, | ||
| 1894 | doc: /* Register known name SERVICE on the D-Bus BUS. | ||
| 1895 | |||
| 1896 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 1897 | denoting the bus address. | ||
| 1898 | |||
| 1899 | SERVICE is the D-Bus service name that should be registered. It must | ||
| 1900 | be a known name. | ||
| 1901 | |||
| 1902 | FLAGS are keywords, which control how the service name is registered. | ||
| 1903 | The following keywords are recognized: | ||
| 1904 | |||
| 1905 | `:allow-replacement': Allow another service to become the primary | ||
| 1906 | owner if requested. | ||
| 1907 | |||
| 1908 | `:replace-existing': Request to replace the current primary owner. | ||
| 1909 | |||
| 1910 | `:do-not-queue': If we can not become the primary owner do not place | ||
| 1911 | us in the queue. | ||
| 1912 | |||
| 1913 | The function returns a keyword, indicating the result of the | ||
| 1914 | operation. One of the following keywords is returned: | ||
| 1915 | |||
| 1916 | `:primary-owner': Service has become the primary owner of the | ||
| 1917 | requested name. | ||
| 1918 | |||
| 1919 | `:in-queue': Service could not become the primary owner and has been | ||
| 1920 | placed in the queue. | ||
| 1921 | |||
| 1922 | `:exists': Service is already in the queue. | ||
| 1923 | |||
| 1924 | `:already-owner': Service is already the primary owner. | ||
| 1925 | |||
| 1926 | Example: | ||
| 1927 | |||
| 1928 | \(dbus-register-service :session dbus-service-emacs) | ||
| 1929 | |||
| 1930 | => :primary-owner. | ||
| 1931 | |||
| 1932 | \(dbus-register-service | ||
| 1933 | :session "org.freedesktop.TextEditor" | ||
| 1934 | dbus-service-allow-replacement dbus-service-replace-existing) | ||
| 1935 | |||
| 1936 | => :already-owner. | ||
| 1937 | |||
| 1938 | usage: (dbus-register-service BUS SERVICE &rest FLAGS) */) | ||
| 1939 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 1940 | { | ||
| 1941 | Lisp_Object bus, service; | ||
| 1942 | DBusConnection *connection; | ||
| 1943 | ptrdiff_t i; | ||
| 1944 | unsigned int value; | ||
| 1945 | unsigned int flags = 0; | ||
| 1946 | int result; | ||
| 1947 | DBusError derror; | ||
| 1948 | |||
| 1949 | bus = args[0]; | ||
| 1950 | service = args[1]; | ||
| 1951 | |||
| 1952 | /* Check parameters. */ | ||
| 1953 | CHECK_STRING (service); | ||
| 1954 | |||
| 1955 | /* Process flags. */ | ||
| 1956 | for (i = 2; i < nargs; ++i) { | ||
| 1957 | value = ((EQ (args[i], QCdbus_request_name_replace_existing)) | ||
| 1958 | ? DBUS_NAME_FLAG_REPLACE_EXISTING | ||
| 1959 | : (EQ (args[i], QCdbus_request_name_allow_replacement)) | ||
| 1960 | ? DBUS_NAME_FLAG_ALLOW_REPLACEMENT | ||
| 1961 | : (EQ (args[i], QCdbus_request_name_do_not_queue)) | ||
| 1962 | ? DBUS_NAME_FLAG_DO_NOT_QUEUE | ||
| 1963 | : -1); | ||
| 1964 | if (value == -1) | ||
| 1965 | XD_SIGNAL2 (build_string ("Unrecognized name request flag"), args[i]); | ||
| 1966 | flags |= value; | ||
| 1967 | } | ||
| 1968 | |||
| 1969 | /* Open a connection to the bus. */ | ||
| 1970 | connection = xd_initialize (bus, TRUE); | ||
| 1971 | |||
| 1972 | /* Request the known name from the bus. */ | ||
| 1973 | dbus_error_init (&derror); | ||
| 1974 | result = dbus_bus_request_name (connection, SSDATA (service), flags, | ||
| 1975 | &derror); | ||
| 1976 | if (dbus_error_is_set (&derror)) | ||
| 1977 | XD_ERROR (derror); | ||
| 1978 | |||
| 1979 | /* Cleanup. */ | ||
| 1980 | dbus_error_free (&derror); | ||
| 1981 | |||
| 1982 | /* Return object. */ | ||
| 1983 | switch (result) | ||
| 1984 | { | ||
| 1985 | case DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER: | ||
| 1986 | return QCdbus_request_name_reply_primary_owner; | ||
| 1987 | case DBUS_REQUEST_NAME_REPLY_IN_QUEUE: | ||
| 1988 | return QCdbus_request_name_reply_in_queue; | ||
| 1989 | case DBUS_REQUEST_NAME_REPLY_EXISTS: | ||
| 1990 | return QCdbus_request_name_reply_exists; | ||
| 1991 | case DBUS_REQUEST_NAME_REPLY_ALREADY_OWNER: | ||
| 1992 | return QCdbus_request_name_reply_already_owner; | ||
| 1993 | default: | ||
| 1994 | /* This should not happen. */ | ||
| 1995 | XD_SIGNAL2 (build_string ("Could not register service"), service); | ||
| 1996 | } | ||
| 1997 | } | ||
| 1998 | |||
| 1999 | DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal, | ||
| 2000 | 6, MANY, 0, | ||
| 2001 | doc: /* Register for signal SIGNAL on the D-Bus BUS. | ||
| 2002 | |||
| 2003 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 2004 | denoting the bus address. | ||
| 2005 | |||
| 2006 | SERVICE is the D-Bus service name used by the sending D-Bus object. | ||
| 2007 | It can be either a known name or the unique name of the D-Bus object | ||
| 2008 | sending the signal. When SERVICE is nil, related signals from all | ||
| 2009 | D-Bus objects shall be accepted. | ||
| 2010 | |||
| 2011 | PATH is the D-Bus object path SERVICE is registered. It can also be | ||
| 2012 | nil if the path name of incoming signals shall not be checked. | ||
| 2013 | |||
| 2014 | INTERFACE is an interface offered by SERVICE. It must provide SIGNAL. | ||
| 2015 | HANDLER is a Lisp function to be called when the signal is received. | ||
| 2016 | It must accept as arguments the values SIGNAL is sending. | ||
| 2017 | |||
| 2018 | All other arguments ARGS, if specified, must be strings. They stand | ||
| 2019 | for the respective arguments of the signal in their order, and are | ||
| 2020 | used for filtering as well. A nil argument might be used to preserve | ||
| 2021 | the order. | ||
| 2022 | |||
| 2023 | INTERFACE, SIGNAL and HANDLER must not be nil. Example: | ||
| 2024 | |||
| 2025 | \(defun my-signal-handler (device) | ||
| 2026 | (message "Device %s added" device)) | ||
| 2027 | |||
| 2028 | \(dbus-register-signal | ||
| 2029 | :system "org.freedesktop.Hal" "/org/freedesktop/Hal/Manager" | ||
| 2030 | "org.freedesktop.Hal.Manager" "DeviceAdded" 'my-signal-handler) | ||
| 2031 | |||
| 2032 | => ((:system "org.freedesktop.Hal.Manager" "DeviceAdded") | ||
| 2033 | ("org.freedesktop.Hal" "/org/freedesktop/Hal/Manager" my-signal-handler)) | ||
| 2034 | |||
| 2035 | `dbus-register-signal' returns an object, which can be used in | ||
| 2036 | `dbus-unregister-object' for removing the registration. | ||
| 2037 | |||
| 2038 | usage: (dbus-register-signal BUS SERVICE PATH INTERFACE SIGNAL HANDLER &rest ARGS) */) | ||
| 2039 | (ptrdiff_t nargs, Lisp_Object *args) | ||
| 2040 | { | ||
| 2041 | Lisp_Object bus, service, path, interface, signal, handler; | ||
| 2042 | struct gcpro gcpro1, gcpro2, gcpro3, gcpro4, gcpro5, gcpro6; | ||
| 2043 | Lisp_Object uname, key, key1, value; | ||
| 2044 | DBusConnection *connection; | ||
| 2045 | ptrdiff_t i; | ||
| 2046 | char rule[DBUS_MAXIMUM_MATCH_RULE_LENGTH]; | ||
| 2047 | int rulelen; | ||
| 2048 | DBusError derror; | ||
| 2049 | |||
| 2050 | /* Check parameters. */ | ||
| 2051 | bus = args[0]; | ||
| 2052 | service = args[1]; | ||
| 2053 | path = args[2]; | ||
| 2054 | interface = args[3]; | ||
| 2055 | signal = args[4]; | ||
| 2056 | handler = args[5]; | ||
| 2057 | |||
| 2058 | if (!NILP (service)) CHECK_STRING (service); | ||
| 2059 | if (!NILP (path)) CHECK_STRING (path); | ||
| 2060 | CHECK_STRING (interface); | ||
| 2061 | CHECK_STRING (signal); | ||
| 2062 | if (!FUNCTIONP (handler)) | ||
| 2063 | wrong_type_argument (Qinvalid_function, handler); | ||
| 2064 | GCPRO6 (bus, service, path, interface, signal, handler); | ||
| 2065 | |||
| 2066 | /* Retrieve unique name of service. If service is a known name, we | ||
| 2067 | will register for the corresponding unique name, if any. Signals | ||
| 2068 | are sent always with the unique name as sender. Note: the unique | ||
| 2069 | name of "org.freedesktop.DBus" is that string itself. */ | ||
| 2070 | if ((STRINGP (service)) | ||
| 2071 | && (SBYTES (service) > 0) | ||
| 2072 | && (strcmp (SSDATA (service), DBUS_SERVICE_DBUS) != 0) | ||
| 2073 | && (strncmp (SSDATA (service), ":", 1) != 0)) | ||
| 2074 | uname = call2 (intern ("dbus-get-name-owner"), bus, service); | ||
| 2075 | else | ||
| 2076 | uname = service; | ||
| 2077 | |||
| 2078 | /* Create a matching rule if the unique name exists (when no | ||
| 2079 | wildcard). */ | ||
| 2080 | if (NILP (uname) || (SBYTES (uname) > 0)) | ||
| 2081 | { | ||
| 2082 | /* Open a connection to the bus. */ | ||
| 2083 | connection = xd_initialize (bus, TRUE); | ||
| 2084 | |||
| 2085 | /* Create a rule to receive related signals. */ | ||
| 2086 | rulelen = snprintf (rule, sizeof rule, | ||
| 2087 | "type='signal',interface='%s',member='%s'", | ||
| 2088 | SDATA (interface), | ||
| 2089 | SDATA (signal)); | ||
| 2090 | if (! (0 <= rulelen && rulelen < sizeof rule)) | ||
| 2091 | string_overflow (); | ||
| 2092 | |||
| 2093 | /* Add unique name and path to the rule if they are non-nil. */ | ||
| 2094 | if (!NILP (uname)) | ||
| 2095 | { | ||
| 2096 | int len = snprintf (rule + rulelen, sizeof rule - rulelen, | ||
| 2097 | ",sender='%s'", SDATA (uname)); | ||
| 2098 | if (! (0 <= len && len < sizeof rule - rulelen)) | ||
| 2099 | string_overflow (); | ||
| 2100 | rulelen += len; | ||
| 2101 | } | ||
| 2102 | |||
| 2103 | if (!NILP (path)) | ||
| 2104 | { | ||
| 2105 | int len = snprintf (rule + rulelen, sizeof rule - rulelen, | ||
| 2106 | ",path='%s'", SDATA (path)); | ||
| 2107 | if (! (0 <= len && len < sizeof rule - rulelen)) | ||
| 2108 | string_overflow (); | ||
| 2109 | rulelen += len; | ||
| 2110 | } | ||
| 2111 | |||
| 2112 | /* Add arguments to the rule if they are non-nil. */ | ||
| 2113 | for (i = 6; i < nargs; ++i) | ||
| 2114 | if (!NILP (args[i])) | ||
| 2115 | { | ||
| 2116 | int len; | ||
| 2117 | CHECK_STRING (args[i]); | ||
| 2118 | len = snprintf (rule + rulelen, sizeof rule - rulelen, | ||
| 2119 | ",arg%"pD"d='%s'", i - 6, SDATA (args[i])); | ||
| 2120 | if (! (0 <= len && len < sizeof rule - rulelen)) | ||
| 2121 | string_overflow (); | ||
| 2122 | rulelen += len; | ||
| 2123 | } | ||
| 2124 | |||
| 2125 | /* Add the rule to the bus. */ | ||
| 2126 | dbus_error_init (&derror); | ||
| 2127 | dbus_bus_add_match (connection, rule, &derror); | ||
| 2128 | if (dbus_error_is_set (&derror)) | ||
| 2129 | { | ||
| 2130 | UNGCPRO; | ||
| 2131 | XD_ERROR (derror); | ||
| 2132 | } | ||
| 2133 | |||
| 2134 | /* Cleanup. */ | ||
| 2135 | dbus_error_free (&derror); | ||
| 2136 | |||
| 2137 | XD_DEBUG_MESSAGE ("Matching rule \"%s\" created", rule); | ||
| 2138 | } | ||
| 2139 | |||
| 2140 | /* Create a hash table entry. */ | ||
| 2141 | key = list3 (bus, interface, signal); | ||
| 2142 | key1 = list5 (uname, service, path, handler, build_string (rule)); | ||
| 2143 | value = Fgethash (key, Vdbus_registered_objects_table, Qnil); | ||
| 2144 | |||
| 2145 | if (NILP (Fmember (key1, value))) | ||
| 2146 | Fputhash (key, Fcons (key1, value), Vdbus_registered_objects_table); | ||
| 2147 | |||
| 2148 | /* Return object. */ | ||
| 2149 | RETURN_UNGCPRO (list2 (key, list3 (service, path, handler))); | ||
| 2150 | } | ||
| 2151 | |||
| 2152 | DEFUN ("dbus-register-method", Fdbus_register_method, Sdbus_register_method, | ||
| 2153 | 6, 7, 0, | ||
| 2154 | doc: /* Register for method METHOD on the D-Bus BUS. | ||
| 2155 | |||
| 2156 | BUS is either a Lisp symbol, `:system' or `:session', or a string | ||
| 2157 | denoting the bus address. | ||
| 2158 | |||
| 2159 | SERVICE is the D-Bus service name of the D-Bus object METHOD is | ||
| 2160 | registered for. It must be a known name (See discussion of | ||
| 2161 | DONT-REGISTER-SERVICE below). | ||
| 2162 | |||
| 2163 | PATH is the D-Bus object path SERVICE is registered (See discussion of | ||
| 2164 | DONT-REGISTER-SERVICE below). INTERFACE is the interface offered by | ||
| 2165 | SERVICE. It must provide METHOD. | ||
| 2166 | |||
| 2167 | HANDLER is a Lisp function to be called when a method call is | ||
| 2168 | received. It must accept the input arguments of METHOD. The return | ||
| 2169 | value of HANDLER is used for composing the returning D-Bus message. | ||
| 2170 | In case HANDLER shall return a reply message with an empty argument | ||
| 2171 | list, HANDLER must return the symbol `:ignore'. | ||
| 2172 | |||
| 2173 | When DONT-REGISTER-SERVICE is non-nil, the known name SERVICE is not | ||
| 2174 | registered. This means that other D-Bus clients have no way of | ||
| 2175 | noticing the newly registered method. When interfaces are constructed | ||
| 2176 | incrementally by adding single methods or properties at a time, | ||
| 2177 | DONT-REGISTER-SERVICE can be used to prevent other clients from | ||
| 2178 | discovering the still incomplete interface.*/) | ||
| 2179 | (Lisp_Object bus, Lisp_Object service, Lisp_Object path, | ||
| 2180 | Lisp_Object interface, Lisp_Object method, Lisp_Object handler, | ||
| 2181 | Lisp_Object dont_register_service) | ||
| 2182 | { | ||
| 2183 | Lisp_Object key, key1, value; | ||
| 2184 | Lisp_Object args[2] = { bus, service }; | ||
| 2185 | |||
| 2186 | /* Check parameters. */ | ||
| 2187 | CHECK_STRING (service); | ||
| 2188 | CHECK_STRING (path); | ||
| 2189 | CHECK_STRING (interface); | ||
| 2190 | CHECK_STRING (method); | ||
| 2191 | if (!FUNCTIONP (handler)) | ||
| 2192 | wrong_type_argument (Qinvalid_function, handler); | ||
| 2193 | /* TODO: We must check for a valid service name, otherwise there is | ||
| 2194 | a segmentation fault. */ | ||
| 2195 | |||
| 2196 | /* Request the name. */ | ||
| 2197 | if (NILP (dont_register_service)) | ||
| 2198 | Fdbus_register_service (2, args); | ||
| 2199 | |||
| 2200 | /* Create a hash table entry. We use nil for the unique name, | ||
| 2201 | because the method might be called from anybody. */ | ||
| 2202 | key = list3 (bus, interface, method); | ||
| 2203 | key1 = list4 (Qnil, service, path, handler); | ||
| 2204 | value = Fgethash (key, Vdbus_registered_objects_table, Qnil); | ||
| 2205 | |||
| 2206 | if (NILP (Fmember (key1, value))) | ||
| 2207 | Fputhash (key, Fcons (key1, value), Vdbus_registered_objects_table); | ||
| 2208 | |||
| 2209 | /* Return object. */ | ||
| 2210 | return list2 (key, list3 (service, path, handler)); | ||
| 2211 | } | ||
| 2212 | |||
| 2213 | 1611 | ||
| 2214 | void | 1612 | void |
| 2215 | syms_of_dbusbind (void) | 1613 | syms_of_dbusbind (void) |
| @@ -2218,35 +1616,11 @@ syms_of_dbusbind (void) | |||
| 2218 | DEFSYM (Qdbus_init_bus, "dbus-init-bus"); | 1616 | DEFSYM (Qdbus_init_bus, "dbus-init-bus"); |
| 2219 | defsubr (&Sdbus_init_bus); | 1617 | defsubr (&Sdbus_init_bus); |
| 2220 | 1618 | ||
| 2221 | DEFSYM (Qdbus_close_bus, "dbus-close-bus"); | ||
| 2222 | defsubr (&Sdbus_close_bus); | ||
| 2223 | |||
| 2224 | DEFSYM (Qdbus_get_unique_name, "dbus-get-unique-name"); | 1619 | DEFSYM (Qdbus_get_unique_name, "dbus-get-unique-name"); |
| 2225 | defsubr (&Sdbus_get_unique_name); | 1620 | defsubr (&Sdbus_get_unique_name); |
| 2226 | 1621 | ||
| 2227 | DEFSYM (Qdbus_call_method, "dbus-call-method"); | 1622 | DEFSYM (Qdbus_message_internal, "dbus-message-internal"); |
| 2228 | defsubr (&Sdbus_call_method); | 1623 | defsubr (&Sdbus_message_internal); |
| 2229 | |||
| 2230 | DEFSYM (Qdbus_call_method_asynchronously, "dbus-call-method-asynchronously"); | ||
| 2231 | defsubr (&Sdbus_call_method_asynchronously); | ||
| 2232 | |||
| 2233 | DEFSYM (Qdbus_method_return_internal, "dbus-method-return-internal"); | ||
| 2234 | defsubr (&Sdbus_method_return_internal); | ||
| 2235 | |||
| 2236 | DEFSYM (Qdbus_method_error_internal, "dbus-method-error-internal"); | ||
| 2237 | defsubr (&Sdbus_method_error_internal); | ||
| 2238 | |||
| 2239 | DEFSYM (Qdbus_send_signal, "dbus-send-signal"); | ||
| 2240 | defsubr (&Sdbus_send_signal); | ||
| 2241 | |||
| 2242 | DEFSYM (Qdbus_register_service, "dbus-register-service"); | ||
| 2243 | defsubr (&Sdbus_register_service); | ||
| 2244 | |||
| 2245 | DEFSYM (Qdbus_register_signal, "dbus-register-signal"); | ||
| 2246 | defsubr (&Sdbus_register_signal); | ||
| 2247 | |||
| 2248 | DEFSYM (Qdbus_register_method, "dbus-register-method"); | ||
| 2249 | defsubr (&Sdbus_register_method); | ||
| 2250 | 1624 | ||
| 2251 | DEFSYM (Qdbus_error, "dbus-error"); | 1625 | DEFSYM (Qdbus_error, "dbus-error"); |
| 2252 | Fput (Qdbus_error, Qerror_conditions, | 1626 | Fput (Qdbus_error, Qerror_conditions, |
| @@ -2256,13 +1630,6 @@ syms_of_dbusbind (void) | |||
| 2256 | 1630 | ||
| 2257 | DEFSYM (QCdbus_system_bus, ":system"); | 1631 | DEFSYM (QCdbus_system_bus, ":system"); |
| 2258 | DEFSYM (QCdbus_session_bus, ":session"); | 1632 | DEFSYM (QCdbus_session_bus, ":session"); |
| 2259 | DEFSYM (QCdbus_request_name_allow_replacement, ":allow-replacement"); | ||
| 2260 | DEFSYM (QCdbus_request_name_replace_existing, ":replace-existing"); | ||
| 2261 | DEFSYM (QCdbus_request_name_do_not_queue, ":do-not-queue"); | ||
| 2262 | DEFSYM (QCdbus_request_name_reply_primary_owner, ":primary-owner"); | ||
| 2263 | DEFSYM (QCdbus_request_name_reply_exists, ":exists"); | ||
| 2264 | DEFSYM (QCdbus_request_name_reply_in_queue, ":in-queue"); | ||
| 2265 | DEFSYM (QCdbus_request_name_reply_already_owner, ":already-owner"); | ||
| 2266 | DEFSYM (QCdbus_timeout, ":timeout"); | 1633 | DEFSYM (QCdbus_timeout, ":timeout"); |
| 2267 | DEFSYM (QCdbus_type_byte, ":byte"); | 1634 | DEFSYM (QCdbus_type_byte, ":byte"); |
| 2268 | DEFSYM (QCdbus_type_boolean, ":boolean"); | 1635 | DEFSYM (QCdbus_type_boolean, ":boolean"); |
| @@ -2276,19 +1643,73 @@ syms_of_dbusbind (void) | |||
| 2276 | DEFSYM (QCdbus_type_string, ":string"); | 1643 | DEFSYM (QCdbus_type_string, ":string"); |
| 2277 | DEFSYM (QCdbus_type_object_path, ":object-path"); | 1644 | DEFSYM (QCdbus_type_object_path, ":object-path"); |
| 2278 | DEFSYM (QCdbus_type_signature, ":signature"); | 1645 | DEFSYM (QCdbus_type_signature, ":signature"); |
| 2279 | |||
| 2280 | #ifdef DBUS_TYPE_UNIX_FD | 1646 | #ifdef DBUS_TYPE_UNIX_FD |
| 2281 | DEFSYM (QCdbus_type_unix_fd, ":unix-fd"); | 1647 | DEFSYM (QCdbus_type_unix_fd, ":unix-fd"); |
| 2282 | #endif | 1648 | #endif |
| 2283 | |||
| 2284 | DEFSYM (QCdbus_type_array, ":array"); | 1649 | DEFSYM (QCdbus_type_array, ":array"); |
| 2285 | DEFSYM (QCdbus_type_variant, ":variant"); | 1650 | DEFSYM (QCdbus_type_variant, ":variant"); |
| 2286 | DEFSYM (QCdbus_type_struct, ":struct"); | 1651 | DEFSYM (QCdbus_type_struct, ":struct"); |
| 2287 | DEFSYM (QCdbus_type_dict_entry, ":dict-entry"); | 1652 | DEFSYM (QCdbus_type_dict_entry, ":dict-entry"); |
| 1653 | DEFSYM (QCdbus_registered_serial, ":serial"); | ||
| 1654 | DEFSYM (QCdbus_registered_method, ":method"); | ||
| 1655 | DEFSYM (QCdbus_registered_signal, ":signal"); | ||
| 1656 | |||
| 1657 | DEFVAR_LISP ("dbus-compiled-version", | ||
| 1658 | Vdbus_compiled_version, | ||
| 1659 | doc: /* The version of D-Bus Emacs is compiled against. */); | ||
| 1660 | #ifdef DBUS_VERSION_STRING | ||
| 1661 | Vdbus_compiled_version = make_pure_c_string (DBUS_VERSION_STRING); | ||
| 1662 | #else | ||
| 1663 | Vdbus_compiled_version = Qnil; | ||
| 1664 | #endif | ||
| 1665 | |||
| 1666 | DEFVAR_LISP ("dbus-runtime-version", | ||
| 1667 | Vdbus_runtime_version, | ||
| 1668 | doc: /* The version of D-Bus Emacs runs with. */); | ||
| 1669 | { | ||
| 1670 | #ifdef DBUS_VERSION | ||
| 1671 | int major, minor, micro; | ||
| 1672 | char s[1024]; | ||
| 1673 | dbus_get_version (&major, &minor, µ); | ||
| 1674 | snprintf (s, sizeof s, "%d.%d.%d", major, minor, micro); | ||
| 1675 | Vdbus_runtime_version = make_string (s, strlen (s)); | ||
| 1676 | #else | ||
| 1677 | Vdbus_runtime_version = Qnil; | ||
| 1678 | #endif | ||
| 1679 | } | ||
| 1680 | |||
| 1681 | DEFVAR_LISP ("dbus-message-type-invalid", | ||
| 1682 | Vdbus_message_type_invalid, | ||
| 1683 | doc: /* This value is never a valid message type. */); | ||
| 1684 | Vdbus_message_type_invalid = make_number (DBUS_MESSAGE_TYPE_INVALID); | ||
| 1685 | |||
| 1686 | DEFVAR_LISP ("dbus-message-type-method-call", | ||
| 1687 | Vdbus_message_type_method_call, | ||
| 1688 | doc: /* Message type of a method call message. */); | ||
| 1689 | Vdbus_message_type_method_call = make_number (DBUS_MESSAGE_TYPE_METHOD_CALL); | ||
| 1690 | |||
| 1691 | DEFVAR_LISP ("dbus-message-type-method-return", | ||
| 1692 | Vdbus_message_type_method_return, | ||
| 1693 | doc: /* Message type of a method return message. */); | ||
| 1694 | Vdbus_message_type_method_return | ||
| 1695 | = make_number (DBUS_MESSAGE_TYPE_METHOD_RETURN); | ||
| 1696 | |||
| 1697 | DEFVAR_LISP ("dbus-message-type-error", | ||
| 1698 | Vdbus_message_type_error, | ||
| 1699 | doc: /* Message type of an error reply message. */); | ||
| 1700 | Vdbus_message_type_error = make_number (DBUS_MESSAGE_TYPE_ERROR); | ||
| 1701 | |||
| 1702 | DEFVAR_LISP ("dbus-message-type-signal", | ||
| 1703 | Vdbus_message_type_signal, | ||
| 1704 | doc: /* Message type of a signal message. */); | ||
| 1705 | Vdbus_message_type_signal = make_number (DBUS_MESSAGE_TYPE_SIGNAL); | ||
| 2288 | 1706 | ||
| 2289 | DEFVAR_LISP ("dbus-registered-buses", | 1707 | DEFVAR_LISP ("dbus-registered-buses", |
| 2290 | Vdbus_registered_buses, | 1708 | Vdbus_registered_buses, |
| 2291 | doc: /* List of D-Bus buses we are polling for messages. */); | 1709 | doc: /* Alist of D-Bus buses we are polling for messages. |
| 1710 | |||
| 1711 | The key is the symbol or string of the bus, and the value is the | ||
| 1712 | connection address. */); | ||
| 2292 | Vdbus_registered_buses = Qnil; | 1713 | Vdbus_registered_buses = Qnil; |
| 2293 | 1714 | ||
| 2294 | DEFVAR_LISP ("dbus-registered-objects-table", | 1715 | DEFVAR_LISP ("dbus-registered-objects-table", |
| @@ -2299,27 +1720,28 @@ There are two different uses of the hash table: for accessing | |||
| 2299 | registered interfaces properties, targeted by signals or method calls, | 1720 | registered interfaces properties, targeted by signals or method calls, |
| 2300 | and for calling handlers in case of non-blocking method call returns. | 1721 | and for calling handlers in case of non-blocking method call returns. |
| 2301 | 1722 | ||
| 2302 | In the first case, the key in the hash table is the list (BUS | 1723 | In the first case, the key in the hash table is the list (TYPE BUS |
| 2303 | INTERFACE MEMBER). BUS is either a Lisp symbol, `:system' or | 1724 | INTERFACE MEMBER). TYPE is one of the Lisp symbols `:method', |
| 1725 | `:signal' or `:property'. BUS is either a Lisp symbol, `:system' or | ||
| 2304 | `:session', or a string denoting the bus address. INTERFACE is a | 1726 | `:session', or a string denoting the bus address. INTERFACE is a |
| 2305 | string which denotes a D-Bus interface, and MEMBER, also a string, is | 1727 | string which denotes a D-Bus interface, and MEMBER, also a string, is |
| 2306 | either a method, a signal or a property INTERFACE is offering. All | 1728 | either a method, a signal or a property INTERFACE is offering. All |
| 2307 | arguments but BUS must not be nil. | 1729 | arguments but BUS must not be nil. |
| 2308 | 1730 | ||
| 2309 | The value in the hash table is a list of quadruple lists | 1731 | The value in the hash table is a list of quadruple lists \((UNAME |
| 2310 | \((UNAME SERVICE PATH OBJECT) (UNAME SERVICE PATH OBJECT) ...). | 1732 | SERVICE PATH OBJECT [RULE]) ...). SERVICE is the service name as |
| 2311 | SERVICE is the service name as registered, UNAME is the corresponding | 1733 | registered, UNAME is the corresponding unique name. In case of |
| 2312 | unique name. In case of registered methods and properties, UNAME is | 1734 | registered methods and properties, UNAME is nil. PATH is the object |
| 2313 | nil. PATH is the object path of the sending object. All of them can | 1735 | path of the sending object. All of them can be nil, which means a |
| 2314 | be nil, which means a wildcard then. OBJECT is either the handler to | 1736 | wildcard then. OBJECT is either the handler to be called when a D-Bus |
| 2315 | be called when a D-Bus message, which matches the key criteria, | 1737 | message, which matches the key criteria, arrives (TYPE `:method' and |
| 2316 | arrives (methods and signals), or a cons cell containing the value of | 1738 | `:signal'), or a cons cell containing the value of the property (TYPE |
| 2317 | the property. | 1739 | `:property'). |
| 2318 | 1740 | ||
| 2319 | For signals, there is also a fifth element RULE, which keeps the match | 1741 | For entries of type `:signal', there is also a fifth element RULE, |
| 2320 | string the signal is registered with. | 1742 | which keeps the match string the signal is registered with. |
| 2321 | 1743 | ||
| 2322 | In the second case, the key in the hash table is the list (BUS | 1744 | In the second case, the key in the hash table is the list (:serial BUS |
| 2323 | SERIAL). BUS is either a Lisp symbol, `:system' or `:session', or a | 1745 | SERIAL). BUS is either a Lisp symbol, `:system' or `:session', or a |
| 2324 | string denoting the bus address. SERIAL is the serial number of the | 1746 | string denoting the bus address. SERIAL is the serial number of the |
| 2325 | non-blocking method call, a reply is expected. Both arguments must | 1747 | non-blocking method call, a reply is expected. Both arguments must |