From e85f48f12f8b7a3fab6c1108e21b7032ff15bab5 Mon Sep 17 00:00:00 2001 From: abose Date: Mon, 13 Apr 2026 12:31:44 +0530 Subject: [PATCH 1/2] fix: bottom panel tab bar infinite switch flicker --- src/view/PanelView.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/view/PanelView.js b/src/view/PanelView.js index 6918b61b0..814874bda 100644 --- a/src/view/PanelView.js +++ b/src/view/PanelView.js @@ -853,9 +853,11 @@ define(function (require, exports, module) { _toggleMaximize(); }); - // Re-check tab overflow when the tab bar resizes (e.g. window resize) - const tabBarResizeObserver = new ResizeObserver(_checkTabOverflow); - tabBarResizeObserver.observe(_$tabsOverflow[0]); + // Observe the outer tab bar container so that only external resizes + // (e.g. window resize) trigger a re-check. Observing _$tabsOverflow + // would cause an infinite loop in WebKit because _checkTabOverflow + // toggles classes that change _$tabsOverflow's size. + new ResizeObserver(_checkTabOverflow).observe(_$tabBar[0]); // Restore maximize state from preferences (survives reload). _isMaximized = PreferencesManager.getViewState(PREF_BOTTOM_PANEL_MAXIMIZED) === true; From f1c8d0dc4ed390e06b3786b047fe67b5b3957257 Mon Sep 17 00:00:00 2001 From: abose Date: Thu, 16 Apr 2026 08:54:10 +0530 Subject: [PATCH 2/2] fix: infinite flicker in mac in bottom panel tab bar due to size change measurement --- src/view/PanelView.js | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/view/PanelView.js b/src/view/PanelView.js index 814874bda..0c6f8e0dd 100644 --- a/src/view/PanelView.js +++ b/src/view/PanelView.js @@ -365,13 +365,28 @@ define(function (require, exports, module) { /** @type {jQueryObject} Overflow dropdown button */ let _$overflowBtn = null; + let _checkTabOverflowTimer = null; + function _checkTabOverflow() { + // Coalesce multiple calls (e.g. rapid tab adds) and defer to the + // next frame so that measurements happen after layout settles. + if (_checkTabOverflowTimer) { + cancelAnimationFrame(_checkTabOverflowTimer); + } + _checkTabOverflowTimer = requestAnimationFrame(_doCheckTabOverflow); + } + + function _doCheckTabOverflow() { + _checkTabOverflowTimer = null; if (!_$tabBar) { return; } - // Remove collapsed state first to measure true width + + // Remove collapsed state first to measure true width. + // Use a 1px tolerance to avoid sub-pixel rounding flicker at + // boundary sizes (e.g. scrollWidth 678 vs clientWidth 677). _$tabBar.removeClass("bottom-panel-tabs-collapsed"); - const isOverflowing = _$tabsOverflow[0].scrollWidth > _$tabsOverflow[0].clientWidth; + const isOverflowing = _$tabsOverflow[0].scrollWidth > _$tabsOverflow[0].clientWidth + 1; _$tabBar.toggleClass("bottom-panel-tabs-collapsed", isOverflowing); // Check if still overflowing after collapse @@ -854,9 +869,9 @@ define(function (require, exports, module) { }); // Observe the outer tab bar container so that only external resizes - // (e.g. window resize) trigger a re-check. Observing _$tabsOverflow - // would cause an infinite loop in WebKit because _checkTabOverflow - // toggles classes that change _$tabsOverflow's size. + // (e.g. window resize, plugin panel open/close) trigger a re-check. + // Observing _$tabsOverflow would cause an infinite loop in WebKit + // because _checkTabOverflow toggles classes that change its size. new ResizeObserver(_checkTabOverflow).observe(_$tabBar[0]); // Restore maximize state from preferences (survives reload).