Skip to content

Commit 5956c25

Browse files
committed
webgl, fallback to canvas renderer
1 parent 7e4c781 commit 5956c25

4 files changed

Lines changed: 69 additions & 42 deletions

File tree

frontend/app/view/term/term-model.ts

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ export class TermViewModel implements ViewModel {
155155
if (isCmd) {
156156
const blockMeta = get(this.blockAtom)?.meta;
157157
let cmdText = blockMeta?.["cmd"];
158-
let cmdArgs = blockMeta?.["cmd:args"];
158+
const cmdArgs = blockMeta?.["cmd:args"];
159159
if (cmdArgs != null && Array.isArray(cmdArgs) && cmdArgs.length > 0) {
160160
cmdText += " " + cmdArgs.join(" ");
161161
}
@@ -242,7 +242,7 @@ export class TermViewModel implements ViewModel {
242242
});
243243
this.termTransparencyAtom = useBlockAtom(blockId, "termtransparencyatom", () => {
244244
return jotai.atom<number>((get) => {
245-
let value = get(getOverrideConfigAtom(this.blockId, "term:transparency")) ?? 0.5;
245+
const value = get(getOverrideConfigAtom(this.blockId, "term:transparency")) ?? 0.5;
246246
return boundNumber(value, 0, 1);
247247
});
248248
});
@@ -517,6 +517,10 @@ export class TermViewModel implements ViewModel {
517517
});
518518
}
519519

520+
getTermRenderer(): "webgl" | "canvas" {
521+
return this.termRef.current?.getTermRenderer() ?? "canvas";
522+
}
523+
520524
isWebGlEnabled(): boolean {
521525
return this.termRef.current?.isWebGlEnabled() ?? false;
522526
}
@@ -525,11 +529,8 @@ export class TermViewModel implements ViewModel {
525529
if (!this.termRef.current) {
526530
return;
527531
}
528-
if (this.termRef.current.isWebGlEnabled()) {
529-
this.termRef.current.disableWebGl();
530-
} else {
531-
this.termRef.current.enableWebGl();
532-
}
532+
const renderer = this.termRef.current.getTermRenderer() === "webgl" ? "canvas" : "webgl";
533+
this.termRef.current.setTermRenderer(renderer);
533534
}
534535

535536
triggerRestartAtom() {
@@ -598,7 +599,7 @@ export class TermViewModel implements ViewModel {
598599
console.log("search is open, not giving focus");
599600
return true;
600601
}
601-
let termMode = globalStore.get(this.termMode);
602+
const termMode = globalStore.get(this.termMode);
602603
if (termMode == "term") {
603604
if (this.termRef?.current?.terminal) {
604605
this.termRef.current.terminal.focus();

frontend/app/view/term/termwrap.ts

Lines changed: 49 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
import * as services from "@/store/services";
1919
import { PLATFORM, PlatformMacOS } from "@/util/platformutil";
2020
import { base64ToArray, fireAndForget } from "@/util/util";
21+
import { CanvasAddon } from "@xterm/addon-canvas";
2122
import { SearchAddon } from "@xterm/addon-search";
2223
import { SerializeAddon } from "@xterm/addon-serialize";
2324
import { WebLinksAddon } from "@xterm/addon-web-links";
@@ -86,6 +87,7 @@ export class TermWrap {
8687
onSearchResultsDidChange?: (result: { resultIndex: number; resultCount: number }) => void;
8788
private toDispose: TermTypes.IDisposable[] = [];
8889
webglAddon: WebglAddon | null = null;
90+
canvasAddon: CanvasAddon | null = null;
8991
webglEnabledAtom: jotai.PrimitiveAtom<boolean>;
9092
pasteActive: boolean = false;
9193
lastUpdated: number;
@@ -182,9 +184,7 @@ export class TermWrap {
182184
}
183185
)
184186
);
185-
if (WebGLSupported && waveOptions.useWebGl) {
186-
this.loadWebGlAddon();
187-
}
187+
this.setTermRenderer(WebGLSupported && waveOptions.useWebGl ? "webgl" : "canvas");
188188
// Register OSC handlers
189189
this.terminal.parser.registerOscHandler(7, (data: string) => {
190190
return handleOsc7Command(data, this.blockId, this.loaded);
@@ -300,42 +300,57 @@ export class TermWrap {
300300
this.terminal.options.cursorBlink = cursorBlink ?? false;
301301
}
302302

303-
loadWebGlAddon() {
304-
const addon = new WebglAddon();
305-
this.toDispose.push(
306-
addon.onContextLoss(() => {
307-
if (addon === this.webglAddon) {
308-
this.disableWebGl();
309-
}
310-
})
311-
);
312-
this.terminal.loadAddon(addon);
313-
this.webglAddon = addon;
314-
globalStore.set(this.webglEnabledAtom, true);
315-
if (!loggedWebGL) {
316-
console.log("loaded webgl!");
317-
loggedWebGL = true;
303+
setTermRenderer(renderer: "webgl" | "canvas") {
304+
if (renderer === "webgl") {
305+
if (this.webglAddon != null) {
306+
return;
307+
}
308+
if (!WebGLSupported) {
309+
renderer = "canvas";
310+
}
311+
} else {
312+
if (this.canvasAddon != null) {
313+
return;
314+
}
315+
}
316+
if (this.webglAddon != null) {
317+
this.webglAddon.dispose();
318+
this.webglAddon = null;
319+
globalStore.set(this.webglEnabledAtom, false);
320+
}
321+
if (this.canvasAddon != null) {
322+
this.canvasAddon.dispose();
323+
this.canvasAddon = null;
324+
}
325+
if (renderer === "webgl") {
326+
const addon = new WebglAddon();
327+
this.toDispose.push(
328+
addon.onContextLoss(() => {
329+
if (addon === this.webglAddon) {
330+
this.setTermRenderer("canvas");
331+
}
332+
})
333+
);
334+
this.terminal.loadAddon(addon);
335+
this.webglAddon = addon;
336+
globalStore.set(this.webglEnabledAtom, true);
337+
if (!loggedWebGL) {
338+
console.log("loaded webgl!");
339+
loggedWebGL = true;
340+
}
341+
} else {
342+
const addon = new CanvasAddon();
343+
this.terminal.loadAddon(addon);
344+
this.canvasAddon = addon;
318345
}
319346
}
320347

321-
isWebGlEnabled(): boolean {
322-
return this.webglAddon != null;
323-
}
324-
325-
enableWebGl() {
326-
if (!WebGLSupported || this.webglAddon != null) {
327-
return;
328-
}
329-
this.loadWebGlAddon();
348+
getTermRenderer(): "webgl" | "canvas" {
349+
return this.webglAddon != null ? "webgl" : "canvas";
330350
}
331351

332-
disableWebGl() {
333-
if (this.webglAddon == null) {
334-
return;
335-
}
336-
this.webglAddon.dispose();
337-
this.webglAddon = null;
338-
globalStore.set(this.webglEnabledAtom, false);
352+
isWebGlEnabled(): boolean {
353+
return this.webglAddon != null;
339354
}
340355

341356
resetCompositionState() {

package-lock.json

Lines changed: 10 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"@table-nav/react": "^0.0.7",
8383
"@tanstack/react-table": "^8.21.3",
8484
"@tanstack/react-virtual": "^3.13.19",
85+
"@xterm/addon-canvas": "^0.7.0",
8586
"@xterm/addon-fit": "^0.10.0",
8687
"@xterm/addon-search": "^0.15.0",
8788
"@xterm/addon-serialize": "^0.13.0",

0 commit comments

Comments
 (0)