2005-06-17 Colin Walters <walters@verbum.org>

* glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): Don't
	spew warnings if we get malformed remote signals.

	* glib/dbus-gobject.c (propsig_iterate): New function.
	(lookup_object_info): New function, extracted from
	lookup_object_and_method.
	(introspect_properties, introspect_signals): Delete; these
	are merged into write_interface.
	(write_interface): Write out signals and properties here;
	dump the org.gtk.object stuff and use the interface given
	in the introspection data blob.  Also fix up property XML.
	(lookup_values): New function.
	(introspect_interfaces): Gather a mapping from interface to a
	list of its methods, signals, and properties, then write out
	each interface.
	(lookup_object_and_method): Use lookup_object_info.
	(struct DBusGSignalClosure): Add interface.
	(dbus_g_signal_closure_new): Add interface. Don't dup signame;
	we can just use the constant data.
	(dbus_g_signal_closure_finalize): Don't free signal name.
	(signal_emitter_marshaller): Use interface from signal closure.
	(export_signals): Only export signals mentioned in introspection
	blob.
	(dbus_g_connection_register_g_object): Warn if we have no
	introspection data for an object.
	(funcsig_equal): Remove unused variable.
	(dbus_g_object_register_marshaller): Take varargs instead of
	list.
	(dbus_g_object_register_marshaller_array): New function,
	extracted from old dbus_g_object_register_marshaller.

	* glib/dbus-binding-tool-glib.c (struct DBusBindingToolCData): Add
	signals and property data.
	(write_quoted_string): New function, extracted from generate_glue.
	(generate_glue): Write signals and properties to introspection
	blob.

	* dbus/dbus-glib.h (struct DBusGObjectInfo): Include
	exported_signals and exported_properties.
	(dbus_g_object_register_marshaller): Update prototype.
	(dbus_g_object_register_marshaller_array): Prototype.

	* test/glib/test-dbus-glib.c: Extend testing to cover new signals.

	* test/glib/test-service-glib.c: Add new test signals and method
	to emit them.

	* test/glib/test-service-glib.xml: Add some test signals.

	* test/glib/Makefile.am (BUILT_SOURCES): Add my-object-marshal.c
	and my-object-marshal.h
	(test_service_glib_SOURCES, test_dbus_glib_SOURCES): Add
	my-object-marshal.c.
	(my-object-marshal.c, my-object-marshal.h): Implement.

	* test/glib/.cvsignore: Update.

	* doc/TODO: Remove two GLib TODO items fixed by this
	patch.
This commit is contained in:
Colin Walters 2005-06-17 14:29:48 +00:00
parent 679018f00c
commit 949436ffac
12 changed files with 660 additions and 286 deletions

View file

@ -1,3 +1,65 @@
2005-06-17 Colin Walters <walters@verbum.org>
* glib/dbus-gproxy.c (dbus_g_proxy_emit_remote_signal): Don't
spew warnings if we get malformed remote signals.
* glib/dbus-gobject.c (propsig_iterate): New function.
(lookup_object_info): New function, extracted from
lookup_object_and_method.
(introspect_properties, introspect_signals): Delete; these
are merged into write_interface.
(write_interface): Write out signals and properties here;
dump the org.gtk.object stuff and use the interface given
in the introspection data blob. Also fix up property XML.
(lookup_values): New function.
(introspect_interfaces): Gather a mapping from interface to a
list of its methods, signals, and properties, then write out
each interface.
(lookup_object_and_method): Use lookup_object_info.
(struct DBusGSignalClosure): Add interface.
(dbus_g_signal_closure_new): Add interface. Don't dup signame;
we can just use the constant data.
(dbus_g_signal_closure_finalize): Don't free signal name.
(signal_emitter_marshaller): Use interface from signal closure.
(export_signals): Only export signals mentioned in introspection
blob.
(dbus_g_connection_register_g_object): Warn if we have no
introspection data for an object.
(funcsig_equal): Remove unused variable.
(dbus_g_object_register_marshaller): Take varargs instead of
list.
(dbus_g_object_register_marshaller_array): New function,
extracted from old dbus_g_object_register_marshaller.
* glib/dbus-binding-tool-glib.c (struct DBusBindingToolCData): Add
signals and property data.
(write_quoted_string): New function, extracted from generate_glue.
(generate_glue): Write signals and properties to introspection
blob.
* dbus/dbus-glib.h (struct DBusGObjectInfo): Include
exported_signals and exported_properties.
(dbus_g_object_register_marshaller): Update prototype.
(dbus_g_object_register_marshaller_array): Prototype.
* test/glib/test-dbus-glib.c: Extend testing to cover new signals.
* test/glib/test-service-glib.c: Add new test signals and method
to emit them.
* test/glib/test-service-glib.xml: Add some test signals.
* test/glib/Makefile.am (BUILT_SOURCES): Add my-object-marshal.c
and my-object-marshal.h
(test_service_glib_SOURCES, test_dbus_glib_SOURCES): Add
my-object-marshal.c.
(my-object-marshal.c, my-object-marshal.h): Implement.
* test/glib/.cvsignore: Update.
* doc/TODO: Remove two GLib TODO items fixed by this
patch.
2005-06-16 Colin Walters <walters@verbum.org>
* doc/TODO: Update for GLib bindings.

