diff options
| author | Christophe Besson <cbesson@gmail.com> | 2026-09-07 15:01:12 +0200 |
|---|---|---|
| committer | Christophe Besson <cbesson@gmail.com> | 2026-09-07 15:01:12 +0200 |
| commit | 8883d60d0afa2ed9dd1ef68bc21fe1b9a65a59ff (patch) | |
| tree | 5b6ecc0da84227e31dba6547ea81dd55c1894645 /packages/meshbay-client/src/main.js | |
| parent | 2c0903c648e24b4e2adf20492398e8b67d033b49 (diff) | |
| download | meshbay-8883d60d0afa2ed9dd1ef68bc21fe1b9a65a59ff.tar.gz | |
fix(client): break the Wayland ready-to-show deadlock
Some Wayland compositors never schedule a first paint for an unmapped
surface, but the window stays unmapped until show() runs, which was
gated entirely on that paint's ready-to-show event — a cycle with no
way out on its own. Observed under GNOME/Mutter on a VM whose
virtio-gpu device fails command-buffer creation. Add a bounded
fallback show(), guarded on isVisible() so it's a no-op once the
event has already fired normally and doesn't steal focus back from
whatever the person switched to.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CHKaCz2gq3ya8t13CvQ7Hp
Diffstat (limited to 'packages/meshbay-client/src/main.js')
| -rw-r--r-- | packages/meshbay-client/src/main.js | 10 |
1 files changed, 10 insertions, 0 deletions
diff --git a/packages/meshbay-client/src/main.js b/packages/meshbay-client/src/main.js index de8de8f..27c81b8 100644 --- a/packages/meshbay-client/src/main.js +++ b/packages/meshbay-client/src/main.js @@ -453,6 +453,16 @@ function createWindow() { }); win.once('ready-to-show', () => win.show()); + // Some Wayland compositors (observed under GNOME/Mutter on a VM with a + // virtio-gpu device whose command-buffer creation fails) never schedule a + // first paint for a surface that isn't mapped yet — but Electron won't map + // it (show()) until `ready-to-show` fires, which waits for that paint. The + // two conditions deadlock the window invisible forever. This bounded + // fallback breaks the cycle. Guarded on isVisible(): show() also raises + // and refocuses an already-visible window, so once the event has fired + // normally (real GPU/X11 hosts, well under 2s) this must stay a no-op + // rather than yank focus back from whatever the person switched to. + setTimeout(() => { if (!win.isDestroyed() && !win.isVisible()) win.show(); }, 2000); // The hub must never become the document origin. Anything that would navigate // away from the packaged interface is refused, and an external link opens in |