From fa7889cdd02436f40e1c581f135900d5fedb9f21 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 1 Apr 2021 12:17:34 -0700 Subject: [PATCH 1/4] add onRecovercontext event --- addons/xterm-addon-webgl/src/WebglAddon.ts | 6 +++++- addons/xterm-addon-webgl/src/WebglRenderer.ts | 12 ++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index aef1301e56..8eeda832ea 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -3,14 +3,17 @@ * @license MIT */ -import { Terminal, ITerminalAddon } from 'xterm'; +import { Terminal, ITerminalAddon, IEvent } from 'xterm'; import { WebglRenderer } from './WebglRenderer'; import { IRenderService } from 'browser/services/Services'; import { IColorSet } from 'browser/Types'; +import { EventEmitter } from 'common/EventEmitter'; export class WebglAddon implements ITerminalAddon { private _terminal?: Terminal; private _renderer?: WebglRenderer; + private _onRecoverContext = new EventEmitter(); + public get onRecoverContext(): IEvent { return this._onRecoverContext.event; } constructor( private _preserveDrawingBuffer?: boolean @@ -24,6 +27,7 @@ export class WebglAddon implements ITerminalAddon { const renderService: IRenderService = (terminal)._core._renderService; const colors: IColorSet = (terminal)._core._colorManager.colors; this._renderer = new WebglRenderer(terminal, colors, this._preserveDrawingBuffer); + this._renderer.onRecoverContext(() => this._onRecoverContext.fire()); renderService.setRenderer(this._renderer); } diff --git a/addons/xterm-addon-webgl/src/WebglRenderer.ts b/addons/xterm-addon-webgl/src/WebglRenderer.ts index fecd57429c..86e2900d39 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -19,6 +19,7 @@ import { IRenderDimensions, IRenderer, IRequestRedrawEvent } from 'browser/rende import { ITerminal, IColorSet } from 'browser/Types'; import { EventEmitter } from 'common/EventEmitter'; import { CellData } from 'common/buffer/CellData'; +import { addDisposableDomListener } from 'browser/Lifecycle'; export class WebglRenderer extends Disposable implements IRenderer { private _renderLayers: IRenderLayer[]; @@ -41,6 +42,9 @@ export class WebglRenderer extends Disposable implements IRenderer { private _onRequestRedraw = new EventEmitter(); public get onRequestRedraw(): IEvent { return this._onRequestRedraw.event; } + private _onRecoverContext = new EventEmitter(); + public get onRecoverContext(): IEvent { return this._onRecoverContext.event; } + constructor( private _terminal: Terminal, private _colors: IColorSet, @@ -82,6 +86,9 @@ export class WebglRenderer extends Disposable implements IRenderer { if (!this._gl) { throw new Error('WebGL2 not supported ' + this._gl); } + + this.register(addDisposableDomListener(this._canvas, 'webglcontextlost', (e) => { this._onContextLost(e); })); + this._core.screenElement!.appendChild(this._canvas); this._rectangleRenderer = new RectangleRenderer(this._terminal, this._colors, this._gl, this.dimensions); @@ -93,6 +100,11 @@ export class WebglRenderer extends Disposable implements IRenderer { this._isAttached = document.body.contains(this._core.screenElement!); } + private _onContextLost(e: Event): void { + e.preventDefault(); + this._onRecoverContext.fire(); + } + public dispose(): void { for (const l of this._renderLayers) { l.dispose(); From b1877b4dc7b903fabaf9edbba116887ce0e83474 Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 1 Apr 2021 13:32:35 -0700 Subject: [PATCH 2/4] onRecoverContext -> onContextLoss --- addons/xterm-addon-webgl/src/WebglAddon.ts | 6 +++--- addons/xterm-addon-webgl/src/WebglRenderer.ts | 11 +++-------- 2 files changed, 6 insertions(+), 11 deletions(-) diff --git a/addons/xterm-addon-webgl/src/WebglAddon.ts b/addons/xterm-addon-webgl/src/WebglAddon.ts index 8eeda832ea..c07bc0d707 100644 --- a/addons/xterm-addon-webgl/src/WebglAddon.ts +++ b/addons/xterm-addon-webgl/src/WebglAddon.ts @@ -12,8 +12,8 @@ import { EventEmitter } from 'common/EventEmitter'; export class WebglAddon implements ITerminalAddon { private _terminal?: Terminal; private _renderer?: WebglRenderer; - private _onRecoverContext = new EventEmitter(); - public get onRecoverContext(): IEvent { return this._onRecoverContext.event; } + private _onContextLoss = new EventEmitter(); + public get onContextLoss(): IEvent { return this._onContextLoss.event; } constructor( private _preserveDrawingBuffer?: boolean @@ -27,7 +27,7 @@ export class WebglAddon implements ITerminalAddon { const renderService: IRenderService = (terminal)._core._renderService; const colors: IColorSet = (terminal)._core._colorManager.colors; this._renderer = new WebglRenderer(terminal, colors, this._preserveDrawingBuffer); - this._renderer.onRecoverContext(() => this._onRecoverContext.fire()); + 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 86e2900d39..08f83b523d 100644 --- a/addons/xterm-addon-webgl/src/WebglRenderer.ts +++ b/addons/xterm-addon-webgl/src/WebglRenderer.ts @@ -42,8 +42,8 @@ export class WebglRenderer extends Disposable implements IRenderer { private _onRequestRedraw = new EventEmitter(); public get onRequestRedraw(): IEvent { return this._onRequestRedraw.event; } - private _onRecoverContext = new EventEmitter(); - public get onRecoverContext(): IEvent { return this._onRecoverContext.event; } + private _onContextLoss = new EventEmitter(); + public get onContextLoss(): IEvent { return this._onContextLoss.event; } constructor( private _terminal: Terminal, @@ -87,7 +87,7 @@ export class WebglRenderer extends Disposable implements IRenderer { throw new Error('WebGL2 not supported ' + this._gl); } - this.register(addDisposableDomListener(this._canvas, 'webglcontextlost', (e) => { this._onContextLost(e); })); + this.register(addDisposableDomListener(this._canvas, 'webglcontextlost', (e) => { this._onContextLoss.fire(e); })); this._core.screenElement!.appendChild(this._canvas); @@ -100,11 +100,6 @@ export class WebglRenderer extends Disposable implements IRenderer { this._isAttached = document.body.contains(this._core.screenElement!); } - private _onContextLost(e: Event): void { - e.preventDefault(); - this._onRecoverContext.fire(); - } - public dispose(): void { for (const l of this._renderLayers) { l.dispose(); From c5339116b5685042afaed3fb31cd7114fc0a094f Mon Sep 17 00:00:00 2001 From: Daniel Imms <2193314+Tyriar@users.noreply.github.com> Date: Thu, 1 Apr 2021 15:45:10 -0700 Subject: [PATCH 3/4] Add note to readme on handling context loss --- addons/xterm-addon-webgl/README.md | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/addons/xterm-addon-webgl/README.md b/addons/xterm-addon-webgl/README.md index 756999db5d..7927a5138f 100644 --- a/addons/xterm-addon-webgl/README.md +++ b/addons/xterm-addon-webgl/README.md @@ -19,3 +19,18 @@ terminal.loadAddon(new WebglAddon()); ``` See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts) for more advanced usage. + +### Handling Context Loss + +The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event fires on the canvas so embedders can handle it however they wish. An easy way but suboptimal way to handle this is by disposing of WebglAddon when the event fires: + +```ts +const terminal = new Terminal(); +const addon = new WebglAddon(); +addon.onContextLoss(e => { + addon.dispose(); +}); +terminal.loadAddon(addon); +``` + +Read more about handling WebGL context losses on the [Khronos wiki](https://www.khronos.org/webgl/wiki/HandlingContextLost). From 113086f97ad767d0d78a7fdd2b0e25a09c69534b Mon Sep 17 00:00:00 2001 From: meganrogge Date: Thu, 1 Apr 2021 16:57:19 -0700 Subject: [PATCH 4/4] tweak readme, expose API --- addons/xterm-addon-webgl/README.md | 2 +- addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts | 6 ++++++ 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/addons/xterm-addon-webgl/README.md b/addons/xterm-addon-webgl/README.md index 7927a5138f..67fafe7bf8 100644 --- a/addons/xterm-addon-webgl/README.md +++ b/addons/xterm-addon-webgl/README.md @@ -22,7 +22,7 @@ See the full [API](https://github.com/xtermjs/xterm.js/blob/master/addons/xterm- ### Handling Context Loss -The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event fires on the canvas so embedders can handle it however they wish. An easy way but suboptimal way to handle this is by disposing of WebglAddon when the event fires: +The browser may drop WebGL contexts for various reasons like OOM or after the system has been suspended. There is an API exposed that fires the `webglcontextlost` event fired on the canvas so embedders can handle it however they wish. An easy, but suboptimal way, to handle this is by disposing of WebglAddon when the event fires: ```ts const terminal = new Terminal(); diff --git a/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts b/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts index 5c15aa1784..d95d896170 100644 --- a/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts +++ b/addons/xterm-addon-webgl/typings/xterm-addon-webgl.d.ts @@ -3,6 +3,7 @@ * @license MIT */ +import { IEvent } from 'node-pty'; import { Terminal, ITerminalAddon } from 'xterm'; declare module 'xterm-addon-webgl' { @@ -29,5 +30,10 @@ declare module 'xterm-addon-webgl' { * Clears the terminal's texture atlas and triggers a redraw. */ public clearTextureAtlas(): void; + + /** + * Fired when the WebglRenderer loses context + */ + public get onContextLoss(): IEvent; } }