]> prime8.dev >> repos - ttyd.git/commitdiff
html: use webgl as the default renderer
authorShuanglei Tao <tsl0922@gmail.com>
Sat, 19 Dec 2020 04:09:47 +0000 (12:09 +0800)
committerShuanglei Tao <tsl0922@gmail.com>
Sat, 19 Dec 2020 04:28:41 +0000 (12:28 +0800)
html/src/components/app.tsx
html/src/components/terminal/index.tsx

index dfe4b1e32502969e5eeb6dcab2fd7e6b12f622f4..a899b7fa70720a7142c7b40422396f633472f19a 100644 (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}
+            />
+        );
     }
 }
index 870261fbaca0d1366becb7f049bafddcad9f3788..8d5ec14c5fbb04b17a771f9dc3fc18d40a657078 100644 (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}`);