diff --git a/ivette/src/dome/main/dome.ts b/ivette/src/dome/main/dome.ts index 726187c36cee5ad038974d269aeb6a8afbbde0a1..993f45c5bdd104cb3bbe59bad0220b97631643ca 100644 --- a/ivette/src/dome/main/dome.ts +++ b/ivette/src/dome/main/dome.ts @@ -477,10 +477,22 @@ function createBrowserWindow( }); // Emitted when the window want's to close. - theWindow.on('close', () => { + const closeHandler = function (event: Event): void { + // Do not call this handler in a cycle; the next close event will forcibly + // close the window + theWindow.off('close', closeHandler); + // Do not close the window yet + event.preventDefault(); + handle.frame = theWindow.getBounds(); handle.devtools = webContents.isDevToolsOpened(); webContents.send('dome.ipc.closing'); + }; + + theWindow.on('close', closeHandler); + + ipcMain.on('dome.ipc.closing.done', () => { + theWindow.close(); }); // Keep track of frame positions (in DEVEL) @@ -631,6 +643,8 @@ ipcMain.on('dome.app.paths', (event) => { // --- Main Application Starter // -------------------------------------------------------------------------- +let isQuitting = false; + /** Starts the main process. */ export function start(): void { @@ -650,6 +664,11 @@ export function start(): void { app.on('activate', activateWindows); // Mac OSX response to dock app.on('second-instance', createSecondaryWindow); + // Configuring macOS for exiting + app.on('before-quit', () => { + isQuitting = true; + }); + // At-exit callbacks app.on('will-quit', () => { saveGlobalSettings(); @@ -661,7 +680,7 @@ export function start(): void { // Warning: when no event handler is registered, the app automatically // quit when all windows are closed. app.on('window-all-closed', () => { - if (System.platform !== 'macos') app.quit(); + if (isQuitting || System.platform !== 'macos') app.quit(); }); } diff --git a/ivette/src/dome/misc/system.ts b/ivette/src/dome/misc/system.ts index 0896e7712106c082ab1ad4a2db4d1da4354e55fa..d3c6f8e5a7f6c01cfae4946ba67ec25d644d47d4 100644 --- a/ivette/src/dome/misc/system.ts +++ b/ivette/src/dome/misc/system.ts @@ -114,7 +114,7 @@ emitter.setMaxListeners(250); // --- At Exit // -------------------------------------------------------------------------- -export type Callback = () => void; +export type Callback = () => (void | Promise<void>); const exitJobs: Callback[] = []; @@ -128,11 +128,14 @@ export function atExit(callback: Callback): void { } /** Execute all pending exit jobs (and flush the list). */ -export function doExit(): void { - exitJobs.forEach((fn) => { - try { fn(); } +export async function doExit(): Promise<void> { + await Promise.all(exitJobs.map(async (fn) => { + try { + const promise = fn(); + promise && await promise; + } catch (err) { D.error('atExit:', err); } - }); + })); exitJobs.length = 0; } @@ -465,13 +468,16 @@ export function rename(oldPath: string, newPath: string): Promise<void> { const childprocess = new Map<number, Exec.ChildProcess>(); -atExit(() => { - childprocess.forEach((process, pid) => { - try { process.kill(); } +atExit(async () => { + await Promise.all(Array.from(childprocess.values()).map(async (process) => { + try { + process.kill(); + await new Promise(resolve => process.on('exit', resolve)); + } catch (err) { - D.warn('killing process', pid, err); + D.warn('killing process', process.pid, err); } - }); + })); }); export type StdPipe = { path?: string | undefined; mode?: number; pipe?: boolean }; diff --git a/ivette/src/dome/renderer/dome.tsx b/ivette/src/dome/renderer/dome.tsx index 4410ed078d74224ccab45073213737b933e9c243..d05bbd025647811411d424b51848735991eb3992 100644 --- a/ivette/src/dome/renderer/dome.tsx +++ b/ivette/src/dome/renderer/dome.tsx @@ -251,10 +251,13 @@ export const globalSettings = new Event(Settings.global); // --- Closing // -------------------------------------------------------------------------- -ipcRenderer.on('dome.ipc.closing', System.doExit); +ipcRenderer.on('dome.ipc.closing', async () => { + await System.doExit(); + ipcRenderer.send('dome.ipc.closing.done'); + }); /** Register a callback to be executed when the window is closing. */ -export function atExit(callback: () => void): void { +export function atExit(callback: () => (void | Promise<void>)): void { System.atExit(callback); } diff --git a/ivette/src/frama-c/server.ts b/ivette/src/frama-c/server.ts index 122f9378047f9bd5274a2584fa88e509d0cbad56..9d2ff03677098da45328e952a7af094b664b93b7 100644 --- a/ivette/src/frama-c/server.ts +++ b/ivette/src/frama-c/server.ts @@ -284,6 +284,8 @@ export function stop(): void { } } +Dome.atExit(stop); + // -------------------------------------------------------------------------- // --- Server Control (Kill) // -------------------------------------------------------------------------- @@ -474,6 +476,9 @@ async function _launch(): Promise<void> { env, }; // Launch Process + System.atExit(() => { + sockaddr && System.remove(sockaddr); + }); process = await System.spawn(command, params, options); const logger = (text: string | string[]): void => { buffer.append(text);