From 5ab8d9b40d6ec21125cd6f74459234c5eb37f049 Mon Sep 17 00:00:00 2001 From: Benjamin Pasero Date: Fri, 24 Nov 2023 11:19:34 +0100 Subject: [PATCH] aux window - introduce common super type for multi-window parts (#199010) --- src/vs/workbench/browser/part.ts | 45 ++++++++++++++++- .../parts/editor/auxiliaryEditorPart.ts | 2 +- .../workbench/browser/parts/editor/editor.ts | 2 +- .../browser/parts/editor/editorParts.ts | 43 +++++----------- .../browser/parts/statusbar/statusbarPart.ts | 49 ++----------------- .../browser/parts/titlebar/titlebarPart.ts | 44 ++--------------- 6 files changed, 67 insertions(+), 118 deletions(-) diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index da15c140e307e..168076b9a6970 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -6,12 +6,13 @@ import 'vs/css!./media/part'; import { Component } from 'vs/workbench/common/component'; import { IThemeService, IColorTheme } from 'vs/platform/theme/common/themeService'; -import { Dimension, size, IDimension } from 'vs/base/browser/dom'; +import { Dimension, size, IDimension, getActiveDocument } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { ISerializableView, IViewSize } from 'vs/base/browser/ui/grid/grid'; import { Event, Emitter } from 'vs/base/common/event'; import { IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { assertIsDefined } from 'vs/base/common/types'; +import { Disposable, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; export interface IPartOptions { readonly hasTitle?: boolean; @@ -181,3 +182,45 @@ class PartLayout { return { titleSize, contentSize }; } } + +export interface IMultiWindowPart { + readonly element: HTMLElement; +} + +export abstract class MultiWindowParts extends Disposable { + + protected readonly _parts = new Set(); + get parts() { return Array.from(this._parts); } + + protected abstract mainPart: T; + + protected registerPart(part: T): IDisposable { + this._parts.add(part); + + return this._register(toDisposable(() => this.unregisterPart(part))); + } + + protected unregisterPart(part: T): void { + this._parts.delete(part); + } + + getPart(container: HTMLElement): T { + return this.getPartByDocument(container.ownerDocument); + } + + protected getPartByDocument(document: Document): T { + if (this._parts.size > 1) { + for (const part of this._parts) { + if (part.element?.ownerDocument === document) { + return part; + } + } + } + + return this.mainPart; + } + + get activePart(): T { + return this.getPartByDocument(getActiveDocument()); + } +} diff --git a/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts b/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts index 220990c5ff4d3..2553a2269af8a 100644 --- a/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts +++ b/src/vs/workbench/browser/parts/editor/auxiliaryEditorPart.ts @@ -90,7 +90,7 @@ export class AuxiliaryEditorPart { auxiliaryWindow.container.appendChild(editorPartContainer); const editorPart = disposables.add(this.instantiationService.createInstance(AuxiliaryEditorPartImpl, auxiliaryWindow.window.vscodeWindowId, this.editorPartsView, label)); - disposables.add(this.editorPartsView.registerEditorPart(editorPart)); + disposables.add(this.editorPartsView.registerPart(editorPart)); editorPart.create(editorPartContainer, { restorePreviousState: false }); // Titlebar diff --git a/src/vs/workbench/browser/parts/editor/editor.ts b/src/vs/workbench/browser/parts/editor/editor.ts index 3721c1ebcdc4f..e3f47d3c4a587 100644 --- a/src/vs/workbench/browser/parts/editor/editor.ts +++ b/src/vs/workbench/browser/parts/editor/editor.ts @@ -176,7 +176,7 @@ function validateEditorPartOptions(options: IEditorPartOptions): IEditorPartOpti export interface IEditorPartsView { readonly mainPart: IEditorGroupsView; - registerEditorPart(part: IEditorPart): IDisposable; + registerPart(part: IEditorPart): IDisposable; readonly activeGroup: IEditorGroupView; readonly groups: IEditorGroupView[]; diff --git a/src/vs/workbench/browser/parts/editor/editorParts.ts b/src/vs/workbench/browser/parts/editor/editorParts.ts index 2a1a9fabee80d..e2810716359b7 100644 --- a/src/vs/workbench/browser/parts/editor/editorParts.ts +++ b/src/vs/workbench/browser/parts/editor/editorParts.ts @@ -6,8 +6,7 @@ import { localize } from 'vs/nls'; import { EditorGroupLayout, GroupDirection, GroupLocation, GroupOrientation, GroupsArrangement, GroupsOrder, IAuxiliaryEditorPart, IAuxiliaryEditorPartCreateEvent, IEditorDropTargetDelegate, IEditorGroupsService, IEditorSideGroup, IFindGroupScope, IMergeGroupOptions } from 'vs/workbench/services/editor/common/editorGroupsService'; import { Emitter } from 'vs/base/common/event'; -import { getActiveDocument } from 'vs/base/browser/dom'; -import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { GroupIdentifier } from 'vs/workbench/common/editor'; import { EditorPart, MainEditorPart } from 'vs/workbench/browser/parts/editor/editorPart'; import { IEditorGroupView, IEditorPartsView } from 'vs/workbench/browser/parts/editor/editor'; @@ -16,8 +15,9 @@ import { IInstantiationService } from 'vs/platform/instantiation/common/instanti import { IAuxiliaryWindowOpenOptions } from 'vs/workbench/services/auxiliaryWindow/browser/auxiliaryWindowService'; import { distinct } from 'vs/base/common/arrays'; import { AuxiliaryEditorPart } from 'vs/workbench/browser/parts/editor/auxiliaryEditorPart'; +import { MultiWindowParts } from 'vs/workbench/browser/part'; -export class EditorParts extends Disposable implements IEditorGroupsService, IEditorPartsView { +export class EditorParts extends MultiWindowParts implements IEditorGroupsService, IEditorPartsView { declare readonly _serviceBrand: undefined; @@ -28,7 +28,7 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd ) { super(); - this._register(this.registerEditorPart(this.mainPart)); + this._register(this.registerPart(this.mainPart)); } protected createMainEditorPart(): MainEditorPart { @@ -56,22 +56,17 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd //#region Registration - private readonly _parts = new Set(); - get parts() { return Array.from(this._parts); } - - registerEditorPart(part: EditorPart): IDisposable { - this._parts.add(part); - + override registerPart(part: EditorPart): IDisposable { const disposables = this._register(new DisposableStore()); - disposables.add(toDisposable(() => this.unregisterEditorPart(part))); + disposables.add(super.registerPart(part)); this.registerEditorPartListeners(part, disposables); return disposables; } - private unregisterEditorPart(part: EditorPart): void { - this._parts.delete(part); + protected override unregisterPart(part: EditorPart): void { + super.unregisterPart(part); // Notify all parts about a groups label change // given it is computed based on the index @@ -111,25 +106,9 @@ export class EditorParts extends Disposable implements IEditorGroupsService, IEd //#region Helpers - get activePart(): EditorPart { - return this.getPartByDocument(getActiveDocument()); - } - - private getPartByDocument(document: Document): EditorPart { - if (this._parts.size > 1) { - for (const part of this._parts) { - if (part.element?.ownerDocument === document) { - return part; - } - } - } - - return this.mainPart; - } - - getPart(group: IEditorGroupView | GroupIdentifier): EditorPart; - getPart(element: HTMLElement): EditorPart; - getPart(groupOrElement: IEditorGroupView | GroupIdentifier | HTMLElement): EditorPart { + override getPart(group: IEditorGroupView | GroupIdentifier): EditorPart; + override getPart(element: HTMLElement): EditorPart; + override getPart(groupOrElement: IEditorGroupView | GroupIdentifier | HTMLElement): EditorPart { if (this._parts.size > 1) { if (groupOrElement instanceof HTMLElement) { const element = groupOrElement; diff --git a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts index 145c2d9687d30..98f233b324ca9 100644 --- a/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts +++ b/src/vs/workbench/browser/parts/statusbar/statusbarPart.ts @@ -6,7 +6,7 @@ import 'vs/css!./media/statusbarpart'; import { localize } from 'vs/nls'; import { Disposable, DisposableStore, dispose, disposeIfDisposable, IDisposable, MutableDisposable, toDisposable } from 'vs/base/common/lifecycle'; -import { Part } from 'vs/workbench/browser/part'; +import { MultiWindowParts, Part } from 'vs/workbench/browser/part'; import { EventType as TouchEventType, Gesture, GestureEvent } from 'vs/base/browser/touch'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { StatusbarAlignment, IStatusbarService, IStatusbarEntry, IStatusbarEntryAccessor, IStatusbarStyleOverride, isStatusbarEntryLocation, IStatusbarEntryLocation, isStatusbarEntryPriority, IStatusbarEntryPriority } from 'vs/workbench/services/statusbar/browser/statusbar'; @@ -16,7 +16,7 @@ import { IThemeService } from 'vs/platform/theme/common/themeService'; import { STATUS_BAR_BACKGROUND, STATUS_BAR_FOREGROUND, STATUS_BAR_NO_FOLDER_BACKGROUND, STATUS_BAR_ITEM_HOVER_BACKGROUND, STATUS_BAR_BORDER, STATUS_BAR_NO_FOLDER_FOREGROUND, STATUS_BAR_NO_FOLDER_BORDER, STATUS_BAR_ITEM_COMPACT_HOVER_BACKGROUND, STATUS_BAR_ITEM_FOCUS_BORDER, STATUS_BAR_FOCUS_BORDER } from 'vs/workbench/common/theme'; import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace'; import { contrastBorder, activeContrastBorder } from 'vs/platform/theme/common/colorRegistry'; -import { EventHelper, createStyleSheet, addDisposableListener, EventType, clearNode, getWindow, getActiveDocument } from 'vs/base/browser/dom'; +import { EventHelper, createStyleSheet, addDisposableListener, EventType, clearNode, getWindow } from 'vs/base/browser/dom'; import { IStorageService } from 'vs/platform/storage/common/storage'; import { Parts, IWorkbenchLayoutService } from 'vs/workbench/services/layout/browser/layoutService'; import { InstantiationType, registerSingleton } from 'vs/platform/instantiation/common/extensions'; @@ -701,7 +701,7 @@ export class AuxiliaryStatusbarPart extends StatusbarPart implements IAuxiliaryS } } -export class StatusbarService extends Disposable implements IStatusbarService { +export class StatusbarService extends MultiWindowParts implements IStatusbarService { declare readonly _serviceBrand: undefined; @@ -712,7 +712,7 @@ export class StatusbarService extends Disposable implements IStatusbarService { ) { super(); - this._register(this.registerStatusbarPart(this.mainPart)); + this._register(this.registerPart(this.mainPart)); } //#region Auxiliary Statusbar Parts @@ -727,7 +727,7 @@ export class StatusbarService extends Disposable implements IStatusbarService { container.appendChild(statusbarPartContainer); const statusbarPart = this.instantiationService.createInstance(AuxiliaryStatusbarPart, statusbarPartContainer); - const disposable = this.registerStatusbarPart(statusbarPart); + const disposable = this.registerPart(statusbarPart); statusbarPart.create(statusbarPartContainer); @@ -742,45 +742,6 @@ export class StatusbarService extends Disposable implements IStatusbarService { //#endregion - //#region Registration - - private readonly parts = new Set(); - - private registerStatusbarPart(part: StatusbarPart): IDisposable { - this.parts.add(part); - - const disposables = this._register(new DisposableStore()); - disposables.add(toDisposable(() => this.parts.delete(part))); - - return disposables; - } - - //#endregion - - //#region Helpers - - getPart(container: HTMLElement): IStatusbarEntryContainer { - return this.getPartByDocument(container.ownerDocument); - } - - private get activePart(): StatusbarPart { - return this.getPartByDocument(getActiveDocument()); - } - - private getPartByDocument(document: Document): StatusbarPart { - if (this.parts.size > 1) { - for (const part of this.parts) { - if (part.element?.ownerDocument === document) { - return part; - } - } - } - - return this.mainPart; - } - - //#endregion - //#region Service Implementation readonly onDidChangeEntryVisibility = this.mainPart.onDidChangeEntryVisibility; diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index c81032fd04fbb..b0f368d830434 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -5,14 +5,14 @@ import 'vs/css!./media/titlebarpart'; import { localize } from 'vs/nls'; -import { Part } from 'vs/workbench/browser/part'; +import { MultiWindowParts, Part } from 'vs/workbench/browser/part'; import { ITitleService } from 'vs/workbench/services/title/browser/titleService'; import { getZoomFactor, isWCOEnabled } from 'vs/base/browser/browser'; import { MenuBarVisibility, getTitleBarStyle, getMenuBarVisibility } from 'vs/platform/window/common/window'; import { IContextMenuService } from 'vs/platform/contextview/browser/contextView'; import { StandardMouseEvent } from 'vs/base/browser/mouseEvent'; import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration'; -import { Disposable, DisposableStore, IDisposable, toDisposable } from 'vs/base/common/lifecycle'; +import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; import { IBrowserWorkbenchEnvironmentService } from 'vs/workbench/services/environment/browser/environmentService'; import { IThemeService } from 'vs/platform/theme/common/themeService'; import { ThemeIcon } from 'vs/base/common/themables'; @@ -74,7 +74,7 @@ export interface ITitlebarPart extends IDisposable { updateProperties(properties: ITitleProperties): void; } -export class BrowserTitleService extends Disposable implements ITitleService { +export class BrowserTitleService extends MultiWindowParts implements ITitleService { declare _serviceBrand: undefined; @@ -85,7 +85,7 @@ export class BrowserTitleService extends Disposable implements ITitleService { ) { super(); - this._register(this.registerTitlebarPart(this.mainPart)); + this._register(this.registerPart(this.mainPart)); } protected createMainTitlebarPart(): BrowserTitlebarPart { @@ -104,7 +104,7 @@ export class BrowserTitleService extends Disposable implements ITitleService { const disposables = new DisposableStore(); const titlebarPart = this.doCreateAuxiliaryTitlebarPart(titlebarPartContainer, editorGroupsContainer); - disposables.add(this.registerTitlebarPart(titlebarPart)); + disposables.add(this.registerPart(titlebarPart)); disposables.add(Event.runAndSubscribe(titlebarPart.onDidChange, () => titlebarPartContainer.style.height = `${titlebarPart.height}px`)); titlebarPart.create(titlebarPartContainer); @@ -120,40 +120,6 @@ export class BrowserTitleService extends Disposable implements ITitleService { //#endregion - //#region Registration - - private readonly parts = new Set(); - - private registerTitlebarPart(part: BrowserTitlebarPart): IDisposable { - this.parts.add(part); - - const disposables = this._register(new DisposableStore()); - disposables.add(toDisposable(() => this.parts.delete(part))); - - return disposables; - } - - //#endregion - - //#region Helpers - - getPart(container: HTMLElement): ITitlebarPart { - return this.getPartByDocument(container.ownerDocument); - } - - private getPartByDocument(document: Document): ITitlebarPart { - if (this.parts.size > 1) { - for (const part of this.parts) { - if (part.element?.ownerDocument === document) { - return part; - } - } - } - - return this.mainPart; - } - - //#endregion //#region Service Implementation