From cade160913db701f9632794e75787b057a1e8ef9 Mon Sep 17 00:00:00 2001 From: seantan22 Date: Tue, 16 Feb 2021 12:21:01 -0500 Subject: [PATCH] Preferences: Support window.zoomLevel Preference Fixes #8751 What it does - Adds support to specify window zoom level as a preference How to test 1. Open `Preferences` view and locate the `window.zoomLevel` preference 2. Enter in a custom value or change the zoom level using ctrl + / - / 0 3. Observe that the zoom level preference is updated 4. Reload the window and observe that the preferred zoom level is preserved Signed-off-by: seantan22 --- .theia/settings.json | 3 +- .../menu/electron-menu-contribution.ts | 35 ++++++++++--- .../window/electron-window-module.ts | 2 + .../window/electron-window-service.ts | 37 ++++++++++++++ .../window/window-preferences.ts | 51 +++++++++++++++++++ .../src/browser/workspace.code-workspace | 7 +++ 6 files changed, 128 insertions(+), 7 deletions(-) create mode 100644 packages/core/src/electron-browser/window/window-preferences.ts create mode 100644 packages/vsx-registry/src/browser/workspace.code-workspace diff --git a/.theia/settings.json b/.theia/settings.json index 23199246981cf..32f85318441b8 100644 --- a/.theia/settings.json +++ b/.theia/settings.json @@ -11,5 +11,6 @@ "editor.tabSize": 2 }, "typescript.tsdk": "node_modules/typescript/lib", - "clang-format.language.typescript.enable": false + "clang-format.language.typescript.enable": false, + "window.zoomLevel": -1 } diff --git a/packages/core/src/electron-browser/menu/electron-menu-contribution.ts b/packages/core/src/electron-browser/menu/electron-menu-contribution.ts index 6a0e01f9c2b8a..a4e9794a11805 100644 --- a/packages/core/src/electron-browser/menu/electron-menu-contribution.ts +++ b/packages/core/src/electron-browser/menu/electron-menu-contribution.ts @@ -20,10 +20,11 @@ import { Command, CommandContribution, CommandRegistry, isOSX, isWindows, MenuModelRegistry, MenuContribution, Disposable } from '../../common'; -import { KeybindingContribution, KeybindingRegistry } from '../../browser'; +import { KeybindingContribution, KeybindingRegistry, PreferenceScope, PreferenceService } from '../../browser'; import { FrontendApplication, FrontendApplicationContribution, CommonMenus } from '../../browser'; import { ElectronMainMenuFactory } from './electron-main-menu-factory'; import { FrontendApplicationStateService, FrontendApplicationState } from '../../browser/frontend-application-state'; +import { WindowPreferences } from '../window/window-preferences'; export namespace ElectronCommands { export const TOGGLE_DEVELOPER_TOOLS: Command = { @@ -65,12 +66,21 @@ export namespace ElectronMenus { export const FILE_CLOSE = [...CommonMenus.FILE_CLOSE, 'window-close']; } +export const MINIMUM_ZOOM_LEVEL = -8; +export const MAXIMUM_ZOOM_LEVEL = 9; + @injectable() export class ElectronMenuContribution implements FrontendApplicationContribution, CommandContribution, MenuContribution, KeybindingContribution { @inject(FrontendApplicationStateService) protected readonly stateService: FrontendApplicationStateService; + @inject(PreferenceService) + protected readonly preferenceService: PreferenceService; + + @inject(WindowPreferences) + protected readonly windowPreferences: WindowPreferences; + constructor( @inject(ElectronMainMenuFactory) protected readonly factory: ElectronMainMenuFactory ) { } @@ -152,19 +162,32 @@ export class ElectronMenuContribution implements FrontendApplicationContribution }); registry.registerCommand(ElectronCommands.ZOOM_IN, { - execute: () => { + execute: async () => { const webContents = currentWindow.webContents; - webContents.setZoomLevel(webContents.zoomLevel + 0.5); + let zoomLevel = webContents.zoomLevel + 0.5; + if (zoomLevel > MAXIMUM_ZOOM_LEVEL) { + zoomLevel = MAXIMUM_ZOOM_LEVEL; + return; + }; + this.preferenceService.set('window.zoomLevel', zoomLevel, PreferenceScope.User); } }); registry.registerCommand(ElectronCommands.ZOOM_OUT, { - execute: () => { + execute: async () => { const webContents = currentWindow.webContents; - webContents.setZoomLevel(webContents.zoomLevel - 0.5); + let zoomLevel = webContents.zoomLevel - 0.5; + if (zoomLevel < MINIMUM_ZOOM_LEVEL) { + zoomLevel = MINIMUM_ZOOM_LEVEL; + return; + }; + this.preferenceService.set('window.zoomLevel', zoomLevel, PreferenceScope.User); } }); registry.registerCommand(ElectronCommands.RESET_ZOOM, { - execute: () => currentWindow.webContents.setZoomLevel(0) + execute: async () => { + const zoomLevel = 0; + this.preferenceService.set('window.zoomLevel', zoomLevel, PreferenceScope.User); + } }); } diff --git a/packages/core/src/electron-browser/window/electron-window-module.ts b/packages/core/src/electron-browser/window/electron-window-module.ts index 31c2dff1a3227..0461e48871233 100644 --- a/packages/core/src/electron-browser/window/electron-window-module.ts +++ b/packages/core/src/electron-browser/window/electron-window-module.ts @@ -22,11 +22,13 @@ import { ElectronClipboardService } from '../electron-clipboard-service'; import { ClipboardService } from '../../browser/clipboard-service'; import { ElectronMainWindowService, electronMainWindowServicePath } from '../../electron-common/electron-main-window-service'; import { ElectronIpcConnectionProvider } from '../messaging/electron-ipc-connection-provider'; +import { bindWindowPreferences } from './window-preferences'; export default new ContainerModule(bind => { bind(ElectronMainWindowService).toDynamicValue(context => ElectronIpcConnectionProvider.createProxy(context.container, electronMainWindowServicePath) ).inSingletonScope(); + bindWindowPreferences(bind); bind(WindowService).to(ElectronWindowService).inSingletonScope(); bind(FrontendApplicationContribution).toService(WindowService); bind(ClipboardService).to(ElectronClipboardService).inSingletonScope(); diff --git a/packages/core/src/electron-browser/window/electron-window-service.ts b/packages/core/src/electron-browser/window/electron-window-service.ts index 75e5f351cb37f..8bc664dde2772 100644 --- a/packages/core/src/electron-browser/window/electron-window-service.ts +++ b/packages/core/src/electron-browser/window/electron-window-service.ts @@ -14,11 +14,14 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ +import * as electron from 'electron'; import { injectable, inject } from 'inversify'; import { remote } from 'electron'; import { NewWindowOptions } from '../../browser/window/window-service'; import { DefaultWindowService } from '../../browser/window/default-window-service'; import { ElectronMainWindowService } from '../../electron-common/electron-main-window-service'; +import { WindowConfiguration, WindowPreferences } from './window-preferences'; +import { PreferenceChangeEvent } from '../../browser'; @injectable() export class ElectronWindowService extends DefaultWindowService { @@ -33,9 +36,17 @@ export class ElectronWindowService extends DefaultWindowService { */ protected closeOnUnload: boolean = false; + /** + * Do not update window zoom level if preference is unchanged. + */ + protected prevPreferredZoomLevel: number | undefined; + @inject(ElectronMainWindowService) protected readonly delegate: ElectronMainWindowService; + @inject(WindowPreferences) + protected readonly windowPreferences: WindowPreferences; + openNewWindow(url: string, { external }: NewWindowOptions = {}): undefined { this.delegate.openNewWindow(url, { external }); return undefined; @@ -67,6 +78,14 @@ export class ElectronWindowService extends DefaultWindowService { return this.preventUnload(event); } }); + + // Update changes to zoom level. + this.updateWindowZoomLevel(); + this.windowPreferences.onPreferenceChanged((e: PreferenceChangeEvent) => { + if (e.preferenceName === 'window.zoomLevel') { + this.updateWindowZoomLevel(); + } + }); } /** @@ -85,4 +104,22 @@ export class ElectronWindowService extends DefaultWindowService { }); return response === 0; // 'Yes', close the window. } + + /** + * Updates the window zoom level based on the amount set in `Preferences`. + */ + protected updateWindowZoomLevel(): void { + const preferredZoomLevel = this.windowPreferences['window.zoomLevel']; + if (this.prevPreferredZoomLevel === preferredZoomLevel) { + return; + } + this.prevPreferredZoomLevel = preferredZoomLevel; + + const currentWindow = electron.remote.getCurrentWindow(); + const webContents = currentWindow.webContents; + + if (webContents.getZoomLevel() !== preferredZoomLevel) { + webContents.setZoomLevel(preferredZoomLevel); + } + } } diff --git a/packages/core/src/electron-browser/window/window-preferences.ts b/packages/core/src/electron-browser/window/window-preferences.ts new file mode 100644 index 0000000000000..e90d3ccebe2fd --- /dev/null +++ b/packages/core/src/electron-browser/window/window-preferences.ts @@ -0,0 +1,51 @@ +/******************************************************************************** + * Copyright (C) 2021 Ericsson and others. + * + * This program and the accompanying materials are made available under the + * terms of the Eclipse Public License v. 2.0 which is available at + * http://www.eclipse.org/legal/epl-2.0. + * + * This Source Code may also be made available under the following Secondary + * Licenses when the conditions for such availability set forth in the Eclipse + * Public License v. 2.0 are satisfied: GNU General Public License, version 2 + * with the GNU Classpath Exception which is available at + * https://www.gnu.org/software/classpath/license.html. + * + * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 + ********************************************************************************/ +import { interfaces } from 'inversify'; +import { createPreferenceProxy, PreferenceContribution, PreferenceProxy, PreferenceSchema, PreferenceService } from '../../browser/preferences'; + +export const windowPreferencesSchema: PreferenceSchema = { + type: 'object', + scope: 'application', + properties: { + 'window.zoomLevel': { + 'type': 'number', + 'default': 0, + 'minimum': -8, + 'maximum': 9, + 'description': 'Adjust the zoom level of the window. The original size is 0. Each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller.' + }, + } +}; + +export class WindowConfiguration { + 'window.zoomLevel': number; +} + +export const WindowPreferences = Symbol('WindowPreferences'); +export type WindowPreferences = PreferenceProxy; + +export function createWindowPreferences(preferences: PreferenceService): WindowPreferences { + return createPreferenceProxy(preferences, windowPreferencesSchema); +} + +export function bindWindowPreferences(bind: interfaces.Bind): void { + bind(WindowPreferences).toDynamicValue(ctx => { + const preferences = ctx.container.get(PreferenceService); + return createWindowPreferences(preferences); + }).inSingletonScope(); + + bind(PreferenceContribution).toConstantValue({ schema: windowPreferencesSchema }); +} diff --git a/packages/vsx-registry/src/browser/workspace.code-workspace b/packages/vsx-registry/src/browser/workspace.code-workspace new file mode 100644 index 0000000000000..e84aa204cb529 --- /dev/null +++ b/packages/vsx-registry/src/browser/workspace.code-workspace @@ -0,0 +1,7 @@ +{ + "folders": [ + { + "path": "..\\..\\..\\.." + } + ] +} \ No newline at end of file