mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-09 17:52:34 -05:00
Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 (#6381)
* Merge from vscode 8e0f348413f4f616c23a88ae30030efa85811973 * disable strict null check
This commit is contained in:
59
src/vs/platform/lifecycle/browser/lifecycleService.ts
Normal file
59
src/vs/platform/lifecycle/browser/lifecycleService.ts
Normal file
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. 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 = 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'));
|
||||
veto = true;
|
||||
}
|
||||
},
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Event } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { isThenable } from 'vs/base/common/async';
|
||||
|
||||
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
|
||||
@@ -29,7 +29,7 @@ export interface BeforeShutdownEvent {
|
||||
/**
|
||||
* The reason why the application will be shutting down.
|
||||
*/
|
||||
reason: ShutdownReason;
|
||||
readonly reason: ShutdownReason;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -51,7 +51,7 @@ export interface WillShutdownEvent {
|
||||
/**
|
||||
* The reason why the application is shutting down.
|
||||
*/
|
||||
reason: ShutdownReason;
|
||||
readonly reason: ShutdownReason;
|
||||
}
|
||||
|
||||
export const enum ShutdownReason {
|
||||
@@ -123,7 +123,7 @@ export function LifecyclePhaseToString(phase: LifecyclePhase) {
|
||||
*/
|
||||
export interface ILifecycleService {
|
||||
|
||||
_serviceBrand: any;
|
||||
_serviceBrand: ServiceIdentifier<any>;
|
||||
|
||||
/**
|
||||
* Value indicates how this window got loaded.
|
||||
@@ -166,12 +166,16 @@ export interface ILifecycleService {
|
||||
}
|
||||
|
||||
export const NullLifecycleService: ILifecycleService = {
|
||||
_serviceBrand: null,
|
||||
|
||||
_serviceBrand: null as any,
|
||||
|
||||
onBeforeShutdown: Event.None,
|
||||
onWillShutdown: Event.None,
|
||||
onShutdown: Event.None,
|
||||
|
||||
phase: LifecyclePhase.Restored,
|
||||
startupKind: StartupKind.NewWindow,
|
||||
|
||||
when() { return Promise.resolve(); }
|
||||
};
|
||||
|
||||
|
||||
@@ -9,19 +9,20 @@ 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; }
|
||||
readonly onBeforeShutdown: Event<BeforeShutdownEvent> = this._onBeforeShutdown.event;
|
||||
|
||||
protected readonly _onWillShutdown = this._register(new Emitter<WillShutdownEvent>());
|
||||
get onWillShutdown(): Event<WillShutdownEvent> { return this._onWillShutdown.event; }
|
||||
readonly onWillShutdown: Event<WillShutdownEvent> = this._onWillShutdown.event;
|
||||
|
||||
protected readonly _onShutdown = this._register(new Emitter<void>());
|
||||
get onShutdown(): Event<void> { return this._onShutdown.event; }
|
||||
readonly onShutdown: Event<void> = this._onShutdown.event;
|
||||
|
||||
protected _startupKind: StartupKind;
|
||||
get startupKind(): StartupKind { return this._startupKind; }
|
||||
|
||||
@@ -4,20 +4,21 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { toErrorMessage } from 'vs/base/common/errorMessage';
|
||||
import { ShutdownReason, StartupKind, handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IStorageService, StorageScope } from 'vs/platform/storage/common/storage';
|
||||
import { ShutdownReason, StartupKind, handleVetos, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { IStorageService, StorageScope, WillSaveStateReason } from 'vs/platform/storage/common/storage';
|
||||
import { ipcRenderer as ipc } from 'electron';
|
||||
import { IWindowService } from 'vs/platform/windows/common/windows';
|
||||
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;
|
||||
|
||||
@@ -89,8 +90,10 @@ export class LifecycleService extends AbstractLifecycleService {
|
||||
});
|
||||
|
||||
// Save shutdown reason to retrieve on next startup
|
||||
this.storageService.onWillSaveState(() => {
|
||||
this.storageService.store(LifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE);
|
||||
this.storageService.onWillSaveState(e => {
|
||||
if (e.reason === WillSaveStateReason.SHUTDOWN) {
|
||||
this.storageService.store(LifecycleService.LAST_SHUTDOWN_REASON_KEY, this.shutdownReason, StorageScope.WORKSPACE);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -7,11 +7,12 @@ import { ipcMain as ipc, app } from 'electron';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IStateService } from 'vs/platform/state/common/state';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { createDecorator, ServiceIdentifier } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ICodeWindow } from 'vs/platform/windows/electron-main/windows';
|
||||
import { handleVetos } from 'vs/platform/lifecycle/common/lifecycle';
|
||||
import { isMacintosh, isWindows } from 'vs/base/common/platform';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { Barrier } from 'vs/base/common/async';
|
||||
|
||||
export const ILifecycleService = createDecorator<ILifecycleService>('lifecycleService');
|
||||
|
||||
@@ -38,42 +39,48 @@ export interface ShutdownEvent {
|
||||
}
|
||||
|
||||
export interface ILifecycleService {
|
||||
_serviceBrand: any;
|
||||
|
||||
_serviceBrand: ServiceIdentifier<ILifecycleService>;
|
||||
|
||||
/**
|
||||
* Will be true if the program was restarted (e.g. due to explicit request or update).
|
||||
*/
|
||||
wasRestarted: boolean;
|
||||
readonly wasRestarted: boolean;
|
||||
|
||||
/**
|
||||
* Will be true if the program was requested to quit.
|
||||
*/
|
||||
quitRequested: boolean;
|
||||
readonly quitRequested: boolean;
|
||||
|
||||
/**
|
||||
* A flag indicating in what phase of the lifecycle we currently are.
|
||||
*/
|
||||
phase: LifecycleMainPhase;
|
||||
|
||||
/**
|
||||
* An event that fires when the application is about to shutdown before any window is closed.
|
||||
* The shutdown can still be prevented by any window that vetos this event.
|
||||
*/
|
||||
onBeforeShutdown: Event<void>;
|
||||
readonly onBeforeShutdown: Event<void>;
|
||||
|
||||
/**
|
||||
* An event that fires after the onBeforeShutdown event has been fired and after no window has
|
||||
* vetoed the shutdown sequence. At this point listeners are ensured that the application will
|
||||
* quit without veto.
|
||||
*/
|
||||
onWillShutdown: Event<ShutdownEvent>;
|
||||
readonly onWillShutdown: Event<ShutdownEvent>;
|
||||
|
||||
/**
|
||||
* An event that fires before a window closes. This event is fired after any veto has been dealt
|
||||
* with so that listeners know for sure that the window will close without veto.
|
||||
*/
|
||||
onBeforeWindowClose: Event<ICodeWindow>;
|
||||
readonly onBeforeWindowClose: Event<ICodeWindow>;
|
||||
|
||||
/**
|
||||
* An event that fires before a window is about to unload. Listeners can veto this event to prevent
|
||||
* the window from unloading.
|
||||
*/
|
||||
onBeforeWindowUnload: Event<IWindowUnloadEvent>;
|
||||
readonly onBeforeWindowUnload: Event<IWindowUnloadEvent>;
|
||||
|
||||
/**
|
||||
* Unload a window for the provided reason. All lifecycle event handlers are triggered.
|
||||
@@ -94,15 +101,41 @@ export interface ILifecycleService {
|
||||
* Forcefully shutdown the application. No livecycle event handlers are triggered.
|
||||
*/
|
||||
kill(code?: number): void;
|
||||
|
||||
/**
|
||||
* Returns a promise that resolves when a certain lifecycle phase
|
||||
* has started.
|
||||
*/
|
||||
when(phase: LifecycleMainPhase): Promise<void>;
|
||||
}
|
||||
|
||||
export const enum LifecycleMainPhase {
|
||||
|
||||
/**
|
||||
* The first phase signals that we are about to startup.
|
||||
*/
|
||||
Starting = 1,
|
||||
|
||||
/**
|
||||
* Services are ready and first window is about to open.
|
||||
*/
|
||||
Ready = 2,
|
||||
|
||||
/**
|
||||
* This phase signals a point in time after the window has opened
|
||||
* and is typically the best place to do work that is not required
|
||||
* for the window to open.
|
||||
*/
|
||||
AfterWindowOpen = 3
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
private windowToCloseRequest: { [windowId: string]: boolean } = Object.create(null);
|
||||
private windowToCloseRequest: Set<number> = new Set();
|
||||
private oneTimeListenerTokenGenerator = 0;
|
||||
private windowCounter = 0;
|
||||
|
||||
@@ -129,6 +162,11 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
private readonly _onBeforeWindowUnload = this._register(new Emitter<IWindowUnloadEvent>());
|
||||
readonly onBeforeWindowUnload: Event<IWindowUnloadEvent> = this._onBeforeWindowUnload.event;
|
||||
|
||||
private _phase: LifecycleMainPhase = LifecycleMainPhase.Starting;
|
||||
get phase(): LifecycleMainPhase { return this._phase; }
|
||||
|
||||
private phaseWhen = new Map<LifecycleMainPhase, Barrier>();
|
||||
|
||||
constructor(
|
||||
@ILogService private readonly logService: ILogService,
|
||||
@IStateService private readonly stateService: IStateService
|
||||
@@ -136,6 +174,7 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
super();
|
||||
|
||||
this.handleRestarted();
|
||||
this.when(LifecycleMainPhase.Ready).then(() => this.registerListeners());
|
||||
}
|
||||
|
||||
private handleRestarted(): void {
|
||||
@@ -146,10 +185,6 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
}
|
||||
}
|
||||
|
||||
ready(): void {
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
private registerListeners(): void {
|
||||
|
||||
// before-quit: an event that is fired if application quit was
|
||||
@@ -238,6 +273,40 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
return this.pendingWillShutdownPromise;
|
||||
}
|
||||
|
||||
set phase(value: LifecycleMainPhase) {
|
||||
if (value < this.phase) {
|
||||
throw new Error('Lifecycle cannot go backwards');
|
||||
}
|
||||
|
||||
if (this._phase === value) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logService.trace(`lifecycle (main): phase changed (value: ${value})`);
|
||||
|
||||
this._phase = value;
|
||||
|
||||
const barrier = this.phaseWhen.get(this._phase);
|
||||
if (barrier) {
|
||||
barrier.open();
|
||||
this.phaseWhen.delete(this._phase);
|
||||
}
|
||||
}
|
||||
|
||||
async when(phase: LifecycleMainPhase): Promise<void> {
|
||||
if (phase <= this._phase) {
|
||||
return;
|
||||
}
|
||||
|
||||
let barrier = this.phaseWhen.get(phase);
|
||||
if (!barrier) {
|
||||
barrier = new Barrier();
|
||||
this.phaseWhen.set(phase, barrier);
|
||||
}
|
||||
|
||||
await barrier.wait();
|
||||
}
|
||||
|
||||
registerWindow(window: ICodeWindow): void {
|
||||
|
||||
// track window count
|
||||
@@ -248,8 +317,8 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
|
||||
// The window already acknowledged to be closed
|
||||
const windowId = window.id;
|
||||
if (this.windowToCloseRequest[windowId]) {
|
||||
delete this.windowToCloseRequest[windowId];
|
||||
if (this.windowToCloseRequest.has(windowId)) {
|
||||
this.windowToCloseRequest.delete(windowId);
|
||||
|
||||
return;
|
||||
}
|
||||
@@ -260,11 +329,11 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
e.preventDefault();
|
||||
this.unload(window, UnloadReason.CLOSE).then(veto => {
|
||||
if (veto) {
|
||||
delete this.windowToCloseRequest[windowId];
|
||||
this.windowToCloseRequest.delete(windowId);
|
||||
return;
|
||||
}
|
||||
|
||||
this.windowToCloseRequest[windowId] = true;
|
||||
this.windowToCloseRequest.add(windowId);
|
||||
|
||||
// Fire onBeforeWindowClose before actually closing
|
||||
this.logService.trace(`Lifecycle#onBeforeWindowClose.fire() - window ID ${windowId}`);
|
||||
@@ -390,10 +459,6 @@ export class LifecycleService extends Disposable implements ILifecycleService {
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* A promise that completes to indicate if the quit request has been veto'd
|
||||
* by the user or not.
|
||||
*/
|
||||
quit(fromUpdate?: boolean): Promise<boolean /* veto */> {
|
||||
if (this.pendingQuitPromise) {
|
||||
return this.pendingQuitPromise;
|
||||
|
||||
Reference in New Issue
Block a user