Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes vscode #200469 #4912

Merged
merged 6 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
15 changes: 13 additions & 2 deletions addons/addon-canvas/src/CanvasRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { ICharSizeService, ICharacterJoinerService, ICoreBrowserService, IThemeS
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
import { Disposable, toDisposable } from 'common/Lifecycle';
import { IBufferService, ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from '@xterm/xterm';
import { IDisposable, Terminal } from '@xterm/xterm';
import { CursorRenderLayer } from './CursorRenderLayer';
import { LinkRenderLayer } from './LinkRenderLayer';
import { SelectionRenderLayer } from './SelectionRenderLayer';
Expand All @@ -22,6 +22,7 @@ import { IRenderLayer } from './Types';
export class CanvasRenderer extends Disposable implements IRenderer {
private _renderLayers: IRenderLayer[];
private _devicePixelRatio: number;
private _observerDisposable: IDisposable | undefined;
jeanp413 marked this conversation as resolved.
Show resolved Hide resolved

public dimensions: IRenderDimensions;

Expand Down Expand Up @@ -60,7 +61,12 @@ export class CanvasRenderer extends Disposable implements IRenderer {
this._devicePixelRatio = this._coreBrowserService.dpr;
this._updateDimensions();

this.register(observeDevicePixelDimensions(this._renderLayers[0].canvas, this._coreBrowserService.window, (w, h) => this._setCanvasDevicePixelDimensions(w, h)));
this._observerDisposable = observeDevicePixelDimensions(this._renderLayers[0].canvas, this._coreBrowserService.window, (w, h) => this._setCanvasDevicePixelDimensions(w, h));
this.register(this._coreBrowserService.onWindowChange(w => {
this._observerDisposable?.dispose();
this._observerDisposable = observeDevicePixelDimensions(this._renderLayers[0].canvas, w, (w, h) => this._setCanvasDevicePixelDimensions(w, h));
}));

this.register(toDisposable(() => {
for (const l of this._renderLayers) {
l.dispose();
Expand Down Expand Up @@ -183,4 +189,9 @@ export class CanvasRenderer extends Disposable implements IRenderer {
private _requestRedrawViewport(): void {
this._onRequestRedraw.fire({ start: 0, end: this._bufferService.rows - 1 });
}

public override dispose(): void {
this._observerDisposable?.dispose();
super.dispose();
}
}
14 changes: 12 additions & 2 deletions addons/addon-webgl/src/WebglRenderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import { AttributeData } from 'common/buffer/AttributeData';
import { CellData } from 'common/buffer/CellData';
import { Attributes, Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
import { ICoreService, IDecorationService, IOptionsService } from 'common/services/Services';
import { Terminal } from '@xterm/xterm';
import { IDisposable, Terminal } from '@xterm/xterm';
import { GlyphRenderer } from './GlyphRenderer';
import { RectangleRenderer } from './RectangleRenderer';
import { COMBINED_CHAR_BIT_MASK, RENDER_MODEL_BG_OFFSET, RENDER_MODEL_EXT_OFFSET, RENDER_MODEL_FG_OFFSET, RENDER_MODEL_INDICIES_PER_CELL, RenderModel } from './RenderModel';
Expand All @@ -33,6 +33,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
private _charAtlasDisposable = this.register(new MutableDisposable());
private _charAtlas: ITextureAtlas | undefined;
private _devicePixelRatio: number;
private _observerDisposable: IDisposable | undefined;
jeanp413 marked this conversation as resolved.
Show resolved Hide resolved

private _model: RenderModel = new RenderModel();
private _workCell: CellData = new CellData();
Expand Down Expand Up @@ -123,7 +124,11 @@ export class WebglRenderer extends Disposable implements IRenderer {
this._requestRedrawViewport();
}));

this.register(observeDevicePixelDimensions(this._canvas, this._coreBrowserService.window, (w, h) => this._setCanvasDevicePixelDimensions(w, h)));
this._observerDisposable = observeDevicePixelDimensions(this._canvas, this._coreBrowserService.window, (w, h) => this._setCanvasDevicePixelDimensions(w, h));
this.register(this._coreBrowserService.onWindowChange(w => {
this._observerDisposable?.dispose();
this._observerDisposable = observeDevicePixelDimensions(this._canvas, w, (w, h) => this._setCanvasDevicePixelDimensions(w, h));
}));

this._core.screenElement!.appendChild(this._canvas);

Expand Down Expand Up @@ -594,6 +599,11 @@ export class WebglRenderer extends Disposable implements IRenderer {
const cursorY = this._terminal.buffer.active.cursorY;
this._onRequestRedraw.fire({ start: cursorY, end: cursorY });
}

public override dispose(): void {
this._observerDisposable?.dispose();
super.dispose();
}
}

// TODO: Share impl with core
Expand Down
11 changes: 6 additions & 5 deletions src/browser/RenderDebouncer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/

import { IRenderDebouncerWithCallback } from 'browser/Types';
import { ICoreBrowserService } from 'browser/services/Services';

/**
* Debounces calls to render terminal rows using animation frames.
Expand All @@ -16,22 +17,22 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback {
private _refreshCallbacks: FrameRequestCallback[] = [];

constructor(
private _parentWindow: Window,
private _renderCallback: (start: number, end: number) => void
private _renderCallback: (start: number, end: number) => void,
private readonly _coreBrowserService: ICoreBrowserService
) {
}

public dispose(): void {
if (this._animationFrame) {
this._parentWindow.cancelAnimationFrame(this._animationFrame);
this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame);
this._animationFrame = undefined;
}
}

public addRefreshCallback(callback: FrameRequestCallback): number {
this._refreshCallbacks.push(callback);
if (!this._animationFrame) {
this._animationFrame = this._parentWindow.requestAnimationFrame(() => this._innerRefresh());
this._animationFrame = this._coreBrowserService.window.requestAnimationFrame(() => this._innerRefresh());
}
return this._animationFrame;
}
Expand All @@ -49,7 +50,7 @@ export class RenderDebouncer implements IRenderDebouncerWithCallback {
return;
}

this._animationFrame = this._parentWindow.requestAnimationFrame(() => this._innerRefresh());
this._animationFrame = this._coreBrowserService.window.requestAnimationFrame(() => this._innerRefresh());
}

private _innerRefresh(): void {
Expand Down
28 changes: 20 additions & 8 deletions src/browser/services/RenderService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
* @license MIT
*/

import { IDisposable } from 'common/Types';
import { RenderDebouncer } from 'browser/RenderDebouncer';
import { IRenderDebouncerWithCallback } from 'browser/Types';
import { IRenderDimensions, IRenderer } from 'browser/renderer/shared/Types';
import { ICharSizeService, ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
import { EventEmitter } from 'common/EventEmitter';
import { Disposable, MutableDisposable } from 'common/Lifecycle';
import { Disposable, MutableDisposable, toDisposable } from 'common/Lifecycle';
import { DebouncedIdleTask } from 'common/TaskQueue';
import { IBufferService, IDecorationService, IInstantiationService, IOptionsService } from 'common/services/Services';
import { IBufferService, IDecorationService, IOptionsService } from 'common/services/Services';

interface ISelectionState {
start: [number, number] | undefined;
Expand All @@ -24,6 +25,7 @@ export class RenderService extends Disposable implements IRenderService {
private _renderer: MutableDisposable<IRenderer> = this.register(new MutableDisposable());
private _renderDebouncer: IRenderDebouncerWithCallback;
private _pausedResizeTask = new DebouncedIdleTask();
private _observerDisposable: IDisposable | undefined;
jeanp413 marked this conversation as resolved.
Show resolved Hide resolved

private _isPaused: boolean = false;
private _needsFullRefresh: boolean = false;
Expand All @@ -38,7 +40,7 @@ export class RenderService extends Disposable implements IRenderService {
};

private readonly _onDimensionsChange = this.register(new EventEmitter<IRenderDimensions>());
public readonly onDimensionsChange = this._onDimensionsChange.event;
public readonly onDimensionsChange = this._onDimensionsChange.event;
private readonly _onRenderedViewportChange = this.register(new EventEmitter<{ start: number, end: number }>());
public readonly onRenderedViewportChange = this._onRenderedViewportChange.event;
private readonly _onRender = this.register(new EventEmitter<{ start: number, end: number }>());
Expand All @@ -56,12 +58,11 @@ export class RenderService extends Disposable implements IRenderService {
@IDecorationService decorationService: IDecorationService,
@IBufferService bufferService: IBufferService,
@ICoreBrowserService coreBrowserService: ICoreBrowserService,
@IInstantiationService instantiationService: IInstantiationService,
@IThemeService themeService: IThemeService
) {
super();

this._renderDebouncer = new RenderDebouncer(coreBrowserService.window, (start, end) => this._renderRows(start, end));
this._renderDebouncer = new RenderDebouncer((start, end) => this._renderRows(start, end), coreBrowserService);
this.register(this._renderDebouncer);

this.register(coreBrowserService.onDprChange(() => this.handleDevicePixelRatioChange()));
Expand Down Expand Up @@ -102,12 +103,18 @@ export class RenderService extends Disposable implements IRenderService {

this.register(themeService.onChangeColors(() => this._fullRefresh()));

this._registerIntersectionObserver(coreBrowserService.window, screenElement);
this.register(coreBrowserService.onWindowChange((w) => this._registerIntersectionObserver(w, screenElement)));
}

private _registerIntersectionObserver(w: Window & typeof globalThis, screenElement: HTMLElement): void {
// Detect whether IntersectionObserver is detected and enable renderer pause
// and resume based on terminal visibility if so
if ('IntersectionObserver' in coreBrowserService.window) {
const observer = new coreBrowserService.window.IntersectionObserver(e => this._handleIntersectionChange(e[e.length - 1]), { threshold: 0 });
this._observerDisposable?.dispose();
if ('IntersectionObserver' in w) {
const observer = new w.IntersectionObserver(e => this._handleIntersectionChange(e[e.length - 1]), { threshold: 0 });
observer.observe(screenElement);
this.register({ dispose: () => observer.disconnect() });
this._observerDisposable = toDisposable(() => observer.disconnect());
}
}

Expand Down Expand Up @@ -276,4 +283,9 @@ export class RenderService extends Disposable implements IRenderService {
public clear(): void {
this._renderer.value?.clear();
}

public override dispose(): void {
this._observerDisposable?.dispose();
super.dispose();
}
}