From e4bb4f2258282ad9fed1748ce819056cc4c3c853 Mon Sep 17 00:00:00 2001 From: Marceli Pawlinski Date: Sun, 26 Jul 2026 04:18:26 +0100 Subject: [PATCH] fix: prevent Windows tray blur->hide race on window show (#3064) On Windows, clicking the tray icon may not transfer focus to the window, triggering electron-menubar's internal blur handler which hides the window after a 100ms timeout. If this timeout fires before the first paint, the user sees no visible result. Workaround: listen for 'after-show' and temporarily set alwaysOnTop=true so the blur handler emits 'focus-lost' instead of hiding. Restore the user's preference after 400ms. --- src/main/lifecycle/window.ts | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/src/main/lifecycle/window.ts b/src/main/lifecycle/window.ts index b1dcd459f..c4459f140 100644 --- a/src/main/lifecycle/window.ts +++ b/src/main/lifecycle/window.ts @@ -1,7 +1,7 @@ import { app } from 'electron'; import type { Menubar } from 'electron-menubar'; -import { isMacOS } from '../../shared/platform'; +import { isMacOS, isWindows } from '../../shared/platform'; import { WindowConfig } from '../config'; import type MenuBuilder from '../menu'; @@ -61,6 +61,25 @@ export function configureWindowEvents(mb: Menubar, menuBuilder: MenuBuilder): vo menuBuilder.setWindowVisibility(false); }); + // Windows tray blur race workaround: + // On Windows, clicking the tray icon may not transfer focus to the window, + // triggering electron-menubar's internal blur→hide timeout before first paint. + // Temporarily set alwaysOnTop so the blur handler emits 'focus-lost' instead + // of hiding; restore the user's preference after the blur window passes. + if (isWindows()) { + mb.on('after-show', () => { + const w = mb.window; + if (!w || w.isDestroyed()) return; + const restoreOnBlur = keepWindowOnBlur; + w.setAlwaysOnTop(true); + setTimeout(() => { + if (!w.isDestroyed()) { + w.setAlwaysOnTop(restoreOnBlur); + } + }, 400); + }); + } + app.on('before-quit', () => { isQuitting = true; });