Cross-window background code... Ideas/Explanation?
-
- Posts: 4019
- Joined: November 16th, 2003, 3:05 am
- Location: Russia, Moscow
- BenBasson
- Moderator
- Posts: 13671
- Joined: February 13th, 2004, 5:49 am
- Location: London, UK
- Contact:
-
- Posts: 4864
- Joined: October 16th, 2003, 5:47 am
- Location: Somewhere in London, riding the Underground
This thread ought to be stickied. I agree with asqueella that good documentation on creating XPCOM components using JavaScript is thin on the ground, and using a sticky to collect information that could make its way into the MozillaZine KB would be invaluable to all extension developers.
Proud user of teh Fox of Fire
Registered Linux User #289618
Registered Linux User #289618
-
- Posts: 331
- Joined: November 24th, 2002, 8:20 pm
- Location: Iowa
- Contact:
Cusser wrote:I tried the "any" type, but XPIDL rejected it. I'm not really sure on it's use. I also tried using a struct, but it seems that the syntax requires that a struct is declared inside a module, which I'm not using... I'm declaring the interfaces globally, since doing otherwise appears to break their registration.
Ultimately, I can play with this later, but thanks anyway. For now, I intend to use methods returning arrays or single values, it's easier and I need to get on with the actual implementation
You could try using an nsIVariant interface for your data.
XPConnect has magic to transparently convert between nsIVariant and JS types.
so at the top of your idl, you would declare the interfaces used like:
<pre>
interface nsIVariant;
</pre>
then in the interface you are defining you would do something like:
<pre>
nsIVariant getData(in PRUint32 aType);
</pre>
My Extensions:
<a href="http://forecastfox.mozdev.org">Forecastfox</a>
<a href="http://tipbar.mozdev.org">Tip of the Day</a>
<a href="http://urlnav.mozdev.org">Location Navigator</a>
<a href="http://finder.mozdev.org">Finder</a>
<a href="http://rsszilla.mozdev.org">RSSzilla</a>
<a href="http://forecastfox.mozdev.org">Forecastfox</a>
<a href="http://tipbar.mozdev.org">Tip of the Day</a>
<a href="http://urlnav.mozdev.org">Location Navigator</a>
<a href="http://finder.mozdev.org">Finder</a>
<a href="http://rsszilla.mozdev.org">RSSzilla</a>
-
- Posts: 118
- Joined: May 26th, 2005, 11:06 am
While we're here... I noticed this:
The instructions I'm looking at (Creating XPCOM Components) say that you need both an IDL and a JS file to define an XPCOM object. Can it be done without an IDL file? If so, how?
I've never used IDL to define an XPCOM object
The instructions I'm looking at (Creating XPCOM Components) say that you need both an IDL and a JS file to define an XPCOM object. Can it be done without an IDL file? If so, how?
-
- Posts: 331
- Joined: November 24th, 2002, 8:20 pm
- Location: Iowa
- Contact:
You only need an idl when you define a new interface. If you are using existing interfaces, it isn't needed.
My Extensions:
<a href="http://forecastfox.mozdev.org">Forecastfox</a>
<a href="http://tipbar.mozdev.org">Tip of the Day</a>
<a href="http://urlnav.mozdev.org">Location Navigator</a>
<a href="http://finder.mozdev.org">Finder</a>
<a href="http://rsszilla.mozdev.org">RSSzilla</a>
<a href="http://forecastfox.mozdev.org">Forecastfox</a>
<a href="http://tipbar.mozdev.org">Tip of the Day</a>
<a href="http://urlnav.mozdev.org">Location Navigator</a>
<a href="http://finder.mozdev.org">Finder</a>
<a href="http://rsszilla.mozdev.org">RSSzilla</a>
-
- Posts: 118
- Joined: May 26th, 2005, 11:06 am
-
- Posts: 0
- Joined: December 31st, 1969, 5:00 pm
You can't. However for what you apparently want to do, you don't have to use your JS object as an XPCOM object. If you look closely at the <a href="jar:http://mozilla.dorando.at/keyconfig.xpi!/components/keyconfig-service.js">keyconfig component</a>, you'll note how the object is actually injected into each window:
For the domwindowopened notification, aSubject is the newly opened window. So you can access your object inside each window as if it were created in an overlay to browser.xul (i.e. as if you had written var keyconfig = { service: { /* your component here */ } }; in your extensions overlay code).
In fact, you could even write
in your component's observe method. That'd be the final equivalent to
in your "normal" code.
Code: Select all
aSubject.keyconfig = {service: this};
For the domwindowopened notification, aSubject is the newly opened window. So you can access your object inside each window as if it were created in an overlay to browser.xul (i.e. as if you had written var keyconfig = { service: { /* your component here */ } }; in your extensions overlay code).
In fact, you could even write
Code: Select all
aSubject.yourObject = this;
in your component's observe method. That'd be the final equivalent to
Code: Select all
var yourObject = { ... };
in your "normal" code.
-
- Posts: 118
- Joined: May 26th, 2005, 11:06 am
OK, looks like a great idea! Thanks!
EDIT: As I thought, I'm running into problems. -_- I'm getting "histree is not defined" in my browser windows. I put the following file (which I named "histree-service.js") in the components subdirectory... any idea what's going wrong?
By the way, I tried putting an alert statement in the "initHistree" function, and it didn't fire. Not sure if that's because the function isn't getting called (even though it's right there in the domwindowopened observer) or because the window isn't defined for some reason...?
EDIT: As I thought, I'm running into problems. -_- I'm getting "histree is not defined" in my browser windows. I put the following file (which I named "histree-service.js") in the components subdirectory... any idea what's going wrong?
By the way, I tried putting an alert statement in the "initHistree" function, and it didn't fire. Not sure if that's because the function isn't getting called (even though it's right there in the domwindowopened observer) or because the window isn't defined for some reason...?
Code: Select all
function NSGetModule(compMgr, fileSpec) { return histreeModule; }
var histreeModule = {
CID: Components.ID("{4a4bb6c4-94e4-11da-956a-00e08161165f}"),
contractID : "@mozilla.org/histree;1",
className : "histreeService",
registerSelf: function (aComponentManager, aFileSpec, aLocation, aType)
{
aComponentManager = aComponentManager.QueryInterface(Components.interfaces.nsIComponentRegistrar);
aComponentManager.registerFactoryLocation(this.CID, this.className, this.contractID, aFileSpec, aLocation, aType);
var CategoryManager = Components.classes["@mozilla.org/categorymanager;1"]
.getService(Components.interfaces.nsICategoryManager);
CategoryManager.addCategoryEntry("app-startup", this.className, "service," + this.contractID, true, true, null);
},
getClassObject: function (aComponentManager, aCID, aIID)
{
if (!aIID.equals(Components.interfaces.nsIFactory)) throw Components.results.NS_ERROR_NOT_IMPLEMENTED;
if (aCID.equals(this.CID)) return this.factory;
throw Components.results.NS_ERROR_NO_INTERFACE;
},
factory: {
createInstance: function (aOuter, aIID)
{
if (aOuter != null) throw Components.results.NS_ERROR_NO_AGGREGATION;
return new histreeService();
}
},
canUnload: function () { return true; }
};
function histreeService() { }
histreeService.prototype = {
observe: function (aSubject, aTopic, aData)
{
var os = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
if(aTopic == "app-startup")
{ os.addObserver(this,"domwindowopened",false);
os.addObserver(this, "domwindowclosed", false);
}
else if(aTopic == "domwindowopened")
{
aSubject.histree = this;
aSubject.histree.initHistree();
aSubject.addEventListener("load", histree.newWindow, false);
}
else if (aTopic == "domwindowclosed")
{
for (var i = 0; i < aSubject.histree.windows.length; i++)
{ if (aSubject.histree.windows[i].window == aSubject)
{ aSubject.histree.windows.splice(i, 1);
return;
}
}
}
},
//////more attributes/functions which were copied and pasted from my original object
}
-
- Posts: 118
- Joined: May 26th, 2005, 11:06 am
-
- Posts: 4019
- Joined: November 16th, 2003, 3:05 am
- Location: Russia, Moscow
It was mentioned in the previous thread on this topic: http://forums.mozillazine.org/viewtopic ... 74#1863874
[edit]
basically:
[edit]
basically:
Code: Select all
// in the component code you set the magical property wrappedJSObject on the component instance in constructor:
function MyComponentImpl {
this.wrappedJSObject = this; // or any other JS object
}
MyComponentImpl.prototype = {
l: 1,
// ...
};
// then in the caller you can access that object easily:
var o = Components.classes[mycontractid].getService/createInstance().wrappedJSObject;
alert(o.l); // alerts 1
-
- Posts: 118
- Joined: May 26th, 2005, 11:06 am
OK... I'm slowly getting there. But I've got this very weird error that just popped up.
Part of my component code:
The weird thing is that the term "this" inside newWindow suddenly seems to be referring to the ChromeWindow object, not my component object! So addWindowListeners isn't defined any more. I can't use a reference to the object itself (as defined in my overlay code) since it doesn't know about it yet. -_- I tried replacing "this" with histreeService.prototype (histreeService being my component object), but I then simply get two "uncaught exception: null" in the JS console.
I am STUMPED.
Part of my component code:
Code: Select all
//Called on startup.
initHistree: function(aWindow)
{ /*...*/
aWindow.addEventListener("load", this.newWindow, false);
}
/**... stuff... **/
//Called when a window is created.
newWindow: function(aEvent)
{ aEvent.currentTarget.removeEventListener("load", this.newWindow, false);
var win = aEvent.currentTarget.top;
if (!win.getBrowser) return; //not a browser window
this.addWindowListeners(win);
},
/*** More stuff... ***/
addWindowListeners: function(aWindow)
{ /**...**/
}
The weird thing is that the term "this" inside newWindow suddenly seems to be referring to the ChromeWindow object, not my component object! So addWindowListeners isn't defined any more. I can't use a reference to the object itself (as defined in my overlay code) since it doesn't know about it yet. -_- I tried replacing "this" with histreeService.prototype (histreeService being my component object), but I then simply get two "uncaught exception: null" in the JS console.
I am STUMPED.
-
- Posts: 4019
- Joined: November 16th, 2003, 3:05 am
- Location: Russia, Moscow