What’s New on MDC

Just thought I’d point out some new content appearing on the Mozilla Developer Center (MDC).

  • Saving Canvas to a File: Given a canvas element and a destinstion file path, this code snippet saves the contents of the canvas to a PNG file. The code could easily be tweaked to become a general purpose “download to file” instead of only handling canvas elements.
  • XUL Control Guide: This is a handy quick guide to the various XUL control elements. In addition to a picture of the control, there are also links to reference and tutorial information.
  • Observing the Download Manager: This snippet shows how you can observe the various notifications of the download manager.
  • Troubleshooting XPCOM Registration: When component registration fails its currently very difficult to figure out the cause. This article steps through a few troubleshooting tips you can use to find the problem. We hope to get better tracing and debugging of component registration failures in Firefox 3.

XUL Explorer 0.3

After getting sidetracked for a while, I have finally made some progress on XUL Explorer. I have been tinkering around with the editor and integrating the XUL validator. I also reorganized the code a little so I could support sidebars in the future.

xulexplorer.png

I have been trying to stick with the XUL as much as possible. Anyone who has worked with the editor would probably tell me it’s a lost cause, but it’s also been quite a learning experience. I have added tabbed editing by dynamically creating elements inside a . It seems to work well. I make use of the tab-close-button and even change tab image if the editor is modified.

editor-tabs.png

You are prompted to save a modified editor when closing the editor or the application. One thing I have not been able to add was a way to display the current cursor position (row, column). I am still looking into it.

I rearranged the UI a little because of the tabbed editors. The preview pane is no longer below the editor. It was taking room away from the editor, so I added a code/preview toggle. I removed the “Insert Snippet” button from the Snippet Sidebar, but added drag-and-drop as a method of inserting snippets. Double-clicking a snippet also inserts it.

I added a Messages pane at the bottom of the workspace to display output from the, incrementally improved, XUL validator. I’ll probably make more use of the Messages pane in the future.

messages-pane.png

Next up for XUL Explorer:

  • Property Sidebar – Will display the structure of the XUL as a tree and properties of the selected element in a grid. Most likely, it will also allow users to insert/delete XUL elements.
  • Wizards/Generators – Will walk the user through creating XUL files, JavaScript XPCOM, extensions and XULRunner applications. For extensions and application wizards, I really need to add a Project Sidebar.
  • Project Sidebar – Will show the bundle of files needed to support extensions and wizards.

Overall, this project is still giving me lots of Mozilla stuff to play with and learn. And it’s fun.

Keep the feedback coming!

The install is still Windows only. I failed to get a Mac DMG file assembled yet, but I just got some tips on IRC. I am hoping to get Mac and Linux installs someday.

Install: xulexplorer-setup-0.3.exe 4.9MB
Source: xulexplorer-src-0.3.zip

FUEL Project Status

FUEL is the little library that John Resig and I are working on which should make developing extensions a little easier. It’s been a while since we last talked about it so I thought an update was in order.

FUEL now has a place in the Mozilla CVS tree (browser/fuel) and development is happening in a branch (FUEL_DEVEL_BRANCH). We have been tweaking the API (0.1 and 0.2) a little over the past couple weeks. We have also added some information on the testing plan. We are using the Mochitest framework to run our unit tests.

So far, we have the basics parts in place, including:

  • Global Application object.
  • Ability to associate user data with the Application and Extension. No more hidden window hacks.
  • Easy access to preferences, again global with Application and per extension with Extension. The extension-based preferences automatically use an “extensions.your-ext.” branch.
  • Simple events for Application (“start”, “ready”, “quit”) and Extension (“install”, “uninstall”). Events can also be used to watch for changes on preferences and storage items.

We hope to get the code and tests ready for review this week. Then we can get something pushed to the trunk after that. As always, feedback is welcome – comments, email, IRC, or Wiki.

Extension Development with FUEL

Removing obstacles for extension developers is my group’s primary task at Mozilla. There are lots of ways we can do this and areas include documentation, tutorials, samples and tools. One thing that becomes clear after watching and helping extension developers is the difficulty some have getting familiar with the Mozilla framework and the plethora of object and interfaces available. Not only are some of the concepts foreign, but in many cases there are no clear ways for extension developers to achieve their goals. There are places to get help. The Mozilla’s IRC channels are a great place to ask questions, especially #extdev.

We have also started work on a JavaScript library to help extension developers shorten the learning curve, feel more comfortable and generally be more productive. Codenamed FUEL, the library is primarily a wrapper around commonly used parts of the Mozilla framework which are unfamiliar or complicated. Some of the goals are:

  • Make it easy for developers to do common extension tasks.
  • Use terminology and interfaces familiar JavaScript developers.
  • Hide as many implementation details as possible.
  • Allow developers to get access to underlying XPCOM interfaces if they want to.
  • Act as a buffer between extensions and Firefox internals.

In addition to making it easier for extension developers, we also want to help improve the overall quality of Firefox. A broken extension appears to be a broken Firefox. Anything that can be done to help extensions avoid breakage and use clearly defined methods of hooking into the browser will help.

Currently, we (myself and John Resig) are in the planning and prototype phases. John’s JavaScript library experience (jQuery) is a huge plus for us. It’s great to have him working at Mozilla.

I invite you to take a look at the FUEL wiki pages and send us feedback and comments. You can use the discussion pages on the wiki or visit IRC (we hang out there way to much) or even use the newsgroup thread.

Update: I forgot to mention that our goal is to ship this library with Firefox (and other Mozilla applications as needed). Of course, we would also want it be able to usable in older Firefox releases too. Packaging could be a challenge.

Code Snippets – Get Your Code Snippets

If you’re new to Firefox extension or XULRunner programming, one of the first things you may want to do is find a good tutorial to help get a “hello world” project bootstrapped. Mozilla Developer Center (MDC) has more than a few to help you get started: Firefox Sidebar, Firefox Statusbar, XULRunner Application. We are working to get more on the way too.

The next thing you may need is small code snippets to help show you how to do common things. Things you probably already know how to do in another language or framework. You just need to know how to do it with XUL, JavaScript and XPCOM. You should definitely check out the Code Snippets section on the MDC. There is also an Example Code section on Mozillazine.

If there is something you want to know how to do, but it’s not on the MDC yet, let me know. Also, for any of you experienced Mozilla developers out there, go check out the code snippets and please add some of your own. Just keep the code snippet short and sweet, we’re not writing a full sample extension or application. If you do want to write a large sample extension or application, create a full blown tutorial.

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.