2010-12-17 21 views

Respuesta

23

yo sólo tenía el mismo problema y encontrar el artículo de emacs-fu que aparece cuando googlear un poco demasiado básica para mis necesidades.

En particular, quería exportar mis propios métodos elisp a través de dbus, y tenía problemas para dar sentido a la terminología dbus y cómo se aplica a la interfaz dbus de emacs.

La primera cosa a la salida, la documentación emacs, Ch f dbus-registro-método

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 es sólo va a ser: la sesión o: Sistema (en el que, probablemente, casi siempre desea utilizar: Sesión como una aplicación de escritorio, supongo).

SERVICE es un nombre único para la aplicación en el bus, como una dirección o nombre de dominio. Dbus.el define dbus-service-emacs como "org.gnu.Emacs".

PATH es para diferentes tipos de funcionalidades de aplicaciones, lo que SERVICE es para las diferentes aplicaciones. Por ejemplo, un determinado módulo de emacs podría exponer la funcionalidad en la ruta de acceso/ModuleName en el servicio org.gnu.Emacs.

INTERFACE es como una interfaz de programación. Es una especificación que le dice a otros clientes dbus cómo comunicarse con el objeto (s) que expone su aplicación. Contiene, por ejemplo, firmas de tipo para sus métodos. Así que puede tener una interfaz que diga algo así como: en el servicio org.gnu.Emacs, en la ruta/ModuleName, encontrará un método llamado helloworld que tomará cero argumentos y devolverá una cadena.

Lo difícil de averiguar para mí fue: ¿cómo puedo definir una interfaz para mi método?

hurgando dbus.el encontrará que hay dbus-interface-introspectable (entre otros) definido, que solo contiene una cadena "org.freedesktop.DBus.Introspectable", que nombra una interfaz estándar que simplemente expone un método:

org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data) 

(enlace a la especificación http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-introspectable)

Y ese es el método que se llama por los clientes para obtener información sobre las aplicaciones que se exponen en el dbus. Entonces podemos usar ese método para ver cómo otras aplicaciones anuncian sus cosas en dbus, y luego podemos implementar nuestro propio método de Introspect simplemente imitando lo que los demás están haciendo y todo estará bien.

Sin embargo, tenga en cuenta que la especificación dice que las aplicaciones pueden implementar la interfaz Introspectable, no es necesario. De hecho, puede llamar al dbus-register-method con una cadena vacía como interfaz (todo parece hacerlo). Podrás llamar a tu método.Sin embargo, siempre tuve errores de NoReply y problemas con las aplicaciones colgando esperando una respuesta de dbus que se fue cuando descubrí cómo hacer que mis cosas fueran introspectibles. Así que supongo que Introspect() se espera con bastante frecuencia.

Así que vamos a hacer esto:

(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) 

Eso es lo que queremos poner en práctica y por lo tanto desee definir una interfaz para (denominados "org.test.emacs"). Puede usarlo así e intentar llamar al método hello con qdbus org.test.emacs /helloworld org.test.emacs.hello. Debería funcionar, para mí funciona solo después de 20 segundos de espera (lo que hace que la aplicación se cuelgue), pero funciona.

Ahora vamos a hacer que introspectable:

(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) 

Aquí vamos. Simplemente definimos dos métodos de Introspect (uno para cada nivel de nuestra jerarquía de ruta) y devolvemos un xml escrito a mano que informa a otras aplicaciones sobre la ruta/helloworld y el método hello dentro de ella. Tenga en cuenta que dbus-test-slash-helloworld-introspect contiene <interface name="org.test.emacs">...</interface> que tiene una firma de tipo para nuestro método, es decir, en lo que a mí respecta, la definición de la interfaz que utilizamos cuando registramos nuestro método con dbus.

Evaluar todo eso y hurgar con 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 

Hooray, funciona como se espera, sin colgante o errores noreply.

Una última cosa, puede intentar poner a prueba su método de este modo:

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

y encontrar que simplemente los tiempos de espera y se pregunta por qué. Eso es porque si te registras y llamas a un método desde la misma instancia de emacs, entonces emacs esperará a que responda. No está pasando ningún hilo de fantasía, siempre obtendrá una respuesta NoReply en esa situación.

Si tiene que llamar y registrar un método dentro de la instancia mismos emacs puede utilizar dbus-call-method-asynchronously así:

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

(dbus-call-method-asynchronously :session "org.test.emacs" "/helloworld" "org.test.emacs" "hello" 'handle-hello) 
+0

Esta debería ser la respuesta más frecuente. –

+0

Esto es genial. ¿Consideras contribuir con el manual de Emacs Lisp? –

4

Aquí es una manera segura de probar la capacidad de 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))) 

Y aquí hay una forma de enviar una notificación 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"))) 
3

O, simplemente evalúe Te lo siguiente dentro de Emacs:

(info "(dbus)") 
+1

o 'C-h i g (dbus) RET' – phils

Cuestiones relacionadas