diff --git a/src/main/index.ts b/src/main/index.ts index 82fa095bb3e..a0587e9dfab 100644 --- a/src/main/index.ts +++ b/src/main/index.ts @@ -145,8 +145,6 @@ function createWindow(): BrowserWindow { } }) - - // HMR for renderer base on electron-vite cli. // Load the remote URL for development or the local html file for production. if (is.dev && process.env['ELECTRON_RENDERER_URL']) { @@ -271,7 +269,7 @@ app.whenReady().then(() => { registerUIHandlers(store) registerFilesystemHandlers(store) warmSystemFontFamilies() - setupAutoUpdater(mainWindow) + setupAutoUpdater(mainWindow, { onBeforeQuit: () => store?.flush() }) // Clipboard: read text via Electron's native clipboard module so the // renderer can bypass Chromium's clipboard pipeline (which holds diff --git a/src/main/updater.ts b/src/main/updater.ts index b7158b93b64..ebbec0462a1 100644 --- a/src/main/updater.ts +++ b/src/main/updater.ts @@ -2,10 +2,12 @@ import { app, BrowserWindow } from 'electron' import { autoUpdater } from 'electron-updater' import { is } from '@electron-toolkit/utils' import type { UpdateStatus } from '../shared/types' +import { killAllPty } from './ipc/pty' let mainWindowRef: BrowserWindow | null = null let currentStatus: UpdateStatus = { state: 'idle' } let userInitiatedCheck = false +let onBeforeQuitCleanup: (() => void) | null = null function sendStatus(status: UpdateStatus): void { currentStatus = status @@ -46,32 +48,35 @@ export function checkForUpdatesFromMenu(): void { } export function quitAndInstall(): void { - if (process.platform === 'darwin') { - // On macOS, autoUpdater.quitAndInstall() calls app.exit() which bypasses - // the normal quit lifecycle, causing the "quit unexpectedly" crash dialog. - // Instead, use app.relaunch() + app.quit() which goes through the proper - // lifecycle. autoInstallOnAppQuit (set in setupAutoUpdater) ensures the - // update is applied during the quit process. - app.relaunch() - app.quit() - } else { - // On Windows/Linux, quitAndInstall works correctly with the NSIS installer. - const windows = BrowserWindow.getAllWindows() - for (const win of windows) { - win.removeAllListeners('close') - win.destroy() - } - setImmediate(() => { - autoUpdater.quitAndInstall(false, true) - }) + // autoUpdater.quitAndInstall() calls app.exit() which bypasses the normal + // before-quit lifecycle. Run cleanup that would normally happen there. + killAllPty() + onBeforeQuitCleanup?.() + + const windows = BrowserWindow.getAllWindows() + for (const win of windows) { + win.removeAllListeners('close') + win.destroy() } + + setImmediate(() => { + autoUpdater.quitAndInstall(false, true) + }) } -export function setupAutoUpdater(mainWindow: BrowserWindow): void { +export function setupAutoUpdater( + mainWindow: BrowserWindow, + opts?: { onBeforeQuit?: () => void } +): void { mainWindowRef = mainWindow + onBeforeQuitCleanup = opts?.onBeforeQuit ?? null - if (!app.isPackaged && !is.dev) return - if (is.dev) return + if (!app.isPackaged && !is.dev) { + return + } + if (is.dev) { + return + } autoUpdater.autoDownload = true autoUpdater.autoInstallOnAppQuit = true