web - best lifecycle support we can do currently
This commit is contained in:
parent
4118892ac5
commit
998a65e2ca
58
src/vs/platform/lifecycle/browser/lifecycleService.ts
Normal file
58
src/vs/platform/lifecycle/browser/lifecycleService.ts
Normal file
|
@ -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<ILifecycleService>;
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -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<ILifecycleService>;
|
||||
|
||||
protected readonly _onBeforeShutdown = this._register(new Emitter<BeforeShutdownEvent>());
|
||||
get onBeforeShutdown(): Event<BeforeShutdownEvent> { return this._onBeforeShutdown.event; }
|
||||
|
|
|
@ -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<ILifecycleService>;
|
||||
|
||||
private shutdownReason: ShutdownReason;
|
||||
|
||||
|
|
|
@ -131,7 +131,7 @@ export const enum LifecycleMainPhase {
|
|||
|
||||
export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: ServiceIdentifier<ILifecycleService>;
|
||||
|
||||
private static readonly QUIT_FROM_RESTART_MARKER = 'quit.from.restart'; // use a marker to find out if the session was restarted
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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 { }
|
||||
|
|
|
@ -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<boolean> {
|
||||
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);
|
|
@ -119,7 +119,7 @@ export abstract class TextFileService extends Disposable implements ITextFileSer
|
|||
}));
|
||||
}
|
||||
|
||||
private beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
|
||||
protected beforeShutdown(reason: ShutdownReason): boolean | Promise<boolean> {
|
||||
|
||||
// Dirty files need treatment on shutdown
|
||||
const dirty = this.getDirty();
|
||||
|
|
|
@ -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<boolean> {
|
||||
|
|
|
@ -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';
|
||||
|
|
Loading…
Reference in a new issue