From 61e631902c37697dd61b31a0d051bb3743c5e213 Mon Sep 17 00:00:00 2001 From: Andrey Bochkarev <50177704+octaviusz@users.noreply.github.com> Date: Sat, 20 Jun 2026 18:18:41 +0300 Subject: [PATCH] gh-14131: Prevent sidebar from flickering when moving a tab (gh-14293) Co-authored-by: mr. m --- .../tabbrowser/content/tabs-js.patch | 55 ++++++++++++------- src/zen/drag-and-drop/ZenDragAndDrop.js | 11 +++- 2 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/browser/components/tabbrowser/content/tabs-js.patch b/src/browser/components/tabbrowser/content/tabs-js.patch index 449d2bae1..167f6b882 100644 --- a/src/browser/components/tabbrowser/content/tabs-js.patch +++ b/src/browser/components/tabbrowser/content/tabs-js.patch @@ -1,8 +1,23 @@ diff --git a/browser/components/tabbrowser/content/tabs.js b/browser/components/tabbrowser/content/tabs.js -index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9ea21b6f6 100644 +index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..b9a1cfe3a4a5035d9b06b0b3826a97c52cfcb39e 100644 --- a/browser/components/tabbrowser/content/tabs.js +++ b/browser/components/tabbrowser/content/tabs.js -@@ -220,7 +220,7 @@ +@@ -197,8 +197,12 @@ + XPCOMUtils.defineLazyPreferenceGetter( + this, + "_sidebarPositionStart", +- "sidebar.position_start", +- true ++ "zen.tabs.vertical.right-side", ++ true, ++ null, ++ newValue => { ++ return !newValue; ++ } + ); + + if (gMultiProcessBrowser) { +@@ -220,7 +224,7 @@ this.tooltip = "tabbrowser-tab-tooltip"; @@ -11,7 +26,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 this.tabDragAndDrop.init(); } -@@ -444,7 +444,7 @@ +@@ -444,7 +448,7 @@ // and we're not hitting the scroll buttons. if ( event.button != 0 || @@ -20,7 +35,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 event.composedTarget.localName == "toolbarbutton" ) { return; -@@ -525,7 +525,6 @@ +@@ -525,7 +529,6 @@ }); } } else if (isTabGroupLabel(event.target)) { @@ -28,7 +43,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 } else if ( event.originalTarget.closest("scrollbox") && !Services.prefs.getBoolPref( -@@ -561,6 +560,9 @@ +@@ -561,6 +564,9 @@ } on_keydown(event) { @@ -38,7 +53,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 let { altKey, shiftKey } = event; let [accel, nonAccel] = AppConstants.platform == "macosx" -@@ -755,7 +757,6 @@ +@@ -755,7 +761,6 @@ this._updateCloseButtons(); if (!this.#animatingGroups.size) { @@ -46,7 +61,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 } document -@@ -822,7 +823,7 @@ +@@ -822,7 +827,7 @@ } get newTabButton() { @@ -55,7 +70,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 } get verticalMode() { -@@ -838,6 +839,7 @@ +@@ -838,6 +843,7 @@ } get overflowing() { @@ -63,7 +78,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 return this.hasAttribute("overflow"); } -@@ -851,29 +853,56 @@ +@@ -851,29 +857,56 @@ if (pinnedChildren?.at(-1)?.id == "pinned-tabs-container-periphery") { pinnedChildren.pop(); } @@ -93,7 +108,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 + } else if (!isTab(tab)) { + tabs.splice(i, 1); + } - } ++ } + }; + expandTabs(pinnedTabs); + expandTabs(unpinnedChildren); @@ -114,7 +129,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 + // remove the separator from the list + allTabs.splice(i, 1); + i--; -+ } + } + i++; } - @@ -130,7 +145,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 } get allSplitViews() { -@@ -958,29 +987,28 @@ +@@ -958,29 +991,28 @@ return this.#focusableItems; } @@ -170,7 +185,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 this.#focusableItems = focusableItems; return this.#focusableItems; -@@ -993,6 +1021,7 @@ +@@ -993,6 +1025,7 @@ * focusable (ex, we don't want the splitview container to be focusable, only its children). */ get dragAndDropElements() { @@ -178,7 +193,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 if (this.#dragAndDropElements) { return this.#dragAndDropElements; } -@@ -1063,6 +1092,7 @@ +@@ -1063,6 +1096,7 @@ _invalidateCachedTabs() { this.#allTabs = null; this._invalidateCachedVisibleTabs(); @@ -186,7 +201,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 } _invalidateCachedVisibleTabs() { -@@ -1082,7 +1112,8 @@ +@@ -1082,7 +1116,8 @@ isContainerVerticalPinnedGrid(tab) { return ( @@ -196,7 +211,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 this.verticalMode && this.hasAttribute("expanded") && !this.expandOnHover -@@ -1176,7 +1207,7 @@ +@@ -1176,7 +1211,7 @@ if (node == null) { // We have a container for non-tab elements at the end of the scrollbox. @@ -205,7 +220,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 } node.before(tab); -@@ -1271,7 +1302,7 @@ +@@ -1271,7 +1306,7 @@ // There are separate "new tab" buttons for horizontal tabs toolbar, vertical tabs and // for when the tab strip is overflowed (which is shared by vertical and horizontal tabs); // Attach the long click popup to all of them. @@ -214,7 +229,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 const newTab2 = this.newTabButton; const newTabVertical = document.getElementById( "vertical-tabs-newtab-button" -@@ -1376,8 +1407,10 @@ +@@ -1376,8 +1411,10 @@ */ _handleTabSelect(aInstant) { let selectedTab = this.selectedItem; @@ -225,7 +240,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 selectedTab._notselectedsinceload = false; } -@@ -1386,7 +1419,7 @@ +@@ -1386,7 +1423,7 @@ * @param {boolean} [shouldScrollInstantly=false] */ #ensureTabIsVisible(tab, shouldScrollInstantly = false) { @@ -234,7 +249,7 @@ index 568f3a7cc7051ff8cb569f6bcb8018a5212f7072..3036768b8911b4fbc28df7528f7189d9 if (arrowScrollbox?.overflowing) { arrowScrollbox.ensureElementIsVisible(tab, shouldScrollInstantly); } -@@ -1513,7 +1546,7 @@ +@@ -1513,7 +1550,7 @@ } _notifyBackgroundTab(aTab) { diff --git a/src/zen/drag-and-drop/ZenDragAndDrop.js b/src/zen/drag-and-drop/ZenDragAndDrop.js index 05f31ac9c..67cf9a238 100644 --- a/src/zen/drag-and-drop/ZenDragAndDrop.js +++ b/src/zen/drag-and-drop/ZenDragAndDrop.js @@ -723,8 +723,11 @@ const { isNearLeftEdge, isNearRightEdge } = this.#shouldSwitchSpace(event); if (isNearLeftEdge || isNearRightEdge) { - if (!this.#changeSpaceTimer) { + if (!this.#changeSpaceTimer && !this.#isOutOfWindow) { this.#changeSpaceTimer = setTimeout(() => { + if (this.#isOutOfWindow) { + return; + } this.clearDragOverVisuals(); gZenWorkspaces .changeWorkspaceShortcut( @@ -956,8 +959,10 @@ if (ownerGlobal?.gZenCompactModeManager) { // Sometimes, dragend doesn't always get called when dragging // to different windows, see gh-8643. - delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged; - ownerGlobal.gZenCompactModeManager._clearAllHoverStates(); + requestAnimationFrame(() => { + delete ownerGlobal.gZenCompactModeManager._isTabBeingDragged; + ownerGlobal.gZenCompactModeManager._clearAllHoverStates(); + }); } this.clearSpaceSwitchTimer(); gZenFolders.highlightGroupOnDragOver(null);