Skip to content

Commit

Permalink
Support pausing in RenderCoordinator
Browse files Browse the repository at this point in the history
This actually removes the pause rendering functionality when the resize
and theme changes but simplifies it as a result, they also rarely happen
especially when off screen/hidden.

Fixes xtermjs#2099
  • Loading branch information
Tyriar committed May 19, 2019
1 parent 72e6863 commit 87dca56
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 38 deletions.
2 changes: 1 addition & 1 deletion src/Terminal.ts
Expand Up @@ -766,7 +766,7 @@ export class Terminal extends EventEmitter implements ITerminal, IDisposable, II
this._colorManager.setTheme(this._theme);
this._setupRenderer();

this._renderCoordinator = new RenderCoordinator(this.renderer, this.rows);
this._renderCoordinator = new RenderCoordinator(this.renderer, this.rows, this.screenElement);
this._renderCoordinator.onRender(e => this._onRender.fire(e));
this.onResize(e => this._renderCoordinator.resize(e.cols, e.rows));

Expand Down
31 changes: 27 additions & 4 deletions src/renderer/RenderCoordinator.ts
Expand Up @@ -14,17 +14,20 @@ export class RenderCoordinator extends Disposable {
private _renderDebouncer: RenderDebouncer;
private _screenDprMonitor: ScreenDprMonitor;

private _isPaused: boolean = false;
private _needsFullRefresh: boolean = false;
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 _onRender = new EventEmitter2<{ start: number, end: number }>();
public get onRender(): IEvent<{ start: number, end: number }> { return this._onRender.event; }

private _canvasWidth: number = 0;
private _canvasHeight: number = 0;

constructor(
private _renderer: IRenderer,
private _rowCount: number
private _rowCount: number,
screenElement: HTMLElement
) {
super();
this._renderDebouncer = new RenderDebouncer((start, end) => this._renderRows(start, end));
Expand All @@ -37,9 +40,29 @@ export class RenderCoordinator extends Disposable {
// dprchange should handle this case, we need this as well for browsers that don't support the
// matchMedia query.
this.register(addDisposableDomListener(window, 'resize', () => this._renderer.onDevicePixelRatioChange()));

// Detect whether IntersectionObserver is detected and enable renderer pause
// and resume based on terminal visibility if so
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(e => this._onIntersectionChange(e[e.length - 1]), { threshold: 0 });
observer.observe(screenElement);
this.register({ dispose: () => observer.disconnect() });
}
}

private _onIntersectionChange(entry: IntersectionObserverEntry): void {
this._isPaused = entry.intersectionRatio === 0;
if (!this._isPaused && this._needsFullRefresh) {
this.refreshRows(0, this._rowCount - 1);
this._needsFullRefresh = false;
}
}

public refreshRows(start: number, end: number): void {
if (this._isPaused) {
this._needsFullRefresh = true;
return;
}
this._renderDebouncer.refresh(start, end, this._rowCount);
}

Expand Down
36 changes: 3 additions & 33 deletions src/renderer/Renderer.ts
Expand Up @@ -16,8 +16,6 @@ import { IColorSet } from '../ui/Types';
export class Renderer extends Disposable implements IRenderer {
private _renderLayers: IRenderLayer[];
private _devicePixelRatio: number;
private _isPaused: boolean = false;
private _needsFullRefresh: boolean = false;
private _characterJoinerRegistry: ICharacterJoinerRegistry;

public dimensions: IRenderDimensions;
Expand Down Expand Up @@ -53,29 +51,13 @@ export class Renderer extends Disposable implements IRenderer {
this._devicePixelRatio = window.devicePixelRatio;
this._updateDimensions();
this.onOptionsChanged();

// Detect whether IntersectionObserver is detected and enable renderer pause
// and resume based on terminal visibility if so
if ('IntersectionObserver' in window) {
const observer = new IntersectionObserver(e => this.onIntersectionChange(e[e.length - 1]), { threshold: 0 });
observer.observe(this._terminal.element);
this.register({ dispose: () => observer.disconnect() });
}
}

public dispose(): void {
super.dispose();
this._renderLayers.forEach(l => l.dispose());
}

public onIntersectionChange(entry: IntersectionObserverEntry): void {
this._isPaused = entry.intersectionRatio === 0;
if (!this._isPaused && this._needsFullRefresh) {
this._terminal.refresh(0, this._terminal.rows - 1);
this._needsFullRefresh = false;
}
}

public onDevicePixelRatioChange(): void {
// If the device pixel ratio changed, the char atlas needs to be regenerated
// and the terminal needs to refreshed
Expand All @@ -94,11 +76,7 @@ export class Renderer extends Disposable implements IRenderer {
l.reset(this._terminal);
});

if (this._isPaused) {
this._needsFullRefresh = true;
} else {
this._terminal.refresh(0, this._terminal.rows - 1);
}
this._terminal.refresh(0, this._terminal.rows - 1);
}

public onResize(cols: number, rows: number): void {
Expand All @@ -109,11 +87,7 @@ export class Renderer extends Disposable implements IRenderer {
this._renderLayers.forEach(l => l.resize(this._terminal, this.dimensions));

// Force a refresh
if (this._isPaused) {
this._needsFullRefresh = true;
} else {
this._terminal.refresh(0, this._terminal.rows - 1);
}
this._terminal.refresh(0, this._terminal.rows - 1);

// Resize the screen
this._terminal.screenElement.style.width = `${this.dimensions.canvasWidth}px`;
Expand Down Expand Up @@ -149,11 +123,7 @@ export class Renderer extends Disposable implements IRenderer {
}

private _runOperation(operation: (layer: IRenderLayer) => void): void {
if (this._isPaused) {
this._needsFullRefresh = true;
} else {
this._renderLayers.forEach(l => operation(l));
}
this._renderLayers.forEach(l => operation(l));
}

/**
Expand Down

0 comments on commit 87dca56

Please sign in to comment.