gobject: Add g_signal_group_connect_closure

This commit is contained in:
Jason Francis 2022-02-22 14:51:37 -05:00 committed by Philip Withnall
parent 28add9abfe
commit 2a842b1173
4 changed files with 79 additions and 29 deletions

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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