diff --git a/src/vs/workbench/browser/layout.ts b/src/vs/workbench/browser/layout.ts index 81fd79a40a4f4b90cfead9a9b6394daead95ae81..70b956eb86214138db185a1495e5d3a9d7304fff 100644 --- a/src/vs/workbench/browser/layout.ts +++ b/src/vs/workbench/browser/layout.ts @@ -95,6 +95,9 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi private readonly _onCenteredLayoutChange: Emitter = this._register(new Emitter()); readonly onCenteredLayoutChange: Event = this._onCenteredLayoutChange.event; + private readonly _onMaximizeChange: Emitter = this._register(new Emitter()); + readonly onMaximizeChange: Event = this._onMaximizeChange.event; + private readonly _onPanelPositionChange: Emitter = this._register(new Emitter()); readonly onPanelPositionChange: Event = this._onPanelPositionChange.event; @@ -142,6 +145,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi protected readonly state = { fullscreen: false, + maximized: false, hasFocus: false, windowBorder: false, @@ -304,6 +308,8 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi // Propagate to grid this.workbenchGrid.setViewVisible(this.titleBarPartView, this.isVisible(Parts.TITLEBAR_PART)); + this.updateWindowBorder(true); + this.layout(); // handle title bar when fullscreen changes } @@ -399,7 +405,7 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi const inactiveBorder = theme.getColor(WINDOW_INACTIVE_BORDER); let windowBorder = false; - if (activeBorder || inactiveBorder) { + if (!this.state.fullscreen && !this.state.maximized && (activeBorder || inactiveBorder)) { windowBorder = true; // If one color is missing, just fallback to the other one @@ -1250,6 +1256,21 @@ export abstract class Layout extends Disposable implements IWorkbenchLayoutServi this._onPanelPositionChange.fire(positionToString(this.state.panel.position)); } + isWindowMaximized() { + return this.state.maximized; + } + + updateWindowMaximizedState(maximized: boolean) { + if (this.state.maximized === maximized) { + return; + } + + this.state.maximized = maximized; + + this.updateWindowBorder(); + this._onMaximizeChange.fire(maximized); + } + private createGridDescriptor(): ISerializedGrid { const workbenchDimensions = this.getClientArea(); const width = this.storageService.getNumber(Storage.GRID_WIDTH, StorageScope.GLOBAL, workbenchDimensions.width); diff --git a/src/vs/workbench/browser/media/style.css b/src/vs/workbench/browser/media/style.css index e458c9af828e84fe578e16c04e821f483e35f7ca..0f6da876c7b1b4ed0317fae277155ad4fd95ddad 100644 --- a/src/vs/workbench/browser/media/style.css +++ b/src/vs/workbench/browser/media/style.css @@ -56,7 +56,7 @@ body.web { width: 100vw; } -.monaco-workbench.border { +.monaco-workbench.border:not(.fullscreen) { box-sizing: border-box; border: 1px solid var(--window-border-color); } diff --git a/src/vs/workbench/browser/part.ts b/src/vs/workbench/browser/part.ts index d5ee8de28874cf90e7860e499491188bb85b4881..1e07ec2345174ced420d4b043848d427c852da83 100644 --- a/src/vs/workbench/browser/part.ts +++ b/src/vs/workbench/browser/part.ts @@ -46,7 +46,7 @@ export abstract class Part extends Component implements ISerializableView { private options: IPartOptions, themeService: IThemeService, storageService: IStorageService, - layoutService: IWorkbenchLayoutService + protected readonly layoutService: IWorkbenchLayoutService ) { super(id, themeService, storageService); diff --git a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts index 5bc062581736f3f28a2886ca22a00f064b62ed57..b4837c8d6388d686b56a9321f67cd8e79345ea33 100644 --- a/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts +++ b/src/vs/workbench/browser/parts/activitybar/activitybarPart.ts @@ -83,7 +83,7 @@ export class ActivitybarPart extends Part implements IActivityBarService { constructor( @IViewletService private readonly viewletService: IViewletService, @IInstantiationService private readonly instantiationService: IInstantiationService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService, @IThemeService themeService: IThemeService, @IStorageService private readonly storageService: IStorageService, @IExtensionService private readonly extensionService: IExtensionService, diff --git a/src/vs/workbench/browser/parts/editor/editorPart.ts b/src/vs/workbench/browser/parts/editor/editorPart.ts index 83b1c0cabe3850b032f50b97ce1b1bc3f71426f8..7cb0562675b10856b27f6c11fd7e1ac38c7c5a91 100644 --- a/src/vs/workbench/browser/parts/editor/editorPart.ts +++ b/src/vs/workbench/browser/parts/editor/editorPart.ts @@ -139,7 +139,7 @@ export class EditorPart extends Part implements IEditorGroupsService, IEditorGro @IThemeService themeService: IThemeService, @IConfigurationService private readonly configurationService: IConfigurationService, @IStorageService storageService: IStorageService, - @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService + @IWorkbenchLayoutService layoutService: IWorkbenchLayoutService ) { super(Parts.EDITOR_PART, { hasTitle: false }, themeService, storageService, layoutService); diff --git a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts index 0e57e5a69082c7efc010c7c05db0cf571e144164..ddf68be9e7381408ca2c8f97c70842c83d407511 100644 --- a/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts +++ b/src/vs/workbench/browser/parts/titlebar/titlebarPart.ts @@ -45,8 +45,6 @@ import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts'; // TODO@sbatten https://github.com/microsoft/vscode/issues/81360 // tslint:disable-next-line: import-patterns layering import { IElectronService } from 'vs/platform/electron/node/electron'; -// tslint:disable-next-line: import-patterns layering -import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; export class TitlebarPart extends Part implements ITitleService { @@ -107,8 +105,7 @@ export class TitlebarPart extends Part implements ITitleService { @IContextKeyService contextKeyService: IContextKeyService, @IHostService private readonly hostService: IHostService, @IProductService private readonly productService: IProductService, - @optional(IElectronService) private electronService: IElectronService, - @optional(IElectronEnvironmentService) private readonly electronEnvironmentService: IElectronEnvironmentService + @optional(IElectronService) private electronService: IElectronService ) { super(Parts.TITLEBAR_PART, { hasTitle: false }, themeService, storageService, layoutService); @@ -448,13 +445,8 @@ export class TitlebarPart extends Part implements ITitleService { // Resizer this.resizer = append(this.element, $('div.resizer')); - const isMaximized = this.environmentService.configuration.maximized ? true : false; - this.onDidChangeMaximized(isMaximized); - - this._register(Event.any( - Event.map(Event.filter(this.electronService.onWindowMaximize, id => id === this.electronEnvironmentService.windowId), _ => true), - Event.map(Event.filter(this.electronService.onWindowUnmaximize, id => id === this.electronEnvironmentService.windowId), _ => false) - )(e => this.onDidChangeMaximized(e))); + this._register(this.layoutService.onMaximizeChange(maximized => this.onDidChangeMaximized(maximized))); + this.onDidChangeMaximized(this.layoutService.isWindowMaximized()); } // Since the title area is used to drag the window, we do not want to steal focus from the diff --git a/src/vs/workbench/electron-browser/window.ts b/src/vs/workbench/electron-browser/window.ts index 1272f66f0a6c605ca8bb4393d1a145a6e6e9f5c9..46a3496a0657451dde34df60456753581babc264 100644 --- a/src/vs/workbench/electron-browser/window.ts +++ b/src/vs/workbench/electron-browser/window.ts @@ -21,7 +21,7 @@ import * as browser from 'vs/base/browser/browser'; import { ICommandService, CommandsRegistry } from 'vs/platform/commands/common/commands'; import { IResourceInput } from 'vs/platform/editor/common/editor'; import { KeyboardMapperFactory } from 'vs/workbench/services/keybinding/electron-browser/nativeKeymapService'; -import { ipcRenderer as ipc, webFrame, crashReporter, Event } from 'electron'; +import { ipcRenderer as ipc, webFrame, crashReporter, Event as IpcEvent } from 'electron'; import { IWorkspaceEditingService } from 'vs/workbench/services/workspaces/common/workspaceEditing'; import { IMenuService, MenuId, IMenu, MenuItemAction, ICommandAction, SubmenuItemAction, MenuRegistry } from 'vs/platform/actions/common/actions'; import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey'; @@ -62,6 +62,7 @@ import { IHostService } from 'vs/workbench/services/host/browser/host'; import { IElectronEnvironmentService } from 'vs/workbench/services/electron/electron-browser/electronEnvironmentService'; import { IWorkingCopyService, WorkingCopyCapabilities } from 'vs/workbench/services/workingCopy/common/workingCopyService'; import { AutoSaveMode, IFilesConfigurationService } from 'vs/workbench/services/filesConfiguration/common/filesConfigurationService'; +import { Event } from 'vs/base/common/event'; export class ElectronWindow extends Disposable { @@ -126,7 +127,7 @@ export class ElectronWindow extends Disposable { }); // Support runAction event - ipc.on('vscode:runAction', async (event: Event, request: IRunActionInWindowRequest) => { + ipc.on('vscode:runAction', async (event: IpcEvent, request: IRunActionInWindowRequest) => { const args: unknown[] = request.args || []; // If we run an action from the touchbar, we fill in the currently active resource @@ -157,27 +158,27 @@ export class ElectronWindow extends Disposable { }); // Support runKeybinding event - ipc.on('vscode:runKeybinding', (event: Event, request: IRunKeybindingInWindowRequest) => { + ipc.on('vscode:runKeybinding', (event: IpcEvent, request: IRunKeybindingInWindowRequest) => { if (document.activeElement) { this.keybindingService.dispatchByUserSettingsLabel(request.userSettingsLabel, document.activeElement); } }); // Error reporting from main - ipc.on('vscode:reportError', (event: Event, error: string) => { + ipc.on('vscode:reportError', (event: IpcEvent, error: string) => { if (error) { errors.onUnexpectedError(JSON.parse(error)); } }); // Support openFiles event for existing and new files - ipc.on('vscode:openFiles', (event: Event, request: IOpenFileRequest) => this.onOpenFiles(request)); + ipc.on('vscode:openFiles', (event: IpcEvent, request: IOpenFileRequest) => this.onOpenFiles(request)); // Support addFolders event if we have a workspace opened - ipc.on('vscode:addFolders', (event: Event, request: IAddFoldersRequest) => this.onAddFoldersRequest(request)); + ipc.on('vscode:addFolders', (event: IpcEvent, request: IAddFoldersRequest) => this.onAddFoldersRequest(request)); // Message support - ipc.on('vscode:showInfoMessage', (event: Event, message: string) => { + ipc.on('vscode:showInfoMessage', (event: IpcEvent, message: string) => { this.notificationService.info(message); }); @@ -215,7 +216,7 @@ export class ElectronWindow extends Disposable { }); // keyboard layout changed event - ipc.on('vscode:accessibilitySupportChanged', (event: Event, accessibilitySupportEnabled: boolean) => { + ipc.on('vscode:accessibilitySupportChanged', (event: IpcEvent, accessibilitySupportEnabled: boolean) => { this.accessibilityService.setAccessibilitySupport(accessibilitySupportEnabled ? AccessibilitySupport.Enabled : AccessibilitySupport.Disabled); }); @@ -281,6 +282,17 @@ export class ElectronWindow extends Disposable { } })); } + + this._register(Event.any( + Event.map(Event.filter(this.electronService.onWindowMaximize, id => id === this.electronEnvironmentService.windowId), () => true), + Event.map(Event.filter(this.electronService.onWindowUnmaximize, id => id === this.electronEnvironmentService.windowId), () => false) + )(e => this.onDidChangeMaximized(e))); + + this.onDidChangeMaximized(this.environmentService.configuration.maximized ?? false); + } + + private onDidChangeMaximized(maximized: boolean): void { + this.layoutService.updateWindowMaximizedState(maximized); } private onDidVisibleEditorsChange(): void { diff --git a/src/vs/workbench/services/layout/browser/layoutService.ts b/src/vs/workbench/services/layout/browser/layoutService.ts index 616d872bf579ac2392b5598b3b3ac8953476b61d..94aa3ef9f55ea0511caf2d8e445afc158fac674c 100644 --- a/src/vs/workbench/services/layout/browser/layoutService.ts +++ b/src/vs/workbench/services/layout/browser/layoutService.ts @@ -41,6 +41,11 @@ export interface IWorkbenchLayoutService extends ILayoutService { */ readonly onFullscreenChange: Event; + /** + * Emits when the window is maximized or unmaximized. + */ + readonly onMaximizeChange: Event; + /** * Emits when centered layout is enabled or disabled. */ @@ -188,4 +193,15 @@ export interface IWorkbenchLayoutService extends ILayoutService { * Register a part to participate in the layout. */ registerPart(part: Part): void; + + + /** + * Returns whether the window is maximized. + */ + isWindowMaximized(): boolean; + + /** + * Updates the maximized state of the window. + */ + updateWindowMaximizedState(maximized: boolean): void; } diff --git a/src/vs/workbench/test/workbenchTestServices.ts b/src/vs/workbench/test/workbenchTestServices.ts index c150c035c6f84e039d7e722f00c72780736b49d8..1e7bd7d147c67de36b875d8a7231e3f7dd1cabf1 100644 --- a/src/vs/workbench/test/workbenchTestServices.ts +++ b/src/vs/workbench/test/workbenchTestServices.ts @@ -463,6 +463,7 @@ export class TestLayoutService implements IWorkbenchLayoutService { onZenModeChange: Event = Event.None; onCenteredLayoutChange: Event = Event.None; onFullscreenChange: Event = Event.None; + onMaximizeChange: Event = Event.None; onPanelPositionChange: Event = Event.None; onPartVisibilityChange: Event = Event.None; onLayout = Event.None; @@ -572,6 +573,12 @@ export class TestLayoutService implements IWorkbenchLayoutService { public resizePart(_part: Parts, _sizeChange: number): void { } public registerPart(part: Part): void { } + + isWindowMaximized() { + return false; + } + + public updateWindowMaximizedState(maximized: boolean): void { } } let activeViewlet: Viewlet = {} as any;