summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorOskar Nyberg <oskar@mullvad.net>2022-08-24 11:07:00 +0200
committerOskar Nyberg <oskar@mullvad.net>2022-08-26 13:39:26 +0200
commit100fc2d1fd26e01a8fe79f6cf696891891fe5c4d (patch)
treee3b7ab3065de80603b244402c2afe6e3b7ac1da3
parent1499e2ab919b853e714cb18a323b77db640e0a51 (diff)
downloadmullvadvpn-100fc2d1fd26e01a8fe79f6cf696891891fe5c4d.tar.xz
mullvadvpn-100fc2d1fd26e01a8fe79f6cf696891891fe5c4d.zip
Simplify app quit procedure
-rw-r--r--gui/src/main/index.ts73
-rw-r--r--gui/src/main/user-interface.ts31
-rw-r--r--gui/src/shared/logging.ts8
3 files changed, 49 insertions, 63 deletions
diff --git a/gui/src/main/index.ts b/gui/src/main/index.ts
index cba52d61e1..ef6fdc894b 100644
--- a/gui/src/main/index.ts
+++ b/gui/src/main/index.ts
@@ -59,12 +59,6 @@ enum CommandLineOptions {
disableResetNavigation = '--disable-reset-navigation', // development only
}
-export enum AppQuitStage {
- unready,
- initiated,
- ready,
-}
-
const ALLOWED_PERMISSIONS = ['clipboard-sanitized-write'];
const SANDBOX_DISABLED = app.commandLine.hasSwitch('no-sandbox');
@@ -94,7 +88,7 @@ class ApplicationMain
private reconnectBackoff = new ReconnectionBackoff();
private beforeFirstDaemonConnection = true;
private isPerformingPostUpgrade = false;
- private quitStage = AppQuitStage.unready;
+ private quitInitiated = false;
private tunnelStateExpectation?: Expectation;
@@ -171,9 +165,16 @@ class ApplicationMain
app.on('activate', this.onActivate);
app.on('ready', this.onReady);
- app.on('window-all-closed', () => app.quit());
+
app.on('before-quit', this.onBeforeQuit);
- app.on('quit', this.onQuit);
+ app.on('will-quit', () => {
+ log.info('will-quit received');
+ this.onQuit();
+ });
+ app.on('quit', () => {
+ log.info('quit received');
+ this.onQuit();
+ });
}
public async performPostUpgradeCheck(): Promise<void> {
@@ -293,45 +294,30 @@ class ApplicationMain
// This is a last try to disconnect and quit gracefully if the app quits without having received
// the before-quit event.
private onQuit = () => {
- if (this.quitStage !== AppQuitStage.ready) {
+ if (!this.quitInitiated) {
this.prepareToQuit();
}
};
private onBeforeQuit = (event: Electron.Event) => {
- switch (this.quitStage) {
- case AppQuitStage.unready:
- // postpone the app shutdown
- event.preventDefault();
-
- this.quitStage = AppQuitStage.initiated;
-
- log.info('Quit initiated');
-
- this.prepareToQuit();
-
- // terminate the app
- this.quitStage = AppQuitStage.ready;
- app.quit();
- break;
-
- case AppQuitStage.initiated:
- // prevent immediate exit, the app will quit after running the shutdown routine
- event.preventDefault();
- return;
-
- case AppQuitStage.ready:
- // let the app quit freely at this point
- break;
+ log.info('before-quit received');
+ if (this.quitInitiated) {
+ event.preventDefault();
+ } else {
+ this.prepareToQuit();
}
};
private prepareToQuit() {
+ this.quitInitiated = true;
+ log.info('Quit initiated');
+
+ this.userInterface?.dispose();
+
// Unsubscribe the event handler
try {
if (this.daemonEventListener) {
this.daemonRpc.unsubscribeDaemonEventListener(this.daemonEventListener);
-
log.info('Unsubscribed from the daemon events');
}
} catch (e) {
@@ -339,29 +325,21 @@ class ApplicationMain
log.error(`Failed to unsubscribe from daemon events: ${error.message}`);
}
- // The window is not closable on macOS to be able to hide the titlebar and workaround
- // a shadow bug rendered above the invisible title bar. This also prevents the window from
- // closing normally, even programmatically. Therefore re-enable the close button just before
- // quitting the app.
- // Github issue: https://github.com/electron/electron/issues/15008
- if (process.platform === 'darwin') {
- this.userInterface?.setWindowClosable(true);
- }
-
if (this.daemonRpc.isConnected) {
this.daemonRpc.disconnect();
}
for (const logger of [log, this.rendererLog]) {
try {
- logger?.dispose();
+ logger?.disposeDisposableOutputs();
} catch (e) {
const error = e as Error;
- console.error('Failed to dispose logger:', error);
+ log.error('Failed to dispose logger:', error);
}
}
- this.userInterface?.dispose();
+ log.info('Disposable logging outputs disposed');
+ log.info('Quit preperations finished');
}
private detectLocale(): string {
@@ -947,7 +925,6 @@ class ApplicationMain
public resetTunnelStateAnnouncements = () =>
this.notificationController.resetTunnelStateAnnouncements();
public isUnpinnedWindow = () => this.settings.gui.unpinnedWindow;
- public getAppQuitStage = () => this.quitStage;
public updateAccountData = () => this.account.updateAccountData();
public getAccountData = () => this.account.accountData;
diff --git a/gui/src/main/user-interface.ts b/gui/src/main/user-interface.ts
index b7a05c7d23..712d7e42b8 100644
--- a/gui/src/main/user-interface.ts
+++ b/gui/src/main/user-interface.ts
@@ -9,7 +9,6 @@ import { messages, relayLocations } from '../shared/gettext';
import log from '../shared/logging';
import { Scheduler } from '../shared/scheduler';
import { DaemonRpc } from './daemon-rpc';
-import { AppQuitStage } from './index';
import { changeIpcWebContents, IpcMainEventChannel } from './ipc-event-channel';
import { isMacOs11OrNewer } from './platform-version';
import TrayIconController, { TrayIconType } from './tray-icon-controller';
@@ -24,7 +23,6 @@ export interface UserInterfaceDelegate {
disconnectTunnel(): void;
isUnpinnedWindow(): boolean;
isLoggedIn(): boolean;
- getAppQuitStage(): AppQuitStage;
getAccountData(): IAccountData | undefined;
getTunnelState(): TunnelState;
}
@@ -158,18 +156,27 @@ export default class UserInterface implements WindowControllerDelegate {
this.trayIconController?.setUseMonochromaticIcon(value);
public setWindowIcon = (icon: string) => this.windowController.window?.setIcon(icon);
- public setWindowClosable = (value: boolean) => {
- if (this.windowController.window) {
- this.windowController.window.closable = value;
- }
- };
-
public updateTrayIcon(tunnelState: TunnelState, blockWhenDisconnected: boolean) {
const type = this.trayIconType(tunnelState, blockWhenDisconnected);
this.trayIconController?.animateToIcon(type);
}
- public dispose = () => this.trayIconController?.dispose();
+ public dispose = () => {
+ this.tray.removeAllListeners();
+ this.windowController.window?.removeAllListeners();
+
+ // The window is not closable on macOS to be able to hide the titlebar and workaround
+ // a shadow bug rendered above the invisible title bar. This also prevents the window from
+ // closing normally, even programmatically. Therefore re-enable the close button just before
+ // quitting the app.
+ // Github issue: https://github.com/electron/electron/issues/15008
+ if (process.platform === 'darwin' && this.windowController.window) {
+ this.windowController.window.closable = true;
+ }
+
+ this.windowController.close();
+ this.trayIconController?.dispose();
+ };
private createTray(): Tray {
const tray = new Tray(nativeImage.createEmpty());
@@ -472,10 +479,8 @@ export default class UserInterface implements WindowControllerDelegate {
}
this.windowController.window?.on('close', (closeEvent: Event) => {
- if (this.delegate.getAppQuitStage() !== AppQuitStage.ready) {
- closeEvent.preventDefault();
- this.windowController.hide();
- }
+ closeEvent.preventDefault();
+ this.windowController.hide();
});
}
diff --git a/gui/src/shared/logging.ts b/gui/src/shared/logging.ts
index 77d0168701..c2537e00d4 100644
--- a/gui/src/shared/logging.ts
+++ b/gui/src/shared/logging.ts
@@ -25,8 +25,12 @@ export class Logger {
public verbose = (...data: unknown[]) => this.log(LogLevel.verbose, ...data);
public debug = (...data: unknown[]) => this.log(LogLevel.debug, ...data);
- public dispose() {
- this.outputs.forEach((output) => output.dispose?.());
+ public disposeDisposableOutputs() {
+ // Keep the outputs that aren't disposable to continue to forward log messages to them.
+ this.outputs = this.outputs.filter((output) => {
+ output.dispose?.();
+ return output.dispose === undefined;
+ });
}
private getDateString(): string {