View file

@ -109,9 +109,11 @@ struct DBusGObjectInfo
int format_version; /**< Allows us to change the rest of this struct
* by adding DBusGObjectInfo2, DBusGObjectInfo3, etc.
*/
const DBusGMethodInfo *infos; /**< Array of method pointers */
int n_infos; /**< Length of the infos array */
const DBusGMethodInfo *method_infos; /**< Array of method pointers */
int n_method_infos; /**< Length of the infos array */
const char *data; /**< Introspection data */
const char *exported_signals; /**< Exported signals */
const char *exported_properties; /**< Exported properties */
};
void dbus_g_object_type_install_info (GType object_type,
@ -189,13 +191,16 @@ gboolean dbus_g_value_iterator_get_values (DBusGValueIterator *iter,
void dbus_g_value_iterator_recurse (DBusGValueIterator *iter,
DBusGValueIterator *sub);
void dbus_g_value_free (DBusGValue *value);
void dbus_g_value_free (DBusGValue *value);
void dbus_g_object_register_marshaller (GType rettype,
guint n_types,
const GType *param_types,
GClosureMarshal marshaller);
void dbus_g_object_register_marshaller (GClosureMarshal marshaller,
GType rettype,
...);
void dbus_g_object_register_marshaller_array(GClosureMarshal marshaller,
GType rettype,
guint n_types,
const GType* types);
typedef struct DBusGProxy DBusGProxy;
typedef struct DBusGProxyClass DBusGProxyClass;

View file

@ -30,11 +30,6 @@ Important for 1.0 GLib Bindings
- Annotations for "do not take ownership of this return value" on server
- Fix/test signals
- Don't autoexport signals and properties; use metadata either in
code (preferable) or annotation in XML
- Fix TYPE_OBJECT_PATH marshalling; see:
http://lists.freedesktop.org/archives/dbus/2005-June/002774.html

View file

@ -48,6 +48,8 @@ typedef struct
GHashTable *generated;
GString *blob;
GString *signal_blob;
GString *property_blob;
guint count;
} DBusBindingToolCData;
@ -364,6 +366,31 @@ write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error,
return ret;
}
static gboolean
write_quoted_string (GIOChannel *channel, GString *string, GError **error)
{
guint i;
WRITE_OR_LOSE ("\"");
for (i = 0; i < string->len; i++)
{
if (string->str[i] != '\0')
{
if (!g_io_channel_write_chars (channel, string->str + i, 1, NULL, error))
return FALSE;
}
else
{
if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
return FALSE;
}
}
WRITE_OR_LOSE ("\\0\"");
return TRUE;
io_lose:
return FALSE;
}
static gboolean
generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
{
@ -371,7 +398,6 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
{
GString *object_introspection_data_blob;
GIOChannel *channel;
guint i;
channel = data->channel;
@ -380,6 +406,9 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
data->blob = object_introspection_data_blob;
data->count = 0;
data->signal_blob = g_string_new_len ("", 0);
data->property_blob = g_string_new_len ("", 0);
if (!write_printf_to_iochannel ("static const DBusGMethodInfo dbus_glib_%s_methods[] = {\n", channel, error, data->prefix))
goto io_lose;
@ -402,29 +431,28 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
goto io_lose;
if (!write_printf_to_iochannel (" %d,\n", channel, error, data->count))
goto io_lose;
WRITE_OR_LOSE(" \"");
for (i = 0; i < object_introspection_data_blob->len; i++)
{
if (object_introspection_data_blob->str[i] != '\0')
{
if (!g_io_channel_write_chars (channel, object_introspection_data_blob->str + i, 1, NULL, error))
return FALSE;
}
else
{
if (!g_io_channel_write_chars (channel, "\\0", -1, NULL, error))
return FALSE;
}
}
WRITE_OR_LOSE ("\"\n};\n\n");
if (!write_quoted_string (channel, object_introspection_data_blob, error))
goto io_lose;
WRITE_OR_LOSE (",\n");
if (!write_quoted_string (channel, data->signal_blob, error))
goto io_lose;
WRITE_OR_LOSE (",\n");
if (!write_quoted_string (channel, data->property_blob, error))
goto io_lose;
WRITE_OR_LOSE ("\n};\n\n");
g_string_free (object_introspection_data_blob, TRUE);
g_string_free (data->signal_blob, TRUE);
g_string_free (data->property_blob, TRUE);
}
else
{
GIOChannel *channel;
InterfaceInfo *interface;
GSList *methods;
GSList *signals;
GSList *properties;
GSList *tmp;
const char *interface_c_name;
GString *object_introspection_data_blob;
@ -532,6 +560,34 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
data->count++;
}
signals = interface_info_get_signals (interface);
for (tmp = signals; tmp != NULL; tmp = g_slist_next (tmp))
{
SignalInfo *sig;
sig = tmp->data;
g_string_append (data->signal_blob, interface_info_get_name (interface));
g_string_append_c (data->signal_blob, '\0');
g_string_append (data->signal_blob, signal_info_get_name (sig));
g_string_append_c (data->signal_blob, '\0');
}
properties = interface_info_get_properties (interface);
for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp))
{
PropertyInfo *prop;
prop = tmp->data;
g_string_append (data->property_blob, interface_info_get_name (interface));
g_string_append_c (data->property_blob, '\0');
g_string_append (data->property_blob, property_info_get_name (prop));
g_string_append_c (data->property_blob, '\0');
}
}
return TRUE;
io_lose:

