/* 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;
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;
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);
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);
* 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
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
--- /dev/null
+#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 ();
+}