Я просмотрел пакет dbus, и кажется, что все функции встроены в исходный код C, и для них нет документации.
Как использовать функцию dbus-call-method
?
Я просмотрел пакет dbus, и кажется, что все функции встроены в исходный код C, и для них нет документации.
Как использовать функцию dbus-call-method
?
Google на помощь... Следуйте ссылке для примера, это не мой код, поэтому я не стану его здесь.
http://emacs-fu.blogspot.com/2009/01/using-d-bus-example.html
У меня была одна и та же проблема, и я нашел статью emacs-fu, которая появляется, когда поиск в Google слишком прост для моих нужд.
В частности, я хотел экспортировать свои собственные методы elisp через dbus и имел проблемы с пониманием терминологии 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, как и настольное приложение, я полагаю).
СЕРВИС - это уникальное имя для приложения на шине, например адрес или доменное имя. Dbus.el определяет dbus-service-emacs
как "org.gnu.Emacs".
PATH относится к различным типам приложений, что SERVICE относится к разным приложениям. Например, определенный модуль emacs может выставить функциональность в /PATH модуля в службе org.gnu.Emacs SERVICE.
ИНТЕРФЕЙС - это как интерфейс в программировании. Это спецификация, которая сообщает другим клиентам dbus, как взаимодействовать с объектом (объектами), которое предоставляет ваша приложение. Он содержит, например, подписи типов для ваших методов. Таким образом, у вас может быть интерфейс, который говорит что-то вроде: под сервисом org.gnu.Emacs в пути /ModuleName вы найдете метод с именем helloworld, который примет нулевые аргументы и вернет строку.
Трудная вещь для меня выяснить: как определить интерфейс для моего метода?
Выбирая dbus.el, вы обнаружите, что существует dbus-interface-introspectable
(среди прочего), который содержит строку "org.freedesktop.DBus.Introspectable", которая называет стандартный интерфейс, который только предоставляет один метод:
org.freedesktop.DBus.Introspectable.Introspect (out STRING xml_data)
(ссылка на spec 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 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" ). Вы можете использовать его именно так и попытаться вызвать метод 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)
Там мы идем. Мы просто определяем два метода 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
Ура, работает так, как ожидалось, без зависания или ошибок 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)
Вот безопасный способ тестирования возможностей 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")))
Или просто оцените следующее в Emacs:
(info "(dbus)")