Merge branch 'window-sync' of https://github.com/zen-browser/desktop into window-sync

This commit is contained in:
Mr. M
2025-11-21 13:19:30 +01:00
2 changed files with 83 additions and 10 deletions

View File

@@ -1,5 +1,6 @@
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4cd44d980e 100644
index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4cd44d980e 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -432,15 +432,64 @@
@@ -479,6 +480,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
TabBarVisibility.update();
}
@@ -4896,6 +5024,7 @@
@@ -4896,6 +5024,7 @@
telemetrySource,
} = {}
@@ -487,6 +489,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
// When 'closeWindowWithLastTab' pref is enabled, closing all tabs
// can be considered equivalent to closing the window.
if (
@@ -4985,6 +5114,7 @@
@@ -4985,6 +5114,7 @@
if (lastToClose) {
this.removeTab(lastToClose, aParams);
@@ -495,6 +498,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
} catch (e) {
console.error(e);
}
@@ -5023,6 +5153,12 @@
@@ -5023,6 +5153,12 @@
aTab._closeTimeNoAnimTimerId = Glean.browserTabclose.timeNoAnim.start();
}
@@ -508,6 +512,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
// Handle requests for synchronously removing an already
// asynchronously closing tab.
if (!animate && aTab.closing) {
@@ -5037,6 +5173,9 @@
@@ -5037,6 +5173,9 @@
// state).
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
@@ -518,6 +523,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
if (
!this._beginRemoveTab(aTab, {
closeWindowFastpath: true,
@@ -5085,7 +5224,13 @@
@@ -5085,7 +5224,13 @@
// We're not animating, so we can cancel the animation stopwatch.
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
@@ -533,6 +539,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
return;
}
@@ -5219,7 +5364,7 @@
@@ -5219,7 +5364,7 @@
closeWindowWithLastTab != null
? closeWindowWithLastTab
@@ -542,6 +549,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
if (closeWindow) {
// We've already called beforeunload on all the relevant tabs if we get here,
@@ -5243,6 +5388,7 @@
@@ -5243,6 +5388,7 @@
newTab = true;
@@ -550,6 +558,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
aTab._endRemoveArgs = [closeWindow, newTab];
// swapBrowsersAndCloseOther will take care of closing the window without animation.
@@ -5283,13 +5429,7 @@
@@ -5283,13 +5429,7 @@
aTab._mouseleave();
@@ -565,6 +574,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
} else {
TabBarVisibility.update();
}
@@ -5422,6 +5562,7 @@
@@ -5422,6 +5562,7 @@
this.tabs[i]._tPos = i;
}
@@ -573,6 +583,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
if (!this._windowIsClosing) {
// update tab close buttons state
this.tabContainer._updateCloseButtons();
@@ -5643,6 +5784,7 @@
@@ -5643,6 +5784,7 @@
}
@@ -581,6 +592,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
// If this tab has a successor, it should be selectable, since
// hiding or closing a tab removes that tab as a successor.
@@ -5655,13 +5797,13 @@
@@ -5655,13 +5797,13 @@
!excludeTabs.has(aTab.owner) &&
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
@@ -597,6 +609,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
);
let tab = this.tabContainer.findNextTab(aTab, {
@@ -5677,7 +5819,7 @@
@@ -5677,7 +5819,7 @@
}
@@ -606,6 +619,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
}
// If no qualifying visible tab was found, see if there is a tab in
@@ -5698,7 +5840,7 @@
@@ -5698,7 +5840,7 @@
});
}
@@ -615,6 +629,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
}
_blurTab(aTab) {
@@ -6104,10 +6246,10 @@
@@ -6104,10 +6246,10 @@
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
}
@@ -628,6 +643,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
aTab.selected ||
aTab.closing ||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
@@ -6166,6 +6308,7 @@
@@ -6166,6 +6308,7 @@
* @param {MozTabbrowserTab|MozTabbrowserTabGroup|MozTabbrowserTabGroup.labelElement} aTab
*/
@@ -636,6 +652,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
if (this.tabs.length == 1) {
return null;
}
@@ -6299,7 +6442,7 @@
@@ -6299,7 +6442,7 @@
* `true` if element is a `<tab-group>`
*/
@@ -645,6 +662,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
}
/**
@@ -6375,8 +6518,8 @@
@@ -6375,8 +6518,8 @@
}
@@ -656,6 +674,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
} else {
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
}
@@ -6402,10 +6545,16 @@
@@ -6402,10 +6545,16 @@
this.#handleTabMove(
element,
@@ -675,6 +694,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
if (neighbor && this.isTab(element) && tabIndex > element._tPos) {
neighbor.after(element);
} else {
@@ -6463,23 +6612,28 @@
@@ -6463,23 +6612,28 @@
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
if (this.isTabGroupLabel(targetElement)) {
@@ -710,6 +730,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
} else if (!element.pinned && targetElement && targetElement.pinned) {
// If the caller asks to move an unpinned element next to a pinned
// tab, move the unpinned element to be the first unpinned element
@@ -6492,14 +6646,34 @@
@@ -6492,14 +6646,34 @@
// move the tab group right before the first unpinned tab.
// 4. Moving a tab group and the first unpinned tab is grouped:
@@ -746,6 +767,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
element.pinned
? this.tabContainer.pinnedTabsContainer
: this.tabContainer;
@@ -6508,7 +6682,7 @@
@@ -6508,7 +6682,7 @@
element,
() => {
@@ -755,6 +777,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
} else if (targetElement) {
targetElement.after(element);
} else {
@@ -6580,10 +6754,10 @@
@@ -6580,10 +6754,10 @@
* @param {TabMetricsContext} [metricsContext]
*/
@@ -768,6 +791,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
return;
}
if (aTab.group && aTab.group.id === aGroup.id) {
@@ -6613,6 +6787,7 @@
@@ -6613,6 +6787,7 @@
let state = {
@@ -776,6 +800,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
};
if (tab.visible) {
state.elementIndex = tab.elementIndex;
@@ -6639,7 +6814,7 @@
@@ -6639,7 +6814,7 @@
let changedTabGroup =
previousTabState.tabGroupId != currentTabState.tabGroupId;
@@ -785,6 +810,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
tab.dispatchEvent(
new CustomEvent("TabMove", {
bubbles: true,
@@ -6676,6 +6851,10 @@
@@ -6676,6 +6851,10 @@
moveActionCallback();
@@ -796,6 +822,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
// Clear tabs cache after moving nodes because the order of tabs may have
// changed.
this.tabContainer._invalidateCachedTabs();
@@ -7576,7 +7755,7 @@
@@ -7576,7 +7755,7 @@
// preventDefault(). It will still raise the window if appropriate.
break;
@@ -805,6 +832,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
window.focus();
aEvent.preventDefault();
break;
@@ -7593,7 +7772,6 @@
@@ -7593,7 +7772,6 @@
}
case "TabGroupCollapse":
@@ -813,6 +841,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
});
break;
case "TabGroupCreateByUser":
@@ -8542,6 +8720,7 @@
@@ -8542,6 +8720,7 @@
aWebProgress.isTopLevel
) {
@@ -821,6 +850,7 @@ index c0eafd4faf8d57b8486c5bf8917375850ec8147e..30c8fd7e978eb3036f35b17ae3f6ea4c
gBrowser._tabAttrModified(this.mTab, ["busy"]);
this.mTab._notselectedsinceload = !this.mTab.selected;
}
@@ -9543,7 +9722,7 @@ var TabContextMenu = {
@@ -9543,7 +9722,7 @@ var TabContextMenu = {
);
contextUnpinSelectedTabs.hidden =

View File

@@ -87,8 +87,11 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
onTabIconChanged(tab, url = null) {
tab.dispatchEvent(new CustomEvent('ZenTabIconChanged', { bubbles: true, detail: { tab } }));
tab.dispatchEvent(new CustomEvent('ZenTabIconChanged', { bubbles: true, detail: { tab } }));
const iconUrl = url ?? tab.iconImage.src;
if (tab.hasAttribute('zen-essential')) {
tab.style.setProperty('--zen-essential-tab-icon', `url(${iconUrl})`);
if (tab.hasAttribute('zen-essential')) {
tab.style.setProperty('--zen-essential-tab-icon', `url(${iconUrl})`);
}
@@ -156,6 +159,17 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
}
async _onTabClick(e) {
const tab = e.target?.closest('tab');
if (e.button === 1 && tab) {
await this.onCloseTabShortcut(e, tab, {
closeIfPending: Services.prefs.getBoolPref(
'zen.pinned-tab-manager.wheel-close-if-pending'
),
});
}
}
async resetPinnedTab(tab) {
if (!tab) {
tab = TabContextMenu.contextTab;
@@ -181,6 +195,9 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
_initClosePinnedTabShortcut() {
let cmdClose = document.getElementById('cmd_close');
_initClosePinnedTabShortcut() {
let cmdClose = document.getElementById('cmd_close');
if (cmdClose) {
cmdClose.addEventListener('command', this.onCloseTabShortcut.bind(this));
}
@@ -212,6 +229,32 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
),
];
async onCloseTabShortcut(
event,
selectedTab = gBrowser.selectedTab,
{
behavior = lazy.zenPinnedTabCloseShortcutBehavior,
noClose = false,
closeIfPending = false,
alwaysUnload = false,
folderToUnload = null,
} = {}
) {
try {
const tabs = Array.isArray(selectedTab) ? selectedTab : [selectedTab];
const pinnedTabs = [
...new Set(
tabs
.flatMap((tab) => {
if (tab.group?.hasAttribute('split-view-group')) {
return tab.group.tabs;
}
return tab;
})
.filter((tab) => tab?.pinned)
),
];
if (!pinnedTabs.length) {
return;
}
@@ -944,16 +987,16 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
}
}
async onTabLabelChanged(tab) {
tab.dispatchEvent(new CustomEvent('ZenTabLabelChanged', { detail: { tab } }));
if (!this._pinsCache) {
return;
}
// If our current pin in the cache point to about:blank, we need to update the entry
const pin = this._pinsCache.find((pin) => pin.uuid === tab.getAttribute('zen-pin-id'));
if (!pin) {
return;
}
async onTabLabelChanged(tab) {
tab.dispatchEvent(new CustomEvent('ZenTabLabelChanged', { detail: { tab } }));
if (!this._pinsCache) {
return;
}
// If our current pin in the cache point to about:blank, we need to update the entry
const pin = this._pinsCache.find((pin) => pin.uuid === tab.getAttribute('zen-pin-id'));
if (!pin) {
return;
}
if (pin.url === 'about:blank' && tab.linkedBrowser.currentURI.spec !== 'about:blank') {
await this.replacePinnedUrlWithCurrent(tab);