changeset 87051:1da959e791de

* dbusbind.c (QCdbus_system_bus, QCdbus_session_bus): Renamed from Qdbus_system_bus and Qdbus_session_bus, respectively. (Vdbus_intern_symbols): Removed. (Vdbus_registered_functions_table): New hash table. (XD_SYMBOL_INTERN_SYMBOL): Removed. (xd_read_message, Fdbus_register_signal, Fdbus_unregister_signal): Rewritten in order to manage registered functions by hash table Vdbus_registered_functions_table.
author Michael Albinus <michael.albinus@gmx.de>
date Tue, 04 Dec 2007 21:29:40 +0000
parents 7d80e0f3d8f8
children dbc80c914a6f
files src/ChangeLog src/dbusbind.c
diffstat 2 files changed, 105 insertions(+), 108 deletions(-) [+]
line wrap: on
line diff
--- a/src/ChangeLog	Tue Dec 04 21:21:09 2007 +0000
+++ b/src/ChangeLog	Tue Dec 04 21:29:40 2007 +0000
@@ -1,3 +1,14 @@
+2007-12-04  Michael Albinus  <michael.albinus@gmx.de>
+
+	* dbusbind.c (QCdbus_system_bus, QCdbus_session_bus): Renamed from
+	Qdbus_system_bus and Qdbus_session_bus, respectively.
+	(Vdbus_intern_symbols): Removed.
+	(Vdbus_registered_functions_table): New hash table.
+	(XD_SYMBOL_INTERN_SYMBOL): Removed.
+	(xd_read_message, Fdbus_register_signal, Fdbus_unregister_signal):
+	Rewritten in order to manage registered functions by hash table
+	Vdbus_registered_functions_table.
+
 2007-12-03  Jan Dj,Ad(Brv  <jan.h.d@swipnet.se>
 
 	* xterm.c: Update URL to Window Manager Specification in comment.
--- a/src/dbusbind.c	Tue Dec 04 21:21:09 2007 +0000
+++ b/src/dbusbind.c	Tue Dec 04 21:29:40 2007 +0000
@@ -40,10 +40,10 @@
 Lisp_Object Qdbus_error;
 
 /* Lisp symbols of the system and session buses.  */
-Lisp_Object Qdbus_system_bus, Qdbus_session_bus;
+Lisp_Object QCdbus_system_bus, QCdbus_session_bus;
 
-/* Obarray which keeps interned symbols.  */
-Lisp_Object Vdbus_intern_symbols;
+/* Hash table which keeps function definitions.  */
+Lisp_Object Vdbus_registered_functions_table;
 
 /* Whether to debug D-Bus.  */
 Lisp_Object Vdbus_debug;
@@ -52,41 +52,6 @@
 /* We use "xd_" and "XD_" as prefix for all internal symbols, because
    we don't want to poison other namespaces with "dbus_".  */
 
-/* Create a new interned symbol which represents a function handler.
-   bus is a Lisp symbol, either :system or :session.  interface and
-   member are both Lisp strings.
-
-   D-Bus sends messages, which are captured by Emacs in the main loop,
-   converted into an event then.  Emacs must identify a message from
-   D-Bus, in order to call the right Lisp function when the event is
-   handled in the event handler function of dbus.el.
-
-   A D-Bus message is determined at least by the D-Bus bus it is
-   raised from (system bus or session bus), the interface and the
-   method the message belongs to.  There could be even more properties
-   for determination, but that isn't implemented yet.
-
-   The approach is to create a new interned Lisp symbol once there is
-   a registration request for a given signal, which is a special D-Bus
-   message.  The symbol's name is a concatenation of the bus name,
-   interface name and method name of the signal; the function cell is
-   the Lisp function to be called when such a signal arrives.  Since
-   this code runs in the main loop, receiving input, it must be
-   performant.  */
-#define XD_SYMBOL_INTERN_SYMBOL(symbol, bus, interface, member)	\
-  {								\
-    XD_DEBUG_VALID_LISP_OBJECT_P (bus);				\
-    XD_DEBUG_VALID_LISP_OBJECT_P (interface);			\
-    XD_DEBUG_VALID_LISP_OBJECT_P (member);			\
-    char s[1024];						\
-    strcpy (s, SDATA (SYMBOL_NAME (bus)));			\
-    strcat (s, ".");						\
-    strcat (s, SDATA (interface));				\
-    strcat (s, ".");						\
-    strcat (s, SDATA (member));					\
-    symbol = Fintern (build_string (s), Vdbus_intern_symbols);	\
-  }
-
 /* Raise a Lisp error from a D-Bus error.  */
 #define XD_ERROR(error)							\
   {									\
@@ -248,13 +213,13 @@
 
   /* Parameter check.  */
   CHECK_SYMBOL (bus);
-  if (!((EQ (bus, Qdbus_system_bus)) ||	(EQ (bus, Qdbus_session_bus))))
+  if (!((EQ (bus, QCdbus_system_bus)) || (EQ (bus, QCdbus_session_bus))))
     xsignal2 (Qdbus_error, build_string ("Wrong bus name"), bus);
 
   /* Open a connection to the bus.  */
   dbus_error_init (&derror);
 
-  if (EQ (bus, Qdbus_system_bus))
+  if (EQ (bus, QCdbus_system_bus))
     connection = dbus_bus_get (DBUS_BUS_SYSTEM, &derror);
   else
     connection = dbus_bus_get (DBUS_BUS_SESSION, &derror);
@@ -577,14 +542,20 @@
 xd_read_message (bus)
      Lisp_Object bus;
 {
-  Lisp_Object symbol;
+  Lisp_Object key;
   struct gcpro gcpro1;
   static struct input_event event;
   DBusConnection *connection;
   DBusMessage *dmessage;
   DBusMessageIter iter;
   uint dtype;
-  char s1[1024], s2[1024];
+  char service[1024], path[1024], interface[1024], member[1024];
+
+  /* Vdbus_registered_functions_table will be made as hash table in
+     dbus.el.  When it isn't loaded yet, it doesn't make sense to
+     handle D-Bus messages.  */
+  if (!HASH_TABLE_P (Vdbus_registered_functions_table))
+    return;
 
   /* Open a connection to the bus.  */
   connection = xd_initialize (bus);
@@ -625,23 +596,32 @@
   /* The arguments are stored in reverse order.  Reorder them.  */
   event.arg = Fnreverse (event.arg);
 
-  /* Add the object path of the sender of the message.  */
-  strcpy (s1, dbus_message_get_path (dmessage));
-  event.arg = Fcons ((s1 == NULL ? Qnil : build_string (s1)), event.arg);
-
-  /* Add the unique name of the sender of the message.  */
-  strcpy (s2, dbus_message_get_sender (dmessage));
-  event.arg = Fcons ((s2 == NULL ? Qnil : build_string (s2)), event.arg);
+  /* Read service, object path interface and member from the
+     message.  */
+  strcpy (service,   dbus_message_get_sender (dmessage));
+  strcpy (path,      dbus_message_get_path (dmessage));
+  strcpy (interface, dbus_message_get_interface (dmessage));
+  strcpy (member,    dbus_message_get_member (dmessage));
 
-  /* Add the interned symbol the message is raised from (signal) or
-     for (method).  */
-  strcpy (s1, dbus_message_get_interface (dmessage));
-  strcpy (s2, dbus_message_get_member (dmessage));
-  XD_SYMBOL_INTERN_SYMBOL
-    (symbol, bus,
-     (s1 == NULL ? Qnil : build_string (s1)),
-     (s2 == NULL ? Qnil : build_string (s2)));
-  event.arg = Fcons (symbol, event.arg);
+  /* Add them to the event.  */
+  event.arg = Fcons ((member == NULL ? Qnil : build_string (member)),
+		     event.arg);
+  event.arg = Fcons ((interface == NULL ? Qnil : build_string (interface)),
+		     event.arg);
+  event.arg = Fcons ((path == NULL ? Qnil : build_string (path)),
+		     event.arg);
+  event.arg = Fcons ((service == NULL ? Qnil : build_string (service)),
+		     event.arg);
+
+  /* Add the bus symbol to the event.  */
+  event.arg = Fcons (bus, event.arg);
+
+  /* Add the registered function of the message.  */
+  key = list3 (bus,
+	       (interface == NULL ? Qnil : build_string (interface)),
+	       (member == NULL ? Qnil : build_string (member)));
+  event.arg = Fcons (Fgethash (key, Vdbus_registered_functions_table, Qnil),
+		     event.arg);
 
   /* Store it into the input event queue.  */
   kbd_buffer_store_event (&event);
@@ -655,8 +635,8 @@
 void
 xd_read_queued_messages ()
 {
-  xd_read_message (Qdbus_system_bus);
-  xd_read_message (Qdbus_session_bus);
+  xd_read_message (QCdbus_system_bus);
+  xd_read_message (QCdbus_session_bus);
 }
 
 DEFUN ("dbus-register-signal", Fdbus_register_signal, Sdbus_register_signal,
@@ -665,85 +645,81 @@
 
 BUS is either the symbol `:system' or the symbol `:session'.
 
-SERVICE is the D-Bus service name to be used.  PATH is the D-Bus
-object path SERVICE is registered.  INTERFACE is an interface offered
-by SERVICE.  It must provide SIGNAL.
+SERVICE is the D-Bus service name used by the sending D-Bus object.
+It can be either a known name or the unique name of the D-Bus object
+sending the signal.  When SERVICE is nil, related signals from all
+D-Bus objects shall be accepted.
 
+PATH is the D-Bus object path SERVICE is registered.  It can also be
+nil if the path name of incoming signals shall not be checked.
+
+INTERFACE is an interface offered by SERVICE.  It must provide SIGNAL.
 HANDLER is a Lisp function to be called when the signal is received.
-It must accept as arguments the values SIGNAL is sending.
-
-Example:
+It must accept as arguments the values SIGNAL is sending.  INTERFACE,
+SIGNAL and HANDLER must not be nil.  Example:
 
 \(defun my-signal-handler (device)
   (message "Device %s added" device))
 
 \(dbus-register-signal
-  :system "DeviceAdded" "org.freedesktop.Hal"
+  :system "DeviceAdded"
+  (dbus-get-name-owner :system "org.freedesktop.Hal")
   "/org/freedesktop/Hal/Manager" "org.freedesktop.Hal.Manager"
   'my-signal-handler)
 
-  => org.freedesktop.Hal.Manager.DeviceAdded
+  => (:system "org.freedesktop.Hal.Manager" "DeviceAdded")
 
 `dbus-register-signal' returns an object, which can be used in
 `dbus-unregister-signal' for removing the registration.  */)
      (bus, signal, service, path, interface, handler)
      Lisp_Object bus, signal, service, path, interface, handler;
 {
-  Lisp_Object name_owner, result;
+  Lisp_Object key;
   DBusConnection *connection;
+  char rule[1024];
   DBusError derror;
-  char rule[1024];
 
   /* Check parameters.  */
   CHECK_SYMBOL (bus);
   CHECK_STRING (signal);
-  CHECK_STRING (service);
-  CHECK_STRING (path);
+  if (!NILP (service)) CHECK_STRING (service);
+  if (!NILP (path)) CHECK_STRING (path);
   CHECK_STRING (interface);
   CHECK_SYMBOL (handler);
 
   /* Open a connection to the bus.  */
   connection = xd_initialize (bus);
 
-#if 0
-  /* TODO: Get name owner.  This is the sending service name.  */
-  name_owner = call2 (intern ("dbus-get-name-owner"), bus, service);
-#endif
-
-  /* Add a rule to the bus in order to receive related signals.  */
-  dbus_error_init (&derror);
+  /* Create a rule to receive related signals.  */
   sprintf (rule,
 	   "type='signal',interface='%s',member=%s%",
 	   SDATA (interface),
 	   SDATA (signal));
-#if 0
-  /* TODO: We need better checks when we want use sender and path.  */
-  sprintf (rule,
-	   "type='signal',sender='%s',path='%s',interface='%s',member=%s%",
-	   SDATA (name_owner),
-	   SDATA (path),
-	   SDATA (interface),
-	   SDATA (signal));
-#endif
+
+  /* Add service and path to the rule if they are non-nil.  */
+  if (!NILP (service))
+    sprintf (rule, "%s,sender='%s'%", rule, SDATA (service));
+
+  if (!NILP (path))
+    sprintf (rule, "%s,path='%s'", rule, SDATA (path));
+
+  /* Add the rule to the bus.  */
+  dbus_error_init (&derror);
   dbus_bus_add_match (connection, rule, &derror);
-
   if (dbus_error_is_set (&derror))
     XD_ERROR (derror);
 
   XD_DEBUG_MESSAGE ("Matching rule \"%s\" created", rule);
 
-  /* Create a new protected symbol, which has the complete name of the
-     signal.  The function cell is taken from the handler.  */
-  result = Qnil;
+  /* Create a hash table entry.  */
+  key = list3 (bus, interface, signal);
+  Fputhash (key, handler, Vdbus_registered_functions_table);
+  XD_DEBUG_MESSAGE ("\"%s\" registered with handler \"%s\"",
+		    SDATA (format2 ("%s", key, Qnil)),
+		    SDATA (format2 ("%s", handler, Qnil)));
 
-  XD_SYMBOL_INTERN_SYMBOL (result, bus, interface, signal);
-  Ffset (result, Fsymbol_function (handler));
-  XD_DEBUG_MESSAGE ("\"%s\" registered with handler \"%s\"",
-		    SDATA (format2 ("%s", result, Qnil)),
-		    SDATA (format2 ("%s", Fsymbol_function (result), Qnil)));
-
-  /* Return.  */
-  return result;
+  /* Return key.  */
+  return key;
 }
 
 DEFUN ("dbus-unregister-signal", Fdbus_unregister_signal, Sdbus_unregister_signal,
@@ -762,7 +738,7 @@
 		    SDATA (format2 ("%s", Fsymbol_function (object), Qnil)));
 
   /* Unintern the signal symbol.  */
-  Funintern (object, Vdbus_intern_symbols);
+  Fremhash (object, Vdbus_registered_functions_table);
 
   /* Return.  */
   return Qnil;
@@ -800,17 +776,27 @@
   Fput (Qdbus_error, Qerror_message,
 	build_string ("D-Bus error"));
 
-  Qdbus_system_bus = intern (":system");
-  staticpro (&Qdbus_system_bus);
+  QCdbus_system_bus = intern (":system");
+  staticpro (&QCdbus_system_bus);
+
+  QCdbus_session_bus = intern (":session");
+  staticpro (&QCdbus_session_bus);
 
-  Qdbus_session_bus = intern (":session");
-  staticpro (&Qdbus_session_bus);
+  DEFVAR_LISP ("dbus-registered-functions-table", &Vdbus_registered_functions_table,
+    doc: /* Hash table of registered functions for D-Bus.
+The key in the hash table is the list (BUS INTERFACE MEMBER).  BUS is
+either the symbol `:system' or the symbol `:session'.  INTERFACE is a
+string which denotes a D-Bus interface, and MEMBER, also a string, is
+either a method or a signal INTERFACE is offering.
 
-  Vdbus_intern_symbols = Fmake_vector (make_number (64), 0);
-  staticpro (&Vdbus_intern_symbols);
+The value in the hash table a the function to be called when a D-Bus
+message, which matches the key criteria, arrives.  */);
+  /* We initialize Vdbus_registered_functions_table in dbus.el,
+     because we need to define a hash table function first.  */
+  Vdbus_registered_functions_table = Qnil;
 
   DEFVAR_LISP ("dbus-debug", &Vdbus_debug,
-	       doc: /* If non-nil, debug messages of D-Bus bindings are raised.  */);
+    doc: /* If non-nil, debug messages of D-Bus bindings are raised.  */);
 #ifdef DBUS_DEBUG
   Vdbus_debug = Qt;
 #else