aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMichael Albinus2020-09-26 11:38:23 +0200
committerMichael Albinus2020-09-26 11:38:23 +0200
commitc540f3323da96eadf41ccfa4e23ec2a5124343b8 (patch)
tree6f513dd3abad6c8e8a61bd2cc939bd5cd9a9461f
parentc98c7def046c5f6b1ac50fda46e32545b5e2ba37 (diff)
downloademacs-c540f3323da96eadf41ccfa4e23ec2a5124343b8.tar.gz
emacs-c540f3323da96eadf41ccfa4e23ec2a5124343b8.zip
Add D-Bus monitor
* lisp/net/dbus.el (dbus-interface-monitoring): New defconst. (dbus-call-method, dbus-call-method-asynchronously) (dbus-send-signal, dbus-method-return-internal) (dbus-method-error-internal, dbus-check-arguments): Accept also :system-private and :session-private. (dbus-check-event, dbus-event-path-name) (dbus-event-interface-name) (dbus-event-member-name, dbus-property-handler) (dbus-handle-bus-disconnect): Adapt according to new structure. (dbus-handle-event): Handle also monitor events. (dbus-event-destination-name, dbus-event-handler) (dbus-event-arguments, dbus-register-monitor, dbus-monitor-handler): New defuns. * src/dbusbind.c (XD_DBUS_VALIDATE_BUS_ADDRESS, xd_remove_watch) (Fdbus__init_bus): Accept also :system-private and :session-private. (xd_read_message_1): Add destination and error_name to dbus-event. Handle monitor events. (syms_of_dbusbind): Declare QCsystem_private, QCsession_private and QCmonitor. (dbus-registered-objects-table): Fix docstring.
-rw-r--r--lisp/net/dbus.el295
-rw-r--r--src/dbusbind.c139
2 files changed, 341 insertions, 93 deletions
diff --git a/lisp/net/dbus.el b/lisp/net/dbus.el
index 86db7cbf18a..da47e5bc7f2 100644
--- a/lisp/net/dbus.el
+++ b/lisp/net/dbus.el
@@ -144,6 +144,17 @@ See URL `https://dbus.freedesktop.org/doc/dbus-specification.html#standard-inter
144;; </signal> 144;; </signal>
145;; </interface> 145;; </interface>
146 146
147(defconst dbus-interface-monitoring (concat dbus-interface-dbus ".Monitoring")
148 "The monitoring interface.
149See URL `https://dbus.freedesktop.org/doc/dbus-specification.html#bus-messages-become-monitor'.")
150
151;; <interface name="org.freedesktop.DBus.Monitoring">
152;; <method name="BecomeMonitor">
153;; <arg name="rule" type="as" direction="in"/>
154;; <arg name="flags" type="u" direction="in"/> ;; Not used, must be 0.
155;; </method>
156;; </interface>
157
147(defconst dbus-interface-local (concat dbus-interface-dbus ".Local") 158(defconst dbus-interface-local (concat dbus-interface-dbus ".Local")
148 "An interface whose methods can only be invoked by the local implementation.") 159 "An interface whose methods can only be invoked by the local implementation.")
149 160
@@ -336,7 +347,8 @@ object is returned instead of a list containing this single Lisp object.
336 347
337 (or (featurep 'dbusbind) 348 (or (featurep 'dbusbind)
338 (signal 'dbus-error (list "Emacs not compiled with dbus support"))) 349 (signal 'dbus-error (list "Emacs not compiled with dbus support")))
339 (or (memq bus '(:system :session)) (stringp bus) 350 (or (memq bus '(:system :session :system-private :session-private))
351 (stringp bus)
340 (signal 'wrong-type-argument (list 'keywordp bus))) 352 (signal 'wrong-type-argument (list 'keywordp bus)))
341 (or (stringp service) 353 (or (stringp service)
342 (signal 'wrong-type-argument (list 'stringp service))) 354 (signal 'wrong-type-argument (list 'stringp service)))
@@ -440,7 +452,8 @@ Example:
440 452
441 (or (featurep 'dbusbind) 453 (or (featurep 'dbusbind)
442 (signal 'dbus-error (list "Emacs not compiled with dbus support"))) 454 (signal 'dbus-error (list "Emacs not compiled with dbus support")))
443 (or (memq bus '(:system :session)) (stringp bus) 455 (or (memq bus '(:system :session :system-private :session-private))
456 (stringp bus)
444 (signal 'wrong-type-argument (list 'keywordp bus))) 457 (signal 'wrong-type-argument (list 'keywordp bus)))
445 (or (stringp service) 458 (or (stringp service)
446 (signal 'wrong-type-argument (list 'stringp service))) 459 (signal 'wrong-type-argument (list 'stringp service)))
@@ -490,7 +503,8 @@ Example:
490 503
491 (or (featurep 'dbusbind) 504 (or (featurep 'dbusbind)
492 (signal 'dbus-error (list "Emacs not compiled with dbus support"))) 505 (signal 'dbus-error (list "Emacs not compiled with dbus support")))
493 (or (memq bus '(:system :session)) (stringp bus) 506 (or (memq bus '(:system :session :system-private :session-private))
507 (stringp bus)
494 (signal 'wrong-type-argument (list 'keywordp bus))) 508 (signal 'wrong-type-argument (list 'keywordp bus)))
495 (or (null service) (stringp service) 509 (or (null service) (stringp service)
496 (signal 'wrong-type-argument (list 'stringp service))) 510 (signal 'wrong-type-argument (list 'stringp service)))
@@ -510,7 +524,8 @@ This is an internal function, it shall not be used outside dbus.el."
510 524
511 (or (featurep 'dbusbind) 525 (or (featurep 'dbusbind)
512 (signal 'dbus-error (list "Emacs not compiled with dbus support"))) 526 (signal 'dbus-error (list "Emacs not compiled with dbus support")))
513 (or (memq bus '(:system :session)) (stringp bus) 527 (or (memq bus '(:system :session :system-private :session-private))
528 (stringp bus)
514 (signal 'wrong-type-argument (list 'keywordp bus))) 529 (signal 'wrong-type-argument (list 'keywordp bus)))
515 (or (stringp service) 530 (or (stringp service)
516 (signal 'wrong-type-argument (list 'stringp service))) 531 (signal 'wrong-type-argument (list 'stringp service)))
@@ -527,7 +542,8 @@ This is an internal function, it shall not be used outside dbus.el."
527 542
528 (or (featurep 'dbusbind) 543 (or (featurep 'dbusbind)
529 (signal 'dbus-error (list "Emacs not compiled with dbus support"))) 544 (signal 'dbus-error (list "Emacs not compiled with dbus support")))
530 (or (memq bus '(:system :session)) (stringp bus) 545 (or (memq bus '(:system :session :system-private :session-private))
546 (stringp bus)
531 (signal 'wrong-type-argument (list 'keywordp bus))) 547 (signal 'wrong-type-argument (list 'keywordp bus)))
532 (or (stringp service) 548 (or (stringp service)
533 (signal 'wrong-type-argument (list 'stringp service))) 549 (signal 'wrong-type-argument (list 'stringp service)))
@@ -545,7 +561,8 @@ This is an internal function, it shall not be used outside dbus.el."
545 561
546 (or (featurep 'dbusbind) 562 (or (featurep 'dbusbind)
547 (signal 'dbus-error (list "Emacs not compiled with dbus support"))) 563 (signal 'dbus-error (list "Emacs not compiled with dbus support")))
548 (or (memq bus '(:system :session)) (stringp bus) 564 (or (memq bus '(:system :session :system-private :session-private))
565 (stringp bus)
549 (signal 'wrong-type-argument (list 'keywordp bus))) 566 (signal 'wrong-type-argument (list 'keywordp bus)))
550 (or (stringp service) 567 (or (stringp service)
551 (signal 'wrong-type-argument (list 'stringp service))) 568 (signal 'wrong-type-argument (list 'stringp service)))
@@ -1018,19 +1035,29 @@ STRING must have been encoded with `dbus-escape-as-identifier'."
1018 "Check whether EVENT is a well formed D-Bus event. 1035 "Check whether EVENT is a well formed D-Bus event.
1019EVENT is a list which starts with symbol `dbus-event': 1036EVENT is a list which starts with symbol `dbus-event':
1020 1037
1021 (dbus-event BUS TYPE SERIAL SERVICE PATH INTERFACE MEMBER HANDLER &rest ARGS) 1038 (dbus-event BUS TYPE SERIAL SERVICE DESTINATION PATH
1039 INTERFACE MEMBER HANDLER &rest ARGS)
1022 1040
1023BUS identifies the D-Bus the message is coming from. It is 1041BUS identifies the D-Bus the message is coming from. It is
1024either a Lisp symbol, `:system' or `:session', or a string 1042either a Lisp symbol, `:system', `:session', `:systemp-private'
1025denoting the bus address. TYPE is the D-Bus message type which 1043or `:session-private', or a string denoting the bus address.
1026has caused the event, SERIAL is the serial number of the received 1044
1027D-Bus message. SERVICE and PATH are the unique name and the 1045TYPE is the D-Bus message type which has caused the event, SERIAL
1028object path of the D-Bus object emitting the message. INTERFACE 1046is the serial number of the received D-Bus message when TYPE is
1029and MEMBER denote the message which has been sent. HANDLER is 1047equal `dbus-message-type-method-return' or `dbus-message-type-error'.
1030the function which has been registered for this message. ARGS 1048
1031are the typed arguments as returned from the message. They are 1049SERVICE and PATH are the unique name and the object path of the
1032passed to HANDLER without type information, when it is called 1050D-Bus object emitting the message. DESTINATION is the D-Bus name
1033during event handling in `dbus-handle-event'. 1051the message is dedicated to, or nil in case thje message is a
1052broadcast signal.
1053
1054INTERFACE and MEMBER denote the message which has been sent.
1055When TYPE is `dbus-message-type-error', MEMBER is the error name.
1056
1057HANDLER is the function which has been registered for this
1058message. ARGS are the typed arguments as returned from the
1059message. They are passed to HANDLER without type information,
1060when it is called during event handling in `dbus-handle-event'.
1034 1061
1035This function signals a `dbus-error' if the event is not well 1062This function signals a `dbus-error' if the event is not well
1036formed." 1063formed."
@@ -1038,7 +1065,7 @@ formed."
1038 (unless (and (listp event) 1065 (unless (and (listp event)
1039 (eq (car event) 'dbus-event) 1066 (eq (car event) 'dbus-event)
1040 ;; Bus symbol. 1067 ;; Bus symbol.
1041 (or (symbolp (nth 1 event)) 1068 (or (keywordp (nth 1 event))
1042 (stringp (nth 1 event))) 1069 (stringp (nth 1 event)))
1043 ;; Type. 1070 ;; Type.
1044 (and (natnump (nth 2 event)) 1071 (and (natnump (nth 2 event))
@@ -1050,20 +1077,26 @@ formed."
1050 (= dbus-message-type-error (nth 2 event)) 1077 (= dbus-message-type-error (nth 2 event))
1051 (or (stringp (nth 4 event)) 1078 (or (stringp (nth 4 event))
1052 (null (nth 4 event)))) 1079 (null (nth 4 event))))
1053 ;; Object path. 1080 ;; Destination.
1054 (or (= dbus-message-type-method-return (nth 2 event)) 1081 (or (= dbus-message-type-method-return (nth 2 event))
1055 (= dbus-message-type-error (nth 2 event)) 1082 (= dbus-message-type-error (nth 2 event))
1056 (stringp (nth 5 event))) 1083 (or (stringp (nth 5 event))
1057 ;; Interface. 1084 (null (nth 5 event))))
1085 ;; Object path.
1058 (or (= dbus-message-type-method-return (nth 2 event)) 1086 (or (= dbus-message-type-method-return (nth 2 event))
1059 (= dbus-message-type-error (nth 2 event)) 1087 (= dbus-message-type-error (nth 2 event))
1060 (stringp (nth 6 event))) 1088 (stringp (nth 6 event)))
1061 ;; Member. 1089 ;; Interface.
1062 (or (= dbus-message-type-method-return (nth 2 event)) 1090 (or (= dbus-message-type-method-return (nth 2 event))
1063 (= dbus-message-type-error (nth 2 event)) 1091 (= dbus-message-type-error (nth 2 event))
1064 (stringp (nth 7 event))) 1092 (stringp (nth 7 event)))
1093 ;; Member.
1094 (or (= dbus-message-type-method-return (nth 2 event))
1095 (stringp (nth 8 event)))
1065 ;; Handler. 1096 ;; Handler.
1066 (functionp (nth 8 event))) 1097 (functionp (nth 9 event))
1098 ;; Arguments.
1099 (listp (nthcdr 10 event)))
1067 (signal 'dbus-error (list "Not a valid D-Bus event" event)))) 1100 (signal 'dbus-error (list "Not a valid D-Bus event" event))))
1068 1101
1069(defun dbus-delete-types (&rest args) 1102(defun dbus-delete-types (&rest args)
@@ -1103,28 +1136,36 @@ part of the event, is called with arguments ARGS (without type information).
1103If the HANDLER returns a `dbus-error', it is propagated as return message." 1136If the HANDLER returns a `dbus-error', it is propagated as return message."
1104 (interactive "e") 1137 (interactive "e")
1105 (condition-case err 1138 (condition-case err
1106 (let (args result) 1139 (let (monitor args result)
1107 ;; We ignore not well-formed events. 1140 ;; We ignore not well-formed events.
1108 (dbus-check-event event) 1141 (dbus-check-event event)
1109 ;; Remove type information. 1142 ;; Remove type information.
1110 (setq args (mapcar #'dbus-delete-types (nthcdr 9 event))) 1143 (setq args (mapcar #'dbus-delete-types (nthcdr 10 event)))
1111 ;; Error messages must be propagated. 1144 (setq monitor
1112 (when (= dbus-message-type-error (nth 2 event)) 1145 (gethash
1113 (signal 'dbus-error args)) 1146 (list :monitor (nth 1 event)) dbus-registered-objects-table))
1114 ;; Apply the handler. 1147 (if monitor
1115 (setq result (apply (nth 8 event) args)) 1148 ;; A monitor event shall not trigger other operations, and
1116 ;; Return an (error) message when it is a message call. 1149 ;; it shall not trigger D-Bus errors.
1117 (when (= dbus-message-type-method-call (nth 2 event)) 1150 (setq result (dbus-ignore-errors (apply (nth 9 event) args)))
1118 (dbus-ignore-errors 1151 ;; Error messages must be propagated. The error name is in
1119 (if (eq (car-safe result) :error) 1152 ;; the member slot.
1120 (apply #'dbus-method-error-internal 1153 (when (= dbus-message-type-error (nth 2 event))
1121 (nth 1 event) (nth 4 event) (nth 3 event) (cdr result)) 1154 (signal 'dbus-error (cons (nth 8 event) args)))
1122 (if (eq result :ignore) 1155 ;; Apply the handler.
1123 (dbus-method-return-internal 1156 (setq result (apply (nth 9 event) args))
1124 (nth 1 event) (nth 4 event) (nth 3 event)) 1157 ;; Return an (error) message when it is a message call.
1125 (apply #'dbus-method-return-internal 1158 (when (= dbus-message-type-method-call (nth 2 event))
1126 (nth 1 event) (nth 4 event) (nth 3 event) 1159 (dbus-ignore-errors
1127 (if (consp result) result (list result)))))))) 1160 (if (eq (car-safe result) :error)
1161 (apply #'dbus-method-error-internal
1162 (nth 1 event) (nth 4 event) (nth 3 event) (cdr result))
1163 (if (eq result :ignore)
1164 (dbus-method-return-internal
1165 (nth 1 event) (nth 4 event) (nth 3 event))
1166 (apply #'dbus-method-return-internal
1167 (nth 1 event) (nth 4 event) (nth 3 event)
1168 (if (consp result) result (list result)))))))))
1128 ;; Error handling. 1169 ;; Error handling.
1129 (dbus-error 1170 (dbus-error
1130 ;; Return an error message when it is a message call. 1171 ;; Return an error message when it is a message call.
@@ -1172,13 +1213,21 @@ formed."
1172 (dbus-check-event event) 1213 (dbus-check-event event)
1173 (nth 4 event)) 1214 (nth 4 event))
1174 1215
1216(defun dbus-event-destination-name (event)
1217 "Return the name of the D-Bus object the event is dedicated to.
1218The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
1219This function signals a `dbus-error' if the event is not well
1220formed."
1221 (dbus-check-event event)
1222 (nth 5 event))
1223
1175(defun dbus-event-path-name (event) 1224(defun dbus-event-path-name (event)
1176 "Return the object path of the D-Bus object the event is coming from. 1225 "Return the object path of the D-Bus object the event is coming from.
1177The result is a string. EVENT is a D-Bus event, see `dbus-check-event'. 1226The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
1178This function signals a `dbus-error' if the event is not well 1227This function signals a `dbus-error' if the event is not well
1179formed." 1228formed."
1180 (dbus-check-event event) 1229 (dbus-check-event event)
1181 (nth 5 event)) 1230 (nth 6 event))
1182 1231
1183(defun dbus-event-interface-name (event) 1232(defun dbus-event-interface-name (event)
1184 "Return the interface name of the D-Bus object the event is coming from. 1233 "Return the interface name of the D-Bus object the event is coming from.
@@ -1186,15 +1235,32 @@ The result is a string. EVENT is a D-Bus event, see `dbus-check-event'.
1186This function signals a `dbus-error' if the event is not well 1235This function signals a `dbus-error' if the event is not well
1187formed." 1236formed."
1188 (dbus-check-event event) 1237 (dbus-check-event event)
1189 (nth 6 event)) 1238 (nth 7 event))
1190 1239
1191(defun dbus-event-member-name (event) 1240(defun dbus-event-member-name (event)
1192 "Return the member name the event is coming from. 1241 "Return the member name the event is coming from.
1193It is either a signal name or a method name. The result is a 1242It is either a signal name, a method name or an error name. The
1194string. EVENT is a D-Bus event, see `dbus-check-event'. This 1243result is a string. EVENT is a D-Bus event, see
1195function signals a `dbus-error' if the event is not well formed." 1244`dbus-check-event'. This function signals a `dbus-error' if the
1245event is not well formed."
1196 (dbus-check-event event) 1246 (dbus-check-event event)
1197 (nth 7 event)) 1247 (nth 8 event))
1248
1249(defun dbus-event-handler (event)
1250 "Return the handler the event is applied with.
1251The result is a function. EVENT is a D-Bus event, see
1252`dbus-check-event'. This function signals a `dbus-error' if the
1253event is not well formed."
1254 (dbus-check-event event)
1255 (nth 9 event))
1256
1257(defun dbus-event-arguments (event)
1258 "Return the arguments the event is carrying on.
1259The result is a list of arguments. EVENT is a D-Bus event, see
1260`dbus-check-event'. This function signals a `dbus-error' if the
1261event is not well formed."
1262 (dbus-check-event event)
1263 (nthcdr 10 event))
1198 1264
1199 1265
1200;;; D-Bus registered names. 1266;;; D-Bus registered names.
@@ -1717,7 +1783,7 @@ It will be registered for all objects created by `dbus-register-property'."
1717 1783
1718 ;; "Set" needs the third typed argument from `last-input-event'. 1784 ;; "Set" needs the third typed argument from `last-input-event'.
1719 ((string-equal method "Set") 1785 ((string-equal method "Set")
1720 (let* ((value (dbus-flatten-types (nth 11 last-input-event))) 1786 (let* ((value (dbus-flatten-types (nth 12 last-input-event)))
1721 (entry (dbus-get-this-registered-property 1787 (entry (dbus-get-this-registered-property
1722 bus service path interface property)) 1788 bus service path interface property))
1723 (object (car (last (car entry))))) 1789 (object (car (last (car entry)))))
@@ -1907,13 +1973,123 @@ It will be registered for all objects created by `dbus-register-service'."
1907 result) 1973 result)
1908 '(:signature "{oa{sa{sv}}}")))))) 1974 '(:signature "{oa{sa{sv}}}"))))))
1909 1975
1976(defun dbus-register-monitor
1977 (bus &optional service path interface member handler &rest args)
1978 "Register HANDLER for monitor events on the D-Bus BUS.
1979
1980BUS is either a Lisp symbol, `:system' or `:session', or a string
1981denoting the bus address.
1982
1983SERVICE is the D-Bus service name of the D-Bus. It must be a
1984known name (see discussion of DONT-REGISTER-SERVICE below).
1985
1986PATH is the D-Bus object path SERVICE is registered at (see
1987discussion of DONT-REGISTER-SERVICE below). INTERFACE is the
1988name of the interface used at PATH. MEMBER is either a method
1989name, a signal name, or an error name.
1990
1991HANDLER is the function to be called when a monitor event
1992arrives. If nil, the default handler `dbus-monitor-handler' is
1993applied. It is called with ARGS as arguments."
1994
1995 (let ((bus-private (if (eq bus :system) :system-private
1996 (if (eq bus :session) :session-private bus)))
1997 keyword type rule1 rule2 key key1 value)
1998 (unless handler (setq handler #'dbus-monitor-handler))
1999 ;; Read arguments.
2000 (while args
2001 (when (keywordp (setq keyword (pop args)))
2002 (cond
2003 ((eq :type keyword)
2004 ;; Must be "signal", "method_call", "method_return", or "error".
2005 (setq type (pop args))))))
2006 ;; Compose rules.
2007 (setq rule1
2008 (or
2009 (string-join
2010 (delq nil
2011 (list (when service (format "sender='%s'" service))
2012 (when path (format "path='%s'" path))
2013 (when interface (format "interface='%s'" interface))
2014 (when member (format "member='%s'" member))
2015 (when type (format "type='%s'" type))))
2016 ",")
2017 "")
2018 rule2
2019 (when service
2020 (string-join
2021 (delq nil
2022 (list (format "destination='%s'" service)
2023 (when path (format "path='%s'" path))
2024 (when interface (format "interface='%s'" interface))
2025 (when member (format "member='%s'" member))
2026 (when type (format "type='%s'" type))))
2027 ",")))
2028
2029 (unless (ignore-errors (dbus-get-unique-name bus-private))
2030 (dbus-init-bus bus 'private))
2031 (dbus-call-method
2032 bus-private dbus-service-dbus dbus-path-dbus dbus-interface-monitoring
2033 "BecomeMonitor"
2034 (append `(:array :string ,rule1) (when rule2 `(:string ,rule2)))
2035 :uint32 0)
2036
2037 (when dbus-debug (message "Matching rule \"%s\" created" rule1))
2038
2039 ;; Create a hash table entry.
2040 (setq key (list :monitor bus-private)
2041 key1 (list nil nil nil handler)
2042 value (gethash key dbus-registered-objects-table))
2043 (unless (member key1 value)
2044 (puthash key (cons key1 value) dbus-registered-objects-table))
2045
2046 (when dbus-debug (message "%s" dbus-registered-objects-table))
2047
2048 ;; Return the object.
2049 (list key (list service path handler))))
2050
2051(defun dbus-monitor-handler (&rest _args)
2052 "Default handler for the \"org.freedesktop.DBus.Monitoring.BecomeMonitor\" interface.
2053It will be applied all objects created by `dbus-register-monitor'."
2054 (with-current-buffer (get-buffer-create "*D-Bus Monitor*")
2055 (special-mode)
2056 (let* ((inhibit-read-only t)
2057 (eobp (eobp))
2058 (event last-input-event)
2059 (type (dbus-event-message-type event))
2060 (sender (dbus-event-service-name event))
2061 (destination (dbus-event-destination-name event))
2062 (serial (dbus-event-serial-number event))
2063 (path (dbus-event-path-name event))
2064 (interface (dbus-event-interface-name event))
2065 (member (dbus-event-member-name event))
2066 (arguments (dbus-event-arguments event)))
2067 (save-excursion
2068 (goto-char (point-max))
2069 (insert
2070 (format
2071 (concat
2072 "%s sender=%s -> destination=%s serial=%s "
2073 "path=%s interface=%s member=%s\n")
2074 (cond
2075 ((= type dbus-message-type-method-call) "method-call")
2076 ((= type dbus-message-type-method-return) "method-return")
2077 ((= type dbus-message-type-error) "error")
2078 ((= type dbus-message-type-signal) "signal"))
2079 sender destination serial path interface member))
2080 (dolist (arg arguments)
2081 (pp (dbus-flatten-types arg) (current-buffer)))
2082 (insert "\n"))
2083 (when eobp
2084 (goto-char (point-max))))))
2085
1910(defun dbus-handle-bus-disconnect () 2086(defun dbus-handle-bus-disconnect ()
1911 "React to a bus disconnection. 2087 "React to a bus disconnection.
1912BUS is the bus that disconnected. This routine unregisters all 2088BUS is the bus that disconnected. This routine unregisters all
1913handlers on the given bus and causes all synchronous calls 2089handlers on the given bus and causes all synchronous calls
1914pending at the time of disconnect to fail." 2090pending at the time of disconnect to fail."
1915 (let ((bus (dbus-event-bus-name last-input-event)) 2091 (let ((bus (dbus-event-bus-name last-input-event))
1916 (keys-to-remove)) 2092 keys-to-remove)
1917 (maphash 2093 (maphash
1918 (lambda (key value) 2094 (lambda (key value)
1919 (when (and (eq (nth 0 key) :serial) 2095 (when (and (eq (nth 0 key) :serial)
@@ -1923,13 +2099,14 @@ pending at the time of disconnect to fail."
1923 (list 'dbus-event 2099 (list 'dbus-event
1924 bus 2100 bus
1925 dbus-message-type-error 2101 dbus-message-type-error
1926 (nth 2 key) 2102 (nth 2 key) ; serial
1927 nil 2103 nil ; service
1928 nil 2104 nil ; destination
1929 nil 2105 nil ; path
1930 nil 2106 nil ; interface
1931 value) 2107 nil ; member
1932 (list 'dbus-error "Bus disconnected" bus)) 2108 value) ; handler
2109 (list 'dbus-error dbus-error-disconnected "Bus disconnected" bus))
1933 (push key keys-to-remove))) 2110 (push key keys-to-remove)))
1934 dbus-registered-objects-table) 2111 dbus-registered-objects-table)
1935 (dolist (key keys-to-remove) 2112 (dolist (key keys-to-remove)
@@ -1980,13 +2157,9 @@ this connection to those buses."
1980 2157
1981;;; TODO: 2158;;; TODO:
1982 2159
1983;; * Check property type in org.freedesktop.DBus.Properties.Set.
1984;;
1985;; * Implement org.freedesktop.DBus.ObjectManager.InterfacesAdded and 2160;; * Implement org.freedesktop.DBus.ObjectManager.InterfacesAdded and
1986;; org.freedesktop.DBus.ObjectManager.InterfacesRemoved. 2161;; org.freedesktop.DBus.ObjectManager.InterfacesRemoved.
1987;; 2162;;
1988;; * Implement org.freedesktop.DBus.Monitoring.BecomeMonitor.
1989;;
1990;; * Cache introspection data. 2163;; * Cache introspection data.
1991;; 2164;;
1992;; * Run handlers in own threads. 2165;; * Run handlers in own threads.
diff --git a/src/dbusbind.c b/src/dbusbind.c
index 4c5ab485803..09f0317be91 100644
--- a/src/dbusbind.c
+++ b/src/dbusbind.c
@@ -44,7 +44,10 @@ along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. */
44 44
45/* Alist of D-Bus buses we are polling for messages. 45/* Alist of D-Bus buses we are polling for messages.
46 The key is the symbol or string of the bus, and the value is the 46 The key is the symbol or string of the bus, and the value is the
47 connection address. */ 47 connection address. For every bus, just one connection is counted.
48 If there shall be a second connection to the same bus, a different
49 symbol or string for the bus must be chosen. On Lisp level, a bus
50 stands for the associated connection. */
48static Lisp_Object xd_registered_buses; 51static Lisp_Object xd_registered_buses;
49 52
50/* Whether we are reading a D-Bus event. */ 53/* Whether we are reading a D-Bus event. */
@@ -279,10 +282,13 @@ XD_OBJECT_TO_STRING (Lisp_Object object)
279 else \ 282 else \
280 { \ 283 { \
281 CHECK_SYMBOL (bus); \ 284 CHECK_SYMBOL (bus); \
282 if (!(EQ (bus, QCsystem) || EQ (bus, QCsession))) \ 285 if (!(EQ (bus, QCsystem) || EQ (bus, QCsession) \
286 || EQ (bus, QCsystem_private) \
287 || EQ (bus, QCsession_private))) \
283 XD_SIGNAL2 (build_string ("Wrong bus name"), bus); \ 288 XD_SIGNAL2 (build_string ("Wrong bus name"), bus); \
284 /* We do not want to have an autolaunch for the session bus. */ \ 289 /* We do not want to have an autolaunch for the session bus. */ \
285 if (EQ (bus, QCsession) && session_bus_address == NULL) \ 290 if ((EQ (bus, QCsession) || EQ (bus, QCsession_private)) \
291 && session_bus_address == NULL) \
286 XD_SIGNAL2 (build_string ("No connection to bus"), bus); \ 292 XD_SIGNAL2 (build_string ("No connection to bus"), bus); \
287 } \ 293 } \
288 } while (0) 294 } while (0)
@@ -968,8 +974,9 @@ xd_lisp_dbus_to_dbus (Lisp_Object bus)
968 return xmint_pointer (bus); 974 return xmint_pointer (bus);
969} 975}
970 976
971/* Return D-Bus connection address. BUS is either a Lisp symbol, 977/* Return D-Bus connection address.
972 :system or :session, or a string denoting the bus address. */ 978 BUS is either a Lisp symbol, :system, :session, :system-private or
979 :session-private, or a string denoting the bus address. */
973static DBusConnection * 980static DBusConnection *
974xd_get_connection_address (Lisp_Object bus) 981xd_get_connection_address (Lisp_Object bus)
975{ 982{
@@ -1031,7 +1038,8 @@ xd_add_watch (DBusWatch *watch, void *data)
1031} 1038}
1032 1039
1033/* Stop monitoring WATCH for possible I/O. 1040/* Stop monitoring WATCH for possible I/O.
1034 DATA is the used bus, either a string or QCsystem or QCsession. */ 1041 DATA is the used bus, either a string or QCsystem, QCsession,
1042 QCsystem_private or QCsession_private. */
1035static void 1043static void
1036xd_remove_watch (DBusWatch *watch, void *data) 1044xd_remove_watch (DBusWatch *watch, void *data)
1037{ 1045{
@@ -1046,7 +1054,7 @@ xd_remove_watch (DBusWatch *watch, void *data)
1046 /* Unset session environment. */ 1054 /* Unset session environment. */
1047#if 0 1055#if 0
1048 /* This is buggy, since unsetenv is not thread-safe. */ 1056 /* This is buggy, since unsetenv is not thread-safe. */
1049 if (XSYMBOL (QCsession) == data) 1057 if (XSYMBOL (QCsession) == data) || (XSYMBOL (QCsession_private) == data)
1050 { 1058 {
1051 XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS"); 1059 XD_DEBUG_MESSAGE ("unsetenv DBUS_SESSION_BUS_ADDRESS");
1052 unsetenv ("DBUS_SESSION_BUS_ADDRESS"); 1060 unsetenv ("DBUS_SESSION_BUS_ADDRESS");
@@ -1120,6 +1128,11 @@ can be a string denoting the address of the corresponding bus. For
1120the system and session buses, this function is called when loading 1128the system and session buses, this function is called when loading
1121`dbus.el', there is no need to call it again. 1129`dbus.el', there is no need to call it again.
1122 1130
1131A special case is BUS being the symbol `:system-private' or
1132`:session-private'. These symbols still denote the system or session
1133bus, but using a private connection. They should not be used outside
1134dbus.el.
1135
1123The function returns a number, which counts the connections this Emacs 1136The function returns a number, which counts the connections this Emacs
1124session has established to the BUS under the same unique name (see 1137session has established to the BUS under the same unique name (see
1125`dbus-get-unique-name'). It depends on the libraries Emacs is linked 1138`dbus-get-unique-name'). It depends on the libraries Emacs is linked
@@ -1142,6 +1155,10 @@ this connection to those buses. */)
1142 ptrdiff_t refcount; 1155 ptrdiff_t refcount;
1143 1156
1144 /* Check parameter. */ 1157 /* Check parameter. */
1158 if (!NILP (private))
1159 bus = EQ (bus, QCsystem)
1160 ? QCsystem_private
1161 : EQ (bus, QCsession) ? QCsession_private : bus;
1145 XD_DBUS_VALIDATE_BUS_ADDRESS (bus); 1162 XD_DBUS_VALIDATE_BUS_ADDRESS (bus);
1146 1163
1147 /* Close bus if it is already open. */ 1164 /* Close bus if it is already open. */
@@ -1169,8 +1186,9 @@ this connection to those buses. */)
1169 1186
1170 else 1187 else
1171 { 1188 {
1172 DBusBusType bustype = (EQ (bus, QCsystem) 1189 DBusBusType bustype
1173 ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION); 1190 = EQ (bus, QCsystem) || EQ (bus, QCsystem_private)
1191 ? DBUS_BUS_SYSTEM : DBUS_BUS_SESSION;
1174 if (NILP (private)) 1192 if (NILP (private))
1175 connection = dbus_bus_get (bustype, &derror); 1193 connection = dbus_bus_get (bustype, &derror);
1176 else 1194 else
@@ -1184,9 +1202,9 @@ this connection to those buses. */)
1184 XD_SIGNAL2 (build_string ("No connection to bus"), bus); 1202 XD_SIGNAL2 (build_string ("No connection to bus"), bus);
1185 1203
1186 /* If it is not the system or session bus, we must register 1204 /* If it is not the system or session bus, we must register
1187 ourselves. Otherwise, we have called dbus_bus_get, which has 1205 ourselves. Otherwise, we have called dbus_bus_get{_private},
1188 configured us to exit if the connection closes - we undo this 1206 which has configured us to exit if the connection closes - we
1189 setting. */ 1207 undo this setting. */
1190 if (STRINGP (bus)) 1208 if (STRINGP (bus))
1191 dbus_bus_register (connection, &derror); 1209 dbus_bus_register (connection, &derror);
1192 else 1210 else
@@ -1215,6 +1233,9 @@ this connection to those buses. */)
1215 dbus_error_free (&derror); 1233 dbus_error_free (&derror);
1216 } 1234 }
1217 1235
1236 XD_DEBUG_MESSAGE ("Registered buses: %s",
1237 XD_OBJECT_TO_STRING (xd_registered_buses));
1238
1218 /* Return reference counter. */ 1239 /* Return reference counter. */
1219 refcount = xd_get_connection_references (connection); 1240 refcount = xd_get_connection_references (connection);
1220 XD_DEBUG_MESSAGE ("Bus %s, Reference counter %"pD"d", 1241 XD_DEBUG_MESSAGE ("Bus %s, Reference counter %"pD"d",
@@ -1533,8 +1554,8 @@ usage: (dbus-message-internal &rest REST) */)
1533} 1554}
1534 1555
1535/* Read one queued incoming message of the D-Bus BUS. 1556/* Read one queued incoming message of the D-Bus BUS.
1536 BUS is either a Lisp symbol, :system or :session, or a string denoting 1557 BUS is either a Lisp symbol, :system, :session, :system-private or
1537 the bus address. */ 1558 :session-private, or a string denoting the bus address. */
1538static void 1559static void
1539xd_read_message_1 (DBusConnection *connection, Lisp_Object bus) 1560xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1540{ 1561{
@@ -1546,7 +1567,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1546 int mtype; 1567 int mtype;
1547 dbus_uint32_t serial; 1568 dbus_uint32_t serial;
1548 unsigned int ui_serial; 1569 unsigned int ui_serial;
1549 const char *uname, *path, *interface, *member, *error_name; 1570 const char *uname, *destination, *path, *interface, *member, *error_name;
1550 1571
1551 dmessage = dbus_connection_pop_message (connection); 1572 dmessage = dbus_connection_pop_message (connection);
1552 1573
@@ -1579,6 +1600,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1579 ? dbus_message_get_reply_serial (dmessage) 1600 ? dbus_message_get_reply_serial (dmessage)
1580 : dbus_message_get_serial (dmessage); 1601 : dbus_message_get_serial (dmessage);
1581 uname = dbus_message_get_sender (dmessage); 1602 uname = dbus_message_get_sender (dmessage);
1603 destination = dbus_message_get_destination (dmessage);
1582 path = dbus_message_get_path (dmessage); 1604 path = dbus_message_get_path (dmessage);
1583 interface = dbus_message_get_interface (dmessage); 1605 interface = dbus_message_get_interface (dmessage);
1584 member = dbus_message_get_member (dmessage); 1606 member = dbus_message_get_member (dmessage);
@@ -1586,7 +1608,8 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1586 1608
1587 XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s %s", 1609 XD_DEBUG_MESSAGE ("Event received: %s %u %s %s %s %s %s %s",
1588 XD_MESSAGE_TYPE_TO_STRING (mtype), 1610 XD_MESSAGE_TYPE_TO_STRING (mtype),
1589 ui_serial, uname, path, interface, member, error_name, 1611 ui_serial, uname, destination, path, interface,
1612 mtype == DBUS_MESSAGE_TYPE_ERROR ? error_name : member,
1590 XD_OBJECT_TO_STRING (args)); 1613 XD_OBJECT_TO_STRING (args));
1591 1614
1592 if (mtype == DBUS_MESSAGE_TYPE_INVALID) 1615 if (mtype == DBUS_MESSAGE_TYPE_INVALID)
@@ -1601,7 +1624,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1601 1624
1602 /* There shall be exactly one entry. Construct an event. */ 1625 /* There shall be exactly one entry. Construct an event. */
1603 if (NILP (value)) 1626 if (NILP (value))
1604 goto cleanup; 1627 goto monitor;
1605 1628
1606 /* Remove the entry. */ 1629 /* Remove the entry. */
1607 Fremhash (key, Vdbus_registered_objects_table); 1630 Fremhash (key, Vdbus_registered_objects_table);
@@ -1610,11 +1633,8 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1610 EVENT_INIT (event); 1633 EVENT_INIT (event);
1611 event.kind = DBUS_EVENT; 1634 event.kind = DBUS_EVENT;
1612 event.frame_or_window = Qnil; 1635 event.frame_or_window = Qnil;
1613 event.arg = 1636 /* Handler. */
1614 Fcons (value, 1637 event.arg = Fcons (value, args);
1615 (mtype == DBUS_MESSAGE_TYPE_ERROR)
1616 ? Fcons (list2 (QCstring, build_string (error_name)), args)
1617 : args);
1618 } 1638 }
1619 1639
1620 else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */ 1640 else /* DBUS_MESSAGE_TYPE_METHOD_CALL, DBUS_MESSAGE_TYPE_SIGNAL. */
@@ -1622,7 +1642,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1622 /* Vdbus_registered_objects_table requires non-nil interface and 1642 /* Vdbus_registered_objects_table requires non-nil interface and
1623 member. */ 1643 member. */
1624 if ((interface == NULL) || (member == NULL)) 1644 if ((interface == NULL) || (member == NULL))
1625 goto cleanup; 1645 goto monitor;
1626 1646
1627 /* Search for a registered function of the message. */ 1647 /* Search for a registered function of the message. */
1628 key = list4 (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL ? QCmethod : QCsignal, 1648 key = list4 (mtype == DBUS_MESSAGE_TYPE_METHOD_CALL ? QCmethod : QCsignal,
@@ -1647,6 +1667,7 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1647 EVENT_INIT (event); 1667 EVENT_INIT (event);
1648 event.kind = DBUS_EVENT; 1668 event.kind = DBUS_EVENT;
1649 event.frame_or_window = Qnil; 1669 event.frame_or_window = Qnil;
1670 /* Handler. */
1650 event.arg 1671 event.arg
1651 = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args); 1672 = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (key)))), args);
1652 break; 1673 break;
@@ -1655,16 +1676,22 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1655 } 1676 }
1656 1677
1657 if (NILP (value)) 1678 if (NILP (value))
1658 goto cleanup; 1679 goto monitor;
1659 } 1680 }
1660 1681
1661 /* Add type, serial, uname, path, interface and member to the event. */ 1682 /* Add type, serial, uname, destination, path, interface and member
1662 event.arg = Fcons ((member == NULL ? Qnil : build_string (member)), 1683 or error_name to the event. */
1663 event.arg); 1684 event.arg
1685 = Fcons (mtype == DBUS_MESSAGE_TYPE_ERROR
1686 ? error_name == NULL ? Qnil : build_string (error_name)
1687 : member == NULL ? Qnil : build_string (member),
1688 event.arg);
1664 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)), 1689 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
1665 event.arg); 1690 event.arg);
1666 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)), 1691 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
1667 event.arg); 1692 event.arg);
1693 event.arg = Fcons ((destination == NULL ? Qnil : build_string (destination)),
1694 event.arg);
1668 event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)), 1695 event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
1669 event.arg); 1696 event.arg);
1670 event.arg = Fcons (INT_TO_INTEGER (serial), event.arg); 1697 event.arg = Fcons (INT_TO_INTEGER (serial), event.arg);
@@ -1678,14 +1705,58 @@ xd_read_message_1 (DBusConnection *connection, Lisp_Object bus)
1678 1705
1679 XD_DEBUG_MESSAGE ("Event stored: %s", XD_OBJECT_TO_STRING (event.arg)); 1706 XD_DEBUG_MESSAGE ("Event stored: %s", XD_OBJECT_TO_STRING (event.arg));
1680 1707
1708 /* Monitor. */
1709 monitor:
1710 /* Search for a registered function of the message. */
1711 key = list2 (QCmonitor, bus);
1712 value = Fgethash (key, Vdbus_registered_objects_table, Qnil);
1713
1714 /* There shall be exactly one entry. Construct an event. */
1715 if (NILP (value))
1716 goto cleanup;
1717
1718 /* Construct an event. */
1719 EVENT_INIT (event);
1720 event.kind = DBUS_EVENT;
1721 event.frame_or_window = Qnil;
1722
1723 /* Add type, serial, uname, destination, path, interface, member
1724 or error_name and handler to the event. */
1725 event.arg
1726 = Fcons (CAR_SAFE (CDR_SAFE (CDR_SAFE (CDR_SAFE (CAR_SAFE (value))))),
1727 args);
1728 event.arg
1729 = Fcons (mtype == DBUS_MESSAGE_TYPE_ERROR
1730 ? error_name == NULL ? Qnil : build_string (error_name)
1731 : member == NULL ? Qnil : build_string (member),
1732 event.arg);
1733 event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
1734 event.arg);
1735 event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
1736 event.arg);
1737 event.arg = Fcons ((destination == NULL ? Qnil : build_string (destination)),
1738 event.arg);
1739 event.arg = Fcons ((uname == NULL ? Qnil : build_string (uname)),
1740 event.arg);
1741 event.arg = Fcons (INT_TO_INTEGER (serial), event.arg);
1742 event.arg = Fcons (make_fixnum (mtype), event.arg);
1743
1744 /* Add the bus symbol to the event. */
1745 event.arg = Fcons (bus, event.arg);
1746
1747 /* Store it into the input event queue. */
1748 kbd_buffer_store_event (&event);
1749
1750 XD_DEBUG_MESSAGE ("Monitor event stored: %s", XD_OBJECT_TO_STRING (event.arg));
1751
1681 /* Cleanup. */ 1752 /* Cleanup. */
1682 cleanup: 1753 cleanup:
1683 dbus_message_unref (dmessage); 1754 dbus_message_unref (dmessage);
1684} 1755}
1685 1756
1686/* Read queued incoming messages of the D-Bus BUS. 1757/* Read queued incoming messages of the D-Bus BUS.
1687 BUS is either a Lisp symbol, :system or :session, or a string denoting 1758 BUS is either a Lisp symbol, :system, :session, :system-private or
1688 the bus address. */ 1759 :session-private, or a string denoting the bus address. */
1689static Lisp_Object 1760static Lisp_Object
1690xd_read_message (Lisp_Object bus) 1761xd_read_message (Lisp_Object bus)
1691{ 1762{
@@ -1762,6 +1833,8 @@ syms_of_dbusbind (void)
1762 /* Lisp symbols of the system and session buses. */ 1833 /* Lisp symbols of the system and session buses. */
1763 DEFSYM (QCsystem, ":system"); 1834 DEFSYM (QCsystem, ":system");
1764 DEFSYM (QCsession, ":session"); 1835 DEFSYM (QCsession, ":session");
1836 DEFSYM (QCsystem_private, ":system-private");
1837 DEFSYM (QCsession_private, ":session-private");
1765 1838
1766 /* Lisp symbol for method call timeout. */ 1839 /* Lisp symbol for method call timeout. */
1767 DEFSYM (QCtimeout, ":timeout"); 1840 DEFSYM (QCtimeout, ":timeout");
@@ -1788,10 +1861,11 @@ syms_of_dbusbind (void)
1788 DEFSYM (QCdict_entry, ":dict-entry"); 1861 DEFSYM (QCdict_entry, ":dict-entry");
1789 1862
1790 /* Lisp symbols of objects in `dbus-registered-objects-table'. 1863 /* Lisp symbols of objects in `dbus-registered-objects-table'.
1791 `:property', which does exist there as well, is not used here. */ 1864 `:property', which does exist there as well, is not declared here. */
1792 DEFSYM (QCserial, ":serial"); 1865 DEFSYM (QCserial, ":serial");
1793 DEFSYM (QCmethod, ":method"); 1866 DEFSYM (QCmethod, ":method");
1794 DEFSYM (QCsignal, ":signal"); 1867 DEFSYM (QCsignal, ":signal");
1868 DEFSYM (QCmonitor, ":monitor");
1795 1869
1796 DEFVAR_LISP ("dbus-compiled-version", 1870 DEFVAR_LISP ("dbus-compiled-version",
1797 Vdbus_compiled_version, 1871 Vdbus_compiled_version,
@@ -1867,8 +1941,9 @@ path of the sending object. All of them can be nil, which means a
1867wildcard then. 1941wildcard then.
1868 1942
1869OBJECT is either the handler to be called when a D-Bus message, which 1943OBJECT is either the handler to be called when a D-Bus message, which
1870matches the key criteria, arrives (TYPE `:method' and `:signal'), or a 1944matches the key criteria, arrives (TYPE `:method', `:signal' and
1871list (ACCESS EMITS-SIGNAL VALUE) for TYPE `:property'. 1945`:monitor'), or a list (ACCESS EMITS-SIGNAL VALUE) for TYPE
1946`:property'.
1872 1947
1873For entries of type `:signal', there is also a fifth element RULE, 1948For entries of type `:signal', there is also a fifth element RULE,
1874which keeps the match string the signal is registered with. 1949which keeps the match string the signal is registered with.