changeset 97167:125ed717ddbb

* net/dbus.el (top): Don't register for "NameOwnerChanged". (dbus-message-type-invalid, dbus-message-type-method-call) (dbus-message-type-method-return, dbus-message-type-error) (dbus-message-type-signal): New defconst. (dbus-ignore-errors): Fix `edebug-form-spec' property. (dbus-return-values-table): New defvar. (dbus-call-method-non-blocking-handler, dbus-event-message-type): New defun. (dbus-check-event, dbus-handle-event, dbus-event-serial-number, ): Extend docstring. Adapt implementation according to new `dbus-event' layout. (dbus-event-service-name, dbus-event-path-name) (dbus-event-interface-name, dbus-event-member-name): Adapt implementation according to new `dbus-event' layout. (dbus-set-property): Correct `dbus-introspect-get-attribute' call.
author Michael Albinus <michael.albinus@gmx.de>
date Thu, 31 Jul 2008 19:25:00 +0000
parents 23dda5132c33
children 3940e23d0099
files lisp/net/dbus.el
diffstat 1 files changed, 124 insertions(+), 41 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/net/dbus.el	Thu Jul 31 18:56:51 2008 +0000
+++ b/lisp/net/dbus.el	Thu Jul 31 19:25:00 2008 +0000
@@ -62,6 +62,21 @@
 (defconst dbus-interface-properties (concat dbus-interface-dbus ".Properties")
   "The interface for property objects.")
 
+(defconst dbus-message-type-invalid 0
+  "This value is never a valid message type.")
+
+(defconst dbus-message-type-method-call 1
+  "Message type of a method call message.")
+
+(defconst dbus-message-type-method-return 2
+  "Message type of a method return message.")
+
+(defconst dbus-message-type-error 3
+  "Message type of an error reply message.")
+
+(defconst dbus-message-type-signal 4
+  "Message type of a signal message.")
+
 (defmacro dbus-ignore-errors (&rest body)
   "Execute BODY; signal D-Bus error when `dbus-debug' is non-nil.
 Otherwise, return result of last form in BODY, or all other errors."
@@ -70,7 +85,7 @@
      (dbus-error (when dbus-debug (signal (car err) (cdr err))))))
 
 (put 'dbus-ignore-errors 'lisp-indent-function 0)
-(put 'dbus-ignore-errors 'edebug-form-spec '(form symbolp body))
+(put 'dbus-ignore-errors 'edebug-form-spec '(form body))
 (font-lock-add-keywords 'emacs-lisp-mode '("\\<dbus-ignore-errors\\>"))
 
 
@@ -80,6 +95,13 @@
 ;; the Lisp code has been loaded.
 (setq dbus-registered-functions-table (make-hash-table :test 'equal))
 
+(defvar dbus-return-values-table (make-hash-table :test 'equal)
+  "Hash table for temporary storing arguments of reply messages.
+A key in this hash table is a list (BUS SERIAL).  BUS is either the
+symbol `:system' or the symbol `:session'.  SERIAL is the serial number
+of the reply message.  See `dbus-call-method-non-blocking-handler' and
+`dbus-call-method-non-blocking'.")
+
 (defun dbus-list-hash-table ()
   "Returns all registered member registrations to D-Bus.
 The return value is a list, with elements of kind (KEY . VALUE).
@@ -120,6 +142,42 @@
 	(setq value t)))
     value))
 
+(defun dbus-call-method-non-blocking-handler (&rest args)
+  "Handler for reply messages of asynchronous D-Bus message calls.
+It calls the function stored in `dbus-registered-functions-table'.
+The result will be made available in `dbus-return-values-table'."
+  (puthash (list (dbus-event-bus-name last-input-event)
+		 (dbus-event-serial-number last-input-event))
+	   (if (= (length args) 1) (car args) args)
+	   dbus-return-values-table))
+
+(defun dbus-call-method-non-blocking
+  (bus service path interface method &rest args)
+  "Call METHOD on the D-Bus BUS, but don't block the event queue.
+This is necessary for communicating to registered D-Bus methods,
+which are running in the same Emacs process.
+
+The arguments are the same as in `dbus-call-method'.
+
+usage: (dbus-call-method-non-blocking
+         BUS SERVICE PATH INTERFACE METHOD
+         &optional :timeout TIMEOUT &rest ARGS)"
+
+  (let ((key
+	 (apply
+	  'dbus-call-method-asynchronously
+	  bus service path interface method
+	  'dbus-call-method-non-blocking-handler args)))
+    ;; Wait until `dbus-call-method-non-blocking-handler' has put the
+    ;; result into `dbus-return-values-table'.
+    (while (not (gethash key dbus-return-values-table nil))
+      (read-event nil nil 0.1))
+
+    ;; Cleanup `dbus-return-values-table'.  Return the result.
+    (prog1
+	(gethash key dbus-return-values-table nil)
+      (remhash key dbus-return-values-table))))
+
 (defun dbus-name-owner-changed-handler (&rest args)
   "Reapplies all member registrations to D-Bus.
 This handler is applied when a \"NameOwnerChanged\" signal has
@@ -166,7 +224,7 @@
 	  args))))))
 
 ;; Register the handler.
