Neil's Place

January 4, 2007

6:35 PM Application State

One common issue that extension developers have is how to maintain state between different windows throughout the lifetime of Firefox (or another application) even while the windows are opened and closed. Once a window is closed, all of its context and state goes away.

The typical approaches are to use an XPCOM component, which can be maintained throughout the application lifetime, but is a bit unweidly to write. A second technique is to use preferences, however they persist even after the application is closed and aren't the most logical way to store temporary state. A third technique is to use the hidden window. Mozilla uses a hidden window because the XUL architecture requires a window to be available to show the menu bar on Mac even though no windows are visible. Storing data on this hidden window is what is officially known as 'an evil hack'. These three techniques are described in more detail in Working with windows in chrome code.

There are some other ways to accomplish this, at least to some degree, like using the persist attribute, RDF or other XPCOM services, although none are really designed for this purpose. What's needed then, is a proper means to store state while the application is running.

Luckily, the WHAT-WG's Client-side session and persistent storage (sometimes called DOM Storage) mechanism can be used, with some small enhancements suitable for extension use.

Right now, there are two types of storage available, 'session' which stores per-window data (actually per-tab of course), and 'global' which stores data to disk permanently (at least until the user deletes it). I propose a third type, called 'application' which behaves the same as the global storage but lasts only until the application exits.

I also propose extending the per-domain storage mechanism to support chrome URIs, identified by names such as 'chrome://packagename'.

For details about this proposal, see XUL Persistent State and Observers. I also provide a specification for the existing XUL broadcaster/observer mechanism and how it might be extended to support observing changes to a storage area.

Thoughts?

Also, I should point out that the proper name is 'Client-side session and persistent storage' not 'DOM Storage'. It doesn't have anything to do with the DOM, and is easy to confuse with the 'Storage' system used in Mozilla which stores data in an sqlite database. Sometime during the implementation of this feature for Firefox 2, someone started refering to it to by that name, possibly because that is what the class name of its implementation is. Unfortunately, the naming of the class was a bit of an accident caused because the underlying DOM implementation doesn't like classes that don't begin with 'nsDOM' and I didn't have time to figure out why. Anyway, internally we can still call it DOM Storage if needed, as I don't have another suitable short enough name, but to users it should always be referred to as 'Client-side session and persistent storage' or any other name deemed acceptable by the WHAT-WG.

Comments ( 7 )

October 19, 2006

10:34 PM RDF, Mozilla, and Complexity

Maybe I should weigh in on the RDF debate currently going on in Mozilla-land. Aparently there have been plans to remove RDF support for some time. What you didn't hear about it? Of course, you didn't. I sure didn't. Finding that out requires that you spend all your time in Mozilla IRC channels. Ah, IRC: the place where ideas go to be discussed, debated, and then left undocumented.

One source of this is perhaps the recent post Brendan on Mozilla 2.0, in which he links to a post by someone trying to retrieve a list of bookmarks and finds the code terribly complex. Brendan then incorrectly ascribes the problem to RDF. While it's true that the code is complex, the actual problem is caused by XPCOM.

Here's an example of a quite common code pattern found thousands of times in Mozilla code:

  var obs = Components.classes["@mozilla.org/observer-service;1"].
              getService(Components.interfaces.nsIObserverService);
  obs.notifyObservers(null, "browser-window-before-show", "");

Here is how to write that same code in a more sane environment:

  ObserverService.notifyObservers(null, "browser-window-before-show", "");

That removes two lines of code from the referenced getBookmarkList function. Several more lines can be removed by having the RDF objects implement nsIClassInfo or some such so one doesn't have to call QueryInterface all the time (more XPCOM overhead).

But what's really interesting, at least in this particular case, is how to access the list of bookmarks using Places, which is destined to replace the RDF bookmarks implementation. Based on the documentation, I wrote a version of getBookmarksList using the Places API instead. Look at this:

