mirror of
https://github.com/zen-browser/desktop.git
synced 2026-06-14 07:23:42 +00:00
Compare commits
3 Commits
stable
...
chore/upst
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
690fff1ca0 | ||
|
|
d5cbe55d2b | ||
|
|
7c885218f7 |
@@ -60,7 +60,7 @@ jobs:
|
||||
|
||||
brew install watchman
|
||||
|
||||
cargo install apple-codesign --locked --force
|
||||
cargo install apple-codesign
|
||||
|
||||
- name: Force usage of gnu-tar
|
||||
run: |
|
||||
|
||||
@@ -35,7 +35,7 @@ Zen is a firefox-based browser with the aim of pushing your productivity to a ne
|
||||
### Firefox Versions
|
||||
|
||||
- [`Release`](https://zen-browser.app/download) - Is currently built using Firefox version `151.0.4`! 🚀
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 151.0.4`!
|
||||
- [`Twilight`](https://zen-browser.app/download?twilight) - Is currently built using Firefox version `RC 152.0`!
|
||||
|
||||
### Contributing
|
||||
|
||||
|
||||
@@ -1 +1 @@
|
||||
9a6aa4c359d1fb6ac60decc82402f82d49a17cea
|
||||
a58ad2d2952face15859068dd4421cf68d6a9dda
|
||||
@@ -1,5 +1,5 @@
|
||||
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008ede72076 100644
|
||||
index 43fb79a3060e20f671ae6ffc26350c7abf497702..028dfcba9e23a17e4152071dd58eb97a70e59c10 100644
|
||||
--- a/browser/components/tabbrowser/content/tabbrowser.js
|
||||
+++ b/browser/components/tabbrowser/content/tabbrowser.js
|
||||
@@ -502,6 +502,7 @@
|
||||
@@ -79,17 +79,15 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
set selectedTab(val) {
|
||||
if (
|
||||
gSharedTabWarning.willShowSharedTabWarning(val) ||
|
||||
@@ -592,6 +644,9 @@
|
||||
@@ -592,6 +644,7 @@
|
||||
) {
|
||||
return;
|
||||
}
|
||||
+ if (gZenWorkspaces.onBeforeTabSelect(val)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ gZenWorkspaces.onBeforeTabSelect(val);
|
||||
// Update the tab
|
||||
this.tabbox.selectedTab = val;
|
||||
}
|
||||
@@ -659,6 +714,10 @@
|
||||
@@ -659,6 +712,10 @@
|
||||
userContextId = parseInt(tabArgument.getAttribute("usercontextid"), 10);
|
||||
}
|
||||
|
||||
@@ -100,7 +98,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (tabArgument && tabArgument.linkedBrowser) {
|
||||
remoteType = tabArgument.linkedBrowser.remoteType;
|
||||
initialBrowsingContextGroupId =
|
||||
@@ -751,6 +810,8 @@
|
||||
@@ -751,6 +808,8 @@
|
||||
this.tabpanels.appendChild(panel);
|
||||
|
||||
let tab = this.tabs[0];
|
||||
@@ -109,7 +107,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
tab.linkedPanel = uniqueId;
|
||||
this._selectedTab = tab;
|
||||
this._selectedBrowser = browser;
|
||||
@@ -1121,13 +1182,18 @@
|
||||
@@ -1121,13 +1180,18 @@
|
||||
}
|
||||
|
||||
this.showTab(aTab);
|
||||
@@ -129,7 +127,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
aTab.setAttribute("pinned", "true");
|
||||
this._updateTabBarForPinnedTabs();
|
||||
@@ -1140,11 +1206,19 @@
|
||||
@@ -1140,11 +1204,19 @@
|
||||
}
|
||||
|
||||
this.#handleTabMove(aTab, () => {
|
||||
@@ -150,7 +148,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
});
|
||||
|
||||
aTab.style.marginInlineStart = "";
|
||||
@@ -1321,6 +1395,9 @@
|
||||
@@ -1321,6 +1393,9 @@
|
||||
|
||||
let LOCAL_PROTOCOLS = ["chrome:", "about:", "resource:", "data:"];
|
||||
|
||||
@@ -160,7 +158,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (
|
||||
aIconURL &&
|
||||
!LOCAL_PROTOCOLS.some(protocol => aIconURL.startsWith(protocol))
|
||||
@@ -1330,6 +1407,9 @@
|
||||
@@ -1330,6 +1405,9 @@
|
||||
);
|
||||
return;
|
||||
}
|
||||
@@ -170,7 +168,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
let browser = this.getBrowserForTab(aTab);
|
||||
browser.mIconURL = aIconURL;
|
||||
@@ -1652,7 +1732,6 @@
|
||||
@@ -1652,7 +1730,6 @@
|
||||
|
||||
// Preview mode should not reset the owner
|
||||
if (!this._previewMode && !oldTab.selected) {
|
||||
@@ -178,7 +176,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
let lastRelatedTab = this._lastRelatedTabMap.get(oldTab);
|
||||
@@ -1743,6 +1822,7 @@
|
||||
@@ -1743,6 +1820,7 @@
|
||||
if (!this._previewMode) {
|
||||
newTab.recordTimeFromUnloadToReload();
|
||||
newTab.updateLastAccessed();
|
||||
@@ -186,7 +184,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
oldTab.updateLastAccessed();
|
||||
// if this is the foreground window, update the last-seen timestamps.
|
||||
if (this.ownerGlobal == BrowserWindowTracker.getTopWindow()) {
|
||||
@@ -1957,6 +2037,9 @@
|
||||
@@ -1957,6 +2035,9 @@
|
||||
}
|
||||
|
||||
let activeEl = document.activeElement;
|
||||
@@ -196,7 +194,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// If focus is on the old tab, move it to the new tab.
|
||||
if (activeEl == oldTab) {
|
||||
newTab.focus();
|
||||
@@ -1995,7 +2078,7 @@
|
||||
@@ -1995,7 +2076,7 @@
|
||||
// Focus the location bar if it was previously focused for that tab.
|
||||
// In full screen mode, only bother making the location bar visible
|
||||
// if the tab is a blank one.
|
||||
@@ -205,7 +203,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
let selectURL = () => {
|
||||
if (this._asyncTabSwitching) {
|
||||
// Set _awaitingSetURI flag to suppress popup notification
|
||||
@@ -2283,7 +2366,12 @@
|
||||
@@ -2283,7 +2364,12 @@
|
||||
return this._setTabLabel(aTab, aLabel);
|
||||
}
|
||||
|
||||
@@ -219,7 +217,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (!aLabel || (isURL && /^about:reader\?url=/.test(aLabel))) {
|
||||
return false;
|
||||
}
|
||||
@@ -2408,7 +2496,7 @@
|
||||
@@ -2408,7 +2494,7 @@
|
||||
newIndex = this.selectedTab._tPos + 1;
|
||||
}
|
||||
|
||||
@@ -228,7 +226,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (this.isTabGroupLabel(targetTab)) {
|
||||
throw new Error(
|
||||
"Replacing a tab group label with a tab is not supported"
|
||||
@@ -2685,6 +2773,7 @@
|
||||
@@ -2685,6 +2771,7 @@
|
||||
uriIsAboutBlank,
|
||||
userContextId,
|
||||
skipLoad,
|
||||
@@ -236,7 +234,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} = {}) {
|
||||
let b = document.createXULElement("browser");
|
||||
// Use the JSM global to create the permanentKey, so that if the
|
||||
@@ -2758,8 +2847,7 @@
|
||||
@@ -2758,8 +2845,7 @@
|
||||
// we use a different attribute name for this?
|
||||
b.setAttribute("name", name);
|
||||
}
|
||||
@@ -246,7 +244,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
b.setAttribute("transparent", "true");
|
||||
}
|
||||
|
||||
@@ -2929,7 +3017,7 @@
|
||||
@@ -2929,7 +3015,7 @@
|
||||
|
||||
let panel = this.getPanel(browser);
|
||||
let uniqueId = this._generateUniquePanelID();
|
||||
@@ -255,7 +253,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
aTab.linkedPanel = uniqueId;
|
||||
|
||||
// Inject the <browser> into the DOM if necessary.
|
||||
@@ -2989,8 +3077,8 @@
|
||||
@@ -2989,8 +3075,8 @@
|
||||
// If we transitioned from one browser to two browsers, we need to set
|
||||
// hasSiblings=false on both the existing browser and the new browser.
|
||||
if (this.tabs.length == 2) {
|
||||
@@ -266,7 +264,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} else {
|
||||
aTab.linkedBrowser.browsingContext.hasSiblings = this.tabs.length > 1;
|
||||
}
|
||||
@@ -3175,7 +3263,6 @@
|
||||
@@ -3175,7 +3261,6 @@
|
||||
this.selectedTab = this.addTrustedTab(BROWSER_NEW_TAB_URL, {
|
||||
tabIndex: tab._tPos + 1,
|
||||
userContextId: tab.userContextId,
|
||||
@@ -274,7 +272,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
focusUrlBar: true,
|
||||
});
|
||||
resolve(this.selectedBrowser);
|
||||
@@ -3285,6 +3372,10 @@
|
||||
@@ -3285,6 +3370,10 @@
|
||||
schemelessInput,
|
||||
hasValidUserGestureActivation = false,
|
||||
textDirectiveUserActivation = false,
|
||||
@@ -285,7 +283,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} = {}
|
||||
) {
|
||||
// all callers of addTab that pass a params object need to pass
|
||||
@@ -3295,10 +3386,25 @@
|
||||
@@ -3295,10 +3384,25 @@
|
||||
);
|
||||
}
|
||||
|
||||
@@ -296,7 +294,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
+
|
||||
+ let hasZenDefaultUserContextId = false;
|
||||
+ let zenForcedWorkspaceId = undefined;
|
||||
+ if (beforeRouteResult.isRouteFound) {
|
||||
+ if (beforeRouteResult.userContextId) {
|
||||
+ userContextId = beforeRouteResult.userContextId;
|
||||
+ hasZenDefaultUserContextId = true;
|
||||
+ } else if (typeof gZenWorkspaces !== "undefined" && !_forZenEmptyTab) {
|
||||
@@ -311,7 +309,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// If we're opening a foreground tab, set the owner by default.
|
||||
ownerTab ??= inBackground ? null : this.selectedTab;
|
||||
|
||||
@@ -3306,6 +3412,7 @@
|
||||
@@ -3306,6 +3410,7 @@
|
||||
if (this.selectedTab.owner) {
|
||||
this.selectedTab.owner = null;
|
||||
}
|
||||
@@ -319,7 +317,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
// Find the tab that opened this one, if any. This is used for
|
||||
// determining positioning, and inherited attributes such as the
|
||||
@@ -3358,6 +3465,22 @@
|
||||
@@ -3358,6 +3463,22 @@
|
||||
noInitialLabel,
|
||||
skipBackgroundNotify,
|
||||
});
|
||||
@@ -342,7 +340,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (insertTab) {
|
||||
// Insert the tab into the tab container in the correct position.
|
||||
this.#insertTabAtIndex(t, {
|
||||
@@ -3366,6 +3489,7 @@
|
||||
@@ -3366,6 +3487,7 @@
|
||||
ownerTab,
|
||||
openerTab,
|
||||
pinned,
|
||||
@@ -350,7 +348,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
bulkOrderedOpen,
|
||||
tabGroup: tabGroup ?? openerTab?.group,
|
||||
});
|
||||
@@ -3384,6 +3508,7 @@
|
||||
@@ -3384,6 +3506,7 @@
|
||||
openWindowInfo,
|
||||
skipLoad,
|
||||
triggeringRemoteType,
|
||||
@@ -358,7 +356,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}));
|
||||
|
||||
if (focusUrlBar) {
|
||||
@@ -3508,6 +3633,12 @@
|
||||
@@ -3508,6 +3631,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +369,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// Additionally send pinned tab events
|
||||
if (pinned) {
|
||||
this.#notifyPinnedStatus(t);
|
||||
@@ -3518,6 +3649,9 @@
|
||||
@@ -3518,6 +3647,9 @@
|
||||
if (!inBackground) {
|
||||
this.selectedTab = t;
|
||||
}
|
||||
@@ -381,7 +379,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
return t;
|
||||
}
|
||||
|
||||
@@ -3750,6 +3884,7 @@
|
||||
@@ -3750,6 +3882,7 @@
|
||||
isAdoptingGroup = false,
|
||||
isUserTriggered = false,
|
||||
telemetryUserCreateSource = "unknown",
|
||||
@@ -389,7 +387,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} = {}
|
||||
) {
|
||||
if (
|
||||
@@ -3760,9 +3895,6 @@
|
||||
@@ -3760,9 +3893,6 @@
|
||||
!this.isSplitViewWrapper(tabOrSplitView)
|
||||
)
|
||||
) {
|
||||
@@ -399,7 +397,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
if (!color) {
|
||||
@@ -3783,9 +3915,14 @@
|
||||
@@ -3783,9 +3913,14 @@
|
||||
label,
|
||||
isAdoptingGroup
|
||||
);
|
||||
@@ -416,7 +414,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
);
|
||||
group.addTabs(tabsAndSplitViews);
|
||||
|
||||
@@ -3906,7 +4043,7 @@
|
||||
@@ -3906,7 +4041,7 @@
|
||||
}
|
||||
|
||||
this.#handleTabMove(tab, () =>
|
||||
@@ -425,7 +423,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3990,6 +4127,7 @@
|
||||
@@ -3990,6 +4125,7 @@
|
||||
color: group.color,
|
||||
insertBefore: newTabs[0],
|
||||
isAdoptingGroup: true,
|
||||
@@ -433,7 +431,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4200,6 +4338,7 @@
|
||||
@@ -4200,6 +4336,7 @@
|
||||
openWindowInfo,
|
||||
skipLoad,
|
||||
triggeringRemoteType,
|
||||
@@ -441,7 +439,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
) {
|
||||
// If we don't have a preferred remote type (or it is `NOT_REMOTE`), and
|
||||
@@ -4269,6 +4408,7 @@
|
||||
@@ -4269,6 +4406,7 @@
|
||||
openWindowInfo,
|
||||
name,
|
||||
skipLoad,
|
||||
@@ -449,7 +447,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
});
|
||||
}
|
||||
|
||||
@@ -4482,9 +4622,9 @@
|
||||
@@ -4482,9 +4620,9 @@
|
||||
}
|
||||
|
||||
// Add a new tab if needed.
|
||||
@@ -461,7 +459,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
let url = "about:blank";
|
||||
if (tabData.entries?.length) {
|
||||
@@ -4521,8 +4661,10 @@
|
||||
@@ -4521,8 +4659,10 @@
|
||||
insertTab: false,
|
||||
skipLoad: true,
|
||||
preferredRemoteType,
|
||||
@@ -473,7 +471,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (select) {
|
||||
tabToSelect = tab;
|
||||
}
|
||||
@@ -4544,7 +4686,8 @@
|
||||
@@ -4544,7 +4684,8 @@
|
||||
this.pinTab(tab);
|
||||
// Then ensure all the tab open/pinning information is sent.
|
||||
this._fireTabOpen(tab, {});
|
||||
@@ -483,7 +481,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
let { groupId } = tabData;
|
||||
const tabGroup = tabGroupWorkingData.get(groupId);
|
||||
// if a tab refers to a tab group we don't know, skip any group
|
||||
@@ -4564,7 +4707,10 @@
|
||||
@@ -4564,7 +4705,10 @@
|
||||
tabGroup.stateData.id,
|
||||
tabGroup.stateData.color,
|
||||
tabGroup.stateData.collapsed,
|
||||
@@ -495,7 +493,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
);
|
||||
tabsFragment.appendChild(tabGroup.node);
|
||||
}
|
||||
@@ -4619,9 +4765,21 @@
|
||||
@@ -4619,9 +4763,21 @@
|
||||
// to remove the old selected tab.
|
||||
if (tabToSelect) {
|
||||
let leftoverTab = this.selectedTab;
|
||||
@@ -517,7 +515,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
if (tabs.length > 1 || !tabs[0].selected) {
|
||||
this._updateTabsAfterInsert();
|
||||
@@ -4812,11 +4970,14 @@
|
||||
@@ -4812,11 +4968,14 @@
|
||||
if (ownerTab) {
|
||||
tab.owner = ownerTab;
|
||||
}
|
||||
@@ -533,7 +531,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (
|
||||
!bulkOrderedOpen &&
|
||||
((openerTab &&
|
||||
@@ -4828,7 +4989,7 @@
|
||||
@@ -4828,7 +4987,7 @@
|
||||
let lastRelatedTab =
|
||||
openerTab && this._lastRelatedTabMap.get(openerTab);
|
||||
let previousTab = lastRelatedTab || openerTab || this.selectedTab;
|
||||
@@ -542,7 +540,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
tabGroup = previousTab.group;
|
||||
}
|
||||
if (
|
||||
@@ -4844,7 +5005,7 @@
|
||||
@@ -4844,7 +5003,7 @@
|
||||
previousTab.splitview
|
||||
) + 1;
|
||||
} else if (previousTab.visible) {
|
||||
@@ -551,7 +549,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} else if (previousTab == FirefoxViewHandler.tab) {
|
||||
elementIndex = 0;
|
||||
}
|
||||
@@ -4872,14 +5033,14 @@
|
||||
@@ -4872,14 +5031,14 @@
|
||||
}
|
||||
// Ensure index is within bounds.
|
||||
if (tab.pinned) {
|
||||
@@ -570,7 +568,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
if (pinned && !itemAfter?.pinned) {
|
||||
itemAfter = null;
|
||||
@@ -4896,7 +5057,7 @@
|
||||
@@ -4896,7 +5055,7 @@
|
||||
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
|
||||
@@ -579,7 +577,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (
|
||||
(this.isTab(itemAfter) && itemAfter.group == tabGroup) ||
|
||||
this.isSplitViewWrapper(itemAfter)
|
||||
@@ -4927,7 +5088,11 @@
|
||||
@@ -4927,7 +5086,11 @@
|
||||
const tabContainer = pinned
|
||||
? this.tabContainer.pinnedTabsContainer
|
||||
: this.tabContainer;
|
||||
@@ -591,7 +589,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
if (tab.group?.collapsed) {
|
||||
@@ -4942,6 +5107,7 @@
|
||||
@@ -4942,6 +5105,7 @@
|
||||
if (pinned) {
|
||||
this._updateTabBarForPinnedTabs();
|
||||
}
|
||||
@@ -599,7 +597,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
TabBarVisibility.update();
|
||||
}
|
||||
@@ -5490,6 +5656,7 @@
|
||||
@@ -5490,6 +5654,7 @@
|
||||
telemetrySource,
|
||||
} = {}
|
||||
) {
|
||||
@@ -607,7 +605,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// When 'closeWindowWithLastTab' pref is enabled, closing all tabs
|
||||
// can be considered equivalent to closing the window.
|
||||
if (
|
||||
@@ -5579,6 +5746,7 @@
|
||||
@@ -5579,6 +5744,7 @@
|
||||
if (lastToClose) {
|
||||
this.removeTab(lastToClose, aParams);
|
||||
}
|
||||
@@ -615,7 +613,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} catch (e) {
|
||||
console.error(e);
|
||||
}
|
||||
@@ -5624,6 +5792,14 @@
|
||||
@@ -5624,6 +5790,14 @@
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -630,7 +628,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
let isVisibleTab = aTab.visible;
|
||||
// We have to sample the tab width now, since _beginRemoveTab might
|
||||
// end up modifying the DOM in such a way that aTab gets a new
|
||||
@@ -5631,6 +5807,9 @@
|
||||
@@ -5631,6 +5805,9 @@
|
||||
// state).
|
||||
let tabWidth = window.windowUtils.getBoundsWithoutFlushing(aTab).width;
|
||||
let isLastTab = this.#isLastTabInWindow(aTab);
|
||||
@@ -640,7 +638,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (
|
||||
!this._beginRemoveTab(aTab, {
|
||||
closeWindowFastpath: true,
|
||||
@@ -5642,13 +5821,14 @@
|
||||
@@ -5642,13 +5819,14 @@
|
||||
telemetrySource,
|
||||
})
|
||||
) {
|
||||
@@ -656,7 +654,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
let lockTabSizing =
|
||||
!this.tabContainer.verticalMode &&
|
||||
!aTab.pinned &&
|
||||
@@ -5679,7 +5859,13 @@
|
||||
@@ -5679,7 +5857,13 @@
|
||||
// We're not animating, so we can cancel the animation stopwatch.
|
||||
Glean.browserTabclose.timeAnim.cancel(aTab._closeTimeAnimTimerId);
|
||||
aTab._closeTimeAnimTimerId = null;
|
||||
@@ -671,7 +669,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -5813,7 +5999,7 @@
|
||||
@@ -5813,7 +5997,7 @@
|
||||
closeWindowWithLastTab != null
|
||||
? closeWindowWithLastTab
|
||||
: !window.toolbar.visible ||
|
||||
@@ -680,7 +678,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
if (closeWindow) {
|
||||
// We've already called beforeunload on all the relevant tabs if we get here,
|
||||
@@ -5837,6 +6023,7 @@
|
||||
@@ -5837,6 +6021,7 @@
|
||||
|
||||
newTab = true;
|
||||
}
|
||||
@@ -688,7 +686,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
aTab._endRemoveArgs = [closeWindow, newTab];
|
||||
|
||||
// swapBrowsersAndCloseOther will take care of closing the window without animation.
|
||||
@@ -5877,13 +6064,7 @@
|
||||
@@ -5877,13 +6062,7 @@
|
||||
aTab._mouseleave();
|
||||
|
||||
if (newTab) {
|
||||
@@ -703,7 +701,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} else {
|
||||
TabBarVisibility.update();
|
||||
}
|
||||
@@ -6016,6 +6197,7 @@
|
||||
@@ -6016,6 +6195,7 @@
|
||||
this.tabs[i]._tPos = i;
|
||||
}
|
||||
|
||||
@@ -711,7 +709,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (!this._windowIsClosing) {
|
||||
// update tab close buttons state
|
||||
this.tabContainer._updateCloseButtons();
|
||||
@@ -6201,6 +6383,7 @@
|
||||
@@ -6201,6 +6381,7 @@
|
||||
memory_after: await getTotalMemoryUsage(),
|
||||
time_to_unload_in_ms: timeElapsed,
|
||||
});
|
||||
@@ -719,7 +717,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6246,6 +6429,7 @@
|
||||
@@ -6246,6 +6427,7 @@
|
||||
}
|
||||
|
||||
let excludeTabs = new Set(aExcludeTabs);
|
||||
@@ -727,7 +725,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
// If this tab has a successor, it should be selectable, since
|
||||
// hiding or closing a tab removes that tab as a successor.
|
||||
@@ -6258,15 +6442,22 @@
|
||||
@@ -6258,15 +6440,22 @@
|
||||
!excludeTabs.has(aTab.owner) &&
|
||||
Services.prefs.getBoolPref("browser.tabs.selectOwnerOnClose")
|
||||
) {
|
||||
@@ -752,7 +750,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
let tab = this.tabContainer.findNextTab(aTab, {
|
||||
direction: 1,
|
||||
filter: _tab => remainingTabs.includes(_tab),
|
||||
@@ -6280,7 +6471,7 @@
|
||||
@@ -6280,7 +6469,7 @@
|
||||
}
|
||||
|
||||
if (tab) {
|
||||
@@ -761,7 +759,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
// If no qualifying visible tab was found, see if there is a tab in
|
||||
@@ -6301,7 +6492,7 @@
|
||||
@@ -6301,7 +6490,7 @@
|
||||
});
|
||||
}
|
||||
|
||||
@@ -770,7 +768,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
_blurTab(aTab) {
|
||||
@@ -6312,7 +6503,7 @@
|
||||
@@ -6312,7 +6501,7 @@
|
||||
* @returns {boolean}
|
||||
* False if swapping isn't permitted, true otherwise.
|
||||
*/
|
||||
@@ -779,7 +777,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// Do not allow transfering a private tab to a non-private window
|
||||
// and vice versa.
|
||||
if (
|
||||
@@ -6366,6 +6557,7 @@
|
||||
@@ -6366,6 +6555,7 @@
|
||||
// fire the beforeunload event in the process. Close the other
|
||||
// window if this was its last tab.
|
||||
if (
|
||||
@@ -787,7 +785,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
!remoteBrowser._beginRemoveTab(aOtherTab, {
|
||||
adoptedByTab: aOurTab,
|
||||
closeWindowWithLastTab: true,
|
||||
@@ -6377,7 +6569,7 @@
|
||||
@@ -6377,7 +6567,7 @@
|
||||
// If this is the last tab of the window, hide the window
|
||||
// immediately without animation before the docshell swap, to avoid
|
||||
// about:blank being painted.
|
||||
@@ -796,7 +794,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (closeWindow) {
|
||||
let win = aOtherTab.ownerGlobal;
|
||||
win.windowUtils.suppressAnimation(true);
|
||||
@@ -6511,11 +6703,13 @@
|
||||
@@ -6511,11 +6701,13 @@
|
||||
}
|
||||
|
||||
// Finish tearing down the tab that's going away.
|
||||
@@ -810,7 +808,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
this.setTabTitle(aOurTab);
|
||||
|
||||
@@ -6717,10 +6911,10 @@
|
||||
@@ -6717,10 +6909,10 @@
|
||||
SessionStore.deleteCustomTabValue(aTab, "hiddenBy");
|
||||
}
|
||||
|
||||
@@ -823,7 +821,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
aTab.selected ||
|
||||
aTab.closing ||
|
||||
// Tabs that are sharing the screen, microphone or camera cannot be hidden.
|
||||
@@ -6780,7 +6974,8 @@
|
||||
@@ -6780,7 +6972,8 @@
|
||||
* @param {object} [aOptions={}]
|
||||
* Key-value pairs that will be serialized into the features string.
|
||||
*/
|
||||
@@ -833,7 +831,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
if (this.tabs.length == 1) {
|
||||
return null;
|
||||
}
|
||||
@@ -6797,7 +6992,7 @@
|
||||
@@ -6797,7 +6990,7 @@
|
||||
// tell a new window to take the "dropped" tab
|
||||
let args = Cc["@mozilla.org/array;1"].createInstance(Ci.nsIMutableArray);
|
||||
args.appendElement(aTab.splitview ?? aTab);
|
||||
@@ -842,7 +840,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
private: PrivateBrowsingUtils.isWindowPrivate(window),
|
||||
features: Object.entries(aOptions)
|
||||
.map(([key, value]) => `${key}=${value}`)
|
||||
@@ -6805,6 +7000,8 @@
|
||||
@@ -6805,6 +6998,8 @@
|
||||
openerWindow: window,
|
||||
args,
|
||||
});
|
||||
@@ -851,7 +849,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -6917,7 +7114,7 @@
|
||||
@@ -6917,7 +7112,7 @@
|
||||
* `true` if element is a `<tab-group>`
|
||||
*/
|
||||
isTabGroup(element) {
|
||||
@@ -860,7 +858,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7002,8 +7199,8 @@
|
||||
@@ -7002,8 +7197,8 @@
|
||||
}
|
||||
|
||||
// Don't allow mixing pinned and unpinned tabs.
|
||||
@@ -871,7 +869,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} else {
|
||||
tabIndex = Math.max(tabIndex, this.pinnedTabCount);
|
||||
}
|
||||
@@ -7049,8 +7246,8 @@
|
||||
@@ -7049,8 +7244,8 @@
|
||||
this.#handleTabMove(
|
||||
element,
|
||||
() => {
|
||||
@@ -882,7 +880,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
neighbor = neighbor.group;
|
||||
}
|
||||
if (neighbor?.splitview) {
|
||||
@@ -7061,6 +7258,12 @@
|
||||
@@ -7061,6 +7256,12 @@
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -895,7 +893,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
if (movingForwards && neighbor) {
|
||||
neighbor.after(element);
|
||||
@@ -7119,23 +7322,31 @@
|
||||
@@ -7119,23 +7320,31 @@
|
||||
#moveTabNextTo(element, targetElement, moveBefore = false, metricsContext) {
|
||||
if (this.isTabGroupLabel(targetElement)) {
|
||||
targetElement = targetElement.group;
|
||||
@@ -933,7 +931,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
} 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
|
||||
@@ -7148,12 +7359,35 @@
|
||||
@@ -7148,12 +7357,35 @@
|
||||
// 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.
|
||||
@@ -970,7 +968,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
// We want to include the splitview wrapper if it's the targetElement, but
|
||||
// not in the case where we want to reverse tabs within the same splitview.
|
||||
@@ -7162,6 +7396,7 @@
|
||||
@@ -7162,6 +7394,7 @@
|
||||
}
|
||||
|
||||
let getContainer = () =>
|
||||
@@ -978,7 +976,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
element.pinned
|
||||
? this.tabContainer.pinnedTabsContainer
|
||||
: this.tabContainer;
|
||||
@@ -7170,11 +7405,15 @@
|
||||
@@ -7170,11 +7403,15 @@
|
||||
element,
|
||||
() => {
|
||||
if (moveBefore) {
|
||||
@@ -995,7 +993,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
},
|
||||
metricsContext
|
||||
@@ -7248,11 +7487,15 @@
|
||||
@@ -7248,11 +7485,15 @@
|
||||
* @param {TabMetricsContext} [metricsContext]
|
||||
*/
|
||||
moveTabToExistingGroup(aTab, aGroup, metricsContext) {
|
||||
@@ -1014,7 +1012,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
if (aTab.group && aTab.group.id === aGroup.id) {
|
||||
return;
|
||||
@@ -7324,6 +7567,7 @@
|
||||
@@ -7324,6 +7565,7 @@
|
||||
|
||||
let state = {
|
||||
tabIndex: tab._tPos,
|
||||
@@ -1022,7 +1020,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
};
|
||||
if (tab.visible) {
|
||||
state.elementIndex = tab.elementIndex;
|
||||
@@ -7355,7 +7599,7 @@
|
||||
@@ -7355,7 +7597,7 @@
|
||||
let changedSplitView =
|
||||
previousTabState.splitViewId != currentTabState.splitViewId;
|
||||
|
||||
@@ -1031,7 +1029,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
tab.dispatchEvent(
|
||||
new CustomEvent("TabMove", {
|
||||
bubbles: true,
|
||||
@@ -7402,6 +7646,10 @@
|
||||
@@ -7402,6 +7644,10 @@
|
||||
|
||||
moveActionCallback();
|
||||
|
||||
@@ -1042,7 +1040,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// Clear tabs cache after moving nodes because the order of tabs may have
|
||||
// changed.
|
||||
this.tabContainer._invalidateCachedTabs();
|
||||
@@ -7452,7 +7700,22 @@
|
||||
@@ -7452,7 +7698,22 @@
|
||||
* @returns {object}
|
||||
* The new tab in the current window, null if the tab couldn't be adopted.
|
||||
*/
|
||||
@@ -1066,7 +1064,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
// Swap the dropped tab with a new one we create and then close
|
||||
// it in the other window (making it seem to have moved between
|
||||
// windows). We also ensure that the tab we create to swap into has
|
||||
@@ -7495,6 +7758,8 @@
|
||||
@@ -7495,6 +7756,8 @@
|
||||
}
|
||||
params.skipLoad = true;
|
||||
let newTab = this.addWebTab("about:blank", params);
|
||||
@@ -1075,7 +1073,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
aTab.container.tabDragAndDrop.finishAnimateTabMove();
|
||||
|
||||
@@ -8205,7 +8470,7 @@
|
||||
@@ -8205,7 +8468,7 @@
|
||||
// preventDefault(). It will still raise the window if appropriate.
|
||||
return;
|
||||
}
|
||||
@@ -1084,7 +1082,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
window.focus();
|
||||
aEvent.preventDefault();
|
||||
}
|
||||
@@ -8222,7 +8487,6 @@
|
||||
@@ -8222,7 +8485,6 @@
|
||||
|
||||
on_TabGroupCollapse(aEvent) {
|
||||
aEvent.target.tabs.forEach(tab => {
|
||||
@@ -1092,7 +1090,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
});
|
||||
}
|
||||
|
||||
@@ -8556,7 +8820,9 @@
|
||||
@@ -8556,7 +8818,9 @@
|
||||
|
||||
let filter = this._tabFilters.get(tab);
|
||||
if (filter) {
|
||||
@@ -1102,7 +1100,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
|
||||
let listener = this._tabListeners.get(tab);
|
||||
if (listener) {
|
||||
@@ -9359,6 +9625,7 @@
|
||||
@@ -9359,6 +9623,7 @@
|
||||
aWebProgress.isTopLevel
|
||||
) {
|
||||
this.mTab.setAttribute("busy", "true");
|
||||
@@ -1110,7 +1108,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
gBrowser._tabAttrModified(this.mTab, ["busy"]);
|
||||
this.mTab._notselectedsinceload = !this.mTab.selected;
|
||||
}
|
||||
@@ -9439,6 +9706,7 @@
|
||||
@@ -9439,6 +9704,7 @@
|
||||
// known defaults. Note we use the original URL since about:newtab
|
||||
// redirects to a prerendered page.
|
||||
const shouldRemoveFavicon =
|
||||
@@ -1118,7 +1116,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
!this.mBrowser.mIconURL &&
|
||||
!ignoreBlank &&
|
||||
!(originalLocation.spec in FAVICON_DEFAULTS);
|
||||
@@ -9613,13 +9881,6 @@
|
||||
@@ -9613,13 +9879,6 @@
|
||||
this.mBrowser.originalURI = aRequest.originalURI;
|
||||
}
|
||||
|
||||
@@ -1132,7 +1130,7 @@ index 43fb79a3060e20f671ae6ffc26350c7abf497702..68a037d5a0e3416f31ffcb163592f008
|
||||
}
|
||||
|
||||
let userContextId = this.mBrowser.getAttribute("usercontextid") || 0;
|
||||
@@ -10507,7 +10768,8 @@ var TabContextMenu = {
|
||||
@@ -10507,7 +10766,8 @@ var TabContextMenu = {
|
||||
);
|
||||
contextUnpinSelectedTabs.hidden =
|
||||
!this.contextTab.pinned || !this.multiselected;
|
||||
|
||||
@@ -0,0 +1,172 @@
|
||||
diff --git a/gfx/webrender_bindings/WebRenderAPI.cpp b/gfx/webrender_bindings/WebRenderAPI.cpp
|
||||
--- a/gfx/webrender_bindings/WebRenderAPI.cpp
|
||||
+++ b/gfx/webrender_bindings/WebRenderAPI.cpp
|
||||
@@ -298,11 +298,13 @@
|
||||
panic_on_gl_error, picTileWidth, picTileHeight,
|
||||
gfx::gfxVars::WebRenderRequiresHardwareDriver(),
|
||||
StaticPrefs::gfx_webrender_low_quality_pinch_zoom_AtStartup(),
|
||||
StaticPrefs::gfx_webrender_max_shared_surface_size_AtStartup(),
|
||||
StaticPrefs::gfx_webrender_enable_subpixel_aa_AtStartup(),
|
||||
- compositor->ShouldUseLayerCompositor())) {
|
||||
+ compositor->ShouldUseLayerCompositor(),
|
||||
+ StaticPrefs::
|
||||
+ gfx_webrender_opaque_backdrop_fallback_AtStartup())) {
|
||||
// wr_window_new puts a message into gfxCriticalNote if it returns
|
||||
// false
|
||||
MOZ_ASSERT(errorMessage);
|
||||
error.AssignASCII(errorMessage);
|
||||
wr_api_free_error_msg(errorMessage);
|
||||
diff --git a/gfx/webrender_bindings/src/bindings.rs b/gfx/webrender_bindings/src/bindings.rs
|
||||
--- a/gfx/webrender_bindings/src/bindings.rs
|
||||
+++ b/gfx/webrender_bindings/src/bindings.rs
|
||||
@@ -1998,10 +1998,11 @@
|
||||
reject_software_rasterizer: bool,
|
||||
low_quality_pinch_zoom: bool,
|
||||
max_shared_surface_size: i32,
|
||||
enable_subpixel_aa: bool,
|
||||
use_layer_compositor: bool,
|
||||
+ opaque_backdrop_fallback: bool,
|
||||
) -> bool {
|
||||
assert!(unsafe { is_in_render_thread() });
|
||||
|
||||
// Ensure the WR profiler callbacks are hooked up to the Gecko profiler.
|
||||
set_profiler_hooks(Some(&PROFILER_HOOKS));
|
||||
@@ -2164,10 +2165,11 @@
|
||||
texture_cache_config,
|
||||
reject_software_rasterizer,
|
||||
low_quality_pinch_zoom,
|
||||
max_shared_surface_size,
|
||||
enable_dithering,
|
||||
+ opaque_backdrop_fallback,
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let window_size = DeviceIntSize::new(window_width, window_height);
|
||||
let notifier = Box::new(CppNotifier { window_id });
|
||||
diff --git a/gfx/wr/webrender/src/device/gl.rs b/gfx/wr/webrender/src/device/gl.rs
|
||||
--- a/gfx/wr/webrender/src/device/gl.rs
|
||||
+++ b/gfx/wr/webrender/src/device/gl.rs
|
||||
@@ -3982,10 +3982,14 @@
|
||||
|
||||
pub fn disable_color_write(&self) {
|
||||
self.gl.color_mask(false, false, false, false);
|
||||
}
|
||||
|
||||
+ pub fn set_color_mask(&self, r: bool, g: bool, b: bool, a: bool) {
|
||||
+ self.gl.color_mask(r, g, b, a);
|
||||
+ }
|
||||
+
|
||||
pub fn set_blend(&mut self, enable: bool) {
|
||||
if enable {
|
||||
self.gl.enable(gl::BLEND);
|
||||
} else {
|
||||
self.gl.disable(gl::BLEND);
|
||||
diff --git a/gfx/wr/webrender/src/renderer/init.rs b/gfx/wr/webrender/src/renderer/init.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/init.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/init.rs
|
||||
@@ -204,10 +204,12 @@
|
||||
pub low_quality_pinch_zoom: bool,
|
||||
pub max_shared_surface_size: i32,
|
||||
/// If true, open a debug socket to listen for remote debugger.
|
||||
/// Relies on `debugger` cargo feature being enabled.
|
||||
pub enable_debugger: bool,
|
||||
+ /// See explanation of `gfx.webrender.opaque-backdrop-fallback`.
|
||||
+ pub opaque_backdrop_fallback: bool,
|
||||
|
||||
/// Use the new quad primitive path for box-shadow blur rendering.
|
||||
pub use_quad_box_shadow: bool,
|
||||
}
|
||||
|
||||
@@ -277,10 +279,11 @@
|
||||
enable_instancing: true,
|
||||
reject_software_rasterizer: false,
|
||||
low_quality_pinch_zoom: false,
|
||||
max_shared_surface_size: 2048,
|
||||
enable_debugger: true,
|
||||
+ opaque_backdrop_fallback: false,
|
||||
use_quad_box_shadow: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -802,10 +805,11 @@
|
||||
allocated_native_surfaces: FastHashSet::default(),
|
||||
debug_overlay_state: DebugOverlayState::new(),
|
||||
buffer_damage_tracker: BufferDamageTracker::default(),
|
||||
max_primitive_instance_count,
|
||||
enable_instancing: options.enable_instancing,
|
||||
+ opaque_backdrop_fallback: options.opaque_backdrop_fallback,
|
||||
consecutive_oom_frames: 0,
|
||||
target_frame_publish_id: None,
|
||||
pending_result_msg: None,
|
||||
layer_compositor_frame_state_in_prev_frame: None,
|
||||
external_composite_debug_items: Vec::new(),
|
||||
diff --git a/gfx/wr/webrender/src/renderer/mod.rs b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
--- a/gfx/wr/webrender/src/renderer/mod.rs
|
||||
+++ b/gfx/wr/webrender/src/renderer/mod.rs
|
||||
@@ -867,10 +867,12 @@
|
||||
buffer_damage_tracker: BufferDamageTracker,
|
||||
|
||||
max_primitive_instance_count: usize,
|
||||
enable_instancing: bool,
|
||||
|
||||
+ opaque_backdrop_fallback: bool,
|
||||
+
|
||||
/// Count consecutive oom frames to detectif we are stuck unable to render
|
||||
/// in a loop.
|
||||
consecutive_oom_frames: u32,
|
||||
|
||||
/// update() defers processing of ResultMsg, if frame_publish_id of
|
||||
@@ -2787,18 +2789,29 @@
|
||||
let read_target = ReadTarget::from_texture(cache_texture);
|
||||
|
||||
// Should always be drawing to picture cache tiles or off-screen surface!
|
||||
debug_assert!(!draw_target.is_default());
|
||||
let device_to_framebuffer = Scale::new(1i32);
|
||||
+ let dest_fb_rect = dest * device_to_framebuffer;
|
||||
|
||||
self.device.blit_render_target(
|
||||
read_target,
|
||||
src * device_to_framebuffer,
|
||||
draw_target,
|
||||
- dest * device_to_framebuffer,
|
||||
+ dest_fb_rect,
|
||||
TextureFilter::Linear,
|
||||
);
|
||||
+
|
||||
+ if self.opaque_backdrop_fallback {
|
||||
+ self.device.set_color_mask(false, false, false, true);
|
||||
+ self.device.clear_target(
|
||||
+ Some([0.0, 0.0, 0.0, 1.0]),
|
||||
+ None,
|
||||
+ Some(dest_fb_rect),
|
||||
+ );
|
||||
+ self.device.set_color_mask(true, true, true, true);
|
||||
+ }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn draw_picture_cache_target(
|
||||
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
|
||||
--- a/modules/libpref/init/StaticPrefList.yaml
|
||||
+++ b/modules/libpref/init/StaticPrefList.yaml
|
||||
@@ -8439,10 +8439,17 @@
|
||||
#else
|
||||
value: false
|
||||
#endif
|
||||
mirror: once
|
||||
|
||||
+# Make backdrop-filter treat its captured backdrop as if it had been
|
||||
+# composited over an opaque-black background. (See bug 2036640)
|
||||
+- name: gfx.webrender.opaque-backdrop-fallback
|
||||
+ type: bool
|
||||
+ value: true
|
||||
+ mirror: once
|
||||
+
|
||||
# Disable wait of GPU execution completion
|
||||
- name: gfx.webrender.wait-gpu-finished.disabled
|
||||
type: bool
|
||||
value: false
|
||||
mirror: once
|
||||
|
||||
@@ -7,7 +7,7 @@ diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content
|
||||
id="selection-shortcut-action-panel"
|
||||
noautofocus="true"
|
||||
consumeoutsideclicks="never"
|
||||
+ nonnativepopover="true"
|
||||
+ nonnative=""
|
||||
type="arrow">
|
||||
<hbox class="panel-subview-body">
|
||||
<html:moz-button id="ai-action-button"/>
|
||||
@@ -19,7 +19,7 @@ diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content
|
||||
<panel class="panel-no-padding"
|
||||
id="chat-shortcuts-options-panel"
|
||||
noautofocus="true"
|
||||
+ nonnativepopover="true"
|
||||
+ nonnative=""
|
||||
type="arrow">
|
||||
<vbox class="panel-subview-body"/>
|
||||
</panel>
|
||||
@@ -31,7 +31,7 @@ diff --git a/browser/base/content/main-popupset.inc.xhtml b/browser/base/content
|
||||
noautofocus="true"
|
||||
norolluponanchor="true"
|
||||
consumeoutsideclicks="false"
|
||||
+ nonnativepopover="true"
|
||||
+ nonnative=""
|
||||
role="tooltip">
|
||||
<html:div class="tab-preview-content-interactive"></html:div>
|
||||
<html:div class="tab-preview-content-main">
|
||||
@@ -46,7 +46,7 @@ diff --git a/browser/components/asrouter/modules/FeatureCallout.sys.mjs b/browse
|
||||
type="arrow"
|
||||
consumeoutsideclicks="never"
|
||||
norolluponanchor="true"
|
||||
+
|
||||
+ nonnative=""
|
||||
position="${panel_position.panel_position_string}"
|
||||
${hide_arrow ? "" : 'show-arrow=""'}
|
||||
${autohide ? "" : 'noautohide="true"'}
|
||||
@@ -61,7 +61,7 @@ diff --git a/browser/components/customizableui/content/panelUI.inc.xhtml b/brows
|
||||
hidden="true"
|
||||
flip="slide"
|
||||
position="bottomright topright"
|
||||
+ hidepopovertail="true"
|
||||
+ hidepopovertail=""
|
||||
noautofocus="true">
|
||||
<panelmultiview id="appMenu-multiView" mainViewId="appMenu-mainView"
|
||||
viewCacheId="appMenu-viewCache">
|
||||
@@ -70,31 +70,33 @@ diff --git a/browser/components/customizableui/content/panelUI.inc.xhtml b/brows
|
||||
diff --git a/dom/xul/XULPopupElement.cpp b/dom/xul/XULPopupElement.cpp
|
||||
--- a/dom/xul/XULPopupElement.cpp
|
||||
+++ b/dom/xul/XULPopupElement.cpp
|
||||
@@ -80,10 +80,14 @@
|
||||
@@ -80,10 +80,15 @@
|
||||
}
|
||||
|
||||
void XULPopupElement::OpenPopupAtScreen(int32_t aXPos, int32_t aYPos,
|
||||
bool aIsContextMenu,
|
||||
Event* aTriggerEvent) {
|
||||
+ // TODO(cheff): At nsCocoaWindow::Show but we check for ShouldShowAsNSPopover
|
||||
+ // to determine whether to use a native popover or not. This should sort of
|
||||
+ // "replicate" that logic here, but it's a bit of a hacky way.
|
||||
+ SetAttr(kNameSpaceID_None, nsGkAtoms::nonnativepopover, u"true"_ns, true);
|
||||
+ if (NodeInfo()->NameAtom() == nsGkAtoms::panel) {
|
||||
+ // TODO(bug 2038354): Remove this and make the front-end set the attribute
|
||||
+ // explicitly.
|
||||
+ SetAttr(kNameSpaceID_None, nsGkAtoms::nonnative, u"true"_ns, true);
|
||||
+ }
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
if (pm) {
|
||||
pm->ShowPopupAtScreen(this, aXPos, aYPos, aIsContextMenu, aTriggerEvent);
|
||||
}
|
||||
}
|
||||
@@ -93,10 +97,14 @@
|
||||
@@ -93,10 +98,15 @@
|
||||
int32_t aWidth, int32_t aHeight,
|
||||
bool aIsContextMenu,
|
||||
bool aAttributesOverride,
|
||||
Event* aTriggerEvent) {
|
||||
nsXULPopupManager* pm = nsXULPopupManager::GetInstance();
|
||||
+ // TODO: See OpenPopupAtScreen. We should remove this and use the other
|
||||
+ // implementation because this is a bit of a hacky way to determine whether to
|
||||
+ // use a native popover or not.
|
||||
+ SetAttr(kNameSpaceID_None, nsGkAtoms::nonnativepopover, u"true"_ns, true);
|
||||
+ if (NodeInfo()->NameAtom() == nsGkAtoms::panel) {
|
||||
+ // TODO(bug 2038354): Remove this and make the front-end set the attribute
|
||||
+ // explicitly.
|
||||
+ SetAttr(kNameSpaceID_None, nsGkAtoms::nonnative, u"true"_ns, true);
|
||||
+ }
|
||||
if (pm) {
|
||||
pm->ShowPopupAtScreenRect(
|
||||
this, aPosition, nsIntRect(aXPos, aYPos, aWidth, aHeight),
|
||||
@@ -103,7 +105,7 @@ diff --git a/dom/xul/XULPopupElement.cpp b/dom/xul/XULPopupElement.cpp
|
||||
diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h
|
||||
--- a/layout/xul/nsMenuPopupFrame.h
|
||||
+++ b/layout/xul/nsMenuPopupFrame.h
|
||||
@@ -528,18 +528,10 @@
|
||||
@@ -516,18 +516,10 @@
|
||||
|
||||
// Move the popup to the position specified in its |left| and |top|
|
||||
// attributes.
|
||||
@@ -122,7 +124,7 @@ diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h
|
||||
public:
|
||||
/**
|
||||
* Return whether the popup direction should be RTL.
|
||||
@@ -548,10 +540,18 @@
|
||||
@@ -536,10 +528,18 @@
|
||||
*
|
||||
* Return whether the popup direction should be RTL.
|
||||
*/
|
||||
@@ -144,7 +146,7 @@ diff --git a/layout/xul/nsMenuPopupFrame.h b/layout/xul/nsMenuPopupFrame.h
|
||||
diff --git a/modules/libpref/init/StaticPrefList.yaml b/modules/libpref/init/StaticPrefList.yaml
|
||||
--- a/modules/libpref/init/StaticPrefList.yaml
|
||||
+++ b/modules/libpref/init/StaticPrefList.yaml
|
||||
@@ -19672,10 +19672,19 @@
|
||||
@@ -19840,10 +19840,19 @@
|
||||
value: true
|
||||
mirror: always
|
||||
|
||||
@@ -168,20 +170,20 @@ diff --git a/toolkit/themes/shared/global-shared.css b/toolkit/themes/shared/glo
|
||||
--- a/toolkit/themes/shared/global-shared.css
|
||||
+++ b/toolkit/themes/shared/global-shared.css
|
||||
@@ -72,10 +72,22 @@
|
||||
--menuitem-border-radius: var(--panel-menuitem-border-radius);
|
||||
--menuitem-padding: var(--panel-menuitem-padding);
|
||||
--menuitem-margin: var(--panel-menuitem-margin);
|
||||
--menuitem-border-radius: var(--arrowpanel-menuitem-border-radius);
|
||||
--menuitem-padding: var(--arrowpanel-menuitem-padding);
|
||||
--menuitem-margin: var(--arrowpanel-menuitem-margin);
|
||||
}
|
||||
|
||||
+/* stylelint-disable-next-line media-query-no-invalid */
|
||||
+@media -moz-pref("widget.macos.native-popovers") and (-moz-platform: macos) {
|
||||
+ panel:not(:where([nonnativepopover="true"])) {
|
||||
+ panel:not([nonnative]) {
|
||||
+ background-color: transparent;
|
||||
+ --panel-background: transparent;
|
||||
+ --panel-shadow: none;
|
||||
+ --panel-box-shadow: none;
|
||||
+ --panel-border-color: transparent;
|
||||
+ --panel-shadow-margin: 0px;
|
||||
+
|
||||
+ --panel-box-shadow-margin: 0px;
|
||||
+ --panel-padding: 0px;
|
||||
+ }
|
||||
+}
|
||||
+
|
||||
@@ -241,7 +243,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
|
||||
|
||||
+ // Check if this window should use NSPopover for popup/menu display
|
||||
+ bool ShouldUseNSPopover() const;
|
||||
+ bool ShouldShowAsNSPopover() const override;
|
||||
+ bool ShouldShowAsNSPopover() const;
|
||||
+
|
||||
[[nodiscard]] nsresult Create(nsIWidget* aParent, const DesktopIntRect& aRect,
|
||||
const InitData&) override;
|
||||
@@ -265,7 +267,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
#include "nsIDOMWindowUtils.h"
|
||||
#include "nsILocalFileMac.h"
|
||||
#include "CocoaCompositorWidget.h"
|
||||
@@ -5031,10 +5034,15 @@
|
||||
@@ -5088,10 +5091,15 @@
|
||||
if (mWindowType == WindowType::Popup) {
|
||||
SetPopupWindowLevel();
|
||||
mWindow.backgroundColor = NSColor.clearColor;
|
||||
@@ -281,7 +283,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
// the active space. Does not work with multiple displays. See
|
||||
// NeedsRecreateToReshow() for multi-display with multi-space workaround.
|
||||
mWindow.collectionBehavior = mWindow.collectionBehavior |
|
||||
@@ -5236,10 +5244,57 @@
|
||||
@@ -5293,10 +5301,57 @@
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
@@ -339,7 +341,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
NS_OBJC_BEGIN_TRY_IGNORE_BLOCK;
|
||||
|
||||
if (!mWindow) {
|
||||
@@ -5300,10 +5355,58 @@
|
||||
@@ -5357,10 +5412,53 @@
|
||||
mWindow.contentView.needsDisplay = YES;
|
||||
if (!nativeParentWindow || mPopupLevel != PopupLevel::Parent) {
|
||||
[mWindow orderFront:nil];
|
||||
@@ -375,22 +377,17 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
+ // specific parent view
|
||||
+ NSRect positioningRect = [parentView convertRect:windowRect
|
||||
+ fromView:nil];
|
||||
+ BOOL shouldHideAnchor = NO;
|
||||
+ auto& element = popupFrame->PopupElement();
|
||||
+ if (element.GetBoolAttr(nsGkAtoms::hidepopovertail)) {
|
||||
+ shouldHideAnchor = YES;
|
||||
+ }
|
||||
+ bool shouldHideAnchor =
|
||||
+ popupFrame->PopupElement().GetBoolAttr(nsGkAtoms::hidepopovertail);
|
||||
+ [(PopupWindow*)mWindow showPopoverRelativeToRect:positioningRect
|
||||
+ ofView:parentView
|
||||
+ preferredEdge:preferredEdge
|
||||
+ hiddenAnchor:shouldHideAnchor];
|
||||
+#pragma clang diagnostic push
|
||||
+#pragma clang diagnostic ignored "-Wobjc-method-access"
|
||||
+ SyncPopoverBounds([(PopupWindow*)mWindow popover], popupFrame);
|
||||
+
|
||||
+
|
||||
+
|
||||
+
|
||||
+#pragma clang diagnostic pop
|
||||
+ // Exit early here since the popover is now shown.
|
||||
+
|
||||
+ return;
|
||||
+ }
|
||||
// If our popup window is a non-native context menu, tell the OS (and
|
||||
@@ -398,7 +395,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
// close other programs' context menus when ours open.
|
||||
if ([mWindow isKindOfClass:[PopupWindow class]] &&
|
||||
[(PopupWindow*)mWindow isContextMenu]) {
|
||||
@@ -5373,11 +5476,15 @@
|
||||
@@ -5430,11 +5528,15 @@
|
||||
// unhook it here before ordering it out. When you order out the child
|
||||
// of a window it hides the parent window.
|
||||
if (mWindowType == WindowType::Popup && nativeParentWindow) {
|
||||
@@ -415,7 +412,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
// other programs) that a menu has closed.
|
||||
if ([mWindow isKindOfClass:[PopupWindow class]] &&
|
||||
[(PopupWindow*)mWindow isContextMenu]) {
|
||||
@@ -5424,10 +5531,28 @@
|
||||
@@ -5481,10 +5583,28 @@
|
||||
return false;
|
||||
}
|
||||
return nsIWidget::ShouldUseOffMainThreadCompositing();
|
||||
@@ -424,8 +421,8 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
+bool nsCocoaWindow::ShouldUseNSPopover() const {
|
||||
+ // Use NSPopover for panel popups when the preference is enabled
|
||||
+ // But not for detached popups - they should use traditional window logic
|
||||
+ return (mWindowType == WindowType::Popup && mPopupType == PopupType::Panel &&
|
||||
+ mozilla::StaticPrefs::widget_macos_native_popovers());
|
||||
+ return mWindowType == WindowType::Popup && mPopupType == PopupType::Panel &&
|
||||
+ mozilla::StaticPrefs::widget_macos_native_popovers();
|
||||
+}
|
||||
+
|
||||
+bool nsCocoaWindow::ShouldShowAsNSPopover() const {
|
||||
@@ -444,7 +441,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
|
||||
return mWindow.isOpaque ? TransparencyMode::Opaque
|
||||
: TransparencyMode::Transparent;
|
||||
@@ -6378,10 +6503,19 @@
|
||||
@@ -6442,10 +6562,22 @@
|
||||
|
||||
// We ignore aRepaint -- we have to call display:YES, otherwise the
|
||||
// title bar doesn't immediately get repainted and is displayed in
|
||||
@@ -454,17 +451,20 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
+ [(PopupWindow*)mWindow updatePopoverContent];
|
||||
+ // A popover won't resize by setting the frame
|
||||
+ // as it's size is calculated based on the content size
|
||||
+ // Therefor the content size has to be changed as well
|
||||
+ // Therefore the content size has to be changed as well
|
||||
+ NSSize contentSize = NSMakeSize(aWidth, aHeight);
|
||||
+#pragma clang diagnostic push
|
||||
+#pragma clang diagnostic ignored "-Wobjc-method-access"
|
||||
+ [[(PopupWindow*)mWindow popover] setContentSize:contentSize];
|
||||
+ SyncPopoverBounds([(PopupWindow*)mWindow popover], GetPopupFrame());
|
||||
+#pragma clang diagnostic pop
|
||||
+ }
|
||||
|
||||
NS_OBJC_END_TRY_IGNORE_BLOCK;
|
||||
}
|
||||
|
||||
void nsCocoaWindow::Resize(const DesktopRect& aRect, bool aRepaint) {
|
||||
@@ -8393,18 +8527,31 @@
|
||||
@@ -8517,18 +8649,31 @@
|
||||
backing:bufferingType
|
||||
defer:deferCreation];
|
||||
if (!self) {
|
||||
@@ -497,7 +497,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
// Return 0 in order to match what the system does for sheet windows and
|
||||
// _NSPopoverWindows.
|
||||
- (CGFloat)_backdropBleedAmount {
|
||||
@@ -8460,10 +8607,122 @@
|
||||
@@ -8584,10 +8729,125 @@
|
||||
|
||||
- (void)setIsContextMenu:(BOOL)flag {
|
||||
mIsContextMenu = flag;
|
||||
@@ -537,7 +537,7 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
+}
|
||||
+
|
||||
+- (BOOL)usePopover {
|
||||
+ return mUsePopover && !mIsContextMenu;
|
||||
+ return mUsePopover;
|
||||
+}
|
||||
+
|
||||
+- (void)showPopoverRelativeToRect:(NSRect)positioningRect
|
||||
@@ -562,7 +562,10 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
+
|
||||
+ // This is a hidden API that prevents the popover from showing its arrow
|
||||
+ // pointing to the anchor.
|
||||
+#pragma clang diagnostic push
|
||||
+#pragma clang diagnostic ignored "-Wobjc-method-access"
|
||||
+ [mPopover setShouldHideAnchor:hiddenAnchor];
|
||||
+#pragma clang diagnostic pop
|
||||
+
|
||||
+ [mPopover showRelativeToRect:positioningRect
|
||||
+ ofView:positioningView
|
||||
@@ -620,25 +623,6 @@ diff --git a/widget/cocoa/nsCocoaWindow.mm b/widget/cocoa/nsCocoaWindow.mm
|
||||
return NO;
|
||||
}
|
||||
|
||||
diff --git a/widget/nsIWidget.h b/widget/nsIWidget.h
|
||||
--- a/widget/nsIWidget.h
|
||||
+++ b/widget/nsIWidget.h
|
||||
@@ -829,10 +829,15 @@
|
||||
virtual void SuppressAnimation(bool aSuppress) {}
|
||||
|
||||
/** Sets windows-specific mica backdrop on this widget. */
|
||||
virtual void SetMicaBackdrop(bool) {}
|
||||
|
||||
+ /**
|
||||
+ * Determine whether this widget should be shown as an NSPopover.
|
||||
+ */
|
||||
+ virtual bool ShouldShowAsNSPopover() const { return false; }
|
||||
+
|
||||
/**
|
||||
* Return size mode (minimized, maximized, normalized).
|
||||
* Returns a value from nsSizeMode (see nsIWidgetListener.h)
|
||||
*/
|
||||
virtual nsSizeMode SizeMode() = 0;
|
||||
diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py
|
||||
--- a/xpcom/ds/StaticAtoms.py
|
||||
+++ b/xpcom/ds/StaticAtoms.py
|
||||
@@ -654,16 +638,4 @@ diff --git a/xpcom/ds/StaticAtoms.py b/xpcom/ds/StaticAtoms.py
|
||||
Atom("highest", "highest"),
|
||||
Atom("horizontal", "horizontal"),
|
||||
Atom("hover", "hover"),
|
||||
@@ -759,10 +760,11 @@
|
||||
Atom("nohref", "nohref"),
|
||||
Atom("noinitialselection", "noinitialselection"),
|
||||
Atom("nomodule", "nomodule"),
|
||||
Atom("nonce", "nonce"),
|
||||
Atom("none", "none"),
|
||||
+ Atom("nonnativepopover", "nonnativepopover"),
|
||||
Atom("noresize", "noresize"),
|
||||
Atom("normal", "normal"),
|
||||
Atom("normalizeSpace", "normalize-space"),
|
||||
Atom("noscript", "noscript"),
|
||||
Atom("noshade", "noshade"),
|
||||
|
||||
|
||||
@@ -1,3 +1,18 @@
|
||||
diff --git a/toolkit/themes/shared/global-shared.css b/toolkit/themes/shared/global-shared.css
|
||||
--- a/toolkit/themes/shared/global-shared.css
|
||||
+++ b/toolkit/themes/shared/global-shared.css
|
||||
@@ -80,11 +80,10 @@
|
||||
background-color: transparent;
|
||||
--panel-background: transparent;
|
||||
--panel-box-shadow: none;
|
||||
--panel-border-color: transparent;
|
||||
--panel-box-shadow-margin: 0px;
|
||||
- --panel-padding: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
/* Lightweight theme roots */
|
||||
|
||||
diff --git a/widget/cocoa/nsCocoaWindow.h b/widget/cocoa/nsCocoaWindow.h
|
||||
--- a/widget/cocoa/nsCocoaWindow.h
|
||||
+++ b/widget/cocoa/nsCocoaWindow.h
|
||||
|
||||
@@ -630,7 +630,6 @@ ${cssSelector} {
|
||||
this.currentBoostData.textCaseOverride = "uppercase";
|
||||
}
|
||||
|
||||
this.currentBoostData.changeWasMade = true;
|
||||
this.updateCaseButtonVisuals();
|
||||
this.updateCurrentBoost();
|
||||
}
|
||||
@@ -652,7 +651,6 @@ ${cssSelector} {
|
||||
await this.zenBoostsChild.sendQuery("ZenBoost:DisableSizeOverride");
|
||||
}
|
||||
|
||||
this.currentBoostData.changeWasMade = true;
|
||||
this.updateSizeButtonVisuals();
|
||||
this.updateCurrentBoost();
|
||||
}
|
||||
|
||||
@@ -100,16 +100,7 @@ class ZenStartup {
|
||||
delete this.promiseInitializedResolve;
|
||||
|
||||
setTimeout(() => {
|
||||
// Wait for the natural PlacesToolbar rebuild before invalidating, so
|
||||
// the two async rebuilds don't interleave and duplicate bookmarks.
|
||||
// promiseRebuilt() returns undefined when no rebuild is in flight.
|
||||
const rebuilt =
|
||||
document
|
||||
.getElementById("PlacesToolbar")
|
||||
?._placesView?.promiseRebuilt() ?? Promise.resolve();
|
||||
rebuilt
|
||||
.catch(console.error)
|
||||
.then(() => gZenWorkspaces._invalidateBookmarkContainers());
|
||||
gZenWorkspaces._invalidateBookmarkContainers();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2290,11 +2290,6 @@ class nsZenWorkspaces {
|
||||
}
|
||||
|
||||
onBeforeTabSelect(aTab) {
|
||||
if (this.#inChangingWorkspace) {
|
||||
// Just in case, Let's not do these checks while we are
|
||||
// in the middle of changing workspace,
|
||||
return false;
|
||||
}
|
||||
const tabSpace = aTab?.getAttribute("zen-workspace-id");
|
||||
if (
|
||||
tabSpace &&
|
||||
@@ -2302,12 +2297,8 @@ class nsZenWorkspaces {
|
||||
!aTab.hasAttribute("zen-empty-tab") &&
|
||||
!aTab.hasAttribute("zen-essential")
|
||||
) {
|
||||
this.lastSelectedWorkspaceTabs[tabSpace] =
|
||||
gZenGlanceManager.getTabOrGlanceParent(aTab);
|
||||
this.changeWorkspaceWithID(tabSpace);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
_shouldShowTab(tab, workspaceUuid, containerId, workspaces) {
|
||||
|
||||
@@ -40,7 +40,7 @@ add_task(async function testNormalBrowsing() {
|
||||
browser: tab.linkedBrowser,
|
||||
uriString: TEST_PAGE,
|
||||
});
|
||||
testWhitelistedPage(tab.ownerGlobal);
|
||||
testWhitelistedPage(tab.documentGlobal);
|
||||
|
||||
info("Load a test page that's no longer whitelisted");
|
||||
Services.prefs.setCharPref(PREF_WHITELISTED_HOSTNAMES, "");
|
||||
@@ -54,5 +54,5 @@ add_task(async function testNormalBrowsing() {
|
||||
);
|
||||
BrowserTestUtils.startLoadingURIString(tab.linkedBrowser, TEST_PAGE);
|
||||
await blockedLoaded;
|
||||
testBlockedPage(tab.ownerGlobal);
|
||||
testBlockedPage(tab.documentGlobal);
|
||||
});
|
||||
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
["browser_1119088.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
support-files = ["mac_desktop_image.py"]
|
||||
support-files = [
|
||||
"large.png",
|
||||
"mac_desktop_image.py"
|
||||
]
|
||||
run-if = [
|
||||
"os == 'mac'",
|
||||
]
|
||||
@@ -12,6 +15,7 @@ skip-if = [
|
||||
]
|
||||
|
||||
["browser_420786.js"]
|
||||
support-files = ["large.png"]
|
||||
run-if = [
|
||||
"os == 'linux' && os_version == '22.04' && arch == 'x86_64' && display == 'wayland'",
|
||||
"os == 'linux' && os_version == '24.04' && arch == 'x86_64' && display == 'x11'",
|
||||
@@ -116,4 +120,5 @@ tags = "os_integration"
|
||||
|
||||
["browser_setDesktopBackgroundPreview.js"]
|
||||
disabled="Disabled by import_external_tests.py"
|
||||
support-files = ["large.png"]
|
||||
tags = "os_integration"
|
||||
|
||||
@@ -92,20 +92,19 @@ add_setup(async function () {
|
||||
/**
|
||||
* Tests "Set As Desktop Background" platform implementation on macOS.
|
||||
*
|
||||
* Sets the desktop background image to the browser logo from the about:logo
|
||||
* page and verifies it was set successfully. Setting the desktop background
|
||||
* (which uses the nsIShellService::setDesktopBackground() interface method)
|
||||
* downloads the image to ~/Pictures using a unique file name and sets the
|
||||
* desktop background to the downloaded file leaving the download in place.
|
||||
* After setDesktopBackground() is called, the test uses a python script to
|
||||
* validate that the current desktop background is in fact set to the
|
||||
* downloaded logo.
|
||||
* Sets the desktop background image to the large.png image and verifies it was
|
||||
* set successfully. Setting the desktop background (which uses the
|
||||
* nsIShellService::setDesktopBackground() interface method) downloads the
|
||||
* image to ~/Pictures using a unique file name and sets the desktop background
|
||||
* to the downloaded file leaving the download in place. After
|
||||
* setDesktopBackground() is called, the test uses a python script to validate
|
||||
* that the current desktop background is in fact set to the downloaded image.
|
||||
*/
|
||||
add_task(async function () {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "about:logo",
|
||||
url: getRootDirectory(gTestPath) + "large.png",
|
||||
},
|
||||
async () => {
|
||||
let dirSvc = Cc["@mozilla.org/file/directory_service;1"].getService(
|
||||
@@ -140,7 +139,7 @@ add_task(async function () {
|
||||
|
||||
// For simplicity, we're going to reach in and access the image on the
|
||||
// page directly, which means the page shouldn't be running in a remote
|
||||
// browser. Thankfully, about:logo runs in the parent process for now.
|
||||
// browser. Thankfully, chrome:// runs in the parent process for now.
|
||||
Assert.ok(
|
||||
!gBrowser.selectedBrowser.isRemoteBrowser,
|
||||
"image can be accessed synchronously from the parent process"
|
||||
|
||||
@@ -12,7 +12,7 @@ add_task(async function () {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "about:logo",
|
||||
url: getRootDirectory(gTestPath) + "large.png",
|
||||
},
|
||||
() => {
|
||||
var brandName = Services.strings
|
||||
@@ -46,7 +46,7 @@ add_task(async function () {
|
||||
|
||||
// For simplicity, we're going to reach in and access the image on the
|
||||
// page directly, which means the page shouldn't be running in a remote
|
||||
// browser. Thankfully, about:logo runs in the parent process for now.
|
||||
// browser. Thankfully, chrome:// runs in the parent process for now.
|
||||
Assert.ok(
|
||||
!gBrowser.selectedBrowser.isRemoteBrowser,
|
||||
"image can be accessed synchronously from the parent process"
|
||||
|
||||
@@ -323,14 +323,39 @@ add_task(async function test_setAsDefaultPDFHandler_knownBrowser() {
|
||||
}
|
||||
});
|
||||
|
||||
// Wait for the deferred set_default_pdf_handler_attempt event to be recorded,
|
||||
// then return the single event that was emitted by the most recent call.
|
||||
async function awaitAttemptEvent() {
|
||||
await TestUtils.waitForCondition(() => {
|
||||
const events = Glean.browser.setDefaultPdfHandlerAttempt.testGetValue();
|
||||
return events && events.length;
|
||||
}, "Recorded set_default_pdf_handler_attempt event");
|
||||
const events = Glean.browser.setDefaultPdfHandlerAttempt.testGetValue();
|
||||
Assert.equal(events.length, 1, "Recorded exactly one attempt event");
|
||||
return events[0];
|
||||
}
|
||||
|
||||
add_task(async function test_setAsDefaultPDFHandler_fallback() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
// Enable the IOpenWithLauncher branch explicitly so the test does not
|
||||
// depend on the build-channel default of
|
||||
// browser.shell.setDefaultPDFHandler.useOpenWith, and use a 0ms wait so
|
||||
// the deferred attempt event fires promptly.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.shell.setDefaultPDFHandler.useOpenWith", true],
|
||||
["browser.shell.setDefaultPDFHandler.attemptWaitTimeMs", 0],
|
||||
],
|
||||
});
|
||||
|
||||
try {
|
||||
const userChoiceStub = sandbox
|
||||
.stub(ShellService, "setAsDefaultPDFHandlerUserChoice")
|
||||
.rejects(new Error("mock userChoice failure"));
|
||||
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
||||
const isDefaultHandlerForStub = sandbox
|
||||
.stub(ShellService, "isDefaultHandlerFor")
|
||||
.returns(true);
|
||||
|
||||
info(
|
||||
"When userChoice fails and open-with picker succeeds, should not fall back to settings dialog"
|
||||
@@ -352,27 +377,42 @@ add_task(async function test_setAsDefaultPDFHandler_fallback() {
|
||||
1,
|
||||
"Recorded user-choice failure"
|
||||
);
|
||||
|
||||
let event = await awaitAttemptEvent();
|
||||
Assert.equal(event.extra.method, "open_with", "Event method is open_with");
|
||||
Assert.equal(event.extra.success, "true", "Event success is true");
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerUserChoiceResult.Success.testGetValue(),
|
||||
undefined,
|
||||
"Did not record user-choice success"
|
||||
event.extra.result_is_default,
|
||||
"true",
|
||||
"Event result_is_default reflects isDefaultHandlerFor"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerOpenWithResult.Success.testGetValue(),
|
||||
1,
|
||||
"Recorded open-with success"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerOpenWithResult.Failure.testGetValue(),
|
||||
undefined,
|
||||
"Did not record open-with failure"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerModernSettingsResult.Success.testGetValue(),
|
||||
undefined,
|
||||
"Did not record modern settings result"
|
||||
Assert.ok(
|
||||
isDefaultHandlerForStub.calledWith(".pdf"),
|
||||
"Sampled isDefaultHandlerFor after the delay"
|
||||
);
|
||||
userChoiceStub.resetHistory();
|
||||
isDefaultHandlerForStub.resetHistory();
|
||||
launchOpenWithDefaultPickerForFileTypeStub.resetHistory();
|
||||
launchModernSettingsDialogDefaultAppsStub.resetHistory();
|
||||
|
||||
info(
|
||||
"When the picker succeeds but Firefox is not default after the delay, event records result_is_default=false"
|
||||
);
|
||||
Services.fog.testResetFOG();
|
||||
isDefaultHandlerForStub.returns(false);
|
||||
await ShellService.setAsDefaultPDFHandler(false);
|
||||
|
||||
event = await awaitAttemptEvent();
|
||||
Assert.equal(event.extra.method, "open_with", "Event method is open_with");
|
||||
Assert.equal(event.extra.success, "true", "Event success is true");
|
||||
Assert.equal(
|
||||
event.extra.result_is_default,
|
||||
"false",
|
||||
"Event result_is_default is false when Firefox did not become default"
|
||||
);
|
||||
isDefaultHandlerForStub.returns(true);
|
||||
userChoiceStub.resetHistory();
|
||||
isDefaultHandlerForStub.resetHistory();
|
||||
launchOpenWithDefaultPickerForFileTypeStub.resetHistory();
|
||||
launchModernSettingsDialogDefaultAppsStub.resetHistory();
|
||||
|
||||
@@ -399,72 +439,120 @@ add_task(async function test_setAsDefaultPDFHandler_fallback() {
|
||||
1,
|
||||
"Recorded user-choice failure"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerUserChoiceResult.Success.testGetValue(),
|
||||
undefined,
|
||||
"Did not record user-choice success"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerOpenWithResult.Failure.testGetValue(),
|
||||
1,
|
||||
"Recorded open-with failure"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerOpenWithResult.Success.testGetValue(),
|
||||
undefined,
|
||||
"Did not record open-with success"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerModernSettingsResult.Success.testGetValue(),
|
||||
1,
|
||||
"Recorded modern settings success"
|
||||
);
|
||||
|
||||
event = await awaitAttemptEvent();
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerModernSettingsResult.Failure.testGetValue(),
|
||||
undefined,
|
||||
"Did not record modern settings failure"
|
||||
event.extra.method,
|
||||
"settings",
|
||||
"Event method is settings (last attempted)"
|
||||
);
|
||||
Assert.equal(
|
||||
event.extra.success,
|
||||
"true",
|
||||
"Event success reflects modern settings launch"
|
||||
);
|
||||
Assert.equal(
|
||||
event.extra.result_is_default,
|
||||
"true",
|
||||
"Event result_is_default reflects isDefaultHandlerFor"
|
||||
);
|
||||
userChoiceStub.resetHistory();
|
||||
isDefaultHandlerForStub.resetHistory();
|
||||
launchOpenWithDefaultPickerForFileTypeStub.resetHistory();
|
||||
launchModernSettingsDialogDefaultAppsStub.resetHistory();
|
||||
|
||||
info(
|
||||
"When userChoice fails, open-with fails, and modern settings fails, should record all failures"
|
||||
"When userChoice fails, open-with fails, and modern settings fails, event records success=false"
|
||||
);
|
||||
Services.fog.testResetFOG();
|
||||
isDefaultHandlerForStub.returns(false);
|
||||
launchModernSettingsDialogDefaultAppsStub.throws(
|
||||
new Error("mock modern settings failure")
|
||||
);
|
||||
await ShellService.setAsDefaultPDFHandler(false);
|
||||
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerUserChoiceResult.ErrOther.testGetValue(),
|
||||
1,
|
||||
"Recorded user-choice failure"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerUserChoiceResult.Success.testGetValue(),
|
||||
undefined,
|
||||
"Did not record user-choice success"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerOpenWithResult.Failure.testGetValue(),
|
||||
1,
|
||||
"Recorded open-with failure"
|
||||
);
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerModernSettingsResult.Failure.testGetValue(),
|
||||
1,
|
||||
"Recorded modern settings failure"
|
||||
);
|
||||
|
||||
event = await awaitAttemptEvent();
|
||||
Assert.equal(
|
||||
Glean.browser.setDefaultPdfHandlerModernSettingsResult.Success.testGetValue(),
|
||||
undefined,
|
||||
"Did not record modern settings success"
|
||||
event.extra.method,
|
||||
"settings",
|
||||
"Event method is settings (last attempted)"
|
||||
);
|
||||
Assert.equal(
|
||||
event.extra.success,
|
||||
"false",
|
||||
"Event success is false when every method failed"
|
||||
);
|
||||
Assert.equal(
|
||||
event.extra.result_is_default,
|
||||
"false",
|
||||
"Event result_is_default is false when no method set the default"
|
||||
);
|
||||
} finally {
|
||||
launchOpenWithDefaultPickerForFileTypeStub.reset();
|
||||
launchModernSettingsDialogDefaultAppsStub.reset();
|
||||
sandbox.restore();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
});
|
||||
|
||||
add_task(async function test_setAsDefaultPDFHandler_useOpenWithDisabled() {
|
||||
const sandbox = sinon.createSandbox();
|
||||
// With useOpenWith disabled, a userChoice failure should skip the
|
||||
// IOpenWithLauncher branch entirely and fall straight through to the
|
||||
// modern settings dialog.
|
||||
await SpecialPowers.pushPrefEnv({
|
||||
set: [
|
||||
["browser.shell.setDefaultPDFHandler.useOpenWith", false],
|
||||
["browser.shell.setDefaultPDFHandler.attemptWaitTimeMs", 0],
|
||||
],
|
||||
});
|
||||
|
||||
try {
|
||||
sandbox
|
||||
.stub(ShellService, "setAsDefaultPDFHandlerUserChoice")
|
||||
.rejects(new Error("mock userChoice failure"));
|
||||
sandbox.stub(ShellService, "_isWindows11").returns(true);
|
||||
sandbox.stub(ShellService, "isDefaultHandlerFor").returns(true);
|
||||
|
||||
Services.fog.testResetFOG();
|
||||
await ShellService.setAsDefaultPDFHandler(false);
|
||||
|
||||
Assert.ok(
|
||||
launchOpenWithDefaultPickerForFileTypeStub.notCalled,
|
||||
"Did not invoke open-with picker when pref is disabled"
|
||||
);
|
||||
Assert.ok(
|
||||
launchModernSettingsDialogDefaultAppsStub.called,
|
||||
"Fell through to modern settings dialog"
|
||||
);
|
||||
|
||||
const event = await awaitAttemptEvent();
|
||||
Assert.equal(
|
||||
event.extra.method,
|
||||
"settings",
|
||||
"Event method skipped open_with and recorded settings"
|
||||
);
|
||||
Assert.equal(event.extra.success, "true", "Event success is true");
|
||||
Assert.equal(
|
||||
event.extra.result_is_default,
|
||||
"true",
|
||||
"Event result_is_default reflects isDefaultHandlerFor"
|
||||
);
|
||||
} finally {
|
||||
launchOpenWithDefaultPickerForFileTypeStub.reset();
|
||||
launchModernSettingsDialogDefaultAppsStub.reset();
|
||||
sandbox.restore();
|
||||
await SpecialPowers.popPrefEnv();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -16,7 +16,7 @@ add_task(async function () {
|
||||
await BrowserTestUtils.withNewTab(
|
||||
{
|
||||
gBrowser,
|
||||
url: "about:logo",
|
||||
url: getRootDirectory(gTestPath) + "large.png",
|
||||
},
|
||||
async () => {
|
||||
const dialogLoad = BrowserTestUtils.domWindowOpened(null, async win => {
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
BIN
src/zen/tests/mochitests/shell/large.png
Normal file
BIN
src/zen/tests/mochitests/shell/large.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
131
src/zen/tests/mochitests/shell/unit/test_desktopEntryStatus.js
Normal file
131
src/zen/tests/mochitests/shell/unit/test_desktopEntryStatus.js
Normal file
@@ -0,0 +1,131 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
http://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
ShellService: "moz-src:///browser/components/shell/ShellService.sys.mjs",
|
||||
});
|
||||
|
||||
const BAREBONES_DESKTOP_ENTRY = `[Desktop Entry]
|
||||
Version=1.5
|
||||
Type=Application
|
||||
Name=test_desktopEntryStatus.js test case
|
||||
`;
|
||||
|
||||
let gHomeDir;
|
||||
let gSystemDir;
|
||||
|
||||
const filename = what => `test_desktopEntryStatus_file_${what}.desktop`;
|
||||
|
||||
// GLib caches results for efficiency. Unfortunately, it doesn't really provide
|
||||
// a way to invalidate that cache, aside from hoping that the file monitor
|
||||
// picks up on it. Resolve this by setting up all of the desktop entries at the
|
||||
// start, then doing checks, then exiting.
|
||||
//
|
||||
// (Some others are special-cased, namely absent and Hidden= checks.)
|
||||
const kDesktopEntries = [
|
||||
{
|
||||
label: "visible",
|
||||
content: BAREBONES_DESKTOP_ENTRY,
|
||||
expected: Ci.nsIGNOMEShellService.DESKTOP_ENTRY_VISIBLE,
|
||||
},
|
||||
{
|
||||
label: "nodisplay",
|
||||
content: BAREBONES_DESKTOP_ENTRY + "NoDisplay=true\n",
|
||||
expected: Ci.nsIGNOMEShellService.DESKTOP_ENTRY_INVISIBLE,
|
||||
},
|
||||
{
|
||||
label: "onlyshowin-matching",
|
||||
content: BAREBONES_DESKTOP_ENTRY + "OnlyShowIn=FirefoxOS\n",
|
||||
expected: Ci.nsIGNOMEShellService.DESKTOP_ENTRY_VISIBLE,
|
||||
},
|
||||
{
|
||||
label: "onlyshowin-notmatching",
|
||||
content: BAREBONES_DESKTOP_ENTRY + "OnlyShowIn=another\n",
|
||||
expected: Ci.nsIGNOMEShellService.DESKTOP_ENTRY_INVISIBLE,
|
||||
},
|
||||
{
|
||||
label: "notshowin-matching",
|
||||
content: BAREBONES_DESKTOP_ENTRY + "NotShowIn=FirefoxOS\n",
|
||||
expected: Ci.nsIGNOMEShellService.DESKTOP_ENTRY_INVISIBLE,
|
||||
},
|
||||
{
|
||||
label: "notshowin-notmatching",
|
||||
content: BAREBONES_DESKTOP_ENTRY + "NotShowIn=another\n",
|
||||
expected: Ci.nsIGNOMEShellService.DESKTOP_ENTRY_VISIBLE,
|
||||
},
|
||||
];
|
||||
|
||||
add_setup(async function setup() {
|
||||
let unique = await IOUtils.createUniqueDirectory(
|
||||
Services.dirsvc.get("TmpD", Ci.nsIFile).path,
|
||||
"desktopEntryStatusTest"
|
||||
);
|
||||
|
||||
let homeDir = PathUtils.join(unique, "data-home");
|
||||
Services.env.set("XDG_DATA_HOME", homeDir);
|
||||
gHomeDir = PathUtils.join(homeDir, "applications");
|
||||
await IOUtils.makeDirectory(gHomeDir, { createAncestors: true });
|
||||
|
||||
let systemDir = PathUtils.join(unique, "data-system");
|
||||
Services.env.set("XDG_DATA_DIRS", systemDir);
|
||||
gSystemDir = PathUtils.join(systemDir, "applications");
|
||||
await IOUtils.makeDirectory(gSystemDir, { createAncestors: true });
|
||||
|
||||
Services.env.set("XDG_CURRENT_DESKTOP", "FirefoxOS");
|
||||
|
||||
await IOUtils.writeUTF8(
|
||||
PathUtils.join(gHomeDir, filename("deleted")),
|
||||
BAREBONES_DESKTOP_ENTRY + "Hidden=true\n"
|
||||
);
|
||||
await IOUtils.writeUTF8(
|
||||
PathUtils.join(gSystemDir, filename("deleted")),
|
||||
BAREBONES_DESKTOP_ENTRY
|
||||
);
|
||||
|
||||
for (const desktopEntry of kDesktopEntries) {
|
||||
await IOUtils.writeUTF8(
|
||||
PathUtils.join(gHomeDir, filename(desktopEntry.label + "-home")),
|
||||
desktopEntry.content
|
||||
);
|
||||
await IOUtils.writeUTF8(
|
||||
PathUtils.join(gSystemDir, filename(desktopEntry.label + "-system")),
|
||||
desktopEntry.content
|
||||
);
|
||||
}
|
||||
|
||||
registerCleanupFunction(async () => {
|
||||
return IOUtils.remove(unique, { recursive: true });
|
||||
});
|
||||
});
|
||||
|
||||
add_task(function test_desktopEntryStatus() {
|
||||
Assert.equal(
|
||||
ShellService.getDesktopEntryStatus(filename("absent")),
|
||||
Ci.nsIGNOMEShellService.DESKTOP_ENTRY_ABSENT,
|
||||
"A desktop entry that doesn't exist should be absent."
|
||||
);
|
||||
Assert.equal(
|
||||
ShellService.getDesktopEntryStatus(filename("hidden")),
|
||||
Ci.nsIGNOMEShellService.DESKTOP_ENTRY_ABSENT,
|
||||
"A desktop entry shadowed by one with the Hidden= attribute should be absent."
|
||||
);
|
||||
|
||||
for (const desktopEntry of kDesktopEntries) {
|
||||
Assert.equal(
|
||||
ShellService.getDesktopEntryStatus(
|
||||
filename(desktopEntry.label + "-home")
|
||||
),
|
||||
desktopEntry.expected,
|
||||
"Desktop entry matches when at the local level: " + desktopEntry.label
|
||||
);
|
||||
Assert.equal(
|
||||
ShellService.getDesktopEntryStatus(
|
||||
filename(desktopEntry.label + "-system")
|
||||
),
|
||||
desktopEntry.expected,
|
||||
"Desktop entry matches when at the system level: " + desktopEntry.label
|
||||
);
|
||||
}
|
||||
});
|
||||
@@ -0,0 +1,109 @@
|
||||
/* Any copyright is dedicated to the Public Domain.
|
||||
* https://creativecommons.org/publicdomain/zero/1.0/ */
|
||||
|
||||
"use strict";
|
||||
|
||||
ChromeUtils.defineESModuleGetters(this, {
|
||||
StartupOSIntegration:
|
||||
"moz-src:///browser/components/shell/StartupOSIntegration.sys.mjs",
|
||||
WindowsLaunchOnLogin: "resource://gre/modules/WindowsLaunchOnLogin.sys.mjs",
|
||||
sinon: "resource://testing-common/Sinon.sys.mjs",
|
||||
});
|
||||
|
||||
const PREF = "browser.startup.windowsLaunchOnLogin.defaultEnabled";
|
||||
|
||||
async function runWith({ isFirstRun, prefValue, approved }) {
|
||||
let sandbox = sinon.createSandbox();
|
||||
let approvedStub = sandbox
|
||||
.stub(WindowsLaunchOnLogin, "getLaunchOnLoginApproved")
|
||||
.resolves(approved);
|
||||
let createStub = sandbox
|
||||
.stub(WindowsLaunchOnLogin, "createLaunchOnLogin")
|
||||
.resolves();
|
||||
|
||||
if (prefValue === null) {
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
} else {
|
||||
Services.prefs.setBoolPref(PREF, prefValue);
|
||||
}
|
||||
|
||||
try {
|
||||
await StartupOSIntegration.maybeCreateLaunchOnLoginOnFirstRun(isFirstRun);
|
||||
return { approvedStub, createStub };
|
||||
} finally {
|
||||
sandbox.restore();
|
||||
Services.prefs.clearUserPref(PREF);
|
||||
}
|
||||
}
|
||||
|
||||
add_task(async function test_creates_when_all_conditions_true() {
|
||||
let { createStub } = await runWith({
|
||||
isFirstRun: true,
|
||||
prefValue: true,
|
||||
approved: true,
|
||||
});
|
||||
Assert.ok(
|
||||
createStub.calledOnce,
|
||||
"createLaunchOnLogin should be called when isFirstRun, pref, and approval are all true"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_skips_when_not_first_run() {
|
||||
let { createStub, approvedStub } = await runWith({
|
||||
isFirstRun: false,
|
||||
prefValue: true,
|
||||
approved: true,
|
||||
});
|
||||
Assert.ok(
|
||||
!createStub.called,
|
||||
"createLaunchOnLogin should not be called when isFirstRun is false"
|
||||
);
|
||||
Assert.ok(
|
||||
!approvedStub.called,
|
||||
"getLaunchOnLoginApproved should be short-circuited when isFirstRun is false"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_skips_when_pref_disabled() {
|
||||
let { createStub, approvedStub } = await runWith({
|
||||
isFirstRun: true,
|
||||
prefValue: false,
|
||||
approved: true,
|
||||
});
|
||||
Assert.ok(
|
||||
!createStub.called,
|
||||
"createLaunchOnLogin should not be called when pref is false"
|
||||
);
|
||||
Assert.ok(
|
||||
!approvedStub.called,
|
||||
"getLaunchOnLoginApproved should be short-circuited when pref is false"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_skips_when_windows_policy_denies() {
|
||||
let { createStub, approvedStub } = await runWith({
|
||||
isFirstRun: true,
|
||||
prefValue: true,
|
||||
approved: false,
|
||||
});
|
||||
Assert.ok(
|
||||
approvedStub.calledOnce,
|
||||
"getLaunchOnLoginApproved should be consulted when pref and isFirstRun are true"
|
||||
);
|
||||
Assert.ok(
|
||||
!createStub.called,
|
||||
"createLaunchOnLogin should not be called when Windows policy denies"
|
||||
);
|
||||
});
|
||||
|
||||
add_task(async function test_uses_pref_default_when_unset() {
|
||||
let { createStub } = await runWith({
|
||||
isFirstRun: true,
|
||||
prefValue: null,
|
||||
approved: true,
|
||||
});
|
||||
Assert.ok(
|
||||
createStub.calledOnce,
|
||||
"createLaunchOnLogin should be called when pref is at its built-in default of true"
|
||||
);
|
||||
});
|
||||
@@ -5,6 +5,11 @@ run-if = [
|
||||
firefox-appdir = "browser"
|
||||
tags = "os_integration"
|
||||
|
||||
["test_desktopEntryStatus.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
]
|
||||
|
||||
["test_linuxDesktopEntry.js"]
|
||||
run-if = [
|
||||
"os == 'linux'",
|
||||
@@ -15,6 +20,11 @@ run-if = [
|
||||
"os == 'mac'",
|
||||
]
|
||||
|
||||
["test_maybeCreateLaunchOnLoginOnFirstRun.js"]
|
||||
run-if = [
|
||||
"os == 'win'"
|
||||
]
|
||||
|
||||
["test_secondaryTileJs.js"]
|
||||
run-if = [
|
||||
"os == 'win'"
|
||||
|
||||
@@ -63,7 +63,7 @@ async function do_test(test) {
|
||||
if (test.value) {
|
||||
info("Creating mock filepicker to select files");
|
||||
let MockFilePicker = SpecialPowers.MockFilePicker;
|
||||
MockFilePicker.init(window.browsingContext);
|
||||
MockFilePicker.init();
|
||||
MockFilePicker.returnValue = MockFilePicker.returnOK;
|
||||
MockFilePicker.displayDirectory = FileUtils.getDir("TmpD", []);
|
||||
MockFilePicker.setFiles([tempFile]);
|
||||
|
||||
@@ -142,9 +142,7 @@ export class nsZenSiteDataPanel {
|
||||
this.anchor.removeAttribute("boosting");
|
||||
}
|
||||
// Force a reflow to ensure the attribute change is applied before any potential animation.
|
||||
if (this.unifiedPanel.state === "open") {
|
||||
this.anchor.getBoundingClientRect();
|
||||
}
|
||||
this.anchor.getBoundingClientRect();
|
||||
}
|
||||
|
||||
#initCopyUrlButton() {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
"version": {
|
||||
"product": "firefox",
|
||||
"version": "151.0.4",
|
||||
"candidate": "151.0.4",
|
||||
"candidate": "152.0",
|
||||
"candidateBuild": 1
|
||||
},
|
||||
"buildOptions": {
|
||||
@@ -20,7 +20,7 @@
|
||||
"brandShortName": "Zen",
|
||||
"brandFullName": "Zen Browser",
|
||||
"release": {
|
||||
"displayVersion": "1.21.1b",
|
||||
"displayVersion": "1.21b",
|
||||
"github": {
|
||||
"repo": "zen-browser/desktop"
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user