toolkit/modules/WindowsPrefSync.jsm

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/toolkit/modules/WindowsPrefSync.jsm	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,173 @@
     1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.7 +
     1.8 +'use strict';
     1.9 +
    1.10 +this.EXPORTED_SYMBOLS = [];
    1.11 +
    1.12 +#ifdef XP_WIN
    1.13 +#ifdef MOZ_METRO
    1.14 +
    1.15 +const {classes: Cc, interfaces: Ci, results: Cr, utils: Cu, manager: Cm} =
    1.16 +  Components;
    1.17 +const PREF_BASE_KEY = "Software\\Mozilla\\Firefox\\Metro\\Prefs\\";
    1.18 +
    1.19 +Cu.import("resource://gre/modules/XPCOMUtils.jsm");
    1.20 +Cu.import("resource://gre/modules/Services.jsm");
    1.21 +
    1.22 +this.EXPORTED_SYMBOLS = [ "WindowsPrefSync" ];
    1.23 +
    1.24 +/**
    1.25 + * Manages preferences that need to be pulled and pushed between Metro
    1.26 + * and desktop.
    1.27 + */
    1.28 +this.WindowsPrefSync = {
    1.29 +  init: function() {
    1.30 +    this.pullSharedPrefs();
    1.31 +    this.prefListToPush.forEach(function(prefName) {
    1.32 +      this.pushSharedPref(prefName);
    1.33 +      Services.prefs.addObserver(prefName, this, false);
    1.34 +    }, this);
    1.35 +  },
    1.36 +
    1.37 +  uninit: function() {
    1.38 +    this.prefListToPush.forEach(function(prefName) {
    1.39 +        Services.prefs.removeObserver(prefName, this);
    1.40 +    }, this);
    1.41 +  },
    1.42 +
    1.43 +  /**
    1.44 +   * Returns the list of prefs that should be pushed for the current
    1.45 +   * environment.
    1.46 +   */
    1.47 +  get prefListToPush() {
    1.48 +    return !Services.metro.immersive ? this.desktopControlledPrefs :
    1.49 +      this.metroControlledPrefs;
    1.50 +  },
    1.51 +
    1.52 +  /**
    1.53 +   * Returns the list of prefs that should be pulled for the current
    1.54 +   * environment.
    1.55 +   */
    1.56 +  get prefListToPull() {
    1.57 +    return Services.metro.immersive ? this.desktopControlledPrefs :
    1.58 +      this.metroControlledPrefs;
    1.59 +  },
    1.60 +
    1.61 +  /**
    1.62 +   * The following preferences will be pushed to registry from Desktop
    1.63 +   * Firefox and pulled in from Metro Firefox.
    1.64 +   *
    1.65 +   * app.update.* prefs are because Metro shares an installation directory with
    1.66 +   * Firefox, and the options for these are only present in the Desktop options.
    1.67 +   *
    1.68 +   * browser.sessionstore.resume_session_once is mainly for the switch to Metro
    1.69 +   * and switch to Desktop feature.
    1.70 +   *
    1.71 +   * browser.startup.page - if a desktop Firefox user wants her/his sessions
    1.72 +   * to always restore, we need to honor that in metro Firefox as well.
    1.73 +   */
    1.74 +  desktopControlledPrefs: ["app.update.auto",
    1.75 +    "app.update.enabled",
    1.76 +    "app.update.service.enabled",
    1.77 +    "app.update.metro.enabled",
    1.78 +    "browser.sessionstore.resume_session_once",
    1.79 +    "browser.startup.page"],
    1.80 +
    1.81 +  /**
    1.82 +   * Returns the base path where registry sync prefs are stored.
    1.83 +   */
    1.84 +  get prefRegistryPath() {
    1.85 +    let profileService = Cc["@mozilla.org/toolkit/profile-service;1"].
    1.86 +      createInstance(Ci.nsIToolkitProfileService);
    1.87 +    return PREF_BASE_KEY + profileService.selectedProfile.name + "\\";
    1.88 +  },
    1.89 +
    1.90 +  /**
    1.91 +   * The following preferences will be pushed to registry from Metro
    1.92 +   * Firefox and pulled in from Desktop Firefox.
    1.93 +   *
    1.94 +   * browser.sessionstore.resume_session_once is mainly for the switch to Metro
    1.95 +   * and switch to Desktop feature.
    1.96 +   */
    1.97 +  metroControlledPrefs: ["browser.sessionstore.resume_session_once"],
    1.98 +
    1.99 +  /**
   1.100 +   * Observes preference changes and writes them to the registry, only
   1.101 +   * the list of preferences initialized will be observed
   1.102 +   */
   1.103 +  observe: function (aSubject, aTopic, aPrefName) {
   1.104 +    if (aTopic != "nsPref:changed")
   1.105 +      return;
   1.106 +
   1.107 +    this.pushSharedPref(aPrefName);
   1.108 +  },
   1.109 +
   1.110 +  /**
   1.111 +   * Writes the pref to HKCU in the registry and adds a pref-observer to keep
   1.112 +   * the registry in sync with changes to the value.
   1.113 +   */
   1.114 +  pushSharedPref : function(aPrefName) {
   1.115 +    let registry = Cc["@mozilla.org/windows-registry-key;1"].
   1.116 +      createInstance(Ci.nsIWindowsRegKey);
   1.117 +    try {
   1.118 +      var prefType = Services.prefs.getPrefType(aPrefName);
   1.119 +      let prefFunc;
   1.120 +      if (prefType == Ci.nsIPrefBranch.PREF_INT)
   1.121 +        prefFunc = "getIntPref";
   1.122 +      else if (prefType == Ci.nsIPrefBranch.PREF_BOOL)
   1.123 +        prefFunc = "getBoolPref";
   1.124 +      else if (prefType == Ci.nsIPrefBranch.PREF_STRING)
   1.125 +        prefFunc = "getCharPref";
   1.126 +      else
   1.127 +        throw "Unsupported pref type";
   1.128 +
   1.129 +      let prefValue = Services.prefs[prefFunc](aPrefName);
   1.130 +      registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
   1.131 +        this.prefRegistryPath + prefType, Ci.nsIWindowsRegKey.ACCESS_WRITE);
   1.132 +      // Always write as string, but the registry subfolder will determine
   1.133 +      // how Metro interprets that string value.
   1.134 +      registry.writeStringValue(aPrefName, prefValue);
   1.135 +    } catch (ex) {
   1.136 +      Cu.reportError("Couldn't push pref " + aPrefName + ": " + ex);
   1.137 +    } finally {
   1.138 +      registry.close();
   1.139 +    }
   1.140 +  },
   1.141 +
   1.142 +  /**
   1.143 +   * Pulls in all shared prefs from the registry
   1.144 +   */
   1.145 +  pullSharedPrefs: function() {
   1.146 +    function pullSharedPrefType(prefType, prefFunc) {
   1.147 +      try {
   1.148 +        registry.create(Ci.nsIWindowsRegKey.ROOT_KEY_CURRENT_USER,
   1.149 +          self.prefRegistryPath + prefType,
   1.150 +          Ci.nsIWindowsRegKey.ACCESS_ALL);
   1.151 +        for (let i = 0; i < registry.valueCount; i++) {
   1.152 +          let prefName = registry.getValueName(i);
   1.153 +          let prefValue = registry.readStringValue(prefName);
   1.154 +          if (prefType == Ci.nsIPrefBranch.PREF_BOOL) {
   1.155 +            prefValue = prefValue == "true";
   1.156 +          }
   1.157 +          if (self.prefListToPull.indexOf(prefName) != -1) {
   1.158 +            Services.prefs[prefFunc](prefName, prefValue);
   1.159 +          }
   1.160 +        }
   1.161 +      } catch (ex) {
   1.162 +        dump("Could not pull for prefType " + prefType + ": " + ex + "\n");
   1.163 +      } finally {
   1.164 +        registry.close();
   1.165 +      }
   1.166 +    }
   1.167 +    let self = this;
   1.168 +    let registry = Cc["@mozilla.org/windows-registry-key;1"].
   1.169 +      createInstance(Ci.nsIWindowsRegKey);
   1.170 +    pullSharedPrefType(Ci.nsIPrefBranch.PREF_INT, "setIntPref");
   1.171 +    pullSharedPrefType(Ci.nsIPrefBranch.PREF_BOOL, "setBoolPref");
   1.172 +    pullSharedPrefType(Ci.nsIPrefBranch.PREF_STRING, "setCharPref");
   1.173 +  }
   1.174 +};
   1.175 +#endif
   1.176 +#endif

mercurial