Reboot

I recently accepted a job offer from Mozilla Corporation. Today, I start working as an extension evangelist / consultant – helping extension developers be more successful, productive and happy.

Mozilla has some really smart people and cool technologies. I can’t wait to get started.

Update: He really is a special guy. Thanks Mike.

Site Specific Browers

Recent posts from Zach Lipton and Robert O’Callahan share a common theme: Give web applications better integration into the desktop.

I have a strong interest in this area myself. A while ago I came across a desktop application for the Mac called Pryo. It’s an application with an embedded browser designed to work exclusively with a single web application: Campfire (a web-based IM service from 37Signals). Pryo allows for many things that are either difficult or impossible for Campfire to do on its own. The guys behind Pryo call it a Site Specific Browser. There is even a Windows clone in the works.

Zach provides a simple proposal for “appifying” Firefox for specific sites. I am wondering if a Firefox extension couldn’t be used to test out some of these features. Instead of a tag, I was thinking of a to some sort of manifest file. The manifest could specify how to modify the Firefox UI to be more site specific as well as setup desktop shortcuts. Of course, the user should be in full control of allowing any of this to happen. Preferences would control a site’s ability to “appify” itself and the user should be able to revert back to the “non-appified” version of the site.

Site specific browsers could be the Next Big Thing with Ajax applications appearing faster than rabbits. Seems like TechCrunch has 2 or 3 new web applications popping up everyday. Better desktop integration would definitely enhance the user experience.

Mozilla Platform – XPCOM in C++

In the spirit of “you can never have too many”, I thought it would be a good idea to document my process of creating an XPCOM object in C++. XPCOM is Mozilla’s cross platform component object model, similar to Microsoft’s COM technology. XPCOM components can be implemented in C, C++, and JavaScript, and can be used from C, C++, and JavaScript. That means you can call JavaScript methods from C++ and vice versa.

Applications built on the Mozilla Platform use XUL and JavaScript (and XBL) for the UI. Much of the core technology is implemented in C/C++ and exposed to JavaScript as XPCOM components. I have been experimenting with XULRunner and thought it would be good experience to build some XPCOM components.

Step 1: Development Setup

The simplest way to get an XPCOM component built is to use the Gecko SDK. On Windows, the SDK is built using a Microsoft compiler, so you need to use one too. I am using Microsoft’s free Visual C++ Express. You could try to use a different compiler, but you are going to need to build XULRunner from source code. Not the simplest thing to do and it would be incompatible with production releases of XULRunner from Mozilla.

I am using XULRunner 1.8.0.4 which has a pre-built SDK at gecko-sdk-win32-msvc-1.8.0.4.zip. I extracted the SDK to a folder called xulrunner-1.8.0.4, but you can call yours whatever you want.

You also need to a couple pre-built libraries (glib-1.2.dll & libIDL-0.6.dll) from the wintools.zip archive. I copied glib-1.2.dll & libIDL-0.6.dll into the bin subfolder of gecko-sdk.

Note: wintools.zip seems old and lots of newer MDC documentation refers to moztools.zip archive, but the version of xpidl.exe that comes with the gecko-sdk crashes with the DLL’s from moztools.

Recap:

  • Use the right Gecko SDK for your XULRunner release
  • Use a Microsoft compiler
  • Use pre-built glib-1.2.dll & libIDL-0.6.dll libraries from wintools.zip

Here is what my folder structure looks like:

xpcom-folders.png

Step 2: Create a VC++ Project

I wish Visual Studio project and file templates (or wizards) existed for creating XPCOM modules and components, but they don’t. I am considering building some, but for now, I offer a XPCOM project that contains a simple XPCOM component. You can use the project as a starting point and modify the component files to add your own functionality.

I started with a standard multi-thread DLL project. Then I made the following tweaks:

  • Added “..\gecko-sdk\include” to Additional Include Directories
  • Added “..\gecko-sdk\lib” to Additional Library Directories
  • Added “nspr4.lib xpcom.lib xpcomglue_s.lib” to Additional Dependencies
  • Added “XP_WIN;XP_WIN32” to Preprocessor Definitions
  • Turned off precompiled headers (just to keep it simple)
  • Used a custom build step for the XPCOM IDL file (spawned xpidl-build.bat to process the IDL with Mozilla toolset, not MIDL)

VC++ Express Project: xpcom-test.zip

Note: I am using xpcom_glue as described in this MDC article. I am using frozen linkage (dependent on XPCOM). I am not defining XPCOM_GLUE and I am linking against xpcomglue_s.lib

Step 3: Create an XPCOM Component

A full tutorial of XPCOM is beyond the scope of this posting. Check out these resources for more information on the world of XPCOM:

Ok then, on with the basic, oversimplified example. Your XPCOM component is made up of 3 parts:

  • Component interface described using IDL. The interface defines the methods, including arguments and return types, of the component.
  • Component implementation using C++. The implementation is where the methods actually do the work.
  • Component factory module, also in C++. The factory is in charge of creating instances of the implementations.

