diff -r 000000000000 -r 6474c204b198 toolkit/modules/WindowsPrefSync.jsm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/toolkit/modules/WindowsPrefSync.jsm Wed Dec 31 06:09:35 2014 +0100 @@ -0,0 +1,173 @@ +/* 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'; + +this.EXPORTED_SYMBOLS = []; + +#ifdef XP_WIN +#ifdef MOZ_METRO + +const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} = + Components; +const PREF_BASE_KEY = "Software\\Mozilla\\Firefox\\Metro\\Prefs\\"; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); +Cu.import("resource://gre/modules/Services.jsm"); + +this.EXPORTED_SYMBOLS = [ "WindowsPrefSync" ]; + +/** + * Manages preferences that need to be pulled and pushed between Metro + * and desktop. + */ +this.WindowsPrefSync = { + init: function() { + this.pullSharedPrefs(); + this.prefListToPush.forEach(function(prefName) { + this.pushSharedPref(prefName); + Services.prefs.addObserver(prefName, this, false); + }, this); + }, + + uninit: function() { + this.prefListToPush.forEach(function(prefName) { + Services.prefs.removeObserver(prefName, this); + }, this); + }, + + /** + * Returns the list of prefs that should be pushed for the current + * environment. + */ + get prefListToPush() { + return !Services.metro.immersive ? this.desktopControlledPrefs : + this.metroControlledPrefs; + }, + + /** + * Returns the list of prefs that should be pulled for the current + * environment. + */ + get prefListToPull() { + return Services.metro.immersive ? this.desktopControlledPrefs : + this.metroControlledPrefs; + }, + + /** + * The following preferences will be pushed to registry from Desktop + * Firefox and pulled in from Metro Firefox. + * + * app.update.* prefs are because Metro shares an installation directory with + * Firefox, and the options for these are only present in the Desktop options. + * + * browser.sessionstore.resume_session_once is mainly for the switch to Metro + * and switch to Desktop feature. + * + * browser.startup.page - if a desktop Firefox user wants her/his sessions + * to always restore, we need to honor that in metro Firefox as well. + */ + desktopControlledPrefs: ["app.update.auto", + "app.update.enabled", + "app.update.service.enabled", + "app.update.metro.enabled", + "browser.sessionstore.resume_session_once", + "browser.startup.page"], + + /** + * Returns the base path where registry sync prefs are stored. + */ + get prefRegistryPath() { + let profileService = Cc["@mozilla.org/toolkit/profile-service;1"]. + createInstance(Ci.nsIToolkitProfileService); + return PREF_BASE_KEY + profileService.selectedProfile.name + "\\"; + }, + + /** + * The following preferences will be pushed to registry from Metro + * Firefox and pulled in from Desktop Firefox. + * + * browser.sessionstore.resume_session_once is mainly for the switch to Metro + * and switch to Desktop feature. + */ + metroControlledPrefs: ["browser.sessionstore.resume_session_once"], + + /** + * Observes preference changes and writes them to the registry, only + * the list of preferences initialized will be observed + */ + observe: function (aSubject, aTopic, aPrefName) { + if (aTopic != "nsPref:changed") + return; + + this.pushSharedPref(aPrefName); + }, + + /** + * Writes the pref to HKCU in the registry and adds a pref-observer to keep + * the registry in sync with changes to the value. + */ + pushSharedPref : function(aPrefName) { + let registry = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + try { + var prefType = Services.prefs.getPrefType(aPrefName); + let prefFunc; + if (prefType == Ci.nsIPrefBranch.PREF_INT) + prefFunc = "getIntPref"; + else if (prefType == Ci.nsIPrefBranch.PREF_BOOL) + prefFunc = "getBoolPref"; + else if (prefType == Ci.nsIPrefBranch.PREF_STRING) + prefFunc = "getCharPref"; + else + throw "Unsupported pref type"; + + let prefValue = Services.prefs[prefFunc](aPrefName); + registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + this.prefRegistryPath + prefType, Ci.nsIWindowsRegKey.ACCESS_WRITE); + // Always write as string, but the registry subfolder will determine + // how Metro interprets that string value. + registry.writeStringValue(aPrefName, prefValue); + } catch (ex) { + Cu.reportError("Couldn't push pref " + aPrefName + ": " + ex); + } finally { + registry.close(); + } + }, + + /** + * Pulls in all shared prefs from the registry + */ + pullSharedPrefs: function() { + function pullSharedPrefType(prefType, prefFunc) { + try { + registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER, + self.prefRegistryPath + prefType, + Ci.nsIWindowsRegKey.ACCESS_ALL); + for (let i = 0; i < registry.valueCount; i++) { + let prefName = registry.getValueName(i); + let prefValue = registry.readStringValue(prefName); + if (prefType == Ci.nsIPrefBranch.PREF_BOOL) { + prefValue = prefValue == "true"; + } + if (self.prefListToPull.indexOf(prefName) != -1) { + Services.prefs[prefFunc](prefName, prefValue); + } + } + } catch (ex) { + dump("Could not pull for prefType " + prefType + ": " + ex + "\n"); + } finally { + registry.close(); + } + } + let self = this; + let registry = Cc["@mozilla.org/windows-registry-key;1"]. + createInstance(Ci.nsIWindowsRegKey); + pullSharedPrefType(Ci.nsIPrefBranch.PREF_INT, "setIntPref"); + pullSharedPrefType(Ci.nsIPrefBranch.PREF_BOOL, "setBoolPref"); + pullSharedPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref"); + } +}; +#endif +#endif