mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-13 15:56:23 +01:00
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.
This commit is contained in:
parent
c95ff4de04
commit
61b0e1c8d4
@ -1340,7 +1340,8 @@ g_signal_new (const gchar *signal_name,
|
|||||||
|
|
||||||
/* optimize NOP emissions with NULL class handlers */
|
/* optimize NOP emissions with NULL class handlers */
|
||||||
if (signal_id && G_TYPE_IS_INSTANTIATABLE (itype) && return_type == G_TYPE_NONE &&
|
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;
|
SignalNode *node;
|
||||||
|
|
||||||
@ -1632,7 +1633,9 @@ g_signal_newv (const gchar *signal_name,
|
|||||||
node->emission_hooks = NULL;
|
node->emission_hooks = NULL;
|
||||||
if (class_closure)
|
if (class_closure)
|
||||||
signal_add_class_closure (node, 0, 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 */
|
/* optimize NOP emissions */
|
||||||
node->test_class_offset = TEST_CLASS_MAGIC;
|
node->test_class_offset = TEST_CLASS_MAGIC;
|
||||||
@ -2976,6 +2979,7 @@ g_signal_emit_valist (gpointer instance,
|
|||||||
SIGNAL_LOCK ();
|
SIGNAL_LOCK ();
|
||||||
}
|
}
|
||||||
SIGNAL_UNLOCK ();
|
SIGNAL_UNLOCK ();
|
||||||
|
|
||||||
instance_and_params->g_type = 0;
|
instance_and_params->g_type = 0;
|
||||||
g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (instance));
|
g_value_init (instance_and_params, G_TYPE_FROM_INSTANCE (instance));
|
||||||
g_value_set_instance (instance_and_params, instance);
|
g_value_set_instance (instance_and_params, instance);
|
||||||
|
@ -108,6 +108,8 @@ typedef gboolean (*GSignalAccumulator) (GSignalInvocationHint *ihint,
|
|||||||
* of as object methods which can be called generically by
|
* of as object methods which can be called generically by
|
||||||
* third-party code.
|
* third-party code.
|
||||||
* @G_SIGNAL_NO_HOOKS: No emissions hooks are supported for this signal.
|
* @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
|
* The signal flags are used to specify a signal's behaviour, the overall
|
||||||
* signal description outlines how especially the RUN flags control the
|
* signal description outlines how especially the RUN flags control the
|
||||||
@ -121,14 +123,15 @@ typedef enum
|
|||||||
G_SIGNAL_NO_RECURSE = 1 << 3,
|
G_SIGNAL_NO_RECURSE = 1 << 3,
|
||||||
G_SIGNAL_DETAILED = 1 << 4,
|
G_SIGNAL_DETAILED = 1 << 4,
|
||||||
G_SIGNAL_ACTION = 1 << 5,
|
G_SIGNAL_ACTION = 1 << 5,
|
||||||
G_SIGNAL_NO_HOOKS = 1 << 6
|
G_SIGNAL_NO_HOOKS = 1 << 6,
|
||||||
|
G_SIGNAL_MUST_COLLECT = 1 << 7
|
||||||
} GSignalFlags;
|
} GSignalFlags;
|
||||||
/**
|
/**
|
||||||
* G_SIGNAL_FLAGS_MASK:
|
* G_SIGNAL_FLAGS_MASK:
|
||||||
*
|
*
|
||||||
* A mask for all #GSignalFlags bits.
|
* A mask for all #GSignalFlags bits.
|
||||||
*/
|
*/
|
||||||
#define G_SIGNAL_FLAGS_MASK 0x7f
|
#define G_SIGNAL_FLAGS_MASK 0xff
|
||||||
/**
|
/**
|
||||||
* GConnectFlags:
|
* GConnectFlags:
|
||||||
* @G_CONNECT_AFTER: whether the handler should be called before or after the
|
* @G_CONNECT_AFTER: whether the handler should be called before or after the
|
||||||
|
@ -9,6 +9,7 @@ TEST_PROGS += \
|
|||||||
boxed \
|
boxed \
|
||||||
enums \
|
enums \
|
||||||
param \
|
param \
|
||||||
|
signals \
|
||||||
threadtests \
|
threadtests \
|
||||||
dynamictests \
|
dynamictests \
|
||||||
binding \
|
binding \
|
||||||
|
91
gobject/tests/signals.c
Normal file
91
gobject/tests/signals.c
Normal file
@ -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 ();
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user