diff --git a/src/vs/platform/lifecycle/common/lifecycle.ts b/src/vs/platform/lifecycle/common/lifecycle.ts index 881196ef1fe..675d8da166f 100644 --- a/src/vs/platform/lifecycle/common/lifecycle.ts +++ b/src/vs/platform/lifecycle/common/lifecycle.ts @@ -32,6 +32,12 @@ export interface ILifecycleService { _serviceBrand: any; + /** + * A flag indicating if the application is in the process of shutting down. This will be true + * before the onWillShutdown event is fired and false if the shutdown is being vetoed. + */ + willShutdown: boolean; + /** * Fired before shutdown happens. Allows listeners to veto against the * shutdown. @@ -47,6 +53,7 @@ export interface ILifecycleService { export const NullLifecycleService: ILifecycleService = { _serviceBrand: null, + willShutdown: false, onWillShutdown: () => ({ dispose() { } }), onShutdown: () => ({ dispose() { } }) }; diff --git a/src/vs/test/utils/servicesTestUtils.ts b/src/vs/test/utils/servicesTestUtils.ts index d0317c15d80..9c4b88924c8 100644 --- a/src/vs/test/utils/servicesTestUtils.ts +++ b/src/vs/test/utils/servicesTestUtils.ts @@ -607,6 +607,8 @@ export class TestLifecycleService implements ILifecycleService { public _serviceBrand: any; + public willShutdown: boolean; + private _onWillShutdown = new Emitter(); private _onShutdown = new Emitter(); diff --git a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts b/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts index 9291a1d4a15..0643c2e34e4 100644 --- a/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts +++ b/src/vs/workbench/parts/files/common/editors/textFileEditorModel.ts @@ -17,6 +17,7 @@ import diagnostics = require('vs/base/common/diagnostics'); import types = require('vs/base/common/types'); import {IModelContentChangedEvent} from 'vs/editor/common/editorCommon'; import {IMode} from 'vs/editor/common/modes'; +import {ILifecycleService} from 'vs/platform/lifecycle/common/lifecycle'; import {ITextFileService, IAutoSaveConfiguration, ModelState, ITextFileEditorModel, ISaveErrorHandler, ISaveParticipant, StateChange} from 'vs/workbench/parts/files/common/files'; import {EncodingMode, EditorModel} from 'vs/workbench/common/editor'; import {BaseTextEditorModel} from 'vs/workbench/common/editor/textEditorModel'; @@ -64,6 +65,7 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil @IModeService modeService: IModeService, @IModelService modelService: IModelService, @IFileService private fileService: IFileService, + @ILifecycleService private lifecycleService: ILifecycleService, @IInstantiationService private instantiationService: IInstantiationService, @ITelemetryService private telemetryService: ITelemetryService, @ITextFileService private textFileService: ITextFileService @@ -441,9 +443,11 @@ export class TextFileEditorModel extends BaseTextEditorModel implements ITextFil // A save participant can still change the model now and since we are so close to saving // we do not want to trigger another auto save or similar, so we block this // In addition we update our version right after in case it changed because of a model change + // We DO NOT run any save participant if we are in the shutdown phase and files are being + // saved as a result of that. let saveParticipantPromise = TPromise.as(versionId); - if (TextFileEditorModel.saveParticipant) { + if (TextFileEditorModel.saveParticipant && !this.lifecycleService.willShutdown) { saveParticipantPromise = TPromise.as(undefined).then(() => { this.blockModelContentChange = true; return TextFileEditorModel.saveParticipant.participate(this, { isAutoSaved }); diff --git a/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts index 68ff9196890..f9902a3bf76 100644 --- a/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts +++ b/src/vs/workbench/services/lifecycle/electron-browser/lifecycleService.ts @@ -20,6 +20,8 @@ export class LifecycleService implements ILifecycleService { private _onWillShutdown = new Emitter(); private _onShutdown = new Emitter(); + private _willShutdown: boolean; + constructor( @IMessageService private messageService: IMessageService, @IWindowService private windowService: IWindowService @@ -27,6 +29,10 @@ export class LifecycleService implements ILifecycleService { this.registerListeners(); } + public get willShutdown(): boolean { + return this._willShutdown; + } + public get onWillShutdown(): Event { return this._onWillShutdown.event; } @@ -40,8 +46,12 @@ export class LifecycleService implements ILifecycleService { // Main side indicates that window is about to unload, check for vetos ipc.on('vscode:beforeUnload', (event, reply: { okChannel: string, cancelChannel: string }) => { + this._willShutdown = true; + + // trigger onWillShutdown events and veto collecting this.onBeforeUnload().done(veto => { if (veto) { + this._willShutdown = false; // reset this flag since the shutdown has been vetoed! ipc.send(reply.cancelChannel, windowId); } else { this._onShutdown.fire();