[glib] Add G_SIGNAL_MUST_COLLECT



commit 61b0e1c8d49b6b42d3b6f27f0663ead75967f81a
Author: Christian Persch <chpe gnome org>
Date:   Wed Mar 2 15:48:40 2011 +0100

    Add G_SIGNAL_MUST_COLLECT
    
    In some cases, signal arguments have to be collected, even if there are i
    no signal handlers connected (e.g. for GVariant parameters, where collection
    consumes a floating variant).
    
    Based on a patch by Christian Persch.
    
    Bug #643624.

 gobject/gsignal.c         |   10 +++-
 gobject/gsignal.h         |    7 ++-
 gobject/tests/Makefile.am |    1 +
 gobject/tests/signals.c   |   91 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 104 insertions(+), 5 deletions(-)
---
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index 2e2dd61..c4375b1 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -1340,7 +1340,8 @@ g_signal_new (const gchar	 *signal_name,
 
   /* optimize NOP emissions with NULL class handlers */
   if (signal_id && G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE &&
-      class_offset && class_offset < MAX_TEST_CLASS_OFFSET)
+      class_offset && class_offset < MAX_TEST_CLASS_OFFSET &&
+      ~signal_flags & G_SIGNAL_MUST_COLLECT)
     {
       SignalNode *node;
 
@@ -1632,7 +1633,9 @@ g_signal_newv (const gchar       *signal_name,
   node->emission_hooks = NULL;
   if (class_closure)
     signal_add_class_closure (node, 0, class_closure);
-  else if (G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE)
+  else if (G_TYPE_IS_INSTANTIATABLE (itype) &&
+           return_type == G_TYPE_NONE &&
+           ~signal_flags & G_SIGNAL_MUST_COLLECT)
     {
       /* optimize NOP emissions */
       node->test_class_offset = TEST_CLASS_MAGIC;
@@ -2913,7 +2916,7 @@ g_signal_emit_valist (gpointer instance,
   GValue *param_values;
   SignalNode *node;
   guint i, n_params;
-  
+
   g_return_if_fail (G_TYPE_CHECK_INSTANCE (instance));
   g_return_if_fail (signal_id > 0);
 
@@ -2976,6 +2979,7 @@ g_signal_emit_valist (gpointer instance,
       SIGNAL_LOCK ();
     }
   SIGNAL_UNLOCK ();
+
   instance_and_params->g_type = 0;
   g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (instance));
   g_value_set_instance (instance_and_params, instance);
diff --git a/gobject/gsignal.h b/gobject/gsignal.h
index 3064d1f..24ef842 100644
--- a/gobject/gsignal.h
+++ b/gobject/gsignal.h
@@ -108,6 +108,8 @@ typedef gboolean (*GSignalAccumulator)	(GSignalInvocationHint *ihint,
  *  of as object methods which can be called generically by 
  *  third-party code.
  * @G_SIGNAL_NO_HOOKS: No emissions hooks are supported for this signal.
+ * @G_SIGNAL_MUST_COLLECT: Varargs signal emission will always collect the
+ *   arguments, even if there are no signal handlers connected.  Since 2.30.
  * 
  * The signal flags are used to specify a signal's behaviour, the overall
  * signal description outlines how especially the RUN flags control the
@@ -121,14 +123,15 @@ typedef enum
   G_SIGNAL_NO_RECURSE	= 1 << 3,
   G_SIGNAL_DETAILED	= 1 << 4,
   G_SIGNAL_ACTION	= 1 << 5,
-  G_SIGNAL_NO_HOOKS	= 1 << 6
+  G_SIGNAL_NO_HOOKS	= 1 << 6,
+  G_SIGNAL_MUST_COLLECT = 1 << 7
 } GSignalFlags;
 /**
  * G_SIGNAL_FLAGS_MASK:
  * 
  * A mask for all #GSignalFlags bits.
  */
-#define G_SIGNAL_FLAGS_MASK  0x7f
+#define G_SIGNAL_FLAGS_MASK  0xff
 /**
  * GConnectFlags:
  * @G_CONNECT_AFTER: whether the handler should be called before or after the 
diff --git a/gobject/tests/Makefile.am b/gobject/tests/Makefile.am
index 2ea23e4..010f04b 100644
--- a/gobject/tests/Makefile.am
+++ b/gobject/tests/Makefile.am
@@ -9,6 +9,7 @@ TEST_PROGS += 		\
 	boxed		\
 	enums		\
 	param		\
+	signals		\
 	threadtests	\
 	dynamictests	\
 	binding		\
diff --git a/gobject/tests/signals.c b/gobject/tests/signals.c
new file mode 100644
index 0000000..f4b8240
--- /dev/null
+++ b/gobject/tests/signals.c
@@ -0,0 +1,91 @@
+#include <glib-object.h>
+
+typedef struct _Test Test;
+typedef struct _TestClass TestClass;
+
+struct _Test
+{
+  GObject parent_instance;
+};
+
+struct _TestClass
+{
+  GObjectClass parent_class;
+
+  void (* variant_changed) (Test *, GVariant *);
+};
+
+static GType test_get_type (void);
+G_DEFINE_TYPE (Test, test, G_TYPE_OBJECT)
+
+static void
+test_init (Test *test)
+{
+}
+
+static void
+test_class_init (TestClass *klass)
+{
+  g_signal_new ("variant-changed-no-slot",
+                G_TYPE_FROM_CLASS (klass),
+                G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
+                0,
+                NULL, NULL,
+                g_cclosure_marshal_VOID__VARIANT,
+                G_TYPE_NONE,
+                1,
+                G_TYPE_VARIANT);
+  g_signal_new ("variant-changed",
+                G_TYPE_FROM_CLASS (klass),
+                G_SIGNAL_RUN_LAST | G_SIGNAL_MUST_COLLECT,
+                G_STRUCT_OFFSET (TestClass, variant_changed),
+                NULL, NULL,
+                g_cclosure_marshal_VOID__VARIANT,
+                G_TYPE_NONE,
+                1,
+                G_TYPE_VARIANT);
+}
+
+static void
+test_variant_signal (void)
+{
+  Test *test;
+  GVariant *v;
+
+  /* Tests that the signal emission consumes the variant,
+   * even if there are no handlers connected.
+   */
+
+  test = g_object_new (test_get_type (), NULL);
+
+  v = g_variant_new_boolean (TRUE);
+  g_variant_ref (v);
+  g_assert (g_variant_is_floating (v));
+  g_signal_emit_by_name (test, "variant-changed-no-slot", v);
+  g_assert (!g_variant_is_floating (v));
+  g_variant_unref (v);
+
+  v = g_variant_new_boolean (TRUE);
+  g_variant_ref (v);
+  g_assert (g_variant_is_floating (v));
+  g_signal_emit_by_name (test, "variant-changed", v);
+  g_assert (!g_variant_is_floating (v));
+  g_variant_unref (v);
+
+  g_object_unref (test);
+}
+
+/* --- */
+
+int
+main (int argc,
+     char *argv[])
+{
+  g_type_init ();
+
+  g_test_init (&argc, &argv, NULL);
+
+  g_test_add_func ("/gobject/signals/variant", test_variant_signal);
+
+  return g_test_run ();
+}



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