clutter/actor: Don't emit property changes after ::destroy

Clutter actors might emit property changes in dispose, while unparenting.
However we assume that the ::destroy signal is the last one we emit for an
actor, and that starting from this moment the object is not valid anymore,
and so we don't expect any signal emission from it.

To avoid this, freeze the object notifications on an actor during its
disposition, just before the ::destroy signal emission.

Update the actor-destroy test to verify this behavior.

https://gitlab.gnome.org/GNOME/mutter/merge_requests/769
This commit is contained in:
Marco Trevisan (Treviño) 2019-09-10 03:34:09 +02:00 committed by Marco Trevisan
parent f376a318ba
commit 105a3f757a
2 changed files with 16 additions and 0 deletions

View File

@ -6069,6 +6069,9 @@ clutter_actor_dispose (GObject *object)
object->ref_count,
g_type_name (G_OBJECT_TYPE (self)));
/* Stop the emission of any property change */
g_object_freeze_notify (object);
g_signal_emit (self, actor_signals[DESTROY], 0);
/* avoid recursing when called from clutter_actor_destroy() */

View File

@ -176,6 +176,16 @@ on_parent_set (ClutterActor *actor,
*parent_set_called = TRUE;
}
static void
on_notify (ClutterActor *actor,
ClutterActor *old_parent,
gpointer data)
{
gboolean *property_changed = data;
*property_changed = TRUE;
}
static void
actor_destruction (void)
{
@ -183,6 +193,7 @@ actor_destruction (void)
ClutterActor *child = clutter_rectangle_new ();
gboolean destroy_called = FALSE;
gboolean parent_set_called = FALSE;
gboolean property_changed = FALSE;
g_object_ref_sink (test);
@ -196,6 +207,7 @@ actor_destruction (void)
clutter_container_add_actor (CLUTTER_CONTAINER (test), child);
g_signal_connect (child, "parent-set", G_CALLBACK (on_parent_set),
&parent_set_called);
g_signal_connect (child, "notify", G_CALLBACK (on_notify), &property_changed);
g_signal_connect (child, "destroy", G_CALLBACK (on_destroy), &destroy_called);
if (g_test_verbose ())
@ -204,6 +216,7 @@ actor_destruction (void)
clutter_actor_destroy (test);
g_assert (destroy_called);
g_assert_false (parent_set_called);
g_assert_false (property_changed);
g_assert_null (child);
g_assert_null (test);
}