Merge pull request #5770 from mgabor3141/fix/viewport-sync-output-flicker
fix: defer viewport DOM sync during synchronized output (DEC 2026)
This commit is contained in:
@@ -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;
|
||||
|
||||
+19
-1
@@ -6,7 +6,7 @@
|
||||
import { ICoreBrowserService, IRenderService, IThemeService } from 'browser/services/Services';
|
||||
import { ViewportConstants } from 'browser/shared/Constants';
|
||||
import { Disposable, toDisposable } from 'common/Lifecycle';
|
||||
import { IBufferService, IMouseStateService, IOptionsService } from 'common/services/Services';
|
||||
import { IBufferService, ICoreService, IMouseStateService, IOptionsService } from 'common/services/Services';
|
||||
import { CoreMouseEventType } from 'common/Types';
|
||||
import { scheduleAtNextAnimationFrame } from 'browser/Dom';
|
||||
import { SmoothScrollableElement } from 'browser/scrollable/scrollableElement';
|
||||
@@ -27,12 +27,14 @@ export class Viewport extends Disposable {
|
||||
private _isSyncing: boolean = false;
|
||||
private _isHandlingScroll: boolean = false;
|
||||
private _suppressOnScrollHandler: boolean = false;
|
||||
private _needsSyncOnRender: boolean = false;
|
||||
|
||||
constructor(
|
||||
element: HTMLElement,
|
||||
screenElement: HTMLElement,
|
||||
@IBufferService private readonly _bufferService: IBufferService,
|
||||
@ICoreBrowserService coreBrowserService: ICoreBrowserService,
|
||||
@ICoreService private readonly _coreService: ICoreService,
|
||||
@IMouseStateService mouseStateService: IMouseStateService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IOptionsService private readonly _optionsService: IOptionsService,
|
||||
@@ -104,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)));
|
||||
|
||||
}
|
||||
@@ -161,6 +173,12 @@ export class Viewport extends Disposable {
|
||||
if (!this._renderService || this._isSyncing) {
|
||||
return;
|
||||
}
|
||||
// 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
|
||||
|
||||
Reference in New Issue
Block a user