fix(desktop): on Linux, reveal window on did-finish-load to avoid Wayland deadlock#2217
fix(desktop): on Linux, reveal window on did-finish-load to avoid Wayland deadlock#2217mwolson wants to merge 1 commit into
Conversation
|
Important Review skippedAuto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
ApprovabilityVerdict: Approved A targeted bug fix for a Linux/Wayland-specific deadlock where the standard Electron window reveal pattern fails. The change adds a fallback event listener only on Linux, with clear documentation and comprehensive unit tests. The logic is simple and the scope is well-contained. You can customize Macroscope's approvability policy. Learn more. |
…and deadlock On Linux/Wayland, Electron's `ready-to-show` event only fires after `show()` is called when the BrowserWindow is created with `show: false`, because the wl_surface has no role assigned until then and the compositor never reports the surface as ready. The standard "wait for ready, then show" pattern deadlocks: nothing ever calls `show()`, so the window never appears. Add `did-finish-load` as a Linux-only fallback trigger so the first event from either source reveals the window. Other platforms keep the no-flash `ready-to-show` path, since `did-finish-load` typically fires before the first paint there. Extract the bind-once logic into `bindFirstRevealTrigger` with focused unit tests.
efd4a55 to
32c6bc3
Compare
|
For anyone hitting this: there's an open Electron tracking issue at electron/electron#48859, and FreeTube landed a |
Summary
BrowserWindowcreated withshow: falsenever receivesready-to-show, because the wl_surface has no role assigned untilshow()is called and the compositor never reports the surface as ready. Net effect: the renderer loads but the window never appears.did-finish-loadas a Linux-only fallback reveal trigger so the first event from either source surfaces the window. Other platforms keep the no-flashready-to-showpath, sincedid-finish-loadtypically fires before the first paint there.bindFirstRevealTrigger(apps/desktop/src/windowReveal.ts) with focused unit tests.Fixes #2216.
Repro
T3-Code-0.0.20-x86_64.AppImage).Diagnosis
Confirmed via the Electron main-process Node inspector against the running process:
webContents.isLoading()transitioned tofalseanddid-finish-loadfired.ready-to-showdid NOT fire during an 8 s observation window.window.show()from the inspector,ready-to-showthen fired and the window appeared.This matches Electron's documented behavior:
ready-to-showis gated behind the renderer being marked "visible," which on Wayland requires the wl_surface to have a role assigned, which only happens onceshow()is called.Why Linux-only (and not Wayland-only)
Per Electron's docs,
ready-to-showis "usually emitted after thedid-finish-loadevent." So on macOS / Windows / X11, a dual-listener that fires on whichever comes first would reveal the window before first paint, regressing the no-flash startup behavior the originalready-to-showpattern was buying us.Gating the fallback to
process.platform === "linux"keeps the no-flash path intact on macOS / Windows / X11. X11 strictly doesn't need the fallback either, so this leaves a small avoidable regression for X11 users, a brief flash of the theme-matchedbackgroundColor(#0a0a0aor#ffffff) on first paint. I went with the broader Linux gate for simplicity.If you'd prefer to narrow this to actual Wayland sessions, the standard heuristic is:
Since Electron 38 (Sept 2025), the default
--ozone-platform-hint=automakes "Wayland session" effectively equal to "Wayland Ozone backend" unless the user forces--ozone-platform=x11. The two-env-var conjunction matches what Chromium itself uses for auto-detection and what VS Code / Signal use. Footguns: it can be missing in nested/non-systemd/sudo launches (rare for an AppImage launched from a desktop entry), and it cannot detect an explicit--ozone-platform=x11override. Happy to switch if maintainers prefer.Test plan
bun run test --filter=@t3tools/desktop(4 new tests, 91 total pass)bun typecheckbun lint(0 errors)bun fmtNote
Low Risk
Small, localized change to window reveal timing in the desktop main process; Linux-only fallback reduces risk of cross-platform behavior regressions.
Overview
Fixes a Linux/Wayland startup deadlock where a
BrowserWindowcreated withshow: falsemay never emitready-to-show, leaving the app invisible.main.tsnow reveals the first window on whichever happens first:ready-to-show(all platforms) or Linux-onlydid-finish-loadas a fallback, using a newbindFirstRevealTriggerhelper with unit tests to ensure the reveal callback fires exactly once.Reviewed by Cursor Bugbot for commit 32c6bc3. Bugbot is set up for automated code reviews on this repo. Configure here.
Note
Fix Wayland deadlock by revealing window on
did-finish-loadas a fallback on LinuxbindFirstRevealTriggerutility inwindowReveal.tsthat accepts multiple event subscribers and fires a reveal callback exactly once on the first event to trigger.ready-to-showcan never fire whenshow: falseis set under Wayland; adid-finish-loadsubscriber is added as a fallback so the window still reveals.ready-to-showas before.Macroscope summarized 32c6bc3.