function getBookmarkList(doSort)
{
  var bookmarks = Components.classes["@mozilla.org/browser/nav-bookmarks-service;1"].
                    getService(Components.interfaces.nsINavBookmarksService),
  var history = Components.classes["@mozilla.org/browser/nav-history-service;1"].
                  getService(Components.interfaces.nsINavHistoryService);
  var ioService = Components.classes["@mozilla.org/network/io-service;1"].
                  getService(Components.interfaces.nsIIOService);
  var query = history.getNewQuery();
  var options = history.getNewQueryOptions();
  options.setGroupingMode(options.GROUP_BY_FOLDER);
  query.setFolders([bookmarks.toolbarRoot], 1);
  if (doSort)
    options.SORT_BY_TITLE_ASCENDING = true;
  var result = history.executeQuery(query, options);
  var root = result.root;
  root.containerOpen = true;
  var items = [];
  var count = root.childCount;
  for (var i = 0; i < count; ++i) {
    var node = root.getChild(i);
    if (node.name && node.url) {
      var iuri = ioService.newURI(node.uri, "" , null);
      bookmarks.getKeywordForURI(iuri);
      items.push({ name: node.name, url: node.url, kw: iuri});
    }
  }
  return items;
}

Now, I don't know about you, and maybe I missed the secret getAllBookmarks function somewhere, but that sure doesn't look all that simpler to me. In fact, once the XPCOM overhead is removed, retrieving the list of bookmarks using the newer Places API appears to require even more code than the equivalent code using the RDF API does. Go figure. Maybe it was just a really bad example. And that doesn't even consider changing the RDF API, which admittedly isn't spectacular by any means.

Maybe instead of focusing so much energy on RDF, which isn't particularly broken, we should instead focus on cleaning up things which are. Like removing all the XPCOM overhead, or why there are fifteen interfaces to desribe a window. Me, I'm working on making the clipboard and drag and drop APIs easier to use. Instead of writing twenty lines of code to indicate you want to drag something, you'll be able to use the WHATWG Drag and Drop API and just write two.

Comments ( 13 )

July 26, 2006

11:06 PM Numbers, times and dates

I'm currently working on adding date and time pickers to XUL. There have been a number of attempts at this (there are actually at least three calendar widgets in the Mozilla source) so I started by building on top of these. Now, however, the code doesn't look anywhere near the same, but the widgets are more complete I think.

The date picker comes in several varieties, for direct entry using textboxes, a grid and a combination entry and popup grid. I decided not to have a popup time picker and to just have the entry type. The image also includes a number entry box.

On the unrelated to Mozilla side, if you happen to be in the Toronto area on Monday July 31 and have nothing to do, yet want to be entertained with wild and crazy comedy, you're in luck. You would want to attend the second showing of Da Tory Code, co-written by me, Neil Deakin. The first showing has received rave reviews from real life members of parliament, so you know you won't be disappointed. Also, it's free, so what more could you ask for?

Comments ( 13 )

July 13, 2006

3:38 PM XML Templates

Just added support for spinbuttons, a widget for the arrows to adjust a numeric value. This will used for widgets for selecting numbers and times, which will also be coming soon. Also, the XUL sort service has been reworked to be better. See the bottom of the template features in 1.9 page for more details.

I've also added a page on how I plan to make XML sources be useable with XUL templates. I've already implemented most of this but still need to do some debugging. Comments on the syntax are most welcome.

Comments ( 3 )

June 7, 2006

5:43 PM XUL Features I've been working on

Hi, I'm Neil Deakin. You may already know me as the author of much of the content on XULPlanet. Or, you might know me from some of the other Mozilla related work I've done. Or, you may have never heard of me. Since February, I've been working for the Mozilla Corporation as the guy responsible for improving XUL. Some of the things I've done so far include:

