9

I've been looking at different tutorials and I know I'm close but I'm getting lost in implementation details because some of them are a little bit dated and a few things have changed since Firefox 3. I have already written the javascript for the firefox extension, now I need to make it into an XPCOM component.

This is the functionality that I need: My Javascript file is simple, I have two functions startServer() and stopServer. I need to run startServer() when the browser starts and stopServer() when firefox quits.

Edit:

I've updated my code with a working solution (thanks to Neil). The following is in MyExtension/components/myextension.js.

Components.utils.import("resource://gre/modules/XPCOMUtils.jsm");
const CI = Components.interfaces, CC = Components.classes, CR = Components.results;

// class declaration
function MyExtension() {}

MyExtension.prototype = {
    classDescription: "My Firefox Extension",
    classID:          Components.ID("{xxxx-xxxx-xxx-xxxxx}"),
    contractID:       "@example.com/MyExtension;1",
    QueryInterface: XPCOMUtils.generateQI([CI.nsIObserver]),

    // add to category manager
    _xpcom_categories: [{
        category: "profile-after-change"
    }],

    // start socket server
    startServer: function () { /* socket initialization code */ },

    // stop socket server
    stopServer: function () { /* stop server */ },


    observe: function(aSubject, aTopic, aData) 
    {
        var obs = CC["@mozilla.org/observer-service;1"].getService(CI.nsIObserverService);

        switch (aTopic) 
        {
            case "quit-application":
                this.stopServer();
                obs.removeObserver(this, "quit-application");
                break;
            case "profile-after-change":
                this.startServer();
                obs.addObserver(this, "quit-application", false);
                break;
            default:
                throw Components.Exception("Unknown topic: " + aTopic);
        }
    }
};

var components = [MyExtension];

function NSGetModule(compMgr, fileSpec) {
    return XPCOMUtils.generateModule(components);
}
Community
  • 1
  • 1
David
  • 7,310
  • 6
  • 41
  • 63

1 Answers1

5

As far as I can tell, all of your code goes into your component.

You need a JavaScript object that represents your component and register it with the component registrar. (It can be a new object or you can multitask an existing object.) The way this is done depends on whether you're targetting Firefox 3.x or Firefox 4.

You need to register for the profile-after-change notification using the category manager. The way this is done also depends on whether you're targetting Firefox 3, Firefox 3.5/6 or Firefox 4.

When the profile-after-change notification fires, your component is then created and the observe method is called. This is where you start your server and also ask to observe the quit-application notification. Note that this also calls the observe method, so it has to check which notification it's getting.

function myExt() {}
myExt.prototype = {
  observe: function(aSubject, aTopic, aData) {
    switch (aTopic) {
      case "quit-application":
        stopServer();
        obs.removeObserver(this, "quit-application");
        break;
      case "profile-after-change":
        startServer();
        obs.addObserver(this, "quit-application", false);
        break;
    }
  }
};
Neil
  • 54,642
  • 8
  • 60
  • 72
  • I've updated my code with my changes so far. The component is registered in compreg.dat but the observe: function doesn't get called. – David Jan 30 '11 at 04:46
  • So, does compreg.dat have entries for you component under all of a) [COMPONENTS] b) [CLASSIDS] c) [CONTRACTIDS] d) [CATEGORIES]? – Neil Jan 30 '11 at 21:40
  • Yes, I finally got it working by not using the XPCOMUtils module for the query interface and XPCOM registration. I had to write a lot more code but I'm still curious as to why it wouldn't work when I used the module. – David Jan 30 '11 at 21:51
  • Thanks for that update, it's made me realise that your QueryInterface was advertising the wrong interface, you need to advertise nsIObserver as (one of) your interface(s). – Neil Jan 30 '11 at 22:08
  • Thanks for catching that. That was my problem. – David Jan 30 '11 at 23:04
  • Note that `XPCOMUtils.generateQI` automatically assumes that `nsISupports` is one of the interfaces you want to advertise, so you don't need to mention it explicitly. Only if you write your own QueryInterface method do you need to explicitly support `nsISupports`. – Neil Jan 31 '11 at 00:23
  • I did not know that, thanks. If there's anything else I'm not doing correctly please feel free to comment. – David Jan 31 '11 at 04:00
  • The wrappedJSObject line is useful for debugging, but you may not want to leave it in the finished extension. Also the nsIMyExtension and its typelib may not be necessary but I can't tell for sure. – Neil Jan 31 '11 at 21:58
  • Yes that's true I don't need the typelib, but from [this tutorial](https://developer.mozilla.org/en/how_to_build_an_xpcom_component_in_javascript) I understood (perhaps wrongly) that if I don't provide an interface I need to put in the wrappedJSObject line. I will test it without. – David Jan 31 '11 at 22:12
  • You only need the typelib or the wrappedJSObject in order to give custom access to your object from other objects. In this case, the only access anything needs to your object is to fire the observer notifications, for which nsIObserver is the correct interface. – Neil Jan 31 '11 at 22:26