nsIPrefBranch2 is no more

  • Posted: Thursday, February 16 2012, 12:29 AM
  • Tags: mozilla

Yesterday I landed bug 718255, taking the guts out of nsIPrefBranch2 and putting them into nsIPrefBranch. That means a QueryInterface call is no longer required to add or remove pref observers. (The interface still exists, to prevent stuff breaking, but it is empty now.)

Hackers and reviewers, please take note. I don't want to be clearing out stray uses forever.

Test running script

Hey Mozilla devs, are you sick of typing TEST_PATH=... make -C objdir mochitest-browser-chrome only to remember halfway through that you're trying to run an XPC shell test, and have to type something completely different? Me too!

There's currently at least 7 makefile targets for running the common unit tests (mochitests, reftests and XPC shell tests). It's a pain remembering which one to use. So I've created a Python script which will do it for you, and you'll only need one command to run tests ever again:

../scripts/runtest.py path/to/test

"Where do I get this magic script?" you ask. It's here. It could be more efficient, it could be better documented, and it could be written by someone who actually knows what they're doing with Python. Who cares? It works.

7 things

Oh no, who started this again? Blair tagged me.

4 Rules:

  1. Link to your original tagger(s) and list these rules in your post.
  2. Share seven facts about yourself in the post.
  3. Tag seven people at the end of your post by leaving their names and the links to their blogs.
  4. Let them know they’ve been tagged.

7 Things:

  1. I was one of the first people in the country to create a high school art portfolio entirely on Photoshop. It scored really well. I still have it somewhere, and I still have the same version of Photoshop (11 years later).
  2. I find dealing with people I don't know well exhausting.
  3. In spite of #2, I work with school kids and teenagers. On Friday nights you'll find me playing touch rugby with 11-14 year-olds, I help run school holiday programmes at my church, and each year at Easter I help run a camp for kids from all over the region.
  4. Unlike Blair, I don't fear heights. I've done stage lighting (as well as sound and A/V stuff, sometimes all three at the same time) for productions, musicals, concerts and church services.
  5. My typical day starts at about 10am and goes until about 1am. I don't do mornings.
  6. My online nickname has nothing to do with Greeks bearing gifts. It has nothing to do with anything really, I made it up when I needed a username for something. Two words that sounded cool, put them together, bam. This is a dumb idea. Don't do it.
  7. I think, a lot more than I do. Things usually work a lot better in my head. Everything I write for this blog, for example.

7 People:

Nah, can't be bothered doing this. It's my blog so I'll not do it if I don't want to.

Extension settings in a tab in Mozilla 7

In addition to settings in the Addon Manager, Firefox 7 also supports extension settings in a tab. Here's a quick bit of code you can use to provide backwards-compatibility.

Put this file at chrome://mynamespace/content/redirect.xul, point your optionsURL there, and set optionsType to 3.

<?xml version="1.0" ?>
<window xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<script type="application/javascript"><![CDATA[

const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import('resource://gre/modules/Services.jsm');

const FAKE_OPTIONS_URL = 'chrome://mynamespace/content/redirect.xul';
const REAL_OPTIONS_URL = 'chrome://mynamespace/content/settings.xul';

window.onload = function () {
var topWindow = window.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShellTreeItem)
.rootTreeItem
.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIDOMWindow);

if (topWindow.document.documentURI == FAKE_OPTIONS_URL) {
let recentWindow = Services.wm.getMostRecentWindow('navigator:browser');
if (recentWindow && 'switchToTabHavingURI' in recentWindow) {
recentWindow.switchToTabHavingURI(REAL_OPTIONS_URL, true);
} else {
window.openDialog(REAL_OPTIONS_URL, null, 'width=1000,height=600,centerscreen,chrome');
}
setTimeout(window.close, 0);
} else {
location.replace (REAL_OPTIONS_URL);
}
};

//]]></script>
</window>

The code will open REAL_OPTIONS_URL in a new tab in Firefox 4+ and SeaMonkey 2.1+, and a window in anything else.

New in-Addon-Manager extension settings in Mozilla 7

A new feature of the Mozilla 7 platform (soon to be on the Aurora channels) is the ability for extensions to have settings user-interface directly inside the Addon Manager. This will enable restartless extensions to easily have settings, and will also work for traditional extensions.

Here's how to use the new tools:

Create an options file

In most cases this will be a file called options.xul, and located inside the top-level directory of the extension (alongside install.rdf etc.). Alternatively, you can put this file elsewhere, and change install.rdf - em:optionsURL pointing to the file, and em:optionsType as 2.

Start with this:

<?xml version="1.0" ?>
<vbox xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
<!-- settings go here -->
</vbox>

The settings are represented as a list of <setting> elements of various types, for example:

<setting type="bool"
title="Boolean Setting"
desc="This is a description of the setting"
pref="extensions.settings.bool"/>

This node is represented with a checkbox. Clicking on the checkbox changes the value of the preference specified.

A description can be set with a desc attribute, or with text between the opening and closing <setting> tags. Other attributes can be use to alter the UI displayed. See the XUL documentation on MDC for control attributes.

Here's what this example looks like:

Settings Types

type attributedisplayed aspreference stored as
bool checkbox boolean
boolint checkbox integer (use the attributes on and off to specify what values to store)
integer
textbox with type="number"
integer
string textbox
string
color colorpicker with type="button"
string (in the #123456 format)
file browse button and label string
directory browse button and label
string

(NB: color, file and directory types haven't landed just yet, see this bug.)

There's also the control type, which allows you to have a button or menulist control:

<setting type="control" title="Button">
<button label="click me!" oncommand="alert('thanks!');"/>
</setting>
<setting type="control" title="Menulist">
<menulist sizetopopup="always" onchange="alert(this.value);">
<menupopup>
<menuitem label="alpha" value="1"/>
<menuitem label="beta" value="2"/>
<menuitem label="charlie" value="3"/>
<menuitem label="delta" value="4"/>
</menupopup>
</menulist>
</setting>

Note that neither of these controls have pref attributes, you'll have to control them yourself. See below for details.

Here's what all these controls look like:

Need script?

Each time the UI is loaded, the notification addon-options-displayed is sent. Here's how to use it:

var observer = {
observe: function(aSubject, aTopic, aData) {
if (aTopic == "addon-options-displayed" && aData == "my@addon.id") {
// your code here
// aSubject is the Addon Manager document, so you can use aSubject.getElementById etc.
}
}
};
Services.obs.addObserver(observer, "addon-options-displayed", false);

Do NOT forget to remove your observer when your extension is shut down.

Adding your own settings types

If you're mad enough you can create your own setting type. Create your own XBL binding, using chrome://mozapps/content/extensions/setting.xml for example code, and bind your setting with it like this:

<setting type="mytype"
style="display:-moz-grid-line; -moz-binding:url('chrome://mynamespace/content/mybindings.xml#binding-id');"/>

If you think your setting type will be useful to others and should become a built-in type, file a bug and CC me (geoff@darktrojan.net).