Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/main-window-show-fallback.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@open-codesign/desktop": patch
---

Show the main window via a 2s fallback timer when `ready-to-show` never fires. On software-rendered systems (e.g. VMware/VirtualBox VMs where Chromium falls back to SwiftShader), the compositor never produces a first frame for a hidden window, so the window stayed invisible forever while the app ran healthy underneath.
17 changes: 16 additions & 1 deletion apps/desktop/src/main/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,22 @@ function createWindow(): void {
},
});

mainWindow.on('ready-to-show', () => mainWindow?.show());
// On software-rendered systems (e.g. VMware SVGA → SwiftShader fallback)
// the compositor never produces a first frame for a hidden window, so
// ready-to-show never fires and the window stays invisible forever while
// the app runs healthy underneath. The fallback timer shows the window
// anyway; on healthy systems ready-to-show fires well within 2s and
// startup stays flicker-free.
const showFallback = setTimeout(() => {
if (mainWindow !== null && !mainWindow.isDestroyed() && !mainWindow.isVisible()) {
mainWindow.show();
}
}, 2000);
mainWindow.on('ready-to-show', () => {
clearTimeout(showFallback);
mainWindow?.show();
});
mainWindow.on('closed', () => clearTimeout(showFallback));
// Null the reference on close so stale IPC sends from async emitters
// (autoUpdater, long-running generate runs) become clean no-ops rather
// than throwing "Object has been destroyed" on a discarded webContents.
Expand Down
Loading