From d962cf9949b4fc69da7674dbea1626172f32a5da Mon Sep 17 00:00:00 2001 From: "Mr. M" Date: Sun, 21 Sep 2025 17:29:40 +0200 Subject: [PATCH] fix: Fixed closing last tab not closing the window and other refactors, b=closes #10455, c=common, configs, kbs, split-view, folders, tests, workspaces --- configs/common/mozconfig | 2 + prefs/browser.yaml | 3 ++ prefs/theme.yaml | 2 +- src/zen/common/styles/zen-omnibox.css | 7 --- src/zen/kbs/ZenKeyboardShortcuts.mjs | 2 +- src/zen/split-view/ZenViewSplitter.mjs | 2 + .../folders/browser_folder_reset_button.js | 2 +- src/zen/tests/ignorePrefs.json | 2 +- .../ub-actions/browser_ub_actions_search.js | 4 ++ src/zen/tests/workspaces/browser.toml | 1 + .../tests/workspaces/browser_issue_10455.js | 45 +++++++++++++++++++ .../tests/workspaces/browser_private_mode.js | 1 + src/zen/urlbar/ZenUBActionsProvider.sys.mjs | 2 +- src/zen/urlbar/ZenUBGlobalActions.sys.mjs | 11 ++++- src/zen/workspaces/ZenWorkspace.mjs | 2 +- src/zen/workspaces/ZenWorkspaces.mjs | 5 ++- tools/ffprefs/src/main.rs | 35 ++++++++++++++- 17 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 src/zen/tests/workspaces/browser_issue_10455.js diff --git a/configs/common/mozconfig b/configs/common/mozconfig index 195d377c6..7949d1bdb 100644 --- a/configs/common/mozconfig +++ b/configs/common/mozconfig @@ -100,6 +100,8 @@ if test "$ZEN_RELEASE"; then ac_add_options --enable-updater export MOZ_PACKAGE_JSSHELL=1 +else + ac_add_options --disable-crashreporter fi ac_add_options --enable-unverified-updates diff --git a/prefs/browser.yaml b/prefs/browser.yaml index de4ddcf6a..30aa603e9 100644 --- a/prefs/browser.yaml +++ b/prefs/browser.yaml @@ -79,3 +79,6 @@ - name: browser.tabs.groups.hoverPreview.enabled value: false + +- name: browser.tabs.closeWindowWithLastTab + value: false diff --git a/prefs/theme.yaml b/prefs/theme.yaml index e061f808b..d4b51666d 100644 --- a/prefs/theme.yaml +++ b/prefs/theme.yaml @@ -33,7 +33,7 @@ value: true - name: zen.theme.styled-status-panel - value: true + value: '@IS_TWILIGHT@' # ==== Mark: border radius ==== diff --git a/src/zen/common/styles/zen-omnibox.css b/src/zen/common/styles/zen-omnibox.css index 960205d9d..cb8b4a69c 100644 --- a/src/zen/common/styles/zen-omnibox.css +++ b/src/zen/common/styles/zen-omnibox.css @@ -66,13 +66,6 @@ } #urlbar:not([breakout-extend='true']) { - & .urlbar-background { - transition: background-color 0.15s ease; - :root[supress-primary-adjustment] & { - transition: none !important; - } - } - &:hover .urlbar-background { background-color: light-dark(rgba(0, 0, 0, 0.1), rgba(255, 255, 255, 0.2)) !important; } diff --git a/src/zen/kbs/ZenKeyboardShortcuts.mjs b/src/zen/kbs/ZenKeyboardShortcuts.mjs index f9636a4eb..db12699f6 100644 --- a/src/zen/kbs/ZenKeyboardShortcuts.mjs +++ b/src/zen/kbs/ZenKeyboardShortcuts.mjs @@ -1084,7 +1084,7 @@ class nsZenKeyboardShortcutsVersioner { data.push( new KeyShortcut( 'zen-new-empty-split-view', - '+', + AppConstants.platform == 'linux' ? '*' : '+', '', ZEN_SPLIT_VIEW_SHORTCUTS_GROUP, nsKeyShortcutModifiers.fromObject({ accel: true, shift: true }), diff --git a/src/zen/split-view/ZenViewSplitter.mjs b/src/zen/split-view/ZenViewSplitter.mjs index 65af61eac..e66f21a10 100644 --- a/src/zen/split-view/ZenViewSplitter.mjs +++ b/src/zen/split-view/ZenViewSplitter.mjs @@ -1951,6 +1951,8 @@ class nsZenViewSplitter extends nsZenDOMOperatedFeature { const newSelectedTab = gBrowser.selectedTab; const cleanup = () => { this.removeTabFromGroup(emptyTab, groupIndex, { changeTab: false }); + const command = document.getElementById('cmd_zenNewEmptySplit'); + command.removeAttribute('disabled'); }; if (onElementPicked) { if ( diff --git a/src/zen/tests/folders/browser_folder_reset_button.js b/src/zen/tests/folders/browser_folder_reset_button.js index b71ed1647..979824df9 100644 --- a/src/zen/tests/folders/browser_folder_reset_button.js +++ b/src/zen/tests/folders/browser_folder_reset_button.js @@ -36,7 +36,7 @@ add_task(async function test_Issue_() { ok(!tab1.hasAttribute('folder-active'), 'Tab 1 should not be in the active folder'); ok(!tab2.hasAttribute('folder-active'), 'Tab 2 should not be in the active folder'); resolve(); - }, 100) + }, 500) ); await removeFolder(folder); }); diff --git a/src/zen/tests/ignorePrefs.json b/src/zen/tests/ignorePrefs.json index e0c610426..25c2cf37a 100644 --- a/src/zen/tests/ignorePrefs.json +++ b/src/zen/tests/ignorePrefs.json @@ -1,6 +1,6 @@ [ "zen.mods.updated-value-observer", "zen.mods.last-update", - "zen.view.compact.should-enable-at-startup", + "zen.view.compact.enable-at-startup", "browser.newtabpage.activity-stream.trendingSearch.defaultSearchEngine" ] diff --git a/src/zen/tests/ub-actions/browser_ub_actions_search.js b/src/zen/tests/ub-actions/browser_ub_actions_search.js index f1e432672..0456abda5 100644 --- a/src/zen/tests/ub-actions/browser_ub_actions_search.js +++ b/src/zen/tests/ub-actions/browser_ub_actions_search.js @@ -10,6 +10,10 @@ ChromeUtils.defineESModuleGetters(this, { add_task(async function test_Ub_Actions_Search() { for (const action of globalActions) { + if (!action.isAvailable(window)) { + ok(true, `Skipping action: ${action.command}`); + continue; + } const label = action.label; await UrlbarTestUtils.promiseAutocompleteResultPopup({ window, diff --git a/src/zen/tests/workspaces/browser.toml b/src/zen/tests/workspaces/browser.toml index 51c06f55b..d97d7ed65 100644 --- a/src/zen/tests/workspaces/browser.toml +++ b/src/zen/tests/workspaces/browser.toml @@ -15,6 +15,7 @@ support-files = [ ["browser_issue_8699.js"] ["browser_issue_9900.js"] +["browser_issue_10455.js"] ["browser_private_mode.js"] ["browser_private_mode_startup.js"] diff --git a/src/zen/tests/workspaces/browser_issue_10455.js b/src/zen/tests/workspaces/browser_issue_10455.js new file mode 100644 index 000000000..06f428415 --- /dev/null +++ b/src/zen/tests/workspaces/browser_issue_10455.js @@ -0,0 +1,45 @@ +/* Any copyright is dedicated to the Public Domain. + https://creativecommons.org/publicdomain/zero/1.0/ */ + +'use strict'; + +add_task(async function test_Issue_10455() { + await SpecialPowers.pushPrefEnv({ + set: [['browser.tabs.closeWindowWithLastTab', true]], + }); + + let newWindow = await BrowserTestUtils.openNewBrowserWindow(); + await newWindow.gZenWorkspaces.promiseInitialized; + ok( + newWindow.document.documentElement.hasAttribute('zen-workspace-id'), + 'New window should have a zen-workspace-id attribute' + ); + + const unloadEvent = BrowserTestUtils.waitForEvent(newWindow, 'unload'); + newWindow.BrowserCommands.closeTabOrWindow(); + await unloadEvent; + + ok(newWindow.closed, 'Window should be closing'); + await SpecialPowers.popPrefEnv(); +}); + +add_task(async function test_Issue_10455_Dont_Close() { + await SpecialPowers.pushPrefEnv({ + set: [['browser.tabs.closeWindowWithLastTab', false]], + }); + + let newWindow = await BrowserTestUtils.openNewBrowserWindow(); + await newWindow.gZenWorkspaces.promiseInitialized; + ok( + newWindow.document.documentElement.hasAttribute('zen-workspace-id'), + 'New window should have a zen-workspace-id attribute' + ); + + newWindow.BrowserCommands.closeTabOrWindow(); + ok(newWindow.gBrowser.tabs.length === 1, 'Window should still have one tab'); + ok(newWindow.gBrowser.selectedTab.hasAttribute('zen-empty-tab'), 'Tab should be a zen empty tab'); + ok(!newWindow.closing, 'Window should be closing'); + + await BrowserTestUtils.closeWindow(newWindow); + await SpecialPowers.popPrefEnv(); +}); diff --git a/src/zen/tests/workspaces/browser_private_mode.js b/src/zen/tests/workspaces/browser_private_mode.js index 3c889bee5..aa361ed55 100644 --- a/src/zen/tests/workspaces/browser_private_mode.js +++ b/src/zen/tests/workspaces/browser_private_mode.js @@ -18,4 +18,5 @@ add_task(async function test_Private_Mode() { ); await BrowserTestUtils.closeWindow(privateWindow); + await SpecialPowers.popPrefEnv(); }); diff --git a/src/zen/urlbar/ZenUBActionsProvider.sys.mjs b/src/zen/urlbar/ZenUBActionsProvider.sys.mjs index 06b978d3e..e8f3b2ff1 100644 --- a/src/zen/urlbar/ZenUBActionsProvider.sys.mjs +++ b/src/zen/urlbar/ZenUBActionsProvider.sys.mjs @@ -367,6 +367,7 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider { const payload = result.payload; const command = payload.zenCommand; const ownerGlobal = details.element.ownerGlobal; + ownerGlobal.gBrowser.selectedBrowser.focus(); if (typeof command === 'function') { command(ownerGlobal); return; @@ -390,7 +391,6 @@ export class ZenUrlbarProviderGlobalActions extends UrlbarProvider { } const commandToRun = ownerGlobal.document.getElementById(command); if (commandToRun) { - ownerGlobal.gBrowser.selectedBrowser.focus(); commandToRun.doCommand(); } } diff --git a/src/zen/urlbar/ZenUBGlobalActions.sys.mjs b/src/zen/urlbar/ZenUBGlobalActions.sys.mjs index c2d5767e8..2fdb25324 100644 --- a/src/zen/urlbar/ZenUBGlobalActions.sys.mjs +++ b/src/zen/urlbar/ZenUBGlobalActions.sys.mjs @@ -69,14 +69,21 @@ const globalActionsTemplate = [ }, }, { - label: 'Next Workspace', + label: 'Next Space', command: 'cmd_zenWorkspaceForward', icon: 'chrome://browser/skin/zen-icons/forward.svg', + isAvailable: (window) => { + return window.gZenWorkspaces._workspaceCache.workspaces.length > 1; + }, }, { - label: 'Previous Workspace', + label: 'Previous Space', command: 'cmd_zenWorkspaceBackward', icon: 'chrome://browser/skin/zen-icons/back.svg', + isAvailable: (window) => { + // This also covers the case of being in private mode + return window.gZenWorkspaces._workspaceCache.workspaces.length > 1; + }, }, { label: 'Close Tab', diff --git a/src/zen/workspaces/ZenWorkspace.mjs b/src/zen/workspaces/ZenWorkspace.mjs index c2c243142..a7d1eee3d 100644 --- a/src/zen/workspaces/ZenWorkspace.mjs +++ b/src/zen/workspaces/ZenWorkspace.mjs @@ -15,7 +15,7 @@ - + !this.shouldOpenNewTabIfLastUnpinnedTabIsClosed || !t.pinned ); - const shouldCloseWindow = this.shouldCloseWindow() && closeWindowWithLastTab; + const shouldCloseWindow = + closeWindowWithLastTab != null ? closeWindowWithLastTab : this.shouldCloseWindow(); if (tabs.length === 1 && tabs[0] === tab) { if (shouldCloseWindow) { // We've already called beforeunload on all the relevant tabs if we get here, diff --git a/tools/ffprefs/src/main.rs b/tools/ffprefs/src/main.rs index 3f0f1be15..e044fd0f5 100644 --- a/tools/ffprefs/src/main.rs +++ b/tools/ffprefs/src/main.rs @@ -105,6 +105,7 @@ use serde::{Deserialize, Serialize}; use std::env; use std::fs; use std::path::PathBuf; +use std::collections::HashMap; const STATIC_PREFS: &str = "../engine/modules/libpref/init/zen-static-prefs.inc"; const FIREFOX_PREFS: &str = "../engine/browser/app/profile/firefox.js"; @@ -308,6 +309,37 @@ fn prepare_zen_prefs() { } } +fn is_twilight_build() -> bool { + // Check if '"twilight"' is on .surfer/dynamicConfig.brand.json + let mut dynamic_config_path = env::current_dir().expect("Failed to get current directory"); + dynamic_config_path.push(".surfer"); + dynamic_config_path.push("dynamicConfig.brand.json"); + if let Ok(content) = fs::read_to_string(&dynamic_config_path) { + return !content.contains("\"release\""); + } + false +} + +fn get_env_values() -> HashMap { + let mut env_values = HashMap::new(); + env_values.insert("IS_TWILIGHT".into(), is_twilight_build()); + env_values +} + +fn expand_pref_values(prefs: &mut [Preference]) { + let env_values = get_env_values(); + for pref in prefs { + let mut new_value = pref.value.clone(); + for (key, value) in &env_values { + let placeholder = format!("@{}@", key); + if new_value.contains(&placeholder) { + new_value = new_value.replace(&placeholder, if *value { "true" } else { "false" }); + } + pref.value = new_value.clone(); + } + } +} + fn main() { let args: Vec = env::args().collect(); let root_path = if args.len() > 1 { @@ -318,6 +350,7 @@ fn main() { env::set_current_dir(&root_path).expect("Failed to change directory"); prepare_zen_prefs(); - let preferences = load_preferences(); + let mut preferences = load_preferences(); + expand_pref_values(&mut preferences); write_preferences(&preferences); }