View file

@ -204,6 +204,49 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object,
return method_dir_signature_from_object_info (object, method, FALSE);
}
static const char *
propsig_iterate (const char *data, const char **iface, const char **name)
{
*iface = data;
data = string_table_next (data);
*name = data;
return string_table_next (data);
}
static const DBusGObjectInfo *
lookup_object_info (GObject *object)
{
const DBusGObjectInfo *ret;
GType classtype;
ret = NULL;
g_static_rw_lock_reader_lock (&globals_lock);
if (info_hash == NULL)
goto out;
for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
{
const DBusGObjectInfo *info;
info = g_hash_table_lookup (info_hash, g_type_class_peek (classtype));
if (info != NULL && info->format_version == 0)
{
ret = info;
break;
}
}
out:
g_static_rw_lock_reader_unlock (&globals_lock);
return ret;
}
static void
gobject_unregister_function (DBusConnection *connection,
void *user_data)
@ -216,148 +259,39 @@ gobject_unregister_function (DBusConnection *connection,
}
static void
introspect_properties (GObject *object, GString *xml)
{
unsigned int i;
unsigned int n_specs;
GType last_type;
GParamSpec **specs;
last_type = G_TYPE_INVALID;
specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object),
&n_specs);
for (i = 0; i < n_specs; i++ )
{
char *s;
const char *dbus_type;
gboolean can_set;
gboolean can_get;
GParamSpec *spec = specs[i];
dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
if (dbus_type == NULL)
continue;
if (spec->owner_type != last_type)
{
if (last_type != G_TYPE_INVALID)
g_string_append (xml, " </interface>\n");
/* FIXME what should the namespace on the interface be in
* general? should people be able to set it for their
* objects?
*/
g_string_append (xml, " <interface name=\"org.gtk.objects.");
g_string_append (xml, g_type_name (spec->owner_type));
g_string_append (xml, "\">\n");
last_type = spec->owner_type;
}
can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
(spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
can_get = (spec->flags & G_PARAM_READABLE) != 0;
s = uscore_to_wincaps (spec->name);
if (can_set || can_get)
{
g_string_append (xml, " <property name=\"");
g_string_append (xml, s);
g_string_append (xml, "\" type=\"");
g_string_append (xml, dbus_type);
g_string_append (xml, "\" access=\"");
if (can_set && can_get)
g_string_append (xml, "readwrite");
else if (can_get)
g_string_append (xml, "read");
else
{
g_assert (can_set);
g_string_append (xml, "write");
}
g_string_append (xml, "\"/>\n");
}
g_free (s);
}
if (last_type != G_TYPE_INVALID)
g_string_append (xml, " </interface>\n");
g_free (specs);
}
static void
introspect_signals (GType type, GString *xml)
{
guint i;
guint *ids, n_ids;
ids = g_signal_list_ids (type, &n_ids);
if (!n_ids)
return;
g_string_append (xml, " <interface name=\"org.gtk.objects.");
g_string_append (xml, g_type_name (type));
g_string_append (xml, "\">\n");
/* FIXME: recurse to parent types ? */
for (i = 0; i < n_ids; i++)
{
guint arg;
GSignalQuery query;
g_signal_query (ids[i], &query);
if (query.return_type != G_TYPE_NONE)
continue; /* FIXME: these could be listed as methods ? */
g_string_append (xml, " <signal name=\"");
g_string_append (xml, query.signal_name);
g_string_append (xml, "\">\n");
for (arg = 0; arg < query.n_params; arg++)
{
const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
if (!dbus_type)
continue;
g_string_append (xml, " <arg type=\"");
g_string_append (xml, dbus_type);
g_string_append (xml, "\"/>\n");
}
g_string_append (xml, " </signal>\n");
}
g_string_append (xml, " </interface>\n");
}
typedef struct
{
GString *xml;
GType gtype;
const DBusGObjectInfo *object_info;
} DBusGlibWriteIterfaceData;
} DBusGLibWriteIterfaceData;
typedef struct
{
GSList *methods;
GSList *signals;
GSList *properties;
} DBusGLibWriteInterfaceValues;
static void
write_interface (gpointer key, gpointer val, gpointer user_data)
{
const char *name;
GSList *methods;
GSList *signals;
GSList *properties;
GString *xml;
const DBusGObjectInfo *object_info;
DBusGlibWriteIterfaceData *data;
DBusGLibWriteIterfaceData *data;
DBusGLibWriteInterfaceValues *values;
name = key;
methods = val;
values = val;
methods = values->methods;
signals = values->signals;
properties = values->properties;
data = user_data;
xml = data->xml;
object_info = data->object_info;
@ -390,64 +324,177 @@ write_interface (gpointer key, gpointer val, gpointer user_data)
}
g_string_append (xml, " </method>\n");
}
}
g_slist_free (values->methods);
for (; signals; signals = signals->next)
{
guint id;
guint arg;
const char *signame;
GSignalQuery query;
char *s;
signame = signals->data;
s = _dbus_gutils_wincaps_to_uscore (signame);
id = g_signal_lookup (s, data->gtype);
g_assert (id != 0);
g_signal_query (id, &query);
g_assert (query.return_type == G_TYPE_NONE);
g_string_append_printf (xml, " <signal name=\"%s\">\n", signame);
for (arg = 0; arg < query.n_params; arg++)
{
const char *dbus_type = dbus_gtype_to_signature (query.param_types[arg]);
g_assert (dbus_type != NULL);
g_string_append (xml, " <arg type=\"");
g_string_append (xml, dbus_type);
g_string_append (xml, "\"/>\n");
}
g_string_append (xml, " </signal>\n");
g_free (s);
}
g_slist_free (values->signals);
for (; properties; properties = properties->next)
{
const char *propname;
GParamSpec *spec;
const char *dbus_type;
gboolean can_set;
gboolean can_get;
char *s;
propname = properties->data;
s = _dbus_gutils_wincaps_to_uscore (spec->name);
spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
g_assert (spec != NULL);
g_free (s);
dbus_type = dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
g_assert (dbus_type != NULL);
can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
(spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
can_get = (spec->flags & G_PARAM_READABLE) != 0;
if (can_set || can_get)
{
g_string_append_printf (xml, " <property name=\"%s\" ", propname);
g_string_append (xml, "type=\"");
g_string_append (xml, dbus_type);
g_string_append (xml, "\" access=\"");
if (can_set && can_get)
g_string_append (xml, "readwrite");
else if (can_get)
g_string_append (xml, "read");
else
{
g_assert (can_set);
g_string_append (xml, "write");
}
g_string_append (xml, "\"/>\n");
}
g_free (s);
g_string_append (xml, " </property>\n");
}
g_slist_free (values->properties);
g_free (values);
g_string_append (xml, " </interface>\n");
}
static DBusGLibWriteInterfaceValues *
lookup_values (GHashTable *interfaces, const char *method_interface)
{
DBusGLibWriteInterfaceValues *values;
if ((values = g_hash_table_lookup (interfaces, (gpointer) method_interface)) == NULL)
{
values = g_new0 (DBusGLibWriteInterfaceValues, 1);
g_hash_table_insert (interfaces, (gpointer) method_interface, values);
}
return values;
}
static void
introspect_interfaces (GObject *object, GString *xml)
{
GType classtype;
const DBusGObjectInfo *info;
DBusGLibWriteIterfaceData data;
int i;
GHashTable *interfaces;
DBusGLibWriteInterfaceValues *values;
const char *propsig;
g_static_rw_lock_reader_lock (&globals_lock);
info = lookup_object_info (object);
for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
g_assert (info != NULL);
/* Gather a list of all interfaces, indexed into their methods */
interfaces = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; i < info->n_method_infos; i++)
{
const DBusGObjectInfo *info;
DBusGlibWriteIterfaceData data;
const char *method_name;
const char *method_interface;
const char *method_args;
const DBusGMethodInfo *method;
info = g_hash_table_lookup (info_hash,
g_type_class_peek (classtype));
method = &(info->method_infos[i]);
if (info != NULL && info->format_version == 0)
{
int i;
GHashTable *interfaces;
method_interface = method_interface_from_object_info (info, method);
method_name = method_name_from_object_info (info, method);
method_args = method_arg_info_from_object_info (info, method);
/* Gather a list of all interfaces, indexed into their methods */
interfaces = g_hash_table_new (g_str_hash, g_str_equal);
for (i = 0; i < info->n_infos; i++)
{
const char *method_name;
const char *method_interface;
const char *method_args;
const DBusGMethodInfo *method;
GSList *methods;
method = &(info->infos[i]);
method_interface = method_interface_from_object_info (info, method);
method_name = method_name_from_object_info (info, method);
method_args = method_arg_info_from_object_info (info, method);
if ((methods = g_hash_table_lookup (interfaces, method_interface)) == NULL)
methods = g_slist_prepend (NULL, (gpointer) method);
else
methods = g_slist_prepend (methods, (gpointer) method);
g_hash_table_insert (interfaces, (gpointer) method_interface, methods);
}
memset (&data, 0, sizeof (data));
data.xml = xml;
data.object_info = info;
g_hash_table_foreach (interfaces, write_interface, &data);
g_hash_table_destroy (interfaces);
}
values = lookup_values (interfaces, method_interface);
values->methods = g_slist_prepend (values->methods, (gpointer) method);
}
g_static_rw_lock_reader_unlock (&globals_lock);
propsig = info->exported_signals;
while (*propsig)
{
const char *iface;
const char *signame;
propsig = propsig_iterate (propsig, &iface, &signame);
values = lookup_values (interfaces, iface);
values->signals = g_slist_prepend (values->signals, (gpointer) signame);
}
propsig = info->exported_properties;
while (*propsig)
{
const char *iface;
const char *propname;
propsig = propsig_iterate (propsig, &iface, &propname);
values = lookup_values (interfaces, iface);
values->properties = g_slist_prepend (values->properties, (gpointer) propname);
}
memset (&data, 0, sizeof (data));
data.xml = xml;
data.gtype = G_TYPE_FROM_INSTANCE (object);
data.object_info = info;
g_hash_table_foreach (interfaces, write_interface, &data);
g_hash_table_destroy (interfaces);
}
static DBusHandlerResult
@ -492,8 +539,6 @@ handle_introspect (DBusConnection *connection,
g_string_append (xml, " </method>\n");
g_string_append (xml, " </interface>\n");
introspect_signals (G_OBJECT_TYPE (object), xml);
introspect_properties (object, xml);
introspect_interfaces (object, xml);
/* Append child nodes */
@ -605,64 +650,47 @@ lookup_object_and_method (GObject *object,
const DBusGObjectInfo **object_ret,
const DBusGMethodInfo **method_ret)
{
GType classtype;
const char *interface;
const char *member;
const char *signature;
gboolean ret;
const DBusGObjectInfo *info;
int i;
interface = dbus_message_get_interface (message);
member = dbus_message_get_member (message);
signature = dbus_message_get_signature (message);
ret = FALSE;
g_static_rw_lock_reader_lock (&globals_lock);
if (!info_hash)
goto out;
info = lookup_object_info (object);
*object_ret = info;
for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype))
for (i = 0; i < info->n_method_infos; i++)
{
const DBusGObjectInfo *info;
const char *expected_member;
const char *expected_interface;
char *expected_signature;
const DBusGMethodInfo *method;
info = g_hash_table_lookup (info_hash,
g_type_class_peek (classtype));
method = &(info->method_infos[i]);
*object_ret = info;
/* Check method interface/name and input signature */
expected_interface = method_interface_from_object_info (*object_ret, method);
expected_member = method_name_from_object_info (*object_ret, method);
expected_signature = method_input_signature_from_object_info (*object_ret, method);
if (info != NULL && info->format_version == 0)
if ((interface == NULL
|| strcmp (expected_interface, interface) == 0)
&& strcmp (expected_member, member) == 0
&& strcmp (expected_signature, signature) == 0)
{
int i;
for (i = 0; i < info->n_infos; i++)
{
const char *expected_member;
const char *expected_interface;
char *expected_signature;
const DBusGMethodInfo *method;
method = &(info->infos[i]);
/* Check method interface/name and input signature */
expected_interface = method_interface_from_object_info (*object_ret, method);
expected_member = method_name_from_object_info (*object_ret, method);
expected_signature = method_input_signature_from_object_info (*object_ret, method);
if ((interface == NULL
|| strcmp (expected_interface, interface) == 0)
&& strcmp (expected_member, member) == 0
&& strcmp (expected_signature, signature) == 0)
{
g_free (expected_signature);
*method_ret = method;
ret = TRUE;
goto out;
}
g_free (expected_signature);
}
g_free (expected_signature);
*method_ret = method;
return TRUE;
}
g_free (expected_signature);
}
out:
g_static_rw_lock_reader_unlock (&globals_lock);
return ret;
}
@ -1084,13 +1112,15 @@ typedef struct {
GClosure closure;
DBusGConnection *connection;
GObject *object;
char *signame;
const char *signame;
const char *sigiface;
} DBusGSignalClosure;
static GClosure *
dbus_g_signal_closure_new (DBusGConnection *connection,
GObject *object,
const char *signame)
const char *signame,
const char *sigiface)
{
DBusGSignalClosure *closure;
@ -1098,7 +1128,8 @@ dbus_g_signal_closure_new (DBusGConnection *connection,
closure->connection = dbus_g_connection_ref (connection);
closure->object = object;
closure->signame = g_strdup (signame);
closure->signame = signame;
closure->sigiface = sigiface;
return (GClosure*) closure;
}
@ -1109,7 +1140,6 @@ dbus_g_signal_closure_finalize (gpointer data,
DBusGSignalClosure *sigclosure = (DBusGSignalClosure *) closure;
dbus_g_connection_unref (sigclosure->connection);
g_free (sigclosure->signame);
}
static void
@ -1135,7 +1165,7 @@ signal_emitter_marshaller (GClosure *closure,
g_assert (path != NULL);
signal = dbus_message_new_signal (path,
"org.gtk.objects",
sigclosure->sigiface,
sigclosure->signame);
if (!signal)
{
@ -1163,34 +1193,52 @@ signal_emitter_marshaller (GClosure *closure,
}
static void
export_signals (DBusGConnection *connection, GObject *object)
export_signals (DBusGConnection *connection, const DBusGObjectInfo *info, GObject *object)
{
guint i;
guint *ids, n_ids;
GType gtype;
const char *sigdata;
const char *iface;
const char *signame;
ids = g_signal_list_ids (G_TYPE_FROM_INSTANCE (object), &n_ids);
if (!n_ids)
return;
gtype = G_TYPE_FROM_INSTANCE (object);
/* FIXME: recurse to parent types ? */
for (i = 0; i < n_ids; i++)
sigdata = info->exported_signals;
while (*sigdata != '\0')
{
guint id;
GSignalQuery query;
GClosure *closure;
char *s;
sigdata = propsig_iterate (sigdata, &iface, &signame);
g_signal_query (ids[i], &query);
s = _dbus_gutils_wincaps_to_uscore (signame);
id = g_signal_lookup (s, gtype);
if (id == 0)
{
g_warning ("signal \"%s\" (from \"%s\") exported but not found in object class \"%s\"",
s, signame, g_type_name (gtype));
g_free (s);
continue;
}
g_signal_query (id, &query);
if (query.return_type != G_TYPE_NONE)
{
g_warning("Not exporting signal '%s' as it has a return type %s", query.signal_name, g_type_name (query.return_type));
g_warning ("Not exporting signal \"%s\" for object class \"%s\" as it has a return type \"%s\"",
s, g_type_name (gtype), g_type_name (query.return_type));
g_free (s);
continue; /* FIXME: these could be listed as methods ? */
}
closure = dbus_g_signal_closure_new (connection, object, query.signal_name);
closure = dbus_g_signal_closure_new (connection, object, signame, (char*) iface);
g_closure_set_marshal (closure, signal_emitter_marshaller);
g_signal_connect_closure_by_id (object,
ids[i],
id,
0,
closure,
FALSE);
@ -1274,10 +1322,19 @@ dbus_g_connection_register_g_object (DBusGConnection *connection,
const char *at_path,
GObject *object)
{
const DBusGObjectInfo *info;
g_return_if_fail (connection != NULL);
g_return_if_fail (at_path != NULL);
g_return_if_fail (G_IS_OBJECT (object));
info = lookup_object_info (object);
if (info == NULL)
{
g_warning ("No introspection data registered for object class \"%s\"",
g_type_name (G_TYPE_FROM_INSTANCE (object)));
return;
}
if (!dbus_connection_register_object_path (DBUS_CONNECTION_FROM_G_CONNECTION (connection),
at_path,
&gobject_dbus_vtable,
@ -1287,7 +1344,7 @@ dbus_g_connection_register_g_object (DBusGConnection *connection,
return;
}
export_signals (connection, object);
export_signals (connection, info, object);
g_object_set_data (object, "dbus_glib_object_path", g_strdup (at_path));
g_object_weak_ref (object, (GWeakNotify)unregister_gobject, connection);
@ -1337,7 +1394,7 @@ funcsig_equal (gconstpointer aval,
const DBusGFuncSignature *b = bval;
const GType *atypes;
const GType *btypes;
guint i, j;
guint i;
if (a->rettype != b->rettype
|| a->n_params != b->n_params)
@ -1422,22 +1479,56 @@ _dbus_gobject_lookup_marshaller (GType rettype,
}
/**
* Register a GClosureMarshal to be used for signal invocations.
* Register a GClosureMarshal to be used for signal invocations,
* giving its return type and a list of parameter types,
* followed by G_TYPE_INVALID.
* This function will not be needed once GLib includes libffi.
*
* @param marshaller a GClosureMarshal to be used for invocation
* @param rettype a GType for the return type of the function
* @param ... The parameter GTypes, followed by G_TYPE_INVALID
*/
void
dbus_g_object_register_marshaller (GClosureMarshal marshaller,
GType rettype,
...)
{
va_list args;
GArray *types;
GType gtype;
va_start (args, rettype);
types = g_array_new (TRUE, TRUE, sizeof (GType));
while ((gtype = va_arg (args, GType)) != G_TYPE_INVALID)
g_array_append_val (types, gtype);
dbus_g_object_register_marshaller_array (marshaller, rettype,
types->len, (GType*) types->data);
g_array_free (types, TRUE);
va_end (args);
}
/**
* Register a GClosureMarshal to be used for signal invocations.
* See also #dbus_g_object_register_marshaller
*
* @param marshaller a GClosureMarshal to be used for invocation
* @param rettype a GType for the return type of the function
* @param n_types number of function parameters
* @param param_types a C array of GTypes values
* @param marshaller a GClosureMarshal to be used for invocation
*/
void
dbus_g_object_register_marshaller (GType rettype,
guint n_types,
const GType *param_types,
GClosureMarshal marshaller)
dbus_g_object_register_marshaller_array (GClosureMarshal marshaller,
GType rettype,
guint n_types,
const GType* types)
{
DBusGFuncSignature *sig;
g_static_rw_lock_writer_lock (&globals_lock);
if (marshal_table == NULL)
@ -1449,7 +1540,7 @@ dbus_g_object_register_marshaller (GType rettype,
sig->rettype = rettype;
sig->n_params = n_types;
sig->params = g_new (GType, n_types);
memcpy (sig->params, param_types, n_types * sizeof (GType));
memcpy (sig->params, types, n_types * sizeof (GType));
g_hash_table_insert (marshal_table, sig, marshaller);

View file

@ -934,9 +934,12 @@ dbus_g_proxy_emit_remote_signal (DBusGProxy *proxy,
g_free (name);
return;
mismatch:
#if 0
/* Don't spew on remote errors */
g_warning ("Unexpected message signature '%s' for signal '%s'\n",
dbus_message_get_signature (message),
name);
#endif
goto out;
}

View file

@ -11,3 +11,5 @@ run-test.conf
test-service-glib-bindings.h
test-service-glib-glue.h
run-with-tmp-session-bus.conf
my-object-marshal.h
my-object-marshal.c

View file

@ -35,14 +35,16 @@ endif
noinst_PROGRAMS= test-dbus-glib test-service-glib $(THREAD_APPS)
test_dbus_glib_SOURCES= \
my-object-marshal.c \
test-dbus-glib.c
test_dbus_glib_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/glib/libdbus-glib-1.la $(top_builddir)/glib/libdbus-gtool.la
test_service_glib_SOURCES= \
test-service-glib.c
BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h
BUILT_SOURCES = test-service-glib-glue.h test-service-glib-bindings.h
test_service_glib_SOURCES= \
my-object-marshal.c \
test-service-glib.c
test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool
$(top_builddir)/glib/dbus-binding-tool --prefix=my_object --mode=glib-server --output=test-service-glib-glue.h $(srcdir)/test-service-glib.xml
@ -50,7 +52,14 @@ test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/glib/dbus-bindin
test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/glib/dbus-binding-tool
$(top_builddir)/glib/dbus-binding-tool --prefix=my_object --mode=glib-client --output=test-service-glib-bindings.h $(srcdir)/test-service-glib.xml
CLEANFILES = test-service-glib-glue.h test-service-glib-bindings.h
my-object-marshal.c: Makefile my-object-marshal.list
@GLIB_GENMARSHAL@ --prefix=my_object_marshal $(srcdir)/my-object-marshal.list --header --body > my-object-marshal.c
my-object-marshal.h: Makefile my-object-marshal.list
@GLIB_GENMARSHAL@ --prefix=my_object_marshal $(srcdir)/my-object-marshal.list --header > my-object-marshal.h
CLEANFILES = $(BUILT_SOURCES)
test_service_glib_LDADD= $(top_builddir)/glib/libdbus-glib-1.la

View file

@ -0,0 +1,2 @@
NONE:STRING,INT,STRING
NONE:STRING,BOXED

View file

@ -7,10 +7,14 @@
#include <glib/dbus-gidl.h>
#include <glib/dbus-gparser.h>
#include <glib-object.h>
#include "my-object-marshal.h"
static GMainLoop *loop = NULL;
static int n_times_foo_received = 0;
static int n_times_frobnicate_received = 0;
static int n_times_sig0_received = 0;
static int n_times_sig1_received = 0;
static guint exit_timeout = 0;
static gboolean
timed_exit (gpointer loop)
@ -27,6 +31,7 @@ foo_signal_handler (DBusGProxy *proxy,
n_times_foo_received += 1;
g_main_loop_quit (loop);
g_source_remove (exit_timeout);
}
static void
@ -39,6 +44,44 @@ frobnicate_signal_handler (DBusGProxy *proxy,
g_assert (val == 42);
g_main_loop_quit (loop);
g_source_remove (exit_timeout);
}
static void
sig0_signal_handler (DBusGProxy *proxy,
const char *str0,
int val,
const char *str1,
void *user_data)
{
n_times_sig0_received += 1;
g_assert (!strcmp (str0, "foo"));
g_assert (val == 22);
g_assert (!strcmp (str1, "moo"));
g_main_loop_quit (loop);
g_source_remove (exit_timeout);
}
static void
sig1_signal_handler (DBusGProxy *proxy,
const char *str0,
GValue *value,
void *user_data)
{
n_times_sig1_received += 1;
g_assert (!strcmp (str0, "baz"));
g_assert (G_VALUE_HOLDS_STRING (value));
g_assert (!strcmp (g_value_get_string (value), "bar"));
g_main_loop_quit (loop);
g_source_remove (exit_timeout);
}
static void lose (const char *fmt, ...) G_GNUC_NORETURN G_GNUC_PRINTF (1, 2);
@ -216,9 +259,7 @@ main (int argc, char **argv)
G_TYPE_INVALID);
dbus_g_connection_flush (connection);
g_timeout_add (5000, timed_exit, loop);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
if (n_times_foo_received != 1)
@ -643,16 +684,81 @@ main (int argc, char **argv)
dbus_g_connection_flush (connection);
#if 0
g_timeout_add (5000, timed_exit, loop);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
if (n_times_frobnicate_received != 1)
lose ("Frobnicate signal received %d times, should have been 1", n_times_frobnicate_received);
#endif
if (!dbus_g_proxy_invoke (proxy, "EmitFrobnicate", &error,
G_TYPE_INVALID, G_TYPE_INVALID))
lose_gerror ("Failed to complete EmitFrobnicate call", error);
dbus_g_connection_flush (connection);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
if (n_times_frobnicate_received != 2)
lose ("Frobnicate signal received %d times, should have been 2", n_times_frobnicate_received);
g_object_unref (G_OBJECT (proxy));
proxy = dbus_g_proxy_new_for_name_owner (connection,
"org.freedesktop.DBus.TestSuiteGLibService",
"/org/freedesktop/DBus/Tests/MyTestObject",
"org.freedesktop.DBus.Tests.FooObject",
&error);
if (proxy == NULL)
lose_gerror ("Failed to create proxy for name owner", error);
dbus_g_object_register_marshaller (my_object_marshal_VOID__STRING_INT_STRING,
G_TYPE_NONE, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_object_register_marshaller (my_object_marshal_VOID__STRING_BOXED,
G_TYPE_NONE, G_TYPE_STRING, G_TYPE_VALUE, G_TYPE_INVALID);
dbus_g_proxy_add_signal (proxy, "Sig0", G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID);
dbus_g_proxy_add_signal (proxy, "Sig1", G_TYPE_STRING, G_TYPE_VALUE);
dbus_g_proxy_connect_signal (proxy, "Sig0",
G_CALLBACK (sig0_signal_handler),
NULL, NULL);
dbus_g_proxy_connect_signal (proxy, "Sig1",
G_CALLBACK (sig1_signal_handler),
NULL, NULL);
dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID);
dbus_g_connection_flush (connection);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
if (n_times_sig0_received != 1)
lose ("Sig0 signal received %d times, should have been 1", n_times_sig0_received);
if (n_times_sig1_received != 1)
lose ("Sig1 signal received %d times, should have been 1", n_times_sig1_received);
dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID);
dbus_g_proxy_call_no_reply (proxy, "EmitSignals", G_TYPE_INVALID);
dbus_g_connection_flush (connection);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
exit_timeout = g_timeout_add (5000, timed_exit, loop);
g_main_loop_run (loop);
if (n_times_sig0_received != 3)
lose ("Sig0 signal received %d times, should have been 3", n_times_sig0_received);
if (n_times_sig1_received != 3)
lose ("Sig1 signal received %d times, should have been 3", n_times_sig1_received);
g_object_unref (G_OBJECT (proxy));
proxy = dbus_g_proxy_new_for_name_owner (connection,
@ -680,7 +786,6 @@ main (int argc, char **argv)
gboolean found_properties;
gboolean found_myobject;
gboolean found_fooobject;
gboolean found_gtk_myobject;
node = description_load_from_string (v_STRING_2, strlen (v_STRING_2), &error);
if (!node)
@ -688,7 +793,6 @@ main (int argc, char **argv)
found_introspectable = FALSE;
found_properties = FALSE;
found_gtk_myobject = FALSE;
found_myobject = FALSE;
found_fooobject = FALSE;
for (elt = node_info_get_interfaces (node); elt ; elt = elt->next)
@ -699,8 +803,6 @@ main (int argc, char **argv)
found_introspectable = TRUE;
else if (!found_properties && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Properties") == 0)
found_properties = TRUE;
else if (strcmp (interface_info_get_name (iface), "org.gtk.objects.MyObject") == 0)
found_gtk_myobject = TRUE;
else if (!found_myobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.Tests.MyObject") == 0)
{
GSList *elt;
@ -729,7 +831,7 @@ main (int argc, char **argv)
lose ("Unexpected or duplicate interface %s", interface_info_get_name (iface));
}
if (!(found_introspectable && found_gtk_myobject && found_myobject && found_properties))
if (!(found_introspectable && found_myobject && found_properties))
lose ("Missing interface");
}
g_free (v_STRING_2);

View file

@ -10,6 +10,7 @@
#include <glib/gi18n.h>
#include <glib-object.h>
#include <glib/gquark.h>
#include "my-object-marshal.h"
typedef struct MyObject MyObject;
typedef struct MyObjectClass MyObjectClass;
@ -77,6 +78,8 @@ gboolean my_object_get_val (MyObject *obj, guint *ret, GError **error);
gboolean my_object_get_value (MyObject *obj, guint *ret, GError **error);
gboolean my_object_emit_signals (MyObject *obj, GError **error);
gboolean my_object_emit_frobnicate (MyObject *obj, GError **error);
#include "test-service-glib-glue.h"
@ -93,10 +96,11 @@ enum
enum
{
FROBNICATE,
SIG0,
SIG1,
LAST_SIGNAL
};
static void *parent_class;
static guint signals[LAST_SIGNAL] = { 0 };
static void
@ -185,6 +189,23 @@ my_object_class_init (MyObjectClass *mobject_class)
g_cclosure_marshal_VOID__INT,
G_TYPE_NONE, 1, G_TYPE_INT);
signals[SIG0] =
g_signal_new ("sig0",
G_OBJECT_CLASS_TYPE (mobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL, NULL,
my_object_marshal_VOID__STRING_INT_STRING,
G_TYPE_NONE, 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_STRING);
signals[SIG1] =
g_signal_new ("sig1",
G_OBJECT_CLASS_TYPE (mobject_class),
G_SIGNAL_RUN_LAST | G_SIGNAL_DETAILED,
0,
NULL, NULL,
my_object_marshal_VOID__STRING_BOXED,
G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_VALUE);
}
GQuark
@ -403,6 +424,21 @@ my_object_emit_frobnicate (MyObject *obj, GError **error)
return TRUE;
}
gboolean
my_object_emit_signals (MyObject *obj, GError **error)
{
GValue val = {0, };
g_signal_emit (obj, signals[SIG0], 0, "foo", 22, "moo");
g_value_init (&val, G_TYPE_STRING);
g_value_set_string (&val, "bar");
g_signal_emit (obj, signals[SIG1], 0, "baz", &val);
g_value_unset (&val);
return TRUE;
}
static GMainLoop *loop;
#define TEST_SERVICE_NAME "org.freedesktop.DBus.TestSuiteGLibService"

View file

@ -84,13 +84,24 @@
<method name="EmitFrobnicate">
</method>
<!-- Export signals -->
<signal name="Frobnicate"/>
</interface>
<!-- Test multiple interfaces on the same object -->
<interface name="org.freedesktop.DBus.Tests.FooObject">
<method name="GetValue">
<arg type="u" direction="out" />
</method>
<method name="EmitSignals">
</method>
<signal name="Sig0"/>
<signal name="Sig1"/>
</interface>
</node>