Rolling Your Own Browser
The browser is dead. It is a two dimensional piece of software that is
slowing the evolution of the Web. Are you shocked by these statements,
reading this article from the comfort of your browser of choice? Well you
should be because no matter what some people lead you to believe, browsers
will be around for a while longer. The purpose of this article is to introduce
you to the concept of customisating, or creating your own browser, and
how you can do it with the wonderful toolkit that is Mozilla.
Why your own browser?
Before proceeding, it must be noted that the rest of this article focuses
on the technical issues involved in getting a XUL browser up and running
in the application framework. This is distinct from embedding Gecko, which
was discussed in a previous article on the DevCenter, 'Let
One Hundred Browsers Bloom'.Gecko is the Mozilla
layout rendering engine. The merits of having multiple browser projects has
been touched on already, so lets look at some of the practical uses that
an integrated browser can bring to your application, apart form the traditional
usage for web navigation.
- Create some HTML or XML help pages for your application and load
them up in a ready made help browser.
- Previewer – test your XML, HTML or CSS layout and styling in
Gecko, one of the most standards compliant browsers around.
- A slight variation of the previous use, you could have mini –
versions inline in dialogs to load up examples that will change depending
on the slection of the user from a number of choices. For example, a font
- Pop-up’s contained in a window for display of web content
Of course, when you have the raison d'etre for your browser, you have to
start putting the pieces in place to get it up and running. This will take
the form of a full blown Mozilla application, complete with the XPFE toolkit
for building your own UI, or perhaps just an add-on to the existing suite
that can be distributed in the form of an XPI. The term XPI refers to Cross-Platform
Install, the native installer for Mozilla.
To get you started straight away, lets look at two if the most straightforward
content widgets available in the Mozilla toolkit, namely the browser
and the iframe. These are marked up with tags of the same name, <browser>and <iframe>, and placed within your
XUL window or binding. Both are essentially designed for holding web content,
which can be anything from HTML and XML to just text and images in formats
recognised by Gecko such as jpeg, png, gif and bmp. Here is a look at a browser
in its simplest form:
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="browser-window" title="Simple Browser Widget Display"
<browser src="http://mozdev.org" flex="1"/>
The code to look out for here is the line with the browser tag which creates
a content area. It is the sole markup in the XUL window. It takes up all the
available space because of the flex attribute, and into is loaded the index
page of mozdev.org. This is the result, a window with web content.
Simple Browser Window
What is missing in the picture and the example code for it is some sort of
context. It is lacking an application space, and has no accompanying widgets
to carry out any complimentary functionality for the browser. In traditional
browsers, including the Mozilla browser that comes with the application suite,
there is a menubar and a toolbar, each containing easy access to functionality
such as Back, Forward, Reload, View Source, and so on.
The <iframe> widget is a more
lightweight version of the <browser>,
yet is just as useful if your needs are just to display some somple we content.
It was designed to act much like the HTML iframe widget, to be an inner frame
within a document. It too has a src atribute to specify the content.
It is useful mainly for dislaying one-off content such as a preview of content,
or a results page.
id="resultsframe" type="content" src="results.xul" flex="1"/>
Remember that XUL content can be loaded into the content areas, as for example
is the case in the Mozilla suite global preferences which has a right frame
into which the various preferences panels are loaded into when selected.
Let's look now at the source code that enables the initialization of the
browser. These are the basics to get some browser functionality working. I
find the best way to find out how Mozilla works is to look at the code. The
perfect way to do this is via LXR, the
Mozilla Cross Reference. The particular files you should be looking at are
The following code is a generic way of setting things up but is based loosely
around the starting up of these windows and setting up of the browser. This
script is best placed in the function associated with the load handler of
the XUL window.
The first step is to give the browser widget in the XUL file a couple more
attributes added to it.
The type attribute is optional but in this instance is important because
it affects the way the content is treated in the application. The value of
"content-primary" means that this is the main browser content area (e.g.content.focus()), and
should gain precedence over other areas. When you use the content
keyword in your script, it is the content in this browser that will be accessed.
The id attribute gives the browser a unique identifier within the
XUL content.This allows you to easily get a handle on the browser widget
from your script:
var myBrowser // declare globally for re-use
Next is to create the browser instance and set up browser window:
myBrowser = document.getElementById("browser-content");
var appCore = null;
// declare globally for re-use
appCore = Components.classes["@mozilla.org/appshell/component/browser/instance;1"]
The browser is initially blank (the use of "about:blank" as the src
attribute), so you have to load some content into the browser. Here a http
URL is used:
const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
This creates an instance of the nsIWebNavigation XPCOM interface, which
exposes a number if handy utilities for changing and navigating through the
content displayed in the browser. In this instance, to load a page, theloadURI
method is being used. Other methods of this interface includegoBack(), goForward(), and reload(). nsIWebNaviagtion is
just one of the interfaces available when you use the browser widget. Other
myBrowser.webNavigation.loadURI("http://www.mozdev.org", nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
A full list can be found in the bindings
file for the widget. These few steps provided in this section will send
you well on your way to getting a rich content browser set up in your Mozilla
application and act as a foundation for adding some of the other bells and
whistles associated with a browser.
The Art of Navigation
What follows is a brief description of adding Back and Forward widgets and
functionality to your window. This is after all the basis of any reasonable
browser, but is used here to illustrate the process for hooking up functionality
to your browser. The XUL file is the place to define your UI buttons. If
you are proficient at XUL and CSS, you can make them into the style and appearance
that you wish, but in this example the current navigator styles (using the
Modern theme) are used.
Back and Forward Buttons
These are simple toolbar buttons. The back and forward buttons used in the
Mozilla browser have an integrated menu that creates a list of pages that
are available for each one. Appearance is achieved by including the communicator
CSS file and using a class specific to buttons (toolbarbutton-1). Here is
the XUL code for the buttons.
<?xml-stylesheet href="chrome://navigator/skin" type="text/css"?>
<toolbarbutton id="back-button" class="toolbarbutton-1"
<toolbarbutton id="forward-button" class="toolbarbutton-1"
Apart from the class attribute on the buttons, the other main ones
to watch for are oncommand, which bridges the functionality, and observes.
The observes atribute determines if the button is active. There is
a little bit more trickery involved to get the buttons to move to and from
a disabled state depending on whether navigation can occur either forward
and back. We will not go into that here, but the full source code for the
XUL file and
fileused in this article are available for reference. Lets look at the
code for the goBack() and goForward() functions.
var webNavigation = myBrowser.webNavigation;
var webNavigation = myBrowser.webNavigation;
Once again the webNavigation interface is accessed through the browser
widget. After an efficiency check on the observer to see if the it is possible,
the goBack() or goForward() routine from the interface
is called. And that is all there is to it -- 3 lines of code. The foundations
were laid in the initialization code, and now the benefits are reaped.
Up to You
The rest, as is said, is up to you. You can choose to make your browser as
simple or as complex as possible. Mozilla provides the widgets to hold your
content, and as was illustated in this article, it also gives you the source
code to add rich functionality. The surface was only touched here. Other features
you can hook in are context menus, events such as drag&drop and onclick
on the content area, and the viewing of page source. If you are truly ambitious
you can even go one step further and use the tabbed browser. Integrated into
the Mozilla browser and turned on by default, this has been a popular addition
to the browsing experience, and has won many new users. Looking at the <tabbrowser>
widget is more complex that the basic browser, but could bring more rewards.
And don't forget, if it doesn't exactly meet your needs, you can change the