From 43015f85f45bea83cc07a066f382dd5d09b458e8 Mon Sep 17 00:00:00 2001 From: Daniel Imms Date: Sat, 18 May 2019 21:15:18 -0700 Subject: [PATCH] Move Renderer ownership to RenderCoordinator --- demo/client.ts | 4 +- src/AccessibilityManager.ts | 25 +++++++--- src/MouseHelper.test.ts | 2 +- src/MouseHelper.ts | 13 +++-- src/Terminal.ts | 82 ++++++++++++------------------- src/Types.ts | 2 - src/Viewport.ts | 16 ++++-- src/addons/fit/fit.ts | 6 +-- src/renderer/RenderCoordinator.ts | 82 +++++++++++++++++++++++++++---- src/renderer/Renderer.ts | 5 -- src/renderer/Types.ts | 15 +++++- 11 files changed, 158 insertions(+), 94 deletions(-) diff --git a/demo/client.ts b/demo/client.ts index 01789402..8bcdc971 100644 --- a/demo/client.ts +++ b/demo/client.ts @@ -296,8 +296,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.renderer.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px'; - const height = (rows * term._core.renderer.dimensions.actualCellHeight).toString() + 'px'; + const width = (cols * term._core._renderCoordinator.dimensions.actualCellWidth + term._core.viewport.scrollBarWidth).toString() + 'px'; + const height = (rows * term._core._renderCoordinator.dimensions.actualCellHeight).toString() + 'px'; terminalContainer.style.width = width; terminalContainer.style.height = height; term.fit(); diff --git a/src/AccessibilityManager.ts b/src/AccessibilityManager.ts index bc1dcdd0..7f1d8eaa 100644 --- a/src/AccessibilityManager.ts +++ b/src/AccessibilityManager.ts @@ -10,6 +10,7 @@ import { RenderDebouncer } from './ui/RenderDebouncer'; import { addDisposableDomListener } from './ui/Lifecycle'; import { Disposable } from './common/Lifecycle'; import { ScreenDprMonitor } from './ui/ScreenDprMonitor'; +import { IRenderDimensions } from './renderer/Types'; const MAX_ROWS_TO_READ = 20; @@ -42,7 +43,10 @@ export class AccessibilityManager extends Disposable { */ private _charsToConsume: string[] = []; - constructor(private _terminal: ITerminal) { + constructor( + private _terminal: ITerminal, + private _dimensions: IRenderDimensions + ) { super(); this._accessibilityTreeRoot = document.createElement('div'); this._accessibilityTreeRoot.classList.add('xterm-accessibility'); @@ -60,7 +64,7 @@ export class AccessibilityManager extends Disposable { this._rowElements[0].addEventListener('focus', this._topBoundaryFocusListener); this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener); - this.refreshRowsDimensions(); + this._refreshRowsDimensions(); this._accessibilityTreeRoot.appendChild(this._rowContainer); this._renderRowsDebouncer = new RenderDebouncer(this._renderRows.bind(this)); @@ -86,10 +90,10 @@ export class AccessibilityManager extends Disposable { this._screenDprMonitor = new ScreenDprMonitor(); this.register(this._screenDprMonitor); - this._screenDprMonitor.setListener(() => this.refreshRowsDimensions()); + this._screenDprMonitor.setListener(() => this._refreshRowsDimensions()); // This shouldn't be needed on modern browsers but is present in case the // media query that drives the ScreenDprMonitor isn't supported - this.register(addDisposableDomListener(window, 'resize', () => this.refreshRowsDimensions())); + this.register(addDisposableDomListener(window, 'resize', () => this._refreshRowsDimensions())); } public dispose(): void { @@ -175,7 +179,7 @@ export class AccessibilityManager extends Disposable { // Add bottom boundary listener this._rowElements[this._rowElements.length - 1].addEventListener('focus', this._bottomBoundaryFocusListener); - this.refreshRowsDimensions(); + this._refreshRowsDimensions(); } private _createAccessibilityTreeNode(): HTMLElement { @@ -258,8 +262,8 @@ export class AccessibilityManager extends Disposable { } } - public refreshRowsDimensions(): void { - if (!this._terminal.renderer.dimensions.actualCellHeight) { + private _refreshRowsDimensions(): void { + if (!this._dimensions.actualCellHeight) { return; } if (this._rowElements.length !== this._terminal.rows) { @@ -270,8 +274,13 @@ export class AccessibilityManager extends Disposable { } } + public setDimensions(dimensions: IRenderDimensions): void { + this._dimensions = dimensions; + this._refreshRowsDimensions(); + } + private _refreshRowDimensions(element: HTMLElement): void { - element.style.height = `${this._terminal.renderer.dimensions.actualCellHeight}px`; + element.style.height = `${this._dimensions.actualCellHeight}px`; } private _announceCharacter(char: string): void { diff --git a/src/MouseHelper.test.ts b/src/MouseHelper.test.ts index 26888bf7..0925d49f 100644 --- a/src/MouseHelper.test.ts +++ b/src/MouseHelper.test.ts @@ -31,7 +31,7 @@ describe('MouseHelper.getCoords', () => { actualCellWidth: CHAR_WIDTH, actualCellHeight: CHAR_HEIGHT }; - mouseHelper = new MouseHelper(renderer); + mouseHelper = new MouseHelper(renderer as any); }); describe('when charMeasure is not initialized', () => { diff --git a/src/MouseHelper.ts b/src/MouseHelper.ts index fb91c9ef..12905222 100644 --- a/src/MouseHelper.ts +++ b/src/MouseHelper.ts @@ -4,13 +4,12 @@ */ import { ICharMeasure, IMouseHelper } from './Types'; -import { IRenderer } from './renderer/Types'; +import { RenderCoordinator } from './renderer/RenderCoordinator'; export class MouseHelper implements IMouseHelper { - constructor(private _renderer: IRenderer) {} - - public setRenderer(renderer: IRenderer): void { - this._renderer = renderer; + constructor( + private _renderCoordinator: RenderCoordinator + ) { } public static getCoordsRelativeToElement(event: {clientX: number, clientY: number}, element: HTMLElement): [number, number] { @@ -42,8 +41,8 @@ export class MouseHelper implements IMouseHelper { return null; } - coords[0] = Math.ceil((coords[0] + (isSelection ? this._renderer.dimensions.actualCellWidth / 2 : 0)) / this._renderer.dimensions.actualCellWidth); - coords[1] = Math.ceil(coords[1] / this._renderer.dimensions.actualCellHeight); + 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); // 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 cb2b3220..f55a84f6 100644 --- a/src/Terminal.ts +++ b/src/Terminal.ts @@ -204,7 +204,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II private _inputHandler: InputHandler; public soundManager: SoundManager; private _renderCoordinator: RenderCoordinator; - public renderer: IRenderer; public selectionManager: SelectionManager; public linkifier: ILinkifier; public buffers: BufferSet; @@ -356,8 +355,6 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II this._inputHandler.onLineFeed(() => this._onLineFeed.fire()); this.register(this._inputHandler); - // Reuse renderer if the Terminal is being recreated via a reset call. - this.renderer = this.renderer || null; this.selectionManager = this.selectionManager || null; this.linkifier = this.linkifier || new Linkifier(this); this._mouseZoneManager = this._mouseZoneManager || null; @@ -469,12 +466,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II } break; case 'theme': - // If open has been called we do not want to set options.theme as the - // source of truth is owned by the renderer. - if (this.renderer) { - this._setTheme(value); - return; - } + this._setTheme(value); break; case 'scrollback': value = Math.min(value, MAX_BUFFER_SIZE); @@ -503,8 +495,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.renderer) { - this.renderer.clear(); + if (this._renderCoordinator) { + this._renderCoordinator.clear(); this.charMeasure.measure(this.options); } break; @@ -516,21 +508,16 @@ 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.renderer) { - this.renderer.clear(); - this.renderer.onResize(this.cols, this.rows); + if (this._renderCoordinator) { + this._renderCoordinator.clear(); + this._renderCoordinator.onResize(this.cols, this.rows); this.refresh(0, this.rows - 1); } break; case 'rendererType': - if (this.renderer) { - this.unregister(this.renderer); - this.renderer.dispose(); - this.renderer = null; + if (this._renderCoordinator) { + this._renderCoordinator.setRenderer(this._createRenderer()); } - this._setupRenderer(); - this.renderer.onCharSizeChanged(); - this.mouseHelper.setRenderer(this.renderer); break; case 'scrollback': this.buffers.resize(this.cols, this.rows); @@ -540,8 +527,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II break; case 'screenReaderMode': if (value) { - if (!this._accessibilityManager) { - this._accessibilityManager = new AccessibilityManager(this); + if (!this._accessibilityManager && this._renderCoordinator) { + this._accessibilityManager = new AccessibilityManager(this, this._renderCoordinator.dimensions); } } else { if (this._accessibilityManager) { @@ -565,8 +552,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II break; } // Inform renderer of changes - if (this.renderer) { - this.renderer.onOptionsChanged(); + if (this._renderCoordinator) { + this._renderCoordinator.onOptionsChanged(); } } @@ -764,27 +751,27 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II this.options.theme = null; this._colorManager = new ColorManager(document, this.options.allowTransparency); this._colorManager.setTheme(this._theme); - this._setupRenderer(); - this._renderCoordinator = new RenderCoordinator(this.renderer, this.rows, this.screenElement); + const renderer = this._createRenderer(); + this._renderCoordinator = new RenderCoordinator(renderer, this.rows, this.screenElement); this._renderCoordinator.onRender(e => this._onRender.fire(e)); this.onResize(e => this._renderCoordinator.resize(e.cols, e.rows)); - this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this.charMeasure); + this.viewport = new Viewport(this, this._viewportElement, this._viewportScrollArea, this.charMeasure, this._renderCoordinator.dimensions); this.viewport.onThemeChange(this._colorManager.colors); this.register(this.viewport); - this.register(this.onCursorMove(() => this.renderer.onCursorMove())); - this.register(this.onResize(() => this.renderer.onResize(this.cols, this.rows))); - this.register(this.addDisposableListener('blur', () => this.renderer.onBlur())); - this.register(this.addDisposableListener('focus', () => this.renderer.onFocus())); - this.register(this.charMeasure.onCharSizeChanged(() => this.renderer.onCharSizeChanged())); - this.register(this._renderCoordinator.onCanvasResize(() => this.viewport.syncScrollArea())); + 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.charMeasure.onCharSizeChanged(() => this._renderCoordinator.onCharSizeChanged())); + this.register(this._renderCoordinator.onDimensionsChange(() => this.viewport.syncScrollArea())); this.selectionManager = new SelectionManager(this, this.charMeasure); 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.renderer.onSelectionChanged(e.start, e.end, e.columnSelectMode))); + this.register(this.selectionManager.onRedrawRequest(e => this._renderCoordinator.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 @@ -799,7 +786,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II })); this.register(addDisposableDomListener(this._viewportElement, 'scroll', () => this.selectionManager.refresh())); - this.mouseHelper = new MouseHelper(this.renderer); + this.mouseHelper = new MouseHelper(this._renderCoordinator); // apply mouse event classes set by escape codes before terminal was attached this.element.classList.toggle('enable-mouse-events', this.mouseEvents); if (this.mouseEvents) { @@ -811,8 +798,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._accessibilityManager.register(this._renderCoordinator.onCanvasResize(() => this._accessibilityManager.refreshRowsDimensions())); + this._accessibilityManager = new AccessibilityManager(this, this._renderCoordinator.dimensions); + this._accessibilityManager.register(this._renderCoordinator.onDimensionsChange(e => this._accessibilityManager.setDimensions(e))); } // Measure the character size @@ -830,17 +817,12 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II } - private _setupRenderer(): void { + private _createRenderer(): IRenderer { switch (this.options.rendererType) { - case 'canvas': this.renderer = new Renderer(this, this._colorManager.colors); break; - case 'dom': this.renderer = new DomRenderer(this, this._colorManager.colors); break; + case 'canvas': return new Renderer(this, this._colorManager.colors); break; + case 'dom': return new DomRenderer(this, this._colorManager.colors); break; default: throw new Error(`Unrecognized rendererType "${this.options.rendererType}"`); } - // TODO: Setting of renderer should be owned by RenderCoordinator - if (this._renderCoordinator) { - this._renderCoordinator.setRenderer(this.renderer); - } - this.register(this.renderer); } /** @@ -850,8 +832,8 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II private _setTheme(theme: ITheme): void { this._theme = theme; this._colorManager.setTheme(theme); - if (this.renderer) { - this.renderer.setColors(this._colorManager.colors); + if (this._renderCoordinator) { + this._renderCoordinator.setColors(this._colorManager.colors); } if (this.viewport) { this.viewport.onThemeChange(this._colorManager.colors); @@ -1593,13 +1575,13 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II } public registerCharacterJoiner(handler: CharacterJoinerHandler): number { - const joinerId = this.renderer.registerCharacterJoiner(handler); + const joinerId = this._renderCoordinator.registerCharacterJoiner(handler); this.refresh(0, this.rows - 1); return joinerId; } public deregisterCharacterJoiner(joinerId: number): void { - if (this.renderer.deregisterCharacterJoiner(joinerId)) { + if (this._renderCoordinator.deregisterCharacterJoiner(joinerId)) { this.refresh(0, this.rows - 1); } } diff --git a/src/Types.ts b/src/Types.ts index 30f943fe..4ab165c1 100644 --- a/src/Types.ts +++ b/src/Types.ts @@ -4,7 +4,6 @@ */ import { ITerminalOptions as IPublicTerminalOptions, IEventEmitter, IDisposable, IMarker, ISelectionPosition } from 'xterm'; -import { IRenderer } from './renderer/Types'; import { ICharset, IAttributeData, ICellData, IBufferLine, CharData } from './core/Types'; import { ICircularList } from './common/Types'; import { IEvent } from './common/EventEmitter2'; @@ -201,7 +200,6 @@ export interface ITerminal extends IPublicTerminal, IElementAccessor, IBufferAcc screenElement: HTMLElement; selectionManager: ISelectionManager; charMeasure: ICharMeasure; - renderer: IRenderer; browser: IBrowser; writeBuffer: string[]; cursorHidden: boolean; diff --git a/src/Viewport.ts b/src/Viewport.ts index e32113e1..e53c99ed 100644 --- a/src/Viewport.ts +++ b/src/Viewport.ts @@ -8,6 +8,7 @@ import { CharMeasure } from './CharMeasure'; import { Disposable } from './common/Lifecycle'; import { addDisposableDomListener } from './ui/Lifecycle'; import { IColorSet } from './ui/Types'; +import { IRenderDimensions } from './renderer/Types'; const FALLBACK_SCROLL_BAR_WIDTH = 15; @@ -43,7 +44,8 @@ export class Viewport extends Disposable implements IViewport { private _terminal: ITerminal, private _viewportElement: HTMLElement, private _scrollArea: HTMLElement, - private _charMeasure: CharMeasure + private _charMeasure: CharMeasure, + private _dimensions: IRenderDimensions ) { super(); @@ -57,6 +59,10 @@ export class Viewport extends Disposable implements IViewport { setTimeout(() => this.syncScrollArea(), 0); } + public onDimensionsChance(dimensions: IRenderDimensions): void { + this._dimensions = dimensions; + } + public onThemeChange(colors: IColorSet): void { this._viewportElement.style.backgroundColor = colors.background.css; } @@ -73,9 +79,9 @@ export class Viewport extends Disposable implements IViewport { private _innerRefresh(): void { if (this._charMeasure.height > 0) { - this._currentRowHeight = this._terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio; + this._currentRowHeight = this._dimensions.scaledCellHeight / window.devicePixelRatio; this._lastRecordedViewportHeight = this._viewportElement.offsetHeight; - const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._terminal.renderer.dimensions.canvasHeight); + const newBufferHeight = Math.round(this._currentRowHeight * this._lastRecordedBufferLength) + (this._lastRecordedViewportHeight - this._dimensions.canvasHeight); if (this._lastRecordedBufferHeight !== newBufferHeight) { this._lastRecordedBufferHeight = newBufferHeight; this._scrollArea.style.height = this._lastRecordedBufferHeight + 'px'; @@ -106,7 +112,7 @@ export class Viewport extends Disposable implements IViewport { } // If viewport height changed - if (this._lastRecordedViewportHeight !== (this._terminal).renderer.dimensions.canvasHeight) { + if (this._lastRecordedViewportHeight !== this._dimensions.canvasHeight) { this._refresh(); return; } @@ -125,7 +131,7 @@ export class Viewport extends Disposable implements IViewport { } // If row height changed - if (this._terminal.renderer.dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) { + if (this._dimensions.scaledCellHeight / window.devicePixelRatio !== this._currentRowHeight) { this._refresh(); return; } diff --git a/src/addons/fit/fit.ts b/src/addons/fit/fit.ts index ac978807..26f8752c 100644 --- a/src/addons/fit/fit.ts +++ b/src/addons/fit/fit.ts @@ -39,8 +39,8 @@ export function proposeGeometry(term: Terminal): IGeometry { const availableHeight = parentElementHeight - elementPaddingVer; const availableWidth = parentElementWidth - elementPaddingHor - (term)._core.viewport.scrollBarWidth; const geometry = { - cols: Math.floor(availableWidth / (term)._core.renderer.dimensions.actualCellWidth), - rows: Math.floor(availableHeight / (term)._core.renderer.dimensions.actualCellHeight) + cols: Math.floor(availableWidth / (term)._core._renderCoordinator.dimensions.actualCellWidth), + rows: Math.floor(availableHeight / (term)._core._renderCoordinator.dimensions.actualCellHeight) }; return geometry; } @@ -50,7 +50,7 @@ export function fit(term: Terminal): void { if (geometry) { // Force a full render if (term.rows !== geometry.rows || term.cols !== geometry.cols) { - (term)._core.renderer.clear(); + (term)._core._renderCoordinator.clear(); term.resize(geometry.cols, geometry.rows); } } diff --git a/src/renderer/RenderCoordinator.ts b/src/renderer/RenderCoordinator.ts index a843c19d..251af38f 100644 --- a/src/renderer/RenderCoordinator.ts +++ b/src/renderer/RenderCoordinator.ts @@ -3,12 +3,14 @@ * @license MIT */ -import { IRenderer } from './Types'; +import { IRenderer, IRenderDimensions } from './Types'; import { RenderDebouncer } from '../ui/RenderDebouncer'; import { EventEmitter2, IEvent } from '../common/EventEmitter2'; import { Disposable } from '../common/Lifecycle'; -import { ScreenDprMonitor } from '../../lib/ui/ScreenDprMonitor'; +import { ScreenDprMonitor } from '../ui/ScreenDprMonitor'; import { addDisposableDomListener } from '../ui/Lifecycle'; +import { IColorSet } from '..//ui/Types'; +import { CharacterJoinerHandler } from '../Types'; export class RenderCoordinator extends Disposable { private _renderDebouncer: RenderDebouncer; @@ -19,10 +21,14 @@ export class RenderCoordinator extends Disposable { private _canvasWidth: number = 0; private _canvasHeight: number = 0; - private _onCanvasResize = new EventEmitter2<{ width: number, height: number }>(); - public get onCanvasResize(): IEvent<{ width: number, height: number }> { return this._onCanvasResize.event; } + private _onDimensionsChange = new EventEmitter2(); + public get onDimensionsChange(): IEvent { return this._onDimensionsChange.event; } private _onRender = new EventEmitter2<{ start: number, end: number }>(); public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; } + private _onRefreshRequest = new EventEmitter2<{ start: number, end: number }>(); + public get onRefreshRequest(): IEvent<{ start: number, end: number }> { return this._onRefreshRequest.event; } + + public get dimensions(): IRenderDimensions { return this._renderer.dimensions; } constructor( private _renderer: IRenderer, @@ -86,15 +92,71 @@ export class RenderCoordinator extends Disposable { if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) { return; } - this._canvasWidth = this._renderer.dimensions.canvasWidth; - this._canvasHeight = this._renderer.dimensions.canvasHeight; - this._onCanvasResize.fire({ - width: this._canvasWidth, - height: this._canvasHeight - }); + this._onDimensionsChange.fire(this._renderer.dimensions); } public setRenderer(renderer: IRenderer): void { + // TODO: RenderCoordinator should be the only one to dispose the renderer + this._renderer.dispose(); this._renderer = renderer; } + + private _fullRefresh(): void { + if (this._isPaused) { + this._needsFullRefresh = true; + } else { + this.refreshRows(0, this._rowCount); + } + } + + public setColors(colors: IColorSet): void { + this._renderer.setColors(colors); + this._fullRefresh(); + } + + public onDevicePixelRatioChange(): void { + this._renderer.onDevicePixelRatioChange(); + } + + public onResize(cols: number, rows: number): void { + this._renderer.onResize(cols, rows); + this._fullRefresh(); + } + + // TODO: Is this useful when we have onResize? + public onCharSizeChanged(): void { + this._renderer.onCharSizeChanged(); + } + + public onBlur(): void { + this._renderer.onBlur(); + } + + public onFocus(): void { + this._renderer.onFocus(); + } + + public onSelectionChanged(start: [number, number], end: [number, number], columnSelectMode: boolean): void { + this._renderer.onSelectionChanged(start, end, columnSelectMode); + } + + public onCursorMove(): void { + this._renderer.onCursorMove(); + } + + public onOptionsChanged(): void { + this._renderer.onOptionsChanged(); + } + + public clear(): void { + this._renderer.clear(); + } + + public registerCharacterJoiner(handler: CharacterJoinerHandler): number { + return this._renderer.registerCharacterJoiner(handler); + } + + public deregisterCharacterJoiner(joinerId: number): boolean { + return this._renderer.deregisterCharacterJoiner(joinerId); + } } diff --git a/src/renderer/Renderer.ts b/src/renderer/Renderer.ts index 08586b16..b3b93ca7 100644 --- a/src/renderer/Renderer.ts +++ b/src/renderer/Renderer.ts @@ -75,8 +75,6 @@ export class Renderer extends Disposable implements IRenderer { l.setColors(this._terminal, this._colors); l.reset(this._terminal); }); - - this._terminal.refresh(0, this._terminal.rows - 1); } public onResize(cols: number, rows: number): void { @@ -86,9 +84,6 @@ export class Renderer extends Disposable implements IRenderer { // Resize all render layers this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions)); - // Force a refresh - this._terminal.refresh(0, this._terminal.rows - 1); - // Resize the screen this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth}px`; this._terminal.screenElement.style.height = `${this.dimensions.canvasHeight}px`; diff --git a/src/renderer/Types.ts b/src/renderer/Types.ts index c4028d6c..c9881ae4 100644 --- a/src/renderer/Types.ts +++ b/src/renderer/Types.ts @@ -25,7 +25,20 @@ export const enum FLAGS { * rendering rows to the screen. */ export interface IRenderer extends IDisposable { - dimensions: IRenderDimensions; + readonly dimensions: IRenderDimensions; + + /** + * A property that is set by consumers of this interface, this will be set to true when the + * terminal is completely offscreen and to false when it comes back on. When true the consumer of + * the renderer will not trigger `renderRows`, the renderer should disable code in functions other + * than `renderRows` that renders to the screen but it should continue to gather state changes. + * When the renderer is unpaused, a full `renderRows` will be triggered if it was called while + * paused. + * + * For example, when `isPaused` is `true`, `IRenderer.onBlur` should record the state change, but + * not actually draw the blurred cursor. + */ + // isPaused: boolean; dispose(): void; setColors(colors: IColorSet): void;