From 6fd8dc151409cfa2825c990c907dc7bc770e4b60 Mon Sep 17 00:00:00 2001 From: Mauro Balades Date: Sat, 18 May 2024 01:41:41 +0200 Subject: [PATCH] Started working on split views! --- src/browser/app/profile/zen-browser.js | 3 + src/browser/base/content/ZenViewSplitter.mjs | 94 +++++++++++-------- src/browser/base/content/tabbrowser-js.patch | 13 +++ .../modules/AsyncTabSwitcher-sys-mjs.patch | 68 ++++++++++++++ src/browser/themes/shared/zen-decks.css | 22 +++-- src/dom/ipc/BrowserHost-cpp.patch | 13 +++ 6 files changed, 167 insertions(+), 46 deletions(-) create mode 100644 src/browser/base/content/tabbrowser-js.patch create mode 100644 src/browser/modules/AsyncTabSwitcher-sys-mjs.patch create mode 100644 src/dom/ipc/BrowserHost-cpp.patch diff --git a/src/browser/app/profile/zen-browser.js b/src/browser/app/profile/zen-browser.js index 068045de4..25af5d149 100644 --- a/src/browser/app/profile/zen-browser.js +++ b/src/browser/app/profile/zen-browser.js @@ -141,3 +141,6 @@ pref('dom.security.sanitizer.enabled', true); pref('zen.sidebar.data', "{\"data\":\n {\"p1\":{\n \"url\":\"https://www.wikipedia.org/\"\n },\n\"p2\":{\n \"url\":\"https://m.twitter.com/\",\n\"ua\": true\n },\n\"p3\": {\n \"url\": \"https://www.youtube.com/\",\n\"ua\": true\n},\n\"p4\": {\n \"url\": \"https://translate.google.com/\",\n\"ua\": true\n},\n\"p5\": {\n \"url\": \"https://todoist.com/\",\n\"ua\": true\n}},\n\"index\":[\"p1\",\"p2\",\"p3\",\"p4\",\"p5\"]}"); pref('zen.sidebar.enabled', true); pref('zen.sidebar.floating', true); + +// Zen Split View +pref('zen.splitView.working', false); diff --git a/src/browser/base/content/ZenViewSplitter.mjs b/src/browser/base/content/ZenViewSplitter.mjs index d29fbd411..4d45357c5 100644 --- a/src/browser/base/content/ZenViewSplitter.mjs +++ b/src/browser/base/content/ZenViewSplitter.mjs @@ -3,7 +3,6 @@ var gZenViewSplitter = { /** * [ * { - * view: , * tabs: [ * tab1, * tab2, @@ -16,19 +15,15 @@ var gZenViewSplitter = { currentView: -1, init() { - return; + Services.prefs.setBoolPref("zen.splitView.working", false); window.addEventListener("TabClose", this); - window.addEventListener("TabChange", this); + console.log("ZenViewSplitter initialized"); }, handleEvent(event) { switch (event.type) { case "TabClose": this.onTabClose(event); - break; - case "TabChange": - this.onTabChange(event); - break; } }, @@ -54,62 +49,85 @@ var gZenViewSplitter = { this._showSplitView(tab); }, - onTabChange(event) { - const tab = event.target; - this._showSplitView(tab); + onLocationChange(browser) { + if (!Services.prefs.getBoolPref("zen.splitView.working")) { + return; + } + let tab = gBrowser.getTabForBrowser(browser); + if (!tab) { + return; + } + if (tab._zenSplitted) { + this._showSplitView(tab); + } }, splitTabs(tabs) { if (tabs.length < 2) { return; } - let gridElement = document.createElement("div"); - gridElement.classList.add("zen-deck"); - tabs.forEach((tab) => { - let container = tab.linkedBrowser.closest(".browserContainer"); - gridElement.appendChild(container); - }); - this.tabBrowserPanel.appendChild(gridElement); this._data.push({ tabs, - element: gridElement, }); this._showSplitView(tabs[0]); }, _showSplitView(tab) { - if (this.currentView !== -1) { - this._data[this.currentView].element.classList.remove("deck-selected"); + const splitData = this._data.find((group) => group.tabs.includes(tab)); + function modifyDecks(tabs, add) { + for (const tab of tabs) { + if (tab.linkedBrowser.docShellIsActive !== add) { + tab.linkedBrowser.docShellIsActive = add; + } + let browser = tab.linkedBrowser.closest(".browserSidebarContainer"); + if (add) { + browser.classList.add("deck-selected"); + continue; + } + browser.classList.remove("deck-selected"); + } + setTimeout((() => { + modifyDecks(tabs, add); + }).bind(tabs, add), 300); + } + const handleClick = (tab) => { + return ((event) => { + gBrowser.selectedTab = tab; + }) + }; + if (!splitData) { + if (this.currentView < 0) { + return; + } for (const tab of this._data[this.currentView].tabs) { tab._zenSplitted = false; let container = tab.linkedBrowser.closest(".browserSidebarContainer"); + container.removeAttribute("zen-split-active"); console.assert(container, "No container found for tab"); - container.classList.remove("deck-selected"); container.removeAttribute("zen-split"); + container.removeEventListener("click", handleClick(tab)); } - } - const splitData = this._data.find((group) => group.tabs.includes(tab)); - console.log(splitData) - if (!splitData) { + this.tabBrowserPanel.removeAttribute("zen-split-view"); + Services.prefs.setBoolPref("zen.splitView.working", false); + modifyDecks(this._data[this.currentView].tabs, false); + this.currentView = -1; return; } + this.tabBrowserPanel.setAttribute("zen-split-view", "true"); + Services.prefs.setBoolPref("zen.splitView.working", true); this.currentView = this._data.indexOf(splitData); - splitData.element.classList.add("deck-selected"); - for (const tab of splitData.tabs) { - tab._zenSplitted = true; - let container = tab.linkedBrowser.closest(".browserSidebarContainer"); + for (const _tab of splitData.tabs) { + _tab._zenSplitted = true; + let container = _tab.linkedBrowser.closest(".browserSidebarContainer"); + container.removeAttribute("zen-split-active"); + if (_tab == tab) { + container.setAttribute("zen-split-active", "true"); + } + container.addEventListener("click", handleClick(_tab)); console.assert(container, "No container found for tab"); - container.classList.add("deck-selected"); container.setAttribute("zen-split", "true"); } - if (splitData.tabs.length < 2) { - let tab = splitData.tabs[0]; - tab._zenSplitted = false; - let container = tab.linkedBrowser.closest(".browserSidebarContainer"); - console.assert(container, "No container found for tab"); - this.tabBrowserPanel.appendChild(container); - splitData.element.remove(); - } + modifyDecks(splitData.tabs, true); }, }; diff --git a/src/browser/base/content/tabbrowser-js.patch b/src/browser/base/content/tabbrowser-js.patch new file mode 100644 index 000000000..9a927761e --- /dev/null +++ b/src/browser/base/content/tabbrowser-js.patch @@ -0,0 +1,13 @@ +diff --git a/browser/base/content/tabbrowser.js b/browser/base/content/tabbrowser.js +index 3bca0b6d30468dc3a755219723f673ec80dfce6e..6dd39545115f57ab2aedb9f8aad79ee35466a4c7 100644 +--- a/browser/base/content/tabbrowser.js ++++ b/browser/base/content/tabbrowser.js +@@ -1349,6 +1349,8 @@ + if (!aForceUpdate) { + TelemetryStopwatch.finish("FX_TAB_SWITCH_UPDATE_MS"); + } ++ ++ gZenViewSplitter.onLocationChange(newBrowser); + }, + + _adjustFocusBeforeTabSwitch(oldTab, newTab) { diff --git a/src/browser/modules/AsyncTabSwitcher-sys-mjs.patch b/src/browser/modules/AsyncTabSwitcher-sys-mjs.patch new file mode 100644 index 000000000..e875e5d16 --- /dev/null +++ b/src/browser/modules/AsyncTabSwitcher-sys-mjs.patch @@ -0,0 +1,68 @@ +diff --git a/browser/modules/AsyncTabSwitcher.sys.mjs b/browser/modules/AsyncTabSwitcher.sys.mjs +index 9f4aa535e07adab496788165f4089be6732b1444..7b7955c0d1f2f3277cb750652458649d181e90e5 100644 +--- a/browser/modules/AsyncTabSwitcher.sys.mjs ++++ b/browser/modules/AsyncTabSwitcher.sys.mjs +@@ -39,6 +39,10 @@ XPCOMUtils.defineLazyPreferenceGetter( + 300 + ); + ++function zenSplitViewIsEnabled() { ++ return Services.prefs.getBoolPref("zen.splitView.working", false); ++} ++ + /** + * The tab switcher is responsible for asynchronously switching + * tabs in e10s. It waits until the new tab is ready (i.e., the +@@ -279,7 +283,7 @@ export class AsyncTabSwitcher { + browser.docShellIsActive = true; + } + +- if (remoteTab) { ++ if (remoteTab && !zenSplitViewIsEnabled()) { + browser.renderLayers = true; + remoteTab.priorityHint = true; + } +@@ -291,7 +295,7 @@ export class AsyncTabSwitcher { + // Setting the docShell to be inactive will also cause it + // to stop rendering layers. + browser.docShellIsActive = false; +- if (remoteTab) { ++ if (remoteTab && !zenSplitViewIsEnabled()) { + remoteTab.priorityHint = false; + } + if (!browser.hasLayers) { +@@ -364,7 +368,7 @@ export class AsyncTabSwitcher { + // constructing BrowserChild's, layer trees, etc, by showing a blank + // tab instead and focusing it immediately. + let shouldBeBlank = false; +- if (requestedBrowser.isRemoteBrowser) { ++ if (requestedBrowser.isRemoteBrowser && !zenSplitViewIsEnabled()) { + // If a tab is remote and the window is not minimized, we can show a + // blank tab instead of a spinner in the following cases: + // +@@ -399,7 +403,7 @@ export class AsyncTabSwitcher { + } + } + +- if (requestedBrowser.isRemoteBrowser) { ++ if (requestedBrowser.isRemoteBrowser && !zenSplitViewIsEnabled()) { + this.addLogFlag("isRemote"); + } + +@@ -825,7 +829,7 @@ export class AsyncTabSwitcher { + `onRemotenessChange(${tab._tPos}, ${tab.linkedBrowser.isRemoteBrowser})` + ); + if (!tab.linkedBrowser.isRemoteBrowser) { +- if (this.getTabState(tab) == this.STATE_LOADING) { ++ if (this.getTabState(tab) == this.STATE_LOADING && !zenSplitViewIsEnabled()) { + this.onLayersReady(tab.linkedBrowser); + } else if (this.getTabState(tab) == this.STATE_UNLOADING) { + this.onLayersCleared(tab.linkedBrowser); +@@ -1018,6 +1022,7 @@ export class AsyncTabSwitcher { + lazy.gTabCacheSize > 1 && + tab.linkedBrowser.isRemoteBrowser && + tab.linkedBrowser.currentURI.spec != "about:blank" ++ && !zenSplitViewIsEnabled() + ) { + let tabIndex = this.tabLayerCache.indexOf(tab); + diff --git a/src/browser/themes/shared/zen-decks.css b/src/browser/themes/shared/zen-decks.css index 1c1e5f255..d898d8b39 100644 --- a/src/browser/themes/shared/zen-decks.css +++ b/src/browser/themes/shared/zen-decks.css @@ -1,14 +1,20 @@ /** Zen Decks - ONLY USED FOR SPLIT VIEWS, DO NOT USE THIS CLASS FOR ANY OTHER PURPOSE **/ -.zen-deck { - display: grid; - position: absolute; - width: 100%; - height: 100%; +#tabbrowser-tabpanels[zen-split-view="true"] { + display: flex; + flex-direction: row; } -.zen-deck:not(.deck-selected) { - z-index: -1; - visibility: hidden; +#tabbrowser-tabpanels[zen-split-view="true"] > *:not(.deck-selected) { + flex: 0; + margin: 0 !important; } + +#tabbrowser-tabpanels[zen-split-view="true"] > .deck-selected { + flex: 1; +} + +#tabbrowser-tabpanels[zen-split-view="true"] .browserSidebarContainer[zen-split-active="true"] { + border-color: var(--zen-primary-color) !important; +} \ No newline at end of file diff --git a/src/dom/ipc/BrowserHost-cpp.patch b/src/dom/ipc/BrowserHost-cpp.patch new file mode 100644 index 000000000..49f789e1a --- /dev/null +++ b/src/dom/ipc/BrowserHost-cpp.patch @@ -0,0 +1,13 @@ +diff --git a/dom/ipc/BrowserHost.cpp b/dom/ipc/BrowserHost.cpp +index 489f07a612e52a3edb00f59e53495dcd9e16c0f5..1799e0d416f9d7be2c9e34c237d6ff741e5e2420 100644 +--- a/dom/ipc/BrowserHost.cpp ++++ b/dom/ipc/BrowserHost.cpp +@@ -106,7 +106,7 @@ void BrowserHost::UpdateEffects(EffectsInfo aEffects) { + /* attribute boolean renderLayers; */ + NS_IMETHODIMP + BrowserHost::GetRenderLayers(bool* aRenderLayers) { +- if (!mRoot) { ++ if (!mRoot && !Preferences::GetBool("zen.splitView.working", false)) { + *aRenderLayers = false; + return NS_OK; + }