From 3581eda9a2ed8d7731ce80d16bb03d84ad251e92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= Date: Thu, 16 Feb 2012 09:57:48 +0100 Subject: [PATCH] gsignal: Allow return types for RUN_FIRST-only signals too Also adds a test that checks that the G_SIGNAL_RUN flags are handled correctly and the class signal handler is called at the right times. Fixes https://gitlab.gnome.org/GNOME/glib/issues/513 --- gobject/gsignal.c | 9 --- gobject/tests/signals.c | 129 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 129 insertions(+), 9 deletions(-) diff --git a/gobject/gsignal.c b/gobject/gsignal.c index c3b453de7..d8a4cd9d9 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -1771,15 +1771,6 @@ g_signal_newv (const gchar *signal_name, SIGNAL_UNLOCK (); return 0; } - if (return_type != G_TYPE_NONE && - (signal_flags & (G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP)) == G_SIGNAL_RUN_FIRST) - { - g_warning (G_STRLOC ": signal \"%s::%s\" has return type '%s' and is only G_SIGNAL_RUN_FIRST", - type_debug_name (itype), name, type_debug_name (return_type)); - g_free (signal_name_copy); - SIGNAL_UNLOCK (); - return 0; - } /* setup permanent portion of signal node */ if (!node) diff --git a/gobject/tests/signals.c b/gobject/tests/signals.c index 37d06a237..ea9a778bf 100644 --- a/gobject/tests/signals.c +++ b/gobject/tests/signals.c @@ -186,6 +186,8 @@ 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); +static gboolean accumulator_concat_string (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer data); +static gchar * accumulator_class (Test *test); struct _TestClass { @@ -194,6 +196,7 @@ struct _TestClass void (* variant_changed) (Test *, GVariant *); void (* all_types) (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); void (* all_types_null) (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); + gchar * (*accumulator_class) (Test *test); }; static GType test_get_type (void); @@ -213,6 +216,7 @@ test_class_init (TestClass *klass) flags_type = g_flags_register_static ("MyFlag", my_flag_values); klass->all_types = all_types_handler; + klass->accumulator_class = accumulator_class; simple_id = g_signal_new ("simple", G_TYPE_FROM_CLASS (klass), @@ -247,6 +251,54 @@ test_class_init (TestClass *klass) NULL, G_TYPE_INT, 0); + g_signal_new ("accumulator-class-first", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (TestClass, accumulator_class), + accumulator_concat_string, NULL, + NULL, + G_TYPE_STRING, + 0); + g_signal_new ("accumulator-class-last", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TestClass, accumulator_class), + accumulator_concat_string, NULL, + NULL, + G_TYPE_STRING, + 0); + g_signal_new ("accumulator-class-cleanup", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (TestClass, accumulator_class), + accumulator_concat_string, NULL, + NULL, + G_TYPE_STRING, + 0); + g_signal_new ("accumulator-class-first-last", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TestClass, accumulator_class), + accumulator_concat_string, NULL, + NULL, + G_TYPE_STRING, + 0); + g_signal_new ("accumulator-class-first-last-cleanup", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_FIRST | G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (TestClass, accumulator_class), + accumulator_concat_string, NULL, + NULL, + G_TYPE_STRING, + 0); + g_signal_new ("accumulator-class-last-cleanup", + G_TYPE_FROM_CLASS (klass), + G_SIGNAL_RUN_LAST | G_SIGNAL_RUN_CLEANUP, + G_STRUCT_OFFSET (TestClass, accumulator_class), + accumulator_concat_string, NULL, + NULL, + G_TYPE_STRING, + 0); g_signal_new ("generic-marshaller-1", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, @@ -1227,6 +1279,76 @@ test_accumulator (void) g_object_unref (test); } +static gboolean +accumulator_concat_string (GSignalInvocationHint *ihint, GValue *return_accu, const GValue *handler_return, gpointer data) +{ + const gchar *acc = g_value_get_string (return_accu); + const gchar *ret = g_value_get_string (handler_return); + + g_assert_nonnull (ret); + + if (acc == NULL) + g_value_set_string (return_accu, ret); + else + g_value_take_string (return_accu, g_strconcat (acc, ret, NULL)); + + return TRUE; +} + +static gchar * +accumulator_class_before_cb (gpointer instance, gpointer data) +{ + return g_strdup ("before"); +} + +static gchar * +accumulator_class_after_cb (gpointer instance, gpointer data) +{ + return g_strdup ("after"); +} + +static gchar * +accumulator_class (Test *test) +{ + return g_strdup ("class"); +} + +static void +test_accumulator_class (void) +{ + const struct { + const gchar *signal_name; + const gchar *return_string; + } tests[] = { + {"accumulator-class-first", "classbeforeafter"}, + {"accumulator-class-last", "beforeclassafter"}, + {"accumulator-class-cleanup", "beforeafterclass"}, + {"accumulator-class-first-last", "classbeforeclassafter"}, + {"accumulator-class-first-last-cleanup", "classbeforeclassafterclass"}, + {"accumulator-class-last-cleanup", "beforeclassafterclass"}, + }; + gsize i; + + for (i = 0; i < G_N_ELEMENTS (tests); i++) + { + GObject *test; + gchar *ret = NULL; + + g_test_message ("Signal: %s", tests[i].signal_name); + + test = g_object_new (test_get_type (), NULL); + + g_signal_connect (test, tests[i].signal_name, G_CALLBACK (accumulator_class_before_cb), NULL); + g_signal_connect_after (test, tests[i].signal_name, G_CALLBACK (accumulator_class_after_cb), NULL); + g_signal_emit_by_name (test, tests[i].signal_name, &ret); + + g_assert_cmpstr (ret, ==, tests[i].return_string); + g_free (ret); + + g_object_unref (test); + } +} + static gboolean in_set (const gchar *s, const gchar *set[]) @@ -1254,6 +1376,12 @@ test_introspection (void) "simple-detailed", "simple-2", "simple-accumulator", + "accumulator-class-first", + "accumulator-class-last", + "accumulator-class-cleanup", + "accumulator-class-first-last", + "accumulator-class-first-last-cleanup", + "accumulator-class-last-cleanup", "generic-marshaller-1", "generic-marshaller-2", "generic-marshaller-enum-return-signed", @@ -1680,6 +1808,7 @@ main (int argc, 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/accumulator-class", test_accumulator_class); 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);