summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-06-29 16:05:52 +0900
committerAdam Malczewski <[email protected]>2026-06-29 16:05:52 +0900
commitc1c7bf0954eb7c0f9d9aff70737e84930630021e (patch)
tree0b708833ddccddd443f33bf1823910b776abc00a
parent4b03f5b5ad8f0b81deafbe85e953cde1a98c3a75 (diff)
downloadstudy-player-c1c7bf0954eb7c0f9d9aff70737e84930630021e.tar.gz
study-player-c1c7bf0954eb7c0f9d9aff70737e84930630021e.zip
fix: switch desktop window backend GLFW -> SDL2 (reliable drag-and-drop)
The GLFW Wayland drag-and-drop crash fix (previous commit) did NOT resolve drag-and-drop on the real target (labwc), so abandon the GLFW path entirely instead of patching it further. Why SDL: raylib ships a first-class SDL backend (PLATFORM_DESKTOP_SDL) that implements file drop via SDL_DROPFILE. GLFW 3.4 (vendored in raylib 6.0) has broken Wayland drag-and-drop (wl_data_offer NULL source_actions/action listeners -> libwayland wl_abort on drag, glfw/glfw#2835) AND its X11 backend segfaults on WSLg (Mesa GLX). SDL's window/EGL/drag-drop is mature on BOTH real Wayland (labwc) and WSLg, so one backend covers both targets with no vendor patches and no X11/Wayland special-casing. Changes (desktop only; web build stays Emscripten+GLFW, untouched): - build.zig: build raylib PLATFORM=PLATFORM_DESKTOP_SDL (SDL_INCLUDE_PATH/ LIBRARY_PATH = system SDL2); link SDL2 instead of wayland-*/xkbcommon/EGL. - Revert the GLFW patch (patches/glfw-wayland-dnd-crash.patch removed; the build.zig patch-application step removed). - Docs: environment.md / study-player.md / BUILDING.md / SCREENSHOT.md updated to reflect the SDL backend + the SDL2 system dependency. The RmlUi binding is backend-agnostic (rlgl render + raylib IsKeyDown input, zero glfw* calls), so the swap is transparent to it. Prerequisite on the cyberdeck: install SDL2 dev (sudo pacman -S sdl2 or sdl2-compat) before building. Verified on the laptop (WSLg): build green; binary runs under SDL (Platform backend: DESKTOP (SDL)), window opens, no GLX segfault, RmlUi fonts load, mp3 loads from argv (132300 frames), no crash. Interactive drag-drop itself still needs user testing on the cyberdeck (SDL_DROPFILE path).
-rw-r--r--.agents/knowledge/environment.md60
-rw-r--r--.agents/knowledge/study-player.md9
-rw-r--r--BUILDING.md14
-rw-r--r--build.zig40
-rw-r--r--patches/glfw-wayland-dnd-crash.patch80
-rw-r--r--tools/SCREENSHOT.md17
6 files changed, 61 insertions, 159 deletions
diff --git a/.agents/knowledge/environment.md b/.agents/knowledge/environment.md
index 38ae92d..a54ddca 100644
--- a/.agents/knowledge/environment.md
+++ b/.agents/knowledge/environment.md
@@ -9,42 +9,30 @@ rake / generator invocation (see rules/wsl-toolchain.md). The build scripts
(`rebuild.sh`, `build_web.sh`) already do this and also prepend the user gem bin
(`$(ruby -e 'puts Gem.user_dir')/bin`) so the Linux `rake` gem resolves.
-## Graphics: use Wayland, not X11 (WSLg)
-WSLg's X11/GLX path **segfaults inside Mesa** (`dri2GalliumConfigQueryb`). raylib
-is therefore built with the **Wayland** GLFW backend:
-`make ... GLFW_LINUX_ENABLE_WAYLAND=TRUE GLFW_LINUX_ENABLE_X11=FALSE`, and
-`build.zig` links the wayland-* libs (`wayland-client/cursor/egl`, `xkbcommon`)
-plus `EGL`. For a normal X11 desktop, swap those back to `X11` in both places.
-
-Expect harmless Mesa/EGL/zink warnings on stderr in this environment
-(`libEGL warning: ... zink ...`, `Wayland: The platform does not provide the
-window position`); they are not errors.
-
-## Wayland drag-and-drop crashes on GLFW 3.4 (patched)
-raylib 6.0 vendors **GLFW 3.4** (release). Its Wayland `wl_data_offer_listener`
-(`vendor/raylib/src/external/glfw/src/wl_window.c`) only sets the `offer`
-(opcode 0) handler; `source_actions` (opcode 1) and `action` (opcode 2) are
-NULL (`wl_data_offer` is v3; those events were added in v3). Modern compositors
-(labwc, GNOME, KDE) emit source_actions/action *during a drag*, and
-libwayland-client then `wl_abort("listener function for opcode N of
-wl_data_offer is NULL")` — **the app crashes the moment a file is dragged over
-the window**, before any drop registers (glfw/glfw#2835, #2562). This is why
-drag-and-drop was "unreliable" in the rewrite but reliable in the original
-`../source` app, which uses the X11/Xdnd backend (`-D_GLFW_X11`) — a separate
-code path with none of these bugs.
-
-Fix: `patches/glfw-wayland-dnd-crash.patch` backports the upstream GLFW-master
-fix (no-op source_actions/action handlers + two NULL-deref guards in the
-data-device path). `build.zig` applies it **idempotently** before `make`
-(marker = `dataOfferHandleAction` in the file; when newly applied it deletes the
-stale `libraylib.a` so `make` actually rebuilds). The vendored file is
-gitignored, so the patch file + the build.zig step ARE the committed fix — a
-fresh checkout reproduces it. **Drop the patch once raylib vendors a GLFW
-release containing the upstream fix.**
-
-Do NOT "fix" this by re-enabling X11 (`GLFW_LINUX_ENABLE_X11=TRUE`): on a real
-Wayland session GLFW 3.4 still picks Wayland (so it wouldn't help), and forcing
-X11 reintroduces the WSLg GLX segfault above.
+## Graphics backend: raylib's SDL2 backend (not GLFW)
+The desktop build uses raylib's **SDL2** backend (`build.zig` builds raylib with
+`PLATFORM=PLATFORM_DESKTOP_SDL`; the binary links `SDL2`). This replaces the
+earlier GLFW backend for two reasons, both WSLg/Wayland-related:
+
+- WSLg's **X11/GLX** path segfaults inside Mesa (`dri2GalliumConfigQueryb`). GLFW
+ was therefore forced to its **Wayland** backend (`GLFW_LINUX_ENABLE_WAYLAND=TRUE
+ GLFW_LINUX_ENABLE_X11=FALSE`), which links the wayland-* libs.
+- GLFW 3.4 (vendored in raylib 6.0) has **broken drag-and-drop on Wayland**: its
+ `wl_data_offer_listener` leaves the `source_actions`/`action` handlers NULL, so
+ libwayland `wl_abort()`s when a compositor sends them during a drag → the app
+ crashes the moment a file is dragged over the window (glfw/glfw#2835). A
+ backport patch was tried and **did not** fix it on the real target (labwc), so
+ the whole GLFW path was abandoned.
+
+SDL's own window/EGL/drag-drop code is mature on **both** real Wayland (labwc)
+and WSLg — one backend covers both targets, no vendor patches, no X11/Wayland
+special-casing. It requires **SDL2 dev installed system-wide** (`pacman -S sdl2`
+or `sdl2-compat`); the binary won't link otherwise. The web build is unaffected
+(still Emscripten + GLFW; `build_web.sh` unchanged). The RmlUi binding is
+backend-agnostic (renders via `rlgl`, reads input via raylib's `IsKeyDown` — no
+`glfw*` calls), so the swap is transparent to it.
+
+Expect harmless Mesa/llvmpipe messages on stderr in WSLg (software GL); not errors.
## Toolchain versions (pinned)
raylib 5.5, mruby 3.3.0, RmlUi 6.1, flecs v4.1.1, Zig 0.16.0, emcc 6.0.0 (emsdk).
diff --git a/.agents/knowledge/study-player.md b/.agents/knowledge/study-player.md
index e0d1831..f0da870 100644
--- a/.agents/knowledge/study-player.md
+++ b/.agents/knowledge/study-player.md
@@ -96,10 +96,11 @@ generated registrar runs.
The Ruby `CheckFileDrop` system (`game/study_player/study_player.rb`) is correct
and identical in pattern to the original C app. If drag-and-drop is unreliable,
-the cause is NOT the Ruby — it is the GLFW/Wayland backend: see
-`.agents/knowledge/environment.md` § "Wayland drag-and-drop crashes on GLFW 3.4"
-(the `wl_data_offer` NULL-listener crash + the `patches/glfw-wayland-dnd-crash.patch`
-fix). The X11 `../source` app never hits it.
+the cause is NOT the Ruby — it is the window backend: see
+`.agents/knowledge/environment.md` § "Graphics backend: raylib's SDL2 backend".
+The rewrite switched from GLFW (whose Wayland drag-drop crashes — glfw/glfw#2835)
+to raylib's SDL backend, which implements drop via `SDL_DROPFILE`. The original
+`../source` app uses X11/Xdnd and never hit it.
## Non-blocking seek (skip_auto_update)
After `Rl.seek_music_stream`, raylib's miniaudio stream may briefly report the
diff --git a/BUILDING.md b/BUILDING.md
index b6daebb..c0ece45 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -52,14 +52,16 @@ after applying — `make -C vendor/raylib/src clean`.)
make -C vendor/raylib/src PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC -j4
```
-> **WSL / WSLg note:** the default X11 backend segfaults inside Mesa's GLX driver
-> (`dri2GalliumConfigQueryb`) on WSLg. Build the **Wayland** backend instead:
+> **WSL / WSLg note:** the desktop build uses raylib's **SDL2** backend
+> (`PLATFORM=PLATFORM_DESKTOP_SDL`), not GLFW. WSLg's X11/GLX path segfaults
+> inside Mesa (`dri2GalliumConfigQueryb`), and GLFW 3.4's Wayland drag-and-drop
+> crashes (glfw/glfw#2835). SDL is robust on both WSLg and real Wayland (labwc),
+> so one backend covers both. It requires SDL2 dev installed system-wide:
> ```sh
-> make -C vendor/raylib/src PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC \
-> GLFW_LINUX_ENABLE_WAYLAND=TRUE GLFW_LINUX_ENABLE_X11=FALSE -j4
+> sudo pacman -S sdl2 # Arch (or sdl2-compat)
+> # then just: zig build # build.zig handles PLATFORM=PLATFORM_DESKTOP_SDL + linking SDL2
> ```
-> `build.zig` currently links the Wayland libs to match. For a normal X11 desktop,
-> swap the Wayland `linkSystemLibrary` calls in `build.zig` back to `X11`.
+> The web build is separate and still uses Emscripten + GLFW (`build_web.sh`).
### 1b. Build RmlUi (static lib)
diff --git a/build.zig b/build.zig
index 333362a..1c3e584 100644
--- a/build.zig
+++ b/build.zig
@@ -10,9 +10,10 @@ const std = @import("std");
// The vendored libs (1,2) are guarded so they only build when missing; mruby (3)
// runs every time (rake is itself incremental). See BUILDING.md.
//
-// Wayland backend is used because WSLg's X11/GLX path segfaults in Mesa; for a
-// normal X11 desktop, swap the wayland-* libs for "X11" and rebuild raylib
-// without the GLFW_LINUX_ENABLE_WAYLAND flags.
+// Desktop window/GL backend is raylib's SDL2 backend (PLATFORM_DESKTOP_SDL),
+// not GLFW: GLFW 3.4's Wayland drag-and-drop is broken (crashes on drag) and
+// its X11 path segfaults on WSLg. SDL is robust on both real Wayland (labwc)
+// and WSLg. Requires SDL2 dev installed system-wide. Web uses Emscripten/GLFW.
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
@@ -23,25 +24,21 @@ pub fn build(b: *std.Build) void {
// across platforms, so `make clean` first to avoid picking up wasm objects
// from a prior web build. Guarded on the desktop lib so it only builds once.
//
- // Before building, apply the GLFW Wayland drag-and-drop crash fix (see
- // patches/glfw-wayland-dnd-crash.patch). GLFW 3.4 (vendored in raylib 6.0)
- // leaves the wl_data_offer source_actions/action listener handlers NULL,
- // so libwayland wl_abort()s when a compositor sends them during a drag ->
- // the app crashes the moment a file is dragged over the window. Idempotent:
- // if the marker (dataOfferHandleAction) is already in the file, skip; else
- // apply the patch and delete any stale lib so `make` actually rebuilds.
+ // We use raylib's SDL backend (PLATFORM_DESKTOP_SDL) instead of the default
+ // GLFW backend. GLFW 3.4 (vendored in raylib 6.0) has broken drag-and-drop on
+ // Wayland (the wl_data_offer source_actions/action listeners are NULL ->
+ // libwayland wl_abort()s when a file is dragged over the window), and its X11
+ // backend segfaults on WSLg (Mesa GLX). SDL's own window/egl/drag-drop code is
+ // mature on both real Wayland (labwc) and WSLg, so one backend covers both
+ // targets with no vendor patches. Requires SDL2 dev installed system-wide
+ // (`pacman -S sdl2` / `sdl2-compat`). Web still uses Emscripten/GLFW (separate).
const raylib_lib = b.addSystemCommand(&.{
"sh", "-c",
"r=\"$PWD\"; mkdir -p \"$r/build/desktop\"; " ++
- "wlw=vendor/raylib/src/external/glfw/src/wl_window.c; " ++
- "if ! grep -q 'dataOfferHandleAction' \"$wlw\" 2>/dev/null; then " ++
- "(cd vendor/raylib && patch -p1 --forward < \"$r/patches/glfw-wayland-dnd-crash.patch\" >/dev/null); " ++
- "rm -f \"$r/build/desktop/libraylib.a\"; " ++
- "fi; " ++
"[ -f \"$r/build/desktop/libraylib.a\" ] || (" ++
"cd vendor/raylib/src && make clean >/dev/null 2>&1; " ++
- "make PLATFORM=PLATFORM_DESKTOP RAYLIB_LIBTYPE=STATIC " ++
- "GLFW_LINUX_ENABLE_WAYLAND=TRUE GLFW_LINUX_ENABLE_X11=FALSE -j4 " ++
+ "make PLATFORM=PLATFORM_DESKTOP_SDL RAYLIB_LIBTYPE=STATIC " ++
+ "SDL_INCLUDE_PATH=/usr/include/SDL2 SDL_LIBRARY_PATH=/usr/lib -j4 " ++
"RAYLIB_RELEASE_PATH=\"$r/build/desktop\")",
});
@@ -145,18 +142,13 @@ pub fn build(b: *std.Build) void {
// (MRB_USE_CXX_EXCEPTION) because a C++ mrbgem (rmlui) is present.
exe.root_module.addObjectFile(.{ .cwd_relative = "/usr/lib/libgcc_s.so.1" });
- // system libraries needed by raylib (desktop GLFW/Wayland) and mruby
+ // system libraries needed by raylib (desktop SDL2 backend) and mruby
+ exe.root_module.linkSystemLibrary("SDL2", .{});
exe.root_module.linkSystemLibrary("GL", .{});
- exe.root_module.linkSystemLibrary("EGL", .{});
exe.root_module.linkSystemLibrary("m", .{});
exe.root_module.linkSystemLibrary("pthread", .{});
exe.root_module.linkSystemLibrary("dl", .{});
exe.root_module.linkSystemLibrary("rt", .{});
- // Wayland backend (WSLg-friendly; avoids the broken Mesa GLX path)
- exe.root_module.linkSystemLibrary("wayland-client", .{});
- exe.root_module.linkSystemLibrary("wayland-cursor", .{});
- exe.root_module.linkSystemLibrary("wayland-egl", .{});
- exe.root_module.linkSystemLibrary("xkbcommon", .{});
// link only after the dependency libs are built
exe.step.dependOn(&raylib_lib.step);
diff --git a/patches/glfw-wayland-dnd-crash.patch b/patches/glfw-wayland-dnd-crash.patch
deleted file mode 100644
index 8a9bf1b..0000000
--- a/patches/glfw-wayland-dnd-crash.patch
+++ /dev/null
@@ -1,80 +0,0 @@
-From: study-player rewrite (backport of upstream GLFW master fix)
-Subject: [Wayland] Fix drag-and-drop crash on data offer source_actions/action
-
-raylib 6.0 vendors GLFW 3.4 (release), which has an unfixed Wayland
-drag-and-drop bug that crashes the host app the moment a file is dragged
-over the window (glfw/glfw#2835, glfw/glfw#2562). Fixed in GLFW master but
-NOT in the 3.4 release:
-
-`struct wl_data_offer_listener dataOfferListener` (wl_window.c) only
-initialises the `offer` (opcode 0) handler. `source_actions` (opcode 1)
-and `action` (opcode 2) are NULL (wl_data_offer is version 3; those events
-were added in v3). Modern compositors (labwc, GNOME, KDE, ...) emit
-source_actions/action during a drag, and libwayland-client then calls
-`wl_abort("listener function for opcode N of wl_data_offer is NULL")` ->
-the app dies on drag-enter, before any drop can happen. Provide no-op
-handlers so the events are safely consumed. (GLFW only needs the `offer`
-mime-types to decide what to accept on drop.)
-
-Also guard two NULL derefs in the same data-device path (both fixed in
-GLFW master, changelog: "A drag entering a non-GLFW surface could cause a
-segfault"): `dataDeviceHandleEnter` dereferenced `window` even when the
-drag entered a non-GLFW surface, and `dataDeviceHandleDrop` passed a
-possibly-NULL `dragFocus` to `_glfwInputDrop` (asserts are off in release).
-
-The X11/Xdnd backend (used by the original 'dev' app, -D_GLFW_X11) is a
-separate code path and is unaffected, which is why drag-and-drop is
-reliable there.
-
-Drop this patch once raylib vendors a GLFW release containing these fixes.
-
-diff --git a/src/external/glfw/src/wl_window.c b/src/external/glfw/src/wl_window.c
-index 505166e..d68faf8 100644
---- a/src/external/glfw/src/wl_window.c
-+++ b/src/external/glfw/src/wl_window.c
-@@ -1935,9 +1935,26 @@ static void dataOfferHandleOffer(void* userData,
- }
- }
-
-+// wl_data_offer v3 events. The compositor sends source_actions / action during
-+// a drag-and-drop; without handlers libwayland-client wl_abort()s on the NULL
-+// listener function pointer (glfw/glfw#2835). No-op handlers are sufficient.
-+static void dataOfferHandleSourceActions(void* userData,
-+ struct wl_data_offer* offer,
-+ uint32_t source_actions)
-+{
-+}
-+
-+static void dataOfferHandleAction(void* userData,
-+ struct wl_data_offer* offer,
-+ uint32_t dnd_action)
-+{
-+}
-+
- static const struct wl_data_offer_listener dataOfferListener =
- {
-- dataOfferHandleOffer
-+ dataOfferHandleOffer,
-+ dataOfferHandleSourceActions,
-+ dataOfferHandleAction
- };
-
- static void dataDeviceHandleDataOffer(void* userData,
-@@ -1987,7 +2004,7 @@ static void dataDeviceHandleEnter(void* userData,
- window = wl_surface_get_user_data(surface);
- }
-
-- if (surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list)
-+ if (window && surface == window->wl.surface && _glfw.wl.offers[i].text_uri_list)
- {
- _glfw.wl.dragOffer = offer;
- _glfw.wl.dragFocus = window;
-@@ -2042,7 +2059,7 @@ static void dataDeviceHandleDrop(void* userData,
- {
- int count;
- char** paths = _glfwParseUriList(string, &count);
-- if (paths)
-+ if (paths && _glfw.wl.dragFocus)
- _glfwInputDrop(_glfw.wl.dragFocus, count, (const char**) paths);
-
- for (int i = 0; i < count; i++)
diff --git a/tools/SCREENSHOT.md b/tools/SCREENSHOT.md
index d3dacad..1d44cc8 100644
--- a/tools/SCREENSHOT.md
+++ b/tools/SCREENSHOT.md
@@ -137,15 +137,14 @@ The desktop target needs a **driven display** — a real, interactive window. In
this WSL2/WSLg dev environment, running the desktop binary from a non-interactive
shell **stalls** (verified):
-- raylib is built **Wayland-only** (`GLFW_LINUX_ENABLE_WAYLAND=TRUE
- GLFW_LINUX_ENABLE_X11=FALSE`; WSLg's X11/GLX path segfaults inside Mesa — see
- `.agents/knowledge/environment.md`). With `XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
- WAYLAND_DISPLAY=wayland-0`, `InitWindow` connects to Wayland then **blocks in
- `do_sys_poll`** (0% CPU, state `S`) — the compositor doesn't drive a
- non-interactive window, so the framebuffer never renders and no PNG is produced.
-- The X11 path (`DISPLAY=:0`) initializes but **segfaults at GL/FBO setup**
- (the known Mesa `dri2GalliumConfigQueryb` crash); software GL (`LIBGL_ALWAYS_SOFTWARE`)
- doesn't help because the X11 backend isn't compiled in.
+- raylib's desktop build now uses the **SDL2** backend (`PLATFORM_DESKTOP_SDL`;
+ see `.agents/knowledge/environment.md`). With `XDG_RUNTIME_DIR=/mnt/wslg/runtime-dir
+ WAYLAND_DISPLAY=wayland-0`, the window opens but a **non-interactive** WSLg
+ compositor doesn't drive it, so the framebuffer never renders and no PNG is
+ produced (the earlier GLFW/Wayland build blocked in `do_sys_poll`; SDL reaches
+ init but the same non-interactive-display problem applies).
+- (Historical: the X11/GLFW path segfaulted in Mesa `dri2GalliumConfigQueryb` on
+ WSLg; that's why it was dropped. SDL sidesteps GLX.)
So `--target desktop` here will hit its 30s timeout and fall back to `ffmpeg`
(which also can't grab an unrendered window). **Use `--target web` in this