Function: dbus-register-signal

dbus-register-signal is a byte-compiled function defined in dbus.el.gz.

Signature

(dbus-register-signal BUS SERVICE PATH INTERFACE SIGNAL HANDLER &rest ARGS)

Documentation

Register for a signal on the D-Bus BUS.

BUS is either a Lisp keyword, :system or :session, or a string denoting the bus address.

SERVICE is the D-Bus service name used by the sending D-Bus object. It can be either a known name or the unique name of the D-Bus object sending the signal.

PATH is the D-Bus object path SERVICE is registered at. INTERFACE is an interface offered by SERVICE. It must provide SIGNAL. HANDLER is a Lisp function to be called when the signal is received. It must accept as arguments the values SIGNAL is sending.

SERVICE, PATH, INTERFACE and SIGNAL can be nil. This is interpreted as a wildcard for the respective argument.

The remaining arguments ARGS can be keywords or keyword string pairs. Their meaning is as follows:

:argN STRING:
:pathN STRING: This stands for the Nth argument of the
signal. :pathN arguments can be used for object path wildcard matches as specified by D-Bus, while an :argN argument requires an exact match.

:arg-namespace STRING: Register for those signals, whose first
argument names a service or interface within the namespace STRING.

:path-namespace STRING: Register for the object path namespace
STRING. All signals sent from an object path, which has STRING as the preceding string, are matched. This requires PATH to be nil.

:eavesdrop: Register for unicast signals which are not directed
to the D-Bus object Emacs is registered at D-Bus BUS, if the security policy of BUS allows this.

Example:

(defun my-signal-handler (device)
  (message "Device %s added" device))

