diff options
| author | Michael Albinus | 2009-11-13 16:05:24 +0000 |
|---|---|---|
| committer | Michael Albinus | 2009-11-13 16:05:24 +0000 |
| commit | b172ed20e0cd9feaf5b057860f23d9baab16c4f3 (patch) | |
| tree | 7a90343cb36b60f777c6ea13ee94c8942d8f5de3 /lisp | |
| parent | 8f11f7ecce714ca7a88d4882ea5139b4120ba3f8 (diff) | |
| download | emacs-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/ChangeLog | 10 | ||||
| -rw-r--r-- | lisp/net/dbus.el | 233 |
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 @@ | |||
| 1 | 2009-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 | |||
| 1 | 2009-11-13 Stefan Monnier <monnier@iro.umontreal.ca> | 11 | 2009-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. |
| 122 | The return value is a list, with elements of kind (KEY . VALUE). | 122 | The return value is a list, with elements of kind (KEY . VALUE). |
| 123 | See `dbus-registered-functions-table' for a description of the | 123 | See `dbus-registered-objects-table' for a description of the |
| 124 | hash table." | 124 | hash 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. |
| 133 | OBJECT must be the result of a preceding `dbus-register-method' | 133 | OBJECT must be the result of a preceding `dbus-register-method', |
| 134 | or `dbus-register-signal' call. It returns `t' if OBJECT has | 134 | `dbus-register-property' or `dbus-register-signal' call. It |
| 135 | been unregistered, `nil' otherwise." | 135 | returns `t' if OBJECT has been unregistered, `nil' otherwise. |
| 136 | |||
| 137 | When OBJECT identifies the last method or property, which is | ||
| 138 | registered for the respective service, Emacs releases its | ||
| 139 | association 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. |
| 181 | It calls the function stored in `dbus-registered-functions-table'. | 188 | It calls the function stored in `dbus-registered-objects-table'. |
| 182 | The result will be made available in `dbus-return-values-table'." | 189 | The 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\"." | |||
| 805 | It will be checked at BUS, SERVICE, PATH. The result can be any | 812 | It will be checked at BUS, SERVICE, PATH. The result can be any |
| 806 | valid D-Bus value, or `nil' if there is no PROPERTY." | 813 | valid 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 | |||
| 824 | been set successful, the result is VALUE. Otherwise, `nil' is | 824 | been set successful, the result is VALUE. Otherwise, `nil' is |
| 825 | returned." | 825 | returned." |
| 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. |
| 851 | The result is a list of entries. Every entry is a cons of the | 836 | The result is a list of entries. Every entry is a cons of the |
| 852 | name of the property, and its value. If there are no properties, | 837 | name 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 | |||
| 853 | BUS is either the symbol `:system' or the symbol `:session'. | ||
| 854 | |||
| 855 | SERVICE is the D-Bus service name of the D-Bus. It must be a | ||
| 856 | known name. | ||
| 857 | |||
| 858 | PATH is the D-Bus object path SERVICE is registered. INTERFACE | ||
| 859 | is the name of the interface used at PATH, PROPERTY is the name | ||
| 860 | of the property of INTERFACE. ACCESS indicates, whether the | ||
| 861 | property can be changed by other services via D-Bus. It must be | ||
| 862 | either the symbol `:read' or `:readwrite'. VALUE is the initial | ||
| 863 | value of the property, it can be of any valid type (see | ||
| 864 | `dbus-call-method' for details). | ||
| 865 | |||
| 866 | If PROPERTY already exists on PATH, it will be overwritten. For | ||
| 867 | properties with access type `:read' this is the only way to | ||
| 868 | change their values. Properties with access type `:readwrite' | ||
| 869 | can be changed by `dbus-set-property'. | ||
| 870 | |||
| 871 | The interface \"org.freedesktop.DBus.Properties\" is added to | ||
| 872 | PATH, 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. | ||
| 906 | It calls the function stored in `dbus-registered-objects-table'. | ||
| 907 | The 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. |