From f820bb35067f1e6b54d56f7652ee333ac8c8c35b Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 30 Mar 2022 21:02:18 +0200 Subject: [PATCH] clutter: Keep actors dirty if a redraw was queued up during paint() In the right combination of circumstances, and given 2 actors (parent actor P with an offscreen effect and child actor C), we may have the following situation happening: - A redraw is queued on the actor C, actors C and P are marked as priv->is_dirty and priv->propagated_one_redraw. - During paint() handling we paint actor P, priv->propagated_one_redraw is turned off. - We recurse into child actor C, priv->propagated_one_redraw is turned off. - A new redraw is queued on actor C, actors C and P are marked as priv->is_dirty and priv->propagated_one_redraw. - The paint() method recurses back, actors C and P get priv->is_dirty disabled, priv->propagated_one_redraw remains set. - At this point queueing up more redraws on actor C will not propagate up, because actor C has priv->propagated_one_redraw set, but the parent actor P has priv->is_dirty unset, so the offscreen effect will not get CLUTTER_EFFECT_PAINT_ACTOR_DIRTY and will avoid repainting actor C. The end result is that actor C does not redraw again, despite requesting redraws. This situation eventually resolves itself through e.g. relayouts on actor P, but may take some time to happen. In order to fix this, consider actors that did get a further redraw request still dirty after paint(). Fixes: https://gitlab.gnome.org/GNOME/mutter/-/issues/2188 Part-of: --- clutter/clutter/clutter-actor.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/clutter/clutter/clutter-actor.c b/clutter/clutter/clutter-actor.c index 2e4b30eff..23ef03dc1 100644 --- a/clutter/clutter/clutter-actor.c +++ b/clutter/clutter/clutter-actor.c @@ -3840,8 +3840,10 @@ clutter_actor_paint (ClutterActor *self, clutter_paint_node_paint (root_node, paint_context); /* If we make it here then the actor has run through a complete - paint run including all the effects so it's no longer dirty */ - priv->is_dirty = FALSE; + * paint run including all the effects so it's no longer dirty, + * unless a new redraw was queued up. + */ + priv->is_dirty = priv->propagated_one_redraw; } /**