Repository navigation
Fix black tooltips and popups on Wayland - #192910
Merged
auto-submit[bot] merged 3 commits intoSep 17, 2026
Merged
Conversation
A window that is sized to its content, like a tooltip, is created before its size is known, so its Wayland surface starts out a single pixel across and is resized when the first frame arrives. The buffer a frame is drawn into is acquired when the previous frame is swapped, so resizing the surface doesn't reach the buffer the frame that asked for the resize is drawn into. That frame went into the old, single pixel buffer, and as a window sized to its content only produces one frame at each size nothing ever replaced it. The window was left showing a buffer that was never painted, which is what made tooltips appear as black boxes. Swap the stale buffer away unused after a resize so the frame is drawn into a buffer of the size it was rendered at. eglQuerySurface() reports the size of the buffer that was last swapped rather than the one being drawn into, so the sizes are tracked here instead of being asked for. Presenting a buffer as soon as it is resized also means the size given to the surface has to be valid, where before an invalid size was always replaced before any buffer of that size was used. A view that hasn't been allocated yet produces a single pixel frame, which isn't a whole number of logical pixels on a display with a scale of two, and Wayland requires buffer sizes to be an integer multiple of the buffer scale. Round sizes up to a whole logical pixel, and keep writing the frame at the top of the buffer so the rounded up rows fall off the bottom, where Wayland clips.
GTK destroys a window's Wayland surface and makes a new one when the window is hidden and shown again, which it does when a popup is resized. The subsurface Flutter renders into belonged to the old surface, so nothing was shown and moving it was a protocol error that could kill the compositor. Notice when the surface has been replaced, make a new subsurface on it and ask the engine for another frame to fill it.
Contributor
There was a problem hiding this comment.
Code Review
This pull request updates the Linux platform shell to handle Wayland subsurface recreation when GTK replaces the parent surface, and ensures buffer sizes are rounded to integer multiples of the buffer scale. Feedback identifies a potential race condition in fl_view_renderer_subsurface.cc when calling fl_subsurface_egl_resize without holding self->frame_mutex, and a potential division-by-zero vulnerability in round_to_scale if scale is zero or negative.
The sizes tracked in FlSubsurfaceEGL are used by the raster thread when it presents a frame, so the GTK thread has to hold the frame mutex while it changes them.
This was referenced Sep 18, 2026
This was referenced Sep 19, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Tooltips and popups were showing as black boxes, and opening a popup could crash the compositor. Two things were wrong. A tooltip only draws one frame, and that frame went into the buffer left over from before the surface was resized, which nothing had ever painted — so we now swap that stale buffer away unused before drawing. Separately, GTK destroys a window’s surface when the window is hidden and makes a new one when it is shown again, which it does when a popup is resized, leaving the subsurface Flutter draws into attached to a surface that no longer exists — so we now notice when the surface has been replaced, make a new subsurface on it, and ask the engine for another frame to fill it.