[glib: 1/2] gobject: Add g_signal_group_connect_closure




commit 2a842b1173eaca3423e955e110227df00fecde43
Author: Jason Francis <jafrancis999 gmail com>
Date:   Tue Feb 22 14:51:37 2022 -0500

    gobject: Add g_signal_group_connect_closure

 docs/reference/gobject/gobject-sections.txt |  1 +
 gobject/gsignalgroup.c                      | 81 ++++++++++++++++++++---------
 gobject/gsignalgroup.h                      |  5 ++
 gobject/tests/signalgroup.c                 | 21 ++++++--
 4 files changed, 79 insertions(+), 29 deletions(-)
---
diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt
index cbab92406a..278c756104 100644
--- a/docs/reference/gobject/gobject-sections.txt
+++ b/docs/reference/gobject/gobject-sections.txt
@@ -1034,6 +1034,7 @@ g_signal_group_connect_after
 g_signal_group_connect_data
 g_signal_group_connect_object
 g_signal_group_connect_swapped
+g_signal_group_connect_closure
 g_signal_group_dup_target
 g_signal_group_get_type
 g_signal_group_new
diff --git a/gobject/gsignalgroup.c b/gobject/gsignalgroup.c
index 8feba543c2..01a0a12c8b 100644
--- a/gobject/gsignalgroup.c
+++ b/gobject/gsignalgroup.c
@@ -705,18 +705,28 @@ g_signal_group_new (GType target_type)
                        NULL);
 }
 
