Merge pull request #4689 from Tyriar/4685
Track CursorBlinkStateManager in MutableDisposable
This commit is contained in:
@@ -16,7 +16,7 @@ import { AttributeData } from 'common/buffer/AttributeData';
|
|||||||
import { CellData } from 'common/buffer/CellData';
|
import { CellData } from 'common/buffer/CellData';
|
||||||
import { Attributes, Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
|
import { Attributes, Content, NULL_CELL_CHAR, NULL_CELL_CODE } from 'common/buffer/Constants';
|
||||||
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
|
import { EventEmitter, forwardEvent } from 'common/EventEmitter';
|
||||||
import { Disposable, getDisposeArrayDisposable, toDisposable } from 'common/Lifecycle';
|
import { Disposable, MutableDisposable, getDisposeArrayDisposable, toDisposable } from 'common/Lifecycle';
|
||||||
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
import { ICoreService, IDecorationService, ILogService, IOptionsService } from 'common/services/Services';
|
||||||
import { CharData, IBufferLine, ICellData } from 'common/Types';
|
import { CharData, IBufferLine, ICellData } from 'common/Types';
|
||||||
import { IDisposable, Terminal } from 'xterm';
|
import { IDisposable, Terminal } from 'xterm';
|
||||||
@@ -31,7 +31,7 @@ import { traceCall } from 'common/services/LogService';
|
|||||||
|
|
||||||
export class WebglRenderer extends Disposable implements IRenderer {
|
export class WebglRenderer extends Disposable implements IRenderer {
|
||||||
private _renderLayers: IRenderLayer[];
|
private _renderLayers: IRenderLayer[];
|
||||||
private _cursorBlinkStateManager: CursorBlinkStateManager | undefined;
|
private _cursorBlinkStateManager: MutableDisposable<CursorBlinkStateManager> = new MutableDisposable();
|
||||||
private _charAtlasDisposable: IDisposable | undefined;
|
private _charAtlasDisposable: IDisposable | undefined;
|
||||||
private _charAtlas: ITextureAtlas | undefined;
|
private _charAtlas: ITextureAtlas | undefined;
|
||||||
private _devicePixelRatio: number;
|
private _devicePixelRatio: number;
|
||||||
@@ -203,7 +203,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
for (const l of this._renderLayers) {
|
for (const l of this._renderLayers) {
|
||||||
l.handleBlur(this._terminal);
|
l.handleBlur(this._terminal);
|
||||||
}
|
}
|
||||||
this._cursorBlinkStateManager?.pause();
|
this._cursorBlinkStateManager.value?.pause();
|
||||||
// Request a redraw for active/inactive selection background
|
// Request a redraw for active/inactive selection background
|
||||||
this._requestRedrawViewport();
|
this._requestRedrawViewport();
|
||||||
}
|
}
|
||||||
@@ -212,7 +212,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
for (const l of this._renderLayers) {
|
for (const l of this._renderLayers) {
|
||||||
l.handleFocus(this._terminal);
|
l.handleFocus(this._terminal);
|
||||||
}
|
}
|
||||||
this._cursorBlinkStateManager?.resume();
|
this._cursorBlinkStateManager.value?.resume();
|
||||||
// Request a redraw for active/inactive selection background
|
// Request a redraw for active/inactive selection background
|
||||||
this._requestRedrawViewport();
|
this._requestRedrawViewport();
|
||||||
}
|
}
|
||||||
@@ -229,7 +229,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
for (const l of this._renderLayers) {
|
for (const l of this._renderLayers) {
|
||||||
l.handleCursorMove(this._terminal);
|
l.handleCursorMove(this._terminal);
|
||||||
}
|
}
|
||||||
this._cursorBlinkStateManager?.restartBlinkAnimation();
|
this._cursorBlinkStateManager.value?.restartBlinkAnimation();
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleOptionsChanged(): void {
|
private _handleOptionsChanged(): void {
|
||||||
@@ -312,7 +312,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
l.reset(this._terminal);
|
l.reset(this._terminal);
|
||||||
}
|
}
|
||||||
|
|
||||||
this._cursorBlinkStateManager?.restartBlinkAnimation();
|
this._cursorBlinkStateManager.value?.restartBlinkAnimation();
|
||||||
this._updateCursorBlink();
|
this._updateCursorBlink();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,21 +359,18 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
// Render
|
// Render
|
||||||
this._rectangleRenderer?.renderBackgrounds();
|
this._rectangleRenderer?.renderBackgrounds();
|
||||||
this._glyphRenderer?.render(this._model);
|
this._glyphRenderer?.render(this._model);
|
||||||
if (!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isCursorVisible) {
|
if (!this._cursorBlinkStateManager.value || this._cursorBlinkStateManager.value.isCursorVisible) {
|
||||||
this._rectangleRenderer?.renderCursor();
|
this._rectangleRenderer?.renderCursor();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private _updateCursorBlink(): void {
|
private _updateCursorBlink(): void {
|
||||||
if (this._terminal.options.cursorBlink) {
|
if (this._terminal.options.cursorBlink) {
|
||||||
if (!this._cursorBlinkStateManager) {
|
this._cursorBlinkStateManager.value = new CursorBlinkStateManager(() => {
|
||||||
this._cursorBlinkStateManager = this.register(new CursorBlinkStateManager(() => {
|
this._requestRedrawCursor();
|
||||||
this._requestRedrawCursor();
|
}, this._coreBrowserService);
|
||||||
}, this._coreBrowserService));
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
this._cursorBlinkStateManager?.dispose();
|
this._cursorBlinkStateManager.clear();
|
||||||
this._cursorBlinkStateManager = undefined;
|
|
||||||
}
|
}
|
||||||
// Request a refresh from the terminal as management of rendering is being
|
// Request a refresh from the terminal as management of rendering is being
|
||||||
// moved back to the terminal
|
// moved back to the terminal
|
||||||
@@ -408,7 +405,7 @@ export class WebglRenderer extends Disposable implements IRenderer {
|
|||||||
const isCursorVisible =
|
const isCursorVisible =
|
||||||
this._coreService.isCursorInitialized &&
|
this._coreService.isCursorInitialized &&
|
||||||
!this._coreService.isCursorHidden &&
|
!this._coreService.isCursorHidden &&
|
||||||
(!this._cursorBlinkStateManager || this._cursorBlinkStateManager.isCursorVisible);
|
(!this._cursorBlinkStateManager.value || this._cursorBlinkStateManager.value.isCursorVisible);
|
||||||
this._model.cursor = undefined;
|
this._model.cursor = undefined;
|
||||||
let modelUpdated = false;
|
let modelUpdated = false;
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,8 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { assert } from 'chai';
|
import { assert } from 'chai';
|
||||||
import { Disposable } from 'common/Lifecycle';
|
import { Disposable, MutableDisposable } from 'common/Lifecycle';
|
||||||
|
import { IDisposable } from 'common/Types';
|
||||||
|
|
||||||
class TestDisposable extends Disposable {
|
class TestDisposable extends Disposable {
|
||||||
public get isDisposed(): boolean {
|
public get isDisposed(): boolean {
|
||||||
@@ -43,3 +44,52 @@ describe('Disposable', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('MutableDisposable', () => {
|
||||||
|
const mutable = new MutableDisposable();
|
||||||
|
class TrackedDisposable extends Disposable {
|
||||||
|
public get isDisposed(): boolean { return this._isDisposed; }
|
||||||
|
}
|
||||||
|
describe('value', () => {
|
||||||
|
it('should set the value', () => {
|
||||||
|
const d1 = new TrackedDisposable();
|
||||||
|
mutable.value = d1;
|
||||||
|
assert.strictEqual(mutable.value, d1);
|
||||||
|
assert.isFalse(d1.isDisposed);
|
||||||
|
});
|
||||||
|
it('should dispose of any previous value', () => {
|
||||||
|
const d1 = new TrackedDisposable();
|
||||||
|
const d2 = new TrackedDisposable();
|
||||||
|
mutable.value = d1;
|
||||||
|
mutable.value = d2;
|
||||||
|
assert.strictEqual(mutable.value, d2);
|
||||||
|
assert.isTrue(d1.isDisposed);
|
||||||
|
assert.isFalse(d2.isDisposed);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
describe('clear', () => {
|
||||||
|
it('should clear and dispose of the object', () => {
|
||||||
|
const d1 = new TrackedDisposable();
|
||||||
|
mutable.value = d1;
|
||||||
|
mutable.clear();
|
||||||
|
assert.strictEqual(mutable.value, undefined);
|
||||||
|
assert.isTrue(d1.isDisposed);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it('dispose', () => {
|
||||||
|
it('should dispose of the object', () => {
|
||||||
|
const d1 = new TrackedDisposable();
|
||||||
|
mutable.value = d1;
|
||||||
|
mutable.dispose();
|
||||||
|
assert.strictEqual(mutable.value, undefined);
|
||||||
|
assert.isTrue(d1.isDisposed);
|
||||||
|
});
|
||||||
|
it('should prevent using the MutableDisposable again', () => {
|
||||||
|
const d1 = new TrackedDisposable();
|
||||||
|
mutable.value = d1;
|
||||||
|
mutable.dispose();
|
||||||
|
mutable.value = new TrackedDisposable();
|
||||||
|
assert.strictEqual(mutable.value, undefined);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|||||||
@@ -50,6 +50,42 @@ export abstract class Disposable implements IDisposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export class MutableDisposable<T extends IDisposable> implements IDisposable {
|
||||||
|
private _value?: T;
|
||||||
|
private _isDisposed = false;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the value if it exists.
|
||||||
|
*/
|
||||||
|
public get value(): T | undefined {
|
||||||
|
return this._isDisposed ? undefined : this._value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value, disposing of the old value if it exists.
|
||||||
|
*/
|
||||||
|
public set value(value: T | undefined) {
|
||||||
|
if (this._isDisposed || value === this._value) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this._value?.dispose();
|
||||||
|
this._value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resets the stored value and disposes of the previously stored value.
|
||||||
|
*/
|
||||||
|
public clear(): void {
|
||||||
|
this.value = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose(): void {
|
||||||
|
this._isDisposed = true;
|
||||||
|
this._value?.dispose();
|
||||||
|
this._value = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wrap a function in a disposable.
|
* Wrap a function in a disposable.
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user