dbus/glib Makefile.am, 1.10, 1.11 dbus-gmarshal.c, NONE, 1.1 dbus-gmarshal.h, NONE, 1.1 dbus-gmarshal.list, NONE, 1.1 dbus-gproxy.c, 1.16, 1.17

Havoc Pennington hp at freedesktop.org
Sun Jan 30 18:55:14 PST 2005


Update of /cvs/dbus/dbus/glib
In directory gabe:/tmp/cvs-serv30297/glib

Modified Files:
	Makefile.am dbus-gproxy.c 
Added Files:
	dbus-gmarshal.c dbus-gmarshal.h dbus-gmarshal.list 
Log Message:
2005-01-30  Havoc Pennington  <hp at redhat.com>

	* tools/dbus-names-model.c: dynamically watch NameOwnerChanged

	* autogen.sh: change to autotools 1.9

	* glib/dbus-gproxy.c: completely change how signals work
	(dbus_g_proxy_add_signal): new function to specify signature of a
	signal
	(dbus_g_proxy_emit_received): marshal the dbus message to GValues,
	and g_warning if the incoming message has the wrong signature.



Index: Makefile.am
===================================================================
RCS file: /cvs/dbus/dbus/glib/Makefile.am,v
retrieving revision 1.10
retrieving revision 1.11
diff -u -d -r1.10 -r1.11
--- Makefile.am	29 Jan 2005 19:52:19 -0000	1.10
+++ Makefile.am	31 Jan 2005 02:55:12 -0000	1.11
@@ -5,6 +5,8 @@
 libdbus_glib_1_la_SOURCES = 			\
 	dbus-glib.c				\
 	dbus-gmain.c				\
+	dbus-gmarshal.c				\
+	dbus-gmarshal.h				\
 	dbus-gobject.c				\
 	dbus-gproxy.c				\
 	dbus-gtest.c				\
@@ -41,6 +43,15 @@
 
 dbus_binding_tool_LDADD= -lexpat libdbus-gtool.la
 
+## we just rebuilt these manually and check them into cvs; easier than
+## convincing automake/make to do this properly
+regenerate-built-sources:
+	@GLIB_GENMARSHAL@ --prefix=_dbus_g_marshal dbus-gmarshal.list --header > dbus-gmarshal.h && \
+	echo '#include "dbus-gmarshal.h"' > dbus-gmarshal.c &&					    \
+        @GLIB_GENMARSHAL@ --prefix=_dbus_g_marshal dbus-gmarshal.list --body >> dbus-gmarshal.c
+
+EXTRA_DIST=dbus-gmarshal.list
+
 if DBUS_BUILD_TESTS
 
 ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we

--- NEW FILE: dbus-gmarshal.c ---
#include "dbus-gmarshal.h"

#include	<glib-object.h>


#ifdef G_ENABLE_DEBUG
#define g_marshal_value_peek_boolean(v)  g_value_get_boolean (v)
#define g_marshal_value_peek_char(v)     g_value_get_char (v)
#define g_marshal_value_peek_uchar(v)    g_value_get_uchar (v)
#define g_marshal_value_peek_int(v)      g_value_get_int (v)
#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
#define g_marshal_value_peek_long(v)     g_value_get_long (v)
#define g_marshal_value_peek_ulong(v)    g_value_get_ulong (v)
#define g_marshal_value_peek_int64(v)    g_value_get_int64 (v)
#define g_marshal_value_peek_uint64(v)   g_value_get_uint64 (v)
#define g_marshal_value_peek_enum(v)     g_value_get_enum (v)
#define g_marshal_value_peek_flags(v)    g_value_get_flags (v)
#define g_marshal_value_peek_float(v)    g_value_get_float (v)
#define g_marshal_value_peek_double(v)   g_value_get_double (v)
#define g_marshal_value_peek_string(v)   (char*) g_value_get_string (v)
#define g_marshal_value_peek_param(v)    g_value_get_param (v)
#define g_marshal_value_peek_boxed(v)    g_value_get_boxed (v)
#define g_marshal_value_peek_pointer(v)  g_value_get_pointer (v)
#define g_marshal_value_peek_object(v)   g_value_get_object (v)
#else /* !G_ENABLE_DEBUG */
/* WARNING: This code accesses GValues directly, which is UNSUPPORTED API.
 *          Do not access GValues directly in your code. Instead, use the
 *          g_value_get_*() functions
 */
