Skip to content

fix(gui): don't let minimize-to-tray block app quit and OS shutdown - #240

Merged
dbfx merged 2 commits into
AdventDevInc:mainfrom
esrever10:fix/quit-blocked-by-tray-close-handler
Jul 27, 2026
Merged

fix(gui): don't let minimize-to-tray block app quit and OS shutdown#240
dbfx merged 2 commits into
AdventDevInc:mainfrom
esrever10:fix/quit-blocked-by-tray-close-handler

Conversation

@esrever10

@esrever10 esrever10 commented Jul 22, 2026

Copy link
Copy Markdown
Contributor

Fixes #239.

Problem

With Minimize to tray enabled, the main window's close handler calls e.preventDefault() unconditionally. app.quit() closes all windows before quitting, so the prevented close aborts the whole quit flow: Cmd+Q and the menu Quit just hide the window, and on macOS the app blocks system shutdown/restart until it is force-quit. See #239 for full details.

Fix

The standard Electron pattern for tray apps:

  • add a module-level isQuitting flag, set in before-quit and in before-quit-for-update (on macOS autoUpdater.quitAndInstall() closes windows before before-quit fires, so without the latter the interceptor would still block update restarts)
  • the close interceptor returns early when isQuitting is set, so windows close and quit proceeds
  • drop the removeAllListeners('close') workaround from the two tray Quit items (createTray / rebuildTrayMenu) — app.quit() now works on its own

Behavior is otherwise unchanged: clicking the window's close button with minimize-to-tray enabled still hides to tray.

Testing

  • electron-vite build passes
  • vitest run: 2054 tests pass (the two electron-binary-dependent test files don't run in my environment; unrelated to this change)
  • Manually verified the quit flow logic against Electron's documented before-quit → window close ordering; with the flag set the interceptor no longer prevents close, so Cmd+Q, Dock → Quit, tray → Quit, and OS shutdown all proceed

🤖 Generated with Claude Code

When minimizeToTray is enabled, the main window's close handler calls
e.preventDefault() unconditionally. Since app.quit() closes all windows
before quitting, the prevented close aborts the whole quit flow: Cmd+Q
and the app menu's Quit just hide the window, and on macOS the app
blocks system shutdown until it is force-quit.

Set a flag in before-quit and let close proceed once it is set. This
also makes the removeAllListeners('close') workaround in the tray Quit
items unnecessary.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
On macOS autoUpdater.quitAndInstall() closes all windows before
before-quit is emitted, so the flag set there is too late and the
minimize-to-tray close interceptor would still block update restarts.
before-quit-for-update fires before the windows close.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@dbfx

dbfx commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Thank you @esrever10 !

@dbfx
dbfx merged commit 252e3e4 into AdventDevInc:main Jul 27, 2026
4 of 5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Quit blocked when minimize-to-tray is enabled: Cmd+Q does nothing and macOS shutdown hangs until Kudu is force-quit

2 participants