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,
+ ¶ms))
+ {
+ 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