commit 5d796ce5231b43eb6c06778a3e6073c7d67c53aa
parent d6720705613bfbd71ecbe41201619e93782a7015
Author: Kelly Cochrane <kcochrane@mozilla.com>
Date: Thu, 11 Dec 2025 13:57:23 +0000
Bug 1997878 - Preserve width of backgrounded split view panels to prevent issues with PiP when switching tabs r=desktop-theme-reviewers,tabbrowser-reviewers,jules,jsudiaman,emilio
Differential Revision: https://phabricator.services.mozilla.com/D275630
Diffstat:
7 files changed, 53 insertions(+), 40 deletions(-)
diff --git a/browser/components/tabbrowser/content/tabbrowser.js b/browser/components/tabbrowser/content/tabbrowser.js
@@ -3297,6 +3297,19 @@
}
/**
+ * Toggle split view active attribute
+ *
+ * @param {boolean} isActive
+ * @param {MozTabbrowserTab[]} tabs
+ */
+ setIsSplitViewActive(isActive, tabs) {
+ for (const tab of tabs) {
+ this.tabpanels.setSplitViewPanelActive(isActive, tab.linkedPanel);
+ }
+ this.tabpanels.isSplitViewActive = gBrowser.selectedTab.splitview;
+ }
+
+ /**
* Ensures the split view footer exists for the given tab.
*
* @param {MozTabbrowserTab} tab
diff --git a/browser/components/tabbrowser/content/tabsplitview.js b/browser/components/tabbrowser/content/tabsplitview.js
@@ -39,9 +39,6 @@
/** @type {MozTabbrowserTab[]} */
#tabs = [];
- /** @type {boolean} */
- #activated = false;
-
/**
* @returns {boolean}
*/
@@ -147,26 +144,26 @@
/**
* Show all Split View tabs in the content area.
*/
- #activate() {
+ #activate(skipShowPanels = false) {
updateUrlbarButton.arm();
- if (this.#activated) {
- return;
+ if (!skipShowPanels) {
+ gBrowser.showSplitViewPanels(this.#tabs);
}
- gBrowser.showSplitViewPanels(this.#tabs);
this.container.dispatchEvent(
new CustomEvent("TabSplitViewActivate", {
detail: { tabs: this.#tabs, splitview: this },
bubbles: true,
})
);
- this.#activated = true;
}
/**
* Remove Split View tabs from the content area.
*/
- #deactivate() {
- gBrowser.hideSplitViewPanels(this.#tabs);
+ #deactivate(skipHidePanels = false) {
+ if (!skipHidePanels) {
+ gBrowser.hideSplitViewPanels(this.#tabs);
+ }
updateUrlbarButton.arm();
this.container.dispatchEvent(
new CustomEvent("TabSplitViewDeactivate", {
@@ -174,7 +171,6 @@
bubbles: true,
})
);
- this.#activated = false;
}
/**
@@ -202,6 +198,7 @@
}
if (this.hasActiveTab) {
this.#activate();
+ gBrowser.setIsSplitViewActive(true, this.#tabs);
}
}
@@ -210,6 +207,7 @@
*/
unsplitTabs() {
gBrowser.unsplitTabs(this);
+ gBrowser.setIsSplitViewActive(false, this.#tabs);
}
/**
@@ -244,10 +242,11 @@
*/
on_TabSelect(event) {
this.hasActiveTab = event.target.splitview === this;
+ gBrowser.setIsSplitViewActive(this.hasActiveTab, this.#tabs);
if (this.hasActiveTab) {
- this.#activate();
+ this.#activate(true);
} else {
- this.#deactivate();
+ this.#deactivate(true);
}
}
}
diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview.js b/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview.js
@@ -28,19 +28,8 @@ async function checkSplitViewPanelVisible(tab, isVisible) {
await BrowserTestUtils.waitForMutationCondition(
panel,
{ attributes: true },
- () => panel.classList.contains("split-view-panel") == isVisible
+ () => panel.classList.contains("split-view-panel-active") == isVisible
);
- if (isVisible) {
- Assert.ok(
- gBrowser.splitViewBrowsers.includes(tab.linkedBrowser),
- "Split view panel is active."
- );
- } else {
- Assert.ok(
- !gBrowser.splitViewBrowsers.includes(tab.linkedBrowser),
- "Split view panel is inactive."
- );
- }
}
function dragSplitter(deltaX, splitter) {
diff --git a/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview_footer.js b/browser/components/tabbrowser/test/browser/tabs/browser_tab_splitview_footer.js
@@ -29,12 +29,18 @@ async function setupSplitView() {
info("Add tabs into an active split view.");
await BrowserTestUtils.switchTab(gBrowser, tabs[0]);
const splitView = gBrowser.addTabSplitView(tabs);
+ const tabpanels = document.getElementById("tabbrowser-tabpanels");
+ await BrowserTestUtils.waitForMutationCondition(
+ tabpanels,
+ { attributes: true },
+ () => tabpanels.hasAttribute("splitview")
+ );
for (const tab of tabs) {
const tabPanel = document.getElementById(tab.linkedPanel);
await BrowserTestUtils.waitForMutationCondition(
tabPanel,
{ attributes: true },
- () => tabPanel.classList.contains("split-view-panel")
+ () => tabPanel.classList.contains("split-view-panel-active")
);
}
diff --git a/browser/themes/shared/tabbrowser/content-area.css b/browser/themes/shared/tabbrowser/content-area.css
@@ -156,16 +156,21 @@
-moz-user-focus: none !important;
}
- &[splitview] {
+ .split-view-panel {
--panel-min-width: 140px;
+ min-width: var(--panel-min-width);
+ max-width: calc(100% - var(--panel-min-width));
+ width: 49.4%;
+ }
- .split-view-panel {
- position: relative;
- flex: 1;
- min-width: var(--panel-min-width);
- max-width: calc(100% - var(--panel-min-width));
+ &[splitview] {
+ .split-view-panel.split-view-panel-active {
margin: var(--space-xsmall);
+ flex: 1;
+ position: relative;
+ width: unset;
}
+
/* Ensure any dialogs are clipped in an inactive/not-selected panel. */
:root:not([inDOMFullscreen]) & > .split-view-panel:not(.deck-selected) {
overflow: clip;
diff --git a/toolkit/content/widgets/tabbox.js b/toolkit/content/widgets/tabbox.js
@@ -367,10 +367,6 @@
}
set splitViewPanels(newPanels) {
- const oldPanels = this.#splitViewPanels;
- for (const panel of oldPanels) {
- this.removePanelFromSplitView(panel, false);
- }
for (const [i, panel] of newPanels.entries()) {
const panelEl = document.getElementById(panel);
panelEl?.classList.add("split-view-panel");
@@ -381,7 +377,7 @@
}
}
this.#splitViewPanels = newPanels;
- this.#isSplitViewActive = !!newPanels.length;
+ this.isSplitViewActive = !!newPanels.length;
}
get splitViewPanels() {
@@ -409,10 +405,10 @@
this.#splitViewPanels.splice(index, 1);
}
}
- this.#isSplitViewActive = !!this.#splitViewPanels.length;
+ this.isSplitViewActive = !!this.#splitViewPanels.length;
}
- set #isSplitViewActive(isActive) {
+ set isSplitViewActive(isActive) {
this.toggleAttribute("splitview", isActive);
this.splitViewSplitter.hidden = !isActive;
if (isActive) {
@@ -421,6 +417,11 @@
firstPanel?.after(this.#splitViewSplitter);
}
}
+
+ setSplitViewPanelActive(isActive, panel) {
+ const panelEl = document.getElementById(panel);
+ panelEl?.classList.toggle("split-view-panel-active", isActive);
+ }
}
MozXULElement.implementCustomInterface(MozTabpanels, [
diff --git a/toolkit/content/xul.css b/toolkit/content/xul.css
@@ -461,7 +461,7 @@ deck > *|*:not(:-moz-native-anonymous) {
}
tabpanels > .deck-selected,
-tabpanels > .split-view-panel,
+tabpanels > .split-view-panel-active,
tabpanels > .split-view-splitter,
deck > .deck-selected {
-moz-subtree-hidden-only-visually: 0;