Open the window on COSMIC's Wayland with SDL2 #1839
No reviewers
Labels
No labels
accessibility
autorelease: pending
autorelease: tagged
bug
dependencies
documentation
duplicate
enhancement
github_actions
good first issue
help wanted
invalid
question
testing wanted
wontfix
No milestone
No assignees
1 participant
Due date
No due date set.
Dependencies
No dependencies set
Reference
MagicBeanDev/Hookshot!1839
Loading…
Reference in a new issue
No description provided.
Delete branch "fix/wayland-libdecor-hang"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
On a COSMIC desktop (Pop!_OS) the game never opens its window on Wayland: it hangs at start-up with nothing drawn, and the only way in today is
SDL_VIDEODRIVER=x11, which gives up the Wayland mailbox present that the game prefers. This makes it start on Wayland with no setting.Reported in #992 and listed under Wayland in #1000.
Why it hangs
The hang is in the bundled SDL2 (2.32.10), before Hookshot touches the GPU: a small program that only opens an SDL2 window with these libraries hangs the same way, and
HOS_HEADLESS=1starts fine. The log stops afterCountAddOnContent, with novk:line, and the main thread waits inpoll()on the Wayland socket forever.xdg-decoration) before the window's firstconfigure, then waits for that configure inWayland_ShowWindowonshell_surface.xdg.initial_configure_seen.CLIENT_SIDEbefore the configure. SDL's handler (handle_configure_zxdg_decoration) then hides the window, clearsshell_surfaceand shows it again with libdecor, all inside that wait.shell_surfaceis a union: the outer loop still reads thexdgmember'sinitial_configure_seen, which the switch cleared and which libdecor never sets. The outer loop dispatches forever.SDL2 2.30 asked for decorations only after that wait, so the same switch did not hang. The SDL2 branch still has this code. SDL3 waits on one
shell_surface_statusinstead and is not affected.GNOME and weston do not offer
xdg-decoration, and sway, KDE and Hyprland answer server-side, so none of them reaches the switch. That is why the reports so far are COSMIC only: a GNOME + NVIDIA laptop in #1000 opens directly. Hybrid GPUs are not the cause.What changed
host/posix/display_sdl.c: with SDL2,hos_display_initsetsSDL_VIDEO_WAYLAND_PREFER_LIBDECOR=1beforeSDL_Init, so SDL uses libdecor from the start and never makes the switch. libdecor still takes the compositor's decorations where they are offered. Without libdecor, SDL keeps its own path. SDL3 is left alone, and the environment variable still wins (SDL2 does not let a hint at normal priority override it), soSDL_VIDEO_WAYLAND_PREFER_LIBDECOR=0restores the old behaviour.tests/test_wayland_libdecor_hint.py(RUN_ALL_ARGSnames the compiler fortests/run_all.py): compiles the actualhos_display_initwith SDL stubs and checks that the hint is set beforeSDL_Initfor SDL2, and not for SDL3 or a headless start. It fails onmainand passes here.How it was tested
Pop!_OS 24.04, COSMIC (cosmic-comp 0.1, Wayland), Intel Raptor Lake iGPU + RTX 3050 6 GB Laptop, NVIDIA 595.104.02, libdecor 0.2.2 with its GTK plugin.
In the game: I rebuilt v2.0.13 with only this change (the v2.0.13 AppImage's tools plus this patch,
--update), with no variables set.rx: renderer: VulkanSDL_VIDEO_WAYLAND_PREFER_LIBDECOR=0On other compositors: I opened a window with the same flags as the game (
SHOWN \| RESIZABLE \| ALLOW_HIGHDPI \| VULKAN) through the bundledlibSDL2-2.0.so.0, with each compositor nested in COSMIC, and read the decoration handshake withWAYLAND_DEBUG=client.xdg-decoration)configure(2), no client frame)xdg-decoration)Only COSMIC changes. On the others the window and who draws its frame are the same before and after.
python -I -B tests/run_all.py: the window checks pass (test_wayland_libdecor_hint,test_display_startup_failure,test_windows_display_startup). Ten checks fail on this machine onmaintoo, because it has noclang++. They do not touch this code.Screenshot
The title screen on COSMIC's Wayland after the change (before it, the window never drew anything):
🤖 Generated with Claude Code
Looks good. Setting SDL_VIDEO_WAYLAND_PREFER_LIBDECOR=1 only for SDL2, before SDL_Init, is a small and well-scoped way around the 2.32 xdg-decoration/initial_configure hang.
Other platforms: the hint is only read by SDL2's Wayland backend, so X11 and Windows are unaffected. Sway, KDE and Hyprland answer server-side, and GNOME and weston don't offer xdg-decoration, so none of them reaches the switch. It's set via hos_sdl_hint (normal priority), so an env value of SDL_VIDEO_WAYLAND_PREFER_LIBDECOR=0 still wins, and without libdecor SDL keeps its own path. SDL3 is left alone. There's no COSMIC detection to get wrong, which I like. The nested-compositor table in the description covers the other cases well.
The test compiles the real hos_display_init with stubs and checks the hint is set early for SDL2 and not for SDL3 or headless. It declares RUN_ALL_ARGS, so it plugs into the new run_all layout. I didn't build or run it.
The fork branch has no CI runs, so a merge of main (or a push) would give CI a chance to run before this goes in, but nothing here conflicts.