]> git.donarmstrong.com Git - dactyl.git/blobdiff - common/bootstrap.js
Imported Upstream version 1.1+hg7904
[dactyl.git] / common / bootstrap.js
index 4d5dcca634a9e863b5afeebe2ab5fb48e325b6e5..a5b25deb4d640ea7d1432f9993385e81caf76530 100755 (executable)
@@ -1,4 +1,4 @@
-// Copyright (c) 2010-2011 by Kris Maglione <maglione.k@gmail.com>
+// Copyright (c) 2010-2014 by Kris Maglione <maglione.k@gmail.com>
 //
 // This work is licensed for reuse under an MIT license. Details are
 // given in the LICENSE.txt file included with this file.
@@ -21,6 +21,8 @@ var { AddonManager } = module("resource://gre/modules/AddonManager.jsm");
 var { XPCOMUtils }   = module("resource://gre/modules/XPCOMUtils.jsm");
 var { Services }     = module("resource://gre/modules/Services.jsm");
 
+var Timer = Components.Constructor("@mozilla.org/timer;1", "nsITimer", "initWithCallback");
+
 const resourceProto = Services.io.getProtocolHandler("resource")
                               .QueryInterface(Ci.nsIResProtocolHandler);
 const categoryManager = Cc["@mozilla.org/categorymanager;1"].getService(Ci.nsICategoryManager);
@@ -57,13 +59,11 @@ let addonData = null;
 let basePath = null;
 let bootstrap;
 let bootstrap_jsm;
-let categories = [];
 let components = {};
