From f8679c1e68ccf89ccaa04d63360affdbbdb34bea Mon Sep 17 00:00:00 2001 From: Martin Aeschlimann Date: Mon, 11 Oct 2021 21:36:37 +0200 Subject: [PATCH] Auto detect color scheme not working after reload window. Fixes #126823 --- src/vs/platform/native/common/native.ts | 2 + .../electron-main/nativeHostMainService.ts | 17 ++++- src/vs/platform/windows/common/windows.ts | 5 +- .../environment/browser/environmentService.ts | 6 +- .../browser/browserHostColorSchemeService.ts | 6 +- .../nativeHostColorSchemeService.ts | 73 +++++++++++++------ .../electron-browser/workbenchTestServices.ts | 3 +- 7 files changed, 73 insertions(+), 39 deletions(-) diff --git a/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts index 2f501280776..d2ffa24556c 100644 --- a/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -108,6 +108,8 @@ export interface ICommonNativeHostService { getOSStatistics(): Promise; getOSVirtualMachineHint(): Promise; + getOSColorScheme(): Promise; + // Process killProcess(pid: number, code: string): Promise; diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index dc2f82e9c91..3b4ca3c8500 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -72,10 +72,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain // Color Scheme changes nativeTheme.on('updated', () => { - this._onDidChangeColorScheme.fire({ - highContrast: nativeTheme.shouldUseInvertedColorScheme || nativeTheme.shouldUseHighContrastColors, - dark: nativeTheme.shouldUseDarkColors - }); + this._onDidChangeColorScheme.fire(this.osColorScheme); }); } @@ -596,6 +593,18 @@ export class NativeHostMainService extends Disposable implements INativeHostMain return virtualMachineHint.value(); } + private get osColorScheme(): IColorScheme { + return { + highContrast: nativeTheme.shouldUseInvertedColorScheme || nativeTheme.shouldUseHighContrastColors, + dark: nativeTheme.shouldUseDarkColors + }; + } + + public async getOSColorScheme(): Promise { + return this.osColorScheme; + } + + //#endregion diff --git a/src/vs/platform/windows/common/windows.ts b/src/vs/platform/windows/common/windows.ts index b53f89e6294..711426f1213 100644 --- a/src/vs/platform/windows/common/windows.ts +++ b/src/vs/platform/windows/common/windows.ts @@ -229,9 +229,6 @@ export interface IColorScheme { export interface IWindowConfiguration { remoteAuthority?: string; - colorScheme: IColorScheme; - autoDetectHighContrast?: boolean; - filesToOpenOrCreate?: IPath[]; filesToDiff?: IPath[]; } @@ -288,6 +285,8 @@ export interface INativeWindowConfiguration extends IWindowConfiguration, Native fullscreen?: boolean; maximized?: boolean; accessibilitySupport?: boolean; + colorScheme: IColorScheme; + autoDetectHighContrast?: boolean; legacyWatcher?: string; // TODO@bpasero remove me once watcher is settled diff --git a/src/vs/workbench/services/environment/browser/environmentService.ts b/src/vs/workbench/services/environment/browser/environmentService.ts index 22952a914e7..ac5b8ac7307 100644 --- a/src/vs/workbench/services/environment/browser/environmentService.ts +++ b/src/vs/workbench/services/environment/browser/environmentService.ts @@ -8,7 +8,7 @@ import { joinPath } from 'vs/base/common/resources'; import { URI } from 'vs/base/common/uri'; import { generateUuid } from 'vs/base/common/uuid'; import { IExtensionHostDebugParams } from 'vs/platform/environment/common/environment'; -import { IColorScheme, IPath, IWindowConfiguration } from 'vs/platform/windows/common/windows'; +import { IPath, IWindowConfiguration } from 'vs/platform/windows/common/windows'; import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import type { IWorkbenchConstructionOptions as IWorkbenchOptions } from 'vs/workbench/workbench.web.api'; import { IProductService } from 'vs/platform/product/common/productService'; @@ -71,10 +71,6 @@ class BrowserWorkbenchConfiguration implements IWindowConfiguration { return undefined; } - - get colorScheme(): IColorScheme { - return { dark: false, highContrast: false }; - } } interface IBrowserWorkbenchOptions extends IWorkbenchOptions { diff --git a/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts b/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts index 7d2fb3dde5c..c49a77efd54 100644 --- a/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts +++ b/src/vs/workbench/services/themes/browser/browserHostColorSchemeService.ts @@ -7,7 +7,6 @@ import { Emitter, Event } from 'vs/base/common/event'; import * as dom from 'vs/base/browser/dom'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; import { Disposable } from 'vs/base/common/lifecycle'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { IHostColorSchemeService } from 'vs/workbench/services/themes/common/hostColorSchemeService'; export class BrowserHostColorSchemeService extends Disposable implements IHostColorSchemeService { @@ -17,7 +16,6 @@ export class BrowserHostColorSchemeService extends Disposable implements IHostCo private readonly _onDidSchemeChangeEvent = this._register(new Emitter()); constructor( - @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService ) { super(); @@ -44,14 +42,14 @@ export class BrowserHostColorSchemeService extends Disposable implements IHostCo } else if (window.matchMedia(`(prefers-color-scheme: dark)`).matches) { return true; } - return this.environmentService.configuration.colorScheme.dark; + return false; } get highContrast(): boolean { if (window.matchMedia(`(forced-colors: active)`).matches) { return true; } - return this.environmentService.configuration.colorScheme.highContrast; + return false; } } diff --git a/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts b/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts index 756b529e92a..4bd56248c81 100644 --- a/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts +++ b/src/vs/workbench/services/themes/electron-sandbox/nativeHostColorSchemeService.ts @@ -6,38 +6,67 @@ import { Emitter } from 'vs/base/common/event'; import { INativeHostService } from 'vs/platform/native/electron-sandbox/native'; import { registerSingleton } from 'vs/platform/instantiation/common/extensions'; -import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService'; import { Disposable } from 'vs/base/common/lifecycle'; import { IHostColorSchemeService } from 'vs/workbench/services/themes/common/hostColorSchemeService'; +import { INativeWorkbenchEnvironmentService } from 'vs/workbench/services/environment/electron-sandbox/environmentService'; +import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storage/common/storage'; +import { isBoolean, isObject } from 'vs/base/common/types'; +import { IColorScheme } from 'vs/platform/windows/common/windows'; export class NativeHostColorSchemeService extends Disposable implements IHostColorSchemeService { + static readonly STORAGE_KEY = 'HostColorSchemeData'; + declare readonly _serviceBrand: undefined; - constructor( - @INativeHostService private readonly nativeHostService: INativeHostService, - @IWorkbenchEnvironmentService private readonly environmentService: IWorkbenchEnvironmentService - ) { - super(); - - this.registerListeners(); - } - - private registerListeners(): void { - - // Color Scheme - this._register(this.nativeHostService.onDidChangeColorScheme(({ highContrast, dark }) => { - this.dark = dark; - this.highContrast = highContrast; - this._onDidChangeColorScheme.fire(); - })); - } - private readonly _onDidChangeColorScheme = this._register(new Emitter()); readonly onDidChangeColorScheme = this._onDidChangeColorScheme.event; - public dark: boolean = this.environmentService.configuration.colorScheme.dark; - public highContrast: boolean = this.environmentService.configuration.colorScheme.highContrast; + public dark: boolean; + public highContrast: boolean; + + constructor( + @INativeHostService private readonly nativeHostService: INativeHostService, + @INativeWorkbenchEnvironmentService environmentService: INativeWorkbenchEnvironmentService, + @IStorageService private storageService: IStorageService + ) { + super(); + + // register listener with the OS + this._register(this.nativeHostService.onDidChangeColorScheme(scheme => this.update(scheme))); + + const initial = this.getStoredValue() ?? environmentService.configuration.colorScheme; + this.dark = initial.dark; + this.highContrast = initial.highContrast; + + // fetch the actual value from the OS + this.nativeHostService.getOSColorScheme().then(scheme => this.update(scheme)); + } + + private getStoredValue(): IColorScheme | undefined { + const stored = this.storageService.get(NativeHostColorSchemeService.STORAGE_KEY, StorageScope.GLOBAL); + if (stored) { + try { + const scheme = JSON.parse(stored); + if (isObject(scheme) && isBoolean(scheme.highContrast) && isBoolean(scheme.dark)) { + return scheme as IColorScheme; + } + } catch (e) { + // ignore + } + } + return undefined; + } + + private update({ highContrast, dark }: IColorScheme) { + if (dark !== this.dark || highContrast !== this.highContrast) { + + this.dark = dark; + this.highContrast = highContrast; + this.storageService.store(NativeHostColorSchemeService.STORAGE_KEY, JSON.stringify({ highContrast, dark }), StorageScope.GLOBAL, StorageTarget.MACHINE); + this._onDidChangeColorScheme.fire(); + } + } } diff --git a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts index cd98feb5507..e6f60f1ea42 100644 --- a/src/vs/workbench/test/electron-browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/electron-browser/workbenchTestServices.ts @@ -23,7 +23,7 @@ import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService import { URI } from 'vs/base/common/uri'; import { IReadTextFileOptions, ITextFileStreamContent, ITextFileService } from 'vs/workbench/services/textfile/common/textfiles'; import { createTextBufferFactoryFromStream } from 'vs/editor/common/model/textModel'; -import { IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IOpenedWindow, IPartsSplash } from 'vs/platform/windows/common/windows'; +import { IOpenEmptyWindowOptions, IWindowOpenable, IOpenWindowOptions, IOpenedWindow, IPartsSplash, IColorScheme } from 'vs/platform/windows/common/windows'; import { parseArgs, OPTIONS } from 'vs/platform/environment/node/argv'; import { LogLevel, ILogService } from 'vs/platform/log/common/log'; import { IPathService } from 'vs/workbench/services/path/common/pathService'; @@ -216,6 +216,7 @@ export class TestNativeHostService implements INativeHostService { async getOSProperties(): Promise { return Object.create(null); } async getOSStatistics(): Promise { return Object.create(null); } async getOSVirtualMachineHint(): Promise { return 0; } + async getOSColorScheme(): Promise { return { dark: true, highContrast: false }; } async killProcess(): Promise { } async setDocumentEdited(edited: boolean): Promise { } async openExternal(url: string): Promise { return false; }