如何使用Emacs的DBUS界面?

Rud*_*lah 12 emacs elisp dbus

我查了一下dbus包,似乎所有的函数都内置在C源代码中,并且没有相关的文档.

我该如何使用该dbus-call-method功能?

And*_*ter 23

我刚遇到同样的问题,发现当google搜索有点过于基本以满足我的需求时出现的emacs-fu文章.

特别是我想通过dbus导出我自己的elisp方法,并且难以理解dbus术语以及它如何应用于emacs dbus接口.

首先要看看,emacs文档,Ch f dbus-register-method

dbus-register-method is a built-in function in `C source code'.

(dbus-register-method BUS SERVICE PATH INTERFACE METHOD HANDLER)

Register for method METHOD on the D-Bus BUS.

BUS is either the symbol `:system' or the symbol `:session'.

SERVICE is the D-Bus service name of the D-Bus object METHOD is
registered for.  It must be a known name.

PATH is the D-Bus object path SERVICE is registered.  INTERFACE is the
interface offered by SERVICE.  It must provide METHOD.  HANDLER is a
Lisp function to be called when a method call is received.  It must
accept the input arguments of METHOD.  The return value of HANDLER is
used for composing the returning D-Bus message.
Run Code Online (Sandbox Code Playgroud)

BUS就是:session或:system(你可能几乎总是想要使用:我认为会话就像桌面应用程序一样).

SERVICE是总线上应用程序的唯一名称,如地址或域名.Dbus.el定义dbus-service-emacs为"org.gnu.Emacs".

PATH是针对不同应用程序功能的不同类型的应用程序功能.例如,某个emacs模块可能会在org.gnu.Emacs SERVICE下的/ ModuleName PATH中公开功能.

INTERFACE就像编程中的界面.它是一个规范,告诉其他dbus客户端如何与您的应用程序公开的对象进行通信.它包含例如方法的类型签名.所以你可能有一个界面,如:在服务org.gnu.Emacs下,在路径/ ModuleName中,你会发现一个名为helloworld的方法,它将采用零参数并返回一个字符串.

难以理解的是:我如何为我的方法定义一个接口?

在dbus.el周围你会发现有dbus-interface-introspectable(其中包括)定义的,只包含一个字符串"org.freedesktop.DBus.Introspectable",它命名一个标准接口,只暴露一个方法:

org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data)
Run Code Online (Sandbox Code Playgroud)

(链接到规范http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable)

这就是客户调用以了解dbus上暴露的应用程序的方法.因此我们可以使用该方法来查看其他应用程序如何在dbus上宣传他们的东西,然后我们可以实现我们自己的Introspect方法,只是模仿其他人正在做的事情,一切都会好的.

但请注意,规范说应用程序可以实现Introspectable接口,但它们不必.实际上你可以dbus-register-method用一个空字符串作为接口调用就好(看起来什么都行).你可以打电话给你的方法.然而,当我想出如何使我的东西内省时,我总是遇到NoReply错误和应用程序挂起等待dbus响应的问题.所以我认为Introspect()很常见.

所以我们这样做:

(defun say-world ()
  ;; you need to map between dbus and emacs datatypes, that's what :string is for
  ;; if you're returning just one value that should work automatically, otherwise
  ;; you're expected to put your return values in a list like I am doing here
  (list :string "world"))

