Posts Tagged ‘xul’

Reel

I wrote a little desktop application to capture short videos and turn them into GIFs. I call it Reel. It’s still rough around the edges but you can grab an early version of it below.

Reel 0.1 (Windows Install)

I’ll have a Linux/Ubuntu version soon. Maybe an OS X version… I have to jump through a few extra hoops here as Apple still refuses to allow OS X to be virtualized.

Reel - Drinking Bird

Aside from its utility, this was also an experiment piecing together some technologies I’ve written about here before: XUL + XPCOM + SocketBridge, video capture using web tech and, in general, using web technologies for desktop applications.

The end of XULRunner

I’ve written a bit on XULRunner (and the related technologies, XUL and XPCOM) for application development, so I felt it was apt to mention that Mozilla no longer provides new builds of XULRunner. The recommended way to run XULRunner-based application is via the Firefox executable (Firefox ships with a private private XULRunner package):

firefox -app application.ini

You can take a copy of a Firefox installation and or compile Firefox from source, which is surprisingly easy.

One nice side effect worth mentioning: while I could never get proper high-DPI support with XULRunner, it works perfectly when Firefox is used as the runner.

Identifying the operating system with XPCOM

The following shows how to get a string identifying the current operating system from an instance of nsIXULRuntime:

var getOS = function() {
var env = Components.classes["@mozilla.org/xre/app-info;1"].getService(Components.interfaces.nsIXULRuntime);
return env.OS;
}

The nsIXULRuntime.OS string is one of the OS_TARGET values.

Ideally, I’d prefer XUL and XPCOM code to remain platform-agnostic, but I’ve used OS detection as a cheap way (versus jumping through 3 objects) to determine what path separator to use when referencing files and directories (backslash for “WINNT”, forward-slash for everything else). XPCOM is sensitive to the path separator; on Windows, it will not reference a file or directory if you use the forward slash. This is actually bizarre because Win32 API functions will accept paths with the forward slash as a separator. Even more bizarre is that we have a layer of abstraction that actually makes it harder to write platform-independent code.

Launching an application with XPCOM

Continuing to document my work with XULRunner, XUL, and XPCOM, here I’m presenting code on how to launch an executable using XPCOM’s nsILocalFile interface fetch the executable file and the nsIProcess interface to execute the process.

// target = path to executable
// args = arguments for executable
function exec(target, args) {

try {

var file = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
file.initWithPath(target);

var process = Components.classes["@mozilla.org/process/util;1"].createInstance(Components.interfaces.nsIProcess);
process.init(file);

var args = [''];
process.run(
false, args, args.length);
        
        
return process;
}
catch (err) {
alert(err);
return null;
}

}

Trilite, application design experiment with XULRunner and .NET

Goodbye Adobe Air

Despite positive first impressions with Adobe Air, I began avoiding it a while ago for a few reason:

  • Air’s focus was very much geared towards Flash development, not HTML/CSS/JS, and I had no interest in Flash development
  • A lot of interesting web technologies never manifested within Air (SVG, WebGL) and it looked doubtful that Adobe cared to add anything that might challenge Flash
  • Linux support was dropped – a platform dropping OS support is not a good sign
  • Native interaction support, a feature in Air 2 which I was excited about, didn’t impress me in its implementation and it was very much geared towards Flash/ActionScript development
  • Adobe’s push for Air became more a platform for mobile development rather than desktop development, to the extent that desktop development was pushed far into the background

With all of the negatives above, coupled with the propriety, vendor lock-in, nature of Air, I really didn’t feel like using it for development of anything.

XULRunner / XPCOM

I was still optimistic and interested in web technologies (HTML/CSS/JS) for layout and styling in desktop applications. As I stated previous:

Looking into cross-platform GUI frameworks, I’ve played around with WinForms (cross platform with Mono), Qt, Gtk, and wxWidgets. I’ve been disappointed to various degrees with all of them. It hit me that the most flexible and powerful cross-platform layout and styling framework out there is the HTML/CSS combo. It’s not perfect (e.g. floats, vertical centering) but it’s pretty damn good.

I stated looking at other solutions. I didn’t want to relive my experiences dealing with compiling webkit (though I was, and still am, tempted to play around with chromiumembedded), so I went with XULRunner, which allows for bootstrapping XUL-based applications (e.g. Firefox). XUL is not HTML, and in actuality provides markup to design a UI with native controls, but one control provided is the iframe control which renders and interprets HTML, CSS, and Javascript.

Having XUL for the application interface, you could write a desktop application with the application logic in Javascript, but you’re bound by the same limitations as a web application. XPCOM is a solution to these limitations and allows for interactions with the host system for things such as reading files, running another process, etc. That said, I wasn’t excited to learn XPCOM – it seemed convoluted and I didn’t want to waste time doing a deep-dive into yet another framework and being tied down to its limitations. I figured if I could write the application logic in another executable and have it communicate with the UI via a lightweight (very lightweight) XPCOM-based component, that would be ideal. In terms of simplicity and availability, sockets seemed like the go-to solution for Inter-process communication between XPCOM and anything else.

The Socket Bridge

So I came around to the idea of a Socket Bridge (I had originally played around with it in an Adobe Air project and was able to apply it here as well). Within the XUL application, Javascript-based XPCOM code would implement the Socket Bridge client and the executable handling the application logic would implement the Socket Bridge server, and the 2 could communicate easily.

SocketBridge

An HTTP server could take the place of the SocketBridge server, but I felt that was overkill, less flexible, and added an additional layer of complexity as the server then needed to be connected to the application code.

Trilite

As a proof-of-concept, I began working on Trilite, a simple HTTP profiling tool, with the application logic done in C#, that would send a number of HTTP requests to a server, capture the time it took to get a response, and calculate some simple stats about the results. A pretty simple application but something pretty handy for optimization work.

I’m pretty happy with the results thus far, particularly with regards to having a consistent, stable, and cross-platform UI.

You can find the current code in the Trilite repository.

There is no bootstrap to launch the Socket Bridge server and XULRunner app, they need to be executed manually for the application to launch:

  • Launch the server by running /trilite.public/app-server/trilite/trilite/bin/Debug/trilite.exe
  • Launch XULRunner, in /trilite.public/xulrunner, with the application.ini file in the root directory. For Windows, you can also run the trilite shortcut in the root directory.

A few screenshots under Windows:

Trilite

Trilite

Trilite

And here’s Trilite running under Ubuntu:

Trilite on Ubuntu

This post should, hopefully, provide a top-level overview of the application architecture. I’ll be writing more about XUL, XPCOM, the Socket Bridge, and Trilite in subsequent posts, providing more details and code.

Fixed (non-resizable) windows with XULRunner

I’ve been working a bit with XULRunner lately and wanted to create a fixed, non-resizable application window. After some searching, I eventually stumbled upon some code which led to a solution – adding a function call to the application’s prefs.js file:

pref("toolkit.defaultChromeFeatures", "chrome,resizable=no,dialog=no");

resizable=no prevents the window from being resized, dialog=no makes it a non-dialog window so that you can still minimize it.

Simple stuff, but this was difficult to find. Discovered thanks to this post on glazman.org

Note that after some testing with XULRunner on Ubuntu, it appears that this may be a Windows-only setting.