Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweak lifecycle phases #63899

Merged
merged 4 commits into from Nov 28, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/vs/code/electron-main/window.ts
Expand Up @@ -466,7 +466,7 @@ export class CodeWindow extends Disposable implements ICodeWindow {

private registerNavigationListenerOn(command: 'swipe' | 'app-command', back: 'left' | 'browser-backward', forward: 'right' | 'browser-forward', acrossEditors: boolean) {
this._win.on(command as 'swipe' /* | 'app-command' */, (e: Electron.Event, cmd: string) => {
if (this._readyState !== ReadyState.READY) {
if (!this.isReady) {
return; // window must be ready
}

Expand Down
6 changes: 3 additions & 3 deletions src/vs/code/electron-main/windows.ts
Expand Up @@ -216,9 +216,9 @@ export class WindowsManager implements IWindowsMainService {
});
});

// React to workbench loaded events from windows
ipc.on('vscode:workbenchLoaded', (event: any, windowId: number) => {
this.logService.trace('IPC#vscode-workbenchLoaded');
// React to workbench ready events from windows
ipc.on('vscode:workbenchReady', (event: any, windowId: number) => {
this.logService.trace('IPC#vscode-workbenchReady');

const win = this.getWindowById(windowId);
if (win) {
Expand Down
28 changes: 23 additions & 5 deletions src/vs/platform/lifecycle/common/lifecycle.ts
Expand Up @@ -84,17 +84,35 @@ export function StartupKindToString(startupKind: StartupKind): string {
}

export const enum LifecyclePhase {

/**
* The first phase signals that we are about to startup getting ready.
*/
Starting = 1,
Restoring = 2,
Running = 3,

/**
* Services are ready and the view is about to restore its state.
*/
Ready = 2,

/**
* Views, panels and editors have restored. For editors this means, that
* they show their contents fully.
*/
Restored = 3,

/**
* The last phase after views, panels and editors have restored and
* some time has passed (few seconds).
*/
Eventually = 4
}

export function LifecyclePhaseToString(phase: LifecyclePhase) {
switch (phase) {
case LifecyclePhase.Starting: return 'Starting';
case LifecyclePhase.Restoring: return 'Restoring';
case LifecyclePhase.Running: return 'Running';
case LifecyclePhase.Ready: return 'Ready';
case LifecyclePhase.Restored: return 'Restored';
case LifecyclePhase.Eventually: return 'Eventually';
}
}
Expand Down Expand Up @@ -142,7 +160,7 @@ export const NullLifecycleService: ILifecycleService = {
_serviceBrand: null,
onWillShutdown: Event.None,
onShutdown: Event.None,
phase: LifecyclePhase.Running,
phase: LifecyclePhase.Restored,
startupKind: StartupKind.NewWindow,
when() { return Promise.resolve(); }
};
Expand Down
Expand Up @@ -188,7 +188,7 @@ export class ActivitybarPart extends Part {
// The workaround is to promote the element onto its own drawing layer. We do
// this only after the workbench has loaded because otherwise there is ugly flicker.
if (isMacintosh) {
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
scheduleAtNextAnimationFrame(() => { // another delay...
scheduleAtNextAnimationFrame(() => { // ...to prevent more flickering on startup
registerThemingParticipant((theme, collector) => {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/parts/compositePart.ts
Expand Up @@ -221,7 +221,7 @@ export abstract class CompositePart<T extends Composite> extends Part {
// Report progress for slow loading composites (but only if we did not create the composites before already)
const progressService = this.mapProgressServiceToComposite[composite.getId()];
if (progressService && !compositeContainer) {
this.mapProgressServiceToComposite[composite.getId()].showWhile(Promise.resolve(), this.partService.isCreated() ? 800 : 3200 /* less ugly initial startup */);
this.mapProgressServiceToComposite[composite.getId()].showWhile(Promise.resolve(), this.partService.isRestored() ? 800 : 3200 /* less ugly initial startup */);
}

// Fill Content and Actions
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/parts/editor/editorControl.ts
Expand Up @@ -168,7 +168,7 @@ export class EditorControl extends Disposable {

// Show progress while setting input after a certain timeout. If the workbench is opening
// be more relaxed about progress showing by increasing the delay a little bit to reduce flicker.
const operation = this.editorOperation.start(this.partService.isCreated() ? 800 : 3200);
const operation = this.editorOperation.start(this.partService.isRestored() ? 800 : 3200);

// Call into editor control
const editorWillChange = !inputMatches;
Expand Down
Expand Up @@ -82,7 +82,7 @@ export class NotificationsToasts extends Themable {
private registerListeners(): void {

// Wait for the running phase to ensure we can draw notifications properly
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {

// Show toast for initial notifications if any
this.model.notifications.forEach(notification => this.addToast(notification));
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/common/actions.ts
Expand Up @@ -96,7 +96,7 @@ Registry.add(Extensions.WorkbenchActions, new class implements IWorkbenchActionR
private triggerAndDisposeAction(instantiationService: IInstantiationService, lifecycleService: ILifecycleService, descriptor: SyncActionDescriptor, args: any): Thenable<void> {

// run action when workbench is created
return lifecycleService.when(LifecyclePhase.Running).then(() => {
return lifecycleService.when(LifecyclePhase.Ready).then(() => {
const actionInstance = instantiationService.createInstance(descriptor.syncDescriptor);
try {
actionInstance.label = descriptor.label || actionInstance.label;
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/common/contributions.ts
Expand Up @@ -69,7 +69,7 @@ class WorkbenchContributionsRegistry implements IWorkbenchContributionsRegistry
this.instantiationService = instantiationService;
this.lifecycleService = lifecycleService;

[LifecyclePhase.Starting, LifecyclePhase.Restoring, LifecyclePhase.Running, LifecyclePhase.Eventually].forEach(phase => {
[LifecyclePhase.Starting, LifecyclePhase.Ready, LifecyclePhase.Restored, LifecyclePhase.Eventually].forEach(phase => {
this.instantiateByPhase(instantiationService, lifecycleService, phase);
});
}
Expand Down
20 changes: 4 additions & 16 deletions src/vs/workbench/electron-browser/shell.ts
Expand Up @@ -100,7 +100,6 @@ import { ILabelService, LabelService } from 'vs/platform/label/common/label';
import { IDownloadService } from 'vs/platform/download/common/download';
import { DownloadService } from 'vs/platform/download/node/downloadService';
import { DownloadServiceChannel } from 'vs/platform/download/node/downloadIpc';
import { runWhenIdle } from 'vs/base/common/async';
import { TextResourcePropertiesService } from 'vs/workbench/services/textfile/electron-browser/textResourcePropertiesService';
import { MulitExtensionManagementService } from 'vs/platform/extensionManagement/node/multiExtensionManagement';
import { IRemoteAuthorityResolverService } from 'vs/platform/remote/common/remoteAuthorityResolver';
Expand Down Expand Up @@ -189,7 +188,7 @@ export class WorkbenchShell extends Disposable {
this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.');
}, 10000);

this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Restored).then(() => {
clearTimeout(timeoutHandle);
});
}
Expand All @@ -208,30 +207,16 @@ export class WorkbenchShell extends Disposable {
try {
const workbench = instantiationService.createInstance(Workbench, container, this.configuration, serviceCollection, this.lifecycleService, this.mainProcessClient);

// Set lifecycle phase to `Restoring`
this.lifecycleService.phase = LifecyclePhase.Restoring;

// Startup Workbench
workbench.startup().then(startupInfos => {

// Set lifecycle phase to `Runnning`
this.lifecycleService.phase = LifecyclePhase.Running;

// Startup Telemetry
this.logStartupTelemetry(startupInfos);

// Storage Telemetry (TODO@Ben remove me later, including storage errors)
if (!this.environmentService.extensionTestsPath) {
this.logStorageTelemetry();
}

// Set lifecycle phase to `Runnning For A Bit` after a short delay
let eventuallPhaseTimeoutHandle = runWhenIdle(() => {
eventuallPhaseTimeoutHandle = void 0;
this.lifecycleService.phase = LifecyclePhase.Eventually;
}, 5000);

this._register(eventuallPhaseTimeoutHandle);
}, error => handleStartupError(this.logService, error));

return workbench;
Expand Down Expand Up @@ -546,6 +531,9 @@ export class WorkbenchShell extends Disposable {

// Listeners
this.registerListeners();

// Set lifecycle phase to `Ready`
this.lifecycleService.phase = LifecyclePhase.Ready;
}

private registerListeners(): void {
Expand Down
20 changes: 10 additions & 10 deletions src/vs/workbench/electron-browser/window.ts
Expand Up @@ -176,13 +176,13 @@ export class ElectronWindow extends Themable {

// Fullscreen Events
ipc.on('vscode:enterFullScreen', () => {
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
browser.setFullscreen(true);
});
});

ipc.on('vscode:leaveFullScreen', () => {
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
browser.setFullscreen(false);
});
});
Expand All @@ -191,7 +191,7 @@ export class ElectronWindow extends Themable {
ipc.on('vscode:enterHighContrast', () => {
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
if (windowConfig && windowConfig.autoDetectHighContrast) {
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
this.themeService.setColorTheme(VS_HC_THEME, null);
});
}
Expand All @@ -200,7 +200,7 @@ export class ElectronWindow extends Themable {
ipc.on('vscode:leaveHighContrast', () => {
const windowConfig = this.configurationService.getValue<IWindowSettings>('window');
if (windowConfig && windowConfig.autoDetectHighContrast) {
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
this.themeService.restoreColorTheme();
});
}
Expand Down Expand Up @@ -278,16 +278,16 @@ export class ElectronWindow extends Themable {
return null;
};

// Emit event when vscode has loaded
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
ipc.send('vscode:workbenchLoaded', this.windowService.getCurrentWindowId());
// Emit event when vscode is ready
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
ipc.send('vscode:workbenchReady', this.windowService.getCurrentWindowId());
});

// Integrity warning
this.integrityService.isPure().then(res => this.titleService.updateProperties({ isPure: res.isPure }));

// Root warning
this.lifecycleService.when(LifecyclePhase.Running).then(() => {
this.lifecycleService.when(LifecyclePhase.Ready).then(() => {
let isAdminPromise: Promise<boolean>;
if (isWindows) {
isAdminPromise = import('native-is-elevated').then(isElevated => isElevated());
Expand Down Expand Up @@ -374,7 +374,7 @@ export class ElectronWindow extends Themable {
}

private resolveKeybindings(actionIds: string[]): Promise<{ id: string; label: string, isNative: boolean; }[]> {
return Promise.all([this.lifecycleService.when(LifecyclePhase.Running), this.extensionService.whenInstalledExtensionsRegistered()]).then(() => {
return Promise.all([this.lifecycleService.when(LifecyclePhase.Ready), this.extensionService.whenInstalledExtensionsRegistered()]).then(() => {
return arrays.coalesce(actionIds.map(id => {
const binding = this.keybindingService.lookupKeybinding(id);
if (!binding) {
Expand Down Expand Up @@ -454,7 +454,7 @@ export class ElectronWindow extends Themable {
}

private openResources(resources: (IResourceInput | IUntitledResourceInput)[], diffMode: boolean): Thenable<any> {
return this.lifecycleService.when(LifecyclePhase.Running).then(() => {
return this.lifecycleService.when(LifecyclePhase.Restored).then(() => {

// In diffMode we open 2 resources as diff
if (diffMode && resources.length === 2) {
Expand Down
26 changes: 17 additions & 9 deletions src/vs/workbench/electron-browser/workbench.ts
Expand Up @@ -9,7 +9,7 @@ import { localize } from 'vs/nls';
import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle';
import { Event, Emitter, once } from 'vs/base/common/event';
import * as DOM from 'vs/base/browser/dom';
import { RunOnceScheduler } from 'vs/base/common/async';
import { RunOnceScheduler, runWhenIdle } from 'vs/base/common/async';
import * as browser from 'vs/base/browser/browser';
import * as perf from 'vs/base/common/performance';
import * as errors from 'vs/base/common/errors';
Expand Down Expand Up @@ -72,7 +72,7 @@ import { ProgressService2 } from 'vs/workbench/services/progress/browser/progres
import { TextModelResolverService } from 'vs/workbench/services/textmodelResolver/common/textModelResolverService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection';
import { ShutdownReason } from 'vs/platform/lifecycle/common/lifecycle';
import { ShutdownReason, LifecyclePhase } from 'vs/platform/lifecycle/common/lifecycle';
import { LifecycleService } from 'vs/platform/lifecycle/electron-browser/lifecycleService';
import { IWindowService, IWindowConfiguration, IPath, MenuBarVisibility, getTitleBarStyle } from 'vs/platform/windows/common/windows';
import { IStatusbarService } from 'vs/platform/statusbar/common/statusbar';
Expand Down Expand Up @@ -188,7 +188,7 @@ export class Workbench extends Disposable implements IPartService {
private workbenchParams: WorkbenchParams;
private workbench: HTMLElement;
private workbenchStarted: boolean;
private workbenchCreated: boolean;
private workbenchRestored: boolean;
private workbenchShutdown: boolean;

private editorService: EditorService;
Expand Down Expand Up @@ -504,9 +504,6 @@ export class Workbench extends Disposable implements IPartService {
}

private onFullscreenChanged(): void {
if (!this.isCreated) {
return; // we need to be ready
}

// Apply as CSS class
const isFullscreen = browser.isFullscreen();
Expand Down Expand Up @@ -772,7 +769,18 @@ export class Workbench extends Disposable implements IPartService {
}

const onRestored = (error?: Error): IWorkbenchStartedInfo => {
this.workbenchCreated = true;
this.workbenchRestored = true;

// Set lifecycle phase to `Restored`
this.lifecycleService.phase = LifecyclePhase.Restored;

// Set lifecycle phase to `Runnning For A Bit` after a short delay
let eventuallPhaseTimeoutHandle = runWhenIdle(() => {
eventuallPhaseTimeoutHandle = void 0;
this.lifecycleService.phase = LifecyclePhase.Eventually;
}, 5000);

this._register(eventuallPhaseTimeoutHandle);

if (error) {
errors.onUnexpectedError(error);
Expand Down Expand Up @@ -1147,8 +1155,8 @@ export class Workbench extends Disposable implements IPartService {

get onEditorLayout(): Event<IDimension> { return this.editorPart.onDidLayout; }

isCreated(): boolean {
return !!(this.workbenchCreated && this.workbenchStarted);
isRestored(): boolean {
return !!(this.workbenchRestored && this.workbenchStarted);
}

hasFocus(part: Parts): boolean {
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/parts/backup/common/backupRestorer.ts
Expand Up @@ -25,7 +25,7 @@ export class BackupRestorer implements IWorkbenchContribution {
}

private restoreBackups(): void {
this.lifecycleService.when(LifecyclePhase.Running).then(() => this.doRestoreBackups());
this.lifecycleService.when(LifecyclePhase.Restored).then(() => this.doRestoreBackups());
}

private doRestoreBackups(): Thenable<URI[]> {
Expand Down
Expand Up @@ -62,7 +62,7 @@ class MultiCursorModifierContextKeyController implements IWorkbenchContribution
}
}

Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MultiCursorModifierContextKeyController, LifecyclePhase.Running);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(MultiCursorModifierContextKeyController, LifecyclePhase.Restored);


const registry = Registry.as<IWorkbenchActionRegistry>(Extensions.WorkbenchActions);
Expand Down
Expand Up @@ -36,6 +36,6 @@ Registry.as<PanelRegistry>(PanelExtensions.Panels).registerPanel(new PanelDescri
));

// Register view location updater
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(CommentPanelVisibilityUpdater, LifecyclePhase.Restoring);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(CommentPanelVisibilityUpdater, LifecyclePhase.Starting);

registerSingleton(ICommentService, CommentService);
Expand Up @@ -123,8 +123,8 @@ const registry = Registry.as<IWorkbenchActionRegistry>(WorkbenchActionRegistryEx
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugPanelAction, OpenDebugPanelAction.ID, OpenDebugPanelAction.LABEL, openPanelKb), 'View: Debug Console', nls.localize('view', "View"));
registry.registerWorkbenchAction(new SyncActionDescriptor(OpenDebugViewletAction, OpenDebugViewletAction.ID, OpenDebugViewletAction.LABEL, openViewletKb), 'View: Show Debug', nls.localize('view', "View"));

Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager, LifecyclePhase.Running);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolbar, LifecyclePhase.Running);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugEditorModelManager, LifecyclePhase.Restored);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugToolbar, LifecyclePhase.Restored);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(DebugContentProvider, LifecyclePhase.Eventually);
Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench).registerWorkbenchContribution(StatusBarColorProvider, LifecyclePhase.Eventually);

Expand Down
Expand Up @@ -53,10 +53,10 @@ registerSingleton(IExtensionTipsService, ExtensionTipsService);
registerSingleton(IExtensionHostProfileService, ExtensionHostProfileService);

const workbenchRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Running);
workbenchRegistry.registerWorkbenchContribution(StatusUpdater, LifecyclePhase.Restored);
workbenchRegistry.registerWorkbenchContribution(MaliciousExtensionChecker, LifecyclePhase.Eventually);
workbenchRegistry.registerWorkbenchContribution(ConfigureRecommendedExtensionsCommandsContributor, LifecyclePhase.Eventually);
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Running);
workbenchRegistry.registerWorkbenchContribution(KeymapExtensions, LifecyclePhase.Restored);
workbenchRegistry.registerWorkbenchContribution(ExtensionsViewletViewsContribution, LifecyclePhase.Starting);
workbenchRegistry.registerWorkbenchContribution(ExtensionActivationProgress, LifecyclePhase.Eventually);
workbenchRegistry.registerWorkbenchContribution(ExtensionsAutoProfiler, LifecyclePhase.Eventually);
Expand Down
Expand Up @@ -350,8 +350,8 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
return;
}

// Return now if the workbench has not yet been created - in this case the workbench takes care of restoring last used editors
if (!this.partService.isCreated()) {
// Return now if the workbench has not yet been restored - in this case the workbench takes care of restoring last used editors
if (!this.partService.isRestored()) {
return;
}

Expand Down Expand Up @@ -795,7 +795,7 @@ export class ExplorerView extends TreeViewsViewletPanel implements IExplorerView
this.decorationProvider.changed(targetsToResolve.map(t => t.root.resource));
return result;
});
this.progressService.showWhile(promise, this.partService.isCreated() ? 800 : 1200 /* less ugly initial startup */);
this.progressService.showWhile(promise, this.partService.isRestored() ? 800 : 1200 /* less ugly initial startup */);

return promise;
}
Expand Down