1
1
import { bind } from 'decko' ;
2
2
import { Component , h } from 'preact' ;
3
- import { ITerminalOptions , RendererType , Terminal } from 'xterm' ;
4
- import { FitAddon } from 'xterm-addon-fit ' ;
3
+ import { ITerminalOptions , Terminal } from 'xterm' ;
4
+ import { CanvasAddon } from 'xterm-addon-canvas ' ;
5
5
import { WebglAddon } from 'xterm-addon-webgl' ;
6
+ import { FitAddon } from 'xterm-addon-fit' ;
6
7
import { WebLinksAddon } from 'xterm-addon-web-links' ;
7
8
import { ImageAddon } from 'xterm-addon-image' ;
8
9
import { OverlayAddon } from './overlay' ;
@@ -36,8 +37,10 @@ const enum Command {
36
37
RESUME = '3' ,
37
38
}
38
39
40
+ export type RendererType = 'dom' | 'canvas' | 'webgl' ;
41
+
39
42
export interface ClientOptions {
40
- rendererType : 'dom' | 'canvas' | 'webgl' ;
43
+ rendererType : RendererType ;
41
44
disableLeaveAlert : boolean ;
42
45
disableResizeOverlay : boolean ;
43
46
titleFixed : string ;
@@ -61,6 +64,7 @@ export class Xterm extends Component<Props> {
61
64
private overlayAddon : OverlayAddon ;
62
65
private zmodemAddon : ZmodemAddon ;
63
66
private webglAddon : WebglAddon ;
67
+ private canvasAddon : CanvasAddon ;
64
68
65
69
private socket : WebSocket ;
66
70
private token : string ;
@@ -212,9 +216,16 @@ export class Xterm extends Component<Props> {
212
216
}
213
217
214
218
@bind
215
- private setRendererType ( value : 'webgl' | RendererType ) {
219
+ private setRendererType ( value : RendererType ) {
216
220
const { terminal } = this ;
217
-
221
+ const disposeCanvasRenderer = ( ) => {
222
+ try {
223
+ this . canvasAddon ?. dispose ( ) ;
224
+ } catch {
225
+ // ignore
226
+ }
227
+ this . canvasAddon = undefined ;
228
+ } ;
218
229
const disposeWebglRenderer = ( ) => {
219
230
try {
220
231
this . webglAddon ?. dispose ( ) ;
@@ -223,33 +234,50 @@ export class Xterm extends Component<Props> {
223
234
}
224
235
this . webglAddon = undefined ;
225
236
} ;
237
+ const enableCanvasRenderer = ( ) => {
238
+ if ( this . canvasAddon ) return ;
239
+ this . canvasAddon = new CanvasAddon ( ) ;
240
+ disposeWebglRenderer ( ) ;
241
+ try {
242
+ this . terminal . loadAddon ( this . canvasAddon ) ;
243
+ console . log ( `[ttyd] canvas renderer loaded` ) ;
244
+ } catch ( e ) {
245
+ console . log ( `[ttyd] canvas renderer could not be loaded, falling back to dom renderer` , e ) ;
246
+ disposeCanvasRenderer ( ) ;
247
+ }
248
+ } ;
249
+ const enableWebglRenderer = ( ) => {
250
+ if ( this . webglAddon ) return ;
251
+ this . webglAddon = new WebglAddon ( ) ;
252
+ disposeCanvasRenderer ( ) ;
253
+ try {
254
+ this . webglAddon . onContextLoss ( ( ) => {
255
+ this . webglAddon ?. dispose ( ) ;
256
+ } ) ;
257
+ terminal . loadAddon ( this . webglAddon ) ;
258
+ console . log ( `[ttyd] WebGL renderer loaded` ) ;
259
+ } catch ( e ) {
260
+ console . log ( `[ttyd] WebGL renderer could not be loaded, falling back to canvas renderer` , e ) ;
261
+ disposeWebglRenderer ( ) ;
262
+ enableCanvasRenderer ( ) ;
263
+ }
264
+ } ;
226
265
227
266
switch ( value ) {
267
+ case 'canvas' :
268
+ enableCanvasRenderer ( ) ;
269
+ break ;
228
270
case 'webgl' :
229
- if ( this . webglAddon ) return ;
230
- try {
231
- if ( window . WebGL2RenderingContext && document . createElement ( 'canvas' ) . getContext ( 'webgl2' ) ) {
232
- this . webglAddon = new WebglAddon ( ) ;
233
- this . webglAddon . onContextLoss ( ( ) => {
234
- disposeWebglRenderer ( ) ;
235
- } ) ;
236
- terminal . loadAddon ( this . webglAddon ) ;
237
- console . log ( `[ttyd] WebGL renderer enabled` ) ;
238
- }
239
- } catch ( e ) {
240
- console . warn ( `[ttyd] webgl2 init error` , e ) ;
241
- }
271
+ enableWebglRenderer ( ) ;
242
272
break ;
273
+ case 'dom' :
243
274
default :
244
- disposeWebglRenderer ( ) ;
245
- console . log ( `[ttyd] option: rendererType=${ value } ` ) ;
246
- terminal . options . rendererType = value ;
247
275
break ;
248
276
}
249
277
}
250
278
251
279
@bind
252
- private applyOptions ( options : any ) {
280
+ private applyOptions ( options : ITerminalOptions ) {
253
281
const { terminal, fitAddon } = this ;
254
282
255
283
Object . keys ( options ) . forEach ( key => {
@@ -373,7 +401,8 @@ export class Xterm extends Component<Props> {
373
401
break ;
374
402
case Command . SET_PREFERENCES :
375
403
const prefs = JSON . parse ( textDecoder . decode ( data ) ) ;
376
- this . applyOptions ( Object . assign ( { } , this . props . clientOptions , prefs ) ) ;
404
+ const options = Object . assign ( { } , this . props . clientOptions , prefs ) as ITerminalOptions ;
405
+ this . applyOptions ( options ) ;
377
406
break ;
378
407
default :
379
408
console . warn ( `[ttyd] unknown command: ${ cmd } ` ) ;
0 commit comments