(dbus-register-method
  :session
  "org.test.emacs"
  "/helloworld"
  "org.test.emacs"
  "hello"
  'say-world)
Run Code Online (Sandbox Code Playgroud)

这就是我们想要实现的,因此想要为(名为"org.test.emacs")定义接口.您可以像这样使用它并尝试调用hello方法qdbus org.test.emacs /helloworld org.test.emacs.hello.它应该工作,对我来说它只在等待20秒后(使应用程序挂起),但它的工作原理.

现在让我们让它内省:

(defun dbus-test-slash-introspect ()
  "<node name='/'>
  <interface name='org.freedesktop.DBus.Introspectable'>
  <method name='Introspect'>
  <arg name='xml_data' type='s' direction='out'/>
  </method>
  </interface>
  <node name='helloworld'>
  </node>
  </node>")

(dbus-register-method
  :session
  "org.test.emacs"
  "/"
  dbus-interface-introspectable
  "Introspect"
  'dbus-test-slash-introspect)

(defun dbus-test-slash-helloworld-introspect ()
  "<node name='/helloworld'>
  <interface name='org.freedesktop.DBus.Introspectable'>
  <method name='Introspect'>
  <arg name='xml_data' type='s' direction='out'/>
  </method>
  </interface>
  <interface name='org.test.emacs'>
  <method name='hello'>
  <arg name='' direction='out' type='s' />
  </method>
  </interface>
  </node>")

(dbus-register-method
  :session
  "org.test.emacs"
  "/helloworld"
  dbus-interface-introspectable
  "Introspect"
  'dbus-test-slash-helloworld-introspect)
Run Code Online (Sandbox Code Playgroud)

我们走了.我们只定义两个Introspect方法(一个用于路径层次的每个级别)并返回一些手写的xml,告诉其他应用程序关于/ helloworld路径和其中的hello方法.请注意,dbus-test-slash-helloworld-introspect包含<interface name="org.test.emacs">...</interface>具有我们方法的类型签名,即,就我而言,我们在使用dbus注册方法时使用的接口的定义.

评估所有这些并使用qdbus进行解决:

~> qdbus org.test.emacs
/
/helloworld

~> qdbus org.test.emacs /
method QString org.freedesktop.DBus.Introspectable.Introspect()

~> qdbus org.test.emacs /helloworld
method QString org.freedesktop.DBus.Introspectable.Introspect()
method QString org.test.emacs.helloworld()

~> qdbus org.test.emacs /helloworld org.test.emacs.hello
world
Run Code Online (Sandbox Code Playgroud)

万岁,按预期工作,没有挂起或NoReply错误.

最后一件事,您可能会尝试像这样测试您的方法:

(dbus-call-method :session "org.test.emacs" "/helloworld" "org.test.emacs" "hello" :timeout 1000)
Run Code Online (Sandbox Code Playgroud)

并发现它只是超时并想知道为什么.那是因为如果您在同一个emacs实例中注册并调用方法,那么emacs将等待自己回答.没有花哨的线程,在那种情况下你总能获得NoReply答案.

如果你必须在同一个emacs实例中调用和注册方法,你可以这样使用dbus-call-method-asynchronously:

(defun handle-hello (hello)
  (print hello))

(dbus-call-method-asynchronously :session "org.test.emacs" "/helloworld" "org.test.emacs" "hello" 'handle-hello)
Run Code Online (Sandbox Code Playgroud)


Tre*_*son 8

谷歌救援......按照示例的链接,这不是我的代码,所以我不会把它放在这里.

http://emacs-fu.blogspot.com/2009/01/using-d-bus-example.html


yPh*_*hil 5

这是测试dbus功能的安全方法:

(defun dbus-capable ()
  "Check if dbus is available"
  (unwind-protect
      (let (retval)
        (condition-case ex
            (setq retval (dbus-ping :session "org.freedesktop.Notifications"))
          ('error
           (message (format "Error: %s - No dbus" ex))))
        retval)))
Run Code Online (Sandbox Code Playgroud)

这是发送dbus通知的一种方法:

(defun mbug-desktop-notification (summary body timeout icon)
  "call notification-daemon method METHOD with ARGS over dbus"
  (if (dbus-capable)
      (dbus-call-method
       :session                                 ; Session (not system) bus
       "org.freedesktop.Notifications"          ; Service name
       "/org/freedesktop/Notifications"         ; Service path
       "org.freedesktop.Notifications" "Notify" ; Method
       "emacs"
       0
       icon
       summary
       body
       '(:array)
       '(:array :signature "{sv}")
       ':int32 timeout)
    (message "Oh well, you're still notified")))
Run Code Online (Sandbox Code Playgroud)