diff --git a/common/content/commandline.js b/common/content/commandline.js index c916dd30..a1d7f0b2 100644 --- a/common/content/commandline.js +++ b/common/content/commandline.js @@ -152,6 +152,14 @@ const CommandWidgets = Class("CommandWidgets", { return this.commandbar; } }); + + let fontSize = util.computedStyle(document.getElementById(config.mainWindowId)).fontSize; + styles.registerSheet("chrome://dactyl/skin/dactyl.css"); + styles.system.add("font-size", "chrome://dactyl/content/buffer.xhtml", + "body { font-size: " + fontSize + "; }"); + }, + cleanup: function cleanup() { + styles.unregisterSheet("chrome://dactyl/skin/dactyl.css"); }, addElement: function (obj) { const self = this; @@ -1810,12 +1818,6 @@ const CommandLine = Module("commandline", { host && (!item.domains || !item.domains.some(function (d) util.isSubdomain(d, host)))); } }); - }, - styles: function () { - let fontSize = util.computedStyle(document.getElementById(config.mainWindowId)).fontSize; - styles.registerSheet("chrome://dactyl/skin/dactyl.css"); - styles.system.add("font-size", "chrome://dactyl/content/buffer.xhtml", - "body { font-size: " + fontSize + "; }"); } }); diff --git a/common/content/configbase.js b/common/content/configbase.js index 459cfda0..0c27691e 100644 --- a/common/content/configbase.js +++ b/common/content/configbase.js @@ -65,6 +65,7 @@ const ConfigBase = Class(ModuleBase, { * must be strings as entered via :set. */ defaults: { guioptions: "rb" }, + cleanups: {}, /** * @property {[["string", "string", "function"]]} An array of diff --git a/common/content/dactyl.js b/common/content/dactyl.js index dbebe862..0ed9f543 100644 --- a/common/content/dactyl.js +++ b/common/content/dactyl.js @@ -19,7 +19,7 @@ const EVAL_ERROR = "__dactyl_eval_error"; const EVAL_RESULT = "__dactyl_eval_result"; const EVAL_STRING = "__dactyl_eval_string"; -const Dactyl = Module("dactyl", { +const Dactyl = Module("dactyl", XPCOM(Ci.nsISupportsWeakReference, ModuleBase), { init: function () { window.dactyl = this; // cheap attempt at compatibility @@ -30,6 +30,7 @@ const Dactyl = Module("dactyl", { this.indices = {}; this.modules = modules; this.observers = {}; + util.addObserver(this); this.commands["dactyl.help"] = function (event) { let elem = event.originalTarget; @@ -37,6 +38,18 @@ const Dactyl = Module("dactyl", { }; }, + observe: { + "dactyl-cleanup": function () { + for (let [, mod] in iter(array(values(modules)).reverse())) + if (mod instanceof ModuleBase) { + if ("cleanup" in mod) + mod.cleanup(); + if ("destroy" in mod) + mod.destroy(); + } + } + }, + /** @property {string} The name of the current user profile. */ profileName: Class.memoize(function () { // NOTE: services.profile.selectedProfile.name doesn't return @@ -52,6 +65,12 @@ const Dactyl = Module("dactyl", { return "unknown"; }), + cleanup: function () { + delete window.dactyl; + delete window.modules; + delete window.liberator; + }, + destroy: function () { autocommands.trigger("LeavePre", {}); storage.saveAll(); @@ -1315,6 +1334,12 @@ const Dactyl = Module("dactyl", { options.add(["guioptions", "go"], "Show or hide certain GUI elements like the menu or toolbar", "charlist", config.defaults.guioptions || "", { + + // FIXME: cleanup + cleanupValue: config.cleanups.guioptions || + "r" + [k for ([k, v] in iter(groups[1].opts)) + if (!document.getElementById(v[1][0]).collapsed)].join(""), + completer: function (context) array(groups).map(function (g) [[k, v[0]] for ([k, v] in Iterator(g.opts))]).flatten(), setter: function (value) { diff --git a/common/content/dactyl.xul b/common/content/dactyl.xul index 20fc35f8..5d6d6b62 100644 --- a/common/content/dactyl.xul +++ b/common/content/dactyl.xul @@ -8,8 +8,6 @@ given in the LICENSE.txt file included with this file. --> - - ]> diff --git a/common/content/options.js b/common/content/options.js index 843c413c..34ce63bf 100644 --- a/common/content/options.js +++ b/common/content/options.js @@ -281,6 +281,8 @@ const Option = Class("Option", { */ description: "", + cleanupValue: null, + /** * @property {function(CompletionContext, Args)} This option's completer. * @see CompletionContext @@ -637,6 +639,12 @@ const Options = Module("options", { }, window); }, + cleanup: function cleanup() { + for (let opt in this) + if (opt.cleanupValue != null) + opt.value = opt.parse(opt.cleanupValue); + }, + /** @property {Iterator(Option)} @private */ __iterator__: function () values(this._options.sort(function (a, b) String.localeCompare(a.name, b.name))), diff --git a/common/content/tabs.js b/common/content/tabs.js index db906ff0..df717760 100644 --- a/common/content/tabs.js +++ b/common/content/tabs.js @@ -36,6 +36,15 @@ const Tabs = Module("tabs", { }; }, + cleanup: function cleanup() { + for (let [i, tab] in Iterator(this.allTabs)) { + function node(clas) document.getAnonymousElementByAttribute(tab, "class", clas); + for (let elem in values(["dactyl-tab-icon-number", "dactyl-tab-number"].map(node))) + if (elem) + elem.parentNode.parentNode.removeChild(elem.parentNode); + } + }, + _updateTabCount: function () { if (dactyl.has("Gecko2")) for (let [i, tab] in Iterator(this.visibleTabs)) { @@ -43,15 +52,15 @@ const Tabs = Module("tabs", { if (!node("dactyl-tab-number")) { let nodes = {}; let dom = util.xmlToDom(.*, document, nodes); let img = node("tab-icon-image"); img.parentNode.appendChild(dom); - tab.__defineGetter__("ordinal", function () Number(nodes.icon.value)); - tab.__defineSetter__("ordinal", function (i) nodes.icon.value = nodes.label.textContent = i); + tab.__defineGetter__("dactylOrdinal", function () Number(nodes.icon.value)); + tab.__defineSetter__("dactylOrdinal", function (i) nodes.icon.value = nodes.label.textContent = i); } - tab.ordinal = i + 1; + tab.dactylOrdinal = i + 1; } statusline.updateTabCount(true); }, diff --git a/common/modules/base.jsm b/common/modules/base.jsm index 19529316..e2abf9d4 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -98,6 +98,7 @@ let loaded = {}; let currentModule; function defineModule(name, params) { let module = Cu.getGlobalForObject ? Cu.getGlobalForObject(params) : params.__parent__; + defineModule.globals.push(module); module.NAME = name; module.EXPORTED_SYMBOLS = params.exports || []; defineModule.loadLog.push("defineModule " + name); @@ -114,6 +115,7 @@ function defineModule(name, params) { currentModule = module; } +defineModule.globals = []; defineModule.loadLog = []; Object.defineProperty(defineModule.loadLog, "push", { value: function (val) { defineModule.dump(val + "\n"); this[this.length] = val; } diff --git a/common/modules/bookmarkcache.jsm b/common/modules/bookmarkcache.jsm index e3d972b6..e230a077 100644 --- a/common/modules/bookmarkcache.jsm +++ b/common/modules/bookmarkcache.jsm @@ -42,6 +42,10 @@ const BookmarkCache = Module("BookmarkCache", XPCOM(Ci.nsINavBookmarkObserver), services.bookmarks.addObserver(this, false); }, + cleanup: function cleanup() { + services.bookmarks.removeObserver(this); + }, + __iterator__: function () (val for ([, val] in Iterator(bookmarkcache.bookmarks))), get bookmarks() Class.replaceProperty(this, "bookmarks", this.load()), diff --git a/common/modules/prefs.jsm b/common/modules/prefs.jsm index d5c935e3..63ebac52 100644 --- a/common/modules/prefs.jsm +++ b/common/modules/prefs.jsm @@ -28,6 +28,10 @@ const Prefs = Module("prefs", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference this.restore(); }, + cleanup: function cleanup() { + this._branch.removeObserver("", this); + }, + observe: { "nsPref:changed": function (subject, data) { let observers = this._observers[data]; diff --git a/common/modules/util.jsm b/common/modules/util.jsm index 0d52730a..b2193827 100644 --- a/common/modules/util.jsm +++ b/common/modules/util.jsm @@ -961,9 +961,21 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) observe: { "dactyl-cleanup": function () { - for (let module in values(defineModule.modules)) - if (module.cleanup) - module.cleanup(); + // Let window cleanup functions run synchronously before we + // destroy modules. + util.timeout(function () { + for (let module in values(defineModule.modules)) + if (module.cleanup) + module.cleanup(); + + let getOwnPropertyNames = Object.getOwnPropertyNames; + for each (let global in defineModule.globals.reverse()) + for each (let k in getOwnPropertyNames(global)) + try { + delete global[k]; + } + catch (e) {} + }); }, "toplevel-window-ready": function (window, data) { window.addEventListener("DOMContentLoaded", wrapCallback(function listener(event) { @@ -1141,6 +1153,7 @@ const Util = Module("Util", XPCOM([Ci.nsIObserver, Ci.nsISupportsWeakReference]) } catch (e) { this.dump(e); + try { util.dump(e.stack) } catch (e) {} } }, diff --git a/common/skin/dactyl.css b/common/skin/dactyl.css index 62c92ca1..ae35761b 100644 --- a/common/skin/dactyl.css +++ b/common/skin/dactyl.css @@ -89,8 +89,8 @@ window[dactyl|highlight~=Bell] > * { } [dactyl|highlight~=CmdLine] { - background: inherit; - color: inherit; + background: inherit !important; + color: inherit !important; } [dactyl|highlight~=CmdLine], [dactyl|highlight~=CmdLine] > [dactyl|highlight~=CmdLine] { @@ -123,8 +123,8 @@ statusbarpanel { } #dactyl-statusline-field-url { - background-color: inherit; - color: inherit; + background-color: inherit !important; + color: inherit !important; } /* no longer at the window's bottom right corner */ @@ -141,8 +141,8 @@ statusbarpanel { padding: 0px; } .dactyl-commandline-command { - background-color: inherit; - color: inherit; + background-color: inherit !important; + color: inherit !important; margin: 0px; } .dactyl-commandline-command html|*:focus {