From: Jan Moringen <jan.moringen@uni-bielefeld.de>
To: emacs-devel@gnu.org
Subject: DBus methods without name grabbing
Date: Sun, 02 Jan 2011 22:06:04 +0100 [thread overview]
Message-ID: <19384_1294002375_ZZh0g13mCbLkV.00_1294002364.12635.44.camel@gunhead> (raw)
[-- Attachment #1: Type: text/plain, Size: 1072 bytes --]
Hi,
recently I ran into the following DBus-related problem: In order to
write a telepathy client [1], it is required to provide a certain
DBus-Interface under a special well-known name. Some telepathy component
seems to start calling methods immediately after the well-known name is
taken. Since the interface consists of multiple methods/properties, it
cannot be ensured that the interface is completely available when the
name is taken and the first calls are made using Emacs' current
DBus-interface. This is due to the fact that the function
`dbus-register-method' immediately takes the name.
To allow Emacs to work with this kind of DBus-interfaces, I suggest the
changes implemented in the attached patch. I don't known the Emacs C
code well very well, so it probably needs revision.
An example for which this change is necessary can be found in the
function `telepathy-client-register' in the attached file client.el from
my telepathy bindings.
Do you think this patch could be applied?
Kind regards,
Jan
[1] http://telepathy.freedesktop.org/spec/Client.html
[-- Attachment #2: dbus-dont-request-name.diff --]
[-- Type: text/x-patch, Size: 3732 bytes --]
=== modified file 'lisp/net/dbus.el'
--- lisp/net/dbus.el 2010-08-30 13:03:05 +0000
+++ lisp/net/dbus.el 2010-10-03 02:25:51 +0000
@@ -868,7 +868,8 @@
(add-to-list 'result (cons (car dict) (caadr dict)) 'append)))))
(defun dbus-register-property
- (bus service path interface property access value &optional emits-signal)
+ (bus service path interface property access value
+ &optional emits-signal dont-request-name)
"Register property PROPERTY on the D-Bus BUS.
BUS is either a Lisp symbol, `:system' or `:session', or a string
@@ -899,7 +900,8 @@
(signal 'dbus-error (list "Access type invalid" access)))
;; Register SERVICE.
- (unless (member service (dbus-list-names bus))
+ (unless (or dont-request-name
+ (member service (dbus-list-names bus)))
(dbus-call-method
bus dbus-service-dbus dbus-path-dbus dbus-interface-dbus
"RequestName" service 0))
@@ -907,11 +909,14 @@
;; Add the handler. We use `dbus-service-emacs' as service name, in
;; order to let unregister SERVICE despite of this default handler.
(dbus-register-method
- bus service path dbus-interface-properties "Get" 'dbus-property-handler)
+ bus service path dbus-interface-properties "Get" 'dbus-property-handler
+ dont-request-name)
(dbus-register-method
- bus service path dbus-interface-properties "GetAll" 'dbus-property-handler)
+ bus service path dbus-interface-properties "GetAll" 'dbus-property-handler
+ dont-request-name)
(dbus-register-method
- bus service path dbus-interface-properties "Set" 'dbus-property-handler)
+ bus service path dbus-interface-properties "Set" 'dbus-property-handler
+ dont-request-name)
;; Send the PropertiesChanged signal.
(when emits-signal
=== modified file 'src/dbusbind.c'
--- src/dbusbind.c 2010-10-01 13:56:33 +0000
+++ src/dbusbind.c 2010-10-03 02:17:34 +0000
@@ -1947,7 +1947,7 @@
}
DEFUN ("dbus-register-method", Fdbus_register_method, Sdbus_register_method,
- 6, 6, 0,
+ 6, 7, 0,
doc: /* Register for method METHOD on the D-Bus BUS.
BUS is either a Lisp symbol, `:system' or `:session', or a string
@@ -1961,7 +1961,7 @@
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. */)
- (Lisp_Object bus, Lisp_Object service, Lisp_Object path, Lisp_Object interface, Lisp_Object method, Lisp_Object handler)
+ (Lisp_Object bus, Lisp_Object service, Lisp_Object path, Lisp_Object interface, Lisp_Object method, Lisp_Object handler, Lisp_Object dont_request_name)
{
Lisp_Object key, key1, value;
DBusConnection *connection;
@@ -1983,10 +1983,16 @@
/* Request the known name from the bus. We can ignore the result,
it is set to -1 if there is an error - kind of redundancy. */
- dbus_error_init (&derror);
- result = dbus_bus_request_name (connection, SDATA (service), 0, &derror);
- if (dbus_error_is_set (&derror))
- XD_ERROR (derror);
+ if (!dont_request_name || NILP (dont_request_name))
+ {
+ dbus_error_init (&derror);
+ result = dbus_bus_request_name (connection, SDATA (service), 0, &derror);
+ if (dbus_error_is_set (&derror))
+ XD_ERROR (derror);
+
+ /* Cleanup. */
+ dbus_error_free (&derror);
+ }
/* Create a hash table entry. We use nil for the unique name,
because the method might be called from anybody. */
@@ -1997,9 +2003,6 @@
if (NILP (Fmember (key1, value)))
Fputhash (key, Fcons (key1, value), Vdbus_registered_objects_table);
- /* Cleanup. */
- dbus_error_free (&derror);
-
/* Return object. */
return list2 (key, list3 (service, path, handler));
}
[-- Attachment #3: client.el --]
[-- Type: text/x-emacs-lisp, Size: 8494 bytes --]
;;; client.el ---
;;
;; Copyright (C) 2010, 2011 Jan Moringen
;;
;; Author: Jan Moringen <jmoringe@techfak.uni-bielefeld.de>
;; Keywords: telepathy, communication, instant messaging
;;
;; This Program is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.
;;
;; This Program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;;
;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses>.
\f
;;; Commentary:
;;
\f
;;; History:
;;
;; 0.1 - Initial version
\f
;;; Code:
;;
(require 'dbus)
(require 'telepathy/util)
\f
;;;
;;
(defconst telepathy-client-introspection-data
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"
\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">
<node name=\"/org/freedesktop/Telepathy/Client/%s\">
<interface name=\"org.freedesktop.DBus.Introspectable\">
<method name=\"Introspect\">
<arg name=\"data\" direction=\"out\" type=\"s\"/>
</method>
</interface>
<interface name=\"org.freedesktop.DBus.Properties\">
<method name=\"Get\">
<arg name=\"interface\" direction=\"in\" type=\"s\"/>
<arg name=\"propname\" direction=\"in\" type=\"s\"/>
<arg name=\"value\" direction=\"out\" type=\"v\"/>
</method>
<method name=\"Set\">
<arg name=\"interface\" direction=\"in\" type=\"s\"/>
<arg name=\"propname\" direction=\"in\" type=\"s\"/>
<arg name=\"value\" direction=\"in\" type=\"v\"/>
</method>
<method name=\"GetAll\">
<arg name=\"interface\" direction=\"in\" type=\"s\"/>
<arg name=\"props\" direction=\"out\" type=\"a{sv}\"/>
</method>
</interface>
<interface name=\"org.freedesktop.Telepathy.Client.Handler\">
<method name=\"HandleChannels\">
<arg name=\"Account\" type=\"o\" direction=\"in\"/>
<arg name=\"Connection\" type=\"o\" direction=\"in\"/>
<arg name=\"Channels\" type=\"a(oa{sv})\" direction=\"in\"/>
<arg name=\"Requests_Satisfied\" type=\"ao\" direction=\"in\"/>
<arg name=\"User_Action_Time\" type=\"t\" direction=\"in\"/>
<arg name=\"Handler_Info\" type=\"a{sv}\" direction=\"in\"/>
</method>
</interface>
</node>"
"")
\f
;;;
;;
(defvar telepathy-client-handlers (make-hash-table :test 'equal)
"")
(defun telepathy-client-handler-services ()
""
(let ((result))
(maphash (lambda (key value) (push key result))
telepathy-client-handlers)
result))
(defun telepathy-client-add-handler (service handler &optional client)
""
(unless client
(setq client "Emacs"))
(unless (zerop (hash-table-count telepathy-client-handlers))
(telepathy-client-unregister client))
(puthash service handler telepathy-client-handlers)
(telepathy-client-register client))
(defun telepathy-client-remove-handler (service &optional client)
""
(unless client
(setq client "Emacs"))
(unless (zerop (hash-table-count telepathy-client-handlers))
(telepathy-client-unregister client))
(remhash service telepathy-client-handlers)
(unless (zerop (hash-table-count telepathy-client-handlers))
(telepathy-client-register client)))
\f
;;;
;;
(defun telepath-client-channel-handler (account connection-path channels &rest args)
""
(dolist (channel-data channels)
(let* ((connection (telepathy-make-remote-proxy-from-path
:session connection-path))
;; Analyze the properties of the channel.
(channel-properties (second channel-data))
(contact-handle (telepathy-prop-get
telepathy-key-target-handle channel-properties))
(contact (telepathy-make-contact
connection contact-handle))
(service (telepathy-prop-get
telepathy-key-service channel-properties))
(handler (gethash service telepathy-client-handlers))
;; Obtain object path of channel object.
(channel-path (first channel-data))
(channel-service (let ((bla (telepathy-path->service channel-path)))
(substring bla 0 (position ?. bla :from-end t))))
(channel-object (dbus-proxy-make-remote-proxy
:session channel-service channel-path
nil 'telepathy-tube))) ;; TODO could be a different kind of channel
(oset channel-object :contact contact)
(message "Channel")
(message " Path %s" channel-path)
(message " Service %s" service)
(message " Contact %s" contact)
(funcall handler channel-object)))
:ignore)
(defun telepathy-client-register (name)
""
;; Create a DBus object to handle tube requests.
(let ((service (format "org.freedesktop.Telepathy.Client.%s" name))
(path (format "/org/freedesktop/Telepathy/Client/%s" name)))
;; Install introspection information.
(lexical-let ((introspection-data
(format telepathy-client-introspection-data name)))
(dbus-register-method
:session service path
"org.freedesktop.DBus.Introspectable"
"Introspect"
(lambda (&rest args) introspection-data)
t)) ;; don't request the name, yet
;; Register all properties belonging to the handler object.
(dolist (name-and-value `(("HandlerChannelFilter"
,(mapcar
#'telepathy-client-make-channel-filter
(telepathy-client-handler-services)))
("BypassApproval" t) ;; TODO was nil
("Capabilities" (:array :signature "as"))
("HandledChannels" (:array :signature "ao"))))
(destructuring-bind (name value) name-and-value
(dbus-register-property
:session service path
"org.freedesktop.Telepathy.Client.Handler"
name :read value nil t))) ;; don't request the name, yet
;; TODO store the dbus objects for unregistering?
(dbus-register-method
:session service path
"org.freedesktop.Telepathy.Client.Handler"
"HandleChannels" #'telepath-client-channel-handler
t) ;; don't request the name, yet
(dbus-register-property
:session service path
"org.freedesktop.Telepathy.Client"
"Interfaces"
:read
'("org.freedesktop.Telepathy.Client.Handler")
nil t) ;; don't request the name, yet
;; Now that everything is in place, request the name.
(dbus-call-method
:session dbus-service-dbus dbus-path-dbus dbus-interface-dbus
"RequestName" service 0)))
;; (/org/freedesktop/Telepathy/Connection/gabble/jabber/scymtym_2dtest_40jabber_2eorg_2fbe153d1c/StreamTubeChannel_2_1273735221
;; ((org.freedesktop.Telepathy.Channel.InitiatorID
;; (scymtym@jabber.org))
;; (org.freedesktop.Telepathy.Channel.TargetHandleType
;; (1))
;; (org.freedesktop.Telepathy.Channel.TargetHandle
;; (2))
;; (org.freedesktop.Telepathy.Channel.TargetID
;; (scymtym@jabber.org))
;; (org.freedesktop.Telepathy.Channel.Requested
;; (nil))
;; (org.freedesktop.Telepathy.Channel.Type.StreamTube.SupportedSocketTypes
;; (((0 (0 3)) (2 (0 1)) (3 (0 1)))))
;; (org.freedesktop.Telepathy.Channel.Type.StreamTube.Service
;; (org.gnu.emacs.rudel.announce))
;; (org.freedesktop.Telepathy.Channel.Interface.Tube.Parameters
;; (nil))
;; (org.freedesktop.Telepathy.Channel.ChannelType
;; (org.freedesktop.Telepathy.Channel.Type.StreamTube))
;; (org.freedesktop.Telepathy.Channel.InitiatorHandle
;; (2))
;; (org.freedesktop.Telepathy.Channel.Interfaces
;; ((org.freedesktop.Telepathy.Channel.Interface.Tube)))))
(defun telepathy-client-unregister (name)
""
(dbus-unregister-service
:session
(format "org.freedesktop.Telepathy.Client.%s" name)))
\f
;;; Helper functions
;;
(defun telepathy-client-make-channel-filter (service)
""
`((:dict-entry
"org.freedesktop.Telepathy.Channel.ChannelType"
(:variant :string "org.freedesktop.Telepathy.Channel.Type.StreamTube"))
(:dict-entry
"org.freedesktop.Telepathy.Channel.TargetHandleType"
(:variant :uint32 1))
(:dict-entry
"org.freedesktop.Telepathy.Channel.Requested"
(:variant :boolean nil))
(:dict-entry
"org.freedesktop.Telepathy.Channel.Type.StreamTube.Service"
(:variant :string ,service))
))
(provide 'telepathy/client)
;;; client.el ends here
next reply other threads:[~2011-01-02 21:06 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2011-01-02 21:06 Jan Moringen [this message]
2011-01-03 12:55 ` DBus methods without name grabbing Michael Albinus
2011-01-04 2:42 ` Jan Moringen
2011-01-04 10:10 ` Michael Albinus
2011-01-04 10:29 ` Jan Moringen
2011-01-04 13:09 ` Michael Albinus
2011-01-05 4:17 ` Jan Moringen
2011-01-05 11:45 ` Michael Albinus
2011-01-08 5:48 ` Jan Moringen
2011-01-09 9:42 ` Michael Albinus
2011-01-09 16:08 ` Jan Moringen
2011-01-10 11:40 ` Michael Albinus
[not found] ` <1294201048.2508.1.camel@gunhead>
2011-01-05 10:46 ` Jan Moringen
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: https://www.gnu.org/software/emacs/
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=19384_1294002375_ZZh0g13mCbLkV.00_1294002364.12635.44.camel@gunhead \
--to=jan.moringen@uni-bielefeld.de \
--cc=emacs-devel@gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://git.savannah.gnu.org/cgit/emacs.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).