summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Zeuthen <davidz@redhat.com>2010-06-18 12:02:38 -0400
committerDavid Zeuthen <davidz@redhat.com>2010-06-18 12:02:38 -0400
commit54050bb239a60f59c573314bc87fbf4c2c740f6f (patch)
tree9c06c3badd31c3fb52f1df78812a3eea6ee3b039
parent427d3c5ea1f4af5d1f26f70ffae5606eb0a70618 (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.c438
-rw-r--r--src/gdbusgi.h4
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,