-static void
-g_signal_group_connect_full (GSignalGroup   *self,
-                             const gchar    *detailed_signal,
-                             GCallback       c_handler,
-                             gpointer        data,
-                             GClosureNotify  notify,
-                             GConnectFlags   flags,
-                             gboolean        is_object)
+/**
+ * g_signal_group_connect_closure:
+ * @self: a #GSignalGroup
+ * @detailed_signal: a string of the form `signal-name` with optional `::signal-detail`
+ * @closure: (not nullable): the closure to connect.
+ * @after: whether the handler should be called before or after the
+ *  default handler of the signal.
+ *
+ * Connects @closure to the signal @detailed_signal on #GSignalGroup:target.
+ *
+ * You cannot connect a signal handler after #GSignalGroup:target has been set.
+ *
+ * Since: 2.74
+ */
+void
+g_signal_group_connect_closure (GSignalGroup   *self,
+                                const gchar    *detailed_signal,
+                                GClosure       *closure,
+                                gboolean        after)
 {
   GObject *target;
   SignalHandler *handler;
-  GClosure *closure;
   guint signal_id;
   GQuark signal_detail;
 
@@ -724,8 +734,7 @@ g_signal_group_connect_full (GSignalGroup   *self,
   g_return_if_fail (detailed_signal != NULL);
   g_return_if_fail (g_signal_parse_name (detailed_signal, self->target_type,
                                          &signal_id, &signal_detail, TRUE) != 0);
-  g_return_if_fail (c_handler != NULL);
-  g_return_if_fail (!is_object || G_IS_OBJECT (data));
+  g_return_if_fail (closure != NULL);
 
   g_rec_mutex_lock (&self->mutex);
 
@@ -736,29 +745,15 @@ g_signal_group_connect_full (GSignalGroup   *self,
       return;
     }
 
-  if ((flags & G_CONNECT_SWAPPED) != 0)
-    closure = g_cclosure_new_swap (c_handler, data, notify);
-  else
-    closure = g_cclosure_new (c_handler, data, notify);
-
   handler = g_slice_new0 (SignalHandler);
   handler->group = self;
   handler->signal_id = signal_id;
   handler->signal_detail = signal_detail;
   handler->closure = g_closure_ref (closure);
-  handler->connect_after = ((flags & G_CONNECT_AFTER) != 0);
+  handler->connect_after = after;
 
   g_closure_sink (closure);
 
-  if (is_object)
-    {
-      /* Set closure->is_invalid when data is disposed. We only track this to avoid
-       * reconnecting in the future. However, we do a round of cleanup when ever we
-       * connect a new object or the target changes to GC the old handlers.
-       */
-      g_object_watch_closure (data, closure);
-    }
-
   g_ptr_array_add (self->handlers, handler);
 
   target = g_weak_ref_get (&self->target_ref);
@@ -775,6 +770,40 @@ g_signal_group_connect_full (GSignalGroup   *self,
   g_rec_mutex_unlock (&self->mutex);
 }
 
+static void
+g_signal_group_connect_full (GSignalGroup   *self,
+                             const gchar    *detailed_signal,
+                             GCallback       c_handler,
+                             gpointer        data,
+                             GClosureNotify  notify,
+                             GConnectFlags   flags,
+                             gboolean        is_object)
+{
+  GClosure *closure;
+
+  g_return_if_fail (c_handler != NULL);
+  g_return_if_fail (!is_object || G_IS_OBJECT (data));
+
+  if ((flags & G_CONNECT_SWAPPED) != 0)
+    closure = g_cclosure_new_swap (c_handler, data, notify);
+  else
+    closure = g_cclosure_new (c_handler, data, notify);
+
+  if (is_object)
+    {
+      /* Set closure->is_invalid when data is disposed. We only track this to avoid
+       * reconnecting in the future. However, we do a round of cleanup when ever we
+       * connect a new object or the target changes to GC the old handlers.
+       */
+      g_object_watch_closure (data, closure);
+    }
+
+  g_signal_group_connect_closure (self,
+                                  detailed_signal,
+                                  closure,
+                                  (flags & G_CONNECT_AFTER) != 0);
+}
+
 /**
  * g_signal_group_connect_object: (skip)
  * @self: a #GSignalGroup
diff --git a/gobject/gsignalgroup.h b/gobject/gsignalgroup.h
index c82a5cd4fa..ec93bdd619 100644
--- a/gobject/gsignalgroup.h
+++ b/gobject/gsignalgroup.h
@@ -59,6 +59,11 @@ GLIB_AVAILABLE_IN_2_72
 void          g_signal_group_block           (GSignalGroup   *self);
 GLIB_AVAILABLE_IN_2_72
 void          g_signal_group_unblock         (GSignalGroup   *self);
+GLIB_AVAILABLE_IN_2_74
+void          g_signal_group_connect_closure (GSignalGroup   *self,
+                                              const gchar    *detailed_signal,
+                                              GClosure       *closure,
+                                              gboolean        after);
 GLIB_AVAILABLE_IN_2_72
 void          g_signal_group_connect_object  (GSignalGroup   *self,
                                               const gchar    *detailed_signal,
diff --git a/gobject/tests/signalgroup.c b/gobject/tests/signalgroup.c
index 5d1f17a813..9b82dc45f3 100644
--- a/gobject/tests/signalgroup.c
+++ b/gobject/tests/signalgroup.c
@@ -107,7 +107,7 @@ connect_after_cb (SignalTarget *target,
   g_assert_true (readback == target);
   g_object_unref (readback);
 
-  g_assert_cmpint (*signal_calls, ==, 4);
+  g_assert_cmpint (*signal_calls, ==, 5);
   *signal_calls += 1;
 }
 
@@ -194,7 +194,8 @@ connect_data_weak_notify_cb (gboolean     *weak_notify_called,
 static void
 connect_all_signals (GSignalGroup *group)
 {
-  GObject *object;
+  GObject  *object;
+  GClosure *closure;
 
   /* Check that these are called in the right order */
   g_signal_group_connect (group,
@@ -245,6 +246,20 @@ connect_all_signals (GSignalGroup *group)
   g_object_weak_ref (G_OBJECT (group),
                      (GWeakNotify)connect_data_weak_notify_cb,
                      &global_weak_notify_called);
+
+
+  /* Check that this can be called as a GClosure */
+  closure = g_cclosure_new (G_CALLBACK (connect_before_cb),
+                            &global_signal_calls,
+                            NULL);
+  g_signal_group_connect_closure (group, "the-signal", closure, FALSE);
+
+  /* Check that invalidated GClosures don't get called */
+  closure = g_cclosure_new (G_CALLBACK (connect_before_cb),
+                            &global_signal_calls,
+                            NULL);
+  g_closure_invalidate (closure);
+  g_signal_group_connect_closure (group, "the-signal", closure, FALSE);
 }
 
 static void
@@ -258,7 +273,7 @@ assert_signals (SignalTarget *target,
   global_signal_calls = 0;
   g_signal_emit (target, signals[THE_SIGNAL],
                  signal_detail_quark (), group);
-  g_assert_cmpint (global_signal_calls, ==, success ? 5 : 0);
+  g_assert_cmpint (global_signal_calls, ==, success ? 6 : 0);
 }
 
 static void


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]