Repository navigation
wayland: fixes to frame insets (C2b), each with a suite assertion - #4
Merged
Merged
Conversation
New assertions in the FizzyWayland suite (testautomation_fizzy_wayland.c) for
the fixes to patch 6 ("Wayland: frame insets") that fizzyedit/fizzy#280 step
C2b lists, each read from libwayland's request trace under headless weston:
- every floating check now also asserts an opaque window's opaque region is
the frame, not the shadow round it, and a maximized or fullscreen one's the
whole surface;
- wayland_frameInsetsBeforeShow: a window made hidden publishes its insets
(SDL_PROP_WINDOW_WAYLAND_FRAME_INSET_*_NUMBER) before it is shown;
- wayland_frameInsetsRecreated: after an OpenGL ES renderer makes the shown
window again through SDL_RecreateWindow, the new objects' window geometry,
input region and opaque region are the frame's;
- wayland_frameInsetsShownAgain: hidden and shown again, the new xdg_surface
gets the frame as its window geometry;
- wayland_frameInsetsInputMarginWide and ...None: the input band follows
SDL_PROP_WINDOW_CREATE_WAYLAND_FRAME_INPUT_MARGIN_NUMBER (12, and 0).
The trace is now read between two marks where a window's objects are made
again, as libwayland reuses the ids of destroyed objects. Test files only.
On fizzy-3.4 (fizzy-3.4.16-8) every new assertion fails; the fixes follow as
their own changes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SDL_RecreateWindow destroys the native window and makes it again with CreateSDLWindow(_this, window, 0): no creation properties. It does so when an OpenGL renderer is made for a shown window created without SDL_WINDOW_OPENGL, and when the Wayland driver reconnects to the compositor. The frame insets were read only from the creation properties, so after that the window had none: its whole surface, shadow included, was the window to the compositor and took input. The insets asked for at creation are now also kept in the window's own properties, under internal names (SDL.internal.wayland.frame_inset.*, as the GPU drivers and the renderer keep their per-window data), which outlive the window data. A window made with no creation properties takes them from there. No public API: upstream main has since added a settable form of the same idea (SDL_PROP_WINDOW_WAYLAND_BORDER_INSET_*_NUMBER, libsdl-org/SDL 5d7167c), so a setter here would be a third shape to reconcile at the next rebase. Tested by FizzyWayland's wayland_frameInsetsRecreated (fizzyedit/fizzy#280, C2b). Squash into 6 ("Wayland: frame insets") at the next rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SetSurfaceOpaqueRegion gave the compositor the whole surface as opaque, so for a window with frame insets that isn't SDL_WINDOW_TRANSPARENT it said the shadow round the frame was opaque too. The compositor may skip drawing what lies under an opaque region, which is wrong under a shadow wherever its buffer carries alpha. The opaque region is now the frame: the surface less the insets in effect, so the whole surface while they are zero (maximized, tiled, fullscreen, or no insets), as before. Fizzy's window is transparent, so fizzy never hit this. Tested by every FizzyWayland check of a floating, maximized or fullscreen window (fizzyedit/fizzy#280, C2b). Squash into 6 ("Wayland: frame insets") at the next rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
When a compositor leaves a new floating toplevel's size to the client (a 0x0 configure), SDL clamps the window's own size to the bounds the compositor sent with xdg_toplevel.configure_bounds. Those bound the window geometry, which with frame insets is the frame, but were compared with the whole surface, so a framed window that would just fit was made smaller by its insets. The bounds are now widened by the insets in effect before the clamp. The libdecor path is unchanged, as insets never apply there. Not covered by a test: weston 14 advertises xdg_wm_base version 5 but never sends configure_bounds (libweston/desktop/xdg-shell.c), so under headless weston the clamp never runs. Checked by reading. In scale_to_display mode the clamp compares bounds in points with a size in pixels; that predates the insets and is left as is. Part of fizzyedit/fizzy#280, C2b. Squash into 6 ("Wayland: frame insets") at the next rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
While a window has frame insets only the frame and a band round it take input, so the rest of the shadow passes clicks through; the band is where the application's hit test answers the edges it resizes from. It was a fixed 8 units. SDL_PROP_WINDOW_CREATE_WAYLAND_FRAME_INPUT_MARGIN_NUMBER now sets it, 8 by default, 0 for the frame alone; each side's band is still at most that side's inset. An application whose resize edge is wider than 8, or that wants no band, can say so. The value is kept for a window SDL makes again, as the insets are. Public API, one creation property beside the frame insets, documented with them. Fizzy keeps the default: its resize edge is 6 points. Tested by FizzyWayland's wayland_frameInsetsInputMarginWide (12) and wayland_frameInsetsInputMarginNone (0) (fizzyedit/fizzy#280, C2b). Squash into 6 ("Wayland: frame insets") at the next rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SDL_PROP_WINDOW_WAYLAND_FRAME_INSET_*_NUMBER were first set by ApplyFrameInsets, at the compositor's first configure, so before a window was shown they were missing and an application could not lay itself out (where its frame and title bar go) before showing it. Wayland_CreateWindow now publishes the insets the window will float with, those asked for (zero for a libdecor window), and the first configure corrects them if the window comes up maximized, tiled or fullscreen. Publishing is split out of ApplyFrameInsets as PublishFrameInsets for that. Tested by FizzyWayland's wayland_frameInsetsBeforeShow (fizzyedit/fizzy#280, C2b). Squash into 6 ("Wayland: frame insets") at the next rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hiding a window destroys its xdg_surface, and with it the window geometry. Shown again at the same size, with the same insets, ConfigureWindowGeometry saw nothing change and never sent set_window_geometry to the new xdg_surface, so the compositor took the whole surface, shadow included, as the window. Hiding now forgets the insets applied, so the configure that shows the window applies them again; and ApplyFrameInsets does nothing for a window without an xdg_surface, so a resize while hidden can't mark them applied before there is a surface to frame. Found by reading while fixing the rest of fizzyedit/fizzy#280's C2b; not in its list. Tested by FizzyWayland's wayland_frameInsetsShownAgain. Squash into 6 ("Wayland: frame insets") at the next rebase. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
foxnne
marked this pull request as ready for review
October 9, 2026 23:09
foxnne
added a commit
to fizzyedit/fizzy
that referenced
this pull request
Oct 10, 2026
…#314) Part of #280 (step C2b landed on the forks). Moves fizzy's `.sdl` pin to sdl_zig `fizzy-1.0.3+3.4.16-9` (SDL `fizzy-3.4.16-9`), which fixes six problems in SDL patch 6 (Wayland frame insets, the margins fizzy draws its Linux window shadow in): | Fix | SDL commit | Shown by the suite | |---|---|---| | A window SDL makes again (e.g. for an OpenGL renderer) keeps its insets | `9258288` | yes | | An opaque window's opaque region is its frame, not its shadow | `0ca75f2` | yes | | The compositor's toplevel bounds are widened by the insets before the clamp | `0426af9` | no: weston never sends bounds | | The input band is a creation property, `SDL_PROP_WINDOW_CREATE_WAYLAND_FRAME_INPUT_MARGIN_NUMBER` (default 8) | `91b7a29` | yes | | The insets are published from creation, not only after show | `883f5c8` | yes | | A window hidden and shown again is framed again | `011a2dc` | yes (new bug, found while testing) | Fork PRs: fizzyedit/SDL#4 → `fizzy-3.4.16-9`, fizzyedit/sdl_zig#4 → `fizzy-1.0.3+3.4.16-9`. - [Red](https://github.com/fizzyedit/sdl_zig/actions/runs/38000927122): with only the test commit, every new assertion fails at scale 1 and 2. - [Green](https://github.com/fizzyedit/sdl_zig/actions/runs/38001031572): with the fixes, all 9 Wayland tests pass at both scales. Fizzy's own use (`linux_titlebar.zig`) is unchanged: it keeps the default band, and its insets now also survive a recreate. **For later:** upstream SDL `main` gained its own version of frame insets on 2026-09-24. It isn't in `release-3.4.x`, and it has none of these fixes. `docs/DEPENDENCIES.md` now says to move fizzy to upstream's API at the rebase onto a release that has it, keeping only what upstream lacks as patches. **#312 overlaps:** it moves this pin from the root `build.zig.zon` into `backend/build.zig.zon`. Whichever PR lands second carries the `-9` pin into the other's location. ## Verified On macOS (arm64), in a fresh workspace on `main`: | Gate | Result | |---|---| | `zig build` | 43/43 steps | | `zig build test` | 75/75 steps | | `zig build test-integration` | 35/35 steps, 354/354 tests | | `zig build check-web` | 16/16 steps | | `zig build test-sdk-version` | 12/12 steps | | `zig build -Dtarget=x86_64-linux-gnu` | 54/54 steps (builds the changed Wayland code) | Not verified: the fixes on a real GNOME desktop with fizzy itself. The evidence is the fork's suite under headless weston. The SDK fingerprint doesn't move, since plugins never link SDL. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
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.
Part of fizzyedit/fizzy#280 (step C2b). Run by fizzyedit/sdl_zig#4.
Patch 6 ("Wayland: frame insets",
2d6efde) before it is proposed upstream. A test commit first, so CI can show it failing onfizzy-3.4, then one fix per problem, each described "squash into 6 at the next rebase".Commits
WAYLAND_DEBUGtrace under headless weston (details below). Test files only.SDL_RecreateWindowcallsCreateSDLWindow(_this, window, 0), so the insets were gone after an OpenGL renderer was attached to a shown window, or after a compositor reconnect. The insets asked for are now also kept in the window's own properties under internal names (SDL.internal.wayland.frame_inset.*, as the GPU drivers and renderer keep per-window data), which outlive the window data. No public setter: see "Upstream" below.(0, 0, w, h).configure_boundsbound the window geometry (the frame), but were compared with the surface. Untested: weston 14 advertisesxdg_wm_basev5 but never sendsconfigure_bounds(nothing inlibweston/desktop/xdg-shell.cdoes), so under headless weston the clamp never runs. The floating0x0configure that reaches it does happen. Checked by reading.SDL_PROP_WINDOW_CREATE_WAYLAND_FRAME_INPUT_MARGIN_NUMBER("SDL.window.create.wayland.frame_input_margin"), default 8, 0 for the frame alone, each side still at most its inset. It is kept on recreate as the insets are. Documented beside the insets inSDL_video.h. Fizzy keeps the default.Wayland_CreateWindowpublishes the insets the window will float with (zero for libdecor). The first configure corrects them if the window comes up maximized, tiled or fullscreen.set_window_geometrywas never sent to the new xdg_surface. Hiding now forgets the applied insets, andApplyFrameInsetsskips a window with no xdg_surface.What the new assertions check
Floating,Maximized/Fullscreenbefore and after,Recreated,ShownAgain, input-margin tests): the opaque region is the frame,(24, 6, 346, 254)for 400x300. Maximized or fullscreen: the whole surface.wayland_frameInsetsBeforeShow: a window made hidden publishes24/6/30/40.wayland_frameInsetsRecreated: afterSDL_CreateRenderer(window, "opengles2")makes the shown window again (flags go from VULKAN to OPENGL), the new objects' geometry, input region and opaque region are the frame's. The trace is read from a mark set before the recreate, because libwayland reuses the ids of destroyed objects.wayland_frameInsetsShownAgain: hide, show; the new xdg_surface's geometry is the frame. The window is released from the GPU device while hidden and claimed again after showing. A first version kept it claimed, and the run hung with nothing printed.wayland_frameInsetsInputMarginWide(12) and...None(0): the input region follows the property.Trace marks now also go to the real stderr, so a test that hangs while tracing shows how far it got.
Verified
011a2dc5) via sdl_zig#4's pin: https://github.com/fizzyedit/sdl_zig/actions/runs/38001031572. Intest-fizzy-wayland-insetsat scale 1 and 2, and intest-fizzy-linux (wayland)(where libdecor is installed), all 9 FizzyWayland tests pass, 0 asserts fail. The run concludes success. Thebuild (master, …)jobs fail as they do onfizzyitself: Zig master,continue-on-error.1eb90b75,fizzy-3.4+ suite) on a throwaway sdl_zig branch, since deleted: https://github.com/fizzyedit/sdl_zig/actions/runs/38000927122. At both scales every new assertion fails, and Popup alone passes:(0, 0, 400, 300)instead of(24, 6, 346, 254)in every floating check (2);created hidden: all four insets-1 (not published)(5);recreated: noset_window_geometry, input region never set, opaque region the whole surface (1);shown again: noset_window_geometry, input and opaque region never set (the hide/show fix);(16, 0, 362, 268)instead of(12, 0, 370, 272); margin 0:(16, 0, 362, 268)instead of(24, 6, 346, 254)(4).wayland_frameInsetsShownAgainwith the window still claimed by the GPU device. That is why the test now releases and reclaims the window, and why the jobs have a timeout.-Wall -Wextra -Wmissing-prototypes -Wmissing-variable-declarations -Wshadowfor x86_64-linux and aarch64-macos (suite), and for Linux through sdl_zig (zig build test-fizzy -Dtarget=x86_64-linux-gnu). The macOS runners skip the suite (Wayland only) and pass.Upstream
Upstream
mainnow has its own version of this feature: libsdl-org/SDL5d7167cb"wayland: Add opt-in border inset window properties" (2026-09-24), with cleanups in86b89cffanddff05080. It isn't inrelease-3.4.x. There an application opts in withSDL_PROP_WINDOW_CREATE_WAYLAND_ENABLE_INSETS_BOOLEANand then setsSDL_PROP_WINDOW_WAYLAND_BORDER_INSET_{LEFT,TOP,RIGHT,BOTTOM}_NUMBERon the window. SDL reads them each time it configures, so they are their own setter. Upstream does the window geometry, configure sizes, min/max and popup anchoring, as patch 6 does. Where they differ:enable_insetscomes from the creation properties, so upstream loses it onSDL_RecreateWindowthe same way (C2b 1). The inset values themselves survive, since window properties outlive the window data.So this PR adds no setter. Upstream already has the setter shape, settable window properties, and a fork-only one would be a third API to reconcile at the next rebase. The upstream path for patch 6 is to adopt upstream's API when fizzy rebases onto an SDL release that has it, and to propose what it lacks as fixes to upstream's feature: input region plus band (with this margin property), opaque region, bounds clamp, re-framing after hide/show, and keeping
enable_insetsacross a recreate.The SDL commit needs a permanent tag before sdl_zig's pin on it merges.
🤖 Generated with Claude Code