diff options
author | Colin Walters <walters@verbum.org> | 2005-06-17 14:29:48 +0000 |
---|---|---|
committer | Colin Walters <walters@verbum.org> | 2005-06-17 14:29:48 +0000 |
commit | 949436ffac9e46649398e1bc9f0ddf567c88dd1c (patch) | |
tree | d8bad3f3ffa5813a7e99726b66bba3de8aafc319 | |
parent | 679018f00c7277ecd6272cb1be5dfdedf134c422 (diff) |
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.
-rw-r--r-- | ChangeLog | 62 | ||||
-rw-r--r-- | dbus/dbus-glib.h | 19 | ||||
-rw-r--r-- | doc/TODO | 5 | ||||
-rw-r--r-- | glib/dbus-binding-tool-glib.c | 88 | ||||
-rw-r--r-- | glib/dbus-gobject.c | 547 | ||||
-rw-r--r-- | glib/dbus-gproxy.c | 3 | ||||
-rw-r--r-- | test/glib/.cvsignore | 2 | ||||
-rw-r--r-- | test/glib/Makefile.am | 17 | ||||
-rw-r--r-- | test/glib/my-object-marshal.list | 2 | ||||
-rw-r--r-- | test/glib/test-dbus-glib.c | 128 | ||||
-rw-r--r-- | test/glib/test-service-glib.c | 38 | ||||
-rw-r--r-- | test/glib/test-service-glib.xml | 11 |
12 files changed, 648 insertions, 274 deletions
@@ -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. diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h index 80ed7f4f..4debe6fe 100644 --- a/dbus/dbus-glib.h +++ b/dbus/dbus-glib.h @@ -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; @@ -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 diff --git a/glib/dbus-binding-tool-glib.c b/glib/dbus-binding-tool-glib.c index b04386bc..fd849a86 100644 --- a/glib/dbus-binding-tool-glib.c +++ b/glib/dbus-binding-tool-glib.c @@ -48,6 +48,8 @@ typedef struct GHashTable *generated; GString *blob; + GString *signal_blob; + GString *property_blob; guint count; } DBusBindingToolCData; @@ -365,13 +367,37 @@ write_printf_to_iochannel (const char *fmt, GIOChannel *channel, GError **error, } 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) { if (base_info_get_type (base) == INFO_TYPE_NODE) { 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: diff --git a/glib/dbus-gobject.c b/glib/dbus-gobject.c index 7a57d4ea..40d1da03 100644 --- a/glib/dbus-gobject.c +++ b/glib/dbus-gobject.c @@ -204,160 +204,94 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object, return method_dir_signature_from_object_info (object, method, FALSE); } -static void -gobject_unregister_function (DBusConnection *connection, - void *user_data) +static const char * +propsig_iterate (const char *data, const char **iface, const char **name) { - GObject *object; - - object = G_OBJECT (user_data); + *iface = data; - /* FIXME */ + data = string_table_next (data); + *name = data; + return string_table_next (data); } -static void -introspect_properties (GObject *object, GString *xml) +static const DBusGObjectInfo * +lookup_object_info (GObject *object) { - unsigned int i; - unsigned int n_specs; - GType last_type; - GParamSpec **specs; + const DBusGObjectInfo *ret; + GType classtype; + + ret = NULL; + + g_static_rw_lock_reader_lock (&globals_lock); - last_type = G_TYPE_INVALID; - specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (object), - &n_specs); + if (info_hash == NULL) + goto out; - for (i = 0; i < n_specs; i++ ) + for (classtype = G_TYPE_FROM_INSTANCE (object); classtype != 0; classtype = g_type_parent (classtype)) { - 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"); - + const DBusGObjectInfo *info; - /* 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"); + info = g_hash_table_lookup (info_hash, g_type_class_peek (classtype)); - last_type = spec->owner_type; + if (info != NULL && info->format_version == 0) + { + ret = info; + break; } - - 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"); + out: + g_static_rw_lock_reader_unlock (&globals_lock); - g_free (specs); + return ret; } static void -introspect_signals (GType type, GString *xml) +gobject_unregister_function (DBusConnection *connection, + void *user_data) { - 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]); + GObject *object; - if (!dbus_type) - continue; - - g_string_append (xml, " <arg type=\""); - g_string_append (xml, dbus_type); - g_string_append (xml, "\"/>\n"); - } + object = G_OBJECT (user_data); - g_string_append (xml, " </signal>\n"); - } + /* FIXME */ - 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); - } + values = lookup_values (interfaces, method_interface); + values->methods = g_slist_prepend (values->methods, (gpointer) method); + } - memset (&data, 0, sizeof (data)); - data.xml = xml; - data.object_info = info; - g_hash_table_foreach (interfaces, write_interface, &data); + propsig = info->exported_signals; + while (*propsig) + { + const char *iface; + const char *signame; - g_hash_table_destroy (interfaces); - } + propsig = propsig_iterate (propsig, &iface, &signame); + + values = lookup_values (interfaces, iface); + values->signals = g_slist_prepend (values->signals, (gpointer) signame); } - g_static_rw_lock_reader_unlock (&globals_lock); + 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; - - info = g_hash_table_lookup (info_hash, - g_type_class_peek (classtype)); - - *object_ret = info; - - if (info != NULL && info->format_version == 0) + const char *expected_member; + const char *expected_interface; + char *expected_signature; + const DBusGMethodInfo *method; + + method = &(info->method_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) { - 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); diff --git a/glib/dbus-gproxy.c b/glib/dbus-gproxy.c index 836167ef..8c683af4 100644 --- a/glib/dbus-gproxy.c +++ b/glib/dbus-gproxy.c @@ -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; } diff --git a/test/glib/.cvsignore b/test/glib/.cvsignore index cdaabeb9..a0cd5e95 100644 --- a/test/glib/.cvsignore +++ b/test/glib/.cvsignore @@ -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 diff --git a/test/glib/Makefile.am b/test/glib/Makefile.am index 568dab3d..77ee1906 100644 --- a/test/glib/Makefile.am +++ b/test/glib/Makefile.am @@ -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 diff --git a/test/glib/my-object-marshal.list b/test/glib/my-object-marshal.list new file mode 100644 index 00000000..48cbfad4 --- /dev/null +++ b/test/glib/my-object-marshal.list @@ -0,0 +1,2 @@ +NONE:STRING,INT,STRING +NONE:STRING,BOXED diff --git a/test/glib/test-dbus-glib.c b/test/glib/test-dbus-glib.c index 2fc8665b..1f979a27 100644 --- a/test/glib/test-dbus-glib.c +++ b/test/glib/test-dbus-glib.c @@ -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); diff --git a/test/glib/test-service-glib.c b/test/glib/test-service-glib.c index 208bfb24..6089367e 100644 --- a/test/glib/test-service-glib.c +++ b/test/glib/test-service-glib.c @@ -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" diff --git a/test/glib/test-service-glib.xml b/test/glib/test-service-glib.xml index f976572b..05cb5abd 100644 --- a/test/glib/test-service-glib.xml +++ b/test/glib/test-service-glib.xml @@ -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> |