[glib: 1/2] gsignal: Add a new GSignalFlag to mark the first run of an accumulator function
- From: Philip Withnall <pwithnall src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [glib: 1/2] gsignal: Add a new GSignalFlag to mark the first run of an accumulator function
- Date: Mon, 21 Dec 2020 17:21:04 +0000 (UTC)
commit 9d1455444cdc1af7c867487385a3cb7b46bbfd08
Author: Sebastian Dröge <sebastian centricular com>
Date: Thu Feb 16 10:09:27 2012 +0100
gsignal: Add a new GSignalFlag to mark the first run of an accumulator function
Also add a test for signal accumulators. There was none before, and this
one now also covers the new flag.
Fixes https://gitlab.gnome.org/GNOME/glib/issues/514
gobject/gsignal.c | 13 ++++--
gobject/gsignal.h | 13 ++++--
gobject/tests/signals.c | 102 ++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 121 insertions(+), 7 deletions(-)
---
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index 81d2834b9..c3b453de7 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -1717,6 +1717,7 @@ g_signal_newv (const gchar *signal_name,
g_return_val_if_fail (accumulator == NULL, 0);
if (!accumulator)
g_return_val_if_fail (accu_data == NULL, 0);
+ g_return_val_if_fail ((signal_flags & G_SIGNAL_ACCUMULATOR_FIRST_RUN) == 0, 0);
if (!is_canonical (signal_name))
{
@@ -3241,6 +3242,8 @@ accumulate (GSignalInvocationHint *ihint,
continue_emission = accumulator->func (ihint, return_accu, handler_return, accumulator->data);
g_value_reset (handler_return);
+ ihint->run_type &= ~G_SIGNAL_ACCUMULATOR_FIRST_RUN;
+
return continue_emission;
}
@@ -3380,7 +3383,7 @@ g_signal_emit_valist (gpointer instance,
emission.instance = instance;
emission.ihint.signal_id = signal_id;
emission.ihint.detail = detail;
- emission.ihint.run_type = run_type;
+ emission.ihint.run_type = run_type | G_SIGNAL_ACCUMULATOR_FIRST_RUN;
emission.state = EMISSION_RUN;
emission.chain_type = instance_type;
emission_push (&emission);
@@ -3658,7 +3661,7 @@ signal_emit_unlocked_R (SignalNode *node,
if (handler_list)
handler_ref (handler_list);
- emission.ihint.run_type = G_SIGNAL_RUN_FIRST;
+ emission.ihint.run_type = G_SIGNAL_RUN_FIRST | G_SIGNAL_ACCUMULATOR_FIRST_RUN;
if ((node->flags & G_SIGNAL_RUN_FIRST) && class_closure)
{
@@ -3766,7 +3769,8 @@ signal_emit_unlocked_R (SignalNode *node,
goto EMIT_RESTART;
}
- emission.ihint.run_type = G_SIGNAL_RUN_LAST;
+ emission.ihint.run_type &= ~G_SIGNAL_RUN_FIRST;
+ emission.ihint.run_type |= G_SIGNAL_RUN_LAST;
if ((node->flags & G_SIGNAL_RUN_LAST) && class_closure)
{
@@ -3837,7 +3841,8 @@ signal_emit_unlocked_R (SignalNode *node,
EMIT_CLEANUP:
- emission.ihint.run_type = G_SIGNAL_RUN_CLEANUP;
+ emission.ihint.run_type &= ~G_SIGNAL_RUN_LAST;
+ emission.ihint.run_type |= G_SIGNAL_RUN_CLEANUP;
if ((node->flags & G_SIGNAL_RUN_CLEANUP) && class_closure)
{
diff --git a/gobject/gsignal.h b/gobject/gsignal.h
index 5cc2b6dfa..536102dad 100644
--- a/gobject/gsignal.h
+++ b/gobject/gsignal.h
@@ -119,7 +119,10 @@ typedef gboolean (*GSignalAccumulator) (GSignalInvocationHint *ihint,
* @G_SIGNAL_DEPRECATED: The signal is deprecated and will be removed
* in a future version. A warning will be generated if it is connected while
* running with G_ENABLE_DIAGNOSTIC=1. Since 2.32.
- *
+ * @G_SIGNAL_ACCUMULATOR_FIRST_RUN: Only used in #GSignalAccumulator accumulator
+ * functions for the #GSignalInvocationHint::run_type field to mark the first
+ * call to the accumulator function for a signal emission. Since 2.68.
+ *
* The signal flags are used to specify a signal's behaviour, the overall
* signal description outlines how especially the RUN flags control the
* stages of a signal emission.
@@ -134,7 +137,9 @@ typedef enum
G_SIGNAL_ACTION = 1 << 5,
G_SIGNAL_NO_HOOKS = 1 << 6,
G_SIGNAL_MUST_COLLECT = 1 << 7,
- G_SIGNAL_DEPRECATED = 1 << 8
+ G_SIGNAL_DEPRECATED = 1 << 8,
+ /* normal signal flags until 1 << 16 */
+ G_SIGNAL_ACCUMULATOR_FIRST_RUN = 1 << 17,
} GSignalFlags;
/**
* G_SIGNAL_FLAGS_MASK:
@@ -215,7 +220,9 @@ typedef enum
* @detail: The detail passed on for this emission
* @run_type: The stage the signal emission is currently in, this
* field will contain one of %G_SIGNAL_RUN_FIRST,
- * %G_SIGNAL_RUN_LAST or %G_SIGNAL_RUN_CLEANUP.
+ * %G_SIGNAL_RUN_LAST or %G_SIGNAL_RUN_CLEANUP and %G_SIGNAL_ACCUMULATOR_FIRST_RUN.
+ * %G_SIGNAL_ACCUMULATOR_FIRST_RUN is only set for the first run of the accumulator
+ * function for a signal emission.
*
* The #GSignalInvocationHint structure is used to pass on additional information
* to callbacks during a signal emission.
diff --git a/gobject/tests/signals.c b/gobject/tests/signals.c
index 55d5207ca..37d06a237 100644
--- a/gobject/tests/signals.c
+++ b/gobject/tests/signals.c
@@ -185,6 +185,7 @@ struct _Test
};
static void all_types_handler (Test *test, int i, gboolean b, char c, guchar uc, guint ui, glong l, gulong
ul, MyEnum e, MyFlags f, float fl, double db, char *str, GParamSpec *param, GBytes *bytes, gpointer ptr, Test
*obj, GVariant *var, gint64 i64, guint64 ui64);
+static gboolean accumulator_sum (GSignalInvocationHint *ihint, GValue *return_accu, const GValue
*handler_return, gpointer data);
struct _TestClass
{
@@ -238,6 +239,14 @@ test_class_init (TestClass *klass)
NULL,
G_TYPE_NONE,
0);
+ g_signal_new ("simple-accumulator",
+ G_TYPE_FROM_CLASS (klass),
+ G_SIGNAL_RUN_LAST,
+ 0,
+ accumulator_sum, NULL,
+ NULL,
+ G_TYPE_INT,
+ 0);
g_signal_new ("generic-marshaller-1",
G_TYPE_FROM_CLASS (klass),
G_SIGNAL_RUN_LAST,
@@ -1127,6 +1136,97 @@ test_invocation_hint (void)
g_object_unref (test);
}
+static gboolean
+accumulator_sum (GSignalInvocationHint *ihint,
+ GValue *return_accu,
+ const GValue *handler_return,
+ gpointer data)
+{
+ gint acc = g_value_get_int (return_accu);
+ gint ret = g_value_get_int (handler_return);
+
+ g_assert_cmpint (ret, >, 0);
+
+ if (ihint->run_type & G_SIGNAL_ACCUMULATOR_FIRST_RUN)
+ {
+ g_assert_cmpint (acc, ==, 0);
+ g_assert_cmpint (ret, ==, 1);
+ g_assert_true (ihint->run_type & G_SIGNAL_RUN_FIRST);
+ g_assert_false (ihint->run_type & G_SIGNAL_RUN_LAST);
+ }
+ else if (ihint->run_type & G_SIGNAL_RUN_FIRST)
+ {
+ /* Only the first signal handler was called so far */
+ g_assert_cmpint (acc, ==, 1);
+ g_assert_cmpint (ret, ==, 2);
+ g_assert_false (ihint->run_type & G_SIGNAL_RUN_LAST);
+ }
+ else if (ihint->run_type & G_SIGNAL_RUN_LAST)
+ {
+ /* Only the first two signal handler were called so far */
+ g_assert_cmpint (acc, ==, 3);
+ g_assert_cmpint (ret, ==, 3);
+ g_assert_false (ihint->run_type & G_SIGNAL_RUN_FIRST);
+ }
+ else
+ {
+ g_assert_not_reached ();
+ }
+
+ g_value_set_int (return_accu, acc + ret);
+
+ /* Continue with the other signal handlers as long as the sum is < 6,
+ * i.e. don't run simple_accumulator_4_cb() */
+ return acc + ret < 6;
+}
+
+static gint
+simple_accumulator_1_cb (gpointer instance, gpointer data)
+{
+ return 1;
+}
+
+static gint
+simple_accumulator_2_cb (gpointer instance, gpointer data)
+{
+ return 2;
+}
+
+static gint
+simple_accumulator_3_cb (gpointer instance, gpointer data)
+{
+ return 3;
+}
+
+static gint
+simple_accumulator_4_cb (gpointer instance, gpointer data)
+{
+ return 4;
+}
+
+static void
+test_accumulator (void)
+{
+ GObject *test;
+ gint ret = -1;
+
+ test = g_object_new (test_get_type (), NULL);
+
+ /* Connect in reverse order to make sure that LAST signal handlers are
+ * called after FIRST signal handlers but signal handlers in each "group"
+ * are called in the order they were registered */
+ g_signal_connect_after (test, "simple-accumulator", G_CALLBACK (simple_accumulator_3_cb), NULL);
+ g_signal_connect_after (test, "simple-accumulator", G_CALLBACK (simple_accumulator_4_cb), NULL);
+ g_signal_connect (test, "simple-accumulator", G_CALLBACK (simple_accumulator_1_cb), NULL);
+ g_signal_connect (test, "simple-accumulator", G_CALLBACK (simple_accumulator_2_cb), NULL);
+ g_signal_emit_by_name (test, "simple-accumulator", &ret);
+
+ /* simple_accumulator_4_cb() is not run because accumulator is 6 */
+ g_assert_cmpint (ret, ==, 6);
+
+ g_object_unref (test);
+}
+
static gboolean
in_set (const gchar *s,
const gchar *set[])
@@ -1153,6 +1253,7 @@ test_introspection (void)
"simple",
"simple-detailed",
"simple-2",
+ "simple-accumulator",
"generic-marshaller-1",
"generic-marshaller-2",
"generic-marshaller-enum-return-signed",
@@ -1578,6 +1679,7 @@ main (int argc,
g_test_add_func ("/gobject/signals/custom-marshaller", test_custom_marshaller);
g_test_add_func ("/gobject/signals/connect", test_connect);
g_test_add_func ("/gobject/signals/emission-hook", test_emission_hook);
+ g_test_add_func ("/gobject/signals/accumulator", test_accumulator);
g_test_add_func ("/gobject/signals/introspection", test_introspection);
g_test_add_func ("/gobject/signals/block-handler", test_block_handler);
g_test_add_func ("/gobject/signals/stop-emission", test_stop_emission);
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]