aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorMichael Albinus2009-11-13 16:05:24 +0000
committerMichael Albinus2009-11-13 16:05:24 +0000
commitb172ed20e0cd9feaf5b057860f23d9baab16c4f3 (patch)
tree7a90343cb36b60f777c6ea13ee94c8942d8f5de3 /lisp
parent8f11f7ecce714ca7a88d4882ea5139b4120ba3f8 (diff)
downloademacs-b172ed20e0cd9feaf5b057860f23d9baab16c4f3.tar.gz
emacs-b172ed20e0cd9feaf5b057860f23d9baab16c4f3.zip
* net/dbus.el (dbus-registered-objects-table): Renamed from
`dbus-registered-functions-table', because it contains also properties. (dbus-unregister-object): Unregister also properties. (dbus-get-property, dbus-set-property, dbus-get-all-properties): Use a timeout of 500 msec, in order to not block. (dbus-register-property, dbus-property-handler): New defuns.
Diffstat (limited to 'lisp')
-rw-r--r--lisp/ChangeLog10
-rw-r--r--lisp/net/dbus.el233
2 files changed, 170 insertions, 73 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index 10cb54857a0..33145165dff 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,13 @@
12009-11-13 Michael Albinus <michael.albinus@gmx.de>
2
3 * net/dbus.el (dbus-registered-objects-table): Renamed from
4 `dbus-registered-functions-table', because it contains also
5 properties.
6 (dbus-unregister-object): Unregister also properties.
7 (dbus-get-property, dbus-set-property, dbus-get-all-properties):
8 Use a timeout of 500 msec, in order to not block.
9 (dbus-register-property, dbus-property-handler): New defuns.
10
12009-11-13 Stefan Monnier <monnier@iro.umontreal.ca> 112009-11-13 Stefan Monnier <monnier@iro.umontreal.ca>
2 12
3 * simple.el (minibuffer-default-add-completions): Drop deprecated 13 * simple.el (minibuffer-default-add-completions): Drop deprecated
diff --git a/lisp/net/dbus.el b/lisp/net/dbus.el
index 065d3d1876a..a7e1d464911 100644
--- a/lisp/net/dbus.el
+++ b/lisp/net/dbus.el
@@ -39,7 +39,7 @@
39(declare-function dbus-method-error-internal "dbusbind.c") 39(declare-function dbus-method-error-internal "dbusbind.c")
40(declare-function dbus-register-signal "dbusbind.c") 40(declare-function dbus-register-signal "dbusbind.c")
41(defvar dbus-debug) 41(defvar dbus-debug)
42(defvar dbus-registered-functions-table) 42(defvar dbus-registered-objects-table)
43 43
44;; Pacify byte compiler. 44;; Pacify byte compiler.
45(eval-when-compile 45(eval-when-compile
@@ -108,7 +108,7 @@ catched in `condition-case' by `dbus-error'.")
108 108
109;; We create it here. So we have a simple test in dbusbind.c, whether 109;; We create it here. So we have a simple test in dbusbind.c, whether
110;; the Lisp code has been loaded. 110;; the Lisp code has been loaded.
111(setq dbus-registered-functions-table (make-hash-table :test 'equal)) 111(setq dbus-registered-objects-table (make-hash-table :test 'equal))
112 112
113(defvar dbus-return-values-table (make-hash-table :test 'equal) 113(defvar dbus-return-values-table (make-hash-table :test 'equal)
114 "Hash table for temporary storing arguments of reply messages. 114 "Hash table for temporary storing arguments of reply messages.
@@ -120,55 +120,62 @@ of the reply message. See `dbus-call-method-non-blocking-handler' and
120(defun dbus-list-hash-table () 120(defun dbus-list-hash-table ()
121 "Returns all registered member registrations to D-Bus. 121 "Returns all registered member registrations to D-Bus.
122The return value is a list, with elements of kind (KEY . VALUE). 122The return value is a list, with elements of kind (KEY . VALUE).
123See `dbus-registered-functions-table' for a description of the 123See `dbus-registered-objects-table' for a description of the
124hash table." 124hash table."
125 (let (result) 125 (let (result)
126 (maphash 126 (maphash
127 '(lambda (key value) (add-to-list 'result (cons key value) 'append)) 127 '(lambda (key value) (add-to-list 'result (cons key value) 'append))
128 dbus-registered-functions-table) 128 dbus-registered-objects-table)
129 result)) 129 result))
130 130
131(defun dbus-unregister-object (object) 131(defun dbus-unregister-object (object)
132 "Unregister OBJECT from D-Bus. 132 "Unregister OBJECT from D-Bus.
133OBJECT must be the result of a preceding `dbus-register-method' 133OBJECT must be the result of a preceding `dbus-register-method',
134or `dbus-register-signal' call. It returns `t' if OBJECT has 134`dbus-register-property' or `dbus-register-signal' call. It
135been unregistered, `nil' otherwise." 135returns `t' if OBJECT has been unregistered, `nil' otherwise.
136
137When OBJECT identifies the last method or property, which is
138registered for the respective service, Emacs releases its
139association to the service from D-Bus."
136 ;; Check parameter. 140 ;; Check parameter.
137 (unless (and (consp object) (not (null (car object))) (consp (cdr object))) 141 (unless (and (consp object) (not (null (car object))) (consp (cdr object)))
138 (signal 'wrong-type-argument (list 'D-Bus object))) 142 (signal 'wrong-type-argument (list 'D-Bus object)))
139 143
140 ;; Find the corresponding entry in the hash table. 144 ;; Find the corresponding entry in the hash table.
141 (let* ((key (car object)) 145 (let* ((key (car object))
142 (value (gethash key dbus-registered-functions-table)) 146 (value (cdr object))
143 (bus (car key)) 147 (entry (gethash key dbus-registered-objects-table))
144 ret) 148 ret)
149 ;; entry has the structure ((UNAME SERVICE PATH MEMBER) ...).
150 ;; value has the structure ((SERVICE PATH [HANDLER]) ...).
151 ;; MEMBER is either a string (the handler), or a cons cell (a
152 ;; property value). UNAME and property values are not taken into
153 ;; account for comparision.
154
145 ;; Loop over the registered functions. 155 ;; Loop over the registered functions.
146 (dolist (val value) 156 (dolist (elt entry)
147 ;; val has the structure (UNAME SERVICE PATH HANDLER). 157 (when (equal
148 ;; (cdr object) has the structure ((SERVICE PATH HANDLER) ...). 158 (car value)
149 (when (equal (cdr val) (car (cdr object))) 159 (butlast (cdr elt) (- (length (cdr elt)) (length (car value)))))
150 ;; Compute new hash value. If it is empty, remove it from 160 ;; Compute new hash value. If it is empty, remove it from the
151 ;; hash table. 161 ;; hash table.
152 (unless 162 (unless (puthash key (delete elt entry) dbus-registered-objects-table)
153 (puthash 163 (remhash key dbus-registered-objects-table))
154 key
155 (delete val (gethash key dbus-registered-functions-table))
156 dbus-registered-functions-table)
157 (remhash key dbus-registered-functions-table))
158 (setq ret t))) 164 (setq ret t)))
159 ;; Check, whether there is still a registered function for the 165 ;; Check, whether there is still a registered function or property
160 ;; given service. If not, unregister the service from the bus. 166 ;; for the given service. If not, unregister the service from the
161 (dolist (val value) 167 ;; bus.
162 (let ((service (cadr val)) 168 (dolist (elt entry)
169 (let ((service (cadr elt))
170 (bus (car key))
163 found) 171 found)
164 (maphash 172 (maphash
165 (lambda (k v) 173 (lambda (k v)
166 (dolist (val v) 174 (dolist (e v)
167 (ignore-errors 175 (ignore-errors
168 (when (and (equal bus (car k)) 176 (when (and (equal bus (car k)) (string-equal service (cadr e)))
169 (string-equal service (cadr val)))
170 (setq found t))))) 177 (setq found t)))))
171 dbus-registered-functions-table) 178 dbus-registered-objects-table)
172 (unless found 179 (unless found
173 (dbus-call-method 180 (dbus-call-method
174 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus 181 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
@@ -178,7 +185,7 @@ been unregistered, `nil' otherwise."
178 185
179(defun dbus-call-method-non-blocking-handler (&rest args) 186(defun dbus-call-method-non-blocking-handler (&rest args)
180 "Handler for reply messages of asynchronous D-Bus message calls. 187 "Handler for reply messages of asynchronous D-Bus message calls.
181It calls the function stored in `dbus-registered-functions-table'. 188It calls the function stored in `dbus-registered-objects-table'.
182The result will be made available in `dbus-return-values-table'." 189The result will be made available in `dbus-return-values-table'."
183 (puthash (list (dbus-event-bus-name last-input-event) 190 (puthash (list (dbus-event-bus-name last-input-event)
184 (dbus-event-serial-number last-input-event)) 191 (dbus-event-serial-number last-input-event))
@@ -248,7 +255,7 @@ usage: (dbus-name-owner-changed-handler service old-owner new-owner)"
248 (nth 0 key) (nth 1 elt) (nth 2 elt) 255 (nth 0 key) (nth 1 elt) (nth 2 elt)
249 ;; INTERFACE MEMBER HANDLER 256 ;; INTERFACE MEMBER HANDLER
250 (nth 1 key) (nth 2 key) (nth 3 elt))))) 257 (nth 1 key) (nth 2 key) (nth 3 elt)))))
251 (copy-hash-table dbus-registered-functions-table)))) 258 (copy-hash-table dbus-registered-objects-table))))
252 ;; The error is reported only in debug mode. 259 ;; The error is reported only in debug mode.
253 (when dbus-debug 260 (when dbus-debug
254 (signal 261 (signal
@@ -805,18 +812,11 @@ be \"out\"."
805It will be checked at BUS, SERVICE, PATH. The result can be any 812It will be checked at BUS, SERVICE, PATH. The result can be any
806valid D-Bus value, or `nil' if there is no PROPERTY." 813valid D-Bus value, or `nil' if there is no PROPERTY."
807 (dbus-ignore-errors 814 (dbus-ignore-errors
808 ;; We must check, whether the "org.freedesktop.DBus.Properties" 815 ;; "Get" returns a variant, so we must use the `car'.
809 ;; interface is supported; otherwise the call blocks. 816 (car
810 (when 817 (dbus-call-method-non-blocking
811 (member 818 bus service path dbus-interface-properties
812 "Get" 819 "Get" :timeout 500 interface property))))
813 (dbus-introspect-get-method-names
814 bus service path "org.freedesktop.DBus.Properties"))
815 ;; "Get" returns a variant, so we must use the car.
816 (car
817 (dbus-call-method
818 bus service path dbus-interface-properties
819 "Get" interface property)))))
820 820
821(defun dbus-set-property (bus service path interface property value) 821(defun dbus-set-property (bus service path interface property value)
822 "Set value of PROPERTY of INTERFACE to VALUE. 822 "Set value of PROPERTY of INTERFACE to VALUE.
@@ -824,46 +824,133 @@ It will be checked at BUS, SERVICE, PATH. When the value has
824been set successful, the result is VALUE. Otherwise, `nil' is 824been set successful, the result is VALUE. Otherwise, `nil' is
825returned." 825returned."
826 (dbus-ignore-errors 826 (dbus-ignore-errors
827 (when 827 ;; "Set" requires a variant.
828 (and 828 (dbus-call-method-non-blocking
829 ;; We must check, whether the 829 bus service path dbus-interface-properties
830 ;; "org.freedesktop.DBus.Properties" interface is supported; 830 "Set" :timeout 500 interface property (list :variant value))
831 ;; otherwise the call blocks. 831 ;; Return VALUE.
832 (member 832 (dbus-get-property bus service path interface property)))
833 "Set"
834 (dbus-introspect-get-method-names
835 bus service path "org.freedesktop.DBus.Properties"))
836 ;; PROPERTY must be writable.
837 (string-equal
838 "readwrite"
839 (dbus-introspect-get-attribute
840 (dbus-introspect-get-property bus service path interface property)
841 "access")))
842 ;; "Set" requires a variant.
843 (dbus-call-method
844 bus service path dbus-interface-properties
845 "Set" interface property (list :variant value))
846 ;; Return VALUE.
847 (dbus-get-property bus service path interface property))))
848 833
849(defun dbus-get-all-properties (bus service path interface) 834(defun dbus-get-all-properties (bus service path interface)
850 "Return all properties of INTERFACE at BUS, SERVICE, PATH. 835 "Return all properties of INTERFACE at BUS, SERVICE, PATH.
851The result is a list of entries. Every entry is a cons of the 836The result is a list of entries. Every entry is a cons of the
852name of the property, and its value. If there are no properties, 837name of the property, and its value. If there are no properties,
853`nil' is returned." 838`nil' is returned."
854 ;; "org.freedesktop.DBus.Properties.GetAll" is not supported at
855 ;; all interfaces. Therefore, we do it ourselves.
856 (dbus-ignore-errors 839 (dbus-ignore-errors
840 ;; "GetAll" returns "a{sv}".
857 (let (result) 841 (let (result)
858 (dolist (property 842 (dolist (dict
859 (dbus-introspect-get-property-names 843 (dbus-call-method-non-blocking
860 bus service path interface) 844 bus service path dbus-interface-properties
845 "GetAll" :timeout 500 interface)
861 result) 846 result)
862 (add-to-list 847 (add-to-list 'result (cons (car dict) (caadr dict)) 'append)))))
863 'result 848
864 (cons property (dbus-get-property bus service path interface property)) 849(defun dbus-register-property
865 'append))))) 850 (bus service path interface property access value)
866 851 "Register property PROPERTY on the D-Bus BUS.
852
853BUS is either the symbol `:system' or the symbol `:session'.
854
855SERVICE is the D-Bus service name of the D-Bus. It must be a
856known name.
857
858PATH is the D-Bus object path SERVICE is registered. INTERFACE
859is the name of the interface used at PATH, PROPERTY is the name
860of the property of INTERFACE. ACCESS indicates, whether the
861property can be changed by other services via D-Bus. It must be
862either the symbol `:read' or `:readwrite'. VALUE is the initial
863value of the property, it can be of any valid type (see
864`dbus-call-method' for details).
865
866If PROPERTY already exists on PATH, it will be overwritten. For
867properties with access type `:read' this is the only way to
868change their values. Properties with access type `:readwrite'
869can be changed by `dbus-set-property'.
870
871The interface \"org.freedesktop.DBus.Properties\" is added to
872PATH, including a default handler for the \"Get\", \"GetAll\" and
873\"Set\" methods of this interface."
874 (unless (member access '(:read :readwrite))
875 (signal 'dbus-error (list "Access type invalid" access)))
876
877 ;; Register SERVICE.
878 (unless (member service (dbus-list-names bus))
879 (dbus-call-method
880 bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
881 "RequestName" service 0))
882
883 ;; Add the handler. We use `dbus-service-emacs' as service name, in
884 ;; order to let unregister SERVICE despite of this default handler.
885 (dbus-register-method
886 bus dbus-service-emacs path dbus-interface-properties
887 "Get" 'dbus-property-handler)
888 (dbus-register-method
889 bus dbus-service-emacs path dbus-interface-properties
890 "GetAll" 'dbus-property-handler)
891 (dbus-register-method
892 bus dbus-service-emacs path dbus-interface-properties
893 "Set" 'dbus-property-handler)
894
895 ;; Create a hash table entry. We use nil for the unique name,
896 ;; because the property might be accessed from anybody.
897 (let ((key (list bus interface property))
898 (val (list (list nil service path (cons access value)))))
899 (puthash key val dbus-registered-objects-table)
900
901 ;; Return the object.
902 (list key (list service path))))
903
904(defun dbus-property-handler (&rest args)
905 "Handler for reply messages of asynchronous D-Bus message calls.
906It calls the function stored in `dbus-registered-objects-table'.
907The result will be made available in `dbus-return-values-table'."
908 (let ((bus (dbus-event-bus-name last-input-event))
909 (path (dbus-event-path-name last-input-event))
910 (method (dbus-event-member-name last-input-event))
911 (interface (car args))
912 (property (cadr args)))
913 (cond
914 ;; "Get" returns a variant.
915 ((string-equal method "Get")
916 (let ((val (gethash (list bus interface property)
917 dbus-registered-objects-table)))
918 (when (string-equal path (nth 2 (car val)))
919 (list (list :variant (cdar (last (car val))))))))
920
921 ;; "Set" expects a variant.
922 ((string-equal method "Set")
923 (let ((val (gethash (list bus interface property)
924 dbus-registered-objects-table)))
925 (unless (consp (car (last (car val))))
926 (signal 'dbus-error
927 (list "Property not registered at path" property path)))
928 (unless (equal (caar (last (car val))) :readwrite)
929 (signal 'dbus-error
930 (list "Property not writable at path" property path)))
931 (puthash (list bus interface property)
932 (list (append (butlast (car val))
933 (list (cons :readwrite (caar (cddr args))))))
934 dbus-registered-objects-table)
935 :ignore))
936
937 ;; "GetAll" returns "a{sv}".
938 ((string-equal method "GetAll")
939 (let (result)
940 (maphash
941 (lambda (key val)
942 (when (and (equal (butlast key) (list bus interface))
943 (string-equal path (nth 2 (car val)))
944 (consp (car (last (car val)))))
945 (add-to-list
946 'result
947 (list :dict-entry
948 (car (last key))
949 (list :variant (cdar (last (car val))))))))
950 dbus-registered-objects-table)
951 (list result))))))
952
953
867;; Initialize :system and :session buses. This adds their file 954;; Initialize :system and :session buses. This adds their file
868;; descriptors to input_wait_mask, in order to detect incoming 955;; descriptors to input_wait_mask, in order to detect incoming
869;; messages immediately. 956;; messages immediately.