fix(electron): keep window reachable when show/hide shortcut has no tray

The globalShowHide shortcut called mainWin.hide() unconditionally. On
Windows/Linux hide() removes the taskbar entry, so with no tray icon
the window became unreachable.

- macOS: use hide() (dock icon always remains).
- Windows/Linux: hide to tray only when minimize-to-tray is on AND the
  tray was created; otherwise minimize() to keep a taskbar handle.
- Log whether Windows tray creation used the GUID path, to help diagnose
  cases where the icon lands in the hidden overflow area.

Refs #7282
This commit is contained in:
Johannes Millan 2026-04-20 13:10:38 +02:00
parent 007c7024c7
commit 2cefde61bf
2 changed files with 26 additions and 5 deletions

View file

@ -136,11 +136,14 @@ const createTray = (): Tray => {
const trayIconPath = DIR + `stopped${suf}`;
let nextTray: Tray;
if (IS_WINDOWS) {
const guid = getWindowsTrayGuid();
try {
nextTray = new Tray(trayIconPath, getWindowsTrayGuid());
nextTray = new Tray(trayIconPath, guid);
log('Tray created on Windows with GUID:', guid);
} catch (e) {
log('Tray creation with GUID failed, retrying without GUID:', e);
nextTray = new Tray(trayIconPath);
log('Tray created on Windows without GUID');
}
} else {
nextTray = new Tray(trayIconPath);

View file

@ -3,10 +3,13 @@ import { IPC } from '../shared-with-frontend/ipc-events.const';
import { KeyboardConfig } from '../../src/app/features/config/keyboard-config.model';
import { getWin } from '../main-window';
import { showOrFocus } from '../various-shared';
import { ensureIndicator } from '../indicator';
import { getIsMinimizeToTray } from '../shared-state';
import { IS_MAC } from '../common.const';
import { errorHandlerWithFrontendInform } from '../error-handler-with-frontend-inform';
export const initGlobalShortcutsIpc = (): void => {
ipcMain.on(IPC.REGISTER_GLOBAL_SHORTCUTS_EVENT, (ev, cfg) => {
ipcMain.on(IPC.REGISTER_GLOBAL_SHORTCUTS_EVENT, (_ev, cfg) => {
registerShowAppShortCuts(cfg);
});
};
@ -32,12 +35,27 @@ const registerShowAppShortCuts = (cfg: KeyboardConfig): void => {
switch (key) {
case 'globalShowHide':
actionFn = () => {
if (mainWin.isFocused()) {
// we need to blur the window for windows
if (!mainWin.isFocused()) {
showOrFocus(mainWin);
return;
}
// Hide strategy differs by platform:
// - macOS: the dock icon always remains after hide(), so the
// window stays reachable without any tray. Match the native
// Cmd+H gesture users expect from a "show/hide" shortcut.
// - Windows/Linux: hide() removes the taskbar entry. Without a
// visible tray icon the window becomes unreachable (see #7282).
// Only hide to tray when minimize-to-tray is enabled AND the
// tray was successfully (re)created; otherwise minimize so a
// taskbar handle remains as a safety net. blur() is a Windows
// focus workaround (electron#20464) and a no-op elsewhere.
if (IS_MAC) {
mainWin.hide();
} else if (getIsMinimizeToTray() && ensureIndicator()) {
mainWin.blur();
mainWin.hide();
} else {
showOrFocus(mainWin);
mainWin.minimize();
}
};
break;