#define g_marshal_value_peek_boolean(v)  (v)->data[0].v_int
#define g_marshal_value_peek_char(v)     (v)->data[0].v_int
#define g_marshal_value_peek_uchar(v)    (v)->data[0].v_uint
#define g_marshal_value_peek_int(v)      (v)->data[0].v_int
#define g_marshal_value_peek_uint(v)     (v)->data[0].v_uint
#define g_marshal_value_peek_long(v)     (v)->data[0].v_long
#define g_marshal_value_peek_ulong(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_int64(v)    (v)->data[0].v_int64
#define g_marshal_value_peek_uint64(v)   (v)->data[0].v_uint64
#define g_marshal_value_peek_enum(v)     (v)->data[0].v_long
#define g_marshal_value_peek_flags(v)    (v)->data[0].v_ulong
#define g_marshal_value_peek_float(v)    (v)->data[0].v_float
#define g_marshal_value_peek_double(v)   (v)->data[0].v_double
#define g_marshal_value_peek_string(v)   (v)->data[0].v_pointer
#define g_marshal_value_peek_param(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_boxed(v)    (v)->data[0].v_pointer
#define g_marshal_value_peek_pointer(v)  (v)->data[0].v_pointer
#define g_marshal_value_peek_object(v)   (v)->data[0].v_pointer
#endif /* !G_ENABLE_DEBUG */


/* NONE:STRING,STRING,STRING (dbus-gmarshal.list:1) */
void
_dbus_g_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
                                            GValue       *return_value,
                                            guint         n_param_values,
                                            const GValue *param_values,
                                            gpointer      invocation_hint,
                                            gpointer      marshal_data)
{
  typedef void (*GMarshalFunc_VOID__STRING_STRING_STRING) (gpointer     data1,
                                                           gpointer     arg_1,
                                                           gpointer     arg_2,
                                                           gpointer     arg_3,
                                                           gpointer     data2);
  register GMarshalFunc_VOID__STRING_STRING_STRING callback;
  register GCClosure *cc = (GCClosure*) closure;
  register gpointer data1, data2;

  g_return_if_fail (n_param_values == 4);

  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = g_value_peek_pointer (param_values + 0);
    }
  else
    {
      data1 = g_value_peek_pointer (param_values + 0);
      data2 = closure->data;
    }
  callback = (GMarshalFunc_VOID__STRING_STRING_STRING) (marshal_data ? marshal_data : cc->callback);

  callback (data1,
            g_marshal_value_peek_string (param_values + 1),
            g_marshal_value_peek_string (param_values + 2),
            g_marshal_value_peek_string (param_values + 3),
            data2);
}


--- NEW FILE: dbus-gmarshal.h ---

#ifndef ___dbus_g_marshal_MARSHAL_H__
#define ___dbus_g_marshal_MARSHAL_H__

#include	<glib-object.h>

G_BEGIN_DECLS

/* NONE:STRING,STRING,STRING (dbus-gmarshal.list:1) */
extern void _dbus_g_marshal_VOID__STRING_STRING_STRING (GClosure     *closure,
                                                        GValue       *return_value,
                                                        guint         n_param_values,
                                                        const GValue *param_values,
                                                        gpointer      invocation_hint,
                                                        gpointer      marshal_data);
#define _dbus_g_marshal_NONE__STRING_STRING_STRING	_dbus_g_marshal_VOID__STRING_STRING_STRING

G_END_DECLS

#endif /* ___dbus_g_marshal_MARSHAL_H__ */


