From 9ad01080f326753e0cdf8bd920447d72f8a187a1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jun 2019 19:24:48 -0700 Subject: [PATCH 1/5] Introduce RenderService Used to be RenderCoordinator --- src/AccessibilityManager.ts | 2 +- src/MouseHelper.ts | 4 +- src/Terminal.ts | 10 ++-- src/TestUtils.test.ts | 4 +- src/Types.ts | 2 - src/Viewport.ts | 2 +- src/browser/ColorManager.ts | 3 +- src/browser/Types.ts | 24 ---------- src/browser/renderer/Types.ts | 47 +++++++++++++++++++ src/browser/services/Services.d.ts | 27 +++++++++++ src/renderer/BaseRenderLayer.ts | 3 +- src/renderer/CursorRenderLayer.ts | 2 +- src/renderer/LinkRenderLayer.ts | 2 +- ...{RenderCoordinator.ts => RenderService.ts} | 5 +- src/renderer/Renderer.ts | 5 +- src/renderer/SelectionRenderLayer.ts | 2 +- src/renderer/TextRenderLayer.ts | 3 +- src/renderer/Types.ts | 41 +--------------- src/renderer/dom/DomRenderer.ts | 4 +- 19 files changed, 103 insertions(+), 89 deletions(-) create mode 100644 src/browser/renderer/Types.ts rename src/renderer/{RenderCoordinator.ts => RenderService.ts} (97%) diff --git a/src/AccessibilityManager.ts b/src/AccessibilityManager.ts index 6d47a75f..884db050 100644 --- a/src/AccessibilityManager.ts +++ b/src/AccessibilityManager.ts @@ -11,7 +11,7 @@ import { RenderDebouncer } from 'browser/RenderDebouncer'; import { addDisposableDomListener } from 'browser/Lifecycle'; import { Disposable } from 'common/Lifecycle'; import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; -import { IRenderDimensions } from './renderer/Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; const MAX_ROWS_TO_READ = 20; diff --git a/src/MouseHelper.ts b/src/MouseHelper.ts index cf4811a5..8ce6543a 100644 --- a/src/MouseHelper.ts +++ b/src/MouseHelper.ts @@ -4,12 +4,12 @@ */ import { IMouseHelper } from './Types'; -import { RenderCoordinator } from './renderer/RenderCoordinator'; +import { RenderService } from './renderer/RenderService'; import { ICharSizeService } from 'browser/services/Services'; export class MouseHelper implements IMouseHelper { constructor( - private _renderCoordinator: RenderCoordinator, + private _renderCoordinator: RenderService, private _charSizeService: ICharSizeService ) { } diff --git a/src/Terminal.ts b/src/Terminal.ts index 851f4d6e..2741ba09 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -21,8 +21,8 @@ * http://linux.die.net/man/7/urxvt */ -import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, CharacterJoinerHandler, IMouseZoneManager } from './Types'; -import { IRenderer } from './renderer/Types'; +import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminalOptions, ITerminal, IBrowser, ILinkifier, ILinkMatcherOptions, CustomKeyEventHandler, LinkMatcherHandler, IMouseZoneManager } from './Types'; +import { IRenderer, CharacterJoinerHandler } from 'browser/renderer/Types'; import { BufferSet } from 'common/buffer/BufferSet'; import { Buffer } from 'common/buffer/Buffer'; import { CompositionHelper } from './CompositionHelper'; @@ -50,7 +50,7 @@ import { EventEmitter2, IEvent } from 'common/EventEmitter2'; import { Attributes, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { applyWindowsMode } from './WindowsMode'; import { ColorManager } from 'browser/ColorManager'; -import { RenderCoordinator } from './renderer/RenderCoordinator'; +import { RenderService } from './renderer/RenderService'; import { IOptionsService, IBufferService } from 'common/services/Services'; import { OptionsService } from 'common/services/OptionsService'; import { ICharSizeService } from 'browser/services/Services'; @@ -171,7 +171,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II private _inputHandler: InputHandler; public soundManager: SoundManager; - private _renderCoordinator: RenderCoordinator; + private _renderCoordinator: RenderService; public selectionManager: SelectionManager; public linkifier: ILinkifier; public buffers: BufferSet; @@ -629,7 +629,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II this._colorManager.setTheme(this._theme); const renderer = this._createRenderer(); - this._renderCoordinator = new RenderCoordinator(renderer, this.rows, this.screenElement, this.optionsService, this._charSizeService); + this._renderCoordinator = new RenderService(renderer, this.rows, this.screenElement, this.optionsService, this._charSizeService); this._renderCoordinator.onRender(e => this._onRender.fire(e)); this.onResize(e => this._renderCoordinator.resize(e.cols, e.rows)); diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index 4697eefb..a206ec10 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { IRenderer, IRenderDimensions } from './renderer/Types'; -import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBrowser, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions, CharacterJoinerHandler } from './Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBrowser, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions } from './Types'; import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener } from 'common/Types'; import { Buffer } from 'common/buffer/Buffer'; diff --git a/src/Types.ts b/src/Types.ts index 9dafbf79..cdd693f4 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -17,8 +17,6 @@ export type LineData = CharData[]; export type LinkMatcherHandler = (event: MouseEvent, uri: string) => void; export type LinkMatcherValidationCallback = (uri: string, callback: (isValid: boolean) => void) => void; -export type CharacterJoinerHandler = (text: string) => [number, number][]; - /** * This interface encapsulates everything needed from the Terminal by the * InputHandler. This cleanly separates the large amount of methods needed by diff --git a/src/Viewport.ts b/src/Viewport.ts index 6fa51bf8..cd5a282c 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -7,7 +7,7 @@ import { ITerminal, IViewport } from './Types'; import { Disposable } from 'common/Lifecycle'; import { addDisposableDomListener } from 'browser/Lifecycle'; import { IColorSet } from 'browser/Types'; -import { IRenderDimensions } from './renderer/Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; import { ICharSizeService } from 'browser/services/Services'; const FALLBACK_SCROLL_BAR_WIDTH = 15; diff --git a/src/browser/ColorManager.ts b/src/browser/ColorManager.ts index 9a574e4a..70d21a7a 100644 --- a/src/browser/ColorManager.ts +++ b/src/browser/ColorManager.ts @@ -3,7 +3,8 @@ * @license MIT */ -import { IColorManager, IColor, IColorSet, ITheme } from 'browser/Types'; +import { IColorManager, IColor, IColorSet } from 'browser/Types'; +import { ITheme } from 'common/services/Services'; const DEFAULT_FOREGROUND = fromHex('#ffffff'); const DEFAULT_BACKGROUND = fromHex('#000000'); diff --git a/src/browser/Types.ts b/src/browser/Types.ts index b7b0ac21..ef725ba6 100644 --- a/src/browser/Types.ts +++ b/src/browser/Types.ts @@ -20,27 +20,3 @@ export interface IColorSet { selection: IColor; ansi: IColor[]; } - -export interface ITheme { - foreground?: string; - background?: string; - cursor?: string; - cursorAccent?: string; - selection?: string; - black?: string; - red?: string; - green?: string; - yellow?: string; - blue?: string; - magenta?: string; - cyan?: string; - white?: string; - brightBlack?: string; - brightRed?: string; - brightGreen?: string; - brightYellow?: string; - brightBlue?: string; - brightMagenta?: string; - brightCyan?: string; - brightWhite?: string; -} diff --git a/src/browser/renderer/Types.ts b/src/browser/renderer/Types.ts new file mode 100644 index 00000000..e580ff8d --- /dev/null +++ b/src/browser/renderer/Types.ts @@ -0,0 +1,47 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IDisposable } from 'common/Types'; +import { IColorSet } from 'browser/Types'; + +export type CharacterJoinerHandler = (text: string) => [number, number][]; + +export interface IRenderDimensions { + scaledCharWidth: number; + scaledCharHeight: number; + scaledCellWidth: number; + scaledCellHeight: number; + scaledCharLeft: number; + scaledCharTop: number; + scaledCanvasWidth: number; + scaledCanvasHeight: number; + canvasWidth: number; + canvasHeight: number; + actualCellWidth: number; + actualCellHeight: number; +} + +/** + * Note that IRenderer implementations should emit the refresh event after + * rendering rows to the screen. + */ +export interface IRenderer extends IDisposable { + readonly dimensions: IRenderDimensions; + + dispose(): void; + setColors(colors: IColorSet): void; + onDevicePixelRatioChange(): void; + onResize(cols: number, rows: number): void; + onCharSizeChanged(): void; + onBlur(): void; + onFocus(): void; + onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void; + onCursorMove(): void; + onOptionsChanged(): void; + clear(): void; + renderRows(start: number, end: number): void; + registerCharacterJoiner(handler: CharacterJoinerHandler): number; + deregisterCharacterJoiner(joinerId: number): boolean; +} diff --git a/src/browser/services/Services.d.ts b/src/browser/services/Services.d.ts index b7a94ea1..6bdf383a 100644 --- a/src/browser/services/Services.d.ts +++ b/src/browser/services/Services.d.ts @@ -4,6 +4,8 @@ */ import { IEvent } from 'common/EventEmitter2'; +import { IRenderDimensions, IRenderer, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { IColorSet } from 'browser/Types'; export interface ICharSizeService { readonly width: number; @@ -14,3 +16,28 @@ export interface ICharSizeService { measure(): void; } + +export interface IRenderService { + onDimensionsChange: IEvent; + onRender: IEvent<{ start: number, end: number }>; + onRefreshRequest: IEvent<{ start: number, end: number }>; + + dimensions: IRenderDimensions; + + refreshRows(start: number, end: number): void; + resize(cols: number, rows: number): void; + changeOptions(): void; + setRenderer(renderer: IRenderer): void; + setColors(colors: IColorSet): void; + onDevicePixelRatioChange(): void; + onResize(cols: number, rows: number): void; + // TODO: Is this useful when we have onResize? + onCharSizeChanged(): void; + onBlur(): void; + onFocus(): void; + onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void; + onCursorMove(): void; + clear(): void; + registerCharacterJoiner(handler: CharacterJoinerHandler): number; + deregisterCharacterJoiner(joinerId: number): boolean; +} diff --git a/src/renderer/BaseRenderLayer.ts b/src/renderer/BaseRenderLayer.ts index 8a06b1c4..8335f76d 100644 --- a/src/renderer/BaseRenderLayer.ts +++ b/src/renderer/BaseRenderLayer.ts @@ -3,7 +3,8 @@ * @license MIT */ -import { IRenderLayer, IRenderDimensions } from './Types'; +import { IRenderLayer } from './Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { ICellData, DEFAULT_COLOR } from 'common/Types'; import { DIM_OPACITY, INVERTED_DEFAULT_COLOR, IGlyphIdentifier } from './atlas/Types'; diff --git a/src/renderer/CursorRenderLayer.ts b/src/renderer/CursorRenderLayer.ts index b5dfcd0f..9626f772 100644 --- a/src/renderer/CursorRenderLayer.ts +++ b/src/renderer/CursorRenderLayer.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IRenderDimensions } from './Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; import { BaseRenderLayer } from './BaseRenderLayer'; import { ITerminal } from '../Types'; import { ICellData } from 'common/Types'; diff --git a/src/renderer/LinkRenderLayer.ts b/src/renderer/LinkRenderLayer.ts index 63cf0335..32db3db9 100644 --- a/src/renderer/LinkRenderLayer.ts +++ b/src/renderer/LinkRenderLayer.ts @@ -4,7 +4,7 @@ */ import { ILinkifierEvent, ITerminal, ILinkifierAccessor } from '../Types'; -import { IRenderDimensions } from './Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; import { BaseRenderLayer } from './BaseRenderLayer'; import { INVERTED_DEFAULT_COLOR } from './atlas/Types'; import { is256Color } from './atlas/CharAtlasUtils'; diff --git a/src/renderer/RenderCoordinator.ts b/src/renderer/RenderService.ts similarity index 97% rename from src/renderer/RenderCoordinator.ts rename to src/renderer/RenderService.ts index f5916b1d..409dd84d 100644 --- a/src/renderer/RenderCoordinator.ts +++ b/src/renderer/RenderService.ts @@ -3,18 +3,17 @@ * @license MIT */ -import { IRenderer, IRenderDimensions } from './Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; import { RenderDebouncer } from 'browser/RenderDebouncer'; import { EventEmitter2, IEvent } from 'common/EventEmitter2'; import { Disposable } from 'common/Lifecycle'; import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; import { addDisposableDomListener } from 'browser/Lifecycle'; import { IColorSet } from 'browser/Types'; -import { CharacterJoinerHandler } from '../Types'; import { IOptionsService } from 'common/services/Services'; import { ICharSizeService } from 'browser/services/Services'; -export class RenderCoordinator extends Disposable { +export class RenderService extends Disposable { private _renderDebouncer: RenderDebouncer; private _screenDprMonitor: ScreenDprMonitor; diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index c56327df..56e12b57 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -6,8 +6,9 @@ import { TextRenderLayer } from './TextRenderLayer'; import { SelectionRenderLayer } from './SelectionRenderLayer'; import { CursorRenderLayer } from './CursorRenderLayer'; -import { IRenderLayer, IRenderer, IRenderDimensions, ICharacterJoinerRegistry } from './Types'; -import { ITerminal, CharacterJoinerHandler } from '../Types'; +import { IRenderLayer, ICharacterJoinerRegistry } from './Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { ITerminal } from '../Types'; import { LinkRenderLayer } from './LinkRenderLayer'; import { CharacterJoinerRegistry } from '../renderer/CharacterJoinerRegistry'; import { Disposable } from 'common/Lifecycle'; diff --git a/src/renderer/SelectionRenderLayer.ts b/src/renderer/SelectionRenderLayer.ts index b555ac98..7c297fd8 100644 --- a/src/renderer/SelectionRenderLayer.ts +++ b/src/renderer/SelectionRenderLayer.ts @@ -4,7 +4,7 @@ */ import { ITerminal } from '../Types'; -import { IRenderDimensions } from './Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; import { BaseRenderLayer } from './BaseRenderLayer'; import { IColorSet } from 'browser/Types'; diff --git a/src/renderer/TextRenderLayer.ts b/src/renderer/TextRenderLayer.ts index 3aeb96c8..39fcb7fc 100644 --- a/src/renderer/TextRenderLayer.ts +++ b/src/renderer/TextRenderLayer.ts @@ -3,7 +3,8 @@ * @license MIT */ -import { IRenderDimensions, ICharacterJoinerRegistry } from './Types'; +import { ICharacterJoinerRegistry } from './Types'; +import { IRenderDimensions } from 'browser/renderer/Types'; import { ITerminal } from '../Types'; import { CharData, ICellData } from 'common/Types'; import { GridCache } from './GridCache'; diff --git a/src/renderer/Types.ts b/src/renderer/Types.ts index 017285d8..153b68e2 100644 --- a/src/renderer/Types.ts +++ b/src/renderer/Types.ts @@ -3,9 +3,10 @@ * @license MIT */ -import { ITerminal, CharacterJoinerHandler } from '../Types'; +import { ITerminal } from '../Types'; import { IDisposable } from 'xterm'; import { IColorSet } from 'browser/Types'; +import { IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; /** * Flags used to render terminal text properly. @@ -20,44 +21,6 @@ export const enum FLAGS { ITALIC = 64 } -/** - * Note that IRenderer implementations should emit the refresh event after - * rendering rows to the screen. - */ -export interface IRenderer extends IDisposable { - readonly dimensions: IRenderDimensions; - - dispose(): void; - setColors(colors: IColorSet): void; - onDevicePixelRatioChange(): void; - onResize(cols: number, rows: number): void; - onCharSizeChanged(): void; - onBlur(): void; - onFocus(): void; - onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void; - onCursorMove(): void; - onOptionsChanged(): void; - clear(): void; - renderRows(start: number, end: number): void; - registerCharacterJoiner(handler: CharacterJoinerHandler): number; - deregisterCharacterJoiner(joinerId: number): boolean; -} - -export interface IRenderDimensions { - scaledCharWidth: number; - scaledCharHeight: number; - scaledCellWidth: number; - scaledCellHeight: number; - scaledCharLeft: number; - scaledCharTop: number; - scaledCanvasWidth: number; - scaledCanvasHeight: number; - canvasWidth: number; - canvasHeight: number; - actualCellWidth: number; - actualCellHeight: number; -} - export interface IRenderLayer extends IDisposable { /** * Called when the terminal loses focus. diff --git a/src/renderer/dom/DomRenderer.ts b/src/renderer/dom/DomRenderer.ts index 7c41f028..8d370336 100644 --- a/src/renderer/dom/DomRenderer.ts +++ b/src/renderer/dom/DomRenderer.ts @@ -3,8 +3,8 @@ * @license MIT */ -import { IRenderer, IRenderDimensions } from '../Types'; -import { ILinkifierEvent, ITerminal, CharacterJoinerHandler } from '../../Types'; +import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; +import { ILinkifierEvent, ITerminal } from '../../Types'; import { BOLD_CLASS, ITALIC_CLASS, CURSOR_CLASS, CURSOR_STYLE_BLOCK_CLASS, CURSOR_BLINK_CLASS, CURSOR_STYLE_BAR_CLASS, CURSOR_STYLE_UNDERLINE_CLASS, DomRendererRowFactory } from './DomRendererRowFactory'; import { INVERTED_DEFAULT_COLOR } from '../atlas/Types'; import { Disposable } from 'common/Lifecycle'; From 54d7bb0b38b09c107b9b91fceb3fef2c34f7ed5c Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jun 2019 19:26:31 -0700 Subject: [PATCH 2/5] Move RenderService into browser --- src/MouseHelper.ts | 2 +- src/Terminal.ts | 2 +- src/{renderer => browser/services}/RenderService.ts | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename src/{renderer => browser/services}/RenderService.ts (97%) diff --git a/src/MouseHelper.ts b/src/MouseHelper.ts index 8ce6543a..78968108 100644 --- a/src/MouseHelper.ts +++ b/src/MouseHelper.ts @@ -4,7 +4,7 @@ */ import { IMouseHelper } from './Types'; -import { RenderService } from './renderer/RenderService'; +import { RenderService } from 'browser/services/RenderService'; import { ICharSizeService } from 'browser/services/Services'; export class MouseHelper implements IMouseHelper { diff --git a/src/Terminal.ts b/src/Terminal.ts index 2741ba09..5929aace 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -50,7 +50,7 @@ import { EventEmitter2, IEvent } from 'common/EventEmitter2'; import { Attributes, DEFAULT_ATTR_DATA } from 'common/buffer/BufferLine'; import { applyWindowsMode } from './WindowsMode'; import { ColorManager } from 'browser/ColorManager'; -import { RenderService } from './renderer/RenderService'; +import { RenderService } from 'browser/services/RenderService'; import { IOptionsService, IBufferService } from 'common/services/Services'; import { OptionsService } from 'common/services/OptionsService'; import { ICharSizeService } from 'browser/services/Services'; diff --git a/src/renderer/RenderService.ts b/src/browser/services/RenderService.ts similarity index 97% rename from src/renderer/RenderService.ts rename to src/browser/services/RenderService.ts index 409dd84d..5930569d 100644 --- a/src/renderer/RenderService.ts +++ b/src/browser/services/RenderService.ts @@ -11,9 +11,9 @@ import { ScreenDprMonitor } from 'browser/ScreenDprMonitor'; import { addDisposableDomListener } from 'browser/Lifecycle'; import { IColorSet } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; -import { ICharSizeService } from 'browser/services/Services'; +import { ICharSizeService, IRenderService } from 'browser/services/Services'; -export class RenderService extends Disposable { +export class RenderService extends Disposable implements IRenderService { private _renderDebouncer: RenderDebouncer; private _screenDprMonitor: ScreenDprMonitor; From cbfbe232d00fd3ff6acb622b3b5469d7f882f731 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jun 2019 19:28:43 -0700 Subject: [PATCH 3/5] Rename coordinator to service --- addons/xterm-addon-fit/src/FitAddon.ts | 6 +-- demo/client.ts | 4 +- src/MouseHelper.ts | 6 +-- src/Terminal.ts | 58 +++++++++++++------------- 4 files changed, 37 insertions(+), 37 deletions(-) diff --git a/addons/xterm-addon-fit/src/FitAddon.ts b/addons/xterm-addon-fit/src/FitAddon.ts index f2c37141..f23bd161 100644 --- a/addons/xterm-addon-fit/src/FitAddon.ts +++ b/addons/xterm-addon-fit/src/FitAddon.ts @@ -39,7 +39,7 @@ export class FitAddon implements ITerminalAddon { // Force a full render if (this._terminal.rows !== dims.rows || this._terminal.cols !== dims.cols) { - core._renderCoordinator.clear(); + core._renderService.clear(); this._terminal.resize(dims.cols, dims.rows); } } @@ -71,8 +71,8 @@ export class FitAddon implements ITerminalAddon { const availableHeight = parentElementHeight - elementPaddingVer; const availableWidth = parentElementWidth - elementPaddingHor - core.viewport.scrollBarWidth; const geometry = { - cols: Math.floor(availableWidth / core._renderCoordinator.dimensions.actualCellWidth), - rows: Math.floor(availableHeight / core._renderCoordinator.dimensions.actualCellHeight) + cols: Math.floor(availableWidth / core._renderService.dimensions.actualCellWidth), + rows: Math.floor(availableHeight / core._renderService.dimensions.actualCellHeight) }; return geometry; } diff --git a/demo/client.ts b/demo/client.ts index 1841e991..f1626c4f 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -307,8 +307,8 @@ function addDomListener(element: HTMLElement, type: string, handler: (...args: a function updateTerminalSize(): void { const cols = parseInt((document.getElementById(`opt-cols`)).value, 10); const rows = parseInt((document.getElementById(`opt-rows`)).value, 10); - const width = (cols * term._core._renderCoordinator.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px'; - const height = (rows * term._core._renderCoordinator.dimensions.actualCellHeight).toString() + 'px'; + const width = (cols * term._core._renderService.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px'; + const height = (rows * term._core._renderService.dimensions.actualCellHeight).toString() + 'px'; terminalContainer.style.width = width; terminalContainer.style.height = height; fitAddon.fit(); diff --git a/src/MouseHelper.ts b/src/MouseHelper.ts index 78968108..12e8cf0e 100644 --- a/src/MouseHelper.ts +++ b/src/MouseHelper.ts @@ -9,7 +9,7 @@ import { ICharSizeService } from 'browser/services/Services'; export class MouseHelper implements IMouseHelper { constructor( - private _renderCoordinator: RenderService, + private _renderService: RenderService, private _charSizeService: ICharSizeService ) { } @@ -42,8 +42,8 @@ export class MouseHelper implements IMouseHelper { return null; } - coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderCoordinator.dimensions.actualCellWidth / 2 : 0)) / this._renderCoordinator.dimensions.actualCellWidth); - coords[1] = Math.ceil(coords[1] / this._renderCoordinator.dimensions.actualCellHeight); + coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderService.dimensions.actualCellWidth / 2 : 0)) / this._renderService.dimensions.actualCellWidth); + coords[1] = Math.ceil(coords[1] / this._renderService.dimensions.actualCellHeight); // Ensure coordinates are within the terminal viewport. Note that selections // need an addition point of precision to cover the end point (as characters diff --git a/src/Terminal.ts b/src/Terminal.ts index 5929aace..a48f895c 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -111,6 +111,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II // browser services private _charSizeService: ICharSizeService; + private _renderService: RenderService; // modes public applicationKeypad: boolean; @@ -171,7 +172,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II private _inputHandler: InputHandler; public soundManager: SoundManager; - private _renderCoordinator: RenderService; public selectionManager: SelectionManager; public linkifier: ILinkifier; public buffers: BufferSet; @@ -360,8 +360,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II case 'fontFamily': case 'fontSize': // When the font changes the size of the cells may change which requires a renderer clear - if (this._renderCoordinator) { - this._renderCoordinator.clear(); + if (this._renderService) { + this._renderService.clear(); } if (this._charSizeService) { this._charSizeService.measure(); @@ -373,15 +373,15 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II case 'fontWeight': case 'fontWeightBold': // When the font changes the size of the cells may change which requires a renderer clear - if (this._renderCoordinator) { - this._renderCoordinator.clear(); - this._renderCoordinator.onResize(this.cols, this.rows); + if (this._renderService) { + this._renderService.clear(); + this._renderService.onResize(this.cols, this.rows); this.refresh(0, this.rows - 1); } break; case 'rendererType': - if (this._renderCoordinator) { - this._renderCoordinator.setRenderer(this._createRenderer()); + if (this._renderService) { + this._renderService.setRenderer(this._createRenderer()); } break; case 'scrollback': @@ -392,8 +392,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II break; case 'screenReaderMode': if (this.optionsService.options.screenReaderMode) { - if (!this._accessibilityManager && this._renderCoordinator) { - this._accessibilityManager = new AccessibilityManager(this, this._renderCoordinator.dimensions); + if (!this._accessibilityManager && this._renderService) { + this._accessibilityManager = new AccessibilityManager(this, this._renderService.dimensions); } } else { if (this._accessibilityManager) { @@ -629,24 +629,24 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II this._colorManager.setTheme(this._theme); const renderer = this._createRenderer(); - this._renderCoordinator = new RenderService(renderer, this.rows, this.screenElement, this.optionsService, this._charSizeService); - this._renderCoordinator.onRender(e => this._onRender.fire(e)); - this.onResize(e => this._renderCoordinator.resize(e.cols, e.rows)); + this._renderService = new RenderService(renderer, this.rows, this.screenElement, this.optionsService, this._charSizeService); + this._renderService.onRender(e => this._onRender.fire(e)); + this.onResize(e => this._renderService.resize(e.cols, e.rows)); - this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this._renderCoordinator.dimensions, this._charSizeService); + this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this._renderService.dimensions, this._charSizeService); this.viewport.onThemeChange(this._colorManager.colors); this.register(this.viewport); - this.register(this.onCursorMove(() => this._renderCoordinator.onCursorMove())); - this.register(this.onResize(() => this._renderCoordinator.onResize(this.cols, this.rows))); - this.register(this.addDisposableListener('blur', () => this._renderCoordinator.onBlur())); - this.register(this.addDisposableListener('focus', () => this._renderCoordinator.onFocus())); - this.register(this._renderCoordinator.onDimensionsChange(() => this.viewport.syncScrollArea())); + this.register(this.onCursorMove(() => this._renderService.onCursorMove())); + this.register(this.onResize(() => this._renderService.onResize(this.cols, this.rows))); + this.register(this.addDisposableListener('blur', () => this._renderService.onBlur())); + this.register(this.addDisposableListener('focus', () => this._renderService.onFocus())); + this.register(this._renderService.onDimensionsChange(() => this.viewport.syncScrollArea())); this.selectionManager = new SelectionManager(this, this._charSizeService, this._bufferService); this.register(this.selectionManager.onSelectionChange(() => this._onSelectionChange.fire())); this.register(addDisposableDomListener(this.element, 'mousedown', (e: MouseEvent) => this.selectionManager.onMouseDown(e))); - this.register(this.selectionManager.onRedrawRequest(e => this._renderCoordinator.onSelectionChanged(e.start, e.end, e.columnSelectMode))); + this.register(this.selectionManager.onRedrawRequest(e => this._renderService.onSelectionChanged(e.start, e.end, e.columnSelectMode))); this.register(this.selectionManager.onLinuxMouseSelection(text => { // If there's a new selection, put it into the textarea, focus and select it // in order to register it as a selection on the OS. This event is fired @@ -661,7 +661,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II })); this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this.selectionManager.refresh())); - this.mouseHelper = new MouseHelper(this._renderCoordinator, this._charSizeService); + this.mouseHelper = new MouseHelper(this._renderService, this._charSizeService); // apply mouse event classes set by escape codes before terminal was attached this.element.classList.toggle('enable-mouse-events', this.mouseEvents); if (this.mouseEvents) { @@ -673,8 +673,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II if (this.options.screenReaderMode) { // Note that this must be done *after* the renderer is created in order to // ensure the correct order of the dprchange event - this._accessibilityManager = new AccessibilityManager(this, this._renderCoordinator.dimensions); - this._accessibilityManager.register(this._renderCoordinator.onDimensionsChange(e => this._accessibilityManager.setDimensions(e))); + this._accessibilityManager = new AccessibilityManager(this, this._renderService.dimensions); + this._accessibilityManager.register(this._renderService.onDimensionsChange(e => this._accessibilityManager.setDimensions(e))); } // Measure the character size @@ -707,8 +707,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II private _setTheme(theme: ITheme): void { this._theme = theme; this._colorManager.setTheme(theme); - if (this._renderCoordinator) { - this._renderCoordinator.setColors(this._colorManager.colors); + if (this._renderService) { + this._renderService.setColors(this._colorManager.colors); } if (this.viewport) { this.viewport.onThemeChange(this._colorManager.colors); @@ -1064,8 +1064,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II * @param end The row to end at (between start and this.rows - 1). */ public refresh(start: number, end: number): void { - if (this._renderCoordinator) { - this._renderCoordinator.refreshRows(start, end); + if (this._renderService) { + this._renderService.refreshRows(start, end); } } @@ -1460,13 +1460,13 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II } public registerCharacterJoiner(handler: CharacterJoinerHandler): number { - const joinerId = this._renderCoordinator.registerCharacterJoiner(handler); + const joinerId = this._renderService.registerCharacterJoiner(handler); this.refresh(0, this.rows - 1); return joinerId; } public deregisterCharacterJoiner(joinerId: number): void { - if (this._renderCoordinator.deregisterCharacterJoiner(joinerId)) { + if (this._renderService.deregisterCharacterJoiner(joinerId)) { this.refresh(0, this.rows - 1); } } From 5dbab76bed4d67a4c6487aa29e4544cebccab5a1 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jun 2019 19:34:38 -0700 Subject: [PATCH 4/5] Move MouseHelper into browser --- src/MouseHelper.test.ts | 2 +- src/SelectionManager.ts | 2 +- src/Terminal.ts | 2 +- src/TestUtils.test.ts | 4 ++-- src/Types.ts | 7 +------ src/browser/Types.ts | 5 +++++ src/{ => browser/input}/MouseHelper.ts | 16 +++++++--------- 7 files changed, 18 insertions(+), 20 deletions(-) rename src/{ => browser/input}/MouseHelper.ts (89%) diff --git a/src/MouseHelper.test.ts b/src/MouseHelper.test.ts index a0669ec0..6f886d75 100644 --- a/src/MouseHelper.test.ts +++ b/src/MouseHelper.test.ts @@ -5,7 +5,7 @@ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { MouseHelper } from './MouseHelper'; +import { MouseHelper } from './browser/input/MouseHelper'; import { MockRenderer, MockCharSizeService } from './TestUtils.test'; const CHAR_WIDTH = 10; diff --git a/src/SelectionManager.ts b/src/SelectionManager.ts index fe36a348..1a8d6b6c 100644 --- a/src/SelectionManager.ts +++ b/src/SelectionManager.ts @@ -6,7 +6,7 @@ import { ITerminal, ISelectionManager, ISelectionRedrawRequestEvent } from './Types'; import { IBuffer } from 'common/buffer/Types'; import { IBufferLine } from 'common/Types'; -import { MouseHelper } from './MouseHelper'; +import { MouseHelper } from './browser/input/MouseHelper'; import * as Browser from 'common/Platform'; import { SelectionModel } from './SelectionModel'; import { AltClickHandler } from './handlers/AltClickHandler'; diff --git a/src/Terminal.ts b/src/Terminal.ts index a48f895c..a18bb209 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -37,7 +37,7 @@ import { SelectionManager } from './SelectionManager'; import * as Browser from 'common/Platform'; import { addDisposableDomListener } from 'browser/Lifecycle'; import * as Strings from './Strings'; -import { MouseHelper } from './MouseHelper'; +import { MouseHelper } from './browser/input/MouseHelper'; import { SoundManager } from './SoundManager'; import { MouseZoneManager } from './MouseZoneManager'; import { AccessibilityManager } from './AccessibilityManager'; diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index a206ec10..f26708a6 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -4,7 +4,7 @@ */ import { IRenderer, IRenderDimensions, CharacterJoinerHandler } from 'browser/renderer/Types'; -import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBrowser, ISelectionManager, ITerminalOptions, ILinkifier, IMouseHelper, ILinkMatcherOptions } from './Types'; +import { IInputHandlingTerminal, IViewport, ICompositionHelper, ITerminal, IBrowser, ISelectionManager, ITerminalOptions, ILinkifier, ILinkMatcherOptions } from './Types'; import { IBuffer, IBufferStringIterator, IBufferSet } from 'common/buffer/Types'; import { IBufferLine, ICellData, IAttributeData, ICircularList, XtermListener } from 'common/Types'; import { Buffer } from 'common/buffer/Buffer'; @@ -12,7 +12,7 @@ import * as Browser from 'common/Platform'; import { IDisposable, IMarker, IEvent, ISelectionPosition } from 'xterm'; import { Terminal } from './Terminal'; import { AttributeData } from 'common/buffer/BufferLine'; -import { IColorManager, IColorSet } from 'browser/Types'; +import { IColorManager, IColorSet, IMouseHelper } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; import { ICharSizeService } from 'browser/services/Services'; diff --git a/src/Types.ts b/src/Types.ts index cdd693f4..71987bbe 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -6,7 +6,7 @@ import { ITerminalOptions as IPublicTerminalOptions, IEventEmitter, IDisposable, IMarker, ISelectionPosition } from 'xterm'; import { ICharset, IAttributeData, CharData } from 'common/Types'; import { IEvent } from 'common/EventEmitter2'; -import { IColorSet } from 'browser/Types'; +import { IColorSet, IMouseHelper } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; import { IBuffer, IBufferSet } from 'common/buffer/Types'; @@ -277,11 +277,6 @@ export interface ILinkifierAccessor { linkifier: ILinkifier; } -export interface IMouseHelper { - getCoords(event: { clientX: number, clientY: number }, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number]; - getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number }; -} - // TODO: The options that are not in the public API should be reviewed export interface ITerminalOptions extends IPublicTerminalOptions { [key: string]: any; diff --git a/src/browser/Types.ts b/src/browser/Types.ts index ef725ba6..a1ea662c 100644 --- a/src/browser/Types.ts +++ b/src/browser/Types.ts @@ -20,3 +20,8 @@ export interface IColorSet { selection: IColor; ansi: IColor[]; } + +export interface IMouseHelper { + getCoords(event: { clientX: number, clientY: number }, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined; + getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number | undefined, y: number | undefined }; +} diff --git a/src/MouseHelper.ts b/src/browser/input/MouseHelper.ts similarity index 89% rename from src/MouseHelper.ts rename to src/browser/input/MouseHelper.ts index 12e8cf0e..b99757db 100644 --- a/src/MouseHelper.ts +++ b/src/browser/input/MouseHelper.ts @@ -3,7 +3,7 @@ * @license MIT */ -import { IMouseHelper } from './Types'; +import { IMouseHelper } from 'browser/Types'; import { RenderService } from 'browser/services/RenderService'; import { ICharSizeService } from 'browser/services/Services'; @@ -31,15 +31,15 @@ export class MouseHelper implements IMouseHelper { * apply an offset to the x value such that the left half of the cell will * select that cell and the right half will select the next cell. */ - public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] { + public getCoords(event: {clientX: number, clientY: number}, element: HTMLElement, colCount: number, rowCount: number, isSelection?: boolean): [number, number] | undefined { // Coordinates cannot be measured if there are no valid if (!this._charSizeService.hasValidSize) { - return null; + return undefined; } const coords = MouseHelper.getCoordsRelativeToElement(event, element); if (!coords) { - return null; + return undefined; } coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderService.dimensions.actualCellWidth / 2 : 0)) / this._renderService.dimensions.actualCellWidth); @@ -63,14 +63,12 @@ export class MouseHelper implements IMouseHelper { * @param colCount The number of columns in the terminal. * @param rowCount The number of rows in the terminal. */ - public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number, y: number } { + public getRawByteCoords(event: MouseEvent, element: HTMLElement, colCount: number, rowCount: number): { x: number | undefined, y: number | undefined } { const coords = this.getCoords(event, element, colCount, rowCount); - let x = coords[0]; - let y = coords[1]; // xterm sends raw bytes and starts at 32 (SP) for each. - x += 32; - y += 32; + const x = coords ? coords[0] + 32 : undefined; + const y = coords ? coords[1] + 32 : undefined; return { x, y }; } From e21826f6cbf7a05b2adb592d2e02f8428dc08a0a Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 8 Jun 2019 19:40:18 -0700 Subject: [PATCH 5/5] Move MouseHelper.test into browser --- src/CompositionHelper.test.ts | 2 +- src/SelectionManager.test.ts | 3 ++- src/TestUtils.test.ts | 8 -------- src/browser/TestUtils.test.ts | 14 ++++++++++++++ src/{ => browser/input}/MouseHelper.test.ts | 19 ++++++++++--------- 5 files changed, 27 insertions(+), 19 deletions(-) create mode 100644 src/browser/TestUtils.test.ts rename src/{ => browser/input}/MouseHelper.test.ts (78%) diff --git a/src/CompositionHelper.test.ts b/src/CompositionHelper.test.ts index 156f5a44..2d28f55d 100644 --- a/src/CompositionHelper.test.ts +++ b/src/CompositionHelper.test.ts @@ -6,7 +6,7 @@ import { assert } from 'chai'; import { CompositionHelper } from './CompositionHelper'; import { ITerminal } from './Types'; -import { MockCharSizeService } from 'TestUtils.test'; +import { MockCharSizeService } from 'browser/TestUtils.test'; describe('CompositionHelper', () => { let terminal: ITerminal; diff --git a/src/SelectionManager.test.ts b/src/SelectionManager.test.ts index 87f7386a..5dc692af 100644 --- a/src/SelectionManager.test.ts +++ b/src/SelectionManager.test.ts @@ -10,10 +10,11 @@ import { BufferSet } from 'common/buffer/BufferSet'; import { ITerminal } from './Types'; import { IBuffer } from 'common/buffer/Types'; import { IBufferLine } from 'common/Types'; -import { MockTerminal, MockCharSizeService } from './TestUtils.test'; +import { MockTerminal } from './TestUtils.test'; import { MockOptionsService, MockBufferService } from 'common/TestUtils.test'; import { BufferLine, CellData } from 'common/buffer/BufferLine'; import { IBufferService } from 'common/services/Services'; +import { MockCharSizeService } from 'browser/TestUtils.test'; class TestMockTerminal extends MockTerminal { emit(event: string, data: any): void {} diff --git a/src/TestUtils.test.ts b/src/TestUtils.test.ts index f26708a6..bbe09508 100644 --- a/src/TestUtils.test.ts +++ b/src/TestUtils.test.ts @@ -14,7 +14,6 @@ import { Terminal } from './Terminal'; import { AttributeData } from 'common/buffer/BufferLine'; import { IColorManager, IColorSet, IMouseHelper } from 'browser/Types'; import { IOptionsService } from 'common/services/Services'; -import { ICharSizeService } from 'browser/services/Services'; export class TestTerminal extends Terminal { writeSync(data: string): void { @@ -428,10 +427,3 @@ export class MockCompositionHelper implements ICompositionHelper { return true; } } - -export class MockCharSizeService implements ICharSizeService { - get hasValidSize(): boolean { return this.width > 0 && this.height > 0; } - onCharSizeChange: IEvent; - constructor(public width: number, public height: number) {} - measure(): void {} -} diff --git a/src/browser/TestUtils.test.ts b/src/browser/TestUtils.test.ts new file mode 100644 index 00000000..7c965c8d --- /dev/null +++ b/src/browser/TestUtils.test.ts @@ -0,0 +1,14 @@ +/** + * Copyright (c) 2019 The xterm.js authors. All rights reserved. + * @license MIT + */ + +import { IEvent, EventEmitter2 } from 'common/EventEmitter2'; +import { ICharSizeService } from 'browser/services/Services'; + +export class MockCharSizeService implements ICharSizeService { + get hasValidSize(): boolean { return this.width > 0 && this.height > 0; } + onCharSizeChange: IEvent = new EventEmitter2().event; + constructor(public width: number, public height: number) {} + measure(): void {} +} diff --git a/src/MouseHelper.test.ts b/src/browser/input/MouseHelper.test.ts similarity index 78% rename from src/MouseHelper.test.ts rename to src/browser/input/MouseHelper.test.ts index 6f886d75..5d4b567c 100644 --- a/src/MouseHelper.test.ts +++ b/src/browser/input/MouseHelper.test.ts @@ -5,8 +5,8 @@ import jsdom = require('jsdom'); import { assert } from 'chai'; -import { MouseHelper } from './browser/input/MouseHelper'; -import { MockRenderer, MockCharSizeService } from './TestUtils.test'; +import { MouseHelper } from 'browser/input/MouseHelper'; +import { MockCharSizeService } from 'browser/TestUtils.test'; const CHAR_WIDTH = 10; const CHAR_HEIGHT = 20; @@ -17,16 +17,17 @@ describe('MouseHelper.getCoords', () => { beforeEach(() => { document = new jsdom.JSDOM('').window.document; - const renderer = new MockRenderer(); - renderer.dimensions = { - actualCellWidth: CHAR_WIDTH, - actualCellHeight: CHAR_HEIGHT + const mockRenderService = { + dimensions: { + actualCellWidth: CHAR_WIDTH, + actualCellHeight: CHAR_HEIGHT + } }; - mouseHelper = new MouseHelper(renderer as any, new MockCharSizeService(CHAR_WIDTH, CHAR_HEIGHT)); + mouseHelper = new MouseHelper(mockRenderService as any, new MockCharSizeService(CHAR_WIDTH, CHAR_HEIGHT)); }); it('should return the cell that was clicked', () => { - let coords: [number, number]; + let coords: [number, number] | undefined; coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH / 2, clientY: CHAR_HEIGHT / 2 }, document.createElement('div'), 10, 10); assert.deepEqual(coords, [1, 1]); coords = mouseHelper.getCoords({ clientX: CHAR_WIDTH, clientY: CHAR_HEIGHT }, document.createElement('div'), 10, 10); @@ -38,7 +39,7 @@ describe('MouseHelper.getCoords', () => { }); it('should ensure the coordinates are returned within the terminal bounds', () => { - let coords: [number, number]; + let coords: [number, number] | undefined; coords = mouseHelper.getCoords({ clientX: -1, clientY: -1 }, document.createElement('div'), 10, 10); assert.deepEqual(coords, [1, 1]); // Event are double the cols/rows