(dbus-register-signal
 :system "org.freedesktop.Hal" "/org/freedesktop/Hal/Manager"
 "org.freedesktop.Hal.Manager" "DeviceAdded" #'my-signal-handler)

  => ((:signal :system "org.freedesktop.Hal.Manager" "DeviceAdded")
      ("org.freedesktop.Hal" "/org/freedesktop/Hal/Manager" my-signal-handler))

dbus-register-signal returns an object, which can be used in dbus-unregister-object for removing the registration.

Probably introduced at or before Emacs version 24.3.

Source Code

;; Defined in /usr/src/emacs/lisp/net/dbus.el.gz
(defun dbus-register-signal
  (bus service path interface signal handler &rest args)
  "Register for a signal on the D-Bus BUS.

BUS is either a Lisp keyword, `:system' or `:session', or a
string denoting the bus address.

SERVICE is the D-Bus service name used by the sending D-Bus object.
It can be either a known name or the unique name of the D-Bus object
sending the signal.

PATH is the D-Bus object path SERVICE is registered at.
INTERFACE is an interface offered by SERVICE.  It must provide
SIGNAL.  HANDLER is a Lisp function to be called when the signal
is received.  It must accept as arguments the values SIGNAL is
sending.

SERVICE, PATH, INTERFACE and SIGNAL can be nil.  This is
interpreted as a wildcard for the respective argument.

The remaining arguments ARGS can be keywords or keyword string pairs.
Their meaning is as follows:

`:argN' STRING:
`:pathN' STRING: This stands for the Nth argument of the
signal.  `:pathN' arguments can be used for object path wildcard
matches as specified by D-Bus, while an `:argN' argument
requires an exact match.

`:arg-namespace' STRING: Register for those signals, whose first
argument names a service or interface within the namespace
STRING.

`:path-namespace' STRING: Register for the object path namespace
STRING.  All signals sent from an object path, which has STRING as
the preceding string, are matched.  This requires PATH to be nil.

`:eavesdrop': Register for unicast signals which are not directed
to the D-Bus object Emacs is registered at D-Bus BUS, if the
security policy of BUS allows this.

Example:

\(defun my-signal-handler (device)
  (message \"Device %s added\" device))

\(dbus-register-signal
 :system \"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\"
 \"org.freedesktop.Hal.Manager\" \"DeviceAdded\" #\\='my-signal-handler)

  => ((:signal :system \"org.freedesktop.Hal.Manager\" \"DeviceAdded\")
      (\"org.freedesktop.Hal\" \"/org/freedesktop/Hal/Manager\" my-signal-handler))

`dbus-register-signal' returns an object, which can be used in
`dbus-unregister-object' for removing the registration."

  (let ((counter 0)
	(rule "type='signal'")
	uname key key1 value)

    ;; Retrieve unique name of service.  If service is a known name,
    ;; we will register for the corresponding unique name, if any.
    ;; Signals are sent always with the unique name as sender.  Note:
    ;; the unique name of `dbus-service-dbus' is that string itself.
    (if (and (stringp service)
	     (not (zerop (length service)))
	     (not (string-equal service dbus-service-dbus))
             (/= (string-to-char service) ?:))
	(setq uname (dbus-get-name-owner bus service))
      (setq uname service))

    (setq rule (concat rule
		       (when uname (format ",sender='%s'" uname))
		       (when interface (format ",interface='%s'" interface))
		       (when signal (format ",member='%s'" signal))
		       (when path (format ",path='%s'" path))))

    ;; Add arguments to the rule.
    (if (or (stringp (car args)) (null (car args)))
	;; As backward compatibility option, we allow just strings.
	(dolist (arg args)
	  (if (stringp arg)
	      (setq rule (concat rule (format ",arg%d='%s'" counter arg)))
	    (if arg (signal 'wrong-type-argument (list "Wrong argument" arg))))
	  (setq counter (1+ counter)))

      ;; Parse keywords.
      (while args
	(setq
	 key (car args)
	 rule (concat
	       rule
	       (cond
		;; `:arg0' .. `:arg63', `:path0' .. `:path63'.
		((and (keywordp key)
		      (string-match
                       "\\`:\\(arg\\|path\\)\\([[:digit:]]+\\)\\'"
		       (symbol-name key)))
		 (setq counter (match-string 2 (symbol-name key))
		       args (cdr args)
		       value (car args))
		 (unless (and (<= (string-to-number counter) 63)
			      (stringp value))
		   (signal 'wrong-type-argument
			   (list "Wrong argument" key value)))
		 (format
		  ",arg%s%s='%s'"
		  counter
		  (if (string-equal (match-string 1 (symbol-name key)) "path")
		      "path" "")
		  value))
		;; `:arg-namespace', `:path-namespace'.
                ((memq key '(:arg-namespace :path-namespace))
		 (setq args (cdr args)
		       value (car args))
		 (unless (stringp value)
		   (signal 'wrong-type-argument
			   (list "Wrong argument" key value)))
		 (format
		  ",%s='%s'"
                  (if (eq key :path-namespace) "path_namespace" "arg0namespace")
		  value))
		;; `:eavesdrop'.
		((eq key :eavesdrop)
		 ",eavesdrop='true'")
		(t (signal 'wrong-type-argument (list "Wrong argument" key)))))
	 args (cdr args))))

    ;; Add the rule to the bus.
    (condition-case err
	(dbus-call-method
	 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
	 "AddMatch" rule)
      (dbus-error
       (if (not (string-match-p "eavesdrop" rule))
	   (signal (car err) (cdr err))
	 ;; The D-Bus spec says we shall fall back to a rule without eavesdrop.
	 (when dbus-debug (message "Removing eavesdrop from rule %s" rule))
         (setq rule (replace-regexp-in-string ",eavesdrop='true'" "" rule t t))
	 (dbus-call-method
	  bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
	  "AddMatch" rule))))

    (when dbus-debug (message "Matching rule \"%s\" created" rule))

    ;; Create a hash table entry.
    (setq key (list :signal bus interface signal)
	  key1 (list uname service path handler rule)
	  value (gethash key dbus-registered-objects-table))
    (unless  (member key1 value)
      (puthash key (cons key1 value) dbus-registered-objects-table))

    ;; Return the object.
    (list key (list service path handler))))