michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: Components.utils.import("resource://gre/modules/XPCOMUtils.jsm"); michael@0: Components.utils.import("resource://gre/modules/AddonManager.jsm"); michael@0: michael@0: //================================================= michael@0: // Console constructor michael@0: function Console() { michael@0: this._console = Components.classes["@mozilla.org/consoleservice;1"] michael@0: .getService(Ci.nsIConsoleService); michael@0: } michael@0: michael@0: //================================================= michael@0: // Console implementation michael@0: Console.prototype = { michael@0: log: function cs_log(aMsg) { michael@0: this._console.logStringMessage(aMsg); michael@0: }, michael@0: michael@0: open: function cs_open() { michael@0: var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"] michael@0: .getService(Ci.nsIWindowMediator); michael@0: var console = wMediator.getMostRecentWindow("global:console"); michael@0: if (!console) { michael@0: var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"] michael@0: .getService(Ci.nsIWindowWatcher); michael@0: wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank", michael@0: "chrome,dialog=no,all", null); michael@0: } else { michael@0: // console was already open michael@0: console.focus(); michael@0: } michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIConsole]) michael@0: }; michael@0: michael@0: michael@0: //================================================= michael@0: // EventItem constructor michael@0: function EventItem(aType, aData) { michael@0: this._type = aType; michael@0: this._data = aData; michael@0: } michael@0: michael@0: //================================================= michael@0: // EventItem implementation michael@0: EventItem.prototype = { michael@0: _cancel: false, michael@0: michael@0: get type() { michael@0: return this._type; michael@0: }, michael@0: michael@0: get data() { michael@0: return this._data; michael@0: }, michael@0: michael@0: preventDefault: function ei_pd() { michael@0: this._cancel = true; michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIEventItem]) michael@0: }; michael@0: michael@0: michael@0: //================================================= michael@0: // Events constructor michael@0: function Events(notifier) { michael@0: this._listeners = []; michael@0: this._notifier = notifier; michael@0: } michael@0: michael@0: //================================================= michael@0: // Events implementation michael@0: Events.prototype = { michael@0: addListener: function evts_al(aEvent, aListener) { michael@0: function hasFilter(element) { michael@0: return element.event == aEvent && element.listener == aListener; michael@0: } michael@0: michael@0: if (this._listeners.some(hasFilter)) michael@0: return; michael@0: michael@0: this._listeners.push({ michael@0: event: aEvent, michael@0: listener: aListener michael@0: }); michael@0: michael@0: if (this._notifier) { michael@0: this._notifier(aEvent, aListener); michael@0: } michael@0: }, michael@0: michael@0: removeListener: function evts_rl(aEvent, aListener) { michael@0: function hasFilter(element) { michael@0: return (element.event != aEvent) || (element.listener != aListener); michael@0: } michael@0: michael@0: this._listeners = this._listeners.filter(hasFilter); michael@0: }, michael@0: michael@0: dispatch: function evts_dispatch(aEvent, aEventItem) { michael@0: var eventItem = new EventItem(aEvent, aEventItem); michael@0: michael@0: this._listeners.forEach(function(key){ michael@0: if (key.event == aEvent) { michael@0: key.listener.handleEvent ? michael@0: key.listener.handleEvent(eventItem) : michael@0: key.listener(eventItem); michael@0: } michael@0: }); michael@0: michael@0: return !eventItem._cancel; michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) michael@0: }; michael@0: michael@0: //================================================= michael@0: // PreferenceObserver (internal class) michael@0: // michael@0: // PreferenceObserver is a global singleton which watches the browser's michael@0: // preferences and sends you events when things change. michael@0: michael@0: function PreferenceObserver() { michael@0: this._observersDict = {}; michael@0: } michael@0: michael@0: PreferenceObserver.prototype = { michael@0: /** michael@0: * Add a preference observer. michael@0: * michael@0: * @param aPrefs the nsIPrefBranch onto which we'll install our listener. michael@0: * @param aDomain the domain our listener will watch (a string). michael@0: * @param aEvent the event to listen to (you probably want "change"). michael@0: * @param aListener the function to call back when the event fires. This michael@0: * function will receive an EventData argument. michael@0: */ michael@0: addListener: function po_al(aPrefs, aDomain, aEvent, aListener) { michael@0: var root = aPrefs.root; michael@0: if (!this._observersDict[root]) { michael@0: this._observersDict[root] = {}; michael@0: } michael@0: var observer = this._observersDict[root][aDomain]; michael@0: michael@0: if (!observer) { michael@0: observer = { michael@0: events: new Events(), michael@0: observe: function po_observer_obs(aSubject, aTopic, aData) { michael@0: this.events.dispatch("change", aData); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, michael@0: Ci.nsISupportsWeakReference]) michael@0: }; michael@0: observer.prefBranch = aPrefs; michael@0: observer.prefBranch.addObserver(aDomain, observer, /* ownsWeak = */ true); michael@0: michael@0: // Notice that the prefBranch keeps a weak reference to the observer; michael@0: // it's this._observersDict which keeps the observer alive. michael@0: this._observersDict[root][aDomain] = observer; michael@0: } michael@0: observer.events.addListener(aEvent, aListener); michael@0: }, michael@0: michael@0: /** michael@0: * Remove a preference observer. michael@0: * michael@0: * This function's parameters are identical to addListener's. michael@0: */ michael@0: removeListener: function po_rl(aPrefs, aDomain, aEvent, aListener) { michael@0: var root = aPrefs.root; michael@0: if (!this._observersDict[root] || michael@0: !this._observersDict[root][aDomain]) { michael@0: return; michael@0: } michael@0: var observer = this._observersDict[root][aDomain]; michael@0: observer.events.removeListener(aEvent, aListener); michael@0: michael@0: if (observer.events._listeners.length == 0) { michael@0: // nsIPrefBranch objects are not singletons -- we can have two michael@0: // nsIPrefBranch'es for the same branch. There's no guarantee that michael@0: // aPrefs is the same object as observer.prefBranch, so we have to call michael@0: // removeObserver on observer.prefBranch. michael@0: observer.prefBranch.removeObserver(aDomain, observer); michael@0: delete this._observersDict[root][aDomain]; michael@0: if (Object.keys(this._observersDict[root]).length == 0) { michael@0: delete this._observersDict[root]; michael@0: } michael@0: } michael@0: } michael@0: }; michael@0: michael@0: //================================================= michael@0: // PreferenceBranch constructor michael@0: function PreferenceBranch(aBranch) { michael@0: if (!aBranch) michael@0: aBranch = ""; michael@0: michael@0: this._root = aBranch; michael@0: this._prefs = Components.classes["@mozilla.org/preferences-service;1"] michael@0: .getService(Ci.nsIPrefService) michael@0: .QueryInterface(Ci.nsIPrefBranch); michael@0: michael@0: if (aBranch) michael@0: this._prefs = this._prefs.getBranch(aBranch); michael@0: michael@0: let prefs = this._prefs; michael@0: this._events = { michael@0: addListener: function pb_al(aEvent, aListener) { michael@0: gPreferenceObserver.addListener(prefs, "", aEvent, aListener); michael@0: }, michael@0: removeListener: function pb_rl(aEvent, aListener) { michael@0: gPreferenceObserver.removeListener(prefs, "", aEvent, aListener); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) michael@0: }; michael@0: } michael@0: michael@0: //================================================= michael@0: // PreferenceBranch implementation michael@0: PreferenceBranch.prototype = { michael@0: get root() { michael@0: return this._root; michael@0: }, michael@0: michael@0: get all() { michael@0: return this.find({}); michael@0: }, michael@0: michael@0: get events() { michael@0: return this._events; michael@0: }, michael@0: michael@0: // XXX: Disabled until we can figure out the wrapped object issues michael@0: // name: "name" or /name/ michael@0: // path: "foo.bar." or "" or /fo+\.bar/ michael@0: // type: Boolean, Number, String (getPrefType) michael@0: // locked: true, false (prefIsLocked) michael@0: // modified: true, false (prefHasUserValue) michael@0: find: function prefs_find(aOptions) { michael@0: var retVal = []; michael@0: var items = this._prefs.getChildList(""); michael@0: michael@0: for (var i = 0; i < items.length; i++) { michael@0: retVal.push(new Preference(items[i], this)); michael@0: } michael@0: michael@0: return retVal; michael@0: }, michael@0: michael@0: has: function prefs_has(aName) { michael@0: return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID); michael@0: }, michael@0: michael@0: get: function prefs_get(aName) { michael@0: return this.has(aName) ? new Preference(aName, this) : null; michael@0: }, michael@0: michael@0: getValue: function prefs_gv(aName, aValue) { michael@0: var type = this._prefs.getPrefType(aName); michael@0: michael@0: switch (type) { michael@0: case Ci.nsIPrefBranch.PREF_STRING: michael@0: aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data; michael@0: break; michael@0: case Ci.nsIPrefBranch.PREF_BOOL: michael@0: aValue = this._prefs.getBoolPref(aName); michael@0: break; michael@0: case Ci.nsIPrefBranch.PREF_INT: michael@0: aValue = this._prefs.getIntPref(aName); michael@0: break; michael@0: } michael@0: michael@0: return aValue; michael@0: }, michael@0: michael@0: setValue: function prefs_sv(aName, aValue) { michael@0: var type = aValue != null ? aValue.constructor.name : ""; michael@0: michael@0: switch (type) { michael@0: case "String": michael@0: var str = Components.classes["@mozilla.org/supports-string;1"] michael@0: .createInstance(Ci.nsISupportsString); michael@0: str.data = aValue; michael@0: this._prefs.setComplexValue(aName, Ci.nsISupportsString, str); michael@0: break; michael@0: case "Boolean": michael@0: this._prefs.setBoolPref(aName, aValue); michael@0: break; michael@0: case "Number": michael@0: this._prefs.setIntPref(aName, aValue); michael@0: break; michael@0: default: michael@0: throw("Unknown preference value specified."); michael@0: } michael@0: }, michael@0: michael@0: reset: function prefs_reset() { michael@0: this._prefs.resetBranch(""); michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIPreferenceBranch]) michael@0: }; michael@0: michael@0: michael@0: //================================================= michael@0: // Preference constructor michael@0: function Preference(aName, aBranch) { michael@0: this._name = aName; michael@0: this._branch = aBranch; michael@0: michael@0: var self = this; michael@0: this._events = { michael@0: addListener: function pref_al(aEvent, aListener) { michael@0: gPreferenceObserver.addListener(self._branch._prefs, self._name, aEvent, aListener); michael@0: }, michael@0: removeListener: function pref_rl(aEvent, aListener) { michael@0: gPreferenceObserver.removeListener(self._branch._prefs, self._name, aEvent, aListener); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) michael@0: }; michael@0: } michael@0: michael@0: //================================================= michael@0: // Preference implementation michael@0: Preference.prototype = { michael@0: get name() { michael@0: return this._name; michael@0: }, michael@0: michael@0: get type() { michael@0: var value = ""; michael@0: var type = this.branch._prefs.getPrefType(this._name); michael@0: michael@0: switch (type) { michael@0: case Ci.nsIPrefBranch.PREF_STRING: michael@0: value = "String"; michael@0: break; michael@0: case Ci.nsIPrefBranch.PREF_BOOL: michael@0: value = "Boolean"; michael@0: break; michael@0: case Ci.nsIPrefBranch.PREF_INT: michael@0: value = "Number"; michael@0: break; michael@0: } michael@0: michael@0: return value; michael@0: }, michael@0: michael@0: get value() { michael@0: return this.branch.getValue(this._name, null); michael@0: }, michael@0: michael@0: set value(aValue) { michael@0: return this.branch.setValue(this._name, aValue); michael@0: }, michael@0: michael@0: get locked() { michael@0: return this.branch._prefs.prefIsLocked(this.name); michael@0: }, michael@0: michael@0: set locked(aValue) { michael@0: this.branch._prefs[ aValue ? "lockPref" : "unlockPref" ](this.name); michael@0: }, michael@0: michael@0: get modified() { michael@0: return this.branch._prefs.prefHasUserValue(this.name); michael@0: }, michael@0: michael@0: get branch() { michael@0: return this._branch; michael@0: }, michael@0: michael@0: get events() { michael@0: return this._events; michael@0: }, michael@0: michael@0: reset: function pref_reset() { michael@0: this.branch._prefs.clearUserPref(this.name); michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIPreference]) michael@0: }; michael@0: michael@0: michael@0: //================================================= michael@0: // SessionStorage constructor michael@0: function SessionStorage() { michael@0: this._storage = {}; michael@0: this._events = new Events(); michael@0: } michael@0: michael@0: //================================================= michael@0: // SessionStorage implementation michael@0: SessionStorage.prototype = { michael@0: get events() { michael@0: return this._events; michael@0: }, michael@0: michael@0: has: function ss_has(aName) { michael@0: return this._storage.hasOwnProperty(aName); michael@0: }, michael@0: michael@0: set: function ss_set(aName, aValue) { michael@0: this._storage[aName] = aValue; michael@0: this._events.dispatch("change", aName); michael@0: }, michael@0: michael@0: get: function ss_get(aName, aDefaultValue) { michael@0: return this.has(aName) ? this._storage[aName] : aDefaultValue; michael@0: }, michael@0: michael@0: QueryInterface : XPCOMUtils.generateQI([Ci.extISessionStorage]) michael@0: }; michael@0: michael@0: //================================================= michael@0: // ExtensionObserver constructor (internal class) michael@0: // michael@0: // ExtensionObserver is a global singleton which watches the browser's michael@0: // extensions and sends you events when things change. michael@0: michael@0: function ExtensionObserver() { michael@0: this._eventsDict = {}; michael@0: michael@0: AddonManager.addAddonListener(this); michael@0: AddonManager.addInstallListener(this); michael@0: } michael@0: michael@0: //================================================= michael@0: // ExtensionObserver implementation (internal class) michael@0: ExtensionObserver.prototype = { michael@0: onDisabling: function eo_onDisabling(addon, needsRestart) { michael@0: this._dispatchEvent(addon.id, "disable"); michael@0: }, michael@0: michael@0: onEnabling: function eo_onEnabling(addon, needsRestart) { michael@0: this._dispatchEvent(addon.id, "enable"); michael@0: }, michael@0: michael@0: onUninstalling: function eo_onUninstalling(addon, needsRestart) { michael@0: this._dispatchEvent(addon.id, "uninstall"); michael@0: }, michael@0: michael@0: onOperationCancelled: function eo_onOperationCancelled(addon) { michael@0: this._dispatchEvent(addon.id, "cancel"); michael@0: }, michael@0: michael@0: onInstallEnded: function eo_onInstallEnded(install, addon) { michael@0: this._dispatchEvent(addon.id, "upgrade"); michael@0: }, michael@0: michael@0: addListener: function eo_al(aId, aEvent, aListener) { michael@0: var events = this._eventsDict[aId]; michael@0: if (!events) { michael@0: events = new Events(); michael@0: this._eventsDict[aId] = events; michael@0: } michael@0: events.addListener(aEvent, aListener); michael@0: }, michael@0: michael@0: removeListener: function eo_rl(aId, aEvent, aListener) { michael@0: var events = this._eventsDict[aId]; michael@0: if (!events) { michael@0: return; michael@0: } michael@0: events.removeListener(aEvent, aListener); michael@0: if (events._listeners.length == 0) { michael@0: delete this._eventsDict[aId]; michael@0: } michael@0: }, michael@0: michael@0: _dispatchEvent: function eo_dispatchEvent(aId, aEvent) { michael@0: var events = this._eventsDict[aId]; michael@0: if (events) { michael@0: events.dispatch(aEvent, aId); michael@0: } michael@0: } michael@0: }; michael@0: michael@0: //================================================= michael@0: // Extension constructor michael@0: function Extension(aItem) { michael@0: this._item = aItem; michael@0: this._firstRun = false; michael@0: this._prefs = new PreferenceBranch("extensions." + this.id + "."); michael@0: this._storage = new SessionStorage(); michael@0: michael@0: let id = this.id; michael@0: this._events = { michael@0: addListener: function ext_events_al(aEvent, aListener) { michael@0: gExtensionObserver.addListener(id, aEvent, aListener); michael@0: }, michael@0: removeListener: function ext_events_rl(aEvent, aListener) { michael@0: gExtensionObserver.addListener(id, aEvent, aListener); michael@0: }, michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIEvents]) michael@0: }; michael@0: michael@0: var installPref = "install-event-fired"; michael@0: if (!this._prefs.has(installPref)) { michael@0: this._prefs.setValue(installPref, true); michael@0: this._firstRun = true; michael@0: } michael@0: } michael@0: michael@0: //================================================= michael@0: // Extension implementation michael@0: Extension.prototype = { michael@0: get id() { michael@0: return this._item.id; michael@0: }, michael@0: michael@0: get name() { michael@0: return this._item.name; michael@0: }, michael@0: michael@0: get enabled() { michael@0: return this._item.isActive; michael@0: }, michael@0: michael@0: get version() { michael@0: return this._item.version; michael@0: }, michael@0: michael@0: get firstRun() { michael@0: return this._firstRun; michael@0: }, michael@0: michael@0: get storage() { michael@0: return this._storage; michael@0: }, michael@0: michael@0: get prefs() { michael@0: return this._prefs; michael@0: }, michael@0: michael@0: get events() { michael@0: return this._events; michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIExtension]) michael@0: }; michael@0: michael@0: michael@0: //================================================= michael@0: // Extensions constructor michael@0: function Extensions(addons) { michael@0: this._cache = {}; michael@0: michael@0: addons.forEach(function (addon) { michael@0: this._cache[addon.id] = new Extension(addon); michael@0: }, this); michael@0: } michael@0: michael@0: //================================================= michael@0: // Extensions implementation michael@0: Extensions.prototype = { michael@0: get all() { michael@0: return this.find({}); michael@0: }, michael@0: michael@0: // XXX: Disabled until we can figure out the wrapped object issues michael@0: // id: "some@id" or /id/ michael@0: // name: "name" or /name/ michael@0: // version: "1.0.1" michael@0: // minVersion: "1.0" michael@0: // maxVersion: "2.0" michael@0: find: function exts_find(aOptions) { michael@0: return [e for each (e in this._cache)]; michael@0: }, michael@0: michael@0: has: function exts_has(aId) { michael@0: return aId in this._cache; michael@0: }, michael@0: michael@0: get: function exts_get(aId) { michael@0: return this.has(aId) ? this._cache[aId] : null; michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIExtensions]) michael@0: }; michael@0: michael@0: //================================================= michael@0: // Application globals michael@0: michael@0: gExtensionObserver = new ExtensionObserver(); michael@0: gPreferenceObserver = new PreferenceObserver(); michael@0: michael@0: //================================================= michael@0: // extApplication constructor michael@0: function extApplication() { michael@0: } michael@0: michael@0: //================================================= michael@0: // extApplication implementation michael@0: extApplication.prototype = { michael@0: initToolkitHelpers: function extApp_initToolkitHelpers() { michael@0: XPCOMUtils.defineLazyServiceGetter(this, "_info", michael@0: "@mozilla.org/xre/app-info;1", michael@0: "nsIXULAppInfo"); michael@0: michael@0: this._obs = Cc["@mozilla.org/observer-service;1"]. michael@0: getService(Ci.nsIObserverService); michael@0: this._obs.addObserver(this, "xpcom-shutdown", /* ownsWeak = */ true); michael@0: this._registered = {"unload": true}; michael@0: }, michael@0: michael@0: classInfo: XPCOMUtils.generateCI({interfaces: [Ci.extIApplication, michael@0: Ci.nsIObserver], michael@0: flags: Ci.nsIClassInfo.SINGLETON}), michael@0: michael@0: // extIApplication michael@0: get id() { michael@0: return this._info.ID; michael@0: }, michael@0: michael@0: get name() { michael@0: return this._info.name; michael@0: }, michael@0: michael@0: get version() { michael@0: return this._info.version; michael@0: }, michael@0: michael@0: // for nsIObserver michael@0: observe: function app_observe(aSubject, aTopic, aData) { michael@0: if (aTopic == "app-startup") { michael@0: this.events.dispatch("load", "application"); michael@0: } michael@0: else if (aTopic == "final-ui-startup") { michael@0: this.events.dispatch("ready", "application"); michael@0: } michael@0: else if (aTopic == "quit-application-requested") { michael@0: // we can stop the quit by checking the return value michael@0: if (this.events.dispatch("quit", "application") == false) michael@0: aSubject.data = true; michael@0: } michael@0: else if (aTopic == "xpcom-shutdown") { michael@0: this.events.dispatch("unload", "application"); michael@0: gExtensionObserver = null; michael@0: gPreferenceObserver = null; michael@0: } michael@0: }, michael@0: michael@0: get console() { michael@0: let console = new Console(); michael@0: this.__defineGetter__("console", function () console); michael@0: return this.console; michael@0: }, michael@0: michael@0: get storage() { michael@0: let storage = new SessionStorage(); michael@0: this.__defineGetter__("storage", function () storage); michael@0: return this.storage; michael@0: }, michael@0: michael@0: get prefs() { michael@0: let prefs = new PreferenceBranch(""); michael@0: this.__defineGetter__("prefs", function () prefs); michael@0: return this.prefs; michael@0: }, michael@0: michael@0: getExtensions: function(callback) { michael@0: AddonManager.getAddonsByTypes(["extension"], function (addons) { michael@0: callback.callback(new Extensions(addons)); michael@0: }); michael@0: }, michael@0: michael@0: get events() { michael@0: michael@0: // This ensures that FUEL only registers for notifications as needed michael@0: // by callers. Note that the unload (xpcom-shutdown) event is listened michael@0: // for by default, as it's needed for cleanup purposes. michael@0: var self = this; michael@0: function registerCheck(aEvent) { michael@0: var rmap = { "load": "app-startup", michael@0: "ready": "final-ui-startup", michael@0: "quit": "quit-application-requested"}; michael@0: if (!(aEvent in rmap) || aEvent in self._registered) michael@0: return; michael@0: michael@0: self._obs.addObserver(self, rmap[aEvent], /* ownsWeak = */ true); michael@0: self._registered[aEvent] = true; michael@0: } michael@0: michael@0: let events = new Events(registerCheck); michael@0: this.__defineGetter__("events", function () events); michael@0: return this.events; michael@0: }, michael@0: michael@0: // helper method for correct quitting/restarting michael@0: _quitWithFlags: function app__quitWithFlags(aFlags) { michael@0: let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"] michael@0: .createInstance(Components.interfaces.nsISupportsPRBool); michael@0: let quitType = aFlags & Components.interfaces.nsIAppStartup.eRestart ? "restart" : null; michael@0: this._obs.notifyObservers(cancelQuit, "quit-application-requested", quitType); michael@0: if (cancelQuit.data) michael@0: return false; // somebody canceled our quit request michael@0: michael@0: let appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1'] michael@0: .getService(Components.interfaces.nsIAppStartup); michael@0: appStartup.quit(aFlags); michael@0: return true; michael@0: }, michael@0: michael@0: quit: function app_quit() { michael@0: return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit); michael@0: }, michael@0: michael@0: restart: function app_restart() { michael@0: return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit | michael@0: Components.interfaces.nsIAppStartup.eRestart); michael@0: }, michael@0: michael@0: QueryInterface: XPCOMUtils.generateQI([Ci.extIApplication, Ci.nsISupportsWeakReference]) michael@0: };