I have been working on a wide variety of other things. Unfortunately, I sometimes tend to implement 90% of some feature and then get distracted by something or someone else, leaving the other feature not quite done. But, over the last few weeks I've managed to set myself down with the goal of not starting anything new until I've completed everything else. Some of these features I've been working on:

  • Improving the sort service - the XUL sort service is used for sorting menus and trees and the like. It currently does what the RDF tree builder does, but with the added bonus of requiring 5 times as much code. So, I've restructured that code in bug 335122. It will also support non-RDF templates, as well as XUL content that isn't built from a template, sorting instead based on attributes.
  • Tree improvements - Jan Varga recently added support for cell selection in trees, allowing individual cells in a tree to be selected. In addition, soon, support will be added for inline editing of cells
  • New widgets - I mentioned above that the <scale> widget is already available in Mozilla 1.9. Other widgets include the <spinbuttons>, which is two arrows for increasing and decreasing a number, styled using the native theme, a numeric entry box, and a timepicker and datepicker. I haven't done anything with the datepicker yet but I will likely just use the one from calendar. The timepicker, however, works nicely and looks and behaves much like the native platform one.
  • XML Templates - I've mostly finished support for building XUL content from templates and XML datasources.

But the main feature which has occupied the last couple of weeks of my time is reworking the XUL popup code.

Right now, in XUL, popups are opened and closed in a fairly complicated way that only crashes if you do it right. Also, popups opened from menus, those not opened from menus and those opened via the showPopup API are handled using three different pieces of code, creating inconsistencies. I've written a short note about how popups behave.

I've reworked how popups are created and opened to avoid the most obvious way of crashing, as well as many others, and have consolidated all the popup opening code into one place. I've also removed the XPCOM usage and made the popup API more logical. I'll post more details soon.

Comments ( 6 )

April 17, 2006

12:22 AM XUL IDs

Right now in XUL, an XML ID isn't actually implemented. It just happens that getElementById returns something reasonable, and is generally what people expect. But XUL doesn't implement anything that conforms to the XML specification in terms of IDs. There are two specific differences:

  1. There are two attributes that can be used as the id. Most people use 'id', but the 'ref' attribute is actually equivalent, at least in all the code where people realized when they were writing it that both attributes were equivalent. That means that in the following code, pressing the button will display, surprise, not the button's label OK, but the checkbox's label 'Check Me':
    <checkbox ref="sample" label="Check Me"/>
    <button id="sample" label="OK" oncommand="alert(document.getElementById('sample').label);"/>
    
    This is despite the fact that the checkbox doesn't even have an id attribute.
  2. XUL actually allows more than one element to have a particular id. That is, ids don't have to be unique. You wouldn't know this in any way, unless you looked at the underlying XUL implementation. It stores a hashtable mapping every id (and ref) to a list of nodes which have that id. The getElementById function returns whatever happens to be first in the list.

The reasons for this date way back to when XUL was actually just a nicer way of displaying RDF. Since a single RDF resource could be displayed in numerous places, it was necessary to map all of them in a table, identified by resource URI. Later, someone decided to implement a DOM for XUL, so the getElementById function used these ids. Little of this history remains today, as XUL has slowly moved away from its RDF roots to a separate language. The need for duplicate ids still remains when using templates however, as a single template or several templates in the same document may generate the same result in multiple places. You can see this, for example, in Thunderbird's account settings window, where preference panels with the same name in the tree all have the same id.

I'm thinking of removing this need, and making XUL have a real ID type. This would mean changing templates to set the ref attribute on generated results rather than the id as it is now. This would make the id attribute an XML ID, and the ref atribute would be used to identify the resource associated with a template-generated element. A function would be added to the template builder to retrieve a specific node by its ref attribute. This is a fairly backwards-incompatible change, but won't affect most usages, unless someone happens to use the generated ids in some way.

Thoughts?

Comments ( 157 )

March 6, 2006

12:31 AM AOL and XML UIs

One of the architects behind Boxely, the XML GUI toolkit used by AOL, describes a long list of requirements that such a toolkit should have. The list is here.

Of course, we're also waiting to find out why an AOL senior VP thinks that IE is a better choice for AOL users than Firefox.

Comments ( 189 )

February 24, 2006

2:59 PM Mac Scales

The Mac native theme code is a lot easier to deal with than any other platform. While it took several days to implement a scale/slider on each of other platforms, it took only an hour to implement on Mac.

Comments ( 179 )