diff options
Diffstat (limited to 'toolkit/components/exthelper')
-rw-r--r-- | toolkit/components/exthelper/extApplication.js | 719 | ||||
-rw-r--r-- | toolkit/components/exthelper/extIApplication.idl | 416 | ||||
-rw-r--r-- | toolkit/components/exthelper/moz.build | 12 |
3 files changed, 1147 insertions, 0 deletions
diff --git a/toolkit/components/exthelper/extApplication.js b/toolkit/components/exthelper/extApplication.js new file mode 100644 index 000000000..a56a04c0e --- /dev/null +++ b/toolkit/components/exthelper/extApplication.js @@ -0,0 +1,719 @@ +/* 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/. */ + +Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); +Components.utils.import("resource://gre/modules/AddonManager.jsm"); + +// ================================================= +// Console constructor +function Console() { + this._console = Components.classes["@mozilla.org/consoleservice;1"] + .getService(Ci.nsIConsoleService); +} + +// ================================================= +// Console implementation +Console.prototype = { + log: function cs_log(aMsg) { + this._console.logStringMessage(aMsg); + }, + + open: function cs_open() { + var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator); + var console = wMediator.getMostRecentWindow("global:console"); + if (!console) { + var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Ci.nsIWindowWatcher); + wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank", + "chrome,dialog=no,all", null); + } else { + // console was already open + console.focus(); + } + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIConsole]) +}; + + +// ================================================= +// EventItem constructor +function EventItem(aType, aData) { + this._type = aType; + this._data = aData; +} + +// ================================================= +// EventItem implementation +EventItem.prototype = { + _cancel: false, + + get type() { + return this._type; + }, + + get data() { + return this._data; + }, + + preventDefault: function ei_pd() { + this._cancel = true; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIEventItem]) +}; + + +// ================================================= +// Events constructor +function Events(notifier) { + this._listeners = []; + this._notifier = notifier; +} + +// ================================================= +// Events implementation +Events.prototype = { + addListener: function evts_al(aEvent, aListener) { + function hasFilter(element) { + return element.event == aEvent && element.listener == aListener; + } + + if (this._listeners.some(hasFilter)) + return; + + this._listeners.push({ + event: aEvent, + listener: aListener + }); + + if (this._notifier) { + this._notifier(aEvent, aListener); + } + }, + + removeListener: function evts_rl(aEvent, aListener) { + function hasFilter(element) { + return (element.event != aEvent) || (element.listener != aListener); + } + + this._listeners = this._listeners.filter(hasFilter); + }, + + dispatch: function evts_dispatch(aEvent, aEventItem) { + var eventItem = new EventItem(aEvent, aEventItem); + + this._listeners.forEach(function(key) { + if (key.event == aEvent) { + key.listener.handleEvent ? + key.listener.handleEvent(eventItem) : + key.listener(eventItem); + } + }); + + return !eventItem._cancel; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) +}; + +// ================================================= +// PreferenceObserver (internal class) +// +// PreferenceObserver is a global singleton which watches the browser's +// preferences and sends you events when things change. + +function PreferenceObserver() { + this._observersDict = {}; +} + +PreferenceObserver.prototype = { + /** + * Add a preference observer. + * + * @param aPrefs the nsIPrefBranch onto which we'll install our listener. + * @param aDomain the domain our listener will watch (a string). + * @param aEvent the event to listen to (you probably want "change"). + * @param aListener the function to call back when the event fires. This + * function will receive an EventData argument. + */ + addListener: function po_al(aPrefs, aDomain, aEvent, aListener) { + var root = aPrefs.root; + if (!this._observersDict[root]) { + this._observersDict[root] = {}; + } + var observer = this._observersDict[root][aDomain]; + + if (!observer) { + observer = { + events: new Events(), + observe: function po_observer_obs(aSubject, aTopic, aData) { + this.events.dispatch("change", aData); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]) + }; + observer.prefBranch = aPrefs; + observer.prefBranch.addObserver(aDomain, observer, /* ownsWeak = */ true); + + // Notice that the prefBranch keeps a weak reference to the observer; + // it's this._observersDict which keeps the observer alive. + this._observersDict[root][aDomain] = observer; + } + observer.events.addListener(aEvent, aListener); + }, + + /** + * Remove a preference observer. + * + * This function's parameters are identical to addListener's. + */ + removeListener: function po_rl(aPrefs, aDomain, aEvent, aListener) { + var root = aPrefs.root; + if (!this._observersDict[root] || + !this._observersDict[root][aDomain]) { + return; + } + var observer = this._observersDict[root][aDomain]; + observer.events.removeListener(aEvent, aListener); + + if (observer.events._listeners.length == 0) { + // nsIPrefBranch objects are not singletons -- we can have two + // nsIPrefBranch'es for the same branch. There's no guarantee that + // aPrefs is the same object as observer.prefBranch, so we have to call + // removeObserver on observer.prefBranch. + observer.prefBranch.removeObserver(aDomain, observer); + delete this._observersDict[root][aDomain]; + if (Object.keys(this._observersDict[root]).length == 0) { + delete this._observersDict[root]; + } + } + } +}; + +// ================================================= +// PreferenceBranch constructor +function PreferenceBranch(aBranch) { + if (!aBranch) + aBranch = ""; + + this._root = aBranch; + this._prefs = Components.classes["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefService) + .QueryInterface(Ci.nsIPrefBranch); + + if (aBranch) + this._prefs = this._prefs.getBranch(aBranch); + + let prefs = this._prefs; + this._events = { + addListener: function pb_al(aEvent, aListener) { + gPreferenceObserver.addListener(prefs, "", aEvent, aListener); + }, + removeListener: function pb_rl(aEvent, aListener) { + gPreferenceObserver.removeListener(prefs, "", aEvent, aListener); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) + }; +} + +// ================================================= +// PreferenceBranch implementation +PreferenceBranch.prototype = { + get root() { + return this._root; + }, + + get all() { + return this.find({}); + }, + + get events() { + return this._events; + }, + + // XXX: Disabled until we can figure out the wrapped object issues + // name: "name" or /name/ + // path: "foo.bar." or "" or /fo+\.bar/ + // type: Boolean, Number, String (getPrefType) + // locked: true, false (prefIsLocked) + // modified: true, false (prefHasUserValue) + find: function prefs_find(aOptions) { + var retVal = []; + var items = this._prefs.getChildList(""); + + for (var i = 0; i < items.length; i++) { + retVal.push(new Preference(items[i], this)); + } + + return retVal; + }, + + has: function prefs_has(aName) { + return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID); + }, + + get: function prefs_get(aName) { + return this.has(aName) ? new Preference(aName, this) : null; + }, + + getValue: function prefs_gv(aName, aValue) { + var type = this._prefs.getPrefType(aName); + + switch (type) { + case Ci.nsIPrefBranch.PREF_STRING: + aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data; + break; + case Ci.nsIPrefBranch.PREF_BOOL: + aValue = this._prefs.getBoolPref(aName); + break; + case Ci.nsIPrefBranch.PREF_INT: + aValue = this._prefs.getIntPref(aName); + break; + } + + return aValue; + }, + + setValue: function prefs_sv(aName, aValue) { + var type = aValue != null ? aValue.constructor.name : ""; + + switch (type) { + case "String": + var str = Components.classes["@mozilla.org/supports-string;1"] + .createInstance(Ci.nsISupportsString); + str.data = aValue; + this._prefs.setComplexValue(aName, Ci.nsISupportsString, str); + break; + case "Boolean": + this._prefs.setBoolPref(aName, aValue); + break; + case "Number": + this._prefs.setIntPref(aName, aValue); + break; + default: + throw ("Unknown preference value specified."); + } + }, + + reset: function prefs_reset() { + this._prefs.resetBranch(""); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIPreferenceBranch]) +}; + + +// ================================================= +// Preference constructor +function Preference(aName, aBranch) { + this._name = aName; + this._branch = aBranch; + + var self = this; + this._events = { + addListener: function pref_al(aEvent, aListener) { + gPreferenceObserver.addListener(self._branch._prefs, self._name, aEvent, aListener); + }, + removeListener: function pref_rl(aEvent, aListener) { + gPreferenceObserver.removeListener(self._branch._prefs, self._name, aEvent, aListener); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) + }; +} + +// ================================================= +// Preference implementation +Preference.prototype = { + get name() { + return this._name; + }, + + get type() { + var value = ""; + var type = this.branch._prefs.getPrefType(this._name); + + switch (type) { + case Ci.nsIPrefBranch.PREF_STRING: + value = "String"; + break; + case Ci.nsIPrefBranch.PREF_BOOL: + value = "Boolean"; + break; + case Ci.nsIPrefBranch.PREF_INT: + value = "Number"; + break; + } + + return value; + }, + + get value() { + return this.branch.getValue(this._name, null); + }, + + set value(aValue) { + return this.branch.setValue(this._name, aValue); + }, + + get locked() { + return this.branch._prefs.prefIsLocked(this.name); + }, + + set locked(aValue) { + this.branch._prefs[aValue ? "lockPref" : "unlockPref"](this.name); + }, + + get modified() { + return this.branch._prefs.prefHasUserValue(this.name); + }, + + get branch() { + return this._branch; + }, + + get events() { + return this._events; + }, + + reset: function pref_reset() { + this.branch._prefs.clearUserPref(this.name); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIPreference]) +}; + + +// ================================================= +// SessionStorage constructor +function SessionStorage() { + this._storage = {}; + this._events = new Events(); +} + +// ================================================= +// SessionStorage implementation +SessionStorage.prototype = { + get events() { + return this._events; + }, + + has: function ss_has(aName) { + return this._storage.hasOwnProperty(aName); + }, + + set: function ss_set(aName, aValue) { + this._storage[aName] = aValue; + this._events.dispatch("change", aName); + }, + + get: function ss_get(aName, aDefaultValue) { + return this.has(aName) ? this._storage[aName] : aDefaultValue; + }, + + QueryInterface : XPCOMUtils.generateQI([Ci.extISessionStorage]) +}; + +// ================================================= +// ExtensionObserver constructor (internal class) +// +// ExtensionObserver is a global singleton which watches the browser's +// extensions and sends you events when things change. + +function ExtensionObserver() { + this._eventsDict = {}; + + AddonManager.addAddonListener(this); + AddonManager.addInstallListener(this); +} + +// ================================================= +// ExtensionObserver implementation (internal class) +ExtensionObserver.prototype = { + onDisabling: function eo_onDisabling(addon, needsRestart) { + this._dispatchEvent(addon.id, "disable"); + }, + + onEnabling: function eo_onEnabling(addon, needsRestart) { + this._dispatchEvent(addon.id, "enable"); + }, + + onUninstalling: function eo_onUninstalling(addon, needsRestart) { + this._dispatchEvent(addon.id, "uninstall"); + }, + + onOperationCancelled: function eo_onOperationCancelled(addon) { + this._dispatchEvent(addon.id, "cancel"); + }, + + onInstallEnded: function eo_onInstallEnded(install, addon) { + this._dispatchEvent(addon.id, "upgrade"); + }, + + addListener: function eo_al(aId, aEvent, aListener) { + var events = this._eventsDict[aId]; + if (!events) { + events = new Events(); + this._eventsDict[aId] = events; + } + events.addListener(aEvent, aListener); + }, + + removeListener: function eo_rl(aId, aEvent, aListener) { + var events = this._eventsDict[aId]; + if (!events) { + return; + } + events.removeListener(aEvent, aListener); + if (events._listeners.length == 0) { + delete this._eventsDict[aId]; + } + }, + + _dispatchEvent: function eo_dispatchEvent(aId, aEvent) { + var events = this._eventsDict[aId]; + if (events) { + events.dispatch(aEvent, aId); + } + } +}; + +// ================================================= +// Extension constructor +function Extension(aItem) { + this._item = aItem; + this._firstRun = false; + this._prefs = new PreferenceBranch("extensions." + this.id + "."); + this._storage = new SessionStorage(); + + let id = this.id; + this._events = { + addListener: function ext_events_al(aEvent, aListener) { + gExtensionObserver.addListener(id, aEvent, aListener); + }, + removeListener: function ext_events_rl(aEvent, aListener) { + gExtensionObserver.addListener(id, aEvent, aListener); + }, + QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) + }; + + var installPref = "install-event-fired"; + if (!this._prefs.has(installPref)) { + this._prefs.setValue(installPref, true); + this._firstRun = true; + } +} + +// ================================================= +// Extension implementation +Extension.prototype = { + get id() { + return this._item.id; + }, + + get name() { + return this._item.name; + }, + + get enabled() { + return this._item.isActive; + }, + + get version() { + return this._item.version; + }, + + get firstRun() { + return this._firstRun; + }, + + get storage() { + return this._storage; + }, + + get prefs() { + return this._prefs; + }, + + get events() { + return this._events; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIExtension]) +}; + + +// ================================================= +// Extensions constructor +function Extensions(addons) { + this._cache = {}; + + addons.forEach(function (addon) { + this._cache[addon.id] = new Extension(addon); + }, this); +} + +// ================================================= +// Extensions implementation +Extensions.prototype = { + get all() { + return this.find({}); + }, + + // XXX: Disabled until we can figure out the wrapped object issues + // id: "some@id" or /id/ + // name: "name" or /name/ + // version: "1.0.1" + // minVersion: "1.0" + // maxVersion: "2.0" + find: function exts_find(aOptions) { + return Object.keys(this._cache).map(id => this._cache[id]); + }, + + has: function exts_has(aId) { + return aId in this._cache; + }, + + get: function exts_get(aId) { + return this.has(aId) ? this._cache[aId] : null; + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIExtensions]) +}; + +// ================================================= +// Application globals + +var gExtensionObserver = new ExtensionObserver(); +var gPreferenceObserver = new PreferenceObserver(); + +// ================================================= +// extApplication constructor +function extApplication() { +} + +// ================================================= +// extApplication implementation +extApplication.prototype = { + initToolkitHelpers: function extApp_initToolkitHelpers() { + XPCOMUtils.defineLazyServiceGetter(this, "_info", + "@mozilla.org/xre/app-info;1", + "nsIXULAppInfo"); + + this._obs = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + this._obs.addObserver(this, "xpcom-shutdown", /* ownsWeak = */ true); + this._registered = {"unload": true}; + }, + + classInfo: XPCOMUtils.generateCI({interfaces: [Ci.extIApplication, + Ci.nsIObserver], + flags: Ci.nsIClassInfo.SINGLETON}), + + // extIApplication + get id() { + return this._info.ID; + }, + + get name() { + return this._info.name; + }, + + get version() { + return this._info.version; + }, + + // for nsIObserver + observe: function app_observe(aSubject, aTopic, aData) { + if (aTopic == "app-startup") { + this.events.dispatch("load", "application"); + } + else if (aTopic == "final-ui-startup") { + this.events.dispatch("ready", "application"); + } + else if (aTopic == "quit-application-requested") { + // we can stop the quit by checking the return value + if (this.events.dispatch("quit", "application") == false) + aSubject.data = true; + } + else if (aTopic == "xpcom-shutdown") { + this.events.dispatch("unload", "application"); + gExtensionObserver = null; + gPreferenceObserver = null; + } + }, + + get console() { + let console = new Console(); + this.__defineGetter__("console", () => console); + return this.console; + }, + + get storage() { + let storage = new SessionStorage(); + this.__defineGetter__("storage", () => storage); + return this.storage; + }, + + get prefs() { + let prefs = new PreferenceBranch(""); + this.__defineGetter__("prefs", () => prefs); + return this.prefs; + }, + + getExtensions: function(callback) { + AddonManager.getAddonsByTypes(["extension"], function (addons) { + callback.callback(new Extensions(addons)); + }); + }, + + get events() { + + // This ensures that FUEL only registers for notifications as needed + // by callers. Note that the unload (xpcom-shutdown) event is listened + // for by default, as it's needed for cleanup purposes. + var self = this; + function registerCheck(aEvent) { + var rmap = { "load": "app-startup", + "ready": "final-ui-startup", + "quit": "quit-application-requested"}; + if (!(aEvent in rmap) || aEvent in self._registered) + return; + + self._obs.addObserver(self, rmap[aEvent], /* ownsWeak = */ true); + self._registered[aEvent] = true; + } + + let events = new Events(registerCheck); + this.__defineGetter__("events", () => events); + return this.events; + }, + + // helper method for correct quitting/restarting + _quitWithFlags: function app__quitWithFlags(aFlags) { + let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] + .createInstance(Components.interfaces.nsISupportsPRBool); + let quitType = aFlags & Components.interfaces.nsIAppStartup.eRestart ? "restart" : null; + this._obs.notifyObservers(cancelQuit, "quit-application-requested", quitType); + if (cancelQuit.data) + return false; // somebody canceled our quit request + + let appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1'] + .getService(Components.interfaces.nsIAppStartup); + appStartup.quit(aFlags); + return true; + }, + + quit: function app_quit() { + return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit); + }, + + restart: function app_restart() { + return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit | + Components.interfaces.nsIAppStartup.eRestart); + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.extIApplication, Ci.nsISupportsWeakReference]) +}; diff --git a/toolkit/components/exthelper/extIApplication.idl b/toolkit/components/exthelper/extIApplication.idl new file mode 100644 index 000000000..51c17b436 --- /dev/null +++ b/toolkit/components/exthelper/extIApplication.idl @@ -0,0 +1,416 @@ +/* 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/. */ + +#include "nsISupports.idl" + +interface nsIVariant; +interface extIPreference; +interface extISessionStorage; + + +/** + * Interface that gives simplified access to the console + */ +[scriptable, uuid(ae8482e0-aa5a-11db-abbd-0800200c9a66)] +interface extIConsole : nsISupports +{ + /** + * Sends a given string to the console. + * @param aMsg + * The text to send to the console + */ + void log(in AString aMsg); + + /** + * Opens the error console window. The console window + * is focused if already open. + */ + void open(); +}; + + +/** + * Interface holds information about an event. + */ +[scriptable, function, uuid(05281820-ab62-11db-abbd-0800200c9a66)] +interface extIEventItem : nsISupports +{ + /** + * The name of the event + */ + readonly attribute AString type; + + /** + * Can hold extra details and data associated with the event. This + * is optional and event specific. If the event does not send extra + * details, this is null. + */ + readonly attribute nsIVariant data; + + /** + * Cancels the event if it is cancelable. + */ + void preventDefault(); +}; + + +/** + * Interface used as a callback for listening to events. + */ +[scriptable, function, uuid(2dfe3a50-ab2f-11db-abbd-0800200c9a66)] +interface extIEventListener : nsISupports +{ + /** + * This method is called whenever an event occurs of the type for which + * the extIEventListener interface was registered. + * + * @param aEvent + * The extIEventItem associated with the event. + */ + void handleEvent(in extIEventItem aEvent); +}; + + +/** + * Interface for supporting custom events. + */ +[scriptable, uuid(3a8ec9d0-ab19-11db-abbd-0800200c9a66)] +interface extIEvents : nsISupports +{ + /** + * Adds an event listener to the list. If multiple identical event listeners + * are registered on the same event target with the same parameters the + * duplicate instances are discarded. They do not cause the EventListener + * to be called twice and since they are discarded they do not need to be + * removed with the removeListener method. + * + * @param aEvent + * The name of an event + * @param aListener + * The reference to a listener + */ + void addListener(in AString aEvent, in extIEventListener aListener); + + /** + * Removes an event listener from the list. Calling remove + * with arguments which do not identify any currently registered + * event listener has no effect. + * @param aEvent + * The name of an event + * @param aListener + * The reference to a listener + */ + void removeListener(in AString aEvent, in extIEventListener aListener); +}; + + +/** + * Interface for simplified access to preferences. The interface has a + * predefined root preference branch. The root branch is set based on the + * context of the owner. For example, an extension's preferences have a root + * of "extensions.<extensionid>.", while the application level preferences + * have an empty root. All preference "aName" parameters used in this interface + * are relative to the root branch. + */ +[scriptable, uuid(ce697d40-aa5a-11db-abbd-0800200c9a66)] +interface extIPreferenceBranch : nsISupports +{ + /** + * The name of the branch root. + */ + readonly attribute AString root; + + /** + * Array of extIPreference listing all preferences in this branch. + */ + readonly attribute nsIVariant all; + + /** + * The events object for the preferences + * supports: "change" + */ + readonly attribute extIEvents events; + + /** + * Check to see if a preference exists. + * @param aName + * The name of preference + * @returns true if the preference exists, false if not + */ + boolean has(in AString aName); + + /** + * Gets an object representing a preference + * @param aName + * The name of preference + * @returns a preference object, or null if the preference does not exist + */ + extIPreference get(in AString aName); + + /** + * Gets the value of a preference. Returns a default value if + * the preference does not exist. + * @param aName + * The name of preference + * @param aDefaultValue + * The value to return if preference does not exist + * @returns value of the preference or the given default value if preference + * does not exists. + */ + nsIVariant getValue(in AString aName, in nsIVariant aDefaultValue); + + /** + * Sets the value of a storage item with the given name. + * @param aName + * The name of an item + * @param aValue + * The value to assign to the item + */ + void setValue(in AString aName, in nsIVariant aValue); + + /** + * Resets all preferences in a branch back to their default values. + */ + void reset(); +}; + +/** + * Interface for accessing a single preference. The data is not cached. + * All reads access the current state of the preference. + */ +[scriptable, uuid(2C7462E2-72C2-4473-9007-0E6AE71E23CA)] +interface extIPreference : nsISupports +{ + /** + * The name of the preference. + */ + readonly attribute AString name; + + /** + * A string representing the type of preference (String, Boolean, or Number). + */ + readonly attribute AString type; + + /** + * Get/Set the value of the preference. + */ + attribute nsIVariant value; + + /** + * Get the locked state of the preference. Set to a boolean value to (un)lock it. + */ + attribute boolean locked; + + /** + * Check if a preference has been modified by the user, or not. + */ + readonly attribute boolean modified; + + /** + * The preference branch that contains this preference. + */ + readonly attribute extIPreferenceBranch branch; + + /** + * The events object for this preference. + * supports: "change" + */ + readonly attribute extIEvents events; + + /** + * Resets a preference back to its default values. + */ + void reset(); +}; + + +/** + * Interface representing an extension + */ +[scriptable, uuid(10cee02c-f6e0-4d61-ab27-c16572b18c46)] +interface extIExtension : nsISupports +{ + /** + * The id of the extension. + */ + readonly attribute AString id; + + /** + * The name of the extension. + */ + readonly attribute AString name; + + /** + * Check if the extension is currently enabled, or not. + */ + readonly attribute boolean enabled; + + /** + * The version number of the extension. + */ + readonly attribute AString version; + + /** + * Indicates whether this is the extension's first run after install + */ + readonly attribute boolean firstRun; + + /** + * The preferences object for the extension. Defaults to the + * "extensions.<extensionid>." branch. + */ + readonly attribute extIPreferenceBranch prefs; + + /** + * The storage object for the extension. + */ + readonly attribute extISessionStorage storage; + + /** + * The events object for the extension. + * supports: "uninstall" + */ + readonly attribute extIEvents events; +}; + +/** + * Interface representing a list of all installed extensions + */ +[scriptable, uuid(de281930-aa5a-11db-abbd-0800200c9a66)] +interface extIExtensions : nsISupports +{ + /** + * Array of extIExtension listing all extensions in the application. + */ + readonly attribute nsIVariant all; + + /** + * Determines if an extension exists with the given id. + * @param aId + * The id of an extension + * @returns true if an extension exists with the given id, + * false otherwise. + */ + boolean has(in AString aId); + + /** + * Gets a extIExtension object for an extension. + * @param aId + * The id of an extension + * @returns An extension object or null if no extension exists + * with the given id. + */ + extIExtension get(in AString aId); +}; + +/** + * Interface representing a callback that receives an array of extIExtensions + */ +[scriptable, function, uuid(2571cbb5-550d-4400-8038-75df9b553f98)] +interface extIExtensionsCallback : nsISupports +{ + void callback(in nsIVariant extensions); +}; + +/** + * Interface representing a simple storage system + */ +[scriptable, uuid(0787ac44-29b9-4889-b97f-13573aec6971)] +interface extISessionStorage : nsISupports +{ + /** + * The events object for the storage + * supports: "change" + */ + readonly attribute extIEvents events; + + /** + * Determines if a storage item exists with the given name. + * @param aName + * The name of an item + * @returns true if an item exists with the given name, + * false otherwise. + */ + boolean has(in AString aName); + + /** + * Sets the value of a storage item with the given name. + * @param aName + * The name of an item + * @param aValue + * The value to assign to the item + */ + void set(in AString aName, in nsIVariant aValue); + + /** + * Gets the value of a storage item with the given name. Returns a + * default value if the item does not exist. + * @param aName + * The name of an item + * @param aDefaultValue + * The value to return if no item exists with the given name + * @returns value of the item or the given default value if no item + * exists with the given name. + */ + nsIVariant get(in AString aName, in nsIVariant aDefaultValue); +}; + +[scriptable, uuid(2be87909-0817-4292-acfa-fc39be53be3f)] +interface extIApplication : nsISupports +{ + /** + * The id of the application. + */ + readonly attribute AString id; + + /** + * The name of the application. + */ + readonly attribute AString name; + + /** + * The version number of the application. + */ + readonly attribute AString version; + + /** + * The console object for the application. + */ + readonly attribute extIConsole console; + + /** + * The extensions object for the application. Contains a list + * of all installed extensions. + */ + void getExtensions(in extIExtensionsCallback aCallback); + + /** + * The preferences object for the application. Defaults to an empty + * root branch. + */ + readonly attribute extIPreferenceBranch prefs; + + /** + * The storage object for the application. + */ + readonly attribute extISessionStorage storage; + + /** + * The events object for the application. + * supports: "load", "ready", "quit", "unload" + */ + readonly attribute extIEvents events; + + /** + * Quits the application (if nobody objects to quit-application-requested). + * @returns whether quitting will proceed + */ + boolean quit(); + + /** + * Restarts the application (if nobody objects to quit-application-requested). + * @returns whether restarting will proceed + */ + boolean restart(); +}; diff --git a/toolkit/components/exthelper/moz.build b/toolkit/components/exthelper/moz.build new file mode 100644 index 000000000..975030a35 --- /dev/null +++ b/toolkit/components/exthelper/moz.build @@ -0,0 +1,12 @@ +# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*- +# vim: set filetype=python: +# 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/. + +XPIDL_SOURCES += [ + 'extIApplication.idl', +] + +XPIDL_MODULE = 'exthelper' + |