diff --git a/src/browser/components/sessionstore/SessionStore-sys-mjs.patch b/src/browser/components/sessionstore/SessionStore-sys-mjs.patch index 4b52a0178..99e1bcb94 100644 --- a/src/browser/components/sessionstore/SessionStore-sys-mjs.patch +++ b/src/browser/components/sessionstore/SessionStore-sys-mjs.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/sessionstore/SessionStore.sys.mjs b/browser/components/sessionstore/SessionStore.sys.mjs -index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e586e4fbd 100644 +index be029379c101a0105d4837136e064e6007b67c3e..93cf9042822f1eed1e53a28bc9f052597bd305bb 100644 --- a/browser/components/sessionstore/SessionStore.sys.mjs +++ b/browser/components/sessionstore/SessionStore.sys.mjs @@ -2120,7 +2120,6 @@ var SessionStoreInternal = { @@ -69,7 +69,7 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e winData.workspaceID = workspaceID; } }, -@@ -5554,14 +5557,15 @@ var SessionStoreInternal = { +@@ -5554,11 +5557,12 @@ var SessionStoreInternal = { } let tabbrowser = aWindow.gBrowser; @@ -82,18 +82,12 @@ index be029379c101a0105d4837136e064e6007b67c3e..f998ad44015b05104e8a1dbeebd7b94e + winData.splitViewData = aWindow.gZenViewSplitter?.storeDataForSessionStore(); // update the internal state data for this window for (let tab of tabs) { -- if (tab == aWindow.FirefoxViewHandler.tab) { -+ if (tab == aWindow.FirefoxViewHandler.tab || tab.hasAttribute("zen-empty-tab")) { - continue; - } - let tabData = lazy.TabState.collect(tab, TAB_CUSTOM_VALUES.get(tab)); -@@ -5580,8 +5584,8 @@ var SessionStoreInternal = { - // We don't store the Firefox View tab in Session Store, so if it was the last selected "tab" when + if (tab == aWindow.FirefoxViewHandler.tab) { +@@ -5581,7 +5585,7 @@ var SessionStoreInternal = { // a window is closed, point to the first item in the tab strip instead (it will never be the Firefox View tab, // since it's only inserted into the tab strip after it's selected). -- if (aWindow.FirefoxViewHandler.tab?.selected) { + if (aWindow.FirefoxViewHandler.tab?.selected) { - selectedIndex = 1; -+ if (aWindow.FirefoxViewHandler.tab?.selected || tabbrowser.selectedTab.hasAttribute("zen-empty-tab")) { + selectedIndex = 0; winData.title = tabbrowser.tabs[0].label; } diff --git a/src/browser/components/tabbrowser/content/tabbrowser-js.patch b/src/browser/components/tabbrowser/content/tabbrowser-js.patch index b3c1aab7b..56effa4e6 100644 --- a/src/browser/components/tabbrowser/content/tabbrowser-js.patch +++ b/src/browser/components/tabbrowser/content/tabbrowser-js.patch @@ -1,5 +1,5 @@ diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js -index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b3d040bba 100644 +index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..41f869c4841ab4055b706487611f022dd09884ba 100644 --- a/browser/components/tabbrowser/content/tabbrowser.js +++ b/browser/components/tabbrowser/content/tabbrowser.js @@ -422,15 +422,49 @@ @@ -316,9 +316,11 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b let url = "about:blank"; if (tabData.entries?.length) { -@@ -3651,7 +3740,8 @@ +@@ -3650,8 +3739,10 @@ + insertTab: false, skipLoad: true, preferredRemoteType, ++ _forZenEmptyTab: tabData.zenIsEmpty, }); - + tab._originalUrl = url; @@ -326,7 +328,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (select) { tabToSelect = tab; } -@@ -3663,7 +3753,8 @@ +@@ -3663,7 +3754,8 @@ this.pinTab(tab); // Then ensure all the tab open/pinning information is sent. this._fireTabOpen(tab, {}); @@ -336,7 +338,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b let { groupId } = tabData; const tabGroup = tabGroupWorkingData.get(groupId); // if a tab refers to a tab group we don't know, skip any group -@@ -3677,7 +3768,10 @@ +@@ -3677,7 +3769,10 @@ tabGroup.stateData.id, tabGroup.stateData.color, tabGroup.stateData.collapsed, @@ -348,7 +350,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b ); tabsFragment.appendChild(tabGroup.node); } -@@ -3722,9 +3816,23 @@ +@@ -3722,9 +3817,23 @@ // to remove the old selected tab. if (tabToSelect) { let leftoverTab = this.selectedTab; @@ -372,7 +374,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (tabs.length > 1 || !tabs[0].selected) { this._updateTabsAfterInsert(); -@@ -3919,7 +4027,7 @@ +@@ -3919,7 +4028,7 @@ // Ensure we have an index if one was not provided. if (typeof elementIndex != "number" && typeof tabIndex != "number") { // Move the new tab after another tab if needed, to the end otherwise. @@ -381,7 +383,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if ( !bulkOrderedOpen && ((openerTab && -@@ -3942,7 +4050,7 @@ +@@ -3942,7 +4051,7 @@ ) { elementIndex = Infinity; } else if (previousTab.visible) { @@ -390,7 +392,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } else if (previousTab == FirefoxViewHandler.tab) { elementIndex = 0; } -@@ -3970,14 +4078,14 @@ +@@ -3970,14 +4079,14 @@ } // Ensure index is within bounds. if (tab.pinned) { @@ -409,7 +411,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b // Prevent a flash of unstyled content by setting up the tab content // and inherited attributes before appending it (see Bug 1592054): -@@ -3985,7 +4093,7 @@ +@@ -3985,7 +4094,7 @@ this.tabContainer._invalidateCachedTabs(); @@ -418,7 +420,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (this.isTab(itemAfter) && itemAfter.group == tabGroup) { // Place at the front of, or between tabs in, the same tab group this.tabContainer.insertBefore(tab, itemAfter); -@@ -4018,6 +4126,7 @@ +@@ -4018,6 +4127,7 @@ if (pinned) { this._updateTabBarForPinnedTabs(); } @@ -426,7 +428,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b TabBarVisibility.update(); } -@@ -4307,6 +4416,9 @@ +@@ -4307,6 +4417,9 @@ return; } @@ -436,7 +438,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b this.removeTabs(selectedTabs, { isUserTriggered, telemetrySource }); } -@@ -4568,6 +4680,7 @@ +@@ -4568,6 +4681,7 @@ telemetrySource, } = {} ) { @@ -444,7 +446,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b // When 'closeWindowWithLastTab' pref is enabled, closing all tabs // can be considered equivalent to closing the window. if ( -@@ -4657,6 +4770,7 @@ +@@ -4657,6 +4771,7 @@ if (lastToClose) { this.removeTab(lastToClose, aParams); } @@ -452,7 +454,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } catch (e) { console.error(e); } -@@ -4695,6 +4809,12 @@ +@@ -4695,6 +4810,12 @@ aTab._closeTimeNoAnimTimerId = Glean.browserTabclose.timeNoAnim.start(); } @@ -465,7 +467,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b // Handle requests for synchronously removing an already // asynchronously closing tab. if (!animate && aTab.closing) { -@@ -4709,6 +4829,9 @@ +@@ -4709,6 +4830,9 @@ // state). let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width; let isLastTab = this.#isLastTabInWindow(aTab); @@ -475,7 +477,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if ( !this._beginRemoveTab(aTab, { closeWindowFastpath: true, -@@ -4891,7 +5014,7 @@ +@@ -4891,7 +5015,7 @@ closeWindowWithLastTab != null ? closeWindowWithLastTab : !window.toolbar.visible || @@ -484,7 +486,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (closeWindow) { // We've already called beforeunload on all the relevant tabs if we get here, -@@ -4915,6 +5038,7 @@ +@@ -4915,6 +5039,7 @@ newTab = true; } @@ -492,7 +494,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b aTab._endRemoveArgs = [closeWindow, newTab]; // swapBrowsersAndCloseOther will take care of closing the window without animation. -@@ -4955,9 +5079,7 @@ +@@ -4955,9 +5080,7 @@ aTab._mouseleave(); if (newTab) { @@ -503,7 +505,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } else { TabBarVisibility.update(); } -@@ -5090,6 +5212,7 @@ +@@ -5090,6 +5213,7 @@ this.tabs[i]._tPos = i; } @@ -511,7 +513,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (!this._windowIsClosing) { // update tab close buttons state this.tabContainer._updateCloseButtons(); -@@ -5302,6 +5425,7 @@ +@@ -5302,6 +5426,7 @@ } let excludeTabs = new Set(aExcludeTabs); @@ -519,7 +521,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b // If this tab has a successor, it should be selectable, since // hiding or closing a tab removes that tab as a successor. -@@ -5314,13 +5438,13 @@ +@@ -5314,13 +5439,13 @@ !excludeTabs.has(aTab.owner) && Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose") ) { @@ -535,7 +537,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b ); let tab = this.tabContainer.findNextTab(aTab, { -@@ -5336,7 +5460,7 @@ +@@ -5336,7 +5461,7 @@ } if (tab) { @@ -544,7 +546,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } // If no qualifying visible tab was found, see if there is a tab in -@@ -5357,7 +5481,7 @@ +@@ -5357,7 +5482,7 @@ }); } @@ -553,7 +555,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } _blurTab(aTab) { -@@ -5759,10 +5883,10 @@ +@@ -5759,10 +5884,10 @@ SessionStore.deleteCustomTabValue(aTab, "hiddenBy"); } @@ -566,7 +568,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b aTab.selected || aTab.closing || // Tabs that are sharing the screen, microphone or camera cannot be hidden. -@@ -5952,7 +6076,7 @@ +@@ -5952,7 +6077,7 @@ * `true` if element is a `` */ isTabGroup(element) { @@ -575,7 +577,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } /** -@@ -6029,7 +6153,7 @@ +@@ -6029,7 +6154,7 @@ // Don't allow mixing pinned and unpinned tabs. if (this.isTab(element) && element.pinned) { @@ -584,7 +586,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b } else { tabIndex = Math.max(tabIndex, this.pinnedTabCount); } -@@ -6055,10 +6179,16 @@ +@@ -6055,10 +6180,16 @@ this.#handleTabMove( element, () => { @@ -603,7 +605,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (neighbor && this.isTab(element) && tabIndex > element._tPos) { neighbor.after(element); } else { -@@ -6116,13 +6246,13 @@ +@@ -6116,13 +6247,13 @@ #moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) { if (this.isTabGroupLabel(targetElement)) { targetElement = targetElement.group; @@ -619,7 +621,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b element = element.group; if (targetElement?.group) { targetElement = targetElement.group; -@@ -6130,8 +6260,15 @@ +@@ -6130,8 +6261,15 @@ } // Don't allow mixing pinned and unpinned tabs. @@ -636,7 +638,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b moveBefore = false; } else if (!element.pinned && targetElement && targetElement.pinned) { // If the caller asks to move an unpinned element next to a pinned -@@ -6145,7 +6282,7 @@ +@@ -6145,7 +6283,7 @@ // move the tab group right before the first unpinned tab. // 4. Moving a tab group and the first unpinned tab is grouped: // move the tab group right before the first unpinned tab's tab group. @@ -645,7 +647,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b if (targetElement.group) { targetElement = targetElement.group; } -@@ -6153,6 +6290,7 @@ +@@ -6153,6 +6291,7 @@ } let getContainer = () => @@ -653,7 +655,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b element.pinned ? this.tabContainer.pinnedTabsContainer : this.tabContainer; -@@ -6210,7 +6348,7 @@ +@@ -6210,7 +6349,7 @@ if (!this.isTab(aTab)) { throw new Error("Can only move a tab into a tab group"); } @@ -662,7 +664,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b return; } if (aTab.group && aTab.group.id === aGroup.id) { -@@ -6304,6 +6442,10 @@ +@@ -6304,6 +6443,10 @@ moveActionCallback(); @@ -673,7 +675,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b // Clear tabs cache after moving nodes because the order of tabs may have // changed. this.tabContainer._invalidateCachedTabs(); -@@ -7198,7 +7340,7 @@ +@@ -7198,7 +7341,7 @@ // preventDefault(). It will still raise the window if appropriate. break; } @@ -682,7 +684,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b window.focus(); aEvent.preventDefault(); break; -@@ -8143,6 +8285,7 @@ +@@ -8143,6 +8286,7 @@ aWebProgress.isTopLevel ) { this.mTab.setAttribute("busy", "true"); @@ -690,7 +692,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b gBrowser._tabAttrModified(this.mTab, ["busy"]); this.mTab._notselectedsinceload = !this.mTab.selected; } -@@ -9108,7 +9251,7 @@ var TabContextMenu = { +@@ -9108,7 +9252,7 @@ var TabContextMenu = { ); contextUnpinSelectedTabs.hidden = !this.contextTab.pinned || !this.multiselected; @@ -699,7 +701,7 @@ index 96fd8acdc09cc4c9649d1ed7503c2a0bde536613..77d690c9beb306781a5f7325473a2a9b // Move Tab items let contextMoveTabOptions = document.getElementById( "context_moveTabOptions" -@@ -9384,6 +9527,7 @@ var TabContextMenu = { +@@ -9384,6 +9528,7 @@ var TabContextMenu = { ) ); } else { diff --git a/src/zen/common/ZenSessionStore.mjs b/src/zen/common/ZenSessionStore.mjs index 1674b7c5e..2b86d886e 100644 --- a/src/zen/common/ZenSessionStore.mjs +++ b/src/zen/common/ZenSessionStore.mjs @@ -18,9 +18,6 @@ if (tabData.zenPinnedId) { tab.setAttribute('zen-pin-id', tabData.zenPinnedId); } - if (tabData.zenIsEmpty) { - tab.setAttribute('zen-empty-tab', 'true'); - } if (tabData.zenHasStaticLabel) { tab.setAttribute('zen-has-static-label', 'true'); } diff --git a/src/zen/glance/ZenGlanceManager.mjs b/src/zen/glance/ZenGlanceManager.mjs index 6103cfa18..be5c0b286 100644 --- a/src/zen/glance/ZenGlanceManager.mjs +++ b/src/zen/glance/ZenGlanceManager.mjs @@ -624,6 +624,7 @@ gBrowser.moveTabAfter(this.#currentTab, this.#currentParentTab); + const browserRect = window.windowUtils.getBoundsWithoutFlushing(this.browserWrapper); this.#currentTab.removeAttribute('zen-glance-tab'); this._clearContainerStyles(this.browserWrapper); this.browserWrapper.removeAttribute('has-finished-animation'); @@ -635,6 +636,7 @@ .closest('.browserSidebarContainer') .classList.remove('zen-glance-background'); this.#currentParentTab._visuallySelected = false; + gBrowser.TabStateFlusher.flush(this.#currentTab); const sidebarButtons = this.browserWrapper.querySelector('.zen-glance-sidebar-container'); if (sidebarButtons) { sidebarButtons.remove(); @@ -648,6 +650,9 @@ this.finishOpeningGlance(); return; } + // Write the styles early to avoid flickering + this.browserWrapper.style.width = `${browserRect.width}px`; + this.browserWrapper.style.height = `${browserRect.height}px`; await gZenUIManager.motion.animate( this.browserWrapper, { diff --git a/src/zen/workspaces/ZenWorkspaces.mjs b/src/zen/workspaces/ZenWorkspaces.mjs index 240b0bd01..4989cfa81 100644 --- a/src/zen/workspaces/ZenWorkspaces.mjs +++ b/src/zen/workspaces/ZenWorkspaces.mjs @@ -314,6 +314,14 @@ var gZenWorkspaces = new (class extends nsZenMultiWindowFeature { } _initializeEmptyTab() { + for (const tab of gBrowser.tabs) { + // Check if session store has an empty tab + if (tab.hasAttribute('zen-empty-tab')) { + this.log('Found existing empty tab from session store!'); + this._emptyTab = tab; + return; + } + } this._emptyTab = gBrowser.addTrustedTab('about:blank', { inBackground: true, userContextId: 0, @@ -952,9 +960,7 @@ var gZenWorkspaces = new (class extends nsZenMultiWindowFeature { } if (this._tabToRemoveForEmpty && !removedEmptyTab) { - const tabs = gBrowser.tabs.filter( - (tab) => !tab.collapsed && !tab.hasAttribute('zen-empty-tab') - ); + const tabs = gBrowser.tabs.filter((tab) => !tab.collapsed); if ( typeof this._tabToSelect === 'number' && this._tabToSelect >= 0 && @@ -964,13 +970,7 @@ var gZenWorkspaces = new (class extends nsZenMultiWindowFeature { ) { this.log(`Found tab to select: ${this._tabToSelect}, ${tabs.length}`); setTimeout(() => { - let tabToUse = gZenGlanceManager.getTabOrGlanceParent(tabs[this._tabToSelect]); - if (tabToUse.pinned) { - // We are before the empty tab here, so we need to select the next tab - tabToUse = gZenGlanceManager.getTabOrGlanceParent( - tabs[this._tabToSelect + 1] || tabs[this._tabToSelect] - ); - } + let tabToUse = gZenGlanceManager.getTabOrGlanceParent(tabs[this._tabToSelect + 1]); gBrowser.selectedTab = tabToUse; this._removedByStartupPage = true; gBrowser.removeTab(this._tabToRemoveForEmpty, {