Fix black window on Linux + NVIDIA (WebKitGTK DMABUF renderer)

On the NVIDIA proprietary driver the app booted, logged "miniSCP started",
reported no error — and painted a completely black window, with stderr showing
"Failed to create GBM buffer of size WxH: Invalid argument" and an X11
GLXBadWindow. WebKitGTK's DMABUF renderer cannot allocate buffers there;
WEBKIT_DISABLE_DMABUF_RENDERER=1 is the upstream workaround. Pre-existing on
Linux, unrelated to the context-menu change — it just had never been looked at
because nothing on Linux had been run before.

The app CANNOT apply this to itself. WebKit reads the variable when it forks
its web process, and Bun's `process.env` writes do not propagate to child
processes (verified: a spawned child sees it unset), so setting it in
src/bun/index.ts is inert even from a module imported before `electrobun/bun`.
It has to be in the environment before the app process starts, which means
every launch path must inject it:

- scripts/linux-gpu.ts — shared `launchEnv()` helper, gated on
  /proc/driver/nvidia so Intel/AMD keep hardware compositing, and never
  overriding an explicit value from the user's environment.
- scripts/dev.ts — uses it for `bun run dev`.
- scripts/start.ts (new) — `bun run start` previously called `bunx electrobun
  dev` straight from package.json, where no env could be set; it now goes
  through a script like dev does.
- scripts/release.ts — writes a `miniSCP.sh` wrapper beside bin/launcher in the
  Linux tarball, since a packaged app goes through none of the above.

Documented in gotchas.md (including that a "does it boot?" log check does NOT
catch this — the log looks healthy) and platform-notes.md, with the smoke test
updated to require that the UI actually renders.

Verified: backend `tsc --noEmit` clean, `bun run build:ui` clean, and
`bun run start` now boots with zero GBM/GLX errors.

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2026-08-15 14:53:22 +02:00
co-authored by Claude
parent f7ebed5478
commit 30a432cd37
9 changed files with 120 additions and 19 deletions
+3 -1
View File
@@ -62,7 +62,9 @@ Facts the script encodes:
`stable-linux-x64-miniSCP.tar.zst` + `update.json`, i.e. the updater feed and
nothing installable, so the script's **`.tar.gz` of the assembled app folder**
under `build/stable-linux-x64/` IS the release artifact (same best-effort
warn). No AppImage/.deb/.desktop — unpack and run `bin/launcher`.
warn). No AppImage/.deb/.desktop — unpack and run the `miniSCP.sh` wrapper the
script writes beside `bin/launcher` (it applies the NVIDIA/DMABUF workaround,
which the app cannot set for itself — see gotchas.md).
- **Linux builds need the AppIndicator dev libraries present to RUN** (not to
build) — see platform-notes.md; a packaged tarball started on a machine
without them dies at `dlopen`.
+19 -3
View File
@@ -67,9 +67,25 @@ touching the adjacent code.
`libasar.so => not found` line in that output is a red herring (it ships beside
the wrapper and resolves at load). Install list per distro is in
[platform-notes.md](platform-notes.md).
- Benign startup noise on Linux — all non-fatal, the app runs normally:
`X11 Error: GLXBadWindow (code 170)`, `Failed to create GBM buffer of size
WxH: Invalid argument` (compositor/GLX chatter from the GTK webview), and
- **Black window on NVIDIA + `Failed to create GBM buffer of size WxH: Invalid
argument`** (usually with `X11 Error: GLXBadWindow (code 170)`). The app boots,
logs "miniSCP started", reports no error — and paints nothing. WebKitGTK's
DMABUF renderer can't allocate buffers on the NVIDIA proprietary driver;
`WEBKIT_DISABLE_DMABUF_RENDERER=1` is the upstream workaround.
- **The app cannot apply this to itself.** WebKit reads the variable when it
forks its web process, and **Bun's `process.env` writes do not propagate to
child processes** (verified: a spawned child sees it unset). Setting it in
`src/bun/index.ts` — even in a module imported before `electrobun/bun` —
does nothing. It must be in the environment before the app process starts.
- Hence every launch path injects it: `scripts/linux-gpu.ts` (`launchEnv()`)
for `bun run dev` / `bun run start`, and the `miniSCP.sh` wrapper that
`release.ts` writes beside `bin/launcher` in the tarball. **A new launch
path must call `launchEnv()` or it will render black on NVIDIA.**
- Gated on `/proc/driver/nvidia` so Intel/AMD keep hardware compositing, and
an explicit `WEBKIT_DISABLE_DMABUF_RENDERER` from the user always wins.
- A "does it boot?" log check does NOT catch this — grep for the GBM line, or
look at the window.
- Benign startup noise on Linux — non-fatal, the app runs normally:
`libayatana-appindicator is deprecated. Please use libayatana-appindicator-glib`
(upstream electrobun's choice, not ours).
- **Window-open flash prevention is three-layer** — remove any one and the
+15 -7
View File
@@ -96,18 +96,26 @@ either way — the tray is a convenience, and every action it offers exists in-a
already macOS-only, and the panel context menus are now HTML on every platform,
so nothing is missing at the UI level — but do not add a feature that depends
on a native menu.
- **Benign startup noise**: `X11 Error: GLXBadWindow (code 170)`, `Failed to
create GBM buffer of size WxH: Invalid argument`, and a deprecation warning
pointing at `libayatana-appindicator-glib`. None are fatal.
- **NVIDIA renders black without the DMABUF workaround.** WebKitGTK can't
allocate GBM buffers on the proprietary driver, so the window paints nothing
while the log looks perfectly healthy. Every launch path sets
`WEBKIT_DISABLE_DMABUF_RENDERER=1` when `/proc/driver/nvidia` exists —
`scripts/linux-gpu.ts` for dev, the `miniSCP.sh` wrapper in the tarball for
releases. The app can't do it itself (Bun's `process.env` writes don't reach
child processes); see [gotchas.md](gotchas.md#linux).
- **Benign startup noise**: a deprecation warning pointing at
`libayatana-appindicator-glib`. Not fatal.
- **Unsigned, unpackaged**: the release artifact is a portable tarball — no
AppImage, `.deb`, `.desktop` entry or icon installation. Unpack and run
`bin/launcher`.
`miniSCP.sh` (which execs `bin/launcher`).
## First-Linux-boot smoke test
1. Install the AppIndicator package for your distro (table above), then
`bun run start`. The window opens and the tray icon appears (or doesn't, on
bare GNOME — that's the extension caveat, not a failure).
`bun run start`. The window opens **and actually renders the UI** (a black
window on NVIDIA means the DMABUF workaround didn't apply — check for
`Failed to create GBM buffer` in the log), and the tray icon appears (or
doesn't, on bare GNOME — that's the extension caveat, not a failure).
2. Right-click a file row: menu appears at the pointer, Send to Other Panel is
first, Permissions is present, Escape / click-outside / arrow keys + Enter all
work, and a right-click near the bottom-right flips the menu instead of
@@ -122,7 +130,7 @@ either way — the tray is a convenience, and every action it offers exists in-a
6. Move to Trash lands the item in the desktop's trash; connections.json is 0600.
7. `bun scripts/release.ts --target linux-x64` produces
`release/linux-x64/miniSCP-Build<N>-linux-x64.tar.gz`; unpack it elsewhere and
run `bin/launcher`.
run `miniSCP.sh`.
## Windows known issues (upstream electrobun, documented not fixed)