[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
on-the-fly D-Bus proxy creation
From: |
Daiki Ueno |
Subject: |
on-the-fly D-Bus proxy creation |
Date: |
Tue, 24 Feb 2015 17:05:34 +0900 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/25.0.50 (gnu/linux) |
Hello,
There are several programming languages with support for D-Bus client
implementation. For example, with the following code:
https://git.gnome.org/browse/gnome-shell/tree/js/ui/keyboard.js#n56
const CaribouDaemonIface = '<node> \
<interface name="org.gnome.Caribou.Daemon"> \
<method name="Run" /> \
<method name="Quit" /> \
</interface> \
</node>';
const CaribouDaemonProxy = Gio.DBusProxy.makeProxyWrapper(CaribouDaemonIface);
One can call a D-Bus method as a normal method of CaribouDaemonProxy.
This is really handy and I wished to have similar feature in Elisp
(though I haven't ever written any practical D-Bus code in Elisp).
Thanks to cl-generic, I gave it a try. With the attached code (far from
complete though), a client can be implemented as:
(dbus-define-proxy search-provider "\
<node>
<interface name=\"org.gnome.Shell.SearchProvider2\">
<method name=\"GetInitialResultSet\">
<arg type=\"as\" name=\"terms\" direction=\"in\" />
<arg type=\"as\" name=\"results\" direction=\"out\" />
</method>
<!-- actually, there are more methods in this interface -->
</interface>
</node>")
Then you can create a client and call D-Bus methods:
(setq search-provider
(search-provider-make :session
"org.gnome.Weather.BackgroundService"
"/org/gnome/Weather/BackgroundService"))
(search-provider-call-GetInitialResultSet search-provider '("tokyo"))
If this seems to be useful, I can finish it off as a patch.
Thanks,
--
Daiki Ueno
(require 'dbus)
(eval-when-compile (require 'cl-lib))
(eval-when-compile (require 'xml))
(cl-defstruct dbus-proxy
(bus :read-only t)
(service :read-only t)
(path :read-only t))
(defmacro dbus-define-proxy (name xml)
(let* ((node (car (with-temp-buffer
(insert xml)
(xml-parse-region (point-min) (point-max)))))
(interface (car (xml-get-children node 'interface)))
(methods (xml-get-children interface 'method))
(interface-name (xml-get-attribute-or-nil interface 'name)))
`(progn
(cl-defstruct (,name (:include dbus-proxy)
(:constructor nil)
(:constructor ,(intern (format "%s-make" name))
(bus service path)))
;; FIXME: slots for cached properties?
)
,@(mapcar
(lambda (method)
(let ((method-name (xml-get-attribute-or-nil method 'name))
;; FIXME: parse argument types?
(in-args
(mapcar #'intern
(delq nil
(mapcar
(lambda (arg)
(let ((direction (xml-get-attribute-or-nil
arg 'direction)))
(if (or (null direction)
(not (equal direction "out")))
(xml-get-attribute-or-nil
arg 'name))))
(xml-get-children method 'arg))))))
;; FIXME: un-CamelCasify method-name?
`(cl-defmethod ,(intern (format "%s-call-%s" name method-name))
((proxy ,name) ,@in-args &rest args)
(apply #'dbus-call-method
(dbus-proxy-bus proxy)
(dbus-proxy-service proxy)
(dbus-proxy-path proxy)
,interface-name
,method-name
,@in-args
args))))
methods)
;; FIXME: asynchronous method calls, signals?
)))
(dbus-define-proxy search-provider "\
<node>
<interface name=\"org.gnome.Shell.SearchProvider2\">
<method name=\"GetInitialResultSet\">
<arg type=\"as\" name=\"terms\" direction=\"in\" />
<arg type=\"as\" name=\"results\" direction=\"out\" />
</method>
<!-- actually, there are more methods in this interface -->
</interface>
</node>")
;; (setq search-provider
;; (search-provider-make :session
;; "org.gnome.Weather.BackgroundService"
;; "/org/gnome/Weather/BackgroundService"))
;; (search-provider-call-GetInitialResultSet search-provider '("tokyo"))