Repository navigation
fix(desktop): finish the macOS Cmd+Q quit after shutdown - #59144
Conversation
Co-authored-by: anmol0b <[email protected]>
There was a problem hiding this comment.
The change looks sound. I couldn't run it: the bug needs keyboard Cmd+Q and the Dock in the macOS desktop app, and this sandbox is Linux with no display. I read the change against Electron's quit flow and effect's Effect.cached. tsc -b and the lifecycle tests pass.
The deferred re-quit still goes through will-quit/quit, so install-on-quit for updates keeps working. The window-all-closed backstop only matters when a quit was dropped, because Electron doesn't send that event while it's quitting. The 10s timeout does stop a hung dispose(): the cached run is stopped and the stop isn't stored. As a result, will-quit starts shutdown.run again from scratch, which is harmless as the app exits.
Public API: unchanged.
A quick Cmd+Q, then Dock click, on a Mac build before merging would confirm the fix end to end.
Related: #54296
Issue for this PR
Closes #56394
Supersedes #58949 (builds on @anmol0b's diagnosis and deferred re-quit there).
Type of change
What does this PR do?
On macOS, keyboard Cmd+Q closes the window but leaves the main process running. Reopening from the Dock then builds a window on a process whose shutdown has already run, and it stays on the loading splash.
Electron's
Browser::Quit()runsis_quitting_ = HandleBeforeQuit(), so it records ourpreventDefault()only afterbefore-quitreturns. When no extension host has loaded,shutdown.runfinishes in a microtask, and the re-issuedapp.quit()runs while the first emit is still on the stack. The nested quit starts closing windows, then the outer call writesis_quitting_ = falseover it. When the last window closes, Electron emitswindow-all-closedinstead ofwill-quit, which is a no-op on macOS.Changes in
lifecycle/index.ts:setImmediateso the cancelled quit has finished unwinding before the new one starts.app.exitisn't used because it skipswill-quit/quit, which electron-updater's install-on-quit depends on.window-all-closed: oncebefore-quithas fired, quit on macOS too. A quit that Electron drops for any reason still finishes instead of leaving a windowless process. The flag is set inbefore-quit, soautoUpdater.quitAndInstall(which closes windows before emittingbefore-quit) is unaffected.activateafter a quit was requested, so the Dock never opens a window on torn-down services.prepareToRestartat 10s, so a hung shutdown step can't leave every quit waiting forever.Also renames
makeMainWindows,makeWindowRecoveryandmakeUnresponsiveSamplertomainWindows,windowRecoveryandunresponsiveSampler.lint:changedchecks whole touched files, andno-service-constructor-importsflags any relativemake[A-Z]import, so each of these fails the check once its importing file is edited.How did you verify your code works?
bun typecheckandbun run typecheck:tscinpackages/desktop.bun run lint:changed: clean.activateguard only take effect when a quit is dropped.Requested by: @Brendonovich (Brendan via Slack)