MozillaZine

notifications for preference changes

Talk about add-ons and extension development.
irshad
 
Posts: 6
Joined: September 8th, 2005, 5:53 am
March 8th, 2006, 7:44 am

Post Posted March 8th, 2006, 7:44 am

How can i get notified if a user changes some preferences for my extension throught the about:config page ???

TIA

old Captain Caveman
 
Posts: 0
Joined: December 31st, 1969, 5:00 pm
March 8th, 2006, 8:11 am

Post Posted March 8th, 2006, 8:11 am

By using a pref observer in your pref service, quick sample:

Code: Select all
const MyPrefObserver =
{
  observe: function(subject, topic, prefName)
  {
    if (topic == "nsPref:changed" && prefName == "extensions.somepref")
    {
      //Do your thing...
    }
  }
};
var oPrefService = Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranchInternal);
oPrefService.addObserver("extensions.somepref", MyPrefObserver, false);


Enjoy!

irshad
 
Posts: 6
Joined: September 8th, 2005, 5:53 am
March 8th, 2006, 8:41 am

Post Posted March 8th, 2006, 8:41 am

Thanks Captain Caveman for your fast reply.

I understand that nsIPrefBranchInternal has been renamed to nsIPrefBranch2 in Gecko 1.8. So should i be using it in extension for newer versions of firefox ???

I found this code through google at http://kb.mozillazine.org/Dev_:_Using_preferences

Code: Select all
var myPrefObserver =
{
  register: function()
  {
    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                                .getService(Components.interfaces.nsIPrefService);
    this._branch = prefService.getBranch("extensions.myextension.");
    this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
    this._branch.addObserver("", this, false);
  },

  unregister: function()
  {
    if(!this._branch) return;
    this._branch.removeObserver("", this);
  },

  observe: function(aSubject, aTopic, aData)
  {
    if(aTopic != "nsPref:changed") return;
    // aSubject is the nsIPrefBranch we're observing (after appropriate QI)
    // aData is the name of the pref that's been changed (relative to aSubject)
    switch (aData) {
      case "pref1":
        // extensions.myextension.pref1 was changed
        break;
      case "pref2":
        // extensions.myextension.pref2 was changed
        break;
    }
  }
}
myPrefListener.register();


Its pretty much similar to your code. Can you explain the significance of the third argument(the boolean one) to the call addObserver().
Why is there a call like
Code: Select all
    this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);

What exactly does QueryInterface() do ???

old Captain Caveman
 
Posts: 0
Joined: December 31st, 1969, 5:00 pm
March 8th, 2006, 9:14 am

Post Posted March 8th, 2006, 9:14 am

That's a lot of questions! I'll try to answer them, but I'm not sure if I have already learned enough to realy know/understand this all correctly.

1. Sorry, you should indeed start using nsIPrefBranch2
nsIPrefBranchInternal
IID: d1d412d9-15d6-4a6a-9533-b949dc175ff5
Inherits From: nsIPrefBranch2
Status: NON-FROZEN interface WHICH WILL PROBABLY GO AWAY.

An empty interface to provide backwards compatibility for existing code that bsmedberg didn't want to break all at once. Don't use me!


2. AFAIK a weak-reference means that the reference does not prevent a garbage collector (internal memory cleanup) to destroy the referenced object. a strong one does prevent that. But I do not know what the consequences of these are in a Firefox extension. I always hold a strong reference, cause that would be "safer"

3. nsIPrefService.getBranch() returns a nsIPrefBranch, with QueryInterface you can cast it to another interface that inherits from it.

Hope this helps/informs you a bit, and also that I did not say too many stupid/n00blike things for all the real developers over here.

irshad
 
Posts: 6
Joined: September 8th, 2005, 5:53 am
March 8th, 2006, 11:13 am

Post Posted March 8th, 2006, 11:13 am

Thank you once again... Its working well n fine...

Philip Chee

User avatar
 
Posts: 4294
Joined: March 1st, 2005, 3:03 pm
March 9th, 2006, 10:15 am

Post Posted March 9th, 2006, 10:15 am

Code: Select all
  register: function()
  {
    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                                .getService(Components.interfaces.nsIPrefService);
    this._branch = prefService.getBranch("extensions.myextension.");
    this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
    this._branch.addObserver("", this, false);
  },
In the call to getBranch() if I use anything except an empty string (i.e. ""), my pref observer is never called.
Anybody know why? No errors in the JS/Error consoles.

Phil

old Captain Caveman
 
Posts: 0
Joined: December 31st, 1969, 5:00 pm
March 9th, 2006, 1:06 pm

Post Posted March 9th, 2006, 1:06 pm

Not sure if I understand your problem Philip, but shouldn't you pass the domain you want to observe in the call to addObserver?
So this one listens to a change in somepref of your extension:
Code: Select all
register: function()
  {
    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                                .getService(Components.interfaces.nsIPrefService);
    this._branch = prefService.getBranch("extensions.myextension.");
    this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
    this._branch.addObserver("extensions.myextension.somepref", this, false);
  },

Philip Chee

User avatar
 
Posts: 4294
Joined: March 1st, 2005, 3:03 pm
March 9th, 2006, 8:15 pm

