From 6493679b2e4363598dcfb1f6b353b9bf84648b48 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 29 Jul 2022 11:00:36 -0700 Subject: [PATCH] Inactive selection bg in dom renderer Part of #3803 --- addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts | 4 +++- src/browser/ColorManager.ts | 6 +++++- src/browser/TestUtils.test.ts | 7 ++++++- src/browser/Types.d.ts | 4 +++- src/browser/renderer/dom/DomRenderer.ts | 6 +++++- src/browser/renderer/dom/DomRendererRowFactory.test.ts | 3 ++- src/browser/renderer/dom/DomRendererRowFactory.ts | 5 +++-- src/common/services/Services.ts | 3 ++- typings/xterm.d.ts | 2 ++ 9 files changed, 31 insertions(+), 9 deletions(-) diff --git a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts index bfcbc689..86f7e5ab 100644 --- a/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts +++ b/addons/xterm-addon-webgl/src/atlas/CharAtlasUtils.ts @@ -21,9 +21,11 @@ export function generateConfig(scaledCellWidth: number, scaledCellHeight: number background: colors.background, cursor: NULL_COLOR, cursorAccent: NULL_COLOR, + selectionForeground: NULL_COLOR, selectionBackgroundTransparent: NULL_COLOR, selectionBackgroundOpaque: NULL_COLOR, - selectionForeground: NULL_COLOR, + selectionInactiveBackgroundTransparent: NULL_COLOR, + selectionInactiveBackgroundOpaque: NULL_COLOR, // For the static char atlas, we only use the first 16 colors, but we need all 256 for the // dynamic character atlas. ansi: colors.ansi.slice(), diff --git a/src/browser/ColorManager.ts b/src/browser/ColorManager.ts index 92a3c6b5..13d47700 100644 --- a/src/browser/ColorManager.ts +++ b/src/browser/ColorManager.ts @@ -102,9 +102,11 @@ export class ColorManager implements IColorManager { background: DEFAULT_BACKGROUND, cursor: DEFAULT_CURSOR, cursorAccent: DEFAULT_CURSOR_ACCENT, + selectionForeground: undefined, selectionBackgroundTransparent: DEFAULT_SELECTION, selectionBackgroundOpaque: color.blend(DEFAULT_BACKGROUND, DEFAULT_SELECTION), - selectionForeground: undefined, + selectionInactiveBackgroundTransparent: DEFAULT_SELECTION, + selectionInactiveBackgroundOpaque: color.blend(DEFAULT_BACKGROUND, DEFAULT_SELECTION), ansi: DEFAULT_ANSI_COLORS.slice(), contrastCache: this._contrastCache }; @@ -134,6 +136,8 @@ export class ColorManager implements IColorManager { this.colors.cursorAccent = this._parseColor(theme.cursorAccent, DEFAULT_CURSOR_ACCENT, true); this.colors.selectionBackgroundTransparent = this._parseColor(theme.selectionBackground, DEFAULT_SELECTION, true); this.colors.selectionBackgroundOpaque = color.blend(this.colors.background, this.colors.selectionBackgroundTransparent); + this.colors.selectionInactiveBackgroundTransparent = this._parseColor(theme.selectionInactiveBackground, this.colors.selectionBackgroundTransparent, true); + this.colors.selectionInactiveBackgroundOpaque = color.blend(this.colors.background, this.colors.selectionInactiveBackgroundTransparent); const nullColor: IColor = { css: '', rgba: 0 diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts index 7c509160..e09097a2 100644 --- a/src/browser/TestUtils.test.ts +++ b/src/browser/TestUtils.test.ts @@ -5,7 +5,7 @@ import { IDisposable, IMarker, ILinkProvider, IDecorationOptions, IDecoration } from 'xterm'; import { IEvent, EventEmitter } from 'common/EventEmitter'; -import { ICharacterJoinerService, ICharSizeService, IMouseService, IRenderService, ISelectionService } from 'browser/services/Services'; +import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService, IMouseService, IRenderService, ISelectionService } from 'browser/services/Services'; import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/renderer/Types'; import { IColorSet, ITerminal, ILinkifier2, IBrowser, IViewport, IColorManager, ICompositionHelper, CharacterJoinerHandler, IRenderDebouncer, IBufferRange } from 'browser/Types'; import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; @@ -340,6 +340,11 @@ export class MockCompositionHelper implements ICompositionHelper { } } +export class MockCoreBrowserService implements ICoreBrowserService { + public serviceBrand: undefined; + public isFocused: boolean = true; +} + export class MockCharSizeService implements ICharSizeService { public serviceBrand: undefined; public get hasValidSize(): boolean { return this.width > 0 && this.height > 0; } diff --git a/src/browser/Types.d.ts b/src/browser/Types.d.ts index 1eb1d1b7..a3c27a88 100644 --- a/src/browser/Types.d.ts +++ b/src/browser/Types.d.ts @@ -115,10 +115,12 @@ export interface IColorSet { background: IColor; cursor: IColor; cursorAccent: IColor; + selectionForeground: IColor | undefined; selectionBackgroundTransparent: IColor; /** The selection blended on top of background. */ selectionBackgroundOpaque: IColor; - selectionForeground: IColor | undefined; + selectionInactiveBackgroundTransparent: IColor; + selectionInactiveBackgroundOpaque: IColor; ansi: IColor[]; contrastCache: IColorContrastCache; } diff --git a/src/browser/renderer/dom/DomRenderer.ts b/src/browser/renderer/dom/DomRenderer.ts index b800a73b..050f9396 100644 --- a/src/browser/renderer/dom/DomRenderer.ts +++ b/src/browser/renderer/dom/DomRenderer.ts @@ -220,9 +220,13 @@ export class DomRenderer extends Disposable implements IRenderer { ` z-index: 1;` + ` pointer-events: none;` + `}` + - `${this._terminalSelector} .${SELECTION_CLASS} div {` + + `${this._terminalSelector}.focus .${SELECTION_CLASS} div {` + ` position: absolute;` + ` background-color: ${this._colors.selectionBackgroundOpaque.css};` + + `}` + + `${this._terminalSelector} .${SELECTION_CLASS} div {` + + ` position: absolute;` + + ` background-color: ${this._colors.selectionInactiveBackgroundOpaque.css};` + `}`; // Colors this._colors.ansi.forEach((c, i) => { diff --git a/src/browser/renderer/dom/DomRendererRowFactory.test.ts b/src/browser/renderer/dom/DomRendererRowFactory.test.ts index db5d258e..55a7b776 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.test.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.test.ts @@ -12,7 +12,7 @@ import { IBufferLine } from 'common/Types'; import { CellData } from 'common/buffer/CellData'; import { MockCoreService, MockDecorationService, MockOptionsService } from 'common/TestUtils.test'; import { css } from 'common/Color'; -import { MockCharacterJoinerService } from 'browser/TestUtils.test'; +import { MockCharacterJoinerService, MockCoreBrowserService } from 'browser/TestUtils.test'; describe('DomRendererRowFactory', () => { let dom: jsdom.JSDOM; @@ -49,6 +49,7 @@ describe('DomRendererRowFactory', () => { } as any, new MockCharacterJoinerService(), new MockOptionsService({ drawBoldTextInBrightColors: true }), + new MockCoreBrowserService(), new MockCoreService(), new MockDecorationService() ); diff --git a/src/browser/renderer/dom/DomRendererRowFactory.ts b/src/browser/renderer/dom/DomRendererRowFactory.ts index 33e92c0b..47f269ce 100644 --- a/src/browser/renderer/dom/DomRendererRowFactory.ts +++ b/src/browser/renderer/dom/DomRendererRowFactory.ts @@ -10,7 +10,7 @@ import { CellData } from 'common/buffer/CellData'; import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services'; import { color, rgba } from 'common/Color'; import { IColorSet } from 'browser/Types'; -import { ICharacterJoinerService } from 'browser/services/Services'; +import { ICharacterJoinerService, ICoreBrowserService } from 'browser/services/Services'; import { JoinedCellData } from 'browser/services/CharacterJoinerService'; import { excludeFromContrastRatioDemands } from 'browser/renderer/RendererUtils'; @@ -37,6 +37,7 @@ export class DomRendererRowFactory { private _colors: IColorSet, @ICharacterJoinerService private readonly _characterJoinerService: ICharacterJoinerService, @IOptionsService private readonly _optionsService: IOptionsService, + @ICoreBrowserService private readonly _coreBrowserService: ICoreBrowserService, @ICoreService private readonly _coreService: ICoreService, @IDecorationService private readonly _decorationService: IDecorationService ) { @@ -218,7 +219,7 @@ export class DomRendererRowFactory { // If in the selection, force the element to be above the selection to improve contrast and // support opaque selections if (isInSelection) { - bgOverride = this._colors.selectionBackgroundOpaque; + bgOverride = this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque; isTop = true; } diff --git a/src/common/services/Services.ts b/src/common/services/Services.ts index 7fa13fe7..585b29ac 100644 --- a/src/common/services/Services.ts +++ b/src/common/services/Services.ts @@ -250,8 +250,9 @@ export interface ITheme { background?: string; cursor?: string; cursorAccent?: string; - selectionBackground?: string; selectionForeground?: string; + selectionBackground?: string; + selectionInactiveBackground?: string; black?: string; red?: string; green?: string; diff --git a/typings/xterm.d.ts b/typings/xterm.d.ts index 1a1ef905..5b4a198e 100644 --- a/typings/xterm.d.ts +++ b/typings/xterm.d.ts @@ -270,6 +270,8 @@ declare module 'xterm' { selectionBackground?: string; /** The selection foreground color */ selectionForeground?: string; + /** The selection background color when the terminal does not have focus (can be transparent) */ + selectionInactiveBackground?: string; /** ANSI black (eg. `\x1b[30m`) */ black?: string; /** ANSI red (eg. `\x1b[31m`) */