Let’s specify a simple interface:


#include "nsISupports.idl"

[scriptable, uuid(263ed1ba-5cc1-11db-9673-00e08161165f)]
interface ISpecialThing : nsISupports
{
  attribute AString name;

  long add(in long a, in long b);
};

Remember to generate your own GUID. The next step is to compile the IDL into a type-library (*.XPT) and a C++ header file (*.H), which we can use to define our implementation object. The blank VC++ project has a BAT file that will create the XPT and the H files. The command executes XPIDL.EXE twice, like this:


{path_to_geckosdk}\bin\xpidl.exe -m header -I..\gecko-sdk\idl {your_idl_file}
{path_to_geckosdk}\bin\xpidl.exe -m typelib -I..\gecko-sdk\idl {your_idl_file}

The generated H file actually has a skeleton implemenation (commented out). You can take the code and create implementation H and CPP files. They could look like this:


H file:

#ifndef __SPECIALTHING_IMPL_H__
#define __SPECIALTHING_IMPL_H__

#include "comp.h"
#include "nsStringAPI.h"

#define SPECIALTHING_CONTRACTID "@starkravingfinkle.org/specialthing;1"
#define SPECIALTHING_CLASSNAME "SpecialThing"
#define SPECIALTHING_CID { 0x245626, 0x5cc1, 0x11db, { 0x96, 0x73, 0x0, 0xe0, 0x81, 0x61, 0x16, 0x5f } }

class CSpecialThing : public ISpecialThing
{
public:
	NS_DECL_ISUPPORTS
	NS_DECL_ISPECIALTHING

	CSpecialThing();

private:
	~CSpecialThing();

protected:
	/* additional members */
	nsString mName;
};

#endif

CPP file:

#include "comp-impl.h"

NS_IMPL_ISUPPORTS1(CSpecialThing, ISpecialThing)

CSpecialThing::CSpecialThing()
{
	/* member initializers and constructor code */
	mName.Assign(L"Default Name");
}

CSpecialThing::~CSpecialThing()
{
	/* destructor code */
}

/* attribute AString name; */
NS_IMETHODIMP CSpecialThing::GetName(nsAString & aName)
{
	aName.Assign(mName);
	return NS_OK;
}
NS_IMETHODIMP CSpecialThing::SetName(const nsAString & aName)
{
	mName.Assign(aName);
	return NS_OK;
}

/* long add (in long a, in long b); */
NS_IMETHODIMP CSpecialThing::Add(PRInt32 a, PRInt32 b, PRInt32 *_retval)
{
	*_retval = a + b;
	return NS_OK;
}

Lastly, we need to create the module implementation. I put this together from some samples I found on the MDC site:


#include "nsIGenericFactory.h"
#include "comp-impl.h"

NS_GENERIC_FACTORY_CONSTRUCTOR(CSpecialThing)

static nsModuleComponentInfo components[] =
{
    {
       SPECIALTHING_CLASSNAME, 
       SPECIALTHING_CID,
       SPECIALTHING_CONTRACTID,
       CSpecialThingConstructor,
    }
};

NS_IMPL_NSGETMODULE("SpecialThingsModule", components) 

Assuming you have the right SDK and setup the include and LIB folders correctly, the project should build your XPCOM component.

Step 4: Test Component in a XULRunner Application

In order to test your component in a XULRunner application, you need to “install” the component, “clear” the component registry, and use the component from JavaScript.

  1. Install Component: Copy your XPT and DLL files to the {app}/components folder. You should not put your component in the xulrunner/components folder.
  2. Clear Registry: Increment the BuildID in your {app}/application.ini.
  3. Use in JavaScript:

function doXPCOM() {
  try {
    const cid = "@starkravingfinkle.org/specialthing;1";
    var obj = Components.classes[cid].createInstance();
    obj = obj.QueryInterface(Components.interfaces.ISpecialThing);
  }
  catch (err) {
    alert(err);
    return;
  }

  var res = obj.add(3, 4);
  alert('3+4 = ' + res);

  var name = obj.name;
  alert('Name = ' + name);

  obj.name = 'New Name';
  name = obj.name;
  alert('Name = ' + name);
}

As I find errors and new information, I’ll be sure to update this post.

Update: Updated doXPCOM per Christian’s comments.

Canvas/SVG/VML Drawing Roundup

Its been a couple months since I released RichDraw. At the time I was looking around at the state of browser-based drawing and diagraming tools. Most were Java or ActiveX based. Now, I am finding lots of pure Javascript API’s and tools.

There also seems to be more of a push to create API’s, making it easier to create cross-browser applications. Each browser seems to support a slightly different technology. Even when they overlap, browser implementations are not always interoperable. Javascript wrappers are a big help.

