diff options
Diffstat (limited to 'toolkit/components/extensions/parent/ext-browserSettings.js')
-rw-r--r-- | toolkit/components/extensions/parent/ext-browserSettings.js | 592 |
1 files changed, 592 insertions, 0 deletions
diff --git a/toolkit/components/extensions/parent/ext-browserSettings.js b/toolkit/components/extensions/parent/ext-browserSettings.js new file mode 100644 index 0000000000..7b292f76b8 --- /dev/null +++ b/toolkit/components/extensions/parent/ext-browserSettings.js @@ -0,0 +1,592 @@ +/* -*- Mode: indent-tabs-mode: nil; js-indent-level: 2 -*- */ +/* vim: set sts=2 sw=2 et tw=80: */ +/* This Source Code Form is subject to the terms of the Mozilla Public + * 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"; + +ChromeUtils.defineESModuleGetters(this, { + AboutNewTab: "resource:///modules/AboutNewTab.sys.mjs", +}); + +var { ExtensionPreferencesManager } = ChromeUtils.importESModule( + "resource://gre/modules/ExtensionPreferencesManager.sys.mjs" +); + +var { ExtensionError } = ExtensionUtils; +var { getSettingsAPI, getPrimedSettingsListener } = ExtensionPreferencesManager; + +const HOMEPAGE_URL_PREF = "browser.startup.homepage"; + +const PERM_DENY_ACTION = Services.perms.DENY_ACTION; + +// Add settings objects for supported APIs to the preferences manager. +ExtensionPreferencesManager.addSetting("allowPopupsForUserEvents", { + permission: "browserSettings", + prefNames: ["dom.popup_allowed_events"], + + setCallback(value) { + let returnObj = {}; + // If the value is true, then reset the pref, otherwise set it to "". + returnObj[this.prefNames[0]] = value ? undefined : ""; + return returnObj; + }, + + getCallback() { + return Services.prefs.getCharPref("dom.popup_allowed_events") != ""; + }, +}); + +ExtensionPreferencesManager.addSetting("cacheEnabled", { + permission: "browserSettings", + prefNames: ["browser.cache.disk.enable", "browser.cache.memory.enable"], + + setCallback(value) { + let returnObj = {}; + for (let pref of this.prefNames) { + returnObj[pref] = value; + } + return returnObj; + }, + + getCallback() { + return ( + Services.prefs.getBoolPref("browser.cache.disk.enable") && + Services.prefs.getBoolPref("browser.cache.memory.enable") + ); + }, +}); + +ExtensionPreferencesManager.addSetting("closeTabsByDoubleClick", { + permission: "browserSettings", + prefNames: ["browser.tabs.closeTabByDblclick"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("browser.tabs.closeTabByDblclick"); + }, + + validate() { + if (AppConstants.platform == "android") { + throw new ExtensionError( + `android is not a supported platform for the closeTabsByDoubleClick setting.` + ); + } + }, +}); + +ExtensionPreferencesManager.addSetting("colorManagement.mode", { + permission: "browserSettings", + prefNames: ["gfx.color_management.mode"], + + setCallback(value) { + switch (value) { + case "off": + return { [this.prefNames[0]]: 0 }; + case "full": + return { [this.prefNames[0]]: 1 }; + case "tagged_only": + return { [this.prefNames[0]]: 2 }; + } + }, + + getCallback() { + switch (Services.prefs.getIntPref("gfx.color_management.mode")) { + case 0: + return "off"; + case 1: + return "full"; + case 2: + return "tagged_only"; + } + }, +}); + +ExtensionPreferencesManager.addSetting("colorManagement.useNativeSRGB", { + permission: "browserSettings", + prefNames: ["gfx.color_management.native_srgb"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("gfx.color_management.native_srgb"); + }, +}); + +ExtensionPreferencesManager.addSetting( + "colorManagement.useWebRenderCompositor", + { + permission: "browserSettings", + prefNames: ["gfx.webrender.compositor"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("gfx.webrender.compositor"); + }, + } +); + +ExtensionPreferencesManager.addSetting("contextMenuShowEvent", { + permission: "browserSettings", + prefNames: ["ui.context_menus.after_mouseup"], + + setCallback(value) { + return { [this.prefNames[0]]: value === "mouseup" }; + }, + + getCallback() { + if (AppConstants.platform === "win") { + return "mouseup"; + } + let prefValue = Services.prefs.getBoolPref( + "ui.context_menus.after_mouseup", + null + ); + return prefValue ? "mouseup" : "mousedown"; + }, +}); + +ExtensionPreferencesManager.addSetting("imageAnimationBehavior", { + permission: "browserSettings", + prefNames: ["image.animation_mode"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getCharPref("image.animation_mode"); + }, +}); + +ExtensionPreferencesManager.addSetting("newTabPosition", { + permission: "browserSettings", + prefNames: [ + "browser.tabs.insertRelatedAfterCurrent", + "browser.tabs.insertAfterCurrent", + ], + + setCallback(value) { + return { + "browser.tabs.insertAfterCurrent": value === "afterCurrent", + "browser.tabs.insertRelatedAfterCurrent": value === "relatedAfterCurrent", + }; + }, + + getCallback() { + if (Services.prefs.getBoolPref("browser.tabs.insertAfterCurrent")) { + return "afterCurrent"; + } + if (Services.prefs.getBoolPref("browser.tabs.insertRelatedAfterCurrent")) { + return "relatedAfterCurrent"; + } + return "atEnd"; + }, +}); + +ExtensionPreferencesManager.addSetting("openBookmarksInNewTabs", { + permission: "browserSettings", + prefNames: ["browser.tabs.loadBookmarksInTabs"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("browser.tabs.loadBookmarksInTabs"); + }, +}); + +ExtensionPreferencesManager.addSetting("openSearchResultsInNewTabs", { + permission: "browserSettings", + prefNames: ["browser.search.openintab"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("browser.search.openintab"); + }, +}); + +ExtensionPreferencesManager.addSetting("openUrlbarResultsInNewTabs", { + permission: "browserSettings", + prefNames: ["browser.urlbar.openintab"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("browser.urlbar.openintab"); + }, +}); + +ExtensionPreferencesManager.addSetting("webNotificationsDisabled", { + permission: "browserSettings", + prefNames: ["permissions.default.desktop-notification"], + + setCallback(value) { + return { [this.prefNames[0]]: value ? PERM_DENY_ACTION : undefined }; + }, + + getCallback() { + let prefValue = Services.prefs.getIntPref( + "permissions.default.desktop-notification", + null + ); + return prefValue === PERM_DENY_ACTION; + }, +}); + +ExtensionPreferencesManager.addSetting("overrideDocumentColors", { + permission: "browserSettings", + prefNames: ["browser.display.document_color_use"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + let prefValue = Services.prefs.getIntPref( + "browser.display.document_color_use" + ); + if (prefValue === 1) { + return "never"; + } else if (prefValue === 2) { + return "always"; + } + return "high-contrast-only"; + }, +}); + +ExtensionPreferencesManager.addSetting("overrideContentColorScheme", { + permission: "browserSettings", + prefNames: ["layout.css.prefers-color-scheme.content-override"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + let prefValue = Services.prefs.getIntPref( + "layout.css.prefers-color-scheme.content-override" + ); + switch (prefValue) { + case 0: + return "dark"; + case 1: + return "light"; + default: + return "auto"; + } + }, +}); + +ExtensionPreferencesManager.addSetting("useDocumentFonts", { + permission: "browserSettings", + prefNames: ["browser.display.use_document_fonts"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return ( + Services.prefs.getIntPref("browser.display.use_document_fonts") !== 0 + ); + }, +}); + +ExtensionPreferencesManager.addSetting("zoomFullPage", { + permission: "browserSettings", + prefNames: ["browser.zoom.full"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("browser.zoom.full"); + }, +}); + +ExtensionPreferencesManager.addSetting("zoomSiteSpecific", { + permission: "browserSettings", + prefNames: ["browser.zoom.siteSpecific"], + + setCallback(value) { + return { [this.prefNames[0]]: value }; + }, + + getCallback() { + return Services.prefs.getBoolPref("browser.zoom.siteSpecific"); + }, +}); + +this.browserSettings = class extends ExtensionAPI { + homePageOverrideListener(fire) { + let listener = () => { + fire.async({ + levelOfControl: "not_controllable", + value: Services.prefs.getStringPref(HOMEPAGE_URL_PREF), + }); + }; + Services.prefs.addObserver(HOMEPAGE_URL_PREF, listener); + return { + unregister: () => { + Services.prefs.removeObserver(HOMEPAGE_URL_PREF, listener); + }, + convert(_fire) { + fire = _fire; + }, + }; + } + + newTabOverrideListener(fire) { + let listener = () => { + fire.async({ + levelOfControl: "not_controllable", + value: AboutNewTab.newTabURL, + }); + }; + Services.obs.addObserver(listener, "newtab-url-changed"); + return { + unregister: () => { + Services.obs.removeObserver(listener, "newtab-url-changed"); + }, + convert(_fire) { + fire = _fire; + }, + }; + } + + primeListener(event, fire) { + let { extension } = this; + if (event == "homepageOverride") { + return this.homePageOverrideListener(fire); + } + if (event == "newTabPageOverride") { + return this.newTabOverrideListener(fire); + } + let listener = getPrimedSettingsListener({ + extension, + name: event, + }); + return listener(fire); + } + + getAPI(context) { + let self = this; + let { extension } = context; + + function makeSettingsAPI(name) { + return getSettingsAPI({ + context, + module: "browserSettings", + name, + }); + } + + return { + browserSettings: { + allowPopupsForUserEvents: makeSettingsAPI("allowPopupsForUserEvents"), + cacheEnabled: makeSettingsAPI("cacheEnabled"), + closeTabsByDoubleClick: makeSettingsAPI("closeTabsByDoubleClick"), + contextMenuShowEvent: Object.assign( + makeSettingsAPI("contextMenuShowEvent"), + { + set: details => { + if (!["mouseup", "mousedown"].includes(details.value)) { + throw new ExtensionError( + `${details.value} is not a valid value for contextMenuShowEvent.` + ); + } + if ( + AppConstants.platform === "android" || + (AppConstants.platform === "win" && + details.value === "mousedown") + ) { + return false; + } + return ExtensionPreferencesManager.setSetting( + extension.id, + "contextMenuShowEvent", + details.value + ); + }, + } + ), + ftpProtocolEnabled: getSettingsAPI({ + context, + name: "ftpProtocolEnabled", + readOnly: true, + callback() { + return false; + }, + }), + homepageOverride: getSettingsAPI({ + context, + // Name differs here to preserve this setting properly + name: "homepage_override", + callback() { + return Services.prefs.getStringPref(HOMEPAGE_URL_PREF); + }, + readOnly: true, + onChange: new ExtensionCommon.EventManager({ + context, + module: "browserSettings", + event: "homepageOverride", + name: "homepageOverride.onChange", + register: fire => { + return self.homePageOverrideListener(fire).unregister; + }, + }).api(), + }), + imageAnimationBehavior: makeSettingsAPI("imageAnimationBehavior"), + newTabPosition: makeSettingsAPI("newTabPosition"), + newTabPageOverride: getSettingsAPI({ + context, + // Name differs here to preserve this setting properly + name: "newTabURL", + callback() { + return AboutNewTab.newTabURL; + }, + storeType: "url_overrides", + readOnly: true, + onChange: new ExtensionCommon.EventManager({ + context, + module: "browserSettings", + event: "newTabPageOverride", + name: "newTabPageOverride.onChange", + register: fire => { + return self.newTabOverrideListener(fire).unregister; + }, + }).api(), + }), + openBookmarksInNewTabs: makeSettingsAPI("openBookmarksInNewTabs"), + openSearchResultsInNewTabs: makeSettingsAPI( + "openSearchResultsInNewTabs" + ), + openUrlbarResultsInNewTabs: makeSettingsAPI( + "openUrlbarResultsInNewTabs" + ), + webNotificationsDisabled: makeSettingsAPI("webNotificationsDisabled"), + overrideDocumentColors: Object.assign( + makeSettingsAPI("overrideDocumentColors"), + { + set: details => { + if ( + !["never", "always", "high-contrast-only"].includes( + details.value + ) + ) { + throw new ExtensionError( + `${details.value} is not a valid value for overrideDocumentColors.` + ); + } + let prefValue = 0; // initialize to 0 - auto/high-contrast-only + if (details.value === "never") { + prefValue = 1; + } else if (details.value === "always") { + prefValue = 2; + } + return ExtensionPreferencesManager.setSetting( + extension.id, + "overrideDocumentColors", + prefValue + ); + }, + } + ), + overrideContentColorScheme: Object.assign( + makeSettingsAPI("overrideContentColorScheme"), + { + set: details => { + let value = details.value; + if (value == "system" || value == "browser") { + // Map previous values that used to be different but were + // unified under the "auto" setting. In practice this should + // almost always behave like the extension author expects. + extension.logger.warn( + `The "${value}" value for overrideContentColorScheme has been deprecated. Use "auto" instead` + ); + value = "auto"; + } + let prefValue = ["dark", "light", "auto"].indexOf(value); + if (prefValue === -1) { + throw new ExtensionError( + `${value} is not a valid value for overrideContentColorScheme.` + ); + } + return ExtensionPreferencesManager.setSetting( + extension.id, + "overrideContentColorScheme", + prefValue + ); + }, + } + ), + useDocumentFonts: Object.assign(makeSettingsAPI("useDocumentFonts"), { + set: details => { + if (typeof details.value !== "boolean") { + throw new ExtensionError( + `${details.value} is not a valid value for useDocumentFonts.` + ); + } + return ExtensionPreferencesManager.setSetting( + extension.id, + "useDocumentFonts", + Number(details.value) + ); + }, + }), + zoomFullPage: Object.assign(makeSettingsAPI("zoomFullPage"), { + set: details => { + if (typeof details.value !== "boolean") { + throw new ExtensionError( + `${details.value} is not a valid value for zoomFullPage.` + ); + } + return ExtensionPreferencesManager.setSetting( + extension.id, + "zoomFullPage", + details.value + ); + }, + }), + zoomSiteSpecific: Object.assign(makeSettingsAPI("zoomSiteSpecific"), { + set: details => { + if (typeof details.value !== "boolean") { + throw new ExtensionError( + `${details.value} is not a valid value for zoomSiteSpecific.` + ); + } + return ExtensionPreferencesManager.setSetting( + extension.id, + "zoomSiteSpecific", + details.value + ); + }, + }), + colorManagement: { + mode: makeSettingsAPI("colorManagement.mode"), + useNativeSRGB: makeSettingsAPI("colorManagement.useNativeSRGB"), + useWebRenderCompositor: makeSettingsAPI( + "colorManagement.useWebRenderCompositor" + ), + }, + }, + }; + } +}; |