diff options
author | David Zeuthen <davidz@redhat.com> | 2010-06-18 12:02:38 -0400 |
---|---|---|
committer | David Zeuthen <davidz@redhat.com> | 2010-06-18 12:02:38 -0400 |
commit | 54050bb239a60f59c573314bc87fbf4c2c740f6f (patch) | |
tree | 9c06c3badd31c3fb52f1df78812a3eea6ee3b039 | |
parent | 427d3c5ea1f4af5d1f26f70ffae5606eb0a70618 (diff) |
Add g_dbus_interface_info_get_for_gtype() and move various cleanups
Signed-off-by: David Zeuthen <davidz@redhat.com>
-rw-r--r-- | src/gdbusgi.c | 438 | ||||
-rw-r--r-- | src/gdbusgi.h | 4 |
2 files changed, 269 insertions, 173 deletions
diff --git a/src/gdbusgi.c b/src/gdbusgi.c index 04a1512..a826c02 100644 --- a/src/gdbusgi.c +++ b/src/gdbusgi.c @@ -1023,29 +1023,48 @@ convert_gvariant_to_gi (GVariant *variant, typedef struct { + GType gtype; + GDBusInterfaceInfo *interface_info; + GHashTable *dbus_method_name_to_method_data; + GHashTable *g_signal_name_to_signal_data; +} InterfaceData; + +static void +interface_data_free (InterfaceData *data) +{ + if (data->interface_info != NULL) + g_dbus_interface_info_unref (data->interface_info); + g_hash_table_unref (data->dbus_method_name_to_method_data); + g_hash_table_unref (data->g_signal_name_to_signal_data); + g_free (data); +} + +static InterfaceData *get_interface_data_for_gtype (GType gtype, + GError **error); + +/* ---------------------------------------------------------------------------------------------------- */ + +typedef struct +{ GObject *object; gchar *object_path; GDBusConnection *connection; - GDBusInterfaceInfo *info; gpointer user_data; GDestroyNotify user_data_free_func; - GHashTable *dbus_method_name_to_method_data; - GHashTable *g_signal_name_to_signal_data; + InterfaceData *interface_data; } ExportData; static void export_data_free (ExportData *data) { - g_hash_table_unref (data->dbus_method_name_to_method_data); - g_hash_table_unref (data->g_signal_name_to_signal_data); + if (data->interface_data != NULL) + interface_data_free (data->interface_data); if (data->object != NULL) g_object_unref (data->object); g_free (data->object_path); if (data->connection != NULL) g_object_unref (data->connection); - if (data->info != NULL) - g_dbus_interface_info_unref (data->info); if (data->user_data_free_func != NULL) data->user_data_free_func (data->user_data); g_free (data); @@ -1205,7 +1224,7 @@ method_data_print (MethodData *data, return g_string_free (str, FALSE); } -static void +G_GNUC_UNUSED static void method_data_dump (MethodData *data, guint indent) { @@ -1267,7 +1286,7 @@ signal_data_print (SignalData *data, return g_string_free (str, FALSE); } -static void +G_GNUC_UNUSED static void signal_data_dump (SignalData *data, guint indent) { @@ -1512,12 +1531,10 @@ on_method_call (GDBusConnection *connection, in_args = NULL; out_args = NULL; - g_print ("##### %s #####\n", method_name); - /* The GDBus core guarantees that only methods matching the given * introspection data is dispatched. */ - method_data = g_hash_table_lookup (data->dbus_method_name_to_method_data, method_name); + method_data = g_hash_table_lookup (data->interface_data->dbus_method_name_to_method_data, method_name); g_assert (method_data != NULL); /* Allocate GArgument vectors */ @@ -1714,6 +1731,165 @@ static const GDBusInterfaceVTable export_vtable = /* ---------------------------------------------------------------------------------------------------- */ +typedef struct +{ + GClosure parent_instance; + + gulong signal_handler_id; + SignalData *signal_data; + ExportData *export_data; +} GDBusClosure; + +static GVariant * +process_signal_args (guint n_param_values, + const GValue *param_values, + SignalData *data) +{ + guint n; + ArgData *ad; + GVariant *value; + GVariantType *gvariant_type; + GVariantBuilder builder; + GArgument *array_len_arg; + GITypeInfo *array_len_arg_type; + GArgument **args; + + g_assert_cmpint (n_param_values, ==, data->args->len); + + /* Convert GValue to GArgument + * + * TODO: verify that the conversion really is that simple... + */ + args = g_new0 (GArgument *, n_param_values); + for (n = 0; n < n_param_values; n++) + args[n] = (GArgument *) &(param_values[n].data[0]); + + g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); + for (n = 0; n < data->args->len; n++) + { + ad = data->args->pdata[n]; + + if (ad->dbus_arg_info == NULL) + continue; + + array_len_arg = NULL; + array_len_arg_type = NULL; + if (ad->array_len_position != -1) + { + array_len_arg = args[ad->array_len_position]; + array_len_arg_type = ((ArgData *) data->args->pdata[ad->array_len_position])->type_info; + } + + gvariant_type = g_variant_type_new (ad->dbus_arg_info->signature); + value = convert_gi_to_gvariant (args[n], + ad->type_info, + gvariant_type, + array_len_arg, + array_len_arg_type); + g_variant_ref_sink (value); + g_variant_builder_add_value (&builder, value); + g_variant_unref (value); + g_variant_type_free (gvariant_type); + } + + g_free (args); + + return g_variant_builder_end (&builder); +} + +static void +marshal_signal_onto_dbus (GClosure *_closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + GDBusClosure *closure = (GDBusClosure *) _closure; + GVariant *variant; + GError *error; + + variant = process_signal_args (n_param_values, + param_values, + closure->signal_data); + error = NULL; + if (!g_dbus_connection_emit_signal (closure->export_data->connection, + NULL, + closure->export_data->object_path, + closure->export_data->interface_data->interface_info->name, + closure->signal_data->dbus_signal->name, + variant, + &error)) + { + g_warning ("Error emitting D-Bus signal `%s' in response to G signal: %s", + closure->signal_data->dbus_signal->name, + error->message); + g_error_free (error); + } + g_variant_unref (variant); +} + +guint +g_dbus_connection_register_gobject (GDBusConnection *connection, + GObject *object, + const gchar *object_path, + gpointer user_data, + GDestroyNotify user_data_free_func, + GError **error) +{ + ExportData *data; + GHashTableIter iter; + const gchar *g_signal_name; + SignalData *signal_data; + + g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0); + g_return_val_if_fail (G_IS_OBJECT (object), 0); + g_return_val_if_fail (g_variant_is_object_path (object_path), 0); + g_return_val_if_fail (error == NULL || *error == NULL, 0); + + data = g_new0 (ExportData, 1); + data->object = g_object_ref (object); + data->object_path = g_strdup (object_path); + data->connection = g_object_ref (connection); + data->user_data = user_data; + data->user_data_free_func = user_data_free_func; + + data->interface_data = get_interface_data_for_gtype (G_TYPE_FROM_INSTANCE (object), error); + if (data->interface_data == NULL) + goto fail; + + /* Set up signal handlers for all exported signals */ + g_hash_table_iter_init (&iter, data->interface_data->g_signal_name_to_signal_data); + while (g_hash_table_iter_next (&iter, (gpointer*) &g_signal_name, (gpointer*) &signal_data)) + { + GDBusClosure *closure; + + closure = (GDBusClosure *) g_closure_new_simple (sizeof (GDBusClosure), NULL); + g_closure_set_marshal ((GClosure *) closure, marshal_signal_onto_dbus); + + closure->signal_data = signal_data; + closure->signal_handler_id = g_signal_connect_closure (object, + g_signal_name, + (GClosure *) closure, + TRUE); + closure->export_data = data; + /* TODO: we need to unregister these handlers in export_data_free() */ + } + + return g_dbus_connection_register_object (connection, + object_path, + data->interface_data->interface_info, + &export_vtable, + data, + (GDestroyNotify) export_data_free, + error); + fail: + export_data_free (data); + return 0; +} + +/* ---------------------------------------------------------------------------------------------------- */ + static GDBusArgInfo * get_arg_info (GICallableInfo *callable, GIArgInfo *arg, @@ -1757,8 +1933,6 @@ get_arg_info (GICallableInfo *callable, ret->name = g_strdup (name); ret->signature = g_variant_type_dup_string (gvariant_type); - g_print (" Using signature `%s' for param `%s'\n", ret->signature, ret->name); - out: if (gvariant_type != NULL) g_variant_type_free (gvariant_type); @@ -1797,8 +1971,6 @@ get_method_data (GIFunctionInfo *method, callable = (GICallableInfo *) method; - g_print ("Using dbus name `%s' for function `%s'\n", dbus_name, g_base_info_get_name ((GIBaseInfo *) method)); - /* Handle return value, if any */ return_type = g_callable_info_get_return_type (callable); ad = arg_data_new (); @@ -1988,8 +2160,6 @@ get_signal_data (GISignalInfo *signal, callable = (GICallableInfo *) signal; - g_print ("Using dbus name `%s' for signal `%s'\n", dbus_name, g_base_info_get_name ((GIBaseInfo *) signal)); - /* TODO: reject if it has a return value */ /* Go through all parameters */ @@ -2082,9 +2252,9 @@ get_signal_data (GISignalInfo *signal, /* ---------------------------------------------------------------------------------------------------- */ static GDBusInterfaceInfo * -compute_introspection_data (GObject *object, - ExportData *data, - GError **error) +compute_introspection_data (GType gtype, + InterfaceData *data, + GError **error) { GPtrArray *signal_infos; GPtrArray *method_infos; @@ -2099,14 +2269,14 @@ compute_introspection_data (GObject *object, info = NULL; repo = g_irepository_get_default (); - info = g_irepository_find_by_gtype (repo, G_OBJECT_TYPE (object)); + info = g_irepository_find_by_gtype (repo, gtype); if (info == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "Error looking up GIBaseInfo for object of type %s", - g_type_name (G_OBJECT_TYPE (object))); + "Error looking up GIBaseInfo for GType %s", + g_type_name (gtype)); goto out; } @@ -2118,8 +2288,8 @@ compute_introspection_data (GObject *object, g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "No gdbus.interface attribute on type %s", - g_type_name (G_OBJECT_TYPE (object))); + "No gdbus.interface attribute on GType %s", + g_type_name (gtype)); g_dbus_interface_info_unref (ret); ret = NULL; goto out; @@ -2153,7 +2323,7 @@ compute_introspection_data (GObject *object, } g_ptr_array_add (method_infos, method_data->dbus_method); - method_data_dump (method_data, 0); + /* method_data_dump (method_data, 0); */ g_hash_table_insert (data->dbus_method_name_to_method_data, g_strdup (dbus_name), @@ -2190,7 +2360,7 @@ compute_introspection_data (GObject *object, } g_ptr_array_add (signal_infos, signal_data->dbus_signal); - signal_data_dump (signal_data, 0); + /* signal_data_dump (signal_data, 0); */ g_hash_table_insert (data->g_signal_name_to_signal_data, g_strdup (g_base_info_get_name ((GIBaseInfo *) signal_data->signal)), @@ -2209,170 +2379,92 @@ compute_introspection_data (GObject *object, /* ---------------------------------------------------------------------------------------------------- */ -typedef struct -{ - GClosure parent_instance; +static GHashTable *gtype_to_interface_repo = NULL; - gulong signal_handler_id; - SignalData *signal_data; - ExportData *export_data; -} GDBusClosure; +G_LOCK_DEFINE_STATIC (repo_lock); -static GVariant * -process_signal_args (guint n_param_values, - const GValue *param_values, - SignalData *data) +/* called with repo_lock held */ +static InterfaceData * +compute_interface_data_for_gtype (GType gtype, + GError **error) { - guint n; - ArgData *ad; - GVariant *value; - GVariantType *gvariant_type; - GVariantBuilder builder; - GArgument *array_len_arg; - GITypeInfo *array_len_arg_type; - GArgument **args; - - g_assert_cmpint (n_param_values, ==, data->args->len); + InterfaceData *data; - /* Convert GValue to GArgument - * - * TODO: verify that the conversion really is that simple... - */ - args = g_new0 (GArgument *, n_param_values); - for (n = 0; n < n_param_values; n++) - args[n] = (GArgument *) &(param_values[n].data[0]); - - g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE); - for (n = 0; n < data->args->len; n++) - { - ad = data->args->pdata[n]; + data = g_new0 (InterfaceData, 1); - if (ad->dbus_arg_info == NULL) - continue; - - array_len_arg = NULL; - array_len_arg_type = NULL; - if (ad->array_len_position != -1) - { - array_len_arg = args[ad->array_len_position]; - array_len_arg_type = ((ArgData *) data->args->pdata[ad->array_len_position])->type_info; - } + data->dbus_method_name_to_method_data = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) method_data_free); - gvariant_type = g_variant_type_new (ad->dbus_arg_info->signature); - value = convert_gi_to_gvariant (args[n], - ad->type_info, - gvariant_type, - array_len_arg, - array_len_arg_type); - g_variant_ref_sink (value); - g_variant_builder_add_value (&builder, value); - g_variant_unref (value); - g_variant_type_free (gvariant_type); - } + data->g_signal_name_to_signal_data = g_hash_table_new_full (g_str_hash, + g_str_equal, + g_free, + (GDestroyNotify) signal_data_free); + data->interface_info = compute_introspection_data (gtype, + data, + error); + if (data->interface_info == NULL) + goto fail; - g_free (args); + return data; - return g_variant_builder_end (&builder); + fail: + interface_data_free (data); + return NULL; } -static void -marshal_signal_onto_dbus (GClosure *_closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) +static InterfaceData * +get_interface_data_for_gtype (GType gtype, + GError **error) { - GDBusClosure *closure = (GDBusClosure *) _closure; - GVariant *variant; - GError *error; + InterfaceData *id; - variant = process_signal_args (n_param_values, - param_values, - closure->signal_data); - error = NULL; - if (!g_dbus_connection_emit_signal (closure->export_data->connection, - NULL, - closure->export_data->object_path, - closure->export_data->info->name, - closure->signal_data->dbus_signal->name, - variant, - &error)) + G_LOCK (repo_lock); + if (gtype_to_interface_repo == NULL) + gtype_to_interface_repo = g_hash_table_new (g_direct_hash, g_direct_equal); + id = g_hash_table_lookup (gtype_to_interface_repo, GUINT_TO_POINTER (gtype)); + if (id == NULL) { - g_warning ("Error emitting D-Bus signal `%s' in response to G signal: %s", - closure->signal_data->dbus_signal->name, - error->message); - g_error_free (error); + id = compute_interface_data_for_gtype (gtype, error); + if (id != NULL) + g_hash_table_insert (gtype_to_interface_repo, GUINT_TO_POINTER (gtype), id); } - g_variant_unref (variant); + G_UNLOCK (repo_lock); + + return id; } -guint -g_dbus_connection_register_gobject (GDBusConnection *connection, - GObject *object, - const gchar *object_path, - gpointer user_data, - GDestroyNotify user_data_free_func, - GError **error) +/** + * g_dbus_interface_info_get_for_gtype: + * @gtype: A #GType for a #GObject<!-- -->-derived class. + * @error: Return location for error or %NULL. + * + * Looks at the runtime type introspection information for the + * #GObject<!-- -->-derived class identified by @gtype and returns a + * #GDBusInterfaceInfo. This only works if the type has suitable + * <literal>gdbus.*</literal> annotations. + * + * TODO: explain all about the gdbus.* annotations. + * + * Returns: A #GDBusInterfaceInfo (free with + * g_dbus_interface_info_free()) or %NULL if @error is set. + */ +GDBusInterfaceInfo * +g_dbus_interface_info_get_for_gtype (GType gtype, + GError **error) { - ExportData *data; - - g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), 0); - g_return_val_if_fail (G_IS_OBJECT (object), 0); - g_return_val_if_fail (g_variant_is_object_path (object_path), 0); - g_return_val_if_fail (error == NULL || *error == NULL, 0); - - data = g_new0 (ExportData, 1); - data->object = g_object_ref (object); - data->object_path = g_strdup (object_path); - data->connection = g_object_ref (connection); - data->user_data = user_data; - data->user_data_free_func = user_data_free_func; - - data->dbus_method_name_to_method_data = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - (GDestroyNotify) method_data_free); - data->g_signal_name_to_signal_data = g_hash_table_new_full (g_str_hash, - g_str_equal, - g_free, - (GDestroyNotify) signal_data_free); - - data->info = compute_introspection_data (object, - data, - error); - if (data->info == NULL) - goto fail; + GDBusInterfaceInfo *ret; + InterfaceData *id; - /* Set up signal handlers for all exported signals */ - GHashTableIter iter; - const gchar *g_signal_name; - SignalData *signal_data; - g_hash_table_iter_init (&iter, data->g_signal_name_to_signal_data); - while (g_hash_table_iter_next (&iter, (gpointer*) &g_signal_name, (gpointer*) &signal_data)) - { - GDBusClosure *closure; + g_return_val_if_fail (g_type_is_a (G_TYPE_FROM_INSTANCE (gtype), G_TYPE_OBJECT), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); - closure = (GDBusClosure *) g_closure_new_simple (sizeof (GDBusClosure), NULL); - g_closure_set_marshal ((GClosure *) closure, marshal_signal_onto_dbus); + ret = NULL; - closure->signal_data = signal_data; - closure->signal_handler_id = g_signal_connect_closure (object, - g_signal_name, - (GClosure *) closure, - TRUE); - closure->export_data = data; - /* TODO: we need to unregister these handlers in export_data_free() */ - } + id = get_interface_data_for_gtype (gtype, error); + if (id != NULL) + ret = g_dbus_interface_info_ref (id->interface_info); - return g_dbus_connection_register_object (connection, - object_path, - data->info, - &export_vtable, - data, - (GDestroyNotify) export_data_free, - error); - fail: - export_data_free (data); - return 0; + return ret; } diff --git a/src/gdbusgi.h b/src/gdbusgi.h index 86444ad..71f02f6 100644 --- a/src/gdbusgi.h +++ b/src/gdbusgi.h @@ -26,6 +26,10 @@ G_BEGIN_DECLS +GDBusInterfaceInfo * +g_dbus_interface_info_get_for_gtype (GType gtype, + GError **error); + guint g_dbus_connection_register_gobject (GDBusConnection *connection, GObject *object, const gchar *object_path, |