[glib] Add a g_dbus_connection_register_object_with_closures function
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib] Add a g_dbus_connection_register_object_with_closures function
- Date: Tue, 18 Aug 2015 20:41:28 +0000 (UTC)
commit 5d014a802a4b47fbf5774f613d61b4218a1aa2a2
Author: Janusz Lewandowski <lew21 xtreeme org>
Date: Fri Oct 10 22:58:20 2014 +0200
Add a g_dbus_connection_register_object_with_closures function
This is a binding-friendly version of g_dbus_connection_register_object.
Based on a patch by Martin Pitt and the code of g_bus_watch_name_with_closures.
https://bugzilla.gnome.org/show_bug.cgi?id=656325
docs/reference/gio/gio-sections.txt | 1 +
gio/gdbusconnection.c | 253 +++++++++++++++++++++++++++++++++++
gio/gdbusconnection.h | 8 +
gio/tests/gdbus-export.c | 58 +++++++-
4 files changed, 313 insertions(+), 7 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 993fe06..2f3f46d 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -2876,6 +2876,7 @@ GDBusInterfaceGetPropertyFunc
GDBusInterfaceSetPropertyFunc
g_dbus_connection_register_object
g_dbus_connection_unregister_object
+g_dbus_connection_register_object_with_closures
GDBusSubtreeVTable
GDBusSubtreeEnumerateFunc
GDBusSubtreeIntrospectFunc
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 9824ad9..4a8d9a5 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -5172,6 +5172,259 @@ g_dbus_connection_unregister_object (GDBusConnection *connection,
return ret;
}
+typedef struct {
+ GClosure *method_call_closure;
+ GClosure *get_property_closure;
+ GClosure *set_property_closure;
+} RegisterObjectData;
+
+static RegisterObjectData *
+register_object_data_new (GClosure *method_call_closure,
+ GClosure *get_property_closure,
+ GClosure *set_property_closure)
+{
+ RegisterObjectData *data;
+
+ data = g_new0 (RegisterObjectData, 1);
+
+ if (method_call_closure != NULL)
+ {
+ data->method_call_closure = g_closure_ref (method_call_closure);
+ g_closure_sink (method_call_closure);
+ if (G_CLOSURE_NEEDS_MARSHAL (method_call_closure))
+ g_closure_set_marshal (method_call_closure, g_cclosure_marshal_generic);
+ }
+
+ if (get_property_closure != NULL)
+ {
+ data->get_property_closure = g_closure_ref (get_property_closure);
+ g_closure_sink (get_property_closure);
+ if (G_CLOSURE_NEEDS_MARSHAL (get_property_closure))
+ g_closure_set_marshal (get_property_closure, g_cclosure_marshal_generic);
+ }
+
+ if (set_property_closure != NULL)
+ {
+ data->set_property_closure = g_closure_ref (set_property_closure);
+ g_closure_sink (set_property_closure);
+ if (G_CLOSURE_NEEDS_MARSHAL (set_property_closure))
+ g_closure_set_marshal (set_property_closure, g_cclosure_marshal_generic);
+ }
+
+ return data;
+}
+
+static void
+register_object_free_func (gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+
+ g_clear_pointer (&data->method_call_closure, g_closure_unref);
+ g_clear_pointer (&data->get_property_closure, g_closure_unref);
+ g_clear_pointer (&data->set_property_closure, g_closure_unref);
+
+ g_free (data);
+}
+
+static void
+register_with_closures_on_method_call (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+ GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT,
G_VALUE_INIT };
+
+ g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
+ g_value_set_object (¶ms[0], connection);
+
+ g_value_init (¶ms[1], G_TYPE_STRING);
+ g_value_set_string (¶ms[1], sender);
+
+ g_value_init (¶ms[2], G_TYPE_STRING);
+ g_value_set_string (¶ms[2], object_path);
+
+ g_value_init (¶ms[3], G_TYPE_STRING);
+ g_value_set_string (¶ms[3], interface_name);
+
+ g_value_init (¶ms[4], G_TYPE_STRING);
+ g_value_set_string (¶ms[4], method_name);
+
+ g_value_init (¶ms[5], G_TYPE_VARIANT);
+ g_value_set_variant (¶ms[5], parameters);
+
+ g_value_init (¶ms[6], G_TYPE_DBUS_METHOD_INVOCATION);
+ g_value_set_object (¶ms[6], invocation);
+
+ g_closure_invoke (data->method_call_closure, NULL, G_N_ELEMENTS (params), params, NULL);
+
+ g_value_unset (params + 0);
+ g_value_unset (params + 1);
+ g_value_unset (params + 2);
+ g_value_unset (params + 3);
+ g_value_unset (params + 4);
+ g_value_unset (params + 5);
+ g_value_unset (params + 6);
+}
+
+static GVariant *
+register_with_closures_on_get_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+ GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
+ GValue result_value = G_VALUE_INIT;
+ GVariant *result;
+
+ g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
+ g_value_set_object (¶ms[0], connection);
+
+ g_value_init (¶ms[1], G_TYPE_STRING);
+ g_value_set_string (¶ms[1], sender);
+
+ g_value_init (¶ms[2], G_TYPE_STRING);
+ g_value_set_string (¶ms[2], object_path);
+
+ g_value_init (¶ms[3], G_TYPE_STRING);
+ g_value_set_string (¶ms[3], interface_name);
+
+ g_value_init (¶ms[4], G_TYPE_STRING);
+ g_value_set_string (¶ms[4], property_name);
+
+ g_value_init (&result_value, G_TYPE_VARIANT);
+
+ g_closure_invoke (data->get_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
+
+ result = g_value_get_variant (&result_value);
+ if (result)
+ g_variant_ref (result);
+
+ g_value_unset (params + 0);
+ g_value_unset (params + 1);
+ g_value_unset (params + 2);
+ g_value_unset (params + 3);
+ g_value_unset (params + 4);
+ g_value_unset (&result_value);
+
+ if (!result)
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ _("Unable to retrieve property %s.%s"),
+ interface_name, property_name);
+
+ return result;
+}
+
+static gboolean
+register_with_closures_on_set_property (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *object_path,
+ const gchar *interface_name,
+ const gchar *property_name,
+ GVariant *value,
+ GError **error,
+ gpointer user_data)
+{
+ RegisterObjectData *data = user_data;
+ GValue params[] = { G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT, G_VALUE_INIT };
+ GValue result_value = G_VALUE_INIT;
+ gboolean result;
+
+ g_value_init (¶ms[0], G_TYPE_DBUS_CONNECTION);
+ g_value_set_object (¶ms[0], connection);
+
+ g_value_init (¶ms[1], G_TYPE_STRING);
+ g_value_set_string (¶ms[1], sender);
+
+ g_value_init (¶ms[2], G_TYPE_STRING);
+ g_value_set_string (¶ms[2], object_path);
+
+ g_value_init (¶ms[3], G_TYPE_STRING);
+ g_value_set_string (¶ms[3], interface_name);
+
+ g_value_init (¶ms[4], G_TYPE_STRING);
+ g_value_set_string (¶ms[4], property_name);
+
+ g_value_init (¶ms[5], G_TYPE_VARIANT);
+ g_value_set_variant (¶ms[5], value);
+
+ g_value_init (&result_value, G_TYPE_BOOLEAN);
+
+ g_closure_invoke (data->set_property_closure, &result_value, G_N_ELEMENTS (params), params, NULL);
+
+ result = g_value_get_boolean (&result_value);
+
+ g_value_unset (params + 0);
+ g_value_unset (params + 1);
+ g_value_unset (params + 2);
+ g_value_unset (params + 3);
+ g_value_unset (params + 4);
+ g_value_unset (params + 5);
+ g_value_unset (&result_value);
+
+ if (!result)
+ g_set_error (error,
+ G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ _("Unable to set property %s.%s"),
+ interface_name, property_name);
+
+ return result;
+}
+
+/**
+ * g_dbus_connection_register_object_with_closures: (rename-to g_dbus_connection_register_object)
+ * @connection: A #GDBusConnection.
+ * @object_path: The object path to register at.
+ * @interface_info: Introspection data for the interface.
+ * @method_call_closure: (nullable): #GClosure for handling incoming method calls.
+ * @get_property_closure: (nullable): #GClosure for getting a property.
+ * @set_property_closure: (nullable): #GClosure for setting a property.
+ * @error: Return location for error or %NULL.
+ *
+ * Version of g_dbus_connection_register_object() using closures instead of a
+ * #GDBusInterfaceVTable for easier binding in other languages.
+ *
+ * Returns: 0 if @error is set, otherwise a registration id (never 0)
+ * that can be used with g_dbus_connection_unregister_object() .
+ *
+ * Since: 2.46
+ */
+guint
+g_dbus_connection_register_object_with_closures (GDBusConnection *connection,
+ const gchar *object_path,
+ GDBusInterfaceInfo *interface_info,
+ GClosure *method_call_closure,
+ GClosure *get_property_closure,
+ GClosure *set_property_closure,
+ GError **error)
+{
+ RegisterObjectData *data;
+ GDBusInterfaceVTable vtable =
+ {
+ method_call_closure != NULL ? register_with_closures_on_method_call : NULL,
+ get_property_closure != NULL ? register_with_closures_on_get_property : NULL,
+ set_property_closure != NULL ? register_with_closures_on_set_property : NULL
+ };
+
+ data = register_object_data_new (method_call_closure, get_property_closure, set_property_closure);
+
+ return g_dbus_connection_register_object (connection,
+ object_path,
+ interface_info,
+ &vtable,
+ data,
+ register_object_free_func,
+ error);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
/**
diff --git a/gio/gdbusconnection.h b/gio/gdbusconnection.h
index ba054db..6876cd4 100644
--- a/gio/gdbusconnection.h
+++ b/gio/gdbusconnection.h
@@ -401,6 +401,14 @@ guint g_dbus_connection_register_object (GDBusConnection
gpointer user_data,
GDestroyNotify
user_data_free_func,
GError **error);
+GLIB_AVAILABLE_IN_2_46
+guint g_dbus_connection_register_object_with_closures (GDBusConnection *connection,
+ const gchar *object_path,
+ GDBusInterfaceInfo *interface_info,
+ GClosure
*method_call_closure,
+ GClosure
*get_property_closure,
+ GClosure
*set_property_closure,
+ GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_unregister_object (GDBusConnection *connection,
guint registration_id);
diff --git a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c
index 5940501..921ba40 100644
--- a/gio/tests/gdbus-export.c
+++ b/gio/tests/gdbus-export.c
@@ -733,10 +733,17 @@ static const GDBusSubtreeVTable dynamic_subtree_vtable =
/* -------------------- */
+typedef struct
+{
+ const gchar *object_path;
+ gboolean check_remote_errors;
+} TestDispatchThreadFuncArgs;
+
static gpointer
test_dispatch_thread_func (gpointer user_data)
{
- const gchar *object_path = user_data;
+ TestDispatchThreadFuncArgs *args = user_data;
+ const gchar *object_path = args->object_path;
GDBusProxy *foo_proxy;
GVariant *value;
GVariant *inner;
@@ -897,8 +904,13 @@ test_dispatch_thread_func (gpointer user_data)
NULL,
&error);
g_assert (value == NULL);
- g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FILE_INVALID);
- g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.Spawn.FileInvalid: Returning
some error instead of writing the value 'NotReadable' to the property ''But Writable you are!''");
+ if (args->check_remote_errors)
+ {
+ /* _with_closures variant doesn't support customizing error data. */
+ g_assert_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_FILE_INVALID);
+ g_assert_cmpstr (error->message, ==, "GDBus.Error:org.freedesktop.DBus.Error.Spawn.FileInvalid:
Returning some error instead of writing the value 'NotReadable' to the property ''But Writable you are!''");
+ }
+ g_assert (error != NULL && error->domain == G_DBUS_ERROR);
g_error_free (error);
error = NULL;
@@ -941,14 +953,17 @@ test_dispatch_thread_func (gpointer user_data)
}
static void
-test_dispatch (const gchar *object_path)
+test_dispatch (const gchar *object_path,
+ gboolean check_remote_errors)
{
GThread *thread;
+
+ TestDispatchThreadFuncArgs args = {object_path, check_remote_errors};
/* run this in a thread to avoid deadlocks */
thread = g_thread_new ("test_dispatch",
test_dispatch_thread_func,
- (gpointer) object_path);
+ (gpointer) &args);
g_main_loop_run (loop);
g_thread_join (thread);
}
@@ -1344,8 +1359,8 @@ test_object_registration (void)
* We do this for both a regular registered object (/foo/boss) and also for an object
* registered through the subtree mechanism.
*/
- test_dispatch ("/foo/boss");
- test_dispatch ("/foo/boss/executives/vp0");
+ test_dispatch ("/foo/boss", TRUE);
+ test_dispatch ("/foo/boss/executives/vp0", TRUE);
/* To prevent from exiting and attaching a D-Bus tool like D-Feet; uncomment: */
#if 0
@@ -1392,6 +1407,34 @@ test_object_registration (void)
g_object_unref (c);
}
+static void
+test_object_registration_with_closures (void)
+{
+ GError *error;
+ guint registration_id;
+
+ error = NULL;
+ c = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (c != NULL);
+
+ registration_id = g_dbus_connection_register_object_with_closures (c,
+ "/foo/boss",
+ (GDBusInterfaceInfo *)
&foo_interface_info,
+ g_cclosure_new (G_CALLBACK
(foo_method_call), NULL, NULL),
+ g_cclosure_new (G_CALLBACK
(foo_get_property), NULL, NULL),
+ g_cclosure_new (G_CALLBACK
(foo_set_property), NULL, NULL),
+ &error);
+ g_assert_no_error (error);
+ g_assert (registration_id > 0);
+
+ test_dispatch ("/foo/boss", FALSE);
+
+ g_assert (g_dbus_connection_unregister_object (c, registration_id));
+
+ g_object_unref (c);
+}
+
static const GDBusInterfaceInfo test_interface_info1 =
{
-1,
@@ -1738,6 +1781,7 @@ main (int argc,
loop = g_main_loop_new (NULL, FALSE);
g_test_add_func ("/gdbus/object-registration", test_object_registration);
+ g_test_add_func ("/gdbus/object-registration-with-closures", test_object_registration_with_closures);
g_test_add_func ("/gdbus/registered-interfaces", test_registered_interfaces);
g_test_add_func ("/gdbus/async-properties", test_async_properties);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]