From 07167fdf2223172cae57b5cf10eba9d29869af3b Mon Sep 17 00:00:00 2001 From: Carlos Garnacho Date: Wed, 7 Apr 2021 21:04:28 +0200 Subject: surface: Always set PHASE_PAINT as pending when updates are scheduled At times (most often when closing subsurfaces that are scheduling relayouts) the PHASE_PAINT handling gets broken with the following sequence: 1. Surface receives wl_callback.done for the previous frame. Surface is thawed. 2. A new update on the surface is scheduled. PHASE_PAINT is requested directly on the frame clock. priv->pending_phase is left unset in the surface. 3. Surface gets frozen 4. Frame clock processes the update scheduled at 2. The surface is frozen, so paint is prevented. PHASE_PAINT is considered handled. 5. Compositor emits wl_callback.done again. Surface is thawed. 6. At this point the machinery is off - The surface didn't paint but has pending update regions - priv->draw_needed is set in the toplevel and other portions of the widget tree - So queueing redraws is ineffective at eventually calling gdk_surface_schedule_update() again on the toplevel surface. - We don't paint anymore, so this broken state is not flushed until other subsurface changes manage to schedule the missing update. To fix this, always set PHASE_PAINT in priv->pending_phase when doing gdk_surface_schedule_update(). If the frame clock turns around before the surface is thawed, it will still be waiting to be processed the next iteration. Fixes: https://gitlab.gnome.org/GNOME/gtk/-/issues/3750 --- gdk/gdksurface.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gdk/gdksurface.c b/gdk/gdksurface.c index c55a9a8042..ef6464c43a 100644 --- a/gdk/gdksurface.c +++ b/gdk/gdksurface.c @@ -1299,12 +1299,11 @@ gdk_surface_schedule_update (GdkSurface *surface) g_return_if_fail (surface); + surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_PAINT; + if (surface->update_freeze_count || gdk_surface_is_toplevel_frozen (surface)) - { - surface->pending_phases |= GDK_FRAME_CLOCK_PHASE_PAINT; - return; - } + return; /* If there's no frame clock (a foreign surface), then the invalid * region will just stick around unless gdk_surface_process_updates() -- cgit v1.2.1