-let resources = [];
 let getURI = null;
 
 let JSMLoader = {
-    SANDBOX: Cu.nukeSandbox && false,
+    SANDBOX: Cu.nukeSandbox,
 
     get addon() addon,
 
@@ -134,7 +134,7 @@ let JSMLoader = {
                     return this.modules[name] = this.globals[uri];
 
                 this.globals[uri] = this.modules[name];
-                bootstrap_jsm.loadSubScript(url, this.modules[name]);
+                bootstrap_jsm.loadSubScript(url, this.modules[name], "UTF-8");
                 return;
             }
             catch (e) {
@@ -172,7 +172,17 @@ let JSMLoader = {
         let module = this.modules[name];
         if (target)
             for each (let symbol in module.EXPORTED_SYMBOLS)
-                target[symbol] = module[symbol];
+                try {
+                    Object.defineProperty(target, symbol, {
+                        configurable: true,
+                        enumerable: true,
+                        writable: true,
+                        value: module[symbol]
+                    });
+                }
+                catch (e) {
+                    target[symbol] = module[symbol];
+                }
 
         return module;
     },
@@ -180,8 +190,8 @@ let JSMLoader = {
     // Cuts down on stupid, fscking url mangling.
     get loadSubScript() bootstrap_jsm.loadSubScript,
 
-    cleanup: function unregister() {
-        for each (let factory in this.factories.splice(0))
+    cleanup: function cleanup() {
+        for (let factory of this.factories.splice(0))
             manager.unregisterFactory(factory.classID, factory);
     },
 
@@ -215,35 +225,29 @@ let JSMLoader = {
 function init() {
     debug("bootstrap: init");
 
-    let manifestURI = getURI("chrome.manifest");
-    let manifest = httpGet(manifestURI)
-            .responseText
-            .replace(/#(resource)#/g, "$1")
-            .replace(/^\s*|\s*$|#.*/g, "")
-            .replace(/^\s*\n/gm, "");
-
-    for each (let line in manifest.split("\n")) {
-        let fields = line.split(/\s+/);
-        switch (fields[0]) {
-        case "category":
-            categoryManager.addCategoryEntry(fields[1], fields[2], fields[3], false, true);
-            categories.push([fields[1], fields[2]]);
-            break;
-        case "component":
-            components[fields[1]] = new FactoryProxy(getURI(fields[2]).spec, fields[1]);
-            break;
-        case "contract":
-            components[fields[2]].contractID = fields[1];
-            break;
-
-        case "resource":
-            moduleName = moduleName || fields[1];
-            resources.push(fields[1]);
-            resourceProto.setSubstitution(fields[1], getURI(fields[2]));
-        }
+    let manifest = JSON.parse(httpGet(getURI("config.json"))
+                                .responseText);
+
+    if (!manifest.categories)
+        manifest.categories = [];
+
+    for (let [classID, { contract, path, categories }] of Iterator(manifest.components || {})) {
+        components[classID] = new FactoryProxy(getURI(path).spec, classID, contract);
+        if (categories)
+            for (let [category, id] in Iterator(categories))
+                manifest.categories.push([category, id, contract]);
+    }
+
+    for (let [category, id, value] of manifest.categories)
+        categoryManager.addCategoryEntry(category, id, value,
+                                         false, true);
+
+    for (let [pkg, path] in Iterator(manifest.resources || {})) {
+        moduleName = moduleName || pkg;
+        resourceProto.setSubstitution(pkg, getURI(path));
     }
 
-    JSMLoader.config = JSON.parse(httpGet("resource://dactyl-local/config.json").responseText);
+    JSMLoader.config = manifest;
 
     bootstrap_jsm = module(BOOTSTRAP);
     if (!JSMLoader.SANDBOX)
@@ -255,22 +259,13 @@ function init() {
     }
     bootstrap.require = JSMLoader.load("base").require;
 
-    // Flush the cache if necessary, just to be paranoid
     let pref = "extensions.dactyl.cacheFlushCheck";
     let val  = addon.version;
     if (!Services.prefs.prefHasUserValue(pref) || Services.prefs.getCharPref(pref) != val) {
         var cacheFlush = true;
-        Services.obs.notifyObservers(null, "startupcache-invalidate", "");
         Services.prefs.setCharPref(pref, val);
     }
 
-    try {
-        //JSMLoader.load("disable-acr").init(addon.id);
-    }
-    catch (e) {
-        reportError(e);
-    }
-
     Services.obs.notifyObservers(null, "dactyl-rehash", null);
 
     JSMLoader.bootstrap = global;
@@ -326,7 +321,9 @@ function updateVersion() {
         // Disable automatic updates when switching to nightlies,
         // restore the default action when switching to stable.
         if (!config.lastVersion || isDev(config.lastVersion) != isDev(addon.version))
-            addon.applyBackgroundUpdates = AddonManager[isDev(addon.version) ? "AUTOUPDATE_DISABLE" : "AUTOUPDATE_DEFAULT"];
+            addon.applyBackgroundUpdates =
+                AddonManager[isDev(addon.version) ? "AUTOUPDATE_DISABLE"
+                                                  : "AUTOUPDATE_DEFAULT"];
     }
     catch (e) {
         reportError(e);
@@ -381,9 +378,10 @@ function startup(data, reason) {
  * @param {string} url The URL of the module housing the real factory.
  * @param {string} classID The CID of the class this factory represents.
  */
-function FactoryProxy(url, classID) {
+function FactoryProxy(url, classID, contractID) {
     this.url = url;
     this.classID = Components.ID(classID);
+    this.contractID = contractID;
 }
 FactoryProxy.prototype = {
     QueryInterface: XPCOMUtils.generateQI(Ci.nsIFactory),
@@ -405,18 +403,12 @@ FactoryProxy.prototype = {
     }
 }
 
+var timer;
 function shutdown(data, reason) {
     let strReason = reasonToString(reason);
     debug("bootstrap: shutdown " + strReason);
 
     if (reason != APP_SHUTDOWN) {
-        try {
-            //JSMLoader.load("disable-acr").cleanup(addon.id);
-        }
-        catch (e) {
-            reportError(e);
-        }
-
         if (~[ADDON_UPGRADE, ADDON_DOWNGRADE, ADDON_UNINSTALL].indexOf(reason))
             Services.obs.notifyObservers(null, "dactyl-purge", null);
 
@@ -426,17 +418,20 @@ function shutdown(data, reason) {
         JSMLoader.atexit(strReason);
         JSMLoader.cleanup(strReason);
 
-        if (JSMLoader.SANDBOX)
-            Cu.nukeSandbox(bootstrap);
-        bootstrap_jsm.require = null;
-        Cu.unload(BOOTSTRAP);
-        bootstrap = null;
-        bootstrap_jsm = null;
-
-        for each (let [category, entry] in categories)
+        for each (let [category, entry] in JSMLoader.config.categories)
             categoryManager.deleteCategoryEntry(category, entry, false);
-        for each (let resource in resources)
+        for (let resource in JSMLoader.config.resources)
             resourceProto.setSubstitution(resource, null);
+
+        timer = Timer(() => {
+            bootstrap_jsm.require = null;
+            if (JSMLoader.SANDBOX)
+                Cu.nukeSandbox(bootstrap);
+            else
+                Cu.unload(BOOTSTRAP);
+            bootstrap = null;
+            bootstrap_jsm = null;
+        }, 5000, Ci.nsITimer.TYPE_ONE_SHOT);
     }
 }