diff --git a/browser/components/BrowserGlue.sys.mjs b/browser/components/BrowserGlue.sys.mjs index 2223f7730577..f8198001eef5 100644 --- a/browser/components/BrowserGlue.sys.mjs +++ b/browser/components/BrowserGlue.sys.mjs @@ -80,7 +80,7 @@ ChromeUtils.defineESModuleGetters(lazy, { "resource:///modules/WebProtocolHandlerRegistrar.sys.mjs", WindowsRegistry: "resource://gre/modules/WindowsRegistry.sys.mjs", setTimeout: "resource://gre/modules/Timer.sys.mjs", - WaterfoxGlue: "resource:///modules/WaterfoxGlue.jsm", + WaterfoxGlue: "resource:///modules/WaterfoxGlue.sys.mjs", }); XPCOMUtils.defineLazyServiceGetters(lazy, { @@ -234,7 +234,7 @@ BrowserGlue.prototype = { const { BootstrapLoader } = ChromeUtils.importESModule( "resource:///modules/BootstrapLoader.sys.mjs" ); - AddonManager.addExternalExtensionLoader(BootstrapLoader); + lazy.AddonManager.addExternalExtensionLoader(BootstrapLoader); break; case "notifications-open-settings": this._openPreferences("privacy-permissions"); @@ -402,7 +402,7 @@ BrowserGlue.prototype = { lazy.DesktopActorRegistry.init(); - WaterfoxGlue.init(); + lazy.WaterfoxGlue.init(); }, // cleanup (called on application shutdown) diff --git a/waterfox/browser/components/WaterfoxGlue.jsm b/waterfox/browser/components/WaterfoxGlue.sys.mjs similarity index 55% rename from waterfox/browser/components/WaterfoxGlue.jsm rename to waterfox/browser/components/WaterfoxGlue.sys.mjs index e7e389929172..0bef02da80e2 100644 --- a/waterfox/browser/components/WaterfoxGlue.jsm +++ b/waterfox/browser/components/WaterfoxGlue.sys.mjs @@ -2,20 +2,11 @@ * 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/. */ -"use strict"; - -const EXPORTED_SYMBOLS = ["WaterfoxGlue"]; - -const { XPCOMUtils } = ChromeUtils.import( - "resource://gre/modules/XPCOMUtils.jsm" -); - -const { Services } = ChromeUtils.import("resource://gre/modules/Services.jsm"); - const lazy = {}; -XPCOMUtils.defineLazyModuleGetters(lazy, { +ChromeUtils.defineESModuleGetters(lazy, { AddonManager: "resource://gre/modules/AddonManager.sys.mjs", + AttributionCode: "resource:///modules/AttributionCode.sys.mjs", BrowserUtils: "resource:///modules/BrowserUtils.sys.mjs", ChromeManifest: "resource:///modules/ChromeManifest.sys.mjs", Overlays: "resource:///modules/Overlays.sys.mjs", @@ -23,12 +14,24 @@ XPCOMUtils.defineLazyModuleGetters(lazy, { PrivateTab: "resource:///modules/PrivateTab.sys.mjs", StatusBar: "resource:///modules/StatusBar.sys.mjs", TabFeatures: "resource:///modules/TabFeatures.sys.mjs", + setTimeout: "resource://gre/modules/Timer.sys.mjs", UICustomizations: "resource:///modules/UICustomizations.sys.mjs", }); -XPCOMUtils.defineLazyGlobalGetters(this, ["fetch"]); +const WATERFOX_CUSTOMIZATIONS_PREF = + "browser.theme.enableWaterfoxCustomizations"; -const WaterfoxGlue = { +const WATERFOX_DEFAULT_THEMES = [ + "default-theme@mozilla.org", + "firefox-compact-light@mozilla.org", + "firefox-compact-dark@mozilla.org", + "firefox-alpenglow@mozilla.org", +]; + +const WATERFOX_USERCHROME = "chrome://browser/skin/userChrome.css"; +const WATERFOX_USERCONTENT = "chrome://browser/skin/userContent.css"; + +export const WaterfoxGlue = { _addonManagersListeners: [], stylesEnabled: false, @@ -36,12 +39,25 @@ const WaterfoxGlue = { // Set pref observers this._setPrefObservers(); - // Load always on Waterfox custom CSS. - // Add additional CSS here. - BrowserUtils.registerStylesheet( + // Load always-on Waterfox custom CSS. + lazy.BrowserUtils.registerStylesheet( "chrome://browser/skin/waterfox/general.css" ); + // Maybe load Waterfox stylesheets + (async () => { + let amInitialized = false; + while (!amInitialized) { + try { + const activeThemeId = await this.getActiveThemeId(); + this.updateCustomStylesheets({ id: activeThemeId, type: "theme" }); + amInitialized = true; + } catch (ex) { + await new Promise(res => lazy.setTimeout(res, 500, {})); + } + } + })(); + // Parse chrome.manifest this.startupManifest = await this.getChromeManifest("startup"); this.privateManifest = await this.getChromeManifest("private"); @@ -52,37 +68,26 @@ const WaterfoxGlue = { Services.obs.addObserver(this, "main-pane-loaded"); // Observe final-ui-startup to launch browser window dependant tasks Services.obs.addObserver(this, "final-ui-startup"); + // Observe browser shutdown + Services.obs.addObserver(this, "quit-application-granted"); + // Listen for addon events + this.addAddonListener(); }, async _setPrefObservers() { - this.leptonListener = PrefUtils.addObserver( - "userChrome.theme.enable", - isEnabled => { - // Pref being false means we need to unload the sheets. - const userChromeSheet = "chrome://browser/skin/userChrome.css"; - const userContentSheet = "chrome://browser/skin/userContent.css"; - - // Only register userContent globally - BrowserUtils.registerOrUnregisterSheet(userContentSheet, isEnabled); - - // Attach or detach userChrome per-window - if (isEnabled) { - this.attachUserChromeToAllWindows(userChromeSheet); - this.stylesEnabled = true; - } else { - this.detachUserChromeFromAllWindows(userChromeSheet); - this.stylesEnabled = false; - } + this.leptonListener = lazy.PrefUtils.addObserver( + WATERFOX_CUSTOMIZATIONS_PREF, + async _ => { + const activeThemeId = await this.getActiveThemeId(); + this.updateCustomStylesheets({ id: activeThemeId, type: "theme" }); } ); - - // Keep the pinned tabs observer - this.pinnedTabListener = PrefUtils.addObserver( + this.pinnedTabListener = lazy.PrefUtils.addObserver( "browser.tabs.pinnedIconOnly", isEnabled => { // Pref being true actually means we need to unload the sheet, so invert. const uri = "chrome://browser/content/tabfeatures/pinnedtab.css"; - BrowserUtils.registerOrUnregisterSheet(uri, !isEnabled); + lazy.BrowserUtils.registerOrUnregisterSheet(uri, !isEnabled); } ); }, @@ -105,7 +110,7 @@ const WaterfoxGlue = { uri = "resource://waterfox/overlays/preferences-other.overlay"; break; } - let chromeManifest = new ChromeManifest(async () => { + let chromeManifest = new lazy.ChromeManifest(async () => { let res = await fetch(uri); let text = await res.text(); if (privateWindow) { @@ -140,25 +145,25 @@ const WaterfoxGlue = { const window = subject.defaultView; // Do not load non-private overlays in private window if (window.PrivateBrowsingUtils.isWindowPrivate(window)) { - Overlays.load(this.privateManifest, window); + lazy.Overlays.load(this.privateManifest, window); } else { - Overlays.load(this.startupManifest, window); + lazy.Overlays.load(this.startupManifest, window); // Only load in non-private browser windows - PrivateTab.init(window); + lazy.PrivateTab.init(window); } // Load in all browser windows (private and normal) - TabFeatures.init(window); - StatusBar.init(window); - UICustomizations.init(window); + lazy.TabFeatures.init(window); + lazy.StatusBar.init(window); + lazy.UICustomizations.init(window); // Attach userChrome.css to this chrome window if styles are enabled if (this.stylesEnabled) { try { window.windowUtils.loadSheetUsingURIString( - "chrome://browser/skin/userChrome.css", + WATERFOX_USERCHROME, Ci.nsIStyleSheetService.USER_SHEET ); - } catch (_) {} + } catch (_e) {} } } break; @@ -169,7 +174,7 @@ const WaterfoxGlue = { // exists before we attempt to load our overlay. If we are loading directly on privacy // this exists before overlaying occurs, so we have no issues. Loading overlays on // #general is fine regardless of which pane we refresh/initially load. - await Overlays.load( + await lazy.Overlays.load( await this.getChromeManifest("preferences-general"), subject ); @@ -178,14 +183,14 @@ const WaterfoxGlue = { !subject.document.getElementById("homeContentsGroup") ) { subject.setTimeout(async () => { - await Overlays.load( + await lazy.Overlays.load( await this.getChromeManifest("preferences-other"), subject ); subject.privacyInitialized = true; }, 500); } else { - await Overlays.load( + await lazy.Overlays.load( await this.getChromeManifest("preferences-other"), subject ); @@ -196,6 +201,7 @@ const WaterfoxGlue = { break; case "final-ui-startup": this._beforeUIStartup(); + this._delayedTasks(); break; } }, @@ -203,7 +209,7 @@ const WaterfoxGlue = { async _beforeUIStartup() { this._migrateUI(); - AddonManager.maybeInstallBuiltinAddon( + lazy.AddonManager.maybeInstallBuiltinAddon( "addonstores@waterfox.net", "1.0.0", "resource://builtin-addons/addonstores/" @@ -216,8 +222,13 @@ const WaterfoxGlue = { 128 ); + const waterfoxUIVersion = lazy.PrefUtils.get( + "browser.migration.waterfox_version", + 0 + ); + async function enableTheme(id) { - const addon = await AddonManager.getAddonByID(id); + const addon = await lazy.AddonManager.getAddonByID(id); // If we found it, enable it. addon?.enable(); } @@ -239,37 +250,121 @@ const WaterfoxGlue = { case "australis-dark@waterfox.net": enableTheme("firefox-compact-dark@mozilla.org"); break; - default: - enableTheme(DEFAULT_THEME); } } else { // If no activeTheme detected, set default. enableTheme(DEFAULT_THEME); } } + if (waterfoxUIVersion < 1) { + const themeEnablePref = "userChrome.theme.enable"; + const enabled = lazy.PrefUtils.get(themeEnablePref); + lazy.PrefUtils.set(WATERFOX_CUSTOMIZATIONS_PREF, enabled ? 1 : 2); + } + + lazy.PrefUtils.set("browser.migration.waterfox_version", 1); + }, + + async _delayedTasks() { + let tasks = [ + { + task: () => { + // Reset prefs + Services.prefs.clearUserPref( + "startup.homepage_welcome_url.additional" + ); + Services.prefs.clearUserPref("startup.homepage_override_url"); + }, + }, + ]; + + for (const task of tasks) { + task.task(); + } + }, + + async getActiveThemeId() { + // Try to get active theme from the pref + const activeThemeID = lazy.PrefUtils.get("extensions.activeThemeID", ""); + if (activeThemeID) { + return activeThemeID; + } + // Otherwise just grab it from AddonManager + const themes = await lazy.AddonManager.getAddonsByTypes(["theme"]); + return themes.find(addon => addon.isActive).id; + }, + + addAddonListener() { + let listener = { + onInstalled: addon => this.updateCustomStylesheets(addon), + onEnabled: addon => this.updateCustomStylesheets(addon), + }; + this._addonManagersListeners.push(listener); + lazy.AddonManager.addAddonListener(listener); + }, + + removeAddonListeners() { + for (let listener of this._addonManagersListeners) { + lazy.AddonManager.removeAddonListener(listener); + } + }, + + updateCustomStylesheets(addon) { + if (addon.type === "theme") { + // If any theme and WF on any theme, reload stylesheets for every theme enable. + // If WF theme and WF customisations, then reload stylesheets. + // If no customizations, unregister sheets for every theme enable. + if ( + lazy.PrefUtils.get(WATERFOX_CUSTOMIZATIONS_PREF, 0) === 0 || + (lazy.PrefUtils.get(WATERFOX_CUSTOMIZATIONS_PREF, 0) === 1 && + WATERFOX_DEFAULT_THEMES.includes(addon.id)) + ) { + this.loadWaterfoxStylesheets(); + } else { + this.unloadWaterfoxStylesheets(); + } + } }, // Attach userChrome.css to all open browser windows (per-window). - attachUserChromeToAllWindows(uri) { - BrowserUtils.executeInAllWindows((win, sheetURI) => { + attachUserChromeToAllWindows() { + lazy.BrowserUtils.executeInAllWindows((win, uri) => { try { win.windowUtils.loadSheetUsingURIString( - sheetURI, + uri, Ci.nsIStyleSheetService.USER_SHEET ); - } catch (_) {} - }, uri); + } catch (_e) {} + }, WATERFOX_USERCHROME); }, // Detach userChrome.css from all open browser windows. - detachUserChromeFromAllWindows(uri) { - BrowserUtils.executeInAllWindows((win, sheetURI) => { + detachUserChromeFromAllWindows() { + lazy.BrowserUtils.executeInAllWindows((win, uri) => { try { win.windowUtils.removeSheetUsingURIString( - sheetURI, + uri, Ci.nsIStyleSheetService.USER_SHEET ); - } catch (_) {} - }, uri); + } catch (_e) {} + }, WATERFOX_USERCHROME); + }, + + loadWaterfoxStylesheets() { + // Register content sheet globally + lazy.BrowserUtils.registerStylesheet(WATERFOX_USERCONTENT); + // Attach chrome sheet to all current browser windows + this.attachUserChromeToAllWindows(); + // Track enabled state so new windows can attach on open + this.stylesEnabled = true; + }, + + unloadWaterfoxStylesheets() { + // Detach chrome sheet from all windows + this.detachUserChromeFromAllWindows(); + // Unregister content sheet globally + lazy.BrowserUtils.unregisterStylesheet(WATERFOX_USERCONTENT); + // Track disabled state so new windows don't attach on open + this.stylesEnabled = false; }, }; diff --git a/waterfox/browser/components/moz.build b/waterfox/browser/components/moz.build index 3ae3ee4d9616..24bf5539ca33 100644 --- a/waterfox/browser/components/moz.build +++ b/waterfox/browser/components/moz.build @@ -16,7 +16,7 @@ DIRS += [ ] EXTRA_JS_MODULES += [ - "WaterfoxGlue.jsm", + "WaterfoxGlue.sys.mjs", ] JAR_MANIFESTS += ["jar.mn"]