Compare commits

..

28 Commits

Author SHA1 Message Date
mr. m
db3eea65b7 gh-13060: Fixed collapsed pins not marked as active (gh-13061) 2026-04-03 00:00:22 +02:00
mr. m
b55358b9ab gh-12979: Import compositor patches from upstream (gh-13054) 2026-04-02 17:17:08 +02:00
mr. m
dba5a0402c no-bug: Dont animate glance image preview opacity (gh-13055) 2026-04-02 17:15:47 +02:00
mr. m
92eb6b07c3 gh-12985: Disable new firefox search widget (gh-13052) 2026-04-02 16:12:24 +02:00
mr. m
36aa7b0a20 gh-13038: Fixed trying to swap browsers that dont exist (gh-13051) 2026-04-02 16:10:18 +02:00
Hythera
0619d3d8de no-bug: remove obsolete patch from Firefox 149.0 (gh-13049) 2026-04-02 14:30:52 +02:00
mr. m
6b5f6c7b9d no-bug: Properly align identity box icon (gh-13035) 2026-04-01 13:07:10 +02:00
mr. m
69e3a995ae gh-13024: Fixed restoring tab state also taking into account scroll (gh-13034) 2026-04-01 12:56:05 +02:00
mr. m
e32ff53d2d gh-13030: Fixed unsplit tab item showing when it shouldn't (gh-13033) 2026-04-01 12:20:25 +02:00
Zack Koppert
ba593a19dc no-bug: update OSPO action references to canonical org path (gh-13028) 2026-03-31 21:57:06 +02:00
mr. m
f40a7aaee1 gh-13016: Fixed pinned tabs not being able to collapse (gh-13018) 2026-03-31 14:46:32 +02:00
mr. m
62286a2758 gh-13015: Fixed tablist scroll beibg occasionally stuck (gh-13017) 2026-03-31 13:46:03 +02:00
Tyson Cung
067b8244ec gh-12966: rename split view tab labels for clarity (gh-12983)
Co-authored-by: Tyson Cung <tysoncung@example.com>
2026-03-30 17:42:00 +02:00
mr. m
be9928beda no-bug: Prevent focusing the urlbar on tab switch (gh-13002) 2026-03-30 17:34:32 +02:00
Davide Taffarello
742a1e6882 gh-12730: conflict keybord shortcut name always shows "Escape" (gh-12993)
Co-authored-by: mr. m <91018726+mr-cheffy@users.noreply.github.com>
2026-03-30 14:15:25 +02:00
mr. m
a2796d7af0 gh-9600: Fixed text being unreadable with some themes (gh-12998) 2026-03-30 14:14:23 +02:00
mr. m
2d6f2cbbde gh-12994: Fixed adress bar not being aligned with the container (gh-12997) 2026-03-30 13:26:34 +02:00
mr. m
3fd89a93f5 no-bug: Move live folder context menu item to the toolbar menu (gh-12991) 2026-03-29 19:20:11 +02:00
mr. m
595f236a7a gh-12989: Make split command use context tabs (gh-12990) 2026-03-29 18:59:15 +02:00
Rugved_018
8fec3702f4 gh-12104: Fix notification tabs overlap (gh-12965)
Co-authored-by: mr. m <mr.m@tuta.com>
2026-03-29 15:44:03 +02:00
mr. m
ec2864902c gh-8206: Respect reduce motion more and dont block switch animations (gh-12980) 2026-03-29 15:32:27 +02:00
mr. m
7f00a16d6d gh-12973: Fixed compact mode toggle being always checked (gh-12977) 2026-03-29 14:14:38 +02:00
mr. m
65597fd6b5 no-bug: Don't run welcome screen on headless mode (gh-12959) 2026-03-28 08:02:05 +01:00
Slowlife
fba5d0c4cc gh-12942: Fixed github pull requests not getting fetched (gh-12958)
Co-authored-by: mr. m <mr.m@tuta.com>
2026-03-28 07:47:33 +01:00
mr. m
1089e72ef6 no-bug: update migration data access to handle undefined safely (gh-12956) 2026-03-27 23:01:26 +01:00
mr. m
0829b3ac36 no-bug: Dont reset heights on tab drop (gh-12947) 2026-03-27 14:35:20 +01:00
Slowlife
4c1e52c063 gh-12942: Fixed unable to enable live folder options (gh-12946) 2026-03-27 14:34:40 +01:00
mr. m
b39b9abc6f gh-12940: Fixed new profiles not being able to startup (gh-12944) 2026-03-27 14:19:48 +01:00
48 changed files with 545 additions and 461 deletions

View File

@@ -42,7 +42,7 @@ jobs:
echo "last_month_year=$previous_year" >> "$GITHUB_ENV"
- name: Run issue-metrics tool
uses: github/issue-metrics@v2
uses: github-community-projects/issue-metrics@v2
env:
GH_TOKEN: ${{ secrets.DEPLOY_KEY }}
HIDE_AUTHOR: true

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,9 +5,9 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[-1] Unsplit Tabs
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[-1] Split out tab
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S

View File

@@ -5,9 +5,9 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[-1] Unsplit Tabs
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[-1] Split out tab
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -6,7 +6,7 @@ tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (sono necessarie più schede selezionate)
*[other] Split { $tabCount } Tabs
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -5,8 +5,8 @@
tab-zen-split-tabs =
.label =
{ $tabCount ->
[1] Split Tab (multiple selected tabs needed)
*[other] Split { $tabCount } Tabs
[1] Join Tab (multiple selected tabs needed)
*[other] Join { $tabCount } Tabs
}
.accesskey = S
zen-split-link =

View File

@@ -86,3 +86,7 @@
- name: browser.tabs.splitView.enabled
value: false
locked: true
# See gh-12985 for details on the following preferences
- name: browser.search.widget.new
value: true

View File

@@ -3,23 +3,6 @@
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
<menupopup id="zenCreateNewPopup">
<menu data-l10n-id="zen-panel-ui-live-folder-create" id="zen-panel-ui-live-folder-create">
<menupopup>
<menuitem
data-l10n-id="zen-live-folder-github-pull-requests"
command="cmd_zenNewLiveFolder"
image="chrome://browser/skin/zen-icons/selectable/logo-github.svg" />
<menuitem
data-l10n-id="zen-live-folder-github-issues"
command="cmd_zenNewLiveFolder"
image="chrome://browser/skin/zen-icons/selectable/logo-github.svg" />
<menuitem
data-l10n-id="zen-live-folder-type-rss"
command="cmd_zenNewLiveFolder"
image="chrome://browser/skin/zen-icons/selectable/logo-rss.svg"/>
</menupopup>
</menu>
<menuseparator/>
<menuitem data-l10n-id="zen-panel-ui-workspaces-create" command="cmd_zenOpenWorkspaceCreation" image="chrome://browser/skin/zen-icons/duplicate-tab.svg" />
<menuitem data-l10n-id="zen-panel-ui-folder-create" command="cmd_zenOpenFolderCreation" image="chrome://browser/skin/zen-icons/folder.svg" />
<menuseparator/>

View File