--- NEW FILE: dbus-gmarshal.list ---
NONE:STRING,STRING,STRING

Index: dbus-gproxy.c
===================================================================
RCS file: /cvs/dbus/dbus/glib/dbus-gproxy.c,v
retrieving revision 1.16
retrieving revision 1.17
diff -u -d -r1.16 -r1.17
--- dbus-gproxy.c	30 Jan 2005 23:06:32 -0000	1.16
+++ dbus-gproxy.c	31 Jan 2005 02:55:12 -0000	1.17
@@ -23,6 +23,8 @@
 #include <dbus/dbus-glib.h>
 #include <dbus/dbus-glib-lowlevel.h>
 #include "dbus-gutils.h"
+#include "dbus-gmarshal.h"
+#include "dbus-gvalue.h"
 #include <string.h>
 
 /**
@@ -48,6 +50,8 @@
   char *name;                 /**< Name messages go to or NULL */
   char *path;                 /**< Path messages go to or NULL */
   char *interface;            /**< Interface messages go to or NULL */
+
+  GData *signal_signatures;   /**< D-BUS signatures for each signal */
 };
 
 /**
@@ -58,14 +62,13 @@
   GObjectClass parent_class;  /**< Parent class */
 };
 
-static void dbus_g_proxy_init          (DBusGProxy      *proxy);
-static void dbus_g_proxy_class_init    (DBusGProxyClass *klass);
-static void dbus_g_proxy_finalize      (GObject         *object);
-static void dbus_g_proxy_dispose       (GObject         *object);
-static void dbus_g_proxy_destroy       (DBusGProxy      *proxy);
-static void dbus_g_proxy_emit_received (DBusGProxy      *proxy,
-                                       DBusMessage     *message);
-
+static void dbus_g_proxy_init               (DBusGProxy      *proxy);
+static void dbus_g_proxy_class_init         (DBusGProxyClass *klass);
+static void dbus_g_proxy_finalize           (GObject         *object);
+static void dbus_g_proxy_dispose            (GObject         *object);
+static void dbus_g_proxy_destroy            (DBusGProxy      *proxy);
+static void dbus_g_proxy_emit_remote_signal (DBusGProxy      *proxy,
+                                             DBusMessage     *message);
 
 /**
  * A list of proxies with a given name+path+interface, used to
@@ -641,7 +644,7 @@
               proxy = DBUS_G_PROXY (tmp->data);
 
               UNLOCK_MANAGER (manager);
-              dbus_g_proxy_emit_received (proxy, message);
+              dbus_g_proxy_emit_remote_signal (proxy, message);
               g_object_unref (G_OBJECT (proxy));
               LOCK_MANAGER (manager);
               
@@ -670,7 +673,6 @@
 enum
 {
   DESTROY,
-  RECEIVED,
   LAST_SIGNAL
 };
 
@@ -680,7 +682,7 @@
 static void
 dbus_g_proxy_init (DBusGProxy *proxy)
 {
-  /* Nothing */
+  g_datalist_init (&proxy->signal_signatures);
 }
 
 static void
@@ -701,16 +703,6 @@
 		  NULL, NULL,
                   g_cclosure_marshal_VOID__VOID,
 		  G_TYPE_NONE, 0);
-  
-  signals[RECEIVED] =
-    g_signal_new ("received",
-		  G_OBJECT_CLASS_TYPE (object_class),
-		  G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
-                  0,
-		  NULL, NULL,
-                  g_cclosure_marshal_VOID__BOXED,
-		  G_TYPE_NONE, 1,
-                  DBUS_TYPE_MESSAGE);
 }
 
 
@@ -721,6 +713,8 @@
 
   proxy = DBUS_G_PROXY (object);
 
+  g_datalist_clear (&proxy->signal_signatures);
+  
   g_signal_emit (object, signals[DESTROY], 0);
   
   G_OBJECT_CLASS (parent_class)->dispose (object);
