From 998a65e2ca6a5d8933416c8cf0a261fe86edafa5 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Tue, 18 Jun 2019 15:12:41 +0200 Subject: [PATCH] web - best lifecycle support we can do currently --- .../lifecycle/browser/lifecycleService.ts | 58 +++++++++++++++++++ .../lifecycle/common/lifecycleService.ts | 3 +- .../electron-browser/lifecycleService.ts | 5 +- .../lifecycle/electron-main/lifecycleMain.ts | 2 +- .../api/browser/mainThreadWebview.ts | 6 +- .../workbench/browser/web.simpleservices.ts | 54 +---------------- .../textfile/browser/textFileService.ts | 14 +++++ .../textfile/common/textFileService.ts | 2 +- .../workspaceEditingService.ts | 6 +- src/vs/workbench/workbench.web.main.ts | 8 +-- 10 files changed, 91 insertions(+), 67 deletions(-) create mode 100644 src/vs/platform/lifecycle/browser/lifecycleService.ts diff --git a/src/vs/platform/lifecycle/browser/lifecycleService.ts b/src/vs/platform/lifecycle/browser/lifecycleService.ts new file mode 100644 index 00000000000..b0c3014986f --- /dev/null +++ b/src/vs/platform/lifecycle/browser/lifecycleService.ts @@ -0,0 +1,58 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { ILogService } from 'vs/platform/log/common/log'; +import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; +import { localize } from 'vs/nls'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; + +export class BrowserLifecycleService extends AbstractLifecycleService { + + _serviceBrand: ServiceIdentifier; + + constructor( + @ILogService readonly logService: ILogService + ) { + super(logService); + + this.registerListeners(); + } + + private registerListeners(): void { + window.onbeforeunload = () => this.beforeUnload(); + } + + private beforeUnload(): string | null { + let veto: boolean = false; + + // Before Shutdown + this._onBeforeShutdown.fire({ + veto(value) { + if (value === true) { + veto = true; + } else if (value instanceof Promise && !veto) { + console.warn(new Error('Long running onBeforeShutdown currently not supported')); + } + }, + reason: ShutdownReason.QUIT + }); + + // Veto: signal back to browser by returning a non-falsify return value + if (veto) { + return localize('lifecycleVeto', "Changes that you made may not be saved. Please check press 'Cancel' and try again."); + } + + // No Veto: continue with Will Shutdown + this._onWillShutdown.fire({ + join() { + console.warn(new Error('Long running onWillShutdown currently not supported')); + }, + reason: ShutdownReason.QUIT + }); + + return null; + } +} \ No newline at end of file diff --git a/src/vs/platform/lifecycle/common/lifecycleService.ts b/src/vs/platform/lifecycle/common/lifecycleService.ts index a82dd63da41..b325cde418a 100644 --- a/src/vs/platform/lifecycle/common/lifecycleService.ts +++ b/src/vs/platform/lifecycle/common/lifecycleService.ts @@ -9,10 +9,11 @@ import { Disposable } from 'vs/base/common/lifecycle'; import { ILifecycleService, BeforeShutdownEvent, WillShutdownEvent, StartupKind, LifecyclePhase, LifecyclePhaseToString } from 'vs/platform/lifecycle/common/lifecycle'; import { ILogService } from 'vs/platform/log/common/log'; import { mark } from 'vs/base/common/performance'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export abstract class AbstractLifecycleService extends Disposable implements ILifecycleService { - _serviceBrand: any; + _serviceBrand: ServiceIdentifier; protected readonly _onBeforeShutdown = this._register(new Emitter()); get onBeforeShutdown(): Event { return this._onBeforeShutdown.event; } diff --git a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts b/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts index aa7f6442e08..ecef5c02772 100644 --- a/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/platform/lifecycle/electron-browser/lifecycleService.ts @@ -4,7 +4,7 @@ *--------------------------------------------------------------------------------------------*/ import { toErrorMessage } from 'vs/base/common/errorMessage'; -import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle'; +import { ShutdownReason, StartupKind, handleVetos, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage'; import { ipcRenderer as ipc } from 'electron'; import { IWindowService } from 'vs/platform/windows/common/windows'; @@ -12,12 +12,13 @@ import { ILogService } from 'vs/platform/log/common/log'; import { INotificationService } from 'vs/platform/notification/common/notification'; import { onUnexpectedError } from 'vs/base/common/errors'; import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; +import { ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation'; export class LifecycleService extends AbstractLifecycleService { private static readonly LAST_SHUTDOWN_REASON_KEY = 'lifecyle.lastShutdownReason'; - _serviceBrand: any; + _serviceBrand: ServiceIdentifier; private shutdownReason: ShutdownReason; diff --git a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts index a56ee98dec6..058efdc2500 100644 --- a/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts +++ b/src/vs/platform/lifecycle/electron-main/lifecycleMain.ts @@ -131,7 +131,7 @@ export const enum LifecycleMainPhase { export class LifecycleService extends Disposable implements ILifecycleService { - _serviceBrand: any; + _serviceBrand: ServiceIdentifier; private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted diff --git a/src/vs/workbench/api/browser/mainThreadWebview.ts b/src/vs/workbench/api/browser/mainThreadWebview.ts index f41c0327ae3..83b6403e4f5 100644 --- a/src/vs/workbench/api/browser/mainThreadWebview.ts +++ b/src/vs/workbench/api/browser/mainThreadWebview.ts @@ -75,7 +75,8 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews })); this._register(lifecycleService.onBeforeShutdown(e => { - e.veto(this._onBeforeShutdown()); + this._onBeforeShutdown(); + e.veto(false); // Don't veto shutdown }, this)); } @@ -217,13 +218,12 @@ export class MainThreadWebviews extends Disposable implements MainThreadWebviews return `mainThreadWebview-${viewType}`; } - private _onBeforeShutdown(): boolean { + private _onBeforeShutdown(): void { this._webviews.forEach((webview) => { if (!webview.isDisposed() && webview.state && this._revivers.has(webview.state.viewType)) { webview.state.state = webview.webviewState; } }); - return false; // Don't veto shutdown } private createWebviewEventDelegate(handle: WebviewPanelHandle) { diff --git a/src/vs/workbench/browser/web.simpleservices.ts b/src/vs/workbench/browser/web.simpleservices.ts index 3654c72f7ae..090913805ad 100644 --- a/src/vs/workbench/browser/web.simpleservices.ts +++ b/src/vs/workbench/browser/web.simpleservices.ts @@ -21,9 +21,8 @@ import { IPager } from 'vs/base/common/paging'; import { IExtensionManifest, ExtensionType, ExtensionIdentifier, IExtension } from 'vs/platform/extensions/common/extensions'; import { IURLHandler, IURLService } from 'vs/platform/url/common/url'; import { ITelemetryService, ITelemetryData, ITelemetryInfo } from 'vs/platform/telemetry/common/telemetry'; -import { AbstractLifecycleService } from 'vs/platform/lifecycle/common/lifecycleService'; -import { ILogService, LogLevel, ConsoleLogService } from 'vs/platform/log/common/log'; -import { ShutdownReason, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { LogLevel, ConsoleLogService } from 'vs/platform/log/common/log'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IProductService } from 'vs/platform/product/common/product'; import { Disposable, IDisposable } from 'vs/base/common/lifecycle'; import { IStorageService, IWorkspaceStorageChangeEvent, StorageScope, IWillSaveStateEvent, WillSaveStateReason } from 'vs/platform/storage/common/storage'; @@ -518,55 +517,6 @@ registerSingleton(IExtensionUrlHandler, SimpleExtensionURLHandler, true); //#endregion -//#region Lifecycle - -export class SimpleLifecycleService extends AbstractLifecycleService { - - _serviceBrand: any; - - constructor( - @ILogService readonly logService: ILogService - ) { - super(logService); - - this.registerListeners(); - } - - private registerListeners(): void { - window.onbeforeunload = () => this.beforeUnload(); - } - - private beforeUnload(): string { - - // Before Shutdown - this._onBeforeShutdown.fire({ - veto(value) { - if (value === true) { - console.warn(new Error('Preventing onBeforeUnload currently not supported')); - } else if (value instanceof Promise) { - console.warn(new Error('Long running onBeforeShutdown currently not supported')); - } - }, - reason: ShutdownReason.QUIT - }); - - // Will Shutdown - this._onWillShutdown.fire({ - join() { - console.warn(new Error('Long running onWillShutdown currently not supported')); - }, - reason: ShutdownReason.QUIT - }); - - // @ts-ignore - return null; - } -} - -registerSingleton(ILifecycleService, SimpleLifecycleService); - -//#endregion - //#region Log export class SimpleLogService extends ConsoleLogService { } diff --git a/src/vs/workbench/services/textfile/browser/textFileService.ts b/src/vs/workbench/services/textfile/browser/textFileService.ts index d15549e21cc..8d653165119 100644 --- a/src/vs/workbench/services/textfile/browser/textFileService.ts +++ b/src/vs/workbench/services/textfile/browser/textFileService.ts @@ -6,6 +6,7 @@ import { TextFileService } from 'vs/workbench/services/textfile/common/textFileService'; import { ITextFileService, IResourceEncodings, IResourceEncoding } from 'vs/workbench/services/textfile/common/textfiles'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; +import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle'; export class BrowserTextFileService extends TextFileService { @@ -14,6 +15,19 @@ export class BrowserTextFileService extends TextFileService { return { encoding: 'utf8', hasBOM: false }; } }; + + protected beforeShutdown(reason: ShutdownReason): boolean | Promise { + const veto = super.beforeShutdown(reason); + + // Web: there is no support for long running unload handlers. As such + // we need to return a direct boolean veto when we detect that there + // are dirty files around. + if (veto instanceof Promise) { + return this.getDirty().length > 0; + } + + return veto; + } } registerSingleton(ITextFileService, BrowserTextFileService); \ No newline at end of file diff --git a/src/vs/workbench/services/textfile/common/textFileService.ts b/src/vs/workbench/services/textfile/common/textFileService.ts index b5e83926419..83e8d940305 100644 --- a/src/vs/workbench/services/textfile/common/textFileService.ts +++ b/src/vs/workbench/services/textfile/common/textFileService.ts @@ -119,7 +119,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer })); } - private beforeShutdown(reason: ShutdownReason): boolean | Promise { + protected beforeShutdown(reason: ShutdownReason): boolean | Promise { // Dirty files need treatment on shutdown const dirty = this.getDirty(); diff --git a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts index d0c60e71c6a..905d2a8b292 100644 --- a/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts +++ b/src/vs/workbench/services/workspace/electron-browser/workspaceEditingService.ts @@ -57,14 +57,16 @@ export class WorkspaceEditingService implements IWorkspaceEditingService { @ILifecycleService readonly lifecycleService: ILifecycleService, @ILabelService readonly labelService: ILabelService ) { + this.registerListeners(); + } - lifecycleService.onBeforeShutdown(async e => { + private registerListeners(): void { + this.lifecycleService.onBeforeShutdown(async e => { const saveOperation = this.saveUntitedBeforeShutdown(e.reason); if (saveOperation) { e.veto(saveOperation); } }); - } private async saveUntitedBeforeShutdown(reason: ShutdownReason): Promise { diff --git a/src/vs/workbench/workbench.web.main.ts b/src/vs/workbench/workbench.web.main.ts index 3b2f85ac6a3..e207ca87c09 100644 --- a/src/vs/workbench/workbench.web.main.ts +++ b/src/vs/workbench/workbench.web.main.ts @@ -68,8 +68,8 @@ import { ContextViewService } from 'vs/platform/contextview/browser/contextViewS // import { ExtensionGalleryService } from 'vs/platform/extensionManagement/node/extensionGalleryService'; // import { IRequestService } from 'vs/platform/request/node/request'; // import { RequestService } from 'vs/platform/request/electron-browser/requestService'; -// import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService'; -// import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; +import { BrowserLifecycleService } from 'vs/platform/lifecycle/browser/lifecycleService'; +import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; // import { ILocalizationsService } from 'vs/platform/localizations/common/localizations'; // import { LocalizationsService } from 'vs/platform/localizations/electron-browser/localizationsService'; // import { ISharedProcessService, SharedProcessService } from 'vs/platform/ipc/electron-browser/sharedProcessService'; @@ -152,7 +152,7 @@ registerSingleton(IAccessibilityService, BrowserAccessibilityService, true); registerSingleton(IContextViewService, ContextViewService, true); // registerSingleton(IExtensionGalleryService, ExtensionGalleryService, true); // registerSingleton(IRequestService, RequestService, true); -// registerSingleton(ILifecycleService, LifecycleService); +registerSingleton(ILifecycleService, BrowserLifecycleService); // registerSingleton(ILocalizationsService, LocalizationsService); // registerSingleton(ISharedProcessService, SharedProcessService, true); // registerSingleton(IProductService, ProductService, true); @@ -238,7 +238,6 @@ import 'vs/workbench/contrib/debug/browser/repl'; import 'vs/workbench/contrib/debug/browser/debugViewlet'; import 'vs/workbench/contrib/debug/browser/debugHelperService'; - // Markers import 'vs/workbench/contrib/markers/browser/markers.contribution'; @@ -288,7 +287,6 @@ import { TaskService } from 'vs/workbench/contrib/tasks/browser/taskService'; import { ITaskService } from 'vs/workbench/contrib/tasks/common/taskService'; registerSingleton(ITaskService, TaskService, true); - // Remote import 'vs/workbench/contrib/remote/common/remote.contribution'; // import 'vs/workbench/contrib/remote/electron-browser/remote.contribution'; -- GitLab