1 /* ***** BEGIN LICENSE BLOCK *****
2 * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 * The contents of this file are subject to the Mozilla Public License Version
5 * 1.1 (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 * http://www.mozilla.org/MPL/
9 * Software distributed under the License is distributed on an "AS IS" basis,
10 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
11 * for the specific language governing rights and limitations under the
14 * The Original Code is FUEL.
16 * The Initial Developer of the Original Code is Mozilla Corporation.
17 * Portions created by the Initial Developer are Copyright (C) 2006
18 * the Initial Developer. All Rights Reserved.
21 * Mark Finkle <mfinkle@mozilla.com> (Original Author)
22 * John Resig <jresig@mozilla.com> (Original Author)
24 * Alternatively, the contents of this file may be used under the terms of
25 * either the GNU General Public License Version 2 or later (the "GPL"), or
26 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 * in which case the provisions of the GPL or the LGPL are applicable instead
28 * of those above. If you wish to allow use of your version of this file only
29 * under the terms of either the GPL or the LGPL, and not to allow others to
30 * use your version of this file under the terms of the MPL, indicate your
31 * decision by deleting the provisions above and replace them with the notice
32 * and other provisions required by the GPL or the LGPL. If you do not delete
33 * the provisions above, a recipient may use your version of this file under
34 * the terms of any one of the MPL, the GPL or the LGPL.
36 * ***** END LICENSE BLOCK ***** */
38 //=================================================
39 // Shutdown - used to store cleanup functions which will
40 // be called on Application shutdown
43 //=================================================
44 // Console constructor
46 this._console = Components.classes["@mozilla.org/consoleservice;1"]
47 .getService(Ci.nsIConsoleService);
50 //=================================================
51 // Console implementation
53 log : function cs_log(aMsg) {
54 this._console.logStringMessage(aMsg);
57 open : function cs_open() {
58 var wMediator = Components.classes["@mozilla.org/appshell/window-mediator;1"]
59 .getService(Ci.nsIWindowMediator);
60 var console = wMediator.getMostRecentWindow("global:console");
62 var wWatch = Components.classes["@mozilla.org/embedcomp/window-watcher;1"]
63 .getService(Ci.nsIWindowWatcher);
64 wWatch.openWindow(null, "chrome://global/content/console.xul", "_blank",
65 "chrome,dialog=no,all", null);
67 // console was already open
72 QueryInterface : XPCOMUtils.generateQI([Ci.extIConsole])
76 //=================================================
77 // EventItem constructor
78 function EventItem(aType, aData) {
83 //=================================================
84 // EventItem implementation
85 EventItem.prototype = {
96 preventDefault : function ei_pd() {
100 QueryInterface : XPCOMUtils.generateQI([Ci.extIEventItem])
104 //=================================================
105 // Events constructor
107 this._listeners = [];
110 //=================================================
111 // Events implementation
113 addListener : function evts_al(aEvent, aListener) {
114 if (this._listeners.some(hasFilter))
117 this._listeners.push({
122 function hasFilter(element) {
123 return element.event == aEvent && element.listener == aListener;
127 removeListener : function evts_rl(aEvent, aListener) {
128 this._listeners = this._listeners.filter(hasFilter);
130 function hasFilter(element) {
131 return element.event != aEvent && element.listener != aListener;
135 dispatch : function evts_dispatch(aEvent, aEventItem) {
136 eventItem = new EventItem(aEvent, aEventItem);
138 this._listeners.forEach(function(key){
139 if (key.event == aEvent) {
140 key.listener.handleEvent ?
141 key.listener.handleEvent(eventItem) :
142 key.listener(eventItem);
146 return !eventItem._cancel;
149 QueryInterface : XPCOMUtils.generateQI([Ci.extIEvents])
153 //=================================================
154 // PreferenceBranch constructor
155 function PreferenceBranch(aBranch) {
159 this._root = aBranch;
160 this._prefs = Components.classes["@mozilla.org/preferences-service;1"]
161 .getService(Ci.nsIPrefService);
164 this._prefs = this._prefs.getBranch(aBranch);
166 this._prefs.QueryInterface(Ci.nsIPrefBranch);
167 this._prefs.QueryInterface(Ci.nsIPrefBranch2);
169 // we want to listen to "all" changes for this branch, so pass in a blank domain
170 this._prefs.addObserver("", this, true);
171 this._events = new Events();
174 gShutdown.push(function() { self._shutdown(); });
177 //=================================================
178 // PreferenceBranch implementation
179 PreferenceBranch.prototype = {
180 // cleanup observer so we don't leak
181 _shutdown: function prefs_shutdown() {
182 this._prefs.removeObserver(this._root, this);
189 observe: function prefs_observe(aSubject, aTopic, aData) {
190 if (aTopic == "nsPref:changed")
191 this._events.dispatch("change", aData);
199 return this.find({});
206 // XXX: Disabled until we can figure out the wrapped object issues
207 // name: "name" or /name/
208 // path: "foo.bar." or "" or /fo+\.bar/
209 // type: Boolean, Number, String (getPrefType)
210 // locked: true, false (prefIsLocked)
211 // modified: true, false (prefHasUserValue)
212 find : function prefs_find(aOptions) {
214 var items = this._prefs.getChildList("", []);
216 for (var i = 0; i < items.length; i++) {
217 retVal.push(new Preference(items[i], this));
223 has : function prefs_has(aName) {
224 return (this._prefs.getPrefType(aName) != Ci.nsIPrefBranch.PREF_INVALID);
227 get : function prefs_get(aName) {
228 return this.has(aName) ? new Preference(aName, this) : null;
231 getValue : function prefs_gv(aName, aValue) {
232 var type = this._prefs.getPrefType(aName);
235 case Ci.nsIPrefBranch2.PREF_STRING:
236 aValue = this._prefs.getComplexValue(aName, Ci.nsISupportsString).data;
238 case Ci.nsIPrefBranch2.PREF_BOOL:
239 aValue = this._prefs.getBoolPref(aName);
241 case Ci.nsIPrefBranch2.PREF_INT:
242 aValue = this._prefs.getIntPref(aName);
249 setValue : function prefs_sv(aName, aValue) {
250 var type = aValue != null ? aValue.constructor.name : "";
254 var str = Components.classes["@mozilla.org/supports-string;1"]
255 .createInstance(Ci.nsISupportsString);
257 this._prefs.setComplexValue(aName, Ci.nsISupportsString, str);
260 this._prefs.setBoolPref(aName, aValue);
263 this._prefs.setIntPref(aName, aValue);
266 throw("Unknown preference value specified.");
270 reset : function prefs_reset() {
271 this._prefs.resetBranch("");
274 QueryInterface : XPCOMUtils.generateQI([Ci.extIPreferenceBranch, Ci.nsISupportsWeakReference])
278 //=================================================
279 // Preference constructor
280 function Preference(aName, aBranch) {
282 this._branch = aBranch;
283 this._events = new Events();
287 this.branch.events.addListener("change", function(aEvent){
288 if (aEvent.data == self.name)
289 self.events.dispatch(aEvent.type, aEvent.data);
293 //=================================================
294 // Preference implementation
295 Preference.prototype = {
302 var type = this.branch._prefs.getPrefType(this._name);
305 case Ci.nsIPrefBranch2.PREF_STRING:
308 case Ci.nsIPrefBranch2.PREF_BOOL:
311 case Ci.nsIPrefBranch2.PREF_INT:
320 return this.branch.getValue(this._name, null);
324 return this.branch.setValue(this._name, aValue);
328 return this.branch._prefs.prefIsLocked(this.name);
332 this.branch._prefs[ aValue ? "lockPref" : "unlockPref" ](this.name);
336 return this.branch._prefs.prefHasUserValue(this.name);
347 reset : function pref_reset() {
348 this.branch._prefs.clearUserPref(this.name);
351 QueryInterface : XPCOMUtils.generateQI([Ci.extIPreference])
355 //=================================================
356 // SessionStorage constructor
357 function SessionStorage() {
359 this._events = new Events();
362 //=================================================
363 // SessionStorage implementation
364 SessionStorage.prototype = {
369 has : function ss_has(aName) {
370 return this._storage.hasOwnProperty(aName);
373 set : function ss_set(aName, aValue) {
374 this._storage[aName] = aValue;
375 this._events.dispatch("change", aName);
378 get : function ss_get(aName, aDefaultValue) {
379 return this.has(aName) ? this._storage[aName] : aDefaultValue;
382 QueryInterface : XPCOMUtils.generateQI([Ci.extISessionStorage])
386 //=================================================
387 // Extension constructor
388 function Extension(aItem) {
390 this._firstRun = false;
391 this._prefs = new PreferenceBranch("extensions." + this._item.id + ".");
392 this._storage = new SessionStorage();
393 this._events = new Events();
395 var installPref = "install-event-fired";
396 if (!this._prefs.has(installPref)) {
397 this._prefs.setValue(installPref, true);
398 this._firstRun = true;
401 this._enabled = false;
402 const PREFIX_ITEM_URI = "urn:mozilla:item:";
403 const PREFIX_NS_EM = "http://www.mozilla.org/2004/em-rdf#";
404 var rdf = Cc["@mozilla.org/rdf/rdf-service;1"].getService(Ci.nsIRDFService);
405 var itemResource = rdf.GetResource(PREFIX_ITEM_URI + this._item.id);
407 var extmgr = Cc["@mozilla.org/extensions/manager;1"].getService(Ci.nsIExtensionManager);
408 var ds = extmgr.datasource;
409 var target = ds.GetTarget(itemResource, rdf.GetResource(PREFIX_NS_EM + "isDisabled"), true);
410 if (target && target instanceof Ci.nsIRDFLiteral)
411 this._enabled = (target.Value != "true");
414 var os = Components.classes["@mozilla.org/observer-service;1"]
415 .getService(Ci.nsIObserverService);
416 os.addObserver(this, "em-action-requested", false);
419 gShutdown.push(function(){ self._shutdown(); });
422 //=================================================
423 // Extension implementation
424 Extension.prototype = {
425 // cleanup observer so we don't leak
426 _shutdown: function ext_shutdown() {
427 var os = Components.classes["@mozilla.org/observer-service;1"]
428 .getService(Ci.nsIObserverService);
429 os.removeObserver(this, "em-action-requested");
432 this._storage = null;
437 observe: function ext_observe(aSubject, aTopic, aData)
439 if ((aSubject instanceof Ci.nsIUpdateItem) && (aSubject.id == this._item.id))
441 if (aData == "item-uninstalled")
442 this._events.dispatch("uninstall", this._item.id);
443 else if (aData == "item-disabled")
444 this._events.dispatch("disable", this._item.id);
445 else if (aData == "item-enabled")
446 this._events.dispatch("enable", this._item.id);
447 else if (aData == "item-cancel-action")
448 this._events.dispatch("cancel", this._item.id);
449 else if (aData == "item-upgraded")
450 this._events.dispatch("upgrade", this._item.id);
455 return this._item.id;
459 return this._item.name;
463 return this._enabled;
467 return this._item.version;
471 return this._firstRun;
475 return this._storage;
486 QueryInterface : XPCOMUtils.generateQI([Ci.extIExtension])
490 //=================================================
491 // Extensions constructor
492 function Extensions() {
493 this._extmgr = Components.classes["@mozilla.org/extensions/manager;1"]
494 .getService(Ci.nsIExtensionManager);
499 gShutdown.push(function() { self._shutdown(); });
502 //=================================================
503 // Extensions implementation
504 Extensions.prototype = {
505 _shutdown : function exts_shutdown() {
511 * Helper method to check cache before creating a new extension
513 _get : function exts_get(aId) {
514 if (this._cache.hasOwnProperty(aId))
515 return this._cache[aId];
517 var newExt = new Extension(this._extmgr.getItemForID(aId));
518 this._cache[aId] = newExt;
523 return this.find({});
526 // XXX: Disabled until we can figure out the wrapped object issues
527 // id: "some@id" or /id/
528 // name: "name" or /name/
532 find : function exts_find(aOptions) {
534 var items = this._extmgr.getItemList(Ci.nsIUpdateItem.TYPE_EXTENSION, {});
536 for (var i = 0; i < items.length; i++) {
537 retVal.push(this._get(items[i].id));
543 has : function exts_has(aId) {
544 return this._extmgr.getItemForID(aId) != null;
547 get : function exts_get(aId) {
548 return this.has(aId) ? this._get(aId) : null;
551 QueryInterface : XPCOMUtils.generateQI([Ci.extIExtensions])
554 //=================================================
555 // extApplication constructor
556 function extApplication() {
559 //=================================================
560 // extApplication implementation
561 extApplication.prototype = {
562 initToolkitHelpers: function extApp_initToolkitHelpers() {
563 this._console = null;
564 this._storage = null;
566 this._extensions = null;
569 this._info = Components.classes["@mozilla.org/xre/app-info;1"]
570 .getService(Ci.nsIXULAppInfo);
572 var os = Components.classes["@mozilla.org/observer-service;1"]
573 .getService(Ci.nsIObserverService);
575 os.addObserver(this, "final-ui-startup", false);
576 os.addObserver(this, "quit-application-requested", false);
577 os.addObserver(this, "xpcom-shutdown", false);
580 // get this contractID registered for certain categories via XPCOMUtils
582 // make Application a startup observer
583 { category: "app-startup", service: true },
585 // add Application as a global property for easy access
586 { category: "JavaScript global privileged property" }
590 flags : Ci.nsIClassInfo.SINGLETON,
591 implementationLanguage : Ci.nsIProgrammingLanguage.JAVASCRIPT,
593 getInterfaces : function app_gi(aCount) {
594 var interfaces = [Ci.extIApplication, Ci.nsIObserver, Ci.nsIClassInfo];
595 aCount.value = interfaces.length;
599 getHelperForLanguage : function app_ghfl(aCount) {
605 return this._info.ID;
609 return this._info.name;
613 return this._info.version;
617 observe: function app_observe(aSubject, aTopic, aData) {
618 if (aTopic == "app-startup") {
619 this.events.dispatch("load", "application");
621 else if (aTopic == "final-ui-startup") {
622 this.events.dispatch("ready", "application");
624 else if (aTopic == "quit-application-requested") {
625 // we can stop the quit by checking the return value
626 if (this.events.dispatch("quit", "application") == false)
627 aSubject.data = true;
629 else if (aTopic == "xpcom-shutdown") {
631 this.events.dispatch("unload", "application");
633 // call the cleanup functions and empty the array
634 while (gShutdown.length) {
638 // release our observers
639 var os = Components.classes["@mozilla.org/observer-service;1"]
640 .getService(Ci.nsIObserverService);
642 os.removeObserver(this, "final-ui-startup");
643 os.removeObserver(this, "quit-application-requested");
644 os.removeObserver(this, "xpcom-shutdown");
647 this._console = null;
649 this._storage = null;
651 this._extensions = null;
656 if (this._console == null)
657 this._console = new Console();
659 return this._console;
663 if (this._storage == null)
664 this._storage = new SessionStorage();
666 return this._storage;
670 if (this._prefs == null)
671 this._prefs = new PreferenceBranch("");
677 if (this._extensions == null)
678 this._extensions = new Extensions();
680 return this._extensions;
684 if (this._events == null)
685 this._events = new Events();
690 // helper method for correct quitting/restarting
691 _quitWithFlags: function app__quitWithFlags(aFlags) {
692 let os = Components.classes["@mozilla.org/observer-service;1"]
693 .getService(Components.interfaces.nsIObserverService);
694 let cancelQuit = Components.classes["@mozilla.org/supports-PRBool;1"]
695 .createInstance(Components.interfaces.nsISupportsPRBool);
696 os.notifyObservers(cancelQuit, "quit-application-requested", null);
698 return false; // somebody canceled our quit request
700 let appStartup = Components.classes['@mozilla.org/toolkit/app-startup;1']
701 .getService(Components.interfaces.nsIAppStartup);
702 appStartup.quit(aFlags);
706 quit: function app_quit() {
707 return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit);
710 restart: function app_restart() {
711 return this._quitWithFlags(Components.interfaces.nsIAppStartup.eAttemptQuit |
712 Components.interfaces.nsIAppStartup.eRestart);
715 QueryInterface : XPCOMUtils.generateQI([Ci.extIApplication, Ci.nsISupportsWeakReference])