Feb 22, 2011

GTK+ in a browser, without plugin: realistic ?


I have been playing a bit with Emscripten these days...

Category: HTML5
Posted by: pierrot

It appears that it is working pretty well, and I am wondering whether it could allow running complex UI libraries such as GTK or Qt, with the HTML5 canvas 2d context as graphical backend. Of course it raises a number of technical questions, without even starting to think at performances.

The idea is simple : allow developers to use feature rich, robust and well known libraries to build user friendly web apps. Let's consider the case where technical problems are resolved, and where the solution gains some traction amongst web developers. It would then be easy to accelerate and extend this JavaScript UI library by just replacing it with its good old native counterpart, directly in the browser.

I firmly believe the thing is not completly impossible, at least technically speaking.

Let's start with a simple example: GTK+-1.2. Yes, it is obsolete, but better start with something easy: GTK+ 1.2 has few dependencies (GLib, XWindow). It seems doable to convert GLib to JavaScript; the following example shows how to use a GArray in a web browser.

Step 1: Get started as indicated on the Emscripten project and build your d8 shell from v8 JavaScript engine sources.

Step 2: get GLib 1.2.10, unpack it and cd into this directory

Step 2 bis: add this to garray.c:

void g_array_append_val_func(GArray* a, gint value) { g_array_append_vals(a, &value, 1); } gint g_array_index_func(GArray* a, guint i) { return ((gint*)(a)->data) [(i)]; }

(Sorry, just a quick&dirty hack)

The aim is to provide some features as functions, the original versions being provided as macro, which are of course useless in JavaScript.

Step 3: generate LLVM bitcode for a few C files:

for i in garray gmem gtree; do clang -I. -DHAVE_CONFIG_H -DG_LOG_DOMAIN=g_log_domain_glib -D_REENTRANT -emit-llvm -c $i.c -o - | llvm-dis -show-annotations -o $i.ll done

At this point you should get three .ll files: garray.ll gmem.ll gtree.ll

Step 4: generate JavaScript code from LLVM bitcode

for i in garray gmem gtree; do ./emscripten.py /$i.ll /d8 > $i.js done

Step 5: execute a sample test script:

cat << EOF > use_garray.js var FALSE=0; var TRUE=1; var garray = _g_array_new (FALSE, FALSE, 4); for (var i = 0; i < 10; i++) { _g_array_append_val_func (garray, i); } for (var i = 0; i < 10; i++) { print(_g_array_index_func(garray, i)); } _g_array_free (garray, TRUE); EOF d8 garray.ll gmem.ll gtree.ll use_garray.js

Et voilà ! If all goes well you should get a nice sequence of numbers, ranging from 0 to 9...

This little example only scratches the surface. There are a number of things to do to make the whole thing work, such as replacing XWindow features with HTML5 Canvas 2D and standard browser input event (tricky !), handling the main loop (though a web worker), and defining JavaScript binding (maybe reuse existing work already done for GTK2).