Post Posted March 9th, 2006, 8:15 pm

I want to listen for changes to several perferences e.g. "extensions.xsidebar.webpanel.*" so following the example given I used:
Code: Select all
  register: function()
  {
    var prefService = Components.classes["@mozilla.org/preferences-service;1"]
                                .getService(Components.interfaces.nsIPrefService);
    this._branch = prefService.getBranch("extensions.myextension.");
    this._branch.QueryInterface(Components.interfaces.nsIPrefBranch2);
    this._branch.addObserver("", this, false);
  },
but my observer is never called despite listening to "" which should return all pref changes. So now I'm using
Code: Select all
  prefBranch : Components.classes["@mozilla.org/preferences-service;1"]
               .getService(Components.interfaces.nsIPrefService)
               .QueryInterface(Components.interfaces.nsIPrefBranchInternal),

  prefObserver : {
    observe: function(subject, topic, data) {
    // subject is the nsIPrefBranch we're observing (after appropriate QI)
    // data is the name of the pref that's been changed (relative to subject)
dump("\nxsbPrefObserver-topic:"+topic);
dump("\nxsbPrefObserver-subject:"+subject);
dump("\nxsbPrefObserver-data:"+data);
      if(topic == "nsPref:changed")
        xsbWebPanel.initSettings();
    }
  },

  addPrefObserver : function () {
dump("\nxsbPrefObserver: adding\n");
    xsbWebPanel.prefBranch.addObserver("extensions.xsidebar.webpanel.", xsbWebPanel.prefObserver, false);
  },
Now this works but the data parameter returned by the observer is the full pref string and not
the part to the right of "extensions.xsidebar.webpanel."

Phil

old Captain Caveman
 
Posts: 0
Joined: December 31st, 1969, 5:00 pm
March 10th, 2006, 3:49 am

Post Posted March 10th, 2006, 3:49 am

That is all "by design" I believe. You can't listen to all pref changes, and the observer's data param will hold the complete pref that has changed.

void addObserver ( char* domain , nsIObserver observer , PRBool holdWeak )

Add a preference change observer. On preference changes, the following arguments will be passed to the nsIObserver.observe() method: subject - The nsIPrefBranch object (this) topic - The string defined by NS_PREFBRANCH_PREFCHANGE_TOPIC_ID data - The preference which has changed

Arguments:
domain: The preference on which to listen for changes. This can be the name of an entire branch to observe. e.g. Holding the "root" prefbranch and calling addObserver("foo.bar.", ...) will observe changes to foo.bar.baz and foo.bar.bzip
observer: The object to be notified if the preference changes.
holdWeak: true Hold a weak reference to |observer|. The object must implement the nsISupportsWeakReference interface or this will fail. false Hold a strong reference to |observer|.


Why is that a problem? Though it might be a bit slower, you could just do a data.replace('extensions.xsidebar.webpanel.', '') to get just the pref.

Philip Chee

User avatar
 
Posts: 4294
Joined: March 1st, 2005, 3:03 pm
March 10th, 2006, 4:17 am

Post Posted March 10th, 2006, 4:17 am

Captain Caveman wrote:Why is that a problem? Though it might be a bit slower, you could just do a data.replace('extensions.xsidebar.webpanel.', '') to get just the pref.
It's not a problem. It's just that the code in the KB article implies that it should work otherwise.

Phil

old Captain Caveman
 
Posts: 0
Joined: December 31st, 1969, 5:00 pm
March 10th, 2006, 5:45 am

Post Posted March 10th, 2006, 5:45 am

Than that's probably the reason why the author of it added this line :)
Here's an example (note, this code hasn't actually been tested, so it may contain typos and other errors):

asqueella
 
Posts: 3996
Joined: November 16th, 2003, 3:05 am
Location: Russia, Moscow
March 12th, 2006, 7:30 pm

Post Posted March 12th, 2006, 7:30 pm

That code works fine for me. aData is relative to the aSubject. You can remove the "untested" warning.

Re: weak references, if you use a strong reference, you must remember to unregister the observer on window unload, otherwise the window will leak. I think weak reference would work fine, since the observer is referenced by the window, and therefore will not be destroyed until the window is closed.

Philip Chee

User avatar
 
Posts: 4294
Joined: March 1st, 2005, 3:03 pm
March 12th, 2006, 8:07 pm

Post Posted March 12th, 2006, 8:07 pm

My observer isn't called at all (as far as my dump statements indicate) if I use .getBranch()
with anything other than an empty string (""). Why is this?

Phil

asqueella
 
Posts: 3996
Joined: November 16th, 2003, 3:05 am
Location: Russia, Moscow
March 13th, 2006, 12:20 pm

Post Posted March 13th, 2006, 12:20 pm

Post the testcase.

Philip Chee

User avatar
 
Posts: 4294
Joined: March 1st, 2005, 3:03 pm
March 14th, 2006, 3:28 am

Post Posted March 14th, 2006, 3:28 am

Sorry, as I said I rewrote my code since. I might try to recreate the problem when I have time.

Phil

Return to Extension Development


Who is online

Users browsing this forum: No registered users and 1 guest