-(ignore-errors
+(when nil ;ignore-errors
   (dbus-register-signal
    :system dbus-service-dbus dbus-path-dbus dbus-interface-dbus
    "NameOwnerChanged" 'dbus-name-owner-changed-handler)
@@ -181,17 +239,18 @@
   "Checks whether EVENT is a well formed D-Bus event.
 EVENT is a list which starts with symbol `dbus-event':
 
-     (dbus-event BUS SERIAL SERVICE PATH INTERFACE MEMBER HANDLER &rest ARGS)
+  (dbus-event BUS TYPE SERIAL SERVICE PATH INTERFACE MEMBER HANDLER &rest ARGS)
 
 BUS identifies the D-Bus the message is coming from.  It is
-either the symbol `:system' or the symbol `:session'.  SERIAL is
-the serial number of the received D-Bus message if it is a method
-call, or `nil'.  SERVICE and PATH are the unique name and the
-object path of the D-Bus object emitting the message.  INTERFACE
-and MEMBER denote the message which has been sent.  HANDLER is
-the function which has been registered for this message.  ARGS
-are the arguments passed to HANDLER, when it is called during
-event handling in `dbus-handle-event'.
+either the symbol `:system' or the symbol `:session'.  TYPE is
+the D-Bus message type which has caused the event, SERIAL is the
+serial number of the received D-Bus message.  SERVICE and PATH
+are the unique name and the object path of the D-Bus object
+emitting the message.  INTERFACE and MEMBER denote the message
+which has been sent.  HANDLER is the function which has been
+registered for this message.  ARGS are the arguments passed to
+HANDLER, when it is called during event handling in
+`dbus-handle-event'.
 
 This function raises a `dbus-error' signal in case the event is
 not well formed."
@@ -200,37 +259,54 @@
 	       (eq (car event) 'dbus-event)
 	       ;; Bus symbol.
 	       (symbolp (nth 1 event))
+	       ;; Type.
+	       (and (natnump (nth 2 event))
+		    (< dbus-message-type-invalid (nth 2 event)))
 	       ;; Serial.
-	       (or (natnump (nth 2 event)) (null (nth 2 event)))
+	       (natnump (nth 3 event))
 	       ;; Service.
-	       (stringp (nth 3 event))
+	       (or (= dbus-message-type-method-return (nth 2 event))
+		   (stringp (nth 4 event)))
 	       ;; Object path.
-	       (stringp (nth 4 event))
+	       (or (= dbus-message-type-method-return (nth 2 event))
+		   (stringp (nth 5 event)))
 	       ;; Interface.
-	       (stringp (nth 5 event))
+	       (or (= dbus-message-type-method-return (nth 2 event))
+		   (stringp (nth 6 event)))
 	       ;; Member.
-	       (stringp (nth 6 event))
+	       (or (= dbus-message-type-method-return (nth 2 event))
+		   (stringp (nth 7 event)))
 	       ;; Handler.
-	       (functionp (nth 7 event)))
+	       (functionp (nth 8 event)))
     (signal 'dbus-error (list "Not a valid D-Bus event" event))))
 
 ;;;###autoload
 (defun dbus-handle-event (event)
   "Handle events from the D-Bus.
 EVENT is a D-Bus event, see `dbus-check-event'.  HANDLER, being
-part of the event, is called with arguments ARGS."
+part of the event, is called with arguments ARGS.
+If the HANDLER returns an `dbus-error', it is propagated as return message."
   (interactive "e")
-  ;; We don't want to raise an error, because this function is called
-  ;; in the event handling loop.
-  (dbus-ignore-errors
-    (let (result)
-      (dbus-check-event event)
-      (setq result (apply (nth 7 event) (nthcdr 8 event)))
-      (unless (consp result) (setq result (cons result nil)))
-      ;; Return a message when serial is not `nil'.
-      (when (not (null (nth 2 event)))
-	(apply 'dbus-method-return-internal
-	       (nth 1 event) (nth 2 event) (nth 3 event) result)))))
+  ;; By default, we don't want to raise an error, because this
+  ;; function is called in the event handling loop.
+  (condition-case err
+      (let (result)
+	(dbus-check-event event)
+	(setq result (apply (nth 8 event) (nthcdr 9 event)))
+	;; Return a message when it is a message call.
+	(when (= dbus-message-type-method-call (nth 2 event))
+	  (dbus-ignore-errors
+	    (dbus-method-return-internal
+	     (nth 1 event) (nth 3 event) (nth 4 event) result))))
+    ;; Error handling.
+    (dbus-error
+     ;; Return an error message when it is a message call.
+     (when (= dbus-message-type-method-call (nth 2 event))
+       (dbus-ignore-errors
+	 (dbus-method-error-internal
+	  (nth 1 event) (nth 3 event) (nth 4 event) (cadr err))))
+     ;; Propagate D-Bus error in the debug case.
+     (when dbus-debug (signal (car err) (cdr err))))))
 
 (defun dbus-event-bus-name (event)
   "Return the bus name the event is coming from.
@@ -241,15 +317,22 @@
   (dbus-check-event event)
   (nth 1 event))
 
+(defun dbus-event-message-type (event)
+  "Return the message type of the corresponding D-Bus message.
+The result is a number.  EVENT is a D-Bus event, see
+`dbus-check-event'.  This function raises a `dbus-error' signal
+in case the event is not well formed."
+  (dbus-check-event event)
+  (nth 2 event))
+
 (defun dbus-event-serial-number (event)
   "Return the serial number of the corresponding D-Bus message.
-The result is a number in case the D-Bus message is a method
-call, or `nil' for all other mesage types.  The serial number is
-needed for generating a reply message.  EVENT is a D-Bus event,
-see `dbus-check-event'.  This function raises a `dbus-error'
-signal in case the event is not well formed."
+The result is a number.  The serial number is needed for
+generating a reply message.  EVENT is a D-Bus event, see
+`dbus-check-event'.  This function raises a `dbus-error' signal
+in case the event is not well formed."
   (dbus-check-event event)
-  (nth 2 event))
+  (nth 3 event))
 
 (defun dbus-event-service-name (event)
   "Return the name of the D-Bus object the event is coming from.
@@ -257,7 +340,7 @@
 This function raises a `dbus-error' signal in case the event is
 not well formed."
   (dbus-check-event event)
-  (nth 3 event))
+  (nth 4 event))
 
 (defun dbus-event-path-name (event)
   "Return the object path of the D-Bus object the event is coming from.
@@ -265,7 +348,7 @@
 This function raises a `dbus-error' signal in case the event is
 not well formed."
   (dbus-check-event event)
-  (nth 4 event))
+  (nth 5 event))
 
 (defun dbus-event-interface-name (event)
   "Return the interface name of the D-Bus object the event is coming from.
@@ -273,7 +356,7 @@
 This function raises a `dbus-error' signal in case the event is
 not well formed."
   (dbus-check-event event)
-  (nth 5 event))
+  (nth 6 event))
 
 (defun dbus-event-member-name (event)
   "Return the member name the event is coming from.
@@ -282,7 +365,7 @@
 function raises a `dbus-error' signal in case the event is not
 well formed."
   (dbus-check-event event)
-  (nth 6 event))
+  (nth 7 event))
 
 
 ;;; D-Bus registered names.
@@ -641,8 +724,8 @@
 	 (string-equal
 	  "readwrite"
 	  (dbus-introspect-get-attribute
-	   bus service path interface property)
-	  "access"))
+	   (dbus-get-property bus service path interface property)
+	   "access")))
       ;; "Set" requires a variant.
       (dbus-call-method
        bus service path dbus-interface-properties