【问题标题】:How do I use Emacs's DBUS interface?如何使用 Emacs 的 DBUS 接口?
【发布时间】:2011-05-27 08:01:27
【问题描述】:

我查看了 dbus 包,似乎所有函数都内置在 C 源代码中,并且没有它们的文档。

如何使用dbus-call-method 函数?

【问题讨论】:

    标签: emacs elisp dbus


    【解决方案1】:

    我刚遇到同样的问题,发现在谷歌搜索时出现的 emacs-fu 文章对我的需求来说有点太基本了。

    特别是我想通过 dbus 导出我自己的 elisp 方法,但在理解 dbus 术语以及它如何应用于 emacs dbus 接口时遇到了问题。

    首先要检查,emacs 文档,C-h 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.
    

    BUS 将是 :session 或 :system (我想你可能几乎总是想像桌面应用程序那样使用 :session)。

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

    PATH 对于不同类型的应用程序功能就像 SERVICE 对于不同的应用程序本身一样。例如,某个 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)
    

    (链接到规范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)
    

    这就是我们想要实现的,因此想要为(命名为“org.test.emacs”)定义一个接口。您可以像这样使用它并尝试使用qdbus org.test.emacs /helloworld org.test.emacs.hello 调用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)
    

    我们去吧。我们只定义了两个 Introspect 方法(一个用于路径层次结构的每一层)并返回一些手写的 xml,告诉其他应用程序 /helloworld 路径和其中的 hello 方法。请注意,dbus-test-slash-helloworld-introspect 包含 &lt;interface name="org.test.emacs"&gt;...&lt;/interface&gt;,它具有我们方法的类型签名,即就我而言,我们在向 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
    

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

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

    (dbus-call-method :session "org.test.emacs" "/helloworld" "org.test.emacs" "hello" :timeout 1000)
    

    并发现它只是超时并想知道为什么。那是因为如果您在同一个 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)
    

    【讨论】:

    • 这应该是最佳答案。
    • 这很棒。您是否考虑将其贡献给 Emacs Lisp 手册?
    【解决方案2】:

    谷歌救援...点击示例链接,这不是我的代码,所以我不会放在这里。

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

    【讨论】:

    • 例如调用dbus-call-method:(progn (require 'dbus) (defun desktop-environment-keyboard-backlight-set (value) "Set keyboard backlight to VALUE." (dbus-call-method :system "org.freedesktop.UPower" "/org/freedesktop/UPower/KbdBacklight" "org.freedesktop.UPower.KbdBacklight" "SetBrightness" :int32 value) (desktop-environment-keyboard-backlight-set 0))。我会添加一些代码,因为链接 bitrot。
    【解决方案3】:

    这是测试 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)))
    

    这是一种发送 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")))
    

    【讨论】:

      【解决方案4】:

      或者,只需在 Emacs 中评估以下内容:

      (info "(dbus)")
      

      【讨论】:

      • C-h i g (dbus) RET
      猜你喜欢
      • 2011-05-15
      • 1970-01-01
      • 1970-01-01
      • 2010-10-31
      • 2012-11-13
      • 2011-04-14
      • 2011-04-09
      • 2014-02-07
      • 1970-01-01
      相关资源
      最近更新 更多