[glib] Add a g_dbus_connection_register_object_with_closures function



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 (&params[0], G_TYPE_DBUS_CONNECTION);
+  g_value_set_object (&params[0], connection);
+
+  g_value_init (&params[1], G_TYPE_STRING);
+  g_value_set_string (&params[1], sender);
+
+  g_value_init (&params[2], G_TYPE_STRING);
+  g_value_set_string (&params[2], object_path);
+
+  g_value_init (&params[3], G_TYPE_STRING);
+  g_value_set_string (&params[3], interface_name);
+
+  g_value_init (&params[4], G_TYPE_STRING);
+  g_value_set_string (&params[4], method_name);
+
+  g_value_init (&params[5], G_TYPE_VARIANT);
+  g_value_set_variant (&params[5], parameters);
+
+  g_value_init (&params[6], G_TYPE_DBUS_METHOD_INVOCATION);
+  g_value_set_object (&params[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 (&params[0], G_TYPE_DBUS_CONNECTION);
+  g_value_set_object (&params[0], connection);
+
+  g_value_init (&params[1], G_TYPE_STRING);
+  g_value_set_string (&params[1], sender);
+
+  g_value_init (&params[2], G_TYPE_STRING);
+  g_value_set_string (&params[2], object_path);
+
+  g_value_init (&params[3], G_TYPE_STRING);
+  g_value_set_string (&params[3], interface_name);
+
+  g_value_init (&params[4], G_TYPE_STRING);
+  g_value_set_string (&params[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 (&params[0], G_TYPE_DBUS_CONNECTION);
+  g_value_set_object (&params[0], connection);
+
+  g_value_init (&params[1], G_TYPE_STRING);
+  g_value_set_string (&params[1], sender);
+
+  g_value_init (&params[2], G_TYPE_STRING);
+  g_value_set_string (&params[2], object_path);
+
+  g_value_init (&params[3], G_TYPE_STRING);
+  g_value_set_string (&params[3], interface_name);
+
+  g_value_init (&params[4], G_TYPE_STRING);
+  g_value_set_string (&params[4], property_name);
+
+  g_value_init (&params[5], G_TYPE_VARIANT);
+  g_value_set_variant (&params[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]