emacs-devel
[Top][All Lists]
Advanced

[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"))

reply via email to

[Prev in Thread] Current Thread [Next in Thread]