Skip to content

Open the window on COSMIC's Wayland with SDL2 - #1839

Merged
hckrman101 merged 2 commits into
NotRexed:mainfrom
italloramon:fix/wayland-libdecor-hang
Nov 10, 2026
Merged

hckrman101 merged 2 commits into
NotRexed:mainfrom
italloramon:fix/wayland-libdecor-hang

Conversation

@italloramon

@italloramon italloramon commented Nov 10, 2026 •

Copy link
Copy Markdown
Contributor

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=1 starts fine. The log stops after CountAddOnContent, with no vk: line, and the main thread waits in poll() on the Wayland socket forever.

  1. SDL2 2.32 asks for the compositor's decorations (xdg-decoration) before the window's first configure, then waits for that configure in Wayland_ShowWindow on shell_surface.xdg.initial_configure_seen.
  2. COSMIC answers CLIENT_SIDE before the configure. SDL's handler (handle_configure_zxdg_decoration) then hides the window, clears shell_surface and shows it again with libdecor, all inside that wait.
  3. The inner show finishes, but shell_surface is a union: the outer loop still reads the xdg member's initial_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_status instead 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_init sets SDL_VIDEO_WAYLAND_PREFER_LIBDECOR=1 before SDL_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), so SDL_VIDEO_WAYLAND_PREFER_LIBDECOR=0 restores the old behaviour.
  • tests/test_wayland_libdecor_hint.py (RUN_ALL_ARGS names the compiler for tests/run_all.py): compiles the actual hos_display_init with SDL stubs and checks that the hint is set before SDL_Init for SDL2, and not for SDL3 or a headless start. It fails on main and 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.

v2.0.13 v2.0.13 + this change
COSMIC, Wayland hangs at start-up (32 log lines, no renderer) title screen, rx: renderer: Vulkan
the same, SDL_VIDEO_WAYLAND_PREFER_LIBDECOR=0 hangs hangs (the variable wins)

On other compositors: I opened a window with the same flags as the game (SHOWN \| RESIZABLE \| ALLOW_HIGHDPI \| VULKAN) through the bundled libSDL2-2.0.so.0, with each compositor nested in COSMIC, and read the decoration handshake with WAYLAND_DEBUG=client.

Compositor Before After Decorations, both before and after
COSMIC hangs opens client (libdecor; COSMIC asks for it)
GNOME Shell 46 opens opens client (no xdg-decoration)
sway 1.9 opens opens server (configure(2), no client frame)
weston 13 opens opens client (no xdg-decoration)
COSMIC / GNOME with libdecor hidden opens, no frame opens, no frame none

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 on main too, because it has no clang++. They do not touch this code.

Screenshot

The title screen on COSMIC's Wayland after the change (before it, the window never drew anything):

after: title screen on COSMIC Wayland

🤖 Generated with Claude Code

italloramon and others added 2 commits November 10, 2026 14:53
…#992)

On COSMIC the game never opened its window: the bundled SDL2 2.32 asks for the
compositor's decorations before the window's first configure, COSMIC answers that
the client draws them, and SDL's switch to libdecor inside that wait leaves it
waiting on a field the switch cleared. SDL2 now takes libdecor from the start
(SDL_VIDEO_WAYLAND_PREFER_LIBDECOR), which still uses the compositor's decorations
where they are offered. SDL3 is left alone, and the variable still wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant