X-Git-Url: https://git.donarmstrong.com/?a=blobdiff_plain;f=common%2Fmodules%2Fbase.jsm;fp=common%2Fmodules%2Fbase.jsm;h=bc767f68887cf45147ac8e9787c6a21b5c2e33d0;hb=9044153cb63835e39b9de8ec4ade237c03e3888a;hp=d07ba1230732b78e0f69eb944b84e8017c91f3fc;hpb=70740024f9c028c1fd63e1a1850ab062ff956054;p=dactyl.git diff --git a/common/modules/base.jsm b/common/modules/base.jsm index d07ba12..bc767f6 100644 --- a/common/modules/base.jsm +++ b/common/modules/base.jsm @@ -2,22 +2,21 @@ // // This work is licensed for reuse under an MIT license. Details are // given in the LICENSE.txt file included with this file. -"use strict"; +/* use strict */ -var Cc = Components.classes; -var Ci = Components.interfaces; -var Cr = Components.results; -var Cu = Components.utils; +var { classes: Cc, interfaces: Ci, results: Cr, utils: Cu } = Components; +Cu.import("resource://dactyl/bootstrap.jsm"); Cu.import("resource://gre/modules/XPCOMUtils.jsm"); try { var ctypes; - Components.utils.import("resource://gre/modules/ctypes.jsm"); + Cu.import("resource://gre/modules/ctypes.jsm"); } catch (e) {} let objproto = Object.prototype; -let { __lookupGetter__, __lookupSetter__, hasOwnProperty, propertyIsEnumerable } = objproto; +let { __lookupGetter__, __lookupSetter__, __defineGetter__, __defineSetter__, + hasOwnProperty, propertyIsEnumerable } = objproto; if (typeof XPCSafeJSObjectWrapper === "undefined") this.XPCSafeJSObjectWrapper = XPCNativeWrapper; @@ -47,15 +46,15 @@ if (!Object.defineProperty) } catch (e if e instanceof TypeError) {} else { - objproto.__defineGetter__.call(obj, prop, function () value); + __defineGetter__.call(obj, prop, function () value); if (desc.writable) - objproto.__defineSetter__.call(obj, prop, function (val) { value = val; }); + __defineSetter__.call(obj, prop, function (val) { value = val; }); } if ("get" in desc) - objproto.__defineGetter__.call(obj, prop, desc.get); + __defineGetter__.call(obj, prop, desc.get); if ("set" in desc) - objproto.__defineSetter__.call(obj, prop, desc.set); + __defineSetter__.call(obj, prop, desc.set); } catch (e) { throw e.stack ? e : Error(e); @@ -123,6 +122,14 @@ if (!Object.keys) let getGlobalForObject = Cu.getGlobalForObject || function (obj) obj.__parent__; +let jsmodules = { + lazyRequire: function lazyRequire(module, names, target) { + for each (let name in names) + memoize(target || this, name, function (name) require(module)[name]); + } +}; +jsmodules.jsmodules = jsmodules; + let use = {}; let loaded = {}; let currentModule; @@ -133,17 +140,17 @@ function defineModule(name, params, module) { module.NAME = name; module.EXPORTED_SYMBOLS = params.exports || []; - defineModule.loadLog.push("defineModule " + name); + if (!~module.EXPORTED_SYMBOLS.indexOf("File")) + delete module.File; + + defineModule.loadLog.push("[Begin " + name + "]"); + defineModule.prefix += " "; + for (let [, mod] in Iterator(params.require || [])) - require(module, mod); + require(module, mod, null, name); + module.__proto__ = jsmodules; - for (let [, mod] in Iterator(params.use || [])) - if (loaded.hasOwnProperty(mod)) - require(module, mod, "use"); - else { - use[mod] = use[mod] || []; - use[mod].push(module); - } + module._lastModule = currentModule; currentModule = module; module.startTime = Date.now(); } @@ -151,20 +158,21 @@ function defineModule(name, params, module) { defineModule.loadLog = []; Object.defineProperty(defineModule.loadLog, "push", { value: function (val) { + val = defineModule.prefix + val; if (false) defineModule.dump(val + "\n"); this[this.length] = Date.now() + " " + val; } }); +defineModule.prefix = ""; defineModule.dump = function dump_() { let msg = Array.map(arguments, function (msg) { if (loaded.util && typeof msg == "object") msg = util.objectToString(msg); return msg; }).join(", "); - let name = loaded.config ? config.name : "dactyl"; dump(String.replace(msg, /\n?$/, "\n") - .replace(/^./gm, name + ": $&")); + .replace(/^./gm, JSMLoader.name + ": $&")); } defineModule.modules = []; defineModule.time = function time(major, minor, func, self) { @@ -184,15 +192,15 @@ defineModule.time = function time(major, minor, func, self) { } function endModule() { - defineModule.loadLog.push("endModule " + currentModule.NAME); - - for (let [, mod] in Iterator(use[currentModule.NAME] || [])) - require(mod, currentModule.NAME, "use"); + defineModule.prefix = defineModule.prefix.slice(0, -2); + defineModule.loadLog.push("(End " + currentModule.NAME + ")"); loaded[currentModule.NAME] = 1; + require(jsmodules, currentModule.NAME); + currentModule = currentModule._lastModule; } -function require(obj, name, from) { +function require(obj, name, from, targetName) { try { if (arguments.length === 1) [obj, name] = [{}, obj]; @@ -200,9 +208,14 @@ function require(obj, name, from) { let caller = Components.stack.caller; if (!loaded[name]) - defineModule.loadLog.push((from || "require") + ": loading " + name + " into " + (obj.NAME || caller.filename + ":" + caller.lineNumber)); + defineModule.loadLog.push((from || "require") + ": loading " + name + + " into " + (targetName || obj.NAME || caller.filename + ":" + caller.lineNumber)); JSMLoader.load(name + ".jsm", obj); + + if (!loaded[name] && obj != jsmodules) + JSMLoader.load(name + ".jsm", jsmodules); + return obj; } catch (e) { @@ -215,25 +228,20 @@ function require(obj, name, from) { } defineModule("base", { - // sed -n 's/^(const|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt + // sed -n 's/^(const|var|function) ([a-zA-Z0-9_]+).*/ "\2",/p' base.jsm | sort | fmt exports: [ - "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", "Runnable", - "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMUtils", "XPCSafeJSObjectWrapper", - "array", "bind", "call", "callable", "ctypes", "curry", "debuggerProperties", "defineModule", - "deprecated", "endModule", "forEach", "isArray", "isGenerator", "isinstance", "isObject", - "isString", "isSubclass", "iter", "iterAll", "iterOwnProperties", "keys", "memoize", "octal", - "properties", "require", "set", "update", "values", "withCallerGlobal" - ], - use: ["config", "services", "util"] + "ErrorBase", "Cc", "Ci", "Class", "Cr", "Cu", "Module", "JSMLoader", "Object", + "Set", "Struct", "StructBase", "Timer", "UTF8", "XPCOM", "XPCOMShim", "XPCOMUtils", + "XPCSafeJSObjectWrapper", "array", "bind", "call", "callable", "ctypes", "curry", + "debuggerProperties", "defineModule", "deprecated", "endModule", "forEach", "isArray", + "isGenerator", "isinstance", "isObject", "isString", "isSubclass", "iter", "iterAll", + "iterOwnProperties", "keys", "memoize", "octal", "properties", "require", "set", "update", + "values", "withCallerGlobal" + ] }, this); -function Runnable(self, func, args) { - return { - __proto__: Runnable.prototype, - run: function () { func.apply(self, args || []); } - }; -} -Runnable.prototype.QueryInterface = XPCOMUtils.generateQI([Ci.nsIRunnable]); +this.lazyRequire("messages", ["_", "Messages"]); +this.lazyRequire("util", ["util"]); /** * Returns a list of all of the top-level properties of an object, by @@ -331,7 +339,7 @@ deprecated.warn = function warn(func, name, alternative, frame) { let filename = util.fixURI(frame.filename || "unknown"); if (!Set.add(func.seenCaller, filename)) util.dactyl(func).warn([util.urlPath(filename), frame.lineNumber, " "].join(":") - + require("messages")._("warn.deprecated", name, alternative)); + + _("warn.deprecated", name, alternative)); } /** @@ -346,6 +354,7 @@ function keys(obj) iter(function keys() { if (hasOwnProperty.call(obj, k)) yield k; }()); + /** * Iterates over all of the top-level, iterable property values of an * object. @@ -594,7 +603,7 @@ function isString(val) objproto.toString.call(val) == "[object String]"; * Returns true if and only if its sole argument may be called * as a function. This includes classes and function objects. */ -function callable(val) typeof val === "function"; +function callable(val) typeof val === "function" && !(val instanceof Ci.nsIDOMElement); function call(fn) { fn.apply(arguments[1], Array.slice(arguments, 2)); @@ -611,13 +620,13 @@ function call(fn) { */ function memoize(obj, key, getter) { if (arguments.length == 1) { - obj = update({ __proto__: obj.__proto__ }, obj); - for (let prop in Object.getOwnPropertyNames(obj)) { + let res = update(Object.create(obj), obj); + for each (let prop in Object.getOwnPropertyNames(obj)) { let get = __lookupGetter__.call(obj, prop); if (get) - memoize(obj, prop, get); + memoize(res, prop, get); } - return obj; + return res; } try { @@ -625,9 +634,15 @@ function memoize(obj, key, getter) { configurable: true, enumerable: true, - get: function g_replaceProperty() ( - Class.replaceProperty(this.instance || this, key, null), - Class.replaceProperty(this.instance || this, key, getter.call(this, key))), + get: function g_replaceProperty() { + try { + Class.replaceProperty(this.instance || this, key, null); + return Class.replaceProperty(this.instance || this, key, getter.call(this, key)); + } + catch (e) { + util.reportError(e); + } + }, set: function s_replaceProperty(val) Class.replaceProperty(this.instance || this, key, val) @@ -680,18 +695,18 @@ function update(target) { if (desc.value instanceof Class.Property) desc = desc.value.init(k, target) || desc.value; - if (typeof desc.value === "function" && target.__proto__) { - let func = desc.value.wrapped || desc.value; - if (!func.superapply) { - func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]); - func.superapply = function superapply(self, args) - let (meth = Object.getPrototypeOf(target)[k]) - meth && meth.apply(self, args); - func.supercall = function supercall(self) - func.superapply(self, Array.slice(arguments, 1)); - } - } try { + if (typeof desc.value === "function" && target.__proto__ && !(desc.value instanceof Ci.nsIDOMElement /* wtf? */)) { + let func = desc.value.wrapped || desc.value; + if (!func.superapply) { + func.__defineGetter__("super", function () Object.getPrototypeOf(target)[k]); + func.superapply = function superapply(self, args) + let (meth = Object.getPrototypeOf(target)[k]) + meth && meth.apply(self, args); + func.supercall = function supercall(self) + func.superapply(self, Array.slice(arguments, 1)); + } + } Object.defineProperty(target, k, desc); } catch (e) {} @@ -732,22 +747,26 @@ function Class() { if (callable(args[0])) superclass = args.shift(); - if (loaded.util && util.haveGecko("6.0a1")) // Bug 657418. + if (loaded.config && (config.haveGecko("5.*", "6.0") || config.haveGecko("6.*"))) // Bug 657418. var Constructor = function Constructor() { - var self = Object.create(Constructor.prototype, { - constructor: { value: Constructor }, - }); + var self = Object.create(Constructor.prototype); self.instance = self; + + if ("_metaInit_" in self && self._metaInit_) + self._metaInit_.apply(self, arguments); + var res = self.init.apply(self, arguments); return res !== undefined ? res : self; }; else var Constructor = eval(String.replace(, @@ -769,10 +788,12 @@ function Class() { } Class.extend(Constructor, superclass, args[0]); + memoize(Constructor, "closure", Class.makeClosure); update(Constructor, args[1]); + Constructor.__proto__ = superclass; - args = args.slice(2); - Array.forEach(args, function (obj) { + + args.slice(2).forEach(function (obj) { if (callable(obj)) obj = obj.prototype; update(Constructor.prototype, obj); @@ -839,7 +860,7 @@ Class.extend = function extend(subclass, superclass, overrides) { * property's value. * @returns {Class.Property} */ -Class.memoize = function memoize(getter, wait) +Class.Memoize = function Memoize(getter, wait) Class.Property({ configurable: true, enumerable: true, @@ -847,6 +868,7 @@ Class.memoize = function memoize(getter, wait) let done = false; if (wait) + // Crazy, yeah, I know. -- Kris this.get = function replace() { let obj = this.instance || this; Object.defineProperty(obj, key, { @@ -871,13 +893,34 @@ Class.memoize = function memoize(getter, wait) return this[key]; }; else - this.get = function replace() { + this.get = function g_Memoize() { let obj = this.instance || this; - Class.replaceProperty(obj, key, null); - return Class.replaceProperty(obj, key, getter.call(this, key)); + try { + Class.replaceProperty(obj, key, null); + return Class.replaceProperty(obj, key, getter.call(this, key)); + } + catch (e) { + util.reportError(e); + } }; - this.set = function replace(val) Class.replaceProperty(this.instance || this, val); + this.set = function s_Memoize(val) Class.replaceProperty(this.instance || this, key, val); + } + }); + +Class.memoize = deprecated("Class.Memoize", function memoize() Class.Memoize.apply(this, arguments)); + +/** + * Updates the given object with the object in the target class's + * prototype. + */ +Class.Update = function Update(obj) + Class.Property({ + configurable: true, + enumerable: true, + writable: true, + init: function (key, target) { + this.value = update({}, target[key], obj); } }); @@ -893,6 +936,9 @@ Class.prototype = { */ init: function c_init() {}, + get instance() ({}), + set instance(val) Class.replaceProperty(this, "instance", val), + withSavedValues: function withSavedValues(names, callback, self) { let vals = names.map(function (name) this[name], this); try { @@ -926,10 +972,14 @@ Class.prototype = { if (self.stale || util.rehashing && !isinstance(Cu.getGlobalForObject(callback), ["BackstagePass"])) return; + self.timeouts.splice(self.timeouts.indexOf(timer), 1); util.trapErrors(callback, self); } - return services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT); + let timer = services.Timer(timeout_notify, timeout || 0, services.Timer.TYPE_ONE_SHOT); + this.timeouts.push(timer); + return timer; }, + timeouts: [], /** * Updates this instance with the properties of the given objects. @@ -968,10 +1018,18 @@ Class.prototype = { catch (e) {} }, this); } + return this; }, + localizedProperties: {}, magicalProperties: {} }; +for (let name in properties(Class.prototype)) { + let desc = Object.getOwnPropertyDescriptor(Class.prototype, name); + desc.enumerable = false; + Object.defineProperty(Class.prototype, name, desc); +} + Class.makeClosure = function makeClosure() { const self = this; function closure(fn) { @@ -1015,16 +1073,35 @@ memoize(Class.prototype, "closure", Class.makeClosure); function XPCOM(interfaces, superClass) { interfaces = Array.concat(interfaces); - let shim = interfaces.reduce(function (shim, iface) shim.QueryInterface(iface), - Cc["@dactyl.googlecode.com/base/xpc-interface-shim"].createInstance()); + let shim = XPCOMShim(interfaces); + + let res = Class("XPCOM(" + interfaces + ")", superClass || Class, + update(iter([k, + v === undefined || callable(v) ? stub : v] + for ([k, v] in Iterator(shim))).toObject(), + { QueryInterface: XPCOMUtils.generateQI(interfaces) })); - let res = Class("XPCOM(" + interfaces + ")", superClass || Class, update( - iter.toObject([k, v === undefined || callable(v) ? function stub() null : v] - for ([k, v] in Iterator(shim))), - { QueryInterface: XPCOMUtils.generateQI(interfaces) })); - shim = interfaces = null; return res; } +function XPCOMShim(interfaces) { + let ip = services.InterfacePointer({ + QueryInterface: function (iid) { + if (iid.equals(Ci.nsISecurityCheckedComponent)) + throw Cr.NS_ERROR_NO_INTERFACE; + return this; + }, + getHelperForLanguage: function () null, + getInterfaces: function (count) { count.value = 0; } + }); + return (interfaces || []).reduce(function (shim, iface) shim.QueryInterface(Ci[iface]), + ip.data) +}; +let stub = Class.Property({ + configurable: true, + enumerable: false, + value: function stub() null, + writable: true +}); /** * An abstract base class for classes that wish to inherit from Error. @@ -1059,17 +1136,32 @@ var ErrorBase = Class("ErrorBase", Error, { * @returns {Class} */ function Module(name, prototype) { - let init = callable(prototype) ? 4 : 3; - const module = Class.apply(Class, Array.slice(arguments, 0, init)); - let instance = module(); - module.className = name.toLowerCase(); + try { + let init = callable(prototype) ? 4 : 3; + let proto = arguments[callable(prototype) ? 2 : 1]; - instance.INIT = update(Object.create(Module.INIT), - arguments[init] || {}); + proto._metaInit_ = function () { + delete module.prototype._metaInit_; + currentModule[name.toLowerCase()] = this; + }; - currentModule[module.className] = instance; - defineModule.modules.push(instance); - return module; + const module = Class.apply(Class, Array.slice(arguments, 0, init)); + let instance = module(); + module.className = name.toLowerCase(); + + instance.INIT = update(Object.create(Module.INIT), + arguments[init] || {}); + + currentModule[module.className] = instance; + defineModule.modules.push(instance); + return module; + } + catch (e) { + if (typeof e === "string") + e = Error(e); + + dump(e.fileName + ":" + e.lineNumber + ": " + e + "\n" + (e.stack || Error().stack)); + } } Module.INIT = { init: function Module_INIT_init(dactyl, modules, window) { @@ -1133,13 +1225,15 @@ function Struct() { }); return Struct; } -let StructBase = Class("StructBase", Array, { +var StructBase = Class("StructBase", Array, { init: function struct_init() { for (let i = 0; i < arguments.length; i++) if (arguments[i] != undefined) this[i] = arguments[i]; }, + get toStringParams() this, + clone: function struct_clone() this.constructor.apply(null, this.slice()), closure: Class.Property(Object.getOwnPropertyDescriptor(Class.prototype, "closure")), @@ -1181,7 +1275,7 @@ let StructBase = Class("StructBase", Array, { localize: function localize(key, defaultValue) { let i = this.prototype.members[key]; - Object.defineProperty(this.prototype, i, require("messages").Messages.Localized(defaultValue).init(key, this.prototype)); + Object.defineProperty(this.prototype, i, Messages.Localized(defaultValue).init(key, this.prototype)); return this; } }); @@ -1211,7 +1305,7 @@ var Timer = Class("Timer", { } catch (e) { if (typeof util === "undefined") - dump("dactyl: " + e + "\n" + (e.stack || Error().stack)); + dump(JSMLoader.name + ": " + e + "\n" + (e.stack || Error().stack)); else util.reportError(e); } @@ -1297,9 +1391,13 @@ function octal(decimal) parseInt(decimal, 8); * function. * * @param {object} obj + * @param {nsIJSIID} iface The interface to which to query all elements. * @returns {Generator} */ -function iter(obj) { +function iter(obj, iface) { + if (arguments.length == 2 && iface instanceof Ci.nsIJSIID) + return iter(obj).map(function (item) item.QueryInterface(iface)); + let args = arguments; let res = Iterator(obj);