Education/Learning/Preferences

From MozillaWiki
Jump to: navigation, search

Introduction

Mozilla applications like Firefox or Thunderbird are highly configurable via a preference system. Developing new features, or fixing bugs in existing code, often means identifying and honouring the wishes of the user, as expressed in various preferences. When you're working on a piece of code in JavaScript or C++, you need to know how to determine the value of preferences at run-time.

This discussion will take a real example from Firefox and show how the preferences is accessed by the user, implemented in terms of UI, and then used by C++ code in order to determine run-time behaviour. All code samples below are taken from the following revision of mozilla-central: http://hg.mozilla.org/mozilla-central/file/0cd41f599080/

A Firefox Preference

When you close your browser, what should happen to all the private data that was stored during your various sessions? Should things like cookies and other data remain? Should they be deleted? It's not something that Firefox determines at compile time. Instead there is a preference so the user can decide.

The easiest way to change this behaviour is to open the Firefox Preferences dialog (Tools > Options on Windows, Firefox > Preferences on Mac) and navigate to the Privacy panel. There, under Private Data, you'll find the following checkbox:

Always clear my private data when I close Firefox

Now that we have the UI string, we can go looking for the actual preference and code to deal with it.

Finding a Preference

Using MXR we can search for this UI string, and find the DTD file where it is defined (Mozilla localizes all strings in the UI). A quick search reveals the following entity in privacy.dtd:

44 <!ENTITY  alwaysClear.label "Always clear my private data when I close &brandShortName;">

Now we have an entity name vs. a localized string (i.e., alwaysClear.label) to search for within the XUL code. Another search reveals the use of this entity in privacy.xul:

178 <checkbox id="alwaysClear" flex="1"
179           preference="privacy.sanitize.sanitizeOnShutdown"
180           label="&alwaysClear.label;"
181           accesskey="&alwaysClear.accesskey;"/>

This is the checkbox we saw in the UI, and also the next bit of information we need to continue our search: the name of the preference itself:

179           preference="privacy.sanitize.sanitizeOnShutdown"

Preferences are named using this dot notation, which denotes a tree structure (i.e., privacy can (and does) have many related children beneath it). At this point we can go and look at the current value of the preference by name using the browser itself. In your address bar, enter the following location:

about:config

This gives a complete list of the preferences currently set for the browser. Obviously there are many more than have visible UI in the preferences dialog. You can add preferences here simply by right-clicking and selecting New.

To locate a preference, begin typing its name: privacy.sanitize.sanitizeOnShutdown. If you want to alter the value of this preference, simply double-click on it.

Accessing the preference value from code

Looking around users of this preference in the code reveals a few interesting things. First, we see the default value being set in firefox.js:

411 pref("privacy.sanitize.sanitizeOnShutdown", false);

We also see how the value of this preference influences what happens on shutdown in nsNavHistoryExpire::OnQuit():

91 // Sanitization preferences
92 #define PREF_SANITIZE_ON_SHUTDOWN   "privacy.sanitize.sanitizeOnShutdown"
...
213   nsCOMPtr<nsIPrefBranch> prefs(do_GetService("@mozilla.org/preferences-service;1"));
214   PRBool sanitizeOnShutdown, sanitizeHistory;
215   prefs->GetBoolPref(PREF_SANITIZE_ON_SHUTDOWN, &sanitizeOnShutdown);
216   prefs->GetBoolPref(PREF_SANITIZE_ITEM_HISTORY, &sanitizeHistory);
217   if (sanitizeHistory && sanitizeOnShutdown)
218     return;

This is a common pattern seen all over the Mozilla source. It begins with a define for the preference name, which will be used by nsIPrefBranch to get the desired value.

Next, we see XPCOM code to get the Preferences Service using the nsIPrefBranch interface. Using nsIPrefBranch's GetBoolPref method, a PRBool is populated with the value needed.

Other Resources

There are many good resources available for further reading on the subject of Preferences:

Also remember that the source code is filled with great examples, like the one above.