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 {
if (!terminal.element) {
throw new Error('Cannot activate WebglAddon before Terminal.open');
(terminal as any)._core.onWillOpen(() => this.activate(terminal));
return;
}
if (isSafari) {
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://';
socketURL = protocol + location.hostname + ((location.port) ? (':' + location.port) : '') + '/terminals/';
term.open(terminalContainer);
addons.fit.instance!.fit();
try {
typedTerm.loadAddon(addons.webgl.instance);
setTimeout(() => {
addTextureAtlas(addons.webgl.instance.textureAtlas);
addons.webgl.instance.onChangeTextureAtlas(e => addTextureAtlas(e));
}, 0);
}
catch {
addons.webgl.instance = undefined;
}
typedTerm.loadAddon(addons.webgl.instance);
setTimeout(() => {
addTextureAtlas(addons.webgl.instance.textureAtlas);
addons.webgl.instance.onChangeTextureAtlas(e => addTextureAtlas(e));
}, 0);
term.open(terminalContainer);
term.focus();
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; }
private _onA11yTabEmitter = new EventEmitter<number>();
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.
@@ -509,12 +512,16 @@ export class Terminal extends CoreTerminal implements ITerminal {
this._characterJoinerService = this._instantiationService.createInstance(CharacterJoinerService);
this._instantiationService.setService(ICharacterJoinerService, this._characterJoinerService);
const renderer = this._createRenderer();
this._renderService = this.register(this._instantiationService.createInstance(RenderService, renderer, this.rows, this.screenElement));
this._renderService = this.register(this._instantiationService.createInstance(RenderService, this.rows, this.screenElement));
this._instantiationService.setService(IRenderService, this._renderService);
this.register(this._renderService.onRenderedViewportChange(e => this._onRender.fire(e)));
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.classList.add('composition-view');
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 onBell!: IEvent<void>;
public onScroll!: IEvent<number>;
public onWillOpen!: IEvent<HTMLElement>;
public onKey!: IEvent<{ key: string, domEvent: KeyboardEvent }>;
public onRender!: IEvent<{ start: number, end: number }>;
public onResize!: IEvent<{ cols: number, rows: number }>;
@@ -400,6 +401,9 @@ export class MockRenderService implements IRenderService {
public resize(cols: number, rows: number): void {
throw new Error('Method not implemented.');
}
public hasRenderer(): boolean {
throw new Error('Method not implemented.');
}
public setRenderer(renderer: IRenderer): void {
throw new Error('Method not implemented.');
}
+1
View File
@@ -23,6 +23,7 @@ export interface ITerminal extends IPublicTerminal, ICoreTerminal {
onFocus: IEvent<void>;
onA11yChar: IEvent<string>;
onA11yTab: IEvent<number>;
onWillOpen: IEvent<HTMLElement>;
cancel(ev: Event, force?: boolean): boolean | void;
}
+38 -13
View File
@@ -23,6 +23,7 @@ interface ISelectionState {
export class RenderService extends Disposable implements IRenderService {
public serviceBrand: undefined;
private _renderer: IRenderer | undefined;
private _renderDebouncer: IRenderDebouncerWithCallback;
private _screenDprMonitor: ScreenDprMonitor;
private _pausedResizeTask = new DebouncedIdleTask();
@@ -48,10 +49,9 @@ export class RenderService extends Disposable implements IRenderService {
private _onRefreshRequest = new EventEmitter<{ start: number, end: number }>();
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(
private _renderer: IRenderer,
private _rowCount: number,
screenElement: HTMLElement,
@IOptionsService optionsService: IOptionsService,
@@ -62,7 +62,7 @@ export class RenderService extends Disposable implements IRenderService {
) {
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.register(this._renderDebouncer);
@@ -83,7 +83,7 @@ export class RenderService extends Disposable implements IRenderService {
this.register(decorationService.onDecorationRemoved(() => this._fullRefresh()));
// 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
// matchMedia query.
@@ -125,6 +125,9 @@ export class RenderService extends Disposable implements IRenderService {
}
private _renderRows(start: number, end: number): void {
if (!this._renderer) {
return;
}
this._renderer.renderRows(start, end);
// Update selection if needed
@@ -147,12 +150,18 @@ export class RenderService extends Disposable implements IRenderService {
}
private _handleOptionsChanged(): void {
if (!this._renderer) {
return;
}
this._renderer.onOptionsChanged();
this.refreshRows(0, this._rowCount - 1);
this._fireOnCanvasResize();
}
private _fireOnCanvasResize(): void {
if (!this._renderer) {
return;
}
// Don't fire the event if the dimensions haven't changed
if (this._renderer.dimensions.canvasWidth === this._canvasWidth && this._renderer.dimensions.canvasHeight === this._canvasHeight) {
return;
@@ -164,9 +173,13 @@ export class RenderService extends Disposable implements IRenderService {
super.dispose();
}
public hasRenderer(): boolean {
return !!this._renderer;
}
public setRenderer(renderer: IRenderer): void {
// TODO: RenderService should be the only one to dispose the renderer
this._renderer.dispose();
this._renderer?.dispose();
this._renderer = renderer;
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 {
this._renderer?.clearTextureAtlas?.();
if (!this._renderer) {
return;
}
this._renderer.clearTextureAtlas?.();
this._fullRefresh();
}
public setColors(colors: IColorSet): void {
if (!this._renderer) {
return;
}
this._renderer.setColors(colors);
this._fullRefresh();
}
@@ -202,13 +221,19 @@ export class RenderService extends Disposable implements IRenderService {
// when devicePixelRatio changes
this._charSizeService.measure();
if (!this._renderer) {
return;
}
this._renderer.onDevicePixelRatioChange();
this.refreshRows(0, this._rowCount - 1);
}
public onResize(cols: number, rows: number): void {
if (!this._renderer) {
return;
}
if (this._isPaused) {
this._pausedResizeTask.set(() => this._renderer.onResize(cols, rows));
this._pausedResizeTask.set(() => this._renderer!.onResize(cols, rows));
} else {
this._renderer.onResize(cols, rows);
}
@@ -217,29 +242,29 @@ export class RenderService extends Disposable implements IRenderService {
// TODO: Is this useful when we have onResize?
public onCharSizeChanged(): void {
this._renderer.onCharSizeChanged();
this._renderer?.onCharSizeChanged();
}
public onBlur(): void {
this._renderer.onBlur();
this._renderer?.onBlur();
}
public onFocus(): void {
this._renderer.onFocus();
this._renderer?.onFocus();
}
public onSelectionChanged(start: [number, number] | undefined, end: [number, number] | undefined, columnSelectMode: boolean): void {
this._selectionState.start = start;
this._selectionState.end = end;
this._selectionState.columnSelectMode = columnSelectMode;
this._renderer.onSelectionChanged(start, end, columnSelectMode);
this._renderer?.onSelectionChanged(start, end, columnSelectMode);
}
public onCursorMove(): void {
this._renderer.onCursorMove();
this._renderer?.onCursorMove();
}
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;
clearTextureAtlas(): void;
resize(cols: number, rows: number): void;
hasRenderer(): boolean;
setRenderer(renderer: IRenderer): void;
setColors(colors: IColorSet): void;
onDevicePixelRatioChange(): void;