From d15635ed32b29de34abb2e8a97a758b8f1bcc202 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 - Allows end-user to specify window zoom level as a preference - Adds support for the addition of other window preferences 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 zoom commands (`ctrl +, ctrl -, ctrl 0`) 3. Observe that the window zoom level changes and the preference is updated in the `settings.json` file 4. Reload the window and observe that the preferred zoom level is restored Signed-off-by: seantan22 --- .../menu/electron-menu-contribution.ts | 25 ++++++-- .../window/electron-window-module.ts | 2 + .../window/electron-window-preferences.ts | 62 +++++++++++++++++++ .../window/electron-window-service.ts | 27 +++++++- 4 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 packages/core/src/electron-browser/window/electron-window-preferences.ts 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..9edde85136911 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 { ZoomLevel } from '../window/electron-window-preferences'; export namespace ElectronCommands { export const TOGGLE_DEVELOPER_TOOLS: Command = { @@ -71,6 +72,9 @@ export class ElectronMenuContribution implements FrontendApplicationContribution @inject(FrontendApplicationStateService) protected readonly stateService: FrontendApplicationStateService; + @inject(PreferenceService) + protected readonly preferenceService: PreferenceService; + constructor( @inject(ElectronMainMenuFactory) protected readonly factory: ElectronMainMenuFactory ) { } @@ -154,17 +158,29 @@ export class ElectronMenuContribution implements FrontendApplicationContribution registry.registerCommand(ElectronCommands.ZOOM_IN, { execute: () => { const webContents = currentWindow.webContents; - webContents.setZoomLevel(webContents.zoomLevel + 0.5); + // When starting at a level that is not a multiple of 0.5, increment by at most 0.5 to reach the next highest multiple of 0.5. + let zoomLevel = (Math.floor(webContents.zoomLevel / ZoomLevel.VARIATION) * ZoomLevel.VARIATION) + ZoomLevel.VARIATION; + if (zoomLevel > ZoomLevel.MAX) { + zoomLevel = ZoomLevel.MAX; + return; + }; + this.preferenceService.set('window.zoomLevel', zoomLevel, PreferenceScope.User); } }); registry.registerCommand(ElectronCommands.ZOOM_OUT, { execute: () => { const webContents = currentWindow.webContents; - webContents.setZoomLevel(webContents.zoomLevel - 0.5); + // When starting at a level that is not a multiple of 0.5, decrement by at most 0.5 to reach the next lowest multiple of 0.5. + let zoomLevel = (Math.ceil(webContents.zoomLevel / ZoomLevel.VARIATION) * ZoomLevel.VARIATION) - ZoomLevel.VARIATION; + if (zoomLevel < ZoomLevel.MIN) { + zoomLevel = ZoomLevel.MIN; + return; + }; + this.preferenceService.set('window.zoomLevel', zoomLevel, PreferenceScope.User); } }); registry.registerCommand(ElectronCommands.RESET_ZOOM, { - execute: () => currentWindow.webContents.setZoomLevel(0) + execute: () => this.preferenceService.set('window.zoomLevel', ZoomLevel.DEFAULT, PreferenceScope.User) }); } @@ -223,5 +239,4 @@ export class ElectronMenuContribution implements FrontendApplicationContribution commandId: ElectronCommands.CLOSE_WINDOW.id, }); } - } 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..750ac9387ee58 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 './electron-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-preferences.ts b/packages/core/src/electron-browser/window/electron-window-preferences.ts new file mode 100644 index 0000000000000..dac99d6bd379b --- /dev/null +++ b/packages/core/src/electron-browser/window/electron-window-preferences.ts @@ -0,0 +1,62 @@ +/******************************************************************************** + * 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 namespace ZoomLevel { + export const DEFAULT = 0; + // copied from https://github.com/microsoft/vscode/blob/dda96b69bfc63f309e60cfc5f98cb863c46b32ac/src/vs/workbench/electron-sandbox/actions/windowActions.ts#L47-L48 + export const MIN = -8; + export const MAX = 9; + // amount to increment or decrement the window zoom level. + export const VARIATION = 0.5; +} + +export const electronWindowPreferencesSchema: PreferenceSchema = { + type: 'object', + properties: { + 'window.zoomLevel': { + 'type': 'number', + 'default': ZoomLevel.DEFAULT, + 'minimum': ZoomLevel.MIN, + 'maximum': ZoomLevel.MAX, + 'scope': 'application', + // eslint-disable-next-line max-len + 'description': 'Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1.0) or below (e.g. -1.0) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity.' + }, + } +}; + +export class ElectronWindowConfiguration { + 'window.zoomLevel': number; +} + +export const ElectronWindowPreferences = Symbol('ElectronWindowPreferences'); +export type ElectronWindowPreferences = PreferenceProxy; + +export function createElectronWindowPreferences(preferences: PreferenceService): ElectronWindowPreferences { + return createPreferenceProxy(preferences, electronWindowPreferencesSchema); +} + +export function bindWindowPreferences(bind: interfaces.Bind): void { + bind(ElectronWindowPreferences).toDynamicValue(ctx => { + const preferences = ctx.container.get(PreferenceService); + return createElectronWindowPreferences(preferences); + }).inSingletonScope(); + + bind(PreferenceContribution).toConstantValue({ schema: electronWindowPreferencesSchema }); +} 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..70da23e8c29b7 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,12 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ -import { injectable, inject } from 'inversify'; +import { injectable, inject, postConstruct } 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 { ElectronWindowPreferences } from './electron-window-preferences'; @injectable() export class ElectronWindowService extends DefaultWindowService { @@ -36,11 +37,24 @@ export class ElectronWindowService extends DefaultWindowService { @inject(ElectronMainWindowService) protected readonly delegate: ElectronMainWindowService; + @inject(ElectronWindowPreferences) + protected readonly electronWindowPreferences: ElectronWindowPreferences; + openNewWindow(url: string, { external }: NewWindowOptions = {}): undefined { this.delegate.openNewWindow(url, { external }); return undefined; } + @postConstruct() + protected init(): void { + // Update the default zoom level on startup when the preferences event is fired. + this.electronWindowPreferences.onPreferenceChanged(e => { + if (e.preferenceName === 'window.zoomLevel') { + this.updateWindowZoomLevel(); + } + }); + } + registerUnloadListeners(): void { window.addEventListener('beforeunload', event => { if (this.isUnloading) { @@ -85,4 +99,15 @@ export class ElectronWindowService extends DefaultWindowService { }); return response === 0; // 'Yes', close the window. } + + /** + * Updates the window zoom level based on the preference value. + */ + protected updateWindowZoomLevel(): void { + const preferredZoomLevel = this.electronWindowPreferences['window.zoomLevel']; + const webContents = remote.getCurrentWindow().webContents; + if (webContents.getZoomLevel() !== preferredZoomLevel) { + webContents.setZoomLevel(preferredZoomLevel); + } + } }