@@ -1067,7 +1067,7 @@ var gZenCKSSettings = {
zenMissingKeyboardShortcutL10n[conflictShortcut.getID()] ??
conflictShortcut.getL10NID();
const [group] = await document.l10n.formatValues([
const [group, conflictName] = await document.l10n.formatValues([
{ id: `${ZEN_CKS_GROUP_PREFIX}-${conflictShortcut.getGroup()}` },
{ id: shortcutL10nKey },
]);
@@ -1082,7 +1082,7 @@ var gZenCKSSettings = {
document.l10n.setAttributes(input.nextElementSibling, "zen-key-conflict", {
group: group ?? "",
shortcut: shortcut ?? "",
shortcut: conflictName ?? shortcut ?? "",
});
}
} else {

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/drag-and-drop.js b/browser/components/tabbrowser/content/drag-and-drop.js
index ced2bfd88de2d16e2c028ca3f4d9d27516363575..aaf6e82782357c819ca875f05020723600e41e6b 100644
index ced2bfd88de2d16e2c028ca3f4d9d27516363575..69b45c7dad9d294e4290de4ce878d184925e5610 100644
--- a/browser/components/tabbrowser/content/drag-and-drop.js
+++ b/browser/components/tabbrowser/content/drag-and-drop.js
@@ -35,6 +35,9 @@
@@ -277,7 +277,11 @@ index ced2bfd88de2d16e2c028ca3f4d9d27516363575..aaf6e82782357c819ca875f050207236
tab.removeAttribute("small-stack");
tab.removeAttribute("big-stack");
}
@@ -2582,7 +2585,6 @@
@@ -2578,11 +2581,9 @@
)) {
label.style.width = "";
label.style.maxWidth = "";
- label.style.height = "";
label.style.left = "";
label.style.top = "";
label.style.pointerEvents = "";

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tab.js b/browser/components/tabbrowser/content/tab.js
index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e0474669fc15c20 100644
index e4266a159a0d5c42cc294602d00b8f66131f35d5..f3e362f062063ebe08bd26cc694f2d965ccffd84 100644
--- a/browser/components/tabbrowser/content/tab.js
+++ b/browser/components/tabbrowser/content/tab.js
@@ -21,6 +21,7 @@
@@ -52,7 +52,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
return;
}
@@ -225,11 +228,23 @@
@@ -225,11 +228,25 @@
}
get visible() {
@@ -74,14 +74,16 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
+ }
+ currentParent = currentParent.group;
+ }
+ if (this.pinned && !this.hasAttribute("zen-essential") && gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs) {
+ if (this.pinned && !this.hasAttribute("zen-essential") &&
+ gZenWorkspaces.activeWorkspaceElement?.hasCollapsedPinnedTabs &&
+ !gZenWorkspaces.activeWorkspaceElement.collapsiblePins.activeTabs?.includes(this)) {
+ return false;
+ }
+ return true;
}
get hidden() {
@@ -308,7 +323,7 @@
@@ -308,7 +325,7 @@
return false;
}
@@ -90,7 +92,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
}
get lastAccessed() {
@@ -393,7 +408,18 @@
@@ -393,7 +410,18 @@
}
get group() {
@@ -110,7 +112,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
}
get splitview() {
@@ -475,6 +501,10 @@
@@ -475,6 +503,10 @@
}
}
@@ -121,7 +123,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
// If the previous target wasn't part of this tab then this is a mouseenter event.
if (!this.contains(event.relatedTarget)) {
this._mouseenter();
@@ -504,6 +534,7 @@
@@ -504,6 +536,7 @@
if (!this.contains(event.relatedTarget)) {
this._mouseleave();
}
@@ -129,7 +131,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
}
on_dragstart(event) {
@@ -538,6 +569,8 @@
@@ -538,6 +571,8 @@
this.style.MozUserFocus = "ignore";
} else if (
event.target.classList.contains("tab-close-button") ||
@@ -138,7 +140,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
event.target.classList.contains("tab-icon-overlay") ||
event.target.classList.contains("tab-audio-button")
) {
@@ -592,16 +625,21 @@
@@ -592,16 +627,21 @@
this.style.MozUserFocus = "";
}
@@ -161,7 +163,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
gBrowser.multiSelectedTabsCount > 0 &&
!event.target.classList.contains("tab-close-button") &&
!event.target.classList.contains("tab-icon-overlay") &&
@@ -613,8 +651,9 @@
@@ -613,8 +653,9 @@
}
if (
@@ -173,7 +175,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
) {
if (this.activeMediaBlocked) {
if (this.multiselected) {
@@ -632,7 +671,7 @@
@@ -632,7 +673,7 @@
return;
}
@@ -182,7 +184,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
if (this.multiselected) {
gBrowser.removeMultiSelectedTabs(
lazy.TabMetrics.userTriggeredContext(
@@ -652,6 +691,14 @@
@@ -652,6 +693,14 @@
// (see tabbrowser-tabs 'click' handler).
gBrowser.tabContainer._blockDblClick = true;
}
@@ -197,7 +199,7 @@ index e4266a159a0d5c42cc294602d00b8f66131f35d5..88c321f05dabd948d06e155f6e047466
}
on_dblclick(event) {
@@ -675,6 +722,8 @@
@@ -675,6 +724,8 @@
animate: true,
triggeringEvent: event,
});

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..d9491b680bf8839038dadc0c6ee52f81a655e998 100644
index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..be4bedce98f404325e547dd8a4e73e895b6025b0 100644
--- a/browser/components/tabbrowser/content/tabbrowser.js
+++ b/browser/components/tabbrowser/content/tabbrowser.js
@@ -413,6 +413,7 @@
@@ -186,6 +186,15 @@ index d88bc0e5570c8fd428a84fdf5af0f6bab1e2a636..d9491b680bf8839038dadc0c6ee52f81
// If focus is on the old tab, move it to the new tab.
if (activeEl == oldTab) {
newTab.focus();
@@ -1822,7 +1902,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.
- if (gURLBar.getBrowserState(newBrowser).urlbarFocused) {
+ if (gURLBar.getBrowserState(newBrowser).urlbarFocused && !gZenVerticalTabsManager._hasSetSingleToolbar) {
let selectURL = () => {
if (this._asyncTabSwitching) {
// Set _awaitingSetURI flag to suppress popup notification
@@ -2110,7 +2190,12 @@
return this._setTabLabel(aTab, aLabel);
}

View File

@@ -1,5 +1,5 @@
diff --git a/browser/components/tabbrowser/content/tabgroup.js b/browser/components/tabbrowser/content/tabgroup.js
index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938d6923f3e 100644
index 3ca119e8dc72fac652c98505211864483d98add2..b65307ee8df896488a4c51e3a25bf9ad9e1c8179 100644
--- a/browser/components/tabbrowser/content/tabgroup.js
+++ b/browser/components/tabbrowser/content/tabgroup.js
@@ -14,11 +14,11 @@
@@ -101,7 +101,13 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
resetDefaultGroupName = () => {
this.#defaultGroupName = "";
@@ -178,7 +201,9 @@
@@ -175,10 +198,15 @@
if (!this.#tabChangeObserver) {
this.#tabChangeObserver = new window.MutationObserver(mutations => {
if (!this.tabs.length) {
+ if (this.tagName === "zen-workspace-collapsible-pins") {
+ return;
+ }
this.dispatchEvent(
new CustomEvent("TabGroupRemoved", { bubbles: true })
);
@@ -111,7 +117,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
Services.obs.notifyObservers(
this,
"browser-tabgroup-removed-from-dom"
@@ -223,7 +248,10 @@
@@ -223,7 +251,10 @@
}
});
}
@@ -123,7 +129,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
}
get color() {
@@ -317,6 +345,9 @@
@@ -317,6 +348,9 @@
}
set collapsed(val) {
@@ -133,7 +139,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
if (!!val == this.collapsed) {
return;
}
@@ -403,7 +434,6 @@
@@ -403,7 +437,6 @@
tabGroupName,
})
.then(result => {
@@ -141,7 +147,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
});
}
@@ -478,13 +508,65 @@
@@ -478,13 +511,65 @@
* @returns {MozTabbrowserTab[]}
*/
get tabs() {
@@ -212,7 +218,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
}
/**
@@ -592,7 +674,6 @@
@@ -592,7 +677,6 @@
);
} else {
if (tabOrSplitView.pinned) {
@@ -220,7 +226,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
}
let tabToMove =
this.ownerGlobal === tabOrSplitView.ownerGlobal
@@ -661,7 +742,7 @@
@@ -661,7 +745,7 @@
*/
on_click(event) {
let isToggleElement =
@@ -229,7 +235,7 @@ index 3ca119e8dc72fac652c98505211864483d98add2..026b524be51170882e788a701095b938
event.target === this.#overflowCountLabel;
if (isToggleElement && event.button === 0) {
event.preventDefault();
@@ -740,5 +821,6 @@
@@ -740,5 +824,6 @@
}
}

View File

@@ -1,5 +1,5 @@
diff --git a/browser/themes/shared/urlbar-searchbar.css b/browser/themes/shared/urlbar-searchbar.css
index cbbf55f31ae5e456401172f79ddbbe41256025a4..8cab0f2809a43c0aa4249453732eb0e006c2c676 100644
index cbbf55f31ae5e456401172f79ddbbe41256025a4..dc471dfe30dedf7c4917322a5b2257a9ec9c4f90 100644
--- a/browser/themes/shared/urlbar-searchbar.css
+++ b/browser/themes/shared/urlbar-searchbar.css
@@ -10,7 +10,7 @@
@@ -25,7 +25,7 @@ index cbbf55f31ae5e456401172f79ddbbe41256025a4..8cab0f2809a43c0aa4249453732eb0e0
.urlbar[breakout][breakout-extend] {
height: auto;
+ align-items: center;
+ :root:not([zen-single-toolbar='true']) {
+ :root:not([zen-single-toolbar='true']) & {
margin-left: calc(-1 * var(--urlbar-margin-inline));
+ }
width: calc(var(--urlbar-width) + 2 * var(--urlbar-margin-inline));

View File

@@ -1,177 +0,0 @@
diff --git a/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs b/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs
--- a/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs
+++ b/toolkit/components/asyncshutdown/AsyncShutdown.sys.mjs
@@ -490,10 +490,27 @@
if (accepted) {
return () => spinner.observe();
}
return undefined;
},
+
+ /**
+ * Reset the phase after a call to _trigger().
+ * For testing purposes only.
+ */
+ get _reset() {
+ let accepted = Services.prefs.getBoolPref(
+ "toolkit.asyncshutdown.testing",
+ false
+ );
+ if (accepted) {
+ return () => {
+ spinner = new Spinner(topic);
+ };
+ }
+ return undefined;
+ },
});
gPhases.set(topic, phase);
return phase;
}
diff --git a/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs b/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs
--- a/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs
+++ b/toolkit/components/contentrelevancy/ContentRelevancyManager.sys.mjs
@@ -104,18 +104,14 @@
this._nimbusUpdateCallback = this.#onNimbusUpdate.bind(this);
// This will handle both Nimbus updates and pref changes.
lazy.NimbusFeatures.contentRelevancy.onUpdate(this._nimbusUpdateCallback);
this.#initialized = true;
- if (
- Services.startup.isInOrBeyondShutdownPhase(
- Ci.nsIAppStartup.SHUTDOWN_PHASE_APPSHUTDOWNCONFIRMED
- )
- ) {
+ if (lazy.AsyncShutdown.profileChangeTeardown.isClosed) {
// Corner case, where we're already in the shutdown phase while being constructed. In this
// case, uninitialize immediately to deregister callback handlers
- // (#https://bugzilla.mozilla.org/show_bug.cgi?id=1990569#c11)
+ // (https://bugzilla.mozilla.org/show_bug.cgi?id=1990569#c11)
this.uninit();
} else {
// If we're not in the above corner case, then register a shutdown blocker to uninitialize.
// Interrupt sooner prior to the `profile-before-change` phase to allow
// all the in-progress IOs to exit.
diff --git a/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js b/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js
--- a/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js
+++ b/toolkit/components/contentrelevancy/tests/xpcshell/test_ContentRelevancyManager.js
@@ -149,10 +149,39 @@
await TestUtils.waitForCondition(
() => ContentRelevancyManager.interrupt.calledOnce,
"The interrupt shutdown blocker should be called"
);
+ AsyncShutdown.profileChangeTeardown._reset();
+ Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
+ Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED);
+ gSandbox.restore();
+});
+
+add_task(async function test_dont_register_blocker_if_in_shutdown() {
+ // Test a corner case: the ContentRelevancyManager is initialized during shutdown.
+ //
+ // In this case it shouldn't register a shutdown blocker, because it's too late to do that.
+ // Instead, it should just immediately uninitialize itself.
+ //
+ // See https://bugzilla.mozilla.org/show_bug.cgi?id=1990569
+ ContentRelevancyManager.uninit();
+ Services.prefs.setBoolPref(PREF_CONTENT_RELEVANCY_ENABLED, true);
+ await TestUtils.waitForTick();
+
+ gSandbox.spy(ContentRelevancyManager, "interrupt");
+
+ // Simulate shutdown.
+ Services.prefs.setBoolPref("toolkit.asyncshutdown.testing", true);
+ AsyncShutdown.profileChangeTeardown._trigger();
+ ContentRelevancyManager.init();
+ Assert.ok(
+ !ContentRelevancyManager.initialized,
+ "ContentRelevancyManager should have uninitialized itself"
+ );
+
+ AsyncShutdown.profileChangeTeardown._reset();
Services.prefs.clearUserPref("toolkit.asyncshutdown.testing");
Services.prefs.clearUserPref(PREF_CONTENT_RELEVANCY_ENABLED);
gSandbox.restore();
});
diff --git a/toolkit/modules/AppServicesTracing.sys.mjs b/toolkit/modules/AppServicesTracing.sys.mjs
--- a/toolkit/modules/AppServicesTracing.sys.mjs
+++ b/toolkit/modules/AppServicesTracing.sys.mjs
@@ -9,10 +9,11 @@
*/
const lazy = {};
ChromeUtils.defineESModuleGetters(lazy, {
+ AsyncShutdown: "resource://gre/modules/AsyncShutdown.sys.mjs",
// eslint-disable-next-line mozilla/use-console-createInstance
Log: "resource://gre/modules/Log.sys.mjs",
});
import {
@@ -118,20 +119,33 @@
}
}
/** A singleton uniffi callback interface. */
class TracingEventHandler extends EventSink {
- static OBSERVER_NAME = "xpcom-will-shutdown";
-
constructor() {
super();
// Map targets to CallbackLists
this.targetCallbackLists = new Map();
// CallbackList for callbacks registered with registerMinLevelEventSink
this.minLevelCallbackList = new CallbackList();
- Services.obs.addObserver(this, TracingEventHandler.OBSERVER_NAME);
+ // Choose `profileBeforeChange` to call `#close()` and deregister our callbacks.
+ //
+ // Most other components will shutdown during the `profileChangeTeardown` phase, since that's
+ // the last opportunity to write to the profile directory. By choosing the next one, we ensure
+ // we can forward any logging that happens when those components shutdown.
+ if (lazy.AsyncShutdown.profileBeforeChange.isClosed) {
+ // Corner case, where we're already in the shutdown phase while being constructed. In this
+ // case, uninitialize immediately.
+ this.#close();
+ } else {
+ // If we're not in the above corner case, then register a shutdown blocker to uninitialize.
+ lazy.AsyncShutdown.profileBeforeChange.addBlocker(
+ "TracingEventHandler: deregister callbacks",
+ () => this.#close()
+ );
+ }
}
register(target, level, callback) {
if (this.targetCallbackLists === null) {
lazy.console.trace(
@@ -223,19 +237,17 @@
targetList.processEvent(event);
}
this.minLevelCallbackList.processEvent(event);
}
- observe(_aSubject, aTopic, _aData) {
- if (aTopic == TracingEventHandler.OBSERVER_NAME) {
- for (let target of this.targetCallbackLists.keys()) {
- unregisterEventSink(target);
- }
- unregisterMinLevelEventSink();
- this.targetCallbackLists = null;
- this.minLevelCallbackList = null;
+ #close() {
+ for (let target of this.targetCallbackLists.keys()) {
+ unregisterEventSink(target);
}
+ unregisterMinLevelEventSink();
+ this.targetCallbackLists = null;
+ this.minLevelCallbackList = null;
}
}
// the singleton.
let tracingEventHandler = new TracingEventHandler();

View File

@@ -0,0 +1,19 @@
diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp
--- a/gfx/webrender_bindings/DCLayerTree.cpp
+++ b/gfx/webrender_bindings/DCLayerTree.cpp
@@ -2097,10 +2097,14 @@
hr = mCompositionSurface->BeginDraw(&updateRect, __uuidof(ID3D11Texture2D),
(void**)getter_AddRefs(backBuffer),
&offset);
if (FAILED(hr)) {
+ LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect);
+
+ gfxCriticalNote << "DCLayerCompositionSurface::Bind failed: "
+ << gfx::hexa(hr) << " " << rect;
RenderThread::Get()->HandleWebRenderError(WebRenderError::BEGIN_DRAW);
return;
}
const auto gl = mDCLayerTree->GetGLContext();

View File

@@ -0,0 +1,43 @@
diff --git a/gfx/webrender_bindings/DCLayerTree.cpp b/gfx/webrender_bindings/DCLayerTree.cpp
--- a/gfx/webrender_bindings/DCLayerTree.cpp
+++ b/gfx/webrender_bindings/DCLayerTree.cpp
@@ -2182,18 +2182,18 @@
updatePos = {0, 0};
}
mFirstDraw = false;
+ LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect);
+ MOZ_ASSERT(!rect.IsEmpty());
hr = mCompositionSurface->BeginDraw(&updateRect, __uuidof(ID3D11Texture2D),
(void**)getter_AddRefs(backBuffer),
&offset);
if (FAILED(hr)) {
- LayoutDeviceIntRect rect = widget::WinUtils::ToIntRect(updateRect);
-
gfxCriticalNote << "DCLayerCompositionSurface::Bind failed: "
<< gfx::hexa(hr) << " " << rect;
RenderThread::Get()->HandleWebRenderError(WebRenderError::BEGIN_DRAW);
return;
}
diff --git a/gfx/wr/webrender/src/renderer/composite.rs b/gfx/wr/webrender/src/renderer/composite.rs
--- a/gfx/wr/webrender/src/renderer/composite.rs
+++ b/gfx/wr/webrender/src/renderer/composite.rs
@@ -1120,11 +1120,13 @@
// Only use supplied clear color for first content layer we encounter
let clear_color = content_clear_color.take().unwrap_or(ColorF::TRANSPARENT);
if let Some(ref mut _compositor) = self.compositor_config.layer_compositor() {
if let Some(PartialPresentMode::Single { dirty_rect }) = partial_present_mode {
- if dirty_rect.is_empty() {
+ let device_rect = DeviceRect::from_size(device_size.to_f32());
+ let clipped_dirty_rect = dirty_rect.intersection_unchecked(&device_rect);
+ if clipped_dirty_rect.is_empty() {
continue;
}
}
}

View File

@@ -0,0 +1,21 @@
diff --git a/gfx/wr/webrender/src/renderer/composite.rs b/gfx/wr/webrender/src/renderer/composite.rs
--- a/gfx/wr/webrender/src/renderer/composite.rs
+++ b/gfx/wr/webrender/src/renderer/composite.rs
@@ -974,12 +974,15 @@
.iter()
.chain(self.layer_compositor_frame_state_in_prev_frame.as_ref().unwrap().rects_without_id.iter()) {
combined_dirty_rect = combined_dirty_rect.union(&rect);
}
+ let device_rect = DeviceRect::from_size(device_size.to_f32());
+ let clipped_dirty_rect = combined_dirty_rect.intersection_unchecked(&device_rect);
+
partial_present_mode = Some(PartialPresentMode::Single {
- dirty_rect: combined_dirty_rect,
+ dirty_rect: clipped_dirty_rect,
});
} else {
partial_present_mode = None;
}

