From 1fd399e12ad5d2765ef23face61e65ffc235f0a7 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 22 Feb 2019 11:29:43 +0100 Subject: [PATCH] debt - move some electron specific listeners --- src/tsconfig.strictNullChecks.json | 2 +- src/vs/workbench/electron-browser/main.ts | 30 ++++----- src/vs/workbench/electron-browser/window.ts | 60 ++++++++++++++++-- .../workbench/electron-browser/workbench.ts | 61 ++----------------- 4 files changed, 77 insertions(+), 76 deletions(-) diff --git a/src/tsconfig.strictNullChecks.json b/src/tsconfig.strictNullChecks.json index afabc6ca0a5..c0951219733 100644 --- a/src/tsconfig.strictNullChecks.json +++ b/src/tsconfig.strictNullChecks.json @@ -311,7 +311,7 @@ "./vs/workbench/contrib/themes/test/electron-browser/themes.test.contribution.ts", "./vs/workbench/contrib/url/common/url.contribution.ts", "./vs/workbench/contrib/webview/electron-browser/webviewProtocols.ts", - "./vs/workbench/electron-browser/window.ts", + // "./vs/workbench/electron-browser/window.ts", TODO@matt https://github.com/Microsoft/vscode/issues/69198 "./vs/workbench/services/activity/common/activity.ts", "./vs/workbench/services/backup/common/backup.ts", "./vs/workbench/services/backup/node/backupFileService.ts", diff --git a/src/vs/workbench/electron-browser/main.ts b/src/vs/workbench/electron-browser/main.ts index 22848a1783e..6cbfd96bffe 100644 --- a/src/vs/workbench/electron-browser/main.ts +++ b/src/vs/workbench/electron-browser/main.ts @@ -4,21 +4,21 @@ *--------------------------------------------------------------------------------------------*/ import * as fs from 'fs'; +import * as gracefulFs from 'graceful-fs'; import { createHash } from 'crypto'; -import * as perf from 'vs/base/common/performance'; +import { importEntries, mark } from 'vs/base/common/performance'; import { Workbench } from 'vs/workbench/electron-browser/workbench'; import { ElectronWindow } from 'vs/workbench/electron-browser/window'; -import * as browser from 'vs/base/browser/browser'; +import { setZoomLevel, setZoomFactor, setFullscreen } from 'vs/base/browser/browser'; import { domContentLoaded, addDisposableListener, EventType, scheduleAtNextAnimationFrame } from 'vs/base/browser/dom'; import { onUnexpectedError } from 'vs/base/common/errors'; -import * as platform from 'vs/base/common/platform'; +import { isLinux, isMacintosh, isWindows } from 'vs/base/common/platform'; import { URI as uri } from 'vs/base/common/uri'; import { WorkspaceService } from 'vs/workbench/services/configuration/node/configurationService'; import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors'; import { ServiceCollection } from 'vs/platform/instantiation/common/serviceCollection'; import { stat } from 'vs/base/node/pfs'; import { EnvironmentService } from 'vs/platform/environment/node/environmentService'; -import * as gracefulFs from 'graceful-fs'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; import { IWindowConfiguration, IWindowsService } from 'vs/platform/windows/common/windows'; import { WindowsChannelClient } from 'vs/platform/windows/node/windowsIpc'; @@ -51,7 +51,7 @@ import { InstantiationService } from 'vs/platform/instantiation/common/instantia import { Disposable } from 'vs/base/common/lifecycle'; import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver'; -export class CodeWindow extends Disposable { +class CodeRendererMain extends Disposable { private workbench: Workbench; @@ -70,12 +70,12 @@ export class CodeWindow extends Disposable { this.reviveUris(); // Setup perf - perf.importEntries(this.configuration.perfEntries); + importEntries(this.configuration.perfEntries); // Browser config - browser.setZoomFactor(webFrame.getZoomFactor()); // Ensure others can listen to zoom level changes - browser.setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */); // Can be trusted because we are not setting it ourselves (https://github.com/Microsoft/vscode/issues/26151) - browser.setFullscreen(!!this.configuration.fullscreen); + setZoomFactor(webFrame.getZoomFactor()); // Ensure others can listen to zoom level changes + setZoomLevel(webFrame.getZoomLevel(), true /* isTrusted */); // Can be trusted because we are not setting it ourselves (https://github.com/Microsoft/vscode/issues/26151) + setFullscreen(!!this.configuration.fullscreen); // Keyboard support KeyboardMapperFactory.INSTANCE._onKeyboardLayoutChanged(); @@ -107,7 +107,7 @@ export class CodeWindow extends Disposable { return this.initServices(electronMainClient).then(services => { return domContentLoaded().then(() => { - perf.mark('willStartWorkbench'); + mark('willStartWorkbench'); const instantiationService = new InstantiationService(services, true); @@ -261,11 +261,11 @@ export class CodeWindow extends Disposable { function computeLocalDiskFolderId(folder: uri, stat: fs.Stats): string { let ctime: number | undefined; - if (platform.isLinux) { + if (isLinux) { ctime = stat.ino; // Linux: birthtime is ctime, so we cannot use it! We use the ino instead! - } else if (platform.isMacintosh) { + } else if (isMacintosh) { ctime = stat.birthtime.getTime(); // macOS: birthtime is fine to use as is - } else if (platform.isWindows) { + } else if (isWindows) { if (typeof stat.birthtimeMs === 'number') { ctime = Math.floor(stat.birthtimeMs); // Windows: fix precision issue in node.js 8.x to get 7.x results (see https://github.com/nodejs/node/issues/19897) } else { @@ -323,7 +323,7 @@ export class CodeWindow extends Disposable { } export function main(configuration: IWindowConfiguration): Promise { - const window = new CodeWindow(configuration); + const renderer = new CodeRendererMain(configuration); - return window.open(); + return renderer.open(); } diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index b53a4c2acb5..e9cb3053da1 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -23,14 +23,13 @@ import * as browser from 'vs/base/browser/browser'; import { ICommandService } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/keybindingService'; -import { Themable } from 'vs/workbench/common/theme'; import { ipcRenderer as ipc, webFrame, crashReporter } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; import { fillInActionBarActions } from 'vs/platform/actions/browser/menuItemActionItem'; import { RunOnceScheduler } from 'vs/base/common/async'; -import { IDisposable, dispose } from 'vs/base/common/lifecycle'; +import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { LifecyclePhase, ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle'; import { IWorkspaceFolderCreationData } from 'vs/platform/workspaces/common/workspaces'; import { IIntegrityService } from 'vs/workbench/services/integrity/common/integrity'; @@ -42,6 +41,7 @@ import { EditorServiceImpl } from 'vs/workbench/browser/parts/editor/editor'; import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding'; import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IAccessibilityService, AccessibilitySupport } from 'vs/platform/accessibility/common/accessibility'; +import { WorkbenchState, IWorkspaceContextService } from 'vs/platform/workspace/common/workspace'; const TextInputActions: IAction[] = [ new Action('undo', nls.localize('undo', "Undo"), undefined, true, () => Promise.resolve(document.execCommand('undo'))), @@ -54,7 +54,9 @@ const TextInputActions: IAction[] = [ new Action('editor.action.selectAll', nls.localize('selectAll', "Select All"), undefined, true, () => Promise.resolve(document.execCommand('selectAll'))) ]; -export class ElectronWindow extends Themable { +export class ElectronWindow extends Disposable { + + private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty'; private touchBarMenu?: IMenu; private touchBarUpdater: RunOnceScheduler; @@ -66,6 +68,8 @@ export class ElectronWindow extends Themable { private addFoldersScheduler: RunOnceScheduler; private pendingFoldersToAdd: URI[]; + private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50)); + constructor( @IEditorService private readonly editorService: EditorServiceImpl, @IWindowsService private readonly windowsService: IWindowsService, @@ -84,9 +88,10 @@ export class ElectronWindow extends Themable { @ILifecycleService private readonly lifecycleService: ILifecycleService, @IIntegrityService private readonly integrityService: IIntegrityService, @IEnvironmentService private readonly environmentService: IEnvironmentService, - @IAccessibilityService private readonly accessibilityService: IAccessibilityService + @IAccessibilityService private readonly accessibilityService: IAccessibilityService, + @IWorkspaceContextService private readonly contextService: IWorkspaceContextService ) { - super(themeService); + super(); this.touchBarDisposables = []; @@ -219,6 +224,51 @@ export class ElectronWindow extends Themable { // Context menu support in input/textarea window.document.addEventListener('contextmenu', e => this.onContextMenu(e)); + + // Listen to visible editor changes + this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange())); + + // Listen to editor closing (if we run with --wait) + const filesToWait = this.windowService.getConfiguration().filesToWait; + if (filesToWait) { + const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri); + const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath); + const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); + + this._register(listenerDispose); + } + } + + private onDidVisibleEditorsChange(): void { + + // Close when empty: check if we should close the window based on the setting + // Overruled by: window has a workspace opened or this window is for extension development + // or setting is disabled. Also enabled when running with --wait from the command line. + const visibleEditors = this.editorService.visibleControls; + if (visibleEditors.length === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) { + const closeWhenEmpty = this.configurationService.getValue(ElectronWindow.closeWhenEmptyConfigurationKey); + if (closeWhenEmpty || this.environmentService.args.wait) { + this.closeEmptyWindowScheduler.schedule(); + } + } + } + + private onAllEditorsClosed(): void { + const visibleEditors = this.editorService.visibleControls.length; + if (visibleEditors === 0) { + this.windowService.closeWindow(); + } + } + + private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void { + + // In wait mode, listen to changes to the editors and wait until the files + // are closed that the user wants to wait for. When this happens we delete + // the wait marker file to signal to the outside that editing is done. + if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { + listenerDispose.dispose(); + this.fileService.del(waitMarkerFile); + } } private onContextMenu(e: MouseEvent): void { diff --git a/src/vs/workbench/electron-browser/workbench.ts b/src/vs/workbench/electron-browser/workbench.ts index 3e0622f6ae9..29e04104f6c 100644 --- a/src/vs/workbench/electron-browser/workbench.ts +++ b/src/vs/workbench/electron-browser/workbench.ts @@ -10,7 +10,7 @@ import { setFileNameComparer } from 'vs/base/common/comparers'; import { IDisposable, dispose, Disposable } from 'vs/base/common/lifecycle'; import { Event, Emitter, setGlobalLeakWarningThreshold } from 'vs/base/common/event'; import { EventType, addDisposableListener, addClasses, addClass, removeClass, isAncestor, getClientArea, position, size, removeClasses } from 'vs/base/browser/dom'; -import { RunOnceScheduler, runWhenIdle, IdleValue } from 'vs/base/common/async'; +import { runWhenIdle, IdleValue } from 'vs/base/common/async'; import { getZoomLevel, onDidChangeFullscreen, isFullscreen, getZoomFactor } from 'vs/base/browser/browser'; import { mark } from 'vs/base/common/performance'; import { onUnexpectedError, setUnexpectedErrorHandler } from 'vs/base/common/errors'; @@ -71,7 +71,6 @@ import { IWorkspaceEditingService } from 'vs/workbench/services/workspace/common import { FileDecorationsService } from 'vs/workbench/services/decorations/browser/decorationsService'; import { IDecorationsService } from 'vs/workbench/services/decorations/browser/decorations'; import { ActivityService } from 'vs/workbench/services/activity/browser/activityService'; -import { URI } from 'vs/base/common/uri'; import { IListService, ListService } from 'vs/platform/list/browser/listService'; import { IViewsService } from 'vs/workbench/common/views'; import { ViewsService } from 'vs/workbench/browser/parts/views/views'; @@ -241,7 +240,6 @@ export class Workbench extends Disposable implements IPartService { private static readonly sidebarPositionConfigurationKey = 'workbench.sideBar.location'; private static readonly statusbarVisibleConfigurationKey = 'workbench.statusBar.visible'; private static readonly activityBarVisibleConfigurationKey = 'workbench.activityBar.visible'; - private static readonly closeWhenEmptyConfigurationKey = 'window.closeWhenEmpty'; private static readonly fontAliasingConfigurationKey = 'workbench.fontAliasing'; _serviceBrand: any; @@ -316,8 +314,6 @@ export class Workbench extends Disposable implements IPartService { private inZenModeContext: IContextKey; private sideBarVisibleContext: IContextKey; - private closeEmptyWindowScheduler: RunOnceScheduler = this._register(new RunOnceScheduler(() => this.onAllEditorsClosed(), 50)); - constructor( private container: HTMLElement, private configuration: IWindowConfiguration, @@ -453,10 +449,7 @@ export class Workbench extends Disposable implements IPartService { this.layout(); // Handle case where workbench is not starting up properly - const timeoutHandle = setTimeout(() => { - this.logService.warn('Workbench did not finish loading in 10 seconds, that might be a problem that should be reported.'); - }, 10000); - + const timeoutHandle = setTimeout(() => 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.Restored).then(() => clearTimeout(timeoutHandle)); // Restore Parts @@ -776,21 +769,9 @@ export class Workbench extends Disposable implements IPartService { // Storage this._register(this.storageService.onWillSaveState(e => this.saveState(e))); - // Listen to visible editor changes - this._register(this.editorService.onDidVisibleEditorsChange(() => this.onDidVisibleEditorsChange())); - - // Listen to editor group activations when editor is hidden - this._register(this.editorPart.onDidActivateGroup(() => { if (this.editorHidden) { this.setEditorHidden(false); } })); - - // Listen to editor closing (if we run with --wait) - const filesToWait = this.configuration.filesToWait; - if (filesToWait) { - const resourcesToWaitFor = filesToWait.paths.map(p => p.fileUri); - const waitMarkerFile = URI.file(filesToWait.waitMarkerFilePath); - const listenerDispose = this.editorService.onDidCloseEditor(() => this.onEditorClosed(listenerDispose, resourcesToWaitFor, waitMarkerFile)); - - this._register(listenerDispose); - } + // Restore editor if hidden and it changes + this._register(this.editorService.onDidVisibleEditorsChange(() => this.restoreHiddenEditor())); + this._register(this.editorPart.onDidActivateGroup(() => this.restoreHiddenEditor())); // Configuration changes this._register(this.configurationService.onDidChangeConfiguration(() => this.onDidUpdateConfiguration())); @@ -837,42 +818,12 @@ export class Workbench extends Disposable implements IPartService { } } - private onEditorClosed(listenerDispose: IDisposable, resourcesToWaitFor: URI[], waitMarkerFile: URI): void { - - // In wait mode, listen to changes to the editors and wait until the files - // are closed that the user wants to wait for. When this happens we delete - // the wait marker file to signal to the outside that editing is done. - if (resourcesToWaitFor.every(resource => !this.editorService.isOpen({ resource }))) { - listenerDispose.dispose(); - this.fileService.del(waitMarkerFile); - } - } - - private onDidVisibleEditorsChange(): void { - const visibleEditors = this.editorService.visibleControls; - - // Close when empty: check if we should close the window based on the setting - // Overruled by: window has a workspace opened or this window is for extension development - // or setting is disabled. Also enabled when running with --wait from the command line. - if (visibleEditors.length === 0 && this.contextService.getWorkbenchState() === WorkbenchState.EMPTY && !this.environmentService.isExtensionDevelopment) { - const closeWhenEmpty = this.configurationService.getValue(Workbench.closeWhenEmptyConfigurationKey); - if (closeWhenEmpty || this.environmentService.args.wait) { - this.closeEmptyWindowScheduler.schedule(); - } - } - + private restoreHiddenEditor(): void { if (this.editorHidden) { this.setEditorHidden(false); } } - private onAllEditorsClosed(): void { - const visibleEditors = this.editorService.visibleControls.length; - if (visibleEditors === 0) { - this.windowService.closeWindow(); - } - } - private onDidUpdateConfiguration(skipLayout?: boolean): void { const newSidebarPositionValue = this.configurationService.getValue(Workbench.sidebarPositionConfigurationKey); const newSidebarPosition = (newSidebarPositionValue === 'right') ? Position.RIGHT : Position.LEFT; -- GitLab