mozilla

Revision 74241 of Building a Thunderbird extension 1: introduction

  • Revision slug: Extensions/Thunderbird/Building_a_Thunderbird_extension
  • Revision title: Building a Thunderbird extension 1: introduction
  • Revision id: 74241
  • Created:
  • Creator: Jcarroll
  • Is current revision? No
  • Comment /* Test */

Revision Content

Introduction

This tutorial will take you through the steps required to build a very basic extension - one which adds a status bar panel to the Thunderbird Mail Client containing the text "Hello, World!"

This was taken almost verbatim from Building an Extension.

Note This tutorial is about building extensions for Thunderbird 2.0.

Setting up the Development Environment

Extensions are packaged and distributed in ZIP files, or Bundles, with the <tt>xpi</tt> (pronounced “zippy”) file extension. The layout of content within the XPI file is like so:

extension.xpi:
              /install.rdf                   
              /components/*  
              /components/cmdline.js                   
              /defaults/
              /defaults/preferences/*.js     
              /plugins/*                        
              /chrome.manifest                
              /chrome/icons/default/*       
              /chrome/
              /chrome/content/
     

Because of this, it is easiest if we lay out our source files in a similar fashion, unless you want to write some sort of Makefile or shell script to package and zip all of your files. Even if you are prepared to do that, testing is much simpler if you lay out your files like this because of a feature of the Add-on System provided by Thunderbird 2.0 and later.

So let's get started. Create a folder for your extension somewhere on your hard disk, e.g. (Windows) <tt>C:\extensions\my_extension\</tt> or (Linux/Unix) <tt>~/extensions/my_extension/</tt>. (note: use all lower case) Inside this folder create another folder called <tt>chrome</tt>, inside the <tt>chrome</tt> folder create a folder called <tt>content</tt>. (On Unix-like systems you can usually create both directories just by running <tt>mkdir -p chrome/content</tt> from within the extension's root directory.)

Inside the root of your extension folder, alongside the <tt>chrome</tt> folder, create two new empty text files, one called <tt>chrome.manifest</tt> and the other called <tt>install.rdf</tt>.

More tips on setting up the development environment can be found in the article Setting up extension development environment.

Create the Install Manifest

Open the file called <tt>install.rdf</tt> that you created at the top of your extension's folder hierarchy and put this inside:

<?xml version="1.0"?>

<RDF xmlns="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
     xmlns:em="http://www.mozilla.org/2004/em-rdf#">

  <Description about="urn:mozilla:install-manifest">
    <em:id>sample@foo.net</em:id>
    <em:version>1.0</em:version>
    
   
    <!-- Target Application this extension can install into, 
         with minimum and maximum supported versions. --> 
    <em:targetApplication>
      <Description>
        <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
        <em:minVersion>1.5</em:minVersion>
        <em:maxVersion>2.0.0.*</em:maxVersion>
      </Description>
    </em:targetApplication>
   
    <!-- Front End MetaData -->
    <em:name>Sample!</em:name>
    <em:description>A test extension</em:description>
    <em:creator>Your Name Here</em:creator>
    <em:homepageURL>http://www.foo.com/</em:homepageURL>
  </Description>      
</RDF>
  • sample@foo.net - the ID of the extension. This is some value you come up with to identify your extension in email address format (note that it should not be your email). Make it unique. You could also use a GUID that looks like Thunderbird's application ID. However it must not be the same and should be unique.
  • We did not specify <tt><em:type>2</em:type></tt> -- the 2 declares that it is installing an extension. Unlike Firefox, Thunderbird seems to not need it. At least Spamato didn't have it in there either and the extension does install properly. If you were to install a theme it would be 4 (see Install Manifests#type for other type codes).
  • {3550f703-e582-4d05-9a08-453d09bdfdc6} - Thunderbird's application ID. Without this exact number it will not install. (Note: this ID is not Thunderbird's current application ID)
  • 1.5 - the minimum version of Thunderbird you're saying this extension will work with. Set this as the minimum version you're going to commit to testing and fixing bugs with.
  • 2.0.0.* - the maximum version of Thunderbird you're saying this extension will work with. Set this to be no newer than the newest currently available version! In this case, "2.0.0.*" indicates that the extension works with versions of Thunderbird 2.0.0.0 through 2.0.0.x.

Extensions designed to work with Thunderbird 1.5.0.x at the latest should set the maximum version to "1.5.0.*".

See Install Manifests for a complete listing of the required and optional properties.

Save the file.

Extending the Mail Client with XUL

Thunderbird's user interface is written in XUL and JavaScript. XUL is an XML grammar that provides user interface widgets like buttons, menus, toolbars, trees etc. User actions are bound to functionality using JavaScript.

To extend the application, we modify parts of the application's UI by adding or modifying widgets. We add widgets by inserting new XUL DOM elements into the application window, and modify them by using script and attaching event handlers.

The application is implemented in a XUL file called <tt>messenger.xul</tt> (<tt>$THUNDERBIRD_INSTALL_DIR/chrome/messenger.jar</tt> contains <tt>content/messenger/messenger.xul</tt>). In messenger.xul we can find the status bar, which looks something like this:

<statusbar id="status-bar">
 ... <statusbarpanel>s ...
</statusbar>

<tt><statusbar id="status-bar"></tt> is a "merge point" for a XUL Overlay. There is nothing special about a merge point except that this is the main widget where you can put your extension. This statusbar is the last component on the screen. It shows the number of UnRead messages and Total messages. So for this example its a good beginning place to put this example extension.

 To view the jar file under linux:
 cd ~
 mkdir tmpext
 cd tmpext
 unzip <tt>$THUNDERBIRD_INSTALL_DIR/chrome/messenger.jar</tt>
 cd content
 gvim messenger/messenger.xul
 press the capital letter G this will place you at the bottom of the file.
 you will see the statusbar. This is where we are "hooking" into.

If you start looking from the top of the file to the end, you will see various IDs. These are associated with a type of widget. In our example, the statusbar is the widget (look before the id= ) and then the name of that particular widget happens to also be statusbar. Now it could have a name of laststatusbar or something like that. If you were to make a statusbar you could name it anything you wanted as long as it didn't conflict with a previous named widget (standard programming rules).

XUL Overlays

XUL Overlays are a way of attaching other UI widgets to a XUL document at run time. A XUL Overlay is a .xul file that specifies XUL fragments to insert at specific merge points within a "master" document. These fragments can specify widgets to be inserted, removed, or modified.

Note that you are adding a line to the indented statusbar. Therefore it becomes an "item owned by" the id called statusbar. This allows us users to modify the application without actually touching any of the install files. Therefore after the main application gets an update installed, all of the user's extensions come right back (if they are compatible) onto the newly installed version of the program.

Example XUL Overlay Document

<?xml version="1.0"?>
<overlay id="sample" 
xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
 <statusbar id="status-bar">
  <statusbarpanel id="my-panel" label="Hello, World"/>
 </statusbar>
</overlay>

The <tt><statusbar></tt> widget named <tt>status-bar</tt> specifies the "merge point" within the browser window that we want to attach to. We want to ADD our item to that widget.

The <tt><statusbarpanel></tt> child is a new widget that we want to insert within the merge point also called a widget. The statusbarpanel type of widget already exists as a widget type in the application. We are saying "Create an instance of statusbarpanel that can be referred to as my-panel". So anything I do to my-panel as a widget will be reflected in my specific widget. So if you wanted to add something to Spamato's widgets, let's say his menu widget (which is a menupopup type of widget). The menupopup widget has an instance name called spamatoPopup. Then you could have something like this (its untested though):

 <menupopup id="spamatoPopup">
  <menuitem id="my-panel" label="Hello, World"/>
 </menupopup>

This would place your item on Spamato's menu under the Tools section of Thunderbirds top menu. Very cool. This example was after unzipping the spamato.xpi file. Go into chrome and unzip the spamato.jar file. It creates a few directories. Go into content/spamato. Now open the file with a text editor called SpamatoOverlay.xul. Search for spamatoPopup and you'll see what his file looks like.

Take this sample code above (not the Spamato code) and save it into a new file called <tt>sample.xul</tt> inside the <tt>chrome/content</tt> folder you created.

For more information about merging widgets and modifying the user interface using Overlays, see below.

Chrome URIs

This is browser related but you must know the underlying reasons for the <tt>chrome://</tt> URI. It is a way of accessing features of the application without knowing where that application is installed. It gives a generalized method for accessing everything that the application offers up.

XUL files are part of "Chrome Packages" - bundles of user interface components which are loaded via <tt>chrome://</tt> URIs. Rather than load the browser from disk using a <tt>file://</tt> URI (since the location of Firefox on the system can change from platform to platform and system to system), Mozilla developers came up with a solution for creating URIs to XUL content that the installed application knows about.

The browser window is: <tt>chrome://browser/content/browser.xul</tt> Try typing this URL into the location bar in Firefox!

On Thunderbird, the URI is <tt>chrome://messenger/content/messenger.xul</tt>

Chrome URIs consist of several components:

  • First, the URI scheme (<tt>chrome</tt>) which tells the application's networking library that this is a Chrome URI. It indicates that the content of the URI should be handled as a (<tt>chrome</tt>). Compare (<tt>chrome</tt>) to (<tt>http</tt>) which tells Firefox to treat the URI as a web page.
  • Second, a package name (in the example above, <tt>browser</tt>) which identifies the bundle of user interface components. This should be as unique to your application as possible to avoid collisions between extensions. Remember for thunderbird it is <tt>messenger</tt> which is a hold over from Netscape Messenger I would venture to guess.
  • Thirdly, the type of data being requested. There are three types: <tt>content</tt> (XUL, JavaScript, XBL bindings, etc.) that form the structure and behavior of an application UI, <tt>locale</tt> (DTD, .properties files etc) that contain strings for the UI's localization, and <tt>skin</tt> (CSS and images) that form the theme of the UI.
  • Finally, the path of a file to load.

So, <tt>chrome://foo/skin/bar.png</tt> loads the file <tt>bar.png</tt> from the <tt>foo</tt> theme's <tt>skin</tt> section.

When you load content using a Chrome URI, the application uses the Chrome Registry to translate these URIs into the actual source files on disk (or in JAR packages).

Create a Chrome Manifest

For more information on Chrome Manifests and the properties they support, see the Chrome Manifest Reference.

Open the file called <tt>chrome.manifest</tt> that you created alongside the <tt>chrome</tt> directory at the root of your extension's source folder hierarchy.

Add in this code:

content     sample    chrome/content/

(Don't forget the trailing slash, "<tt>/</tt>"! Without it, the extension won't get loaded.)

Note: Make sure you use all lowercase characters for the package name ("sample") as Firefox/Thunderbird 1.5 doesn't support mixed/camel case. Apparently it will in version 2.

This specifies the:

  1. type of material within a chrome package
  2. name of the chrome package
  3. location of the chrome packages' files

So, this line says that for a chrome package sample, we can find its content files at the location <tt>chrome/content</tt> which is a path relative to the location of <tt>chrome.manifest</tt>.

Note that content, locale and skin files must be kept inside folders called content, locale and skin within your <tt>chrome</tt> subdirectory.

Save the file. When you launch Thunderbird with your extension, (later in this tutorial), this will register the chrome package.

Register an Overlay

You need Thunderbird to merge your overlay with the messenger window whenever it displays one. So add this line to your <tt>chrome.manifest</tt> file:

overlay chrome://messenger/content/messenger.xul chrome://sample/content/sample.xul

This tells Thunderbird to merge <tt>sample.xul</tt> into <tt>messenger.xul</tt> when <tt>messenger.xul</tt> loads. Ever wonder why these apps start up so slowly? Its all the parsing of these files and running down the "includes" at runtime instead of at compile time.

Test

First, we need to tell Thunderbird about your extension. In the bad old days of Firefox 1.0 this meant packaging your extension as a XPI and installing it through the user interface, which was a real pain. Now, it's much simpler (well sort of). Thunderbird has digressed a bit in this area for security reasons. You or the user can do one of three things: 1) save the xpi (shown in the next step) into your (Linux) ~/.thunderbird/(profile name)/extensions directory or 2) unzip the xpi into that directory. 3) create a symlink in ~/.thunderbird/(profile name)/extensions that points to the directory containing your install.rdf file. If using the first step then when you restart Thunderbird will recognize that you have an uninstalled extension waiting to be installed and prompt you to install it. If you use number two then you might miss something that the install script wanted you to do. So its best to install using the first method. Using number 3 will yield similar behaviour as number 1.

  1. Shutdown Thunderbird completely. All instances that are being tested with the profile.
  2. Open your Thunderbird Profile Folder. In Linux it is ~/.thunderbird/(profile name) . The profile name could look like a cryptic string with the .default at the end.
  3. Open the extensions folder.
     mkdir sample@foo.net 
  4. Remember when you made the Install Manifest above? You said the id of this extension was sample@foo.net. After you get this running, go back and change that and these instructions according to what you will really call this extension.
     cd sample@foo.net 
  5. Copy the entire directory structure of your extension <tt>C:\extensions\my_extension\</tt> or <tt>~/extensions/my_extension/</tt> to the extensions directory. In this test, you don't need a fancy install so this will suffice. In Linux you'll <tt>cp -fr ~/extensions/my_extension/* .</tt> You can also create a symlink if you would rather not place your development files under your <tt>.thunderbird </tt> directory.

Now you're ready to test your extension!

Start Thunderbird. Thunderbird will detect the extension and automatically use it. When the message window appears you should see the text "Hello, World!" on the right side of the status bar panel.

You can now go back and make changes to the .xul file, close and restart Thunderbird and they should appear.

Package

Now that your extension works, you can package it for deployment and installation.

Zip up the contents of your extension's folder (not the extension folder itself), and rename the zip file to have a .xpi extension. In Windows XP, you can do this easily by selecting all the files and subfolders in your extension folder, right click and choose "Send To -> Compressed (Zipped) Folder". A .zip file will be created for you. Just rename it and you're done!

On Mac OS X, you can right-click on the contents of the extension's folder and choose "Create Archive of..." to make the zip file. However, since Mac OS X adds hidden files to folders in order to track file metadata, you should instead use the Terminal, delete the hidden files (whose names begin with a period), and then use the <tt>zip</tt> command on the command line to create the zip file.

On Linux, you would likewise use the command-line Zip tool.

 cd ~/extensions/my_extensions
 zip -r ../sample.xpi *

When placed in the (user's profile)/extension directory, Thunderbird will open the xpi, check the id in the install.rdf and create that directory for your package. It will then cd to that directory and unzip the files thereby creating a mirror of your ~/extensions/my_extension directory structure and files.

If you have the 'Extension Builder' extension installed it can compile the .xpi file for you (Tools -> Extension Developer -> Extension Builder). Merely navigate to the directory where your extension is (install.rdf etc.), and hit the Build Extension button. This extension has a slew of tools to make development easier.

Now upload the .xpi file to your server, making sure it's served as <tt>application/x-xpinstall</tt>. You can link to it and allow people to download and install it in Thunderbird.

Note As a service to your users, tell them to save the file into their local Thunderbird directory, profile name, extensions. In Linux it is ~/.thunderbird/(profile name is different for each user)/extensions .

Installing from a web page

There are a variety of ways you can install extensions from web pages, including direct linking to the XPI files and using the InstallTrigger object. Extension and web authors are encouraged to use the InstallTrigger method to install XPIs, as it provides the best experience to users.

Using addons.mozilla.org

Mozilla Update is a distribution site where you can host your extension for free. Your extension will be hosted on Mozilla's mirror network to guarantee your download even though it might be very popular. Mozilla's site also provides users easier installation, and will automatically make your newer versions available to users of your existing versions when you upload them. In addition Mozilla Update allows users to comment and provide feedback on your extension. It is highly recommended that you use Mozilla Update to distribute your extensions!

Visit http://addons.mozilla.org/developers/ to create an account and begin distributing your extensions!

Note: Your Extension will be passed faster and downloaded more if you have a good description and some screenshots of the extension in action.

Registering Extensions in the Windows Registry

On Windows, information about extensions can be added to the registry, and the extensions will automatically be picked up the next time the applications starts. This allows application installers to easily add integration hooks as extensions. See Adding Extensions using the Windows Registry for more information.

Revision Source

<h4 name="Introduction"> Introduction </h4>
<p>This tutorial will take you through the steps required to build a very basic <a href="en/Extensions">extension</a> - one which adds a status bar panel to the Thunderbird Mail Client containing the text "Hello, World!"
</p><p>This was taken almost verbatim from <a href="en/Building_an_Extension">Building an Extension</a>.
</p>
<div class="note">
<p><b>Note</b> This tutorial is about building extensions for Thunderbird 2.0. 
</p>
</div>
<h4 name="Setting_up_the_Development_Environment"> Setting up the Development Environment </h4>
<p>Extensions are packaged and distributed in ZIP files, or <a href="en/Bundles">Bundles</a>, with the <tt>xpi</tt> (<i>pronounced “zippy”</i>) file extension. The layout of content within the XPI file is like so:
</p>
<pre class="eval">extension.xpi:
              /<a href="en/Install.rdf">install.rdf</a>                   
              <a href="#XPCOM_Components">/components/*</a>  
              <a href="#Application_Command_Line">/components/cmdline.js</a>                   
              <a href="#Defaults_Files">/defaults/</a>
              <a href="#Defaults_Files">/defaults/preferences/*.js</a>     
              /plugins/*                        
              /<a href="en/Chrome.manifest">chrome.manifest</a>                
              /<a href="en/Chrome_window_icons">chrome/icons/default/*</a>       
              /chrome/
              /chrome/content/
     
</pre>
<p>Because of this, it is easiest if we lay out our source files in a similar fashion, unless you want to write some sort of Makefile or shell script to package and zip all of your files. Even if you are prepared to do that, testing is much simpler if you lay out your files like this because of a feature of the Add-on System provided by Thunderbird 2.0 and later. 
</p><p>So let's get started. Create a folder for your extension somewhere on your hard disk, e.g. (Windows) <tt>C:\extensions\my_extension\</tt> or (Linux/Unix) <tt>~/extensions/my_extension/</tt>. (note: use all lower case) 
Inside this folder create another folder called <tt>chrome</tt>, inside the <tt>chrome</tt> folder create a folder called <tt>content</tt>. (On Unix-like systems you can usually create both directories just by running <tt>mkdir -p chrome/content</tt> from within the extension's root directory.)
</p><p>Inside the <b>root</b> of your extension folder, alongside the <tt>chrome</tt> folder, create two new empty text files, one called <tt>chrome.manifest</tt> and the other called <tt>install.rdf</tt>.
</p><p>More tips on setting up the development environment can be found in the article <a href="en/Setting_up_extension_development_environment">Setting up extension development environment</a>.
</p>
<h4 name="Create_the_Install_Manifest"> Create the Install Manifest </h4>
<p>Open the file called <tt><a href="en/Install_Manifests">install.rdf</a></tt> that you created at the top of your extension's folder hierarchy and put this inside:
</p>
<pre class="eval">&lt;?xml version="1.0"?&gt;

&lt;RDF xmlns="<span class="plain">http://www.w3.org/1999/02/22-rdf-syntax-ns#</span>"
     xmlns:em="<span class="plain">http://www.mozilla.org/2004/em-rdf#</span>"&gt;

  &lt;Description about="urn:mozilla:install-manifest"&gt;
    &lt;em:id&gt;<b>sample@foo.net</b>&lt;/em:id&gt;
    &lt;em:version&gt;<b>1.0</b>&lt;/em:version&gt;
    
   
    &lt;!-- Target Application this extension can install into, 
         with minimum and maximum supported versions. --&gt; 
    &lt;em:targetApplication&gt;
      &lt;Description&gt;
        &lt;em:id&gt;<b>{3550f703-e582-4d05-9a08-453d09bdfdc6}</b>&lt;/em:id&gt;
        &lt;em:minVersion&gt;<b>1.5</b>&lt;/em:minVersion&gt;
        &lt;em:maxVersion&gt;<b>2.0.0.*</b>&lt;/em:maxVersion&gt;
      &lt;/Description&gt;
    &lt;/em:targetApplication&gt;
   
    &lt;!-- Front End MetaData --&gt;
    &lt;em:name&gt;<b>Sample!</b>&lt;/em:name&gt;
    &lt;em:description&gt;<b>A test extension</b>&lt;/em:description&gt;
    &lt;em:creator&gt;<b>Your Name Here</b>&lt;/em:creator&gt;
    &lt;em:homepageURL&gt;<b><span class="plain">http://www.foo.com/</span></b>&lt;/em:homepageURL&gt;
  &lt;/Description&gt;      
&lt;/RDF&gt;
</pre>
<ul><li> <b>sample@foo.net</b> - the ID of the extension. This is some value you come up with to identify your extension in email address format (note that it should not be <i>your</i> email). Make it unique. You could also use a GUID that looks like Thunderbird's application ID. However it must not be the same and should be unique.
</li><li> We did not specify <tt>&lt;em:type&gt;2&lt;/em:type&gt;</tt> -- the 2 declares that it is installing an extension. Unlike Firefox, Thunderbird seems to not need it. At least Spamato didn't have it in there either and the extension does install properly. If you were to install a theme it would be 4 (see <a href="en/Install_Manifests#type">Install Manifests#type</a> for other type codes).
</li><li> <b>{3550f703-e582-4d05-9a08-453d09bdfdc6}</b> - Thunderbird's application ID. Without this exact number it will not install. (Note: this ID is not Thunderbird's current application ID)
</li><li> <b>1.5</b> - the minimum version of Thunderbird you're saying this extension will work with. Set this as the minimum version you're going to commit to testing and fixing bugs with. 
</li><li> <b>2.0.0.*</b> - the maximum version of Thunderbird you're saying this extension will work with. Set this to be no newer than the newest currently available version!  In this case, "2.0.0.*" indicates that the extension works with versions of Thunderbird 2.0.0.0 through 2.0.0.x.
</li></ul>
<p>Extensions designed to work with Thunderbird 1.5.0.x at the latest should set the maximum version to "1.5.0.*".
</p><p>See <a href="en/Install_Manifests">Install Manifests</a> for a complete listing of the required and optional properties. 
</p><p>Save the file.
</p>
<h4 name="Extending_the_Mail_Client_with_XUL"> Extending the Mail Client with XUL </h4>
<p>Thunderbird's user interface is written in XUL and JavaScript. <a href="en/XUL">XUL</a> is an XML grammar that provides user interface widgets like buttons, menus, toolbars, trees etc. User actions are bound to functionality using JavaScript. 
</p><p>To extend the application, we modify parts of the application's UI by adding or modifying widgets. We add widgets by inserting new XUL DOM elements into the application window, and modify them by using script and attaching event handlers. 
</p><p>The application is implemented in a XUL file called       <tt>messenger.xul</tt> (<tt>$THUNDERBIRD_INSTALL_DIR/chrome/messenger.jar</tt> contains <tt>content/messenger/messenger.xul</tt>). In messenger.xul we can find the status bar, which looks something like this:
</p>
<pre class="eval">&lt;statusbar id="status-bar"&gt;
 ... &lt;statusbarpanel&gt;s ...
&lt;/statusbar&gt;
</pre>
<p><tt>&lt;statusbar id="status-bar"&gt;</tt> is a "merge point" for a XUL Overlay. There is nothing special about a merge point except that this is the main widget where you can put your extension. This statusbar is the last component on the screen. It shows the number of UnRead messages and Total messages. So for this example its a good beginning place to put this example extension.
</p>
<pre class="eval"> To view the jar file under linux:
 cd ~
 mkdir tmpext
 cd tmpext
 unzip <tt>$THUNDERBIRD_INSTALL_DIR/chrome/messenger.jar</tt>
 cd content
 gvim messenger/messenger.xul
 press the capital letter G this will place you at the bottom of the file.
 you will see the statusbar. This is where we are "hooking" into.
</pre>
<p>If you start looking from the top of the file to the end, you will see various IDs. These are associated with a type of widget. In our example, the statusbar is the 
widget (look before the id= ) and then the name of that particular widget happens to also be statusbar. Now it could have a name of laststatusbar or something like that. If you were to make a statusbar you could name it anything you wanted as long as it didn't conflict with a previous named widget (standard programming rules).
</p>
<h5 name="XUL_Overlays"> XUL Overlays </h5>
<p><a href="en/XUL_Overlays">XUL Overlays</a> are a way of attaching other UI widgets to a XUL document at run time. A XUL Overlay is a .xul file that specifies XUL fragments to insert at specific merge points within a "master" document. These fragments can specify widgets to be inserted, removed, or modified. 
</p><p>Note that you are adding a line to the indented statusbar. Therefore it becomes an "item owned by" the id called statusbar. This allows us users to modify the application without actually touching any of the install files. Therefore after the main application gets an update installed, all of the user's extensions come right back (if they are compatible) onto the newly installed version of the program. 
</p><p><b>Example XUL Overlay Document</b>
</p>
<pre class="eval">&lt;?xml version="1.0"?&gt;
&lt;overlay id="sample" 
xmlns="<span class="plain">http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul</span>"&gt;
 &lt;statusbar id="<b>status-bar</b>"&gt;
  &lt;statusbarpanel id="my-panel" label="Hello, World"/&gt;
 &lt;/statusbar&gt;
&lt;/overlay&gt;
</pre>
<p>The <tt>&lt;statusbar&gt;</tt> widget named <tt><b>status-bar</b></tt> specifies the "merge point" within the browser window that we want to attach to. We want to ADD our item to that widget.
</p><p>The <tt>&lt;statusbarpanel&gt;</tt> child is a new widget that we want to insert within the merge point also called a widget. The statusbarpanel type of widget already exists as a widget type in the application. We are saying "Create an instance of statusbarpanel that can be referred to as my-panel". So anything I do to my-panel as a widget will be reflected in my specific widget. So if you wanted to add something to Spamato's widgets, let's say his menu widget (which is a menupopup type of widget). The menupopup widget has an instance name called spamatoPopup. Then you could have something like this (its untested though):
</p>
<pre class="eval"> &lt;menupopup id="<b>spamatoPopup</b>"&gt;
  &lt;menuitem id="my-panel" label="Hello, World"/&gt;
 &lt;/menupopup&gt;
</pre>
<p>This would place your item on Spamato's menu under the Tools section of Thunderbirds top menu. Very cool. This example was after unzipping the spamato.xpi file. Go into chrome and unzip the spamato.jar file. It creates a few directories. Go into content/spamato. Now open the file with a text editor called SpamatoOverlay.xul. Search for spamatoPopup and you'll see what his file looks like.
</p><p>Take this sample code above (not the Spamato code) and save it into a new file called     <tt><b>sample.xul</b></tt> inside the <tt>chrome/content</tt> folder you created.
</p><p>For more information about merging widgets and modifying the user interface using Overlays, see below.
</p>
<h4 name="Chrome_URIs"> Chrome URIs </h4>
<p>This is browser related but you must know the underlying reasons for the <tt>chrome://</tt> URI. It is a way of accessing features of the application without knowing where that application is installed. It gives a generalized method for accessing everything that the application offers up.
</p><p>XUL files are part of "<a href="en/Chrome_Registration">Chrome Packages</a>" - bundles of user interface components which are loaded via <tt>chrome://</tt> URIs. Rather than load the browser from disk using a <tt>file://</tt> URI (since the location of Firefox on the system can change from platform to platform and system to system), Mozilla developers came up with a solution for creating URIs to XUL content that the installed application knows about. 
</p><p>The browser window is: <tt>chrome://browser/content/browser.xul</tt> Try typing this URL into the location bar in Firefox!
</p><p>On Thunderbird, the URI is <tt>chrome://messenger/content/messenger.xul</tt>
</p><p>Chrome URIs consist of several components:
</p>
<ul><li> First, the <b>URI scheme</b> (<tt>chrome</tt>) which tells the application's networking library that this is a Chrome URI.  It indicates that the content of the URI should be handled as a (<tt>chrome</tt>).  Compare (<tt>chrome</tt>) to (<tt>http</tt>) which tells Firefox to treat the URI as a web page. 
</li><li> Second, a package name (in the example above, <tt><b>browser</b></tt>) which identifies the bundle of user interface components. This should be as unique to your application as possible to avoid collisions between extensions. Remember for thunderbird it is <tt><b>messenger</b></tt> which is a hold over from Netscape Messenger I would venture to guess.
</li><li> Thirdly, the type of data being requested. There are three types: <tt>content</tt> (XUL, JavaScript, XBL bindings, etc.) that form the structure and behavior of an application UI, <tt>locale</tt> (DTD, .properties files etc) that contain strings for the UI's <a href="en/Localization">localization</a>, and <tt>skin</tt> (CSS and images) that form the <a href="en/Theme">theme</a> of the UI.
</li><li> Finally, the path of a file to load. 
</li></ul>
<p>So, <tt>chrome://foo/skin/bar.png</tt> loads the file <tt>bar.png</tt> from the <tt>foo</tt> theme's <tt>skin</tt> section. 
</p><p>When you load content using a Chrome URI, the application uses the Chrome Registry to translate these URIs into the actual source files on disk (or in JAR packages).
</p>
<h4 name="Create_a_Chrome_Manifest"> Create a Chrome Manifest </h4>
<p>For more information on Chrome Manifests and the properties they support, see the <a href="en/Chrome_Manifest">Chrome Manifest</a> Reference.
</p><p>Open the file called <tt><b>chrome.manifest</b></tt> that you created alongside the <tt>chrome</tt> directory at the root of your extension's source folder hierarchy. 
</p><p>Add in this code:
</p>
<pre class="eval">content     sample    chrome/content/
</pre>
<p>(<b>Don't forget the trailing slash, "<tt>/</tt>"!</b> Without it, the extension won't get loaded.)
</p><p>Note: Make sure you use all lowercase characters for the package name ("sample") as Firefox/Thunderbird 1.5 doesn't support mixed/camel case. Apparently it will in version 2.
</p><p>This specifies the:
</p>
<ol><li> type of material within a chrome package
</li><li> name of the chrome package
</li><li> location of the chrome packages' files
</li></ol>
<p>So, this line says that for a chrome package <b>sample</b>, we can find its <b>content</b> files at the location <tt>chrome/content</tt> which is a path relative to the location of <tt>chrome.manifest</tt>. 
</p><p>Note that content, locale and skin files must be kept inside folders called content, locale and skin within your <tt>chrome</tt> subdirectory.
</p><p>Save the file. When you launch Thunderbird with your extension, (later in this tutorial), this will register the chrome package.
</p>
<h4 name="Register_an_Overlay"> Register an Overlay </h4>
<p>You need Thunderbird to merge your overlay with the messenger window whenever it displays one. So add this line to your <tt>chrome.manifest</tt> file:
</p>
<pre class="eval">overlay chrome://messenger/content/messenger.xul chrome://sample/content/sample.xul
</pre>
<p>This tells Thunderbird to merge <tt>sample.xul</tt> into <tt>messenger.xul</tt> when <tt>messenger.xul</tt> loads. Ever wonder why these apps start up so slowly? Its all the parsing of these files and running down the "includes" at runtime instead of at compile time.
</p>
<h4 name="Test"> Test </h4>
<p>First, we need to tell Thunderbird about your extension. In the bad old days of Firefox 1.0 this meant packaging your extension as a XPI and installing it through the user interface, which was a real pain. Now, it's much simpler (well sort of). Thunderbird has digressed a bit in this area for security reasons. You or the user can do one of three things: 1) save the xpi (shown in the next step) into your (Linux) ~/.thunderbird/(profile name)/extensions directory or 2) unzip the xpi into that directory. 3) create a symlink in ~/.thunderbird/(profile name)/extensions that points to the directory containing your install.rdf file. If using the first step then when you restart Thunderbird will recognize that you have an uninstalled extension waiting to be installed and prompt you to install it. If you use number two then you might miss something that the install script wanted you to do. So its best to install using the first method. Using number 3 will yield similar behaviour as number 1.
</p>
<ol>
<li> Shutdown Thunderbird completely. All instances that are being tested with the profile.
</li><li> Open your Thunderbird <a class="external" href="http://kb.mozillazine.org/Profile_folder">Profile Folder</a>. In Linux it is ~/.thunderbird/(profile name) .  The profile name could look like a cryptic string with the .default   at the end.
</li><li> Open the <b>extensions</b> folder.
<pre> mkdir sample@foo.net </pre>
</li><li>Remember when you made the Install Manifest above? You said the id of this extension was sample@foo.net. After you get this running, go back and change that and these instructions according to what you will really call this extension.
<pre> cd sample@foo.net </pre>
</li><li> Copy the entire directory structure of your extension <tt>C:\extensions\my_extension\</tt> or <tt>~/extensions/my_extension/</tt> to the extensions directory. In this test, you don't need a fancy install so this will suffice. In Linux you'll <tt>cp -fr ~/extensions/my_extension/* .</tt> You can also create a symlink if you would rather not place your development files under your <tt>.thunderbird </tt> directory.
</li></ol>
<p>Now you're ready to test your extension!
</p><p>Start Thunderbird. Thunderbird will detect the extension and automatically use it. When the message window appears you should see the text "Hello, World!" on the right side of the status bar panel. 
</p><p>You can now go back and make changes to the .xul file, close and restart Thunderbird and they should appear.
</p>
<h4 name="Package"> Package </h4>
<p>Now that your extension works, you can <a href="en/Extension_Packaging">package</a> it for deployment and installation. 
</p><p>Zip up the <b>contents</b> of your extension's folder (not the extension folder itself), and rename the zip file to have a .xpi extension. In Windows XP, you can do this easily by selecting all the files and subfolders in your extension folder, right click and choose "Send To -&gt; Compressed (Zipped) Folder". A .zip file will be created for you. Just rename it and you're done!
</p><p>On Mac OS X, you can right-click on the <b>contents</b> of the extension's folder and choose "Create Archive of..." to make the zip file.  However, since Mac OS X adds hidden files to folders in order to track file metadata, you should instead use the Terminal, delete the hidden files (whose names begin with a period), and then use the <tt>zip</tt> command on the command line to create the zip file.
</p><p>On Linux, you would likewise use the command-line Zip tool. 
</p>
<pre class="eval"> cd ~/extensions/my_extensions
 zip -r ../sample.xpi *
</pre>
<p>When placed in the (user's profile)/extension directory, Thunderbird will open the xpi, check the id in the install.rdf and create that directory for your package. It will then cd to that directory and unzip the files thereby creating a mirror of your ~/extensions/my_extension directory structure and files.
</p><p>If you have the 'Extension Builder' extension installed it can compile the .xpi file for you (Tools -&gt; Extension Developer -&gt; Extension Builder). Merely navigate to the directory where your extension is (install.rdf etc.), and hit the Build Extension button. This extension has a slew of tools to make development easier.
</p><p>Now upload the .xpi file to your server, making sure it's served as <tt>application/x-xpinstall</tt>. You can link to it and allow people to download and install it in Thunderbird. 
</p>
<div class="note">
<p><b>Note</b> As a service to your users, tell them to save the file into their local Thunderbird directory, profile name, extensions.
In Linux it is ~/.thunderbird/(profile name is different for each user)/extensions .
</p>
</div>
<h5 name="Installing_from_a_web_page"> Installing from a web page </h5>
<p>There are a variety of ways you can install extensions from web pages, including direct linking to the XPI files and using the InstallTrigger object. Extension and web authors are encouraged to use the <a href="en/Installing_Extensions_and_Themes_From_Web_Pages"> InstallTrigger method</a> to install XPIs, as it provides the best experience to users.
</p>
<h5 name="Using_addons.mozilla.org"> Using addons.mozilla.org </h5>
<p>Mozilla Update is a distribution site where you can host your extension for free. Your extension will be hosted on Mozilla's mirror network to guarantee your download even though it might be very popular. Mozilla's site also provides users easier installation, and will automatically make your newer versions available to users of your existing versions when you upload them. In addition Mozilla Update allows users to comment and provide feedback on your extension. It is highly recommended that you use Mozilla Update to distribute your extensions!
</p><p>Visit http://addons.mozilla.org/developers/ to create an account and begin distributing your extensions!
</p><p><i>Note:</i> Your Extension will be passed faster and downloaded more if you have a good description and some screenshots of the extension in action.
</p>
<h5 name="Registering_Extensions_in_the_Windows_Registry"> Registering Extensions in the Windows Registry </h5>
<p>On Windows, information about extensions can be added to the registry, and the extensions will automatically be picked up the next time the applications starts. This allows application installers to easily add integration hooks as extensions. See <a href="en/Adding_Extensions_using_the_Windows_Registry">Adding Extensions using the Windows Registry</a> for more information.
</p>
Revert to this revision