html: use webgl as the default renderer

This commit is contained in:
Shuanglei Tao
2020-12-19 12:09:47 +08:00
parent a1097300df
commit c62de53104
2 changed files with 80 additions and 43 deletions

View File

@@ -1,7 +1,7 @@
import { h, Component } from 'preact';
import { ITerminalOptions, ITheme } from 'xterm';
import { Xterm } from './terminal';
import { ClientOptions, Xterm } from './terminal';
if ((module as any).hot) {
// tslint:disable-next-line:no-var-requires
@@ -12,6 +12,12 @@ const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const path = window.location.pathname.replace(/[\/]+$/, '');
const wsUrl = [protocol, '//', window.location.host, path, '/ws', window.location.search].join('');
const tokenUrl = [window.location.protocol, '//', window.location.host, path, '/token'].join('');
const clientOptions = {
rendererType: 'webgl',
disableLeaveAlert: false,
disableResizeOverlay: false,
titleFixed: null,
} as ClientOptions;
const termOptions = {
fontSize: 13,
fontFamily: 'Menlo For Powerline,Consolas,Liberation Mono,Menlo,Courier,monospace',
@@ -40,6 +46,14 @@ const termOptions = {
export class App extends Component {
render() {
return <Xterm id="terminal-container" wsUrl={wsUrl} tokenUrl={tokenUrl} options={termOptions} />;
return (
<Xterm
id="terminal-container"
wsUrl={wsUrl}
tokenUrl={tokenUrl}
clientOptions={clientOptions}
termOptions={termOptions}
/>
);
}
}

View File

@@ -32,11 +32,19 @@ const enum Command {
RESIZE_TERMINAL = '1',
}
export interface ClientOptions {
rendererType: 'dom' | 'canvas' | 'webgl';
disableLeaveAlert: boolean;
disableResizeOverlay: boolean;
titleFixed: string;
}
interface Props {
id: string;
wsUrl: string;
tokenUrl: string;
options: ITerminalOptions;
clientOptions: ClientOptions;
termOptions: ITerminalOptions;
}
export class Xterm extends Component<Props> {
@@ -44,9 +52,11 @@ export class Xterm extends Component<Props> {
private textDecoder: TextDecoder;
private container: HTMLElement;
private terminal: Terminal;
private fitAddon: FitAddon;
private overlayAddon: OverlayAddon;
private zmodemAddon: ZmodemAddon;
private socket: WebSocket;
private token: string;
private title: string;
@@ -149,7 +159,7 @@ export class Xterm extends Component<Props> {
@bind
private openTerminal() {
this.terminal = new Terminal(this.props.options);
this.terminal = new Terminal(this.props.termOptions);
const { terminal, container, fitAddon, overlayAddon } = this;
window.term = terminal as TtydTerminal;
window.term.fit = () => {
@@ -190,6 +200,54 @@ export class Xterm extends Component<Props> {
socket.onerror = this.onSocketError;
}
@bind
private applyOptions(options: any) {
const { terminal, fitAddon } = this;
const isWebGL2Available = () => {
try {
const canvas = document.createElement('canvas');
return !!(window.WebGL2RenderingContext && canvas.getContext('webgl2'));
} catch (e) {
return false;
}
};
Object.keys(options).forEach(key => {
const value = options[key];
switch (key) {
case 'rendererType':
if (value === 'webgl' && isWebGL2Available()) {
terminal.loadAddon(new WebglAddon());
console.log(`[ttyd] WebGL renderer enabled`);
}
break;
case 'disableLeaveAlert':
if (value) {
window.removeEventListener('beforeunload', this.onWindowUnload);
console.log('[ttyd] Leave site alert disabled');
}
break;
case 'disableResizeOverlay':
if (value) {
console.log(`[ttyd] Resize overlay disabled`);
this.resizeOverlay = false;
}
break;
case 'titleFixed':
if (!value || value === '') return;
console.log(`[ttyd] setting fixed title: ${value}`);
this.titleFixed = value;
document.title = value;
break;
default:
console.log(`[ttyd] option: ${key}=${value}`);
terminal.setOption(key, value);
if (key.indexOf('font') === 0) fitAddon.fit();
break;
}
});
}
@bind
private onSocketOpen() {
console.log('[ttyd] websocket connection opened');
@@ -208,6 +266,8 @@ export class Xterm extends Component<Props> {
fitAddon.fit();
}
this.applyOptions(this.props.clientOptions);
terminal.focus();
}
@@ -235,7 +295,7 @@ export class Xterm extends Component<Props> {
@bind
private onSocketData(event: MessageEvent) {
const { terminal, textDecoder, zmodemAddon, fitAddon } = this;
const { textDecoder, zmodemAddon } = this;
const rawData = event.data as ArrayBuffer;
const cmd = String.fromCharCode(new Uint8Array(rawData)[0]);
const data = rawData.slice(1);
@@ -249,44 +309,7 @@ export class Xterm extends Component<Props> {
document.title = this.title;
break;
case Command.SET_PREFERENCES:
const preferences = JSON.parse(textDecoder.decode(data));
Object.keys(preferences).forEach(key => {
const value = preferences[key];
switch (key) {
case 'rendererType':
if (preferences[key] === 'webgl') {
terminal.loadAddon(new WebglAddon());
console.log(`[ttyd] WebGL renderer enabled`);
}
break;
case 'disableLeaveAlert':
if (preferences[key]) {
window.removeEventListener('beforeunload', this.onWindowUnload);
console.log('[ttyd] Leave site alert disabled');
}
break;
case 'disableResizeOverlay':
if (preferences[key]) {
console.log(`[ttyd] disabled resize overlay`);
this.resizeOverlay = false;
}
break;
case 'fontSize':
console.log(`[ttyd] setting font size to ${value}`);
terminal.setOption(key, value);
fitAddon.fit();
break;
case 'titleFixed':
console.log(`[ttyd] setting fixed title: ${value}`);
this.titleFixed = value;
document.title = value;
break;
default:
console.log(`[ttyd] option: ${key}=${value}`);
terminal.setOption(key, value);
break;
}
});
this.applyOptions(JSON.parse(textDecoder.decode(data)));
break;
default:
console.warn(`[ttyd] unknown command: ${cmd}`);