SeaMonkey:Toolkit Transition:PrefwindowPanes:HowTo

From MozillaWiki
Jump to navigation Jump to search

The architecture patch in bug 394522 paved the way for migrating SeaMonkey's old XPFE preference panels to toolkit's <prefpane>s. See SeaMonkey:Toolkit_Transition:PrefwindowPanes for migration coordination (who's doing what?).

If you have any suggestions or questions, you can ask in the newsgroup mozilla.dev.apps.seamonkey or join the IRC channel #seamonkey on MozNet. Or email me.

PrefWindow v5 (XPFE) vs. v6 ("new toolkit")

The main difference between the two prefwindow versions is the way preference panels are handled: while v5 loaded each panel into one iframe (thus reloading the panel each time you change the panel!), v6 uses a lazy overlay mechanism: a pane is only loaded if it's needed and then only once. It's overlayed over the main preference window by courtesy of document.loadOverlay.

This change in behaviour has some important consequences:

  • Any pref panel is loaded only once, hence its potential Startup() method doesn't need to care for reentrancy or persisting data over panel changes.
  • In v6, nsWidgetStateManager.js and nsPrefWindow.js are obsolete and replaced by several bindings in preferences.xml.
  • Any <script>s in a panel's XUL will be loaded into the main preference window (not into the panel!), hence their globals and methods are likely to clash!

And preference panels are called "panes" in v6.

How to migrate a preference panel

To ease the migration, both v5 and v6 preference windows will be accessible during the transition:

  • Edit → Preferences... opens the new prefwindow main window preferences.xul.
  • Edit → (Legacy Prefwindow...) opens the old XPFE pref.xul.

1. Tree items

Edit /suite/common/pref/preferences.xul (or the respective overlay, if eg. you're migrating a MailNews panel) and set the following attributes on the respective <treeitem>:

<treeitem container="true"
          id="navigator"
          label="&navigator.label;"
          prefpane="navigator_pane"
          helpTopic="navigator_pref_navigator"
          url="chrome://communicator/content/pref/pref-navigator.xul">
  • The id attribute should adhere to the "xxxItem" meme — and all <treeitem>s should have an id! This id is used by overlays to place themselves at the correct place. (Certain old names - like the above - may not yet follow this, but this should be fixed!)
  • Keep the label of the old panel.
  • The prefpane attribute should adhere to the "xxx_pane" meme. This will be the id of the preference panel to be reached by this <treeitem> (see below).
  • Set the helpTopic attribute to the respective help identifier from /suite/common/pref/pref-help.js (that file will go, too, once all panels are migrated).
  • Set the url attribute to the chrome URI of the panel to be reached by this <treeitem>.

To minimize confusion about which panels are migrated and which not, comment out unmigrated treeitems in the new dialog and replace the label in the legacy dialog with "(migrated)". This is not done yet in the new dialog!

2. Panels

Old panels were actually "real" documents, loaded into a browser window. New panels are <prefpane> elements, overlayed over the main window. To avoid the global namespace clashes of <script>s mentioned above, SeaMonkey's prefwindow brings along some additional internal handling.

Old:

<page xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
      id="pref-navigator"
       onload="parent.initPanel('chrome://communicator/content/pref/pref-navigator.xul');"
      headertitle="&pref.navigator.title;">
...
  <script type="application/x-javascript"
          src="chrome://communicator/content/pref/pref-navigator.js"/>

New:

<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
  <prefpane id="navigator_pane"
            label="&pref.navigator.title;"
            script="chrome://communicator/content/pref/pref-navigator.js">
  • The id of the <prefpane> must the value of the prefpane attribute of the <treeitem> (see above).
  • The label should have the same value as the the old <page>.headertitle attribute. It will be shown above the panel.
  • The script attribute contains a whitespace delimited list of chrome URIs of the script files to be loaded into the panel's(!) scope. This means that the contents of these scripts will be accessible as members of the <prefpane> object, eg. document.getElementById("navigator_pane").Startup().
  • The onpaneload attribute can contain code which will be executed when the panel has finished loading, eg. this.Startup().

The old call to parent.initPanel is not needed anymore, panel initialization is done by the backend. If the panel's loaded scripts contain the special Startup() function, it will be called automatically on panel load.

3. Preferences

Preferences handling required some complicated hack-arounds, this has changed.

Old:

<page>
  <script type="application/x-javascript">
  <![CDATA[
    var _elementIDs = ["startupPage", "newWinPage", "newTabPage",
                       "bookmarksButton", "goButton", "homeButton",
                       "printButton", "searchButton" ];
  ]]>
  </script>
...
  <checkbox id="homeButton"
            label="&homeButton.label;"
            accesskey="&homeButton.accesskey;"
            prefstring="browser.toolbars.showbutton.home"/>

New:

<overlay>
  <prefpane>
    <preferences id="navigator_preferences">
      <preference id="browser.toolbars.showbutton.home"
                  name="browser.toolbars.showbutton.home"
                  type="bool"/>
...
    </preferences>
...
    <checkbox id="homeButton"
              label="&homeButton.label;"
              accesskey="&homeButton.accesskey;"
              preference="browser.toolbars.showbutton.home"/>

The <preferences> element must be a direct child of the <prefpane>, with the <preference>s as its children. Each <preference> needs the attributes name (with the name of the preference in prefs.js etc.) and type with its type, see DevMo for details. Since preference names are unique by default, the id attribute should be set to the pref name as well.

The former prefstring attribute on an element must be replaced by a preference attribute, which contains the id of the respective <preference>.

All reading/writing of preferences is handled by the backend, there is usally no need to instantiate preference interface/service!