toolsmith opportunity at Mozdev

The Mozilla-related job market seems to be heating up these days, and I even received an inquiry from a recruiter lately asking if I know of (or am) someone to hire.

Job postings from that recruiter (and others) are available on, and the Mozilla Corporation is also hiring, but I’d like to highlight something else: a Web Apps Developer/Sysadmin contract position at Mozdev.

Mozdev provides project hosting and development tools to Mozilla-related projects, and we’re looking for someone to enhance and integrate the services we provide.

This is a fantastic opportunity for an engineer’s engineer who really appreciates the value of good tools in the software development process and wants to implement and integrate the state of the art collaborative development tools (VCS, wiki, forum, bug tracking, etc.) and push the toolsmithing envelope.

If you know of (or are) the right person for this job, then don’t hesitate to apply!


tab-specific mute

I’ve heard from a number of folks that it’d be very useful for Firefox to let you mute a particular tab in the browser, since more and more sites are incorporating music or other audio content, and users are leaving more tabs open in the background, and they don’t necessarily want to hear those tabs while listening to tunes or working.

So I looked around for a way to do this (ideally something I could integrate with site-specific preferences, so you could specify which sites are allowed to quack), and the closest I could find is FlashMute, a small Windows app written by Einar Otto Stangvik that mutes all Flash (and other browser-based sound).

It’s like a global mute for browsers, and although it isn’t open source, its author says it will be once he gets around to pushing it to Google Code.

But it doesn’t let you mute individual tabs, much less specific sites, so it’s not quite the feature folks have been clamoring for.  So I asked around a bit, and smart folks seem to think it would be very hard to well nigh impossible to implement this on Windows, except possibly on Vista with major changes to our plugin architecture.

Anyone know different or know what the situation is on other platforms?


Site-Specific Preferences, Take 0.3

The Content Preferences extension version 0.3 is now available from the AMO sandbox.

I added these user-facing enhancements:

  • a site-specific Page Style setting for sites like that provide alternate stylesheets;
  • a site-specific Character Encoding setting for when Firefox incorrectly guesses the encoding on a site;
  • a Reset All button at the bottom of the sidebar that lets you reset all settings to their default values for the current site;
  • a Global tab that lets you set preferences that apply to all sites;
  • a yellow background color behind modified settings that helps you identify the settings you’ve twiddled;
  • a Reset button () next to modified settings for setting them back to their default values (thanks to Mark James for the icon, which comes from his Silk icon set).

Props to Alex Faaborg for his feedback on and assistance with several of these enhancements and to Dan Mosedale for pointing out the spiffy way OmniWeb lets you reset modified settings.

I should note that while I implemented site-specific Page Style (primarily to exercise the back-end code) in a way that could be integrated into the Firefox core, I think it would make more sense to move the entire Page Style feature out of the core and make it available only as an extension, given how rarely the feature is used.

But, as Mike Connor pointed out to me recently, UI for selecting an alternate stylesheet is actually mandated by the CSS 2 spec (section 3.2, point 5), and if we have to include it, we might as well make it work better.

On the back-end, the extension sports the following enhancements:

  • a declarative syntax (modeled after the one used by the Preferences dialog) for describing widgets in the sidebar, which the sidebar controller uses to auto-update prefs when users twiddle widgets (and vice-versa);
  • nsIObserver-style notifications from the service and the controller;
  • DOMContentLoaded notifications from the controller, in addition to the location change notifications, to support settings like Page Style that need to do their thing after the page has loaded;
  • nsIVariant pref values stored as blobs in the database, for theoretical round-trip integrity to the database and beyond, err, back;
  • auto-derivation of sites from URIs inside all service methods, so instead of calling getSiteForURI to derive the site and then a second method like getPref to do some actual work, you just call the second method, passing it the URI, and let the service do the deriving.

I also fixed a number of miscellaneous bugs (and undoubtedly introduced new ones) and worked around a few bugs in Firefox. Many thanks to John P. Baker for spotting some of the problems and providing useful feedback on the API.

Per the Firefox 3 product plan, my next step will be to integrate the core service and site-specific text zoom into the browser core, for which I’ve filed bugs 378547 and 378549, respectively.

The sidebar, on the other hand, and the other two settings it exposes will remain an extension for now.


The End of the URL?

