I've been playing recently with a time-keeping tool, written in XUL, open in a popup window. The application is pretty simple,
just allowing me to enter a list of tasks, and keep track of how long I've had any task selected. Being in a popup allows me to
quickly change tasks and keep a much more accurate log of my time.
I was having a problem though, because clicking links from emails or IMs would open up into my popup window, and not a new tab
in Firefox, making me lose my data. Nathan suggested XULRunner, and after losing my data 3 more times, I broke
down and figured out how to set it up. XULRunner is a command-line app to run XUL applications, essentially starting another gecko instance
and running your code in that. That way Outlook won't think that's a good place to load windows, and if Firefox crashes, my XULRunner instance
is still fine and dandy.
Documentation on XULRunner is a bit scant, but googling
revealed a xulmine sample, and from that I was
able to reverse engineer what the hell XULRunner wanted me to do. And, now that I review some of these links,
I see Darin has more information about XULRunner than I thought.
As a convention, emphasized words are variables, and should be replaced with a value that makes
sense for your application.
Setting up your folder structure
Set up your application like so:
/applicationName
/chrome
/applicationName
your app files
chrome.manifest
/defaults
/preferences
prefs.js
application.ini
There are more complicated ways to do it, but this seems to be the bare bones. Now let's set up all the configuration files.
Setting up your application.ini
XULRunner works by reading an application.ini file, and then loading things up by looking at specific directories.
Here's a sample application.ini:
[App]
Vendor=company
Name=applicationName
Version=0.1
BuildID=20050506
[Gecko]
MinVersion=1.8
MaxVersion=1.8
The important bit is the
[Gecko] section. The
[App] section is nice, but doesn't seem to serve any essential function.
The
[Gecko] part tells XULRunner what versions of Gecko can be used with your app, and XULRunner will fail if those lines aren't there.
Setting up your prefs.js
This is a preferences file, where you set initial values of things, either gecko engine settings or application specific settings. All we need
here is:
pref("toolkit.defaultChromeURI", "chrome://applicationName/content/startPage.xul");
The
startPage is what XUL page you want to view initially.
Setting up your chrome.manifest
This file performs the mapping between a chrome:// url and your application files:
content applicationName file:applicationName/
That effectively tells XULRunner to look at
applicationName/ in the chrome directory when it encounters a
chrome://
applicationName/content/ URI.
Most XUL apps I've seen are distributed as a .jar file, rather than a subfolder of chrome/ with all the files scattered about.
Having your application unpacked is much easier for development, but when you do want to deploy it as a jar:
- Zip up your /chrome/applicationName folder, put the applicationName.zip in the /chrome directory.
- Rename applicationName.zip to applicationName.jar
-
Change the
chrome.manifest to point to applicationName.jar:
content applicationName jar:applicationName.jar!/
The jar: protocol tells XULRunner that this is a jar file, the the ! after the filename tells it to look inside the jar file.
Running your app with XULRunner
Now all the prep work has been done, and your application is ready to be run. After you download XULRunner, this is just a matter of a command line:
xulrunner application.ini
Your
startPage.xul should open up in a window, like any other desktop app.
Conclusion
To get a XUL app working with XUL Runner, you need 3 config files in 3 different formats. That's kinda messed up.
To be fair, the chrome.manifest format is something used for Firefox extensions, so it makes sense to re-use that functionality, but
needing to specify your start page in prefs.js seems arbitrary. There are some proposals for a different method of
XUL Application Packaging, but that's about a week old right now, and
there's no code to support it.
A XULRunner-based app seems like a good solution when you want to avoid Firefox. I want to avoid Firefox because of outlook, but in general
I don't see much of an advantage over just making an extension, its just a series of trade offs.
Pros:
- Runs in its own process
- Unaffected by other Firefox extensions, skins, configuration.
- Doesn't require Firefox
Cons:
- Doesn't auto-update with Firefox, auto-update code would need to be written
- Unaffected by other Firefox extensions, skins, configuration.
- Install package would be larger download to include the XULRunner binaries (13MB more)
The big internal app we're writing will likely remain as a Firefox extension, but going through this process has certainly taught me a lot more about how
to organize XUL apps. I wonder if you could munge XULRunner config files to point to a Firefox extension? Then you could auto-update with Firefox,
and still get the benefits of XULRunner.