@@ -755,28 +749,102 @@
   g_object_run_dispose (G_OBJECT (proxy));
 }
 
+/* this is to avoid people using g_signal_connect() directly,
+ * to avoid confusion with local signal names, and because
+ * of the horribly broken current setup (signals are added
+ * globally to all proxies)
+ */
 static char*
-create_signal_detail (const char *interface,
-                      const char *signal)
+create_signal_name (const char *interface,
+                    const char *signal)
 {
   GString *str;
+  char *p;
 
   str = g_string_new (interface);
 
-  g_string_append (str, ".");
-
+  g_string_append (str, "-");
+  
   g_string_append (str, signal);
 
+  /* GLib will silently barf on '.' in signal names */
+  p = str->str;
+  while (*p)
+    {
+      if (*p == '.')
+        *p = '-';
+      ++p;
+    }
+  
   return g_string_free (str, FALSE);
 }
 
 static void
-dbus_g_proxy_emit_received (DBusGProxy  *proxy,
-                           DBusMessage *message)
+emit_remote_internal (DBusGProxy  *proxy,
+                      DBusMessage *message,
+                      guint        signal_id,
+                      gboolean     marshal_args)
+{
+#define MAX_SIGNATURE_ARGS 20
+  GValue values[MAX_SIGNATURE_ARGS];
+  int arg;
+  int i;
+
+  memset (&values[0], 0, sizeof (values));
+  
+  arg = 0;
+      
+  g_value_init (&values[arg], G_TYPE_FROM_INSTANCE (proxy));
+  g_value_set_instance (&values[arg], proxy);
+  ++arg;
+
+  if (marshal_args)
+    {
+      DBusMessageIter iter;
+      int dtype;
+
+      dbus_message_iter_init (message, &iter);
+      
+      while ((dtype = dbus_message_iter_get_arg_type (&iter)) != DBUS_TYPE_INVALID)
+        {
+          if (arg == MAX_SIGNATURE_ARGS)
+            {
+              g_warning ("Don't support more than %d signal args\n", MAX_SIGNATURE_ARGS);
+              goto out;
+            }
+          
+          if (!dbus_gvalue_demarshal (&iter, &values[arg]))
+            {
+              g_warning ("Unable to convert arg type %d to GValue to emit DBusGProxy signal", dtype);
+              goto out;
+            }
+          
+          ++arg;
+          dbus_message_iter_next (&iter);
+        }
+    }
+      
+  g_signal_emitv (&values[0],
+                  signal_id,
+                  0,
+                  NULL);
+
+ out:
+  i = 0;
+  while (i < arg)
+    {
+      g_value_unset (&values[i]);
+      ++i;
+    }
+}
+
+static void
+dbus_g_proxy_emit_remote_signal (DBusGProxy  *proxy,
+                                 DBusMessage *message)
 {
   const char *interface;
   const char *signal;
-  char *detail;
+  char *name;
   GQuark q;
   
   interface = dbus_message_get_interface (message);
@@ -785,21 +853,43 @@
   g_assert (interface != NULL);
   g_assert (signal != NULL);
 
-  detail = create_signal_detail (interface, signal);
+  name = create_signal_name (interface, signal);
 
   /* If the quark isn't preexisting, there's no way there
    * are any handlers connected. We don't want to create
    * extra quarks for every possible signal.
    */
-  q = g_quark_try_string (detail);
+  q = g_quark_try_string (name);
 
   if (q != 0)
-    g_signal_emit (G_OBJECT (proxy),
-                   signals[RECEIVED],
-                   q,
-                   message);
+    {
+      const char *signature;
 
-  g_free (detail);
+      signature = g_datalist_id_get_data (&proxy->signal_signatures, q);
+      if (signature == NULL)
+        {
+          g_warning ("Signal '%s' has not been added to this proxy object\n",
+                     name);
+        }
+      else if (!dbus_message_has_signature (message, signature))
+        {
+          g_warning ("Signature '%s' expected for signal '%s', actual signature '%s'\n",
+                     signature,
+                     name,
+                     dbus_message_get_signature (message));
+        }
+      else
+        {
+          guint signal_id;
+
+          signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy));
+          g_assert (signal_id != 0); /* because we have the signature */
+          
+          emit_remote_internal (proxy, message, signal_id, signature != NULL);
+        }
+    }
+
+  g_free (name);
 }
 
 /** @} End of DBusGLibInternals */
