2014-06-25 09:12:07 +04:00
|
|
|
/* -*- indent-tabs-mode: nil; js-indent-level: 2 -*-
|
2009-08-31 20:32:05 +04:00
|
|
|
* vim: sw=2 ts=2 sts=2 et filetype=javascript
|
2012-05-21 15:12:37 +04:00
|
|
|
* 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/. */
|
2007-05-16 03:27:40 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Utilities for JavaScript components loaded by the JS component
|
|
|
|
* loader.
|
|
|
|
*
|
|
|
|
* Import into a JS component using
|
2007-07-15 01:43:35 +04:00
|
|
|
* 'Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");'
|
2007-05-16 03:27:40 +04:00
|
|
|
*
|
2007-06-21 08:53:35 +04:00
|
|
|
* Exposing a JS 'class' as a component using these utility methods consists
|
|
|
|
* of several steps:
|
|
|
|
* 0. Import XPCOMUtils, as described above.
|
|
|
|
* 1. Declare the 'class' (or multiple classes) implementing the component(s):
|
|
|
|
* function MyComponent() {
|
|
|
|
* // constructor
|
|
|
|
* }
|
|
|
|
* MyComponent.prototype = {
|
|
|
|
* // properties required for XPCOM registration:
|
|
|
|
* classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
|
|
|
|
*
|
|
|
|
* // [optional] custom factory (an object implementing nsIFactory). If not
|
|
|
|
* // provided, the default factory is used, which returns
|
2007-07-19 00:19:05 +04:00
|
|
|
* // |(new MyComponent()).QueryInterface(iid)| in its createInstance().
|
2007-08-24 04:21:10 +04:00
|
|
|
* _xpcom_factory: { ... },
|
|
|
|
*
|
2010-07-14 21:09:42 +04:00
|
|
|
* // QueryInterface implementation, e.g. using the generateQI helper
|
|
|
|
* QueryInterface: XPCOMUtils.generateQI(
|
|
|
|
* [Components.interfaces.nsIObserver,
|
|
|
|
* Components.interfaces.nsIMyInterface,
|
|
|
|
* "nsIFoo",
|
|
|
|
* "nsIBar" ]),
|
|
|
|
*
|
2011-05-25 12:46:51 +04:00
|
|
|
* // [optional] classInfo implementation, e.g. using the generateCI helper.
|
|
|
|
* // Will be automatically returned from QueryInterface if that was
|
|
|
|
* // generated with the generateQI helper.
|
|
|
|
* classInfo: XPCOMUtils.generateCI(
|
|
|
|
* {classID: Components.ID("{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"),
|
|
|
|
* contractID: "@example.com/xxx;1",
|
|
|
|
* classDescription: "unique text description",
|
|
|
|
* interfaces: [Components.interfaces.nsIObserver,
|
|
|
|
* Components.interfaces.nsIMyInterface,
|
|
|
|
* "nsIFoo",
|
|
|
|
* "nsIBar"],
|
|
|
|
* flags: Ci.nsIClassInfo.SINGLETON}),
|
|
|
|
*
|
2010-07-14 21:09:42 +04:00
|
|
|
* // The following properties were used prior to Mozilla 2, but are no
|
|
|
|
* // longer supported. They may still be included for compatibility with
|
|
|
|
* // prior versions of XPCOMUtils. In Mozilla 2, this information is
|
|
|
|
* // included in the .manifest file which registers this JS component.
|
|
|
|
* classDescription: "unique text description",
|
|
|
|
* contractID: "@example.com/xxx;1",
|
|
|
|
*
|
2007-08-24 04:21:10 +04:00
|
|
|
* // [optional] an array of categories to register this component in.
|
|
|
|
* _xpcom_categories: [{
|
|
|
|
* // Each object in the array specifies the parameters to pass to
|
|
|
|
* // nsICategoryManager.addCategoryEntry(). 'true' is passed for
|
|
|
|
* // both aPersist and aReplace params.
|
|
|
|
* category: "some-category",
|
|
|
|
* // optional, defaults to the object's classDescription
|
|
|
|
* entry: "entry name",
|
|
|
|
* // optional, defaults to the object's contractID (unless
|
|
|
|
* // 'service' is specified)
|
|
|
|
* value: "...",
|
|
|
|
* // optional, defaults to false. When set to true, and only if 'value'
|
|
|
|
* // is not specified, the concatenation of the string "service," and the
|
|
|
|
* // object's contractID is passed as aValue parameter of addCategoryEntry.
|
2010-05-22 12:41:00 +04:00
|
|
|
* service: true,
|
|
|
|
* // optional, it can be an array of applications' IDs in the form:
|
|
|
|
* // [ "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}", ... ]
|
|
|
|
* // If defined the component will be registered in this category only for
|
|
|
|
* // the provided applications.
|
|
|
|
* apps: [...]
|
2007-08-24 04:21:10 +04:00
|
|
|
* }],
|
2007-06-21 08:53:35 +04:00
|
|
|
*
|
|
|
|
* // ...component implementation...
|
|
|
|
* };
|
|
|
|
*
|
|
|
|
* 2. Create an array of component constructors (like the one
|
|
|
|
* created in step 1):
|
|
|
|
* var components = [MyComponent];
|
|
|
|
*
|
2010-07-14 21:09:42 +04:00
|
|
|
* 3. Define the NSGetFactory entry point:
|
2012-10-31 20:13:28 +04:00
|
|
|
* this.NSGetFactory = XPCOMUtils.generateNSGetFactory(components);
|
2007-05-16 03:27:40 +04:00
|
|
|
*/
|
|
|
|
|
2007-06-21 08:53:35 +04:00
|
|
|
|
2012-10-31 20:13:28 +04:00
|
|
|
this.EXPORTED_SYMBOLS = [ "XPCOMUtils" ];
|
2007-05-16 03:27:40 +04:00
|
|
|
|
2009-08-31 20:32:05 +04:00
|
|
|
const Cc = Components.classes;
|
2007-06-21 08:53:35 +04:00
|
|
|
const Ci = Components.interfaces;
|
2007-09-19 02:11:31 +04:00
|
|
|
const Cr = Components.results;
|
2011-03-30 21:40:47 +04:00
|
|
|
const Cu = Components.utils;
|
2007-06-21 08:53:35 +04:00
|
|
|
|
2012-10-31 20:13:28 +04:00
|
|
|
this.XPCOMUtils = {
|
2007-06-21 08:53:35 +04:00
|
|
|
/**
|
|
|
|
* Generate a QueryInterface implementation. The returned function must be
|
|
|
|
* assigned to the 'QueryInterface' property of a JS object. When invoked on
|
|
|
|
* that object, it checks if the given iid is listed in the |interfaces|
|
|
|
|
* param, and if it is, returns |this| (the object it was called on).
|
2011-05-25 12:46:51 +04:00
|
|
|
* If the JS object has a classInfo property it'll be returned for the
|
|
|
|
* nsIClassInfo IID, generateCI can be used to generate the classInfo
|
|
|
|
* property.
|
2007-06-21 08:53:35 +04:00
|
|
|
*/
|
2009-12-16 10:25:38 +03:00
|
|
|
generateQI: function XPCU_generateQI(interfaces) {
|
2009-06-16 03:06:20 +04:00
|
|
|
/* Note that Ci[Ci.x] == Ci.x for all x */
|
2014-07-17 09:45:29 +04:00
|
|
|
let a = [];
|
|
|
|
if (interfaces) {
|
|
|
|
for (let i = 0; i < interfaces.length; i++) {
|
|
|
|
let iface = interfaces[i];
|
2017-07-21 04:38:14 +03:00
|
|
|
let name = (iface && iface.name) || String(iface);
|
|
|
|
if (name in Ci) {
|
|
|
|
a.push(name);
|
2014-07-17 09:45:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return makeQI(a);
|
2007-06-21 08:53:35 +04:00
|
|
|
},
|
2007-05-16 03:27:40 +04:00
|
|
|
|
2011-05-25 12:46:51 +04:00
|
|
|
/**
|
|
|
|
* Generate a ClassInfo implementation for a component. The returned object
|
|
|
|
* must be assigned to the 'classInfo' property of a JS object. The first and
|
|
|
|
* only argument should be an object that contains a number of optional
|
|
|
|
* properties: "interfaces", "contractID", "classDescription", "classID" and
|
|
|
|
* "flags". The values of the properties will be returned as the values of the
|
|
|
|
* various properties of the nsIClassInfo implementation.
|
|
|
|
*/
|
|
|
|
generateCI: function XPCU_generateCI(classInfo)
|
|
|
|
{
|
|
|
|
if (QueryInterface in classInfo)
|
|
|
|
throw Error("In generateCI, don't use a component for generating classInfo");
|
|
|
|
/* Note that Ci[Ci.x] == Ci.x for all x */
|
2014-07-17 09:45:29 +04:00
|
|
|
let _interfaces = [];
|
|
|
|
for (let i = 0; i < classInfo.interfaces.length; i++) {
|
|
|
|
let iface = classInfo.interfaces[i];
|
|
|
|
if (Ci[iface]) {
|
|
|
|
_interfaces.push(Ci[iface]);
|
|
|
|
}
|
|
|
|
}
|
2011-05-25 12:46:51 +04:00
|
|
|
return {
|
|
|
|
getInterfaces: function XPCU_getInterfaces(countRef) {
|
|
|
|
countRef.value = _interfaces.length;
|
|
|
|
return _interfaces;
|
|
|
|
},
|
2015-10-18 18:01:58 +03:00
|
|
|
getScriptableHelper: function XPCU_getScriptableHelper() {
|
|
|
|
return null;
|
|
|
|
},
|
2011-05-25 12:46:51 +04:00
|
|
|
contractID: classInfo.contractID,
|
|
|
|
classDescription: classInfo.classDescription,
|
|
|
|
classID: classInfo.classID,
|
|
|
|
flags: classInfo.flags,
|
|
|
|
QueryInterface: this.generateQI([Ci.nsIClassInfo])
|
|
|
|
};
|
|
|
|
},
|
|
|
|
|
2007-05-16 03:27:40 +04:00
|
|
|
/**
|
2010-06-21 22:29:32 +04:00
|
|
|
* Generate a NSGetFactory function given an array of components.
|
2007-05-16 03:27:40 +04:00
|
|
|
*/
|
2010-06-21 22:29:32 +04:00
|
|
|
generateNSGetFactory: function XPCU_generateNSGetFactory(componentsArray) {
|
|
|
|
let classes = {};
|
2014-07-17 09:45:29 +04:00
|
|
|
for (let i = 0; i < componentsArray.length; i++) {
|
|
|
|
let component = componentsArray[i];
|
2010-06-28 05:05:47 +04:00
|
|
|
if (!(component.prototype.classID instanceof Components.ID))
|
|
|
|
throw Error("In generateNSGetFactory, classID missing or incorrect for component " + component);
|
|
|
|
|
2010-06-21 22:29:32 +04:00
|
|
|
classes[component.prototype.classID] = this._getFactory(component);
|
2007-06-21 08:53:35 +04:00
|
|
|
}
|
2010-06-21 22:29:32 +04:00
|
|
|
return function NSGetFactory(cid) {
|
|
|
|
let cidstring = cid.toString();
|
|
|
|
if (cidstring in classes)
|
|
|
|
return classes[cidstring];
|
|
|
|
throw Cr.NS_ERROR_FACTORY_NOT_REGISTERED;
|
2010-05-22 12:41:00 +04:00
|
|
|
}
|
2007-05-16 03:27:40 +04:00
|
|
|
},
|
|
|
|
|
2009-08-31 20:32:05 +04:00
|
|
|
/**
|
|
|
|
* Defines a getter on a specified object that will be created upon first use.
|
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
|
|
|
* @param aName
|
|
|
|
* The name of the getter to define on aObject.
|
|
|
|
* @param aLambda
|
|
|
|
* A function that returns what the getter should return. This will
|
|
|
|
* only ever be called once.
|
|
|
|
*/
|
|
|
|
defineLazyGetter: function XPCU_defineLazyGetter(aObject, aName, aLambda)
|
|
|
|
{
|
2012-09-25 19:04:25 +04:00
|
|
|
Object.defineProperty(aObject, aName, {
|
|
|
|
get: function () {
|
2015-02-28 18:17:43 +03:00
|
|
|
// Redefine this accessor property as a data property.
|
|
|
|
// Delete it first, to rule out "too much recursion" in case aObject is
|
|
|
|
// a proxy whose defineProperty handler might unwittingly trigger this
|
|
|
|
// getter again.
|
2012-09-25 19:04:25 +04:00
|
|
|
delete aObject[aName];
|
2015-02-28 18:17:43 +03:00
|
|
|
let value = aLambda.apply(aObject);
|
|
|
|
Object.defineProperty(aObject, aName, {
|
|
|
|
value,
|
|
|
|
writable: true,
|
|
|
|
configurable: true,
|
|
|
|
enumerable: true
|
|
|
|
});
|
|
|
|
return value;
|
2012-09-25 19:04:25 +04:00
|
|
|
},
|
|
|
|
configurable: true,
|
|
|
|
enumerable: true
|
2009-08-31 20:32:05 +04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-07-23 01:17:54 +03:00
|
|
|
/**
|
|
|
|
* Defines a getter on a specified object for a script. The script will not
|
|
|
|
* be loaded until first use.
|
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
2017-07-23 01:17:56 +03:00
|
|
|
* @param aNames
|
2017-07-23 01:17:54 +03:00
|
|
|
* The name of the getter to define on aObject for the script.
|
2017-07-23 01:17:56 +03:00
|
|
|
* This can be a string if the script exports only one symbol,
|
|
|
|
* or an array of strings if the script can be first accessed
|
|
|
|
* from several different symbols.
|
2017-07-23 01:17:54 +03:00
|
|
|
* @param aResource
|
|
|
|
* The URL used to obtain the script.
|
|
|
|
*/
|
2017-07-23 01:17:56 +03:00
|
|
|
defineLazyScriptGetter: function XPCU_defineLazyScriptGetter(aObject, aNames,
|
2017-07-23 01:17:54 +03:00
|
|
|
aResource)
|
|
|
|
{
|
2017-07-23 01:17:56 +03:00
|
|
|
if (!Array.isArray(aNames)) {
|
|
|
|
aNames = [aNames];
|
|
|
|
}
|
|
|
|
for (let name of aNames) {
|
|
|
|
Object.defineProperty(aObject, name, {
|
|
|
|
get: function() {
|
|
|
|
for (let n of aNames) {
|
|
|
|
delete aObject[n];
|
|
|
|
}
|
|
|
|
Services.scriptloader.loadSubScript(aResource, aObject);
|
|
|
|
return aObject[name];
|
|
|
|
},
|
|
|
|
configurable: true,
|
|
|
|
enumerable: true
|
|
|
|
});
|
|
|
|
}
|
2017-07-23 01:17:54 +03:00
|
|
|
},
|
|
|
|
|
2009-08-31 20:32:05 +04:00
|
|
|
/**
|
|
|
|
* Defines a getter on a specified object for a service. The service will not
|
|
|
|
* be obtained until first use.
|
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
|
|
|
* @param aName
|
|
|
|
* The name of the getter to define on aObject for the service.
|
|
|
|
* @param aContract
|
|
|
|
* The contract used to obtain the service.
|
|
|
|
* @param aInterfaceName
|
|
|
|
* The name of the interface to query the service to.
|
|
|
|
*/
|
|
|
|
defineLazyServiceGetter: function XPCU_defineLazyServiceGetter(aObject, aName,
|
|
|
|
aContract,
|
|
|
|
aInterfaceName)
|
|
|
|
{
|
|
|
|
this.defineLazyGetter(aObject, aName, function XPCU_serviceLambda() {
|
2010-06-23 23:19:18 +04:00
|
|
|
return Cc[aContract].getService(Ci[aInterfaceName]);
|
2009-08-31 20:32:05 +04:00
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2017-08-09 23:06:43 +03:00
|
|
|
/**
|
|
|
|
* Defines a lazy service getter on a specified object for each
|
|
|
|
* property in the given object.
|
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
|
|
|
* @param aServices
|
|
|
|
* An object with a property for each service to be
|
|
|
|
* imported, where the property name is the name of the
|
|
|
|
* symbol to define, and the value is a 2-element array
|
|
|
|
* containing the contract ID and the interface name of the
|
|
|
|
* service, as passed to defineLazyServiceGetter.
|
|
|
|
*/
|
|
|
|
defineLazyServiceGetters: function XPCU_defineLazyServiceGetters(
|
|
|
|
aObject, aServices)
|
|
|
|
{
|
|
|
|
for (let [name, service] of Object.entries(aServices)) {
|
|
|
|
// Note: This is hot code, and cross-compartment array wrappers
|
|
|
|
// are not JIT-friendly to destructuring or spread operators, so
|
|
|
|
// we need to use indexed access instead.
|
|
|
|
this.defineLazyServiceGetter(aObject, name, service[0], service[1]);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2011-03-30 21:40:47 +04:00
|
|
|
/**
|
|
|
|
* Defines a getter on a specified object for a module. The module will not
|
2015-06-15 20:16:00 +03:00
|
|
|
* be imported until first use. The getter allows to execute setup and
|
|
|
|
* teardown code (e.g. to register/unregister to services) and accepts
|
|
|
|
* a proxy object which acts on behalf of the module until it is imported.
|
2011-03-30 21:40:47 +04:00
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
|
|
|
* @param aName
|
|
|
|
* The name of the getter to define on aObject for the module.
|
|
|
|
* @param aResource
|
|
|
|
* The URL used to obtain the module.
|
|
|
|
* @param aSymbol
|
|
|
|
* The name of the symbol exported by the module.
|
|
|
|
* This parameter is optional and defaults to aName.
|
2015-06-15 20:16:00 +03:00
|
|
|
* @param aPreLambda
|
|
|
|
* A function that is executed when the proxy is set up.
|
|
|
|
* This will only ever be called once.
|
|
|
|
* @param aPostLambda
|
|
|
|
* A function that is executed when the module has been imported to
|
|
|
|
* run optional teardown procedures on the proxy object.
|
|
|
|
* This will only ever be called once.
|
|
|
|
* @param aProxy
|
|
|
|
* An object which acts on behalf of the module to be imported until
|
|
|
|
* the module has been imported.
|
2011-03-30 21:40:47 +04:00
|
|
|
*/
|
2015-06-15 20:16:00 +03:00
|
|
|
defineLazyModuleGetter: function XPCU_defineLazyModuleGetter(
|
|
|
|
aObject, aName, aResource, aSymbol,
|
|
|
|
aPreLambda, aPostLambda, aProxy)
|
2011-03-30 21:40:47 +04:00
|
|
|
{
|
2018-01-18 06:20:16 +03:00
|
|
|
if (arguments.length == 3) {
|
|
|
|
return ChromeUtils.defineModuleGetter(aObject, aName, aResource);
|
|
|
|
}
|
|
|
|
|
2015-06-15 20:16:00 +03:00
|
|
|
let proxy = aProxy || {};
|
|
|
|
|
|
|
|
if (typeof(aPreLambda) === "function") {
|
|
|
|
aPreLambda.apply(proxy);
|
|
|
|
}
|
|
|
|
|
2017-08-27 03:34:08 +03:00
|
|
|
this.defineLazyGetter(aObject, aName, function XPCU_moduleLambda() {
|
|
|
|
var temp = {};
|
2014-05-19 21:12:49 +04:00
|
|
|
try {
|
2018-01-25 09:04:59 +03:00
|
|
|
Cu.import(aResource, temp);
|
2015-06-15 20:16:00 +03:00
|
|
|
|
|
|
|
if (typeof(aPostLambda) === "function") {
|
|
|
|
aPostLambda.apply(proxy);
|
|
|
|
}
|
2014-05-19 21:12:49 +04:00
|
|
|
} catch (ex) {
|
2014-05-22 03:48:19 +04:00
|
|
|
Cu.reportError("Failed to load module " + aResource + ".");
|
2014-05-19 21:12:49 +04:00
|
|
|
throw ex;
|
|
|
|
}
|
2017-08-27 03:34:08 +03:00
|
|
|
return temp[aSymbol || aName];
|
|
|
|
});
|
2011-03-30 21:40:47 +04:00
|
|
|
},
|
|
|
|
|
2017-08-09 23:06:43 +03:00
|
|
|
/**
|
|
|
|
* Defines a lazy module getter on a specified object for each
|
|
|
|
* property in the given object.
|
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
|
|
|
* @param aModules
|
|
|
|
* An object with a property for each module property to be
|
|
|
|
* imported, where the property name is the name of the
|
|
|
|
* imported symbol and the value is the module URI.
|
|
|
|
*/
|
|
|
|
defineLazyModuleGetters: function XPCU_defineLazyModuleGetters(
|
|
|
|
aObject, aModules)
|
|
|
|
{
|
|
|
|
for (let [name, module] of Object.entries(aModules)) {
|
2018-01-18 06:20:16 +03:00
|
|
|
ChromeUtils.defineModuleGetter(aObject, name, module);
|
2017-08-09 23:06:43 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2016-04-15 02:37:30 +03:00
|
|
|
/**
|
|
|
|
* Defines a getter on a specified object for preference value. The
|
|
|
|
* preference is read the first time that the property is accessed,
|
|
|
|
* and is thereafter kept up-to-date using a preference observer.
|
|
|
|
*
|
|
|
|
* @param aObject
|
|
|
|
* The object to define the lazy getter on.
|
|
|
|
* @param aName
|
|
|
|
* The name of the getter property to define on aObject.
|
|
|
|
* @param aPreference
|
|
|
|
* The name of the preference to read.
|
|
|
|
* @param aDefaultValue
|
|
|
|
* The default value to use, if the preference is not defined.
|
2016-09-28 17:33:20 +03:00
|
|
|
* @param aOnUpdate
|
|
|
|
* A function to call upon update. Receives as arguments
|
|
|
|
* `(aPreference, previousValue, newValue)`
|
2017-04-29 08:39:13 +03:00
|
|
|
* @param aTransform
|
|
|
|
* An optional function to transform the value. If provided,
|
|
|
|
* this function receives the new preference value as an argument
|
|
|
|
* and its return value is used by the getter.
|
2016-04-15 02:37:30 +03:00
|
|
|
*/
|
|
|
|
defineLazyPreferenceGetter: function XPCU_defineLazyPreferenceGetter(
|
2016-09-28 17:33:20 +03:00
|
|
|
aObject, aName, aPreference,
|
|
|
|
aDefaultValue = null,
|
2017-04-29 08:39:13 +03:00
|
|
|
aOnUpdate = null,
|
|
|
|
aTransform = val => val)
|
2016-04-15 02:37:30 +03:00
|
|
|
{
|
|
|
|
// Note: We need to keep a reference to this observer alive as long
|
|
|
|
// as aObject is alive. This means that all of our getters need to
|
|
|
|
// explicitly close over the variable that holds the object, and we
|
|
|
|
// cannot define a value in place of a getter after we read the
|
|
|
|
// preference.
|
|
|
|
let observer = {
|
2017-08-09 09:19:06 +03:00
|
|
|
QueryInterface: XPCU_lazyPreferenceObserverQI,
|
2016-04-15 02:37:30 +03:00
|
|
|
|
|
|
|
value: undefined,
|
|
|
|
|
|
|
|
observe(subject, topic, data) {
|
|
|
|
if (data == aPreference) {
|
2016-09-28 17:33:20 +03:00
|
|
|
if (aOnUpdate) {
|
|
|
|
let previous = this.value;
|
|
|
|
|
|
|
|
// Fetch and cache value.
|
|
|
|
this.value = undefined;
|
|
|
|
let latest = lazyGetter();
|
2017-04-29 06:24:34 +03:00
|
|
|
aOnUpdate(data, previous, latest);
|
2016-09-28 17:33:20 +03:00
|
|
|
} else {
|
|
|
|
|
|
|
|
// Empty cache, next call to the getter will cause refetch.
|
|
|
|
this.value = undefined;
|
|
|
|
}
|
2016-04-15 02:37:30 +03:00
|
|
|
}
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
let defineGetter = get => {
|
|
|
|
Object.defineProperty(aObject, aName, {
|
|
|
|
configurable: true,
|
|
|
|
enumerable: true,
|
|
|
|
get,
|
|
|
|
});
|
|
|
|
};
|
|
|
|
|
|
|
|
function lazyGetter() {
|
|
|
|
if (observer.value === undefined) {
|
2017-07-29 00:04:47 +03:00
|
|
|
let prefValue;
|
|
|
|
switch (Services.prefs.getPrefType(aPreference)) {
|
|
|
|
case Ci.nsIPrefBranch.PREF_STRING:
|
|
|
|
prefValue = Services.prefs.getStringPref(aPreference);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Ci.nsIPrefBranch.PREF_INT:
|
|
|
|
prefValue = Services.prefs.getIntPref(aPreference);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Ci.nsIPrefBranch.PREF_BOOL:
|
|
|
|
prefValue = Services.prefs.getBoolPref(aPreference);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case Ci.nsIPrefBranch.PREF_INVALID:
|
|
|
|
prefValue = aDefaultValue;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
// This should never happen.
|
|
|
|
throw new Error(`Error getting pref ${aPreference}; its value's type is ` +
|
|
|
|
`${Services.prefs.getPrefType(aPreference)}, which I don't ` +
|
|
|
|
`know how to handle.`);
|
|
|
|
}
|
|
|
|
|
|
|
|
observer.value = aTransform(prefValue);
|
2016-04-15 02:37:30 +03:00
|
|
|
}
|
|
|
|
return observer.value;
|
|
|
|
}
|
|
|
|
|
|
|
|
defineGetter(() => {
|
|
|
|
Services.prefs.addObserver(aPreference, observer, true);
|
|
|
|
|
|
|
|
defineGetter(lazyGetter);
|
|
|
|
return lazyGetter();
|
|
|
|
});
|
|
|
|
},
|
|
|
|
|
2010-02-10 04:05:31 +03:00
|
|
|
/**
|
|
|
|
* Helper which iterates over a nsISimpleEnumerator.
|
|
|
|
* @param e The nsISimpleEnumerator to iterate over.
|
|
|
|
* @param i The expected interface for each element.
|
|
|
|
*/
|
2016-07-12 03:33:06 +03:00
|
|
|
IterSimpleEnumerator: function* XPCU_IterSimpleEnumerator(e, i)
|
2010-02-10 04:05:31 +03:00
|
|
|
{
|
|
|
|
while (e.hasMoreElements())
|
|
|
|
yield e.getNext().QueryInterface(i);
|
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Helper which iterates over a string enumerator.
|
|
|
|
* @param e The string enumerator (nsIUTF8StringEnumerator or
|
|
|
|
* nsIStringEnumerator) over which to iterate.
|
|
|
|
*/
|
2016-07-12 03:33:06 +03:00
|
|
|
IterStringEnumerator: function* XPCU_IterStringEnumerator(e)
|
2010-02-10 04:05:31 +03:00
|
|
|
{
|
|
|
|
while (e.hasMore())
|
|
|
|
yield e.getNext();
|
|
|
|
},
|
|
|
|
|
2016-07-12 03:33:06 +03:00
|
|
|
/**
|
|
|
|
* Helper which iterates over the entries in a category.
|
|
|
|
* @param aCategory The name of the category over which to iterate.
|
|
|
|
*/
|
|
|
|
enumerateCategoryEntries: function* XPCOMUtils_enumerateCategoryEntries(aCategory)
|
|
|
|
{
|
|
|
|
let category = this.categoryManager.enumerateCategory(aCategory);
|
|
|
|
for (let entry of this.IterSimpleEnumerator(category, Ci.nsISupportsCString)) {
|
|
|
|
yield [entry.data, this.categoryManager.getCategoryEntry(aCategory, entry.data)];
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
2007-06-21 08:53:35 +04:00
|
|
|
/**
|
|
|
|
* Returns an nsIFactory for |component|.
|
|
|
|
*/
|
2009-12-16 10:25:38 +03:00
|
|
|
_getFactory: function XPCOMUtils__getFactory(component) {
|
2007-06-21 08:53:35 +04:00
|
|
|
var factory = component.prototype._xpcom_factory;
|
|
|
|
if (!factory) {
|
|
|
|
factory = {
|
|
|
|
createInstance: function(outer, iid) {
|
2007-09-19 02:11:31 +04:00
|
|
|
if (outer)
|
|
|
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
2007-06-21 08:53:35 +04:00
|
|
|
return (new component()).QueryInterface(iid);
|
2015-02-18 21:42:28 +03:00
|
|
|
},
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
|
2007-06-21 08:53:35 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return factory;
|
2011-04-14 02:10:13 +04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Allows you to fake a relative import. Expects the global object from the
|
|
|
|
* module that's calling us, and the relative filename that we wish to import.
|
|
|
|
*/
|
2014-04-23 02:37:26 +04:00
|
|
|
importRelative: function XPCOMUtils__importRelative(that, path, scope) {
|
2011-04-14 02:10:13 +04:00
|
|
|
if (!("__URI__" in that))
|
|
|
|
throw Error("importRelative may only be used from a JSM, and its first argument "+
|
|
|
|
"must be that JSM's global object (hint: use this)");
|
2017-07-22 04:01:42 +03:00
|
|
|
|
|
|
|
Cu.importGlobalProperties(["URL"]);
|
2018-01-25 09:04:59 +03:00
|
|
|
Components.utils.import(new URL(path, that.__URI__).href, scope || that);
|
2011-04-14 02:10:13 +04:00
|
|
|
},
|
2012-02-07 13:17:42 +04:00
|
|
|
|
|
|
|
/**
|
|
|
|
* generates a singleton nsIFactory implementation that can be used as
|
|
|
|
* the _xpcom_factory of the component.
|
|
|
|
* @param aServiceConstructor
|
|
|
|
* Constructor function of the component.
|
|
|
|
*/
|
|
|
|
generateSingletonFactory:
|
|
|
|
function XPCOMUtils_generateSingletonFactory(aServiceConstructor) {
|
|
|
|
return {
|
|
|
|
_instance: null,
|
|
|
|
createInstance: function XPCU_SF_createInstance(aOuter, aIID) {
|
|
|
|
if (aOuter !== null) {
|
|
|
|
throw Cr.NS_ERROR_NO_AGGREGATION;
|
|
|
|
}
|
|
|
|
if (this._instance === null) {
|
|
|
|
this._instance = new aServiceConstructor();
|
|
|
|
}
|
|
|
|
return this._instance.QueryInterface(aIID);
|
|
|
|
},
|
|
|
|
lockFactory: function XPCU_SF_lockFactory(aDoLock) {
|
|
|
|
throw Cr.NS_ERROR_NOT_IMPLEMENTED;
|
|
|
|
},
|
|
|
|
QueryInterface: XPCOMUtils.generateQI([Ci.nsIFactory])
|
|
|
|
};
|
|
|
|
},
|
2015-10-07 15:03:21 +03:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Defines a non-writable property on an object.
|
|
|
|
*/
|
|
|
|
defineConstant: function XPCOMUtils__defineConstant(aObj, aName, aValue) {
|
|
|
|
Object.defineProperty(aObj, aName, {
|
|
|
|
value: aValue,
|
|
|
|
enumerable: true,
|
|
|
|
writable: false
|
|
|
|
});
|
|
|
|
},
|
2007-05-16 03:27:40 +04:00
|
|
|
};
|
2007-06-21 08:53:35 +04:00
|
|
|
|
2017-08-09 09:19:06 +03:00
|
|
|
var XPCU_lazyPreferenceObserverQI = XPCOMUtils.generateQI([Ci.nsIObserver, Ci.nsISupportsWeakReference]);
|
|
|
|
|
2018-01-25 09:04:59 +03:00
|
|
|
XPCOMUtils.defineLazyModuleGetter(this, "Services",
|
|
|
|
"resource://gre/modules/Services.jsm");
|
2016-04-15 02:37:30 +03:00
|
|
|
|
2016-07-12 03:33:06 +03:00
|
|
|
XPCOMUtils.defineLazyServiceGetter(XPCOMUtils, "categoryManager",
|
|
|
|
"@mozilla.org/categorymanager;1",
|
|
|
|
"nsICategoryManager");
|
|
|
|
|
2007-06-21 08:53:35 +04:00
|
|
|
/**
|
|
|
|
* Helper for XPCOMUtils.generateQI to avoid leaks - see bug 381651#c1
|
|
|
|
*/
|
|
|
|
function makeQI(interfaceNames) {
|
|
|
|
return function XPCOMUtils_QueryInterface(iid) {
|
|
|
|
if (iid.equals(Ci.nsISupports))
|
|
|
|
return this;
|
2011-05-25 12:46:51 +04:00
|
|
|
if (iid.equals(Ci.nsIClassInfo) && "classInfo" in this)
|
|
|
|
return this.classInfo;
|
2014-07-17 09:45:29 +04:00
|
|
|
for (let i = 0; i < interfaceNames.length; i++) {
|
|
|
|
if (Ci[interfaceNames[i]].equals(iid))
|
2007-06-21 08:53:35 +04:00
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
2007-09-19 02:11:31 +04:00
|
|
|
throw Cr.NS_ERROR_NO_INTERFACE;
|
2007-06-21 08:53:35 +04:00
|
|
|
};
|
|
|
|
}
|