View File

@@ -2,11 +2,6 @@
// 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/.
[
{
"type": "phabricator",
"id": "D279007",
"name": "Fix MacOS Crash on Shutdown Firefox 149"
},
{
"type": "phabricator",
"id": "D284084",
@@ -40,5 +35,20 @@
// the parameter's help description with the correct one.
"application": "Application"
}
},
{
"type": "phabricator",
"id": "D291099",
"name": "gh-12979 1 Add gfxCriticalNote to DCLayerCompositionSurface"
},
{
"type": "phabricator",
"id": "D291123",
"name": "gh-12979 2 Compositor rendering performance fix"
},
{
"type": "phabricator",
"id": "D291714",
"name": "gh-12979 3 Clip dirty_rect to device_size"
}
]

View File

@@ -1,5 +1,5 @@
diff --git a/toolkit/content/widgets/arrowscrollbox.js b/toolkit/content/widgets/arrowscrollbox.js
index b80d1049bb6ae305f2ac9c4c35fe975fd508031c..be2cbdb20cb2064459b6f7bef56fd0470c3b7f40 100644
index b80d1049bb6ae305f2ac9c4c35fe975fd508031c..574149bffa49329e927c8db9db0c080eb6b87f5f 100644
--- a/toolkit/content/widgets/arrowscrollbox.js
+++ b/toolkit/content/widgets/arrowscrollbox.js
@@ -98,6 +98,7 @@
@@ -10,7 +10,19 @@ index b80d1049bb6ae305f2ac9c4c35fe975fd508031c..be2cbdb20cb2064459b6f7bef56fd047
let contentSize =
slot.getBoundingClientRect()[this.#verticalMode ? "height" : "width"];
// NOTE(emilio): This should be contentSize > scrollClientSize, but due
@@ -642,7 +643,7 @@
@@ -125,6 +126,11 @@
overflowObserver.observe(this.scrollbox);
}
+ connectedMoveCallback() {
+ // See gh-13015, define connectedMoveCallback to prevent connectedCallback
+ // from being called when using moveBefore.
+ }
+
connectedCallback() {
this.removeAttribute("overflowing");
@@ -642,7 +648,7 @@
on_wheel(event) {
// Don't consume the event if we can't scroll.

View File

@@ -46,14 +46,13 @@ class ZenStartup {
}
newContainer.appendChild(node);
}
// Fix notification deck
const deckTemplate = document.getElementById(
"tab-notification-deck-template"
);
if (deckTemplate) {
document.getElementById("zen-appcontent-wrapper").prepend(deckTemplate);
}
const deckTemplate =
document.getElementById("tab-notification-deck-template") ||
document.getElementById("tab-notification-deck");
// overlap and interaction issues with vertical tabs
document.getElementById("browser").prepend(deckTemplate);
gZenWorkspaces.init();
setTimeout(() => {
@@ -159,8 +158,13 @@ class ZenStartup {
}
#checkForWelcomePage() {
if (!Services.prefs.getBoolPref("zen.welcome-screen.seen", false)) {
Services.prefs.setBoolPref("zen.welcome-screen.seen", true);
const kWelcomeScreenSeenPref = "zen.welcome-screen.seen";
if (Services.env.get("MOZ_HEADLESS")) {
Services.prefs.setBoolPref(kWelcomeScreenSeenPref, true);
return;
}
if (!Services.prefs.getBoolPref(kWelcomeScreenSeenPref, false)) {
Services.prefs.setBoolPref(kWelcomeScreenSeenPref, true);
Services.prefs.setStringPref(
"zen.updates.last-build-id",
Services.appinfo.appBuildID

View File

@@ -999,7 +999,7 @@ window.gZenVerticalTabsManager = {
command="cmd_zenToggleTabsOnRight"
/>
`);
document.getElementById("viewToolbarsMenuSeparator").before(fragment);
document.getElementById("toolbar-context-customize").before(fragment);
},
get _topButtonsSeparatorElement() {
@@ -1014,6 +1014,7 @@ window.gZenVerticalTabsManager = {
animateItemOpen(aItem) {
if (
gReduceMotion ||
!gZenUIManager.motion ||
!aItem ||
!gZenUIManager._hasLoadedDOM ||

View File

@@ -13,35 +13,36 @@ export default function checkForZenUpdates() {
const lastVersion = Services.prefs.getStringPref(ZEN_UPDATE_PREF, "");
Services.prefs.setStringPref(ZEN_UPDATE_PREF, version);
if (
version !== lastVersion &&
!gZenUIManager.testingEnabled &&
Services.prefs.getBoolPref(ZEN_UPDATE_SHOW, true)
version === lastVersion ||
gZenUIManager.testingEnabled ||
!Services.prefs.getBoolPref(ZEN_UPDATE_SHOW, true)
) {
const updateUrl = Services.prefs.getStringPref(
"app.releaseNotesURL.prompt",
""
);
createSidebarNotification({
headingL10nId: "zen-sidebar-notification-updated-heading",
links: [
{
url: Services.urlFormatter.formatURL(
updateUrl.replace("%VERSION%", version)
),
l10nId: "zen-sidebar-notification-updated",
special: true,
icon: "chrome://browser/skin/zen-icons/heart-circle-fill.svg",
},
{
action: () => {
Services.obs.notifyObservers(window, "restart-in-safe-mode");
},
l10nId: "zen-sidebar-notification-restart-safe-mode",
icon: "chrome://browser/skin/zen-icons/security-broken.svg",
},
],
});
return;
}
const updateUrl = Services.prefs.getStringPref(
"app.releaseNotesURL.prompt",
""
);
createSidebarNotification({
headingL10nId: "zen-sidebar-notification-updated-heading",
links: [
{
url: Services.urlFormatter.formatURL(
updateUrl.replace("%VERSION%", version)
),
l10nId: "zen-sidebar-notification-updated",
special: true,
icon: "chrome://browser/skin/zen-icons/heart-circle-fill.svg",
},
{
action: () => {
Services.obs.notifyObservers(window, "restart-in-safe-mode");
},
l10nId: "zen-sidebar-notification-restart-safe-mode",
icon: "chrome://browser/skin/zen-icons/security-broken.svg",
},
],
});
}
export async function createWindowUpdateAnimation() {

View File

@@ -3,5 +3,4 @@
% file, You can obtain one at http://mozilla.org/MPL/2.0/.
color-scheme: dark;
--toolbar-color-scheme: dark;
--zen-urlbar-outline-offset: -2px;

View File

@@ -3,5 +3,4 @@
% file, You can obtain one at http://mozilla.org/MPL/2.0/.
color-scheme: light;
--toolbar-color-scheme: light;
--zen-urlbar-outline-offset: 0px;

View File

@@ -268,7 +268,7 @@
background-color: var(--zen-urlbar-background-transparent, var(--zen-urlbar-background-base)) !important;
box-shadow: 0 30px 140px -15px light-dark(rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.6)) !important;
backdrop-filter: none !important;
outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.2), rgba(255, 255, 255, 0.2)) !important;
outline: 0.5px solid light-dark(rgba(0, 0, 0, 0.3), rgba(255, 255, 255, 0.2)) !important;
outline-offset: var(--zen-urlbar-outline-offset) !important;
/* stylelint-disable-next-line media-query-no-invalid */
@@ -404,32 +404,6 @@
min-width: 26px;
}
/* Notification Stack */
.notificationbox-stack {
background: transparent;
&[notificationside="top"] {
position: fixed;
bottom: calc(var(--zen-element-separation) * 1.5);
right: calc(var(--zen-element-separation) * 1.5);
width: fit-content;
max-width: 30rem !important;
z-index: 9999;
& notification-message {
background: color-mix(in srgb, var(--zen-colors-tertiary) 70%, transparent 30%);
backdrop-filter: blur(10px);
border: 1px solid var(--arrowpanel-border-color);
border-radius: var(--zen-border-radius);
&::before {
display: none;
}
}
}
}
#nav-bar,
#zen-sidebar-top-buttons {
min-height: var(--zen-toolbar-height) !important;
@@ -512,6 +486,11 @@
margin-block: -1px !important;
}
}
& #identity-icon-box {
--urlbar-box-hover-bgcolor: transparent;
margin-inline: 2px 8px;
}
}
/* stylelint-disable-next-line media-query-no-invalid */
@@ -708,7 +687,8 @@
}
#identity-box {
margin-inline-end: 0;
margin-inline-end: 3px !important;
margin-inline-start: 2px !important;
}
}

View File

@@ -650,3 +650,36 @@
gap: 4px;
}
}
/* Notification Stack */
.notificationbox-stack {
background: transparent;
&[notificationside="top"] {
position: fixed;
bottom: calc(var(--zen-element-separation) * 1.5);
right: calc(var(--zen-element-separation) * 1.5);
:root[zen-right-side="true"] & {
right: auto;
left: calc(var(--zen-element-separation) * 1.5);
}
width: fit-content;
max-width: 30rem !important;
z-index: 9999;
& notification-message {
background: color-mix(in srgb, var(--zen-colors-tertiary) 70%, transparent 30%);
backdrop-filter: blur(10px);
border: 1px solid var(--arrowpanel-border-color);
border-radius: var(--zen-border-radius);
&::before {
display: none;
}
}
}
}

View File

@@ -247,7 +247,7 @@ window.gZenCompactModeManager = {
}
}
document.getElementById("viewToolbarsMenuSeparator").before(fragment);
document.getElementById("toolbar-context-customize").before(fragment);
this.updateContextMenu();
},
@@ -590,7 +590,7 @@ window.gZenCompactModeManager = {
if (!toggle) {
return;
}
toggle.setAttribute("checked", this.preference);
toggle.toggleAttribute("checked", this.preference);
const hideTabBar = this.canHideSidebar;
const hideToolbar = this.canHideToolbar;
@@ -600,9 +600,9 @@ window.gZenCompactModeManager = {
const sidebarItem = document.getElementById(idName + "sidebar");
const toolbarItem = document.getElementById(idName + "toolbar");
const bothItem = document.getElementById(idName + "both");
sidebarItem.setAttribute("checked", !hideBoth && hideTabBar);
toolbarItem.setAttribute("checked", !hideBoth && hideToolbar);
bothItem.setAttribute("checked", hideBoth);
sidebarItem.toggleAttribute("checked", !hideBoth && hideTabBar);
toolbarItem.toggleAttribute("checked", !hideBoth && hideToolbar);
bothItem.toggleAttribute("checked", hideBoth);
},
_removeOpenStateOnUnifiedExtensions() {

View File

@@ -70,7 +70,24 @@ class nsZenFolders extends nsZenDOMOperatedFeature {
);
document.getElementById("context_moveTabToGroup").before(contextMenuItems);
const contextMenuItemsToolbar = window.MozXULElement.parseXULToFragment(
`<menuitem id="zen-context-menu-new-folder-toolbar" data-l10n-id="zen-toolbar-context-new-folder"/>`
`<menuitem id="zen-context-menu-new-folder-toolbar" data-l10n-id="zen-toolbar-context-new-folder"/>
<menuseparator />
<menu data-l10n-id="zen-panel-ui-live-folder-create" id="zen-panel-ui-live-folder-create">
<menupopup>
<menuitem
data-l10n-id="zen-live-folder-github-pull-requests"
command="cmd_zenNewLiveFolder"
image="chrome://browser/skin/zen-icons/selectable/logo-github.svg" />
<menuitem
data-l10n-id="zen-live-folder-github-issues"
command="cmd_zenNewLiveFolder"
image="chrome://browser/skin/zen-icons/selectable/logo-github.svg" />
<menuitem
data-l10n-id="zen-live-folder-type-rss"
command="cmd_zenNewLiveFolder"
image="chrome://browser/skin/zen-icons/selectable/logo-rss.svg"/>
</menupopup>
</menu>`
);
document
.getElementById("toolbar-context-openANewTab")

View File

@@ -507,17 +507,6 @@ class nsZenGlanceManager extends nsZenDOMOperatedFeature {
this.#glances.get(this.#currentGlanceID).elementImageData =
data.elementData;
gZenUIManager.motion.animate(
imageDataElement,
{
opacity: [1, 0],
},
{
duration: this.#GLANCE_ANIMATION_DURATION / 2,
easing: "easeInOut",
}
);
return imageDataElement;
}

View File

@@ -170,6 +170,7 @@
position: absolute;
pointer-events: none;
width: 100%;
height: 100%;
max-width: 100%;
max-height: 100%;
z-index: 0;
@@ -179,6 +180,10 @@
translate: -50% -50%;
background: rgba(255, 255, 255, 0.1);
display: flex;
align-items: center;
justify-content: center;
& image {
width: 100%;
max-width: 100%;

View File

@@ -10,8 +10,11 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
constructor({ id, state, manager }) {
super({ id, state, manager });
this.state.url = "https://github.com/issues/assigned";
this.state.type = state.type;
this.state.url =
this.state.type === "pull-requests"
? "https://github.com/pulls"
: "https://github.com/issues/assigned";
this.state.options = state.options ?? {};
this.state.repos = new Set(state.repos ?? []);
@@ -29,22 +32,106 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
return "zen-live-folder-github-no-filter";
}
const searchParams = this.#buildSearchOptions();
const url = `${this.state.url}?${searchParams}`;
const queries = this.#buildSearchOptions();
const requests = await Promise.all(
queries.map(query => {
const url = new URL(this.state.url);
url.searchParams.set("q", query);
const { text, status } = await this.fetch(url);
if (this.state.type === "pull-requests") {
return this.parsePullRequests(url.href);
}
// Assume no auth
if (status === 404) {
return "zen-live-folder-github-no-auth";
return this.parseIssues(url.href);
})
);
const combinedItems = new Map();
const combinedActiveRepos = new Set();
for (const { status, items, activeRepos } of requests) {
// Assume no auth
if (status === 404) {
return "zen-live-folder-github-no-auth";
}
if (items) {
items.forEach(item => combinedItems.set(item.id, item));
}
if (activeRepos) {
activeRepos.forEach(repo => combinedActiveRepos.add(repo));
}
}
this.state.repos = combinedActiveRepos;
return Array.from(combinedItems.values());
} catch (error) {
console.error("Error fetching or parsing GitHub issues:", error);
return "zen-live-folder-failed-fetch";
}
}
async parsePullRequests(url) {
const { text, status } = await this.fetch(url);
try {
const document = new DOMParser().parseFromString(text, "text/html");
const issues = document.querySelectorAll("div[id^=issue_]");
const items = [];
const activeRepos = [];
if (issues.length) {
const authors = document.querySelectorAll(".opened-by a");
const titles = document.querySelectorAll("a[id^=issue_]");
for (let i = 0; i < issues.length; i++) {
const author = authors[i].textContent;
const title = titles[i].textContent;
const repo = titles[i].previousElementSibling.textContent.trim();
if (repo) {
activeRepos.push(repo);
}
const idMatch = authors[i].parentElement.textContent
.match(/#[0-9]+/)
.shift();
items.push({
title,
subtitle: author,
icon: "chrome://browser/content/zen-images/favicons/github.svg",
url: new URL(titles[i].href, this.state.url),
id: `${repo}${idMatch}`,
});
}
}
return {
status,
items,
activeRepos,
};
} catch (err) {
console.error("Failed to parse Github pull requests", err);
return {
status,
};
}
}
async parseIssues(url) {
const { text, status } = await this.fetch(url);
try {
const document = new DOMParser().parseFromString(text, "text/html");
const issues = document.querySelectorAll(
"div[class^=IssueItem-module__defaultRepoContainer]"
);
const items = [];
const activeRepos = new Set();
const activeRepos = [];
if (issues.length) {
const authors = document.querySelectorAll(
@@ -65,7 +152,7 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
const repo = rawRepo.textContent?.trim();
if (repo) {
activeRepos.add(repo);
activeRepos.push(repo);
}
const numberMatch = rawNumber?.textContent?.match(/[0-9]+/);
@@ -81,76 +168,67 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
}
}
this.state.repos = activeRepos;
return {
status,
return items;
} catch (error) {
console.error("Error fetching or parsing GitHub issues:", error);
return "zen-live-folder-failed-fetch";
items,
activeRepos,
};
} catch (err) {
console.error("Failed to parse Github Issues", err);
return {
status,
};
}
}
#buildSearchOptions() {
let searchParams = new URLSearchParams();
const baseQuery = [
this.state.type === "pull-requests" ? "is:pr" : "is:issue",
"state:open",
"sort:updated-desc",
];
const options = [
{
value: "state:open",
enabled: true,
value: "author:@me",
enabled: this.state.options.authorMe ?? false,
},
{
value: "sort:updated-desc",
enabled: true,
value: "assignee:@me",
enabled: this.state.options.assignedMe ?? true,
},
{
value: "review-requested:@me",
enabled: this.state.options.reviewRequested ?? false,
},
[
{
value: "is:pr",
enabled: this.state.type === "pull-requests",
},
{
value: "is:issue",
enabled: this.state.type === "issues",
},
],
[
{
value: "author:@me",
enabled: this.state.options.authorMe ?? false,
},
{
value: "assignee:@me",
enabled: this.state.options.assignedMe ?? true,
},
{
value: "review-requested:@me",
enabled: this.state.options.reviewRequested ?? false,
},
],
];
const excluded = this.state.options.repoExcludes;
for (const repo of excluded) {
if (repo && repo.trim()) {
options.push({ value: `-repo:${repo.trim()}`, enabled: true });
baseQuery.push(`-repo:${repo.trim()}`);
}
}
let outputString = "";
const queries = [];
for (const option of options) {
if (Array.isArray(option)) {
const enabledOptions = option.filter(x => x.enabled).map(x => x.value);
if (enabledOptions.length) {
outputString += ` (${enabledOptions.join(" OR ")}) `;
}
continue;
}
if (option.enabled) {
outputString += ` ${option.value} `;
queries.push(option.value);
}
}
searchParams.set("q", outputString.trim().replace(/ +(?= )/g, ""));
return searchParams.toString();
const searchParams = [];
if (this.state.type === "pull-requests") {
for (const query of queries) {
searchParams.push(`${baseQuery.join(" ")} ${query}`);
}
return searchParams;
}
// type: issues
return [`${baseQuery.join(" ")} ${queries.join(" OR ")}`];
}
get options() {
@@ -209,7 +287,7 @@ export class nsGithubLiveFolderProvider extends nsZenLiveFolderProvider {
super.onOptionTrigger(option);
const key = option.getAttribute("option-key");
const checked = option.getAttribute("checked") === "true";
const checked = option.hasAttribute("checked");
if (!this.options.some(x => x.key === key)) {
return;
}

View File

@@ -151,10 +151,11 @@ export class nsZenSessionManager {
);
const db = await PlacesUtils.promiseDBConnection();
let data = {};
let rows = await db.execute(
"SELECT * FROM zen_workspaces ORDER BY created_at ASC"
);
let rows = [];
try {
rows = await db.execute(
"SELECT * FROM zen_workspaces ORDER BY created_at ASC"
);
data.spaces = rows.map(row => ({
uuid: row.getResultByName("uuid"),
name: row.getResultByName("name"),

View File

@@ -790,7 +790,10 @@ class nsZenWindowSync {
// We *shouldn't* care about this scenario since the remoteness should be
// the same anyways.
if (!aOurTab.linkedBrowser || !aOtherTab.linkedBrowser) {
return true;
this.log(
`Cannot swap browsers between tabs ${aOurTab.id} and ${aOtherTab.id} because one of them doesn't have a linked browser`
);
return false;
}
// Can't swap between chrome and content processes.
if (

View File

@@ -1753,6 +1753,10 @@ export class nsZenThemePicker extends nsZenMultiWindowFeature {
"--toolbox-textcolor",
`rgba(${textColor[0]}, ${textColor[1]}, ${textColor[2]}, ${textColor[3]})`
);
docElement.style.setProperty(
"--toolbar-color-scheme",
isDarkMode ? "dark" : "light"
);
}
if (!skipUpdate) {

View File

@@ -10,9 +10,6 @@ window.ZenWorkspaceBookmarksStorage = {
ChromeUtils.defineESModuleGetters(this.lazy, {
PlacesUtils: "resource://gre/modules/PlacesUtils.sys.mjs",
});
if (!window.gZenWorkspaces) {
return;
}
this.promiseInitialized = new Promise(resolve => {
this._resolveInitialized = resolve;
});

View File

@@ -199,25 +199,27 @@ class nsZenWorkspaceCreation extends MozXULElement {
this.style.visibility = "visible";
gZenCompactModeManager.getAndApplySidebarWidth();
this.resolveInitialized();
gZenUIManager.motion
.animate(
this.elementsToAnimate,
{
y: [20, 0],
opacity: [0, 1],
filter: ["blur(2px)", "blur(0)"],
},
{
duration: 0.6,
type: "spring",
bounce: 0,
delay: gZenUIManager.motion.stagger(0.05, { startDelay: 0.2 }),
}
)
.then(() => {
this.inputName.focus();
gZenWorkspaces.workspaceElement(this.workspaceId).hidden = false;
});
let animation = gZenUIManager.motion.animate(
this.elementsToAnimate,
{
y: [20, 0],
opacity: [0, 1],
filter: ["blur(2px)", "blur(0)"],
},
{
duration: 0.6,
type: "spring",
bounce: 0,
delay: gZenUIManager.motion.stagger(0.05, { startDelay: 0.2 }),
}
);
if (gReduceMotion) {
animation.complete();
}
animation.then(() => {
this.inputName.focus();
gZenWorkspaces.workspaceElement(this.workspaceId).hidden = false;
});
});
}
@@ -303,20 +305,22 @@ class nsZenWorkspaceCreation extends MozXULElement {
}
async #cleanup() {
await gZenUIManager.motion.animate(
this.elementsToAnimate.reverse(),
{
y: [0, 20],
opacity: [1, 0],
filter: ["blur(0)", "blur(2px)"],
},
{
duration: 0.4,
type: "spring",
bounce: 0,
delay: gZenUIManager.motion.stagger(0.05),
}
);
if (!gReduceMotion) {
await gZenUIManager.motion.animate(
this.elementsToAnimate.reverse(),
{
y: [0, 20],
opacity: [1, 0],
filter: ["blur(0)", "blur(2px)"],
},
{
duration: 0.4,
type: "spring",
bounce: 0,
delay: gZenUIManager.motion.stagger(0.05),
}
);
}
document.getElementById("zen-sidebar-splitter").style.pointerEvents = "";

View File

@@ -44,6 +44,10 @@ class nsZenWorkspaces {
_workspaceCache = [];
#lastScrollTime = 0;
#currentSpaceSwitchContext = {
promise: null,
animations: [],
};
bookmarkMenus = [
"PlacesToolbar",
@@ -777,7 +781,7 @@ class nsZenWorkspaces {
if (
!this.privateWindowOrDisabled &&
spacesFromStore.length === 0 &&
lazy.ZenSessionStore._migrationData
lazy.ZenSessionStore._migrationData?.spaces
) {
spacesFromStore.push(...lazy.ZenSessionStore._migrationData.spaces);
}
@@ -1631,9 +1635,18 @@ class nsZenWorkspaces {
}
async changeWorkspace(workspace, ...args) {
if (!this.workspaceEnabled || this.#inChangingWorkspace) {
if (!this.workspaceEnabled) {
return;
}
this.#currentSpaceSwitchContext.animations.forEach(animation => {
animation.complete();
});
await this.#currentSpaceSwitchContext.promise;
let { resolve, promise } = Promise.withResolvers();
this.#currentSpaceSwitchContext = {
promise,
animations: [],
};
this.#inChangingWorkspace = true;
try {
this.log("Changing workspace to", workspace?.uuid);
@@ -1642,10 +1655,11 @@ class nsZenWorkspaces {
console.error("gZenWorkspaces: Error changing workspace", e);
}
this.#inChangingWorkspace = false;
resolve();
}
_cancelSwipeAnimation() {
this._animateTabs(this.getActiveWorkspaceFromCache(), true);
this.#animateTabs(this.getActiveWorkspaceFromCache(), true);
}
async #performWorkspaceChange(
@@ -1923,7 +1937,7 @@ class nsZenWorkspaces {
}
/* eslint-disable complexity */
async _animateTabs(
async #animateTabs(
newWorkspace,
shouldAnimate,
tabToSelect = null,
@@ -2253,12 +2267,14 @@ class nsZenWorkspaces {
let promiseTimeout = new Promise(resolve =>
setTimeout(resolve, kGlobalAnimationDuration * 1000 + 50)
);
this.#currentSpaceSwitchContext.animations = animations;
// See issue https://github.com/zen-browser/desktop/issues/9334, we need to add
// some sort of timeout to the animation promise, just in case it gets stuck.
// We are doing a race between the timeout and the animations finishing.
await Promise.race([Promise.all(animations), promiseTimeout]).catch(
console.error
);
this.#currentSpaceSwitchContext.animations = [];
document.documentElement.removeAttribute("animating-background");
if (shouldAnimate) {
for (const cloned of clonedEssentials) {
@@ -2420,7 +2436,7 @@ class nsZenWorkspaces {
gZenUIManager.tabsWrapper.scrollbarWidth = "none";
this.workspaceIcons.activeIndex = workspace.uuid;
await this._animateTabs(
await this.#animateTabs(
workspace,
!onInit && !this._animatingChange,
tabToSelect,

View File

@@ -1164,12 +1164,16 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
insetUpdateContextMenuItems() {
const contentAreaContextMenu = document.getElementById("tabContextMenu");
contentAreaContextMenu.addEventListener("popupshowing", () => {
let isExistingSplitView = gBrowser.selectedTabs.some(tab =>
let contextTab = TabContextMenu.contextTab;
let selectedTabs = contextTab.multiselected
? gBrowser.selectedTabs
: [contextTab];
let isExistingSplitView = selectedTabs.every(tab =>
tab.group?.hasAttribute("split-view-group")
);
const splitTabCommand = document.getElementById("context_zenSplitTabs");
document.l10n.setAttributes(splitTabCommand, "tab-zen-split-tabs", {
tabCount: isExistingSplitView ? -1 : gBrowser.selectedTabs.length,
tabCount: isExistingSplitView ? -1 : selectedTabs.length,
});
if (isExistingSplitView) {
splitTabCommand.removeAttribute("hidden");
@@ -1237,9 +1241,14 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
* Splits the selected tabs.
*/
contextSplitTabs() {
const tabs = window.gBrowser.selectedTabs;
// If any is already in a split view, we unsplit them first
if (tabs.some(tab => tab.splitView)) {
let tabs;
if (TabContextMenu.contextTab.multiselected) {
tabs = gBrowser.selectedTabs;
} else {
tabs = [TabContextMenu.contextTab];
}
// If all are already in a split view, we unsplit them first.
if (tabs.every(tab => tab.splitView)) {
for (const tab of tabs) {
if (tab.splitView) {
this.removeTabFromGroup(tab);
@@ -1263,7 +1272,7 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature {
return false;
}
for (const tab of window.gBrowser.selectedTabs) {
if (tab.splitView || tab.hasAttribute("zen-empty-tab")) {
if (tab.hasAttribute("zen-empty-tab")) {
return false;
}
}

View File

@@ -427,6 +427,11 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
state.image = tab.zenStaticIcon || initialState.image;
state.index = 0;
// See gh-13024, we need to remove the scroll position from the state,
// otherwise when we reset the pinned tab, it will scroll to the previous position
// which can be confusing for the user, especially if they have a long page.
delete state.scroll;
SessionStore.setTabState(tab, state);
this.resetPinChangedUrl(tab);
}
@@ -673,14 +678,15 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
return tab;
}
let workspaceId;
if (
!tab.hasAttribute("zen-essential") &&
tab.getAttribute("zen-workspace-id") != gZenWorkspaces.activeWorkspace
) {
workspaceId = gZenWorkspaces.activeWorkspace;
}
if (tab.ownerGlobal !== window) {
fromDifferentWindow = true;
if (
!tab.hasAttribute("zen-essential") &&
tab.getAttribute("zen-workspace-id") !=
gZenWorkspaces.activeWorkspace
) {
workspaceId = gZenWorkspaces.activeWorkspace;
if (workspaceId) {
tab.ownerGlobal.gBrowser.selectedTab =
tab.ownerGlobal.gBrowser._findTabToBlurTo(tab, movingTabs);
tab.ownerGlobal.gZenWorkspaces.moveTabToWorkspace(tab, workspaceId);
@@ -695,9 +701,9 @@ class nsZenPinnedTabManager extends nsZenDOMOperatedFeature {
if (tab) {
++newIndex;
}
if (workspaceId) {
tab.setAttribute("zen-workspace-id", workspaceId);
}
}
if (workspaceId) {
tab.setAttribute("zen-workspace-id", workspaceId);
}
return tab;
});

View File

@@ -310,11 +310,13 @@
}
& .tabbrowser-tab {
&,
& .tab-content > image {
transition:
scale 0.2s ease,
var(--zen-tabbox-element-indent-transition);
@media not (prefers-reduced-motion: reduce) {
&,
& .tab-content > image {
transition:
scale 0.2s ease,
var(--zen-tabbox-element-indent-transition);
}
}
:root[zen-sidebar-expanded="true"] &:not([zen-glance-tab]) {

View File

@@ -20,7 +20,7 @@
"brandShortName": "Zen",
"brandFullName": "Zen Browser",
"release": {
"displayVersion": "1.19.4b",
"displayVersion": "1.19.6b",
"github": {
"repo": "zen-browser/desktop"
},