@@ -1264,8 +1354,8 @@
  * @param client_serial return location for message's serial, or #NULL */
 void
 dbus_g_proxy_send (DBusGProxy          *proxy,
-                  DBusMessage         *message,
-                  dbus_uint32_t       *client_serial)
+                   DBusMessage         *message,
+                   dbus_uint32_t       *client_serial)
 {
   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
   
@@ -1289,15 +1379,103 @@
     g_error ("Out of memory\n");
 }
 
+static gboolean
+siginfo_from_signature (const char         *signature,
+                        GSignalCMarshaller *c_marshaller,
+                        GType              *return_type,
+                        guint              *n_params,
+                        GType             **param_types)
+{
+  /* FIXME (which marshalers should we include?
+   * probably need public API to add your own
+   */
+  
+  if (strcmp (signature, "sss") == 0)
+    {
+      *c_marshaller = _dbus_g_marshal_NONE__STRING_STRING_STRING;
+      *return_type = G_TYPE_NONE;
+      *n_params = 3;
+      *param_types = g_new0 (GType, *n_params);
+      (*param_types)[0] = G_TYPE_STRING;
+      (*param_types)[1] = G_TYPE_STRING;
+      (*param_types)[2] = G_TYPE_STRING;
+
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * Specifies the signature of a signal, such that it's possible to
+ * connect to the signal on this proxy.
+ *
+ * @param proxy the proxy for a remote interface
+ * @param signal_name the name of the signal
+ * @param signature D-BUS signature of the signal
+ */
+void
+dbus_g_proxy_add_signal  (DBusGProxy        *proxy,
+                          const char        *signal_name,
+                          const char        *signature)
+{
+  GSignalCMarshaller c_marshaller;
+  GType return_type;
+  int n_params;
+  GType *params;
+  
+  g_return_if_fail (DBUS_IS_G_PROXY (proxy));
+  g_return_if_fail (signal_name != NULL);
+  g_return_if_fail (signature != NULL);
+
+  if (siginfo_from_signature (signature,
+                              &c_marshaller,
+                              &return_type,
+                              &n_params,
+                              &params))
+    {
+      GQuark q;
+      char *name;
+
+      name = create_signal_name (proxy->interface, signal_name);
+      
+      q = g_quark_from_string (name);
+      
+      g_return_if_fail (g_datalist_id_get_data (&proxy->signal_signatures, q) == NULL);
+      
+      g_datalist_id_set_data_full (&proxy->signal_signatures,
+                                   q, g_strdup (signature),
+                                   g_free);
+
+      /* hackaround global nature of g_signal_newv()... this whole thing needs unhosing */
+
+      if (g_signal_lookup (name,
+                           G_OBJECT_TYPE (proxy)) == 0)
+        {
+          g_signal_newv (name,
+                         G_OBJECT_TYPE (proxy),
+                         G_SIGNAL_RUN_LAST,
+                         0,
+                         NULL, NULL,
+                         c_marshaller,
+                         return_type, n_params, params);
+        }
+
+      g_free (params);
+      g_free (name);
+    }
+  else
+    {
+      g_warning ("DBusGProxy doesn't know how to create a signal with signature '%s'\n",
+                 signature);
+    }
+}
+
 /**
  * Connect a signal handler to a proxy for a remote interface.  When
  * the remote interface emits the specified signal, the proxy will
  * emit a corresponding GLib signal.
  *
- * @todo Right now there's no way to specify the signature to use
- * for invoking the GCallback. Need to either rely on introspection,
- * or require signature here.
- *
  * @param proxy a proxy for a remote interface
  * @param signal_name the DBus signal name to listen for
  * @param handler the handler to connect
@@ -1306,27 +1484,40 @@
  */
 void
 dbus_g_proxy_connect_signal (DBusGProxy             *proxy,
-                            const char             *signal_name,
-                            GCallback               handler,
-                            void                   *data,
-                            GClosureNotify          free_data_func)
+                             const char             *signal_name,
+                             GCallback               handler,
+                             void                   *data,
+                             GClosureNotify          free_data_func)
 {
-  GClosure *closure;
-  char *detail;
+  char *name;
+  guint signal_id;
 
   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
   g_return_if_fail (signal_name != NULL);
   g_return_if_fail (handler != NULL);
   
-  detail = create_signal_detail (proxy->interface, signal_name);
-  
-  closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
-  g_signal_connect_closure_by_id (G_OBJECT (proxy),
-                                  signals[RECEIVED],
-                                  g_quark_from_string (detail),
-                                  closure, FALSE);
+  name = create_signal_name (proxy->interface, signal_name);
 
-  g_free (detail);
+  g_printerr ("Looking up signal '%s'\n", name);
+  signal_id = g_signal_lookup (name,
+                               G_OBJECT_TYPE (proxy));
+  if (signal_id != 0)
+    {
+      GClosure *closure;
+      
+      closure = g_cclosure_new (G_CALLBACK (handler), data, free_data_func);
+      g_signal_connect_closure_by_id (G_OBJECT (proxy),
+                                      signal_id,
+                                      0,
+                                      closure, FALSE);
+    }
+  else
+    {
+      g_warning ("You have to add signal '%s' with dbus_g_proxy_add_signal() before you can connect to it\n",
+                 name);
+    }
+  
+  g_free (name);
 }
 
 /**
@@ -1340,38 +1531,38 @@
  */
 void
 dbus_g_proxy_disconnect_signal (DBusGProxy             *proxy,
-                               const char             *signal_name,
-                               GCallback               handler,
-                               void                   *data)
+                                const char             *signal_name,
+                                GCallback               handler,
+                                void                   *data)
 {
-  char *detail;
-  GQuark q;
+  char *name;
+  guint signal_id;
   
   g_return_if_fail (DBUS_IS_G_PROXY (proxy));
   g_return_if_fail (signal_name != NULL);
   g_return_if_fail (handler != NULL);
 
-  detail = create_signal_detail (proxy->interface, signal_name);
-  q = g_quark_try_string (detail);
-  g_free (detail);
+  name = create_signal_name (proxy->interface, signal_name);
 
-#ifndef G_DISABLE_CHECKS
-  if (q == 0)
+  signal_id = g_signal_lookup (name, G_OBJECT_TYPE (proxy));
+  if (signal_id != 0)
     {
-      g_warning ("%s: No signal handlers for %s found on this DBusGProxy",
-                 G_GNUC_FUNCTION, signal_name);
-      return;
+      g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
+                                            G_SIGNAL_MATCH_DETAIL |
+                                            G_SIGNAL_MATCH_FUNC   |
+                                            G_SIGNAL_MATCH_DATA,
+                                            signal_id,
+                                            0,
+                                            NULL,
+                                            G_CALLBACK (handler), data);
+    }
+  else
+    {
+      g_warning ("Attempt to disconnect from signal '%s' which is not registered\n",
+                 name);
     }
-#endif
 
-  g_signal_handlers_disconnect_matched (G_OBJECT (proxy),
-                                        G_SIGNAL_MATCH_DETAIL |
-                                        G_SIGNAL_MATCH_FUNC   |
-                                        G_SIGNAL_MATCH_DATA,
-                                        signals[RECEIVED],
-                                        q,
-                                        NULL,
-                                        G_CALLBACK (handler), data);
+  g_free (name);
 }
 
 /** @} End of DBusGLib public */



More information about the dbus-commit mailing list