fix: defer viewport DOM sync during synchronized output

Defer Viewport DOM scroll updates while DEC 2026 synchronized output is
active, then flush once rendering resumes so DOM and canvas update
atomically.

Also update demo sizing to avoid relying on removed internal viewport
scrollBarWidth.
This commit is contained in:
mgabor3141
2026-03-12 18:51:38 +01:00
parent f4042876c6
commit 9feb963cc9
2 changed files with 22 additions and 3 deletions
+5 -1
View File
@@ -617,8 +617,12 @@ function addDomListener(element: HTMLElement, type: string, handler: (...args: a
}
function updateTerminalSize(): void {
const showScrollbar = term!.options.scrollbar?.showScrollbar ?? true;
const scrollBarWidth = (term!.options.scrollback === 0 || !showScrollbar)
? 0
: (term!.options.scrollbar?.width ?? 14);
const width = optionsWindow.autoResize ? '100%'
: ((term as any).dimensions.css.canvas.width + (term as any)._core.viewport.scrollBarWidth).toString() + 'px';
: ((term as any).dimensions.css.canvas.width + scrollBarWidth).toString() + 'px';
const height = optionsWindow.autoResize ? '100%'
: ((term as any).dimensions.css.canvas.height).toString() + 'px';
terminalContainer!.style.width = width;
+17 -2
View File
@@ -27,6 +27,7 @@ export class Viewport extends Disposable {
private _isSyncing: boolean = false;
private _isHandlingScroll: boolean = false;
private _suppressOnScrollHandler: boolean = false;
private _needsSyncOnRender: boolean = false;
constructor(
element: HTMLElement,
@@ -105,6 +106,16 @@ export class Viewport extends Disposable {
}));
this._register(this._bufferService.onScroll(() => this._sync()));
// Flush deferred viewport sync after a render completes (e.g. after ESU ends
// synchronized output mode). This ensures DOM scroll position updates atomically
// with the canvas render.
this._register(this._renderService.onRender(() => {
if (this._needsSyncOnRender) {
this._needsSyncOnRender = false;
this._sync();
}
}));
this._register(this._scrollableElement.onScroll(e => this._handleScroll(e)));
}
@@ -162,8 +173,12 @@ export class Viewport extends Disposable {
if (!this._renderService || this._isSyncing) {
return;
}
// Plumb synchronized output state into Viewport for follow-up behavior changes.
void this._coreService.decPrivateModes.synchronizedOutput;
// Defer DOM scroll updates during synchronized output to prevent visible
// scroll position flickering while the canvas content is frozen.
if (this._coreService.decPrivateModes.synchronizedOutput) {
this._needsSyncOnRender = true;
return;
}
this._isSyncing = true;
// Ignore any onScroll event that happens as a result of dimensions changing as this should