|
|
How to Create a Toolbar with XULPosted by Baron Quezada on 06/07/2011 in xulrunner , xul , xpcom , gecko |
The first time that I was asked to make a toolbar for Firefox my first thought was, "sounds like fun!" However, I didn’t have a clue about where to start and how to find the information about it. I wrote this post to share my experience and help anybody who finds himself in a similar situation

Toolset
For this tutorial is recommended that you have the following software installed:
- Firefox 3.6 or later
- Extension Developer (ADD-ONS for Firefox)
- Visual Studio 2008 or 2010
- Text Editor
How to Create a Toolbar with XUL
To create a toolbar we will use the following,
- toolbox: A box that contains toolbars.
- toolbar: A single toolbar that contains toolbar items such as buttons.
- toolbarbutton: A button on a toolbar, which has all the same features of a regular button but is usually drawn differently.
- toolbarseparator: Creates a separator between groups of toolbar items.
- toolbarspring: A flexible space between toolbar items.
- menu: Despite the name, this is actually only the title of the menu on the menubar/toolbar. This element can be placed on a menubar/toolbar or can be placed separately.
- menupopup: The popup box that appears when you click on the menu title. This box contains the list of menu commands.
- menuitem: An individual command on a menu. This would be placed in a menupopup.
- menuseparator: A separator bar on a menu. This would be placed in a menupopup.
To start, do the following,
- Open Firefox
- Open Real-time XUL Editor of Extension Developer or any page of XUL Edit online like (e.g., http://ted.mielczarek.org/code/mozilla/xuledit/index.html)
- Copy the following source,
<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
<window id="yourwindow" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:h="http://www.w3.org/1999/xhtml">
<toolbox>
<toolbar>
<toolbarbutton tooltiptext="tooltiptext1" oncommand="functionJS_1()" label="LabelButton1"/>
<toolbarseparator/>
<toolbarbutton tooltiptext="tooltiptext2" oncommand="functionJS_2()" label="LabelButton2"/>
<toolbarbutton tooltiptext="tooltiptextN" oncommand="functionJS_N()" label="LabelButtonN"/>
<toolbarspring/>
<menu label="LabelMenu" tooltiptext="tooltiptextMenu">
<menupopup>
<menuitem label="LabelMenuitemCheckbox1" type="checkbox"/>
<menuitem label="LabelMenuitemCheckbox2" type="checkbox"/>
<menuitem label="LabelMenuitem" oncommand="functionMenuitem();"/>
</menupopup>
</menu>
<toolbarseparator/>
<menu label="Help" tooltiptext="About this toolbar">
<menupopup>
<menuitem label="Visit blog of nearsoft" oncommand="OpenNS();"/>
<menuseparator/>
<menuitem label="About this toolbar"/>
</menupopup>
</menu>
</toolbar>
</toolbox>
</window> - After you paste the source on the XUL Editor it will show you the preview, which will look like this,

- Of course, you may modify the source, depending on what you want to do. If you want to save sometime, visit http://addons.mozilla.org/en-US/developers/tools/builder or http//:www.mozdev.org/projects/wizard/. Alternatively, you can download our toolbar.
How to Create a XPCOM Component in Windows
- Extract the xulrunner-sdk.zip and add Xulrunner-SDK/Gecko-SDK to the system path.

- Generate the GUID http://www.guidgen.com/ or http://mozilla.pettay.fi/cgi-bin/mozuuid.pl
- Create the VC++ Project:
- Start an empty Win32 project in Visual Studio, selecting the "Dynamic Linked Library (DLL)" option.
- Create the interface file inside Header Files folder in the Visual Studio project with name IMyComponent.idl.
- Paste the following code,
#include "nsISupports.idl"
[scriptable, uuid(_YOUR_INTERFACE_GUID_)]
interface IMyComponent : nsISupports {
long Rand();
string Other(in string a);
};
Long Rand() will return a random number from 0 to 2. string Other(in string a) will receive a string and it will return "Hello+string"

- Go to the path of your project and run xpidl twice on the IDL file, with:
- xpidl -I < xulrunner-sdk/idl path> -m header "<youridl>" outputs IMyComponent.h.
- xpidl -I < xulrunner-sdk/idl path> -m typelib "<youridl>" outputs IMyComponent.xpt.

- Add the generated IMyComponent.h file to the visual studio project. Right click on headers -> add Existing item…
- Make the following tweaks:
- Add "..xulrunner-sdkinclude" at C/C++ -> Additional Include Directories
- Add "..xulrunner-sdklib" at Linker -> Additional Library Directories
- Add "nspr4.lib xpcom.lib xpcomglue_s.lib" at Linker-> Additional Dependencies
- Add "XP_WIN;XP_WIN32" to C/C++ -> Preprocessor Definitions
- Not Using Precompiled Headers (just to keep it simple) at C/C++ -> Create/Use Precompiled Header
- Add "/Zc:wchar_t-" in C/ C++ -> Command Line -> Additional option to support wchar_t (Couldn't find how)
- Use a custom build step for the XPCOM IDL file (exclude from build by MIDL)
- The interface header file IMyComponent.h contains templates for building your component header and implementation files. You can copy and paste the templates to create these files, changing only your component name.
- Create your component header file - MyComponent.h.
- Start by inserting double inclusion protection code (#ifndef _MY_COMPONENT_H_…).
- Add #include "IMyComponent.h" to include the interface definition.
- Use the GUID for your component,
- Add the following lines, which define your component name, contract ID, and GUID:
#define MY_COMPONENT_CONTRACTID "@nearsoft.com/XPCOMSample/MyComponent;1"
#define MY_COMPONENT_CLASSNAME "A Nearsoft’s XPCOM"
#define MY_COMPONENT_CID _YOUR_COMPONENT_GUID_

- Copy the header template from IMyComponent.h (starting with /* Header file */) into the MyComponent.h file.
- Replace all the instances of _MYCLASS_ with the name of your component.
- Create your component implementation file - MyComponent.cpp.
- Add #include "MyComponent.h" to include your component definitions.
- Copy the implementation template from IMyComponent.h (starting with /* Implementation file */) into the MyComponent.cpp file.
- Replace all the instances of _MYCLASS_ with the name of your component.
- Add method implementation code.
- Create your module definitions file - MyComponentModule.cpp.
- Add #include "nsIGenericFactory.h" to include Mozilla GenericFactory definitions.
- Add #include "MyComponent.h" to include your component definitions.
- Add NS_GENERIC_FACTORY_CONSTRUCTOR(MyComponent) to define the constructor for your component.
- Add the following lines, which define your component name, contract ID, and GUID:
- Add the following code to define the class name, contract ID and GUID of your component:
static nsModuleComponentInfo components[] =
{
{
MY_COMPONENT_CLASSNAME,
MY_COMPONENT_CID,
MY_COMPONENT_CONTRACTID,
MyComponentConstructor,
}
};
- Add NS_IMPL_NSGETMODULE("MyComponentsModule", components) to export the above information to Mozilla.
- Compile.
- Link to Project VS 2008 with Gecko 1.9.2
Install the XPCOM
- Copy your YourFile.XPT and YourFile.DLL to the component directory of Firefox something like: "C:Program FilesMozilla Firefoxcomponents".
- Add "YourFile.DLL" at the end of the "components.list" file at components folder.
- Run Windows key + R, type %APPDATA%MozillaFirefoxProfiles and click OK.

- Delete "xpti.dat" and "compreg.dat" files from your profiles directory.
- Open your cmd or PowerShell and write: C:xulrunner-sdksdkin
egxpcom.exe -x "C:Program FilesMozilla FirefoxcomponentsYourFile.DLL"

- Now we are going to check that our XPCOM is installed, check with the addon XPCOMViewer and search nearsoft or MyComponent, if you open IMyComponent you should see:
- Other
- Rand
- QueryInterface
Connect XUL with XPCOM and JavaScript
We are using XUL only for the visual. To add functionality to our buttons and so on, we are going to create the file functions.js in chrome/content.
In the file.xul we have the following,<toolbarbutton tooltiptext="tooltiptext1" oncommand="functionJS_1()" label="LabelButton1"/>
Now change it to this:
<toolbarbutton tooltiptext="tooltiptext1" oncommand="connectJS()" label="LabelButton1"/>
Remember that we need to add this after <overlay>: <script src="/functions.js"/>
In the file "functions.js" add the follow code:function connectJS(){
alert("Function oncommand");
}
Now the connection with JavaScript is done and when you click the button it should show you the following message,

Add functionality with Firefox’s XPCOM
You can find a lot of XPCOM interfaces that are provided by the Mozilla platform. For this tutorial, we are going to use: nsIWindowMediator. This particular XPCOM Interface will tell us the URL most recent window.
function Url() {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var WindowMediator = Components
.classes['@mozilla.org/appshell/window-mediator;1']
.getService(Components.interfaces.nsIWindowMediator);
var recentWindow = WindowMediator.getMostRecentWindow("navigator:browser");
var url = recentWindow.content.document.location;
} catch (err) {
alert(err);
return;
}
alert('Url ' + url);
}

Add functionality with your XPCOM
Now we want to connect our file.xul with the function that we did before on our library.dll, for this we need to add other function in our file of JavaScript that it will be our connection between both components.
function RanDll() {
try {
netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
const cid = "@nearsoft.com/XPCOMSample/MyComponent;1";
obj = Components.classes[cid].createInstance();
obj = obj.QueryInterface(Components.interfaces.IMyComponent);
} catch (err) {
alert(err);
return;
}
var res = obj.Rand();
alert('Returned ' + res);
}

Conclusion
For me, the architecture of Firefox is amazing with a lot of advantages. I think it is one of the best browser of the world, but no everything is gold and glory. In particular, the documentation doing plugins is really terrible, hopefully this post and the previous one helps a little in this respect.
TweetBacks (Tweet this post)
Trackback(0)
TrackBack URI for this entryComments (0)
Show/hide comments



