Allow setting renderer addon before open is called

This commit is contained in:
Daniel Imms
2022-09-24 14:41:48 -07:00
parent a9eea3fd46
commit 693d09cbad
7 changed files with 62 additions and 27 deletions
+2 -1
View File
@@ -26,7 +26,8 @@ export class WebglAddon implements ITerminalAddon {
public activate(terminal: Terminal): void { public activate(terminal: Terminal): void {
if (!terminal.element) { if (!terminal.element) {
throw new Error('Cannot activate WebglAddon before Terminal.open'); (terminal as any)._core.onWillOpen(() => this.activate(terminal));
return;
} }
if (isSafari) { if (isSafari) {
throw new Error('Webgl is not currently supported on Safari'); throw new Error('Webgl is not currently supported on Safari');
+7 -11
View File
@@ -267,18 +267,14 @@ function createTerminal(): void {
protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://'; protocol = (location.protocol === 'https:') ? 'wss://' : 'ws://';
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/'; socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
term.open(terminalContainer);
addons.fit.instance!.fit(); addons.fit.instance!.fit();
try { typedTerm.loadAddon(addons.webgl.instance);
typedTerm.loadAddon(addons.webgl.instance); setTimeout(() => {
setTimeout(() => { addTextureAtlas(addons.webgl.instance.textureAtlas);
addTextureAtlas(addons.webgl.instance.textureAtlas); addons.webgl.instance.onChangeTextureAtlas(e => addTextureAtlas(e));
addons.webgl.instance.onChangeTextureAtlas(e => addTextureAtlas(e)); }, 0);
}, 0);
} term.open(terminalContainer);
catch {
addons.webgl.instance = undefined;
}
term.focus(); term.focus();
addDomListener(paddingElement, 'change', setPadding); addDomListener(paddingElement, 'change', setPadding);
+9 -2
View File
@@ -143,6 +143,9 @@ export class Terminal extends CoreTerminal implements ITerminal {
public get onA11yChar(): IEvent<string> { return this._onA11yCharEmitter.event; } public get onA11yChar(): IEvent<string> { return this._onA11yCharEmitter.event; }
private _onA11yTabEmitter = new EventEmitter<number>(); private _onA11yTabEmitter = new EventEmitter<number>();
public get onA11yTab(): IEvent<number> { return this._onA11yTabEmitter.event; } public get onA11yTab(): IEvent<number> { return this._onA11yTabEmitter.event; }
private _onWillOpen = new EventEmitter<HTMLElement>();
public get onWillOpen(): IEvent<HTMLElement> { return this._onWillOpen.event; }
/** /**
* Creates a new `Terminal` object. * Creates a new `Terminal` object.
@@ -509,12 +512,16 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService); this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService);
this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService); this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService);
const renderer = this._createRenderer(); this._renderService = this.register(this._instantiationService.createInstance(RenderService, this.rows, this.screenElement));
this._renderService = this.register(this._instantiationService.createInstance(RenderService, renderer, this.rows, this.screenElement));
this._instantiationService.setService(IRenderService, this._renderService); this._instantiationService.setService(IRenderService, this._renderService);
this.register(this._renderService.onRenderedViewportChange(e => this._onRender.fire(e))); this.register(this._renderService.onRenderedViewportChange(e => this._onRender.fire(e)));
this.onResize(e => this._renderService!.resize(e.cols, e.rows)); this.onResize(e => this._renderService!.resize(e.cols, e.rows));
this._onWillOpen.fire(this.element);
if (!this._renderService.hasRenderer()) {
this._renderService.setRenderer(this._createRenderer());
}
this._compositionView = document.createElement('div'); this._compositionView = document.createElement('div');
this._compositionView.classList.add('composition-view'); this._compositionView.classList.add('composition-view');
this._compositionHelper = this._instantiationService.createInstance(CompositionHelper, this.textarea, this._compositionView); this._compositionHelper = this._instantiationService.createInstance(CompositionHelper, this.textarea, this._compositionView);
+4
View File
@@ -41,6 +41,7 @@ export class MockTerminal implements ITerminal {
public onTitleChange!: IEvent<string>; public onTitleChange!: IEvent<string>;
public onBell!: IEvent<void>; public onBell!: IEvent<void>;
public onScroll!: IEvent<number>; public onScroll!: IEvent<number>;
public onWillOpen!: IEvent<HTMLElement>;
public onKey!: IEvent<{ key: string, domEvent: KeyboardEvent }>; public onKey!: IEvent<{ key: string, domEvent: KeyboardEvent }>;
public onRender!: IEvent<{ start: number, end: number }>; public onRender!: IEvent<{ start: number, end: number }>;
public onResize!: IEvent<{ cols: number, rows: number }>; public onResize!: IEvent<{ cols: number, rows: number }>;
@@ -400,6 +401,9 @@ export class MockRenderService implements IRenderService {
public resize(cols: number, rows: number): void { public resize(cols: number, rows: number): void {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
public hasRenderer(): boolean {
throw new Error('Method not implemented.');
}
public setRenderer(renderer: IRenderer): void { public setRenderer(renderer: IRenderer): void {
throw new Error('Method not implemented.'); throw new Error('Method not implemented.');
} }
+1
View File
@@ -23,6 +23,7 @@ export interface ITerminal extends IPublicTerminal, ICoreTerminal {
onFocus: IEvent<void>; onFocus: IEvent<void>;
onA11yChar: IEvent<string>; onA11yChar: IEvent<string>;
onA11yTab: IEvent<number>; onA11yTab: IEvent<number>;
onWillOpen: IEvent<HTMLElement>;
cancel(ev: Event, force?: boolean): boolean | void; cancel(ev: Event, force?: boolean): boolean | void;
} }
+38 -13
View File
@@ -23,6 +23,7 @@ interface ISelectionState {
export class RenderService extends Disposable implements IRenderService { export class RenderService extends Disposable implements IRenderService {
public serviceBrand: undefined; public serviceBrand: undefined;
private _renderer: IRenderer | undefined;
private _renderDebouncer: IRenderDebouncerWithCallback; private _renderDebouncer: IRenderDebouncerWithCallback;
private _screenDprMonitor: ScreenDprMonitor; private _screenDprMonitor: ScreenDprMonitor;
private _pausedResizeTask = new DebouncedIdleTask(); private _pausedResizeTask = new DebouncedIdleTask();
@@ -48,10 +49,9 @@ export class RenderService extends Disposable implements IRenderService {
private _onRefreshRequest = new EventEmitter<{ start: number, end: number }>(); private _onRefreshRequest = new EventEmitter<{ start: number, end: number }>();
public get onRefreshRequest(): IEvent<{ start: number, end: number }> { return this._onRefreshRequest.event; } public get onRefreshRequest(): IEvent<{ start: number, end: number }> { return this._onRefreshRequest.event; }
public get dimensions(): IRenderDimensions { return this._renderer.dimensions; } public get dimensions(): IRenderDimensions { return this._renderer!.dimensions; }
constructor( constructor(
private _renderer: IRenderer,
private _rowCount: number, private _rowCount: number,
screenElement: HTMLElement, screenElement: HTMLElement,
@IOptionsService optionsService: IOptionsService, @IOptionsService optionsService: IOptionsService,
@@ -62,7 +62,7 @@ export class RenderService extends Disposable implements IRenderService {
) { ) {
super(); super();
this.register({ dispose: () => this._renderer.dispose() }); this.register({ dispose: () => this._renderer?.dispose() });
this._renderDebouncer = new RenderDebouncer(coreBrowserService.window, (start, end) => this._renderRows(start, end)); this._renderDebouncer = new RenderDebouncer(coreBrowserService.window, (start, end) => this._renderRows(start, end));
this.register(this._renderDebouncer); this.register(this._renderDebouncer);
@@ -83,7 +83,7 @@ export class RenderService extends Disposable implements IRenderService {
this.register(decorationService.onDecorationRemoved(() => this._fullRefresh())); this.register(decorationService.onDecorationRemoved(() => this._fullRefresh()));
// No need to register this as renderer is explicitly disposed in RenderService.dispose // No need to register this as renderer is explicitly disposed in RenderService.dispose
this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true)); // this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true));
// dprchange should handle this case, we need this as well for browsers that don't support the // dprchange should handle this case, we need this as well for browsers that don't support the
// matchMedia query. // matchMedia query.
@@ -125,6 +125,9 @@ export class RenderService extends Disposable implements IRenderService {
} }
private _renderRows(start: number, end: number): void { private _renderRows(start: number, end: number): void {
if (!this._renderer) {
return;
}
this._renderer.renderRows(start, end); this._renderer.renderRows(start, end);
// Update selection if needed // Update selection if needed
@@ -147,12 +150,18 @@ export class RenderService extends Disposable implements IRenderService {
} }
private _handleOptionsChanged(): void { private _handleOptionsChanged(): void {
if (!this._renderer) {
return;
}
this._renderer.onOptionsChanged(); this._renderer.onOptionsChanged();
this.refreshRows(0, this._rowCount - 1); this.refreshRows(0, this._rowCount - 1);
this._fireOnCanvasResize(); this._fireOnCanvasResize();
} }
private _fireOnCanvasResize(): void { private _fireOnCanvasResize(): void {
if (!this._renderer) {
return;
}
// Don't fire the event if the dimensions haven't changed // Don't fire the event if the dimensions haven't changed
if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) { if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) {
return; return;
@@ -164,9 +173,13 @@ export class RenderService extends Disposable implements IRenderService {
super.dispose(); super.dispose();
} }
public hasRenderer(): boolean {
return !!this._renderer;
}
public setRenderer(renderer: IRenderer): void { public setRenderer(renderer: IRenderer): void {
// TODO: RenderService should be the only one to dispose the renderer // TODO: RenderService should be the only one to dispose the renderer
this._renderer.dispose(); this._renderer?.dispose();
this._renderer = renderer; this._renderer = renderer;
this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true)); this._renderer.onRequestRedraw(e => this.refreshRows(e.start, e.end, true));
@@ -188,11 +201,17 @@ export class RenderService extends Disposable implements IRenderService {
} }
public clearTextureAtlas(): void { public clearTextureAtlas(): void {
this._renderer?.clearTextureAtlas?.(); if (!this._renderer) {
return;
}
this._renderer.clearTextureAtlas?.();
this._fullRefresh(); this._fullRefresh();
} }
public setColors(colors: IColorSet): void { public setColors(colors: IColorSet): void {
if (!this._renderer) {
return;
}
this._renderer.setColors(colors); this._renderer.setColors(colors);
this._fullRefresh(); this._fullRefresh();
} }
@@ -202,13 +221,19 @@ export class RenderService extends Disposable implements IRenderService {
// when devicePixelRatio changes // when devicePixelRatio changes
this._charSizeService.measure(); this._charSizeService.measure();
if (!this._renderer) {
return;
}
this._renderer.onDevicePixelRatioChange(); this._renderer.onDevicePixelRatioChange();
this.refreshRows(0, this._rowCount - 1); this.refreshRows(0, this._rowCount - 1);
} }
public onResize(cols: number, rows: number): void { public onResize(cols: number, rows: number): void {
if (!this._renderer) {
return;
}
if (this._isPaused) { if (this._isPaused) {
this._pausedResizeTask.set(() => this._renderer.onResize(cols, rows)); this._pausedResizeTask.set(() => this._renderer!.onResize(cols, rows));
} else { } else {
this._renderer.onResize(cols, rows); this._renderer.onResize(cols, rows);
} }
@@ -217,29 +242,29 @@ export class RenderService extends Disposable implements IRenderService {
// TODO: Is this useful when we have onResize? // TODO: Is this useful when we have onResize?
public onCharSizeChanged(): void { public onCharSizeChanged(): void {
this._renderer.onCharSizeChanged(); this._renderer?.onCharSizeChanged();
} }
public onBlur(): void { public onBlur(): void {
this._renderer.onBlur(); this._renderer?.onBlur();
} }
public onFocus(): void { public onFocus(): void {
this._renderer.onFocus(); this._renderer?.onFocus();
} }
public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void { public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
this._selectionState.start = start; this._selectionState.start = start;
this._selectionState.end = end; this._selectionState.end = end;
this._selectionState.columnSelectMode = columnSelectMode; this._selectionState.columnSelectMode = columnSelectMode;
this._renderer.onSelectionChanged(start, end, columnSelectMode); this._renderer?.onSelectionChanged(start, end, columnSelectMode);
} }
public onCursorMove(): void { public onCursorMove(): void {
this._renderer.onCursorMove(); this._renderer?.onCursorMove();
} }
public clear(): void { public clear(): void {
this._renderer.clear(); this._renderer?.clear();
} }
} }
+1
View File
@@ -71,6 +71,7 @@ export interface IRenderService extends IDisposable {
refreshRows(start: number, end: number): void; refreshRows(start: number, end: number): void;
clearTextureAtlas(): void; clearTextureAtlas(): void;
resize(cols: number, rows: number): void; resize(cols: number, rows: number): void;
hasRenderer(): boolean;
setRenderer(renderer: IRenderer): void; setRenderer(renderer: IRenderer): void;
setColors(colors: IColorSet): void; setColors(colors: IColorSet): void;
onDevicePixelRatioChange(): void; onDevicePixelRatioChange(): void;