Mozilla DevCenter    
 Published on Mozilla DevCenter (http://www.oreillynet.com/mozilla/)
 See this if you're having trouble printing code examples


Creating Applications with Mozilla

Roll Your Own Browser

by Brian King, coauthor of Creating Applications with Mozilla
09/24/2002

The browser is dead. It's a two-dimensional piece of software that is slowing the evolution of the Web.

Are you shocked by these statements as you read this article from the comfort of your browser of choice? Well, you should be, because contrary to 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 customizing, or creating, your own browser using the wonderful toolkit that is Mozilla.

Why Your Own Browser?

Before proceeding, you should know that 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 Mozilla 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 let's look at some of the practical uses that an integrated browser can bring to your application, apart from its traditional use--for Web navigation:

Related Reading

Creating Applications with Mozilla
By David Boswell, Brian King, Ian Oeschger, Pete Collins, Eric Murphy

Of course, when you have the raison d'etre for your browser, you have to start putting the pieces in place to get it running. This will take the form of a full-blown Mozilla application, complete with the XPFE toolkit (XPFE is the user interface component of Mozilla) for building your own UI, or perhaps just to create an add-on to the existing suite, which can be distributed in the form of an XPI. The term "XPI" refers to cross-platform install, the native installer for Mozilla.

The Widgets

To get you started, let's look at two of the most straightforward content widgets available in the Mozilla toolkit, namely the browser and the iframe. These have tags with the same name, <browser> and <iframe>, and are placed in 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 recognized by Gecko, such as jpeg, png, gif, and bmp. Here is a look at a browser in its simplest form:


<?xml version="1.0"?>
<?xml-stylesheet href="chrome://global/skin" type="text/css"?>
<window id="browser-window" title="Simple Browser Widget Display"
    xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
           width="640" height="480">
<browser src="http://mozdev.org" flex="1"/>
</window>

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 it you'll load the mozdev.org index page. The result is 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's lacking an application space and has no accompanying widgets to carry out any complementary 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 functions such as Back, Forward, Reload, View Source, and so on.

The <iframe> widget is a more lightweight version of the <browser>, yet is also useful when your needs are just to display some simple Web 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 attribute to specify the content. It is useful mainly for displaying one-off content such as a preview of content or a results page.

<iframe class="results" id="resultsframe" type="content" src="results.xul" flex="1"/>

Remember that XUL content can be loaded into the content areas, as is the case, for example, in the Mozilla suite global preferences, which has a right frame into which the various preferences panels are loaded when selected.

The Script

Let's look now at the source code that initializes the browser. We'll cover the basics just to get some browser functionality working. In my opinion, the best way to find out how Mozilla works is to look at the code. The way to do this is via LXR, the Mozilla Cross Reference. The particular files you should be looking at are navigator.js and help.js, the main JavaScript files associated with the Browser and Help windows respectively.

The following code is a generic way to set things up, but is loosely based on starting these windows and setting up the browser. This script is best placed in the function associated with the load handler of the XUL window.

The first step is to add a couple more attributes to the browser widget in the XUL file.

<browser id="browser-content" type="content-primary" src="about:blank" flex="1"/>

The type attribute is optional but in this instance it 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 (for example, content.focus()), and should gain precedence over other areas. The content in this browser will be accessed when you use the content keyword in your script. 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
myBrowser = document.getElementById("browser-content");

Next, we'll create the browser instance and set up browser window:

var appCore = null;  // declare globally for re-use
appCore = Components.classes["@mozilla.org/appshell/component/browser/instance;1"]
          .createInstance(Components.interfaces.nsIBrowserInstance);
appCore.setWebShellWindow(window);

The browser is initially blank (because of using the "about:blank" as the src attribute), so you'll have to load some content into the browser. Here an http URL is used:

const nsIWebNavigation = Components.interfaces.nsIWebNavigation;
myBrowser.webNavigation.loadURI("http://www.mozdev.org", 
          nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);

This creates an instance of the nsIWebNavigation XPCOM interface, which exposes a number of handy utilities for changing and navigating through the content displayed in the browser. In this instance, to load a page, the loadURI method is used. Other methods of this interface include goBack(), goForward(), and reload(). nsIWebNaviagtion is just one of the interfaces available when you use the browser widget. Others include:

A full list can be found in the bindings file for the widget. The steps provided in this section will get you well on your way to creating a rich content browser 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 key to any reasonable browser, so I'll illustrate the process for hooking up this 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 the pages available for each one. Appearance is achieved by including the navigator 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" 
              tooltiptext="Go Back"
              oncommand="goBack();"
              observes="canGoBack">
</toolbarbutton>

<toolbarbutton id="forward-button" class="toolbarbutton-1"
              tooltiptext="Go Forward"
              oncommand="goForward();"
              observes="canGoForward">
</toolbarbutton>

Apart from the class attribute on the buttons, others to watch for are oncommand, which bridges the functionality, and observes. The observes attribute determines if the button is active. There is a little bit of trickery involved to get the buttons to move to and from a disabled state. It depends on whether navigation can occur either Forward or Back. We will not go into that here, but the full source code for the XUL file and the JavaScript file used in this article is available for reference. Let's look at the code for the goBack() and goForward() functions.

function goBack()
{
    var webNavigation = myBrowser.webNavigation;
    if (webNavigation.canGoBack)
       webNavigation.goBack();
}

function goForward()
{
    var webNavigation = myBrowser.webNavigation;
    if (webNavigation.canGoForward)
       webNavigation.goForward();
}

Once again the webNavigation interface is accessed through the browser widget. After an efficiency check on the observer, the goBack() or goForward() routine from the interface is called. That's all there is to it--three lines of code. The foundations were laid in the initialization code, so now you reap the benefits.

Summary

The rest, as they say, is up to you. You can choose to make your browser as simple or as complex as you wish. Mozilla provides the widgets to hold your content, and as was illustrated in this article, it also gives you the source code to add rich functionality. I just touched the surface here. Other features you can hook in are context menus, events such as drag&drop and onclick on the content area, and view 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 over many new users. The <tabbrowser> widget is more complex than the basic browser, but could bring more rewards. And don't forget, if it doesn't exactly meet your needs, you can change the source code!

Brian King is an independent consultant who works with web and open source technologies.


Return to the Mozilla DevCenter.

Copyright © 2009 O'Reilly Media, Inc.