Here are some Javascript libraries focused on cross-browser drawing:

Here are some neat browser-based drawing applications:

  • Whiteboard – A little colaborative whiteboard experiment. Uses the Dojo.gfx toolkit to do the rendering.
  • Paintr – A weekend project by Anne van Kesteren. Uses suppport to do the rendering.
  • Draw – Has the makings of a full-blown flowcharting tool. Many shape types and support for connectors. Currently IE only, but since it is built on RichDraw, Firefox and Opera could be supported as well.
  • XDrawGavin Doughtie’s early work that may have started the Dojo.gfx toolkit.

Not an exhaustive list, but at least some evidence that drawing in a browser is getting serious.

Mozilla Platform – UI Basics [Part 2]

Last time I covered some simple XUL for creating windows, menus and toolbars. This time I’ll look at dialogs, your own and common OS dialogs too. Dialogs are pretty fundamental to a desktop application. Certain types of dialogs are used over and over. So much so that the OS can provide a default implementation. File open and save are good examples. Whenever possible, it is a good idea to reuse these ‘native’ dialogs so users get a consistent experience across applications.

Custom Dialogs

Building dialogs in XUL is very similar to creating windows. Each dialog seems to be in it’s own XUL file. Also like windows, XUL provides a

element to act as the container for the dialog. As their window counterparts, dialog XUL files can have DTD, CSS, JS links too. Here is an example XUL dialog:







  

  
  
    
    
      
      
      
    
  


XUL window elements have a special method to openDialogs. Here is the code needed to open a dialog:


function openDialog() {
  window.openDialog("chrome://basicapp/content/dialog.xul", "newdlg", "modal");
}

mydialog.png
(on Win2K)

The first thing that caught my eye about

is the button and related attributes. In an effort to make things easier for developers and more consistent for users, XUL has a mechanism to auto create and position the core dialog buttons (‘ok’, ‘cancel’ and help’ for example). The developer just declares the need for the button, the caption and access key for the button and the JS function to call if the button is pressed. XUL handles placing and styling the buttons on the dialog. This is also nice for cross-platform applications too. Each OS seems to have its own convention for where buttons should be placed on a dialog. Here is a short list of the button attributes (see the above link for a complete reference):

  • buttons – comma separated list of buttons to show on dialog (‘accept’, ‘cancel’, ‘help’, ‘extra1’ and ‘extra2’)
  • buttonlabelaccept – label for accept button (same for other buttons)
  • buttonaccesskeyaccept – access key for accept button (same for other buttons)
  • ondialogaccept – Javascript to execute if accept is pressed (same for other buttons)

XUL has a wide range of input controls you can use on a dialog. In the future, I will try to go into more detail on some of the existing and planned XUL input controls. Not too sure if I’ll use the , but if I did, the single element would be a big time saver over building the header from scratch.

Common Dialogs

Some of the most frequently used common dialogs are for opening and saving files. For instance, Windows has supported builtin file open and file save dialogs for many years. It makes creating an application easier for developers. The consisent UI also makes using an application easier too. XUL supports native implementations of filepickers (Mozilla for File Open and Save dialogs). Newer releases will allow using preferences to switch to a XUL emulation filepicker, if you want to. The XUL filepickers are XPCOM components and must be instantiated before using, like this:


function doFileOpen() {
  /* See: http://developer.mozilla.org/en/docs/XUL_Tutorial:Open_and_Save_Dialogs */
  
  var nsIFilePicker = Components.interfaces.nsIFilePicker;
  var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);

  fp.init(window, "Open File", nsIFilePicker.modeOpen);
  fp.appendFilters(nsIFilePicker.filterText | nsIFilePicker.filterAll);
  
  var res = fp.show();
  if (res == nsIFilePicker.returnOK) {
    var thefile = fp.file;
    alert(thefile.leafName);
    // --- do something with the file here ---
  }  
}

XUL does not appear to currently support any other common dialogs. That could change with Firefox 2 and 3 releases coming up. Firefox and Thunderbird both support nearly native Page Setup and Print dialogs. However, XUL does support elements to make creating Wizards a simple task as well.

I still want to look at Input Controls, Printing, Clipboard and XPCOM.

Mozilla Platform – UI Basics [Part 1]

My quest to build a basic desktop application using XUL continues. Last time I installed XULRunner and built a very simple, bare-bones test application. This time I want to add some of the things common to a desktop application UI:

  • Windows and Dialogs
  • Menus and Toolbars
  • OS Common Dialogs
  • Controls or Widgets

Windows
Each window or dialog should be created in it’s own XUL file. The XUL file may also contain other top-level declarations for CSS and DTD, which I will discuss in a moment. is the basic windowing element in XUL. It has attributes to set the title/caption as well as control width and height. Although I have not seen it mentioned yet, I am assuming that you can only have one element per XUL file. Here is an example: