Blob Blame History Raw
From e10d6a7994dcdd9faa913444857bbe96b32528f5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Marco=20Trevisan=20=28Trevi=C3=B1o=29?= <mail@3v1n0.net>
Date: Tue, 10 Sep 2019 03:34:09 +0200
Subject: [PATCH 2/2] 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
(cherry picked from commit 105a3f757a31299ed4eaafa0615e1fcd0b4ffeec)
---
 clutter/clutter/clutter-actor.c       |  3 +++
 clutter/tests/conform/actor-destroy.c | 13 +++++++++++++
 2 files changed, 16 insertions(+)

diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c
index 0e531eea52..e381352e72 100644
--- a/clutter/clutter/clutter-actor.c
+++ b/clutter/clutter/clutter-actor.c
@@ -5933,6 +5933,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() */
diff --git a/clutter/tests/conform/actor-destroy.c b/clutter/tests/conform/actor-destroy.c
index 14ad1a25c8..0f648cf6c8 100644
--- a/clutter/tests/conform/actor-destroy.c
+++ b/clutter/tests/conform/actor-destroy.c
@@ -174,6 +174,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)
 {
@@ -181,6 +191,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);
 
@@ -194,6 +205,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 ())
@@ -202,6 +214,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);
 }
-- 
2.28.0