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 1/4] 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`) */ From 954d9371a12e90639030ba394b183855f4346c24 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 29 Jul 2022 11:05:41 -0700 Subject: [PATCH 2/4] Inactive selection in webgl --- addons/xterm-addon-webgl/src/WebglAddon.ts | 5 +++-- addons/xterm-addon-webgl/src/WebglRenderer.ts | 9 +++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index 4ff31ee9..c04cd0d4 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -5,7 +5,7 @@ import { Terminal, ITerminalAddon, IEvent } from 'xterm'; import { WebglRenderer } from './WebglRenderer'; -import { ICharacterJoinerService, IRenderService } from 'browser/services/Services'; +import { ICharacterJoinerService, ICoreBrowserService, IRenderService } from 'browser/services/Services'; import { IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { isSafari } from 'common/Platform'; @@ -31,9 +31,10 @@ export class WebglAddon implements ITerminalAddon { this._terminal = terminal; const renderService: IRenderService = (terminal as any)._core._renderService; const characterJoinerService: ICharacterJoinerService = (terminal as any)._core._characterJoinerService; + const coreBrowserService: ICoreBrowserService = (terminal as any)._core._coreBrowserService; const decorationService: IDecorationService = (terminal as any)._core._decorationService; const colors: IColorSet = (terminal as any)._core._colorManager.colors; - this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, decorationService, this._preserveDrawingBuffer); + this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, coreBrowserService, decorationService, this._preserveDrawingBuffer); this._renderer.onContextLoss(() => this._onContextLoss.fire()); renderService.setRenderer(this._renderer); } diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index 4a57ae91..af1ceef5 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -21,7 +21,7 @@ import { ITerminal, IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { CellData } from 'common/buffer/CellData'; import { addDisposableDomListener } from 'browser/Lifecycle'; -import { ICharacterJoinerService } from 'browser/services/Services'; +import { ICharacterJoinerService, ICoreBrowserService } from 'browser/services/Services'; import { CharData, ICellData } from 'common/Types'; import { AttributeData } from 'common/buffer/AttributeData'; import { IDecorationService } from 'common/services/Services'; @@ -55,6 +55,7 @@ export class WebglRenderer extends Disposable implements IRenderer { private _terminal: Terminal, private _colors: IColorSet, private readonly _characterJoinerService: ICharacterJoinerService, + private readonly _coreBrowserService: ICoreBrowserService, private readonly _decorationService: IDecorationService, preserveDrawingBuffer?: boolean ) { @@ -187,12 +188,16 @@ export class WebglRenderer extends Disposable implements IRenderer { for (const l of this._renderLayers) { l.onBlur(this._terminal); } + // Request a redraw for active/inactive selection background + this._requestRedrawViewport(); } public onFocus(): void { for (const l of this._renderLayers) { l.onFocus(this._terminal); } + // Request a redraw for active/inactive selection background + this._requestRedrawViewport(); } public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { @@ -405,7 +410,7 @@ export class WebglRenderer extends Disposable implements IRenderer { // Apply the selection color if needed if (this._isCellSelected(x, y)) { - bgOverride = this._colors.selectionBackgroundOpaque.rgba >> 8 & 0xFFFFFF; + bgOverride = (this._coreBrowserService.isFocused ? this._colors.selectionBackgroundOpaque : this._colors.selectionInactiveBackgroundOpaque).rgba >> 8 & 0xFFFFFF; if (this._colors.selectionForeground) { fgOverride = this._colors.selectionForeground.rgba >> 8 & 0xFFFFFF; } From 4ac8e4ca51db8008fdeb5d10326629791b0b0a48 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 29 Jul 2022 11:09:19 -0700 Subject: [PATCH 3/4] Remove reliance on core in some webgl parts --- addons/xterm-addon-webgl/src/WebglAddon.ts | 5 ++-- addons/xterm-addon-webgl/src/WebglRenderer.ts | 5 ++-- .../src/renderLayer/CursorRenderLayer.ts | 28 +++++++++---------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index c04cd0d4..02ab942e 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -9,7 +9,7 @@ import { ICharacterJoinerService, ICoreBrowserService, IRenderService } from 'br import { IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { isSafari } from 'common/Platform'; -import { IDecorationService } from 'common/services/Services'; +import { ICoreService, IDecorationService } from 'common/services/Services'; export class WebglAddon implements ITerminalAddon { private _terminal?: Terminal; @@ -32,9 +32,10 @@ export class WebglAddon implements ITerminalAddon { const renderService: IRenderService = (terminal as any)._core._renderService; const characterJoinerService: ICharacterJoinerService = (terminal as any)._core._characterJoinerService; const coreBrowserService: ICoreBrowserService = (terminal as any)._core._coreBrowserService; + const coreService: ICoreService = (terminal as any)._core.coreService; const decorationService: IDecorationService = (terminal as any)._core._decorationService; const colors: IColorSet = (terminal as any)._core._colorManager.colors; - this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, coreBrowserService, decorationService, this._preserveDrawingBuffer); + this._renderer = new WebglRenderer(terminal, colors, characterJoinerService, coreBrowserService, coreService, decorationService, this._preserveDrawingBuffer); this._renderer.onContextLoss(() => this._onContextLoss.fire()); renderService.setRenderer(this._renderer); } diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index af1ceef5..be7517a3 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -24,7 +24,7 @@ import { addDisposableDomListener } from 'browser/Lifecycle'; import { ICharacterJoinerService, ICoreBrowserService } from 'browser/services/Services'; import { CharData, ICellData } from 'common/Types'; import { AttributeData } from 'common/buffer/AttributeData'; -import { IDecorationService } from 'common/services/Services'; +import { ICoreService, IDecorationService } from 'common/services/Services'; export class WebglRenderer extends Disposable implements IRenderer { private _renderLayers: IRenderLayer[]; @@ -56,6 +56,7 @@ export class WebglRenderer extends Disposable implements IRenderer { private _colors: IColorSet, private readonly _characterJoinerService: ICharacterJoinerService, private readonly _coreBrowserService: ICoreBrowserService, + coreService: ICoreService, private readonly _decorationService: IDecorationService, preserveDrawingBuffer?: boolean ) { @@ -65,7 +66,7 @@ export class WebglRenderer extends Disposable implements IRenderer { this._renderLayers = [ new LinkRenderLayer(this._core.screenElement!, 2, this._colors, this._core), - new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._core, this._onRequestRedraw) + new CursorRenderLayer(_terminal, this._core.screenElement!, 3, this._colors, this._onRequestRedraw, this._coreBrowserService, coreService) ]; this.dimensions = { scaledCharWidth: 0, diff --git a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts index fd686cc7..04e2b387 100644 --- a/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts +++ b/addons/xterm-addon-webgl/src/renderLayer/CursorRenderLayer.ts @@ -10,6 +10,8 @@ import { CellData } from 'common/buffer/CellData'; import { IColorSet, ITerminal } from 'browser/Types'; import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types'; import { IEventEmitter } from 'common/EventEmitter'; +import { ICoreBrowserService } from 'browser/services/Services'; +import { ICoreService } from 'common/services/Services'; interface ICursorState { x: number; @@ -35,8 +37,9 @@ export class CursorRenderLayer extends BaseRenderLayer { container: HTMLElement, zIndex: number, colors: IColorSet, - private readonly _terminal: ITerminal, - private _onRequestRefreshRowsEvent: IEventEmitter + private _onRequestRefreshRowsEvent: IEventEmitter, + private readonly _coreBrowserService: ICoreBrowserService, + private readonly _coreService: ICoreService ) { super(container, 'cursor', zIndex, true, colors); this._state = { @@ -91,9 +94,9 @@ export class CursorRenderLayer extends BaseRenderLayer { public onOptionsChanged(terminal: Terminal): void { if (terminal.options.cursorBlink) { if (!this._cursorBlinkStateManager) { - this._cursorBlinkStateManager = new CursorBlinkStateManager(terminal, () => { + this._cursorBlinkStateManager = new CursorBlinkStateManager(() => { this._render(terminal, true); - }); + }, this._coreBrowserService); } } else { this._cursorBlinkStateManager?.dispose(); @@ -118,8 +121,7 @@ export class CursorRenderLayer extends BaseRenderLayer { private _render(terminal: Terminal, triggeredByAnimationFrame: boolean): void { // Don't draw the cursor if it's hidden - // TODO: Need to expose API for this - if (!this._terminal.coreService.isCursorInitialized || this._terminal.coreService.isCursorHidden) { + if (!this._coreService.isCursorInitialized || this._coreService.isCursorHidden) { this._clearCursor(); return; } @@ -142,7 +144,7 @@ export class CursorRenderLayer extends BaseRenderLayer { return; } - if (!isTerminalFocused(terminal)) { + if (!this._coreBrowserService.isFocused) { this._clearCursor(); this._ctx.save(); this._ctx.fillStyle = this._colors.cursor.css; @@ -171,7 +173,7 @@ export class CursorRenderLayer extends BaseRenderLayer { // The cursor is already in the correct spot, don't redraw if (this._state.x === cursorX && this._state.y === viewportRelativeCursorY && - this._state.isFocused === isTerminalFocused(terminal) && + this._state.isFocused === this._coreBrowserService.isFocused && this._state.style === terminal.options.cursorStyle && this._state.width === this._cell.getWidth()) { return; @@ -254,11 +256,11 @@ class CursorBlinkStateManager { private _animationTimeRestarted: number | undefined; constructor( - terminal: Terminal, - private _renderCallback: () => void + private _renderCallback: () => void, + coreBrowserService: ICoreBrowserService ) { this.isCursorVisible = true; - if (isTerminalFocused(terminal)) { + if (coreBrowserService.isFocused) { this._restartInterval(); } } @@ -373,7 +375,3 @@ class CursorBlinkStateManager { this.restartBlinkAnimation(terminal); } } - -function isTerminalFocused(terminal: Terminal): boolean { - return document.activeElement === terminal.textarea && document.hasFocus(); -} From 53e4e9ad72271cd3ff701e4b651c56efdf487cd8 Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Fri, 29 Jul 2022 11:20:32 -0700 Subject: [PATCH 4/4] Inactive selection bg in canvas --- .../xterm-addon-canvas/src/CanvasRenderer.ts | 4 +-- .../src/CursorRenderLayer.ts | 2 +- .../src/SelectionRenderLayer.ts | 28 +++++++++++++++---- src/browser/ColorManager.ts | 4 +++ 4 files changed, 30 insertions(+), 8 deletions(-) diff --git a/addons/xterm-addon-canvas/src/CanvasRenderer.ts b/addons/xterm-addon-canvas/src/CanvasRenderer.ts index c0c332ef..cb30106d 100644 --- a/addons/xterm-addon-canvas/src/CanvasRenderer.ts +++ b/addons/xterm-addon-canvas/src/CanvasRenderer.ts @@ -12,7 +12,7 @@ import { LinkRenderLayer } from './LinkRenderLayer'; import { Disposable } from 'common/Lifecycle'; import { IColorSet, ILinkifier2 } from 'browser/Types'; import { ICharacterJoinerService, ICharSizeService, ICoreBrowserService } from 'browser/services/Services'; -import { IBufferService, IOptionsService, IInstantiationService, IDecorationService, ICoreService } from 'common/services/Services'; +import { IBufferService, IOptionsService, IDecorationService, ICoreService } from 'common/services/Services'; import { removeTerminalFromCache } from './atlas/CharAtlasCache'; import { EventEmitter, IEvent } from 'common/EventEmitter'; import { observeDevicePixelDimensions } from 'browser/renderer/DevicePixelObserver'; @@ -46,7 +46,7 @@ export class CanvasRenderer extends Disposable implements IRenderer { const allowTransparency = this._optionsService.rawOptions.allowTransparency; this._renderLayers = [ new TextRenderLayer(this._screenElement, 0, this._colors, allowTransparency, this._id, this._bufferService, this._optionsService, characterJoinerService, decorationService), - new SelectionRenderLayer(this._screenElement, 1, this._colors, this._id, this._bufferService, this._optionsService, decorationService), + new SelectionRenderLayer(this._screenElement, 1, this._colors, this._id, this._bufferService, coreBrowserService, decorationService, this._optionsService), new LinkRenderLayer(this._screenElement, 2, this._colors, this._id, linkifier2, this._bufferService, this._optionsService, decorationService), new CursorRenderLayer(this._screenElement, 3, this._colors, this._id, this._onRequestRedraw, this._bufferService, this._optionsService, coreService, coreBrowserService, decorationService) ]; diff --git a/addons/xterm-addon-canvas/src/CursorRenderLayer.ts b/addons/xterm-addon-canvas/src/CursorRenderLayer.ts index 4d7e0570..19d414b6 100644 --- a/addons/xterm-addon-canvas/src/CursorRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/CursorRenderLayer.ts @@ -36,7 +36,7 @@ export class CursorRenderLayer extends BaseRenderLayer { zIndex: number, colors: IColorSet, rendererId: number, - private _onRequestRedraw: IEventEmitter, + private readonly _onRequestRedraw: IEventEmitter, bufferService: IBufferService, optionsService: IOptionsService, private readonly _coreService: ICoreService, diff --git a/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts b/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts index 12af5f75..61fc4783 100644 --- a/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts +++ b/addons/xterm-addon-canvas/src/SelectionRenderLayer.ts @@ -3,10 +3,12 @@ * @license MIT */ -import { IRenderDimensions } from 'browser/renderer/Types'; +import { IRenderDimensions, IRequestRedrawEvent } from 'browser/renderer/Types'; import { BaseRenderLayer } from './BaseRenderLayer'; import { IColorSet } from 'browser/Types'; import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services'; +import { ICoreBrowserService } from 'browser/services/Services'; +import { IEventEmitter } from 'common/EventEmitter'; interface ISelectionState { start?: [number, number]; @@ -24,8 +26,9 @@ export class SelectionRenderLayer extends BaseRenderLayer { colors: IColorSet, rendererId: number, bufferService: IBufferService, - optionsService: IOptionsService, - decorationService: IDecorationService + private readonly _coreBrowserService: ICoreBrowserService, + decorationService: IDecorationService, + optionsService: IOptionsService ) { super(container, 'selection', zIndex, true, colors, rendererId, bufferService, optionsService, decorationService); this._clearState(); @@ -45,7 +48,7 @@ export class SelectionRenderLayer extends BaseRenderLayer { // On resize use the base render layer's cached selection values since resize clears _state // inside reset. if (this._selectionStart && this._selectionEnd) { - this.onSelectionChanged(this._selectionStart, this._selectionEnd, this._columnSelectMode); + this._redrawSelection(this._selectionStart, this._selectionEnd, this._columnSelectMode); } } @@ -56,9 +59,22 @@ export class SelectionRenderLayer extends BaseRenderLayer { } } + public onBlur(): void { + this.reset(); + this._redrawSelection(this._selectionStart, this._selectionEnd, this._columnSelectMode); + } + + public onFocus(): void { + this.reset(); + this._redrawSelection(this._selectionStart, this._selectionEnd, this._columnSelectMode); + } + public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { super.onSelectionChanged(start, end, columnSelectMode); + this._redrawSelection(start, end, columnSelectMode); + } + private _redrawSelection(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { // Selection has not changed if (!this._didStateChange(start, end, columnSelectMode, this._bufferService.buffer.ydisp)) { return; @@ -85,7 +101,9 @@ export class SelectionRenderLayer extends BaseRenderLayer { return; } - this._ctx.fillStyle = this._colors.selectionBackgroundTransparent.css; + this._ctx.fillStyle = (this._coreBrowserService.isFocused + ? this._colors.selectionBackgroundTransparent + : this._colors.selectionInactiveBackgroundTransparent).css; if (columnSelectMode) { const startCol = start[0]; diff --git a/src/browser/ColorManager.ts b/src/browser/ColorManager.ts index 13d47700..d8dcde6f 100644 --- a/src/browser/ColorManager.ts +++ b/src/browser/ColorManager.ts @@ -155,6 +155,10 @@ export class ColorManager implements IColorManager { const opacity = 0.3; this.colors.selectionBackgroundTransparent = color.opacity(this.colors.selectionBackgroundTransparent, opacity); } + if (color.isOpaque(this.colors.selectionInactiveBackgroundTransparent)) { + const opacity = 0.3; + this.colors.selectionInactiveBackgroundTransparent = color.opacity(this.colors.selectionInactiveBackgroundTransparent, opacity); + } this.colors.ansi = DEFAULT_ANSI_COLORS.slice(); this.colors.ansi[0] = this._parseColor(theme.black, DEFAULT_ANSI_COLORS[0]); this.colors.ansi[1] = this._parseColor(theme.red, DEFAULT_ANSI_COLORS[1]);