I was listening to BBC news radio last night when the announcer said to “type World Business Report into the search engine and follow the link from there” for the latest version of the report.

He followed up by mentioning the BBC’s news domain name ( as an alternative, but it was striking that he considered “the search engine” a more reliable path to the program’s page.

Of course, the actual URL for that page is pretty long, and it isn’t available directly from the BBC news home page or even from its Business page, so he’s probably right.

For Google and MSN, anyway, both of which return the report as the second search result (the first being the BBC’s other World Business Report, a TV program).

Yahoo, on the other hand, returns the Wikipedia entry describing the TV program as its first result.  The radio program page is below the fold (on my monitor) as the fourth result.


microsummaries for the Summer of Code

I’ve added three microsummary-related projects to Mozilla’s Summer of Code project list:

  • rich content microsummaries: support for HTML and image-based microsummaries
  • microsummary builder: a tool to make microsummaries simpler to create (for both regular users and developers)
  • microsummary generator web service: integration with a generator repository, including auto-notification and easy installation of available generators for the sites you browse

The deadline for applying to hack on one of these projects is today at 5pm PDT (midnight UTC), which is just hours away, so if you’re interested in tackling one of these, don’t delay!


Content Preferences – Architecture/API

The content preferences code currently has a four piece architecture:

  1. a service that manages the database of prefs;
  2. a controller for each window that watches the browser’s location and notifies pref handlers when it changes;
  3. pref handlers that tweak the browser according to the user’s prefs;
  4. a sidebar housing controls for twiddling prefs.

In the first version of the extension, I designed these to support preferences like the text zoom pref.  In v2 I redesigned them to improve that support and tried to generalize the API to work for other prefs.

But a single caller is a very limited perspective for designing an API (indeed, I’ve already found issues while getting a second pref up and running on it), so I’m keen to get feedback on how to make this work well for other prefs (in both core code and extensions).

Here’s how it works at the moment:

The Service (mozISitePrefService)

The service manages the database of prefs.  Its API is pretty simple.  It has four core methods, getPref, setPref, hasPref, and removePref:

mozISitePref getPref(in AUTF8String site, in AUTF8String key);
void setPref(in AUTF8String site, in AUTF8String key, in AUTF8String value);
boolean hasPref(in AUTF8String site, in AUTF8String key);
void removePref(in AUTF8String site, in AUTF8String key);

It also has a method, getPrefs, that gets all prefs for a site, and it has another method, getSiteForURI, that extracts a site identifier from a URI:

void getPrefs(in AUTF8String site, 
out unsigned long prefCount,
[retval, array, size_is(prefCount)] out mozISitePref prefs);

AUTF8String getSiteForURI(in nsIURI uri);

Site identifiers are full domains by default (f.e., but you can configure the extension to use base domains (f.e., and perhaps we’ll cook up other options in the future.

The interface to a preference (mozISitePref) is very basic:

readonly attribute AUTF8String site;
readonly attribute AUTF8String key;
readonly attribute AUTF8String value;

The Controller (SitePref)

The controller’s job is to notify pref handlers when the browser location changes so those handlers can apply the user’s preferences for the new location.  It has addObserver and removeObserver methods that handlers can use to register/unregister themselves for notifications:

addObserver(in AUTF8String key, in nsISupports observer)
removeObserver(in AUTF8String key, in nsISupports observer)

The methods take a pref key so the controller know what setting the handler cares about.  When the location changes, the controller grabs the set of prefs for the new location and calls each observer’s onLocationChange method with the pref it cares about (if any):

onLocationChange(in nsISitePref pref) 

The Pref Handlers

The pref handlers implement the aforementioned onLocationChange method and then do whatever they need to do to apply user preferences to the browser.

The Sidebar (chrome://cpref/content/sidebar.xul)

The sidebar provides a central location for site-specific preference controls.  It’s an experiment in exposing these preferences in a place that is location-specific (unlike the Preferences dialog) and visible alongside the page being affected (unlike the View menu).

It doesn’t do much besides provide a place for pref controls to overlay themselves onto.  Controls are responsible for updating themselves when the location changes.  But the sidebar does define a gMainWindow shortcut for getting the browser window that the sidebar is embedded in.


I’m interested in feedback on all aspects of this API.  Here are the questions I know I should ask:

  1. Should pref values be typed?

    We can’t store them typed in the database given the EAV model we’re using to store them (although we could change the model if it mattered enough), but we could convert them on their way in and out of the database and have type-specific methods for getting and setting them (à la nsIPrefBranch).

  2. Should pref handlers listen for location changes themselves and get their prefs directly from the service instead of having that work be mediated by the controller?

    It’s faster for the controller to query once for all prefs, and it’s simpler on the pref handlers not to have to implement nsIWebProgressListener themselves, but it makes the architecture more complex, since it adds an extra layer between the service and the handlers.

  3. Is AUTF8String the right string type for site identifiers and keys?

And then there are all those questions I don’t know I should be asking (along with their answers), so clue me in!


Content Preferences – take 2

I released an updated version of the Content Preferences extension today.

This update features significant changes under the hood to improve the API for extensions that want to use it to store their own site-specific prefs (about which more shortly).

It also offers the following two improvements for end-users who use it for its text-zoom functionality:

  1. Text zoom changes via the mousewheel are now supported, so no matter how you change your text zoom (via the View menu, keyboard shortcuts, the sidebar slider provided by this extension, or mousewheel gestures), this extension will save your setting for each site you visit.
  2. An experimental mode lets you set preferences for a domain and all its subdomains. (f.e. * To enable this mode, use about:config to set the extensions.cpref.siteMode preference to the number 1.

    If you’re trying out the Gran Paradiso Alpha 2 release (or trunk nightlies), the extension uses the new “effective TLD service” to correctly determine the base domain for each site (f.e. for and for Otherwise, it falls back to the “top-level domain plus one segment” rule (i.e. for and for

Give it a try, and let me know what you think.


Three Things I Love About Komodo

Last week ActiveState released version 4.0 of their Komodo IDE (and announced Komodo Edit, a new free-as-in-beer version of the app).  Komodo, like Songbird and Democracy, is Mozilla-based, and I’ve been using it as my primary editor for several years.

Here are three things I love about it:


Like Firefox with web pages, Komodo uses tabs to present multiple documents in a single window.  Tabs blows away every previous MDI approach for usability, and I wince whenever I have to use an application (TextWrangler, emacs) that presents multiple documents in any other way.

Indentation Adjustment

This may sound trivial, but Komodo has the easiest keyboard shortcut for adjusting indentation of any editor I’ve ever used.  Just select the lines (or portions thereof) you want to indent and press the Tab key.  To unindent, press Shift-Tab.

Komodo will indent using tab characters or spaces per your settings (which you can set for individual files) or by sniffing out the indentation strategy already in use in the file.

Fully-Configurable Key Bindings and Syntax Highlighting

I almost never tweak these settings, but it made a big difference to be able to do so when I first started using the application.

In Komodo, every keyboard shortcut is configurable, which I used to change “Find Next” from F3 to Ctrl-G and “Go to Line” from Ctrl-G to Ctrl-L to match what I was used to from previous editors.

Syntax highlighting is also customizable–including font family, size, color, and background color–down to individual language elements, so you can give JS variables, HTML attributes, and Python comments their own individual styles.

Komodo also provides an Emacs key binding scheme and a Vi compatibility mode, if that’s your thing.  And it includes several built-in highlighting schemes, so you don’t have to design your own from scratch (I started with “Dark” and made a few tweaks).

Everything Else

There are tons of other things to love, of course, like integrated debugging for half a dozen scripting languages, remote file access via S/FTP or SCP, code completion, background syntax checking, integrated source control for CVS, SVN, and Perforce, and so on.

And then there are the features I haven’t learned to love yet, because they’re new in version 4.0, but which I expect to come to rely upon in the future, like support for Firefox-style extensions.

Did I mention that it’s cross-platform (Windows, Mac, and Linux)?  If you’re looking for a great text editor/IDE, check it out.


cool vs. useful

Software engineers love cool new features, because programming is hard, and a cool hack represents a triumph of ingenuity and skill against the odds.

But computer users tend to prefer useful features to cool ones, because they use computers in order to get things done, and useful features help them do that.

Unfortunately, many apps suffer from an overfocus on cool, but I’m pleased to note (in a super-unscientific survey) that Google Groups reports only 24 results for the word “cool” in the newsgroup, where engineers and others discuss the development of Firefox, whereas “useful” appears in 85 posts.