tech

Mise-en-abîme

Mise-en-abîme ("placing into infinity or "placing into the abyss", see Wikipedia) has always fascinated me. I suppose it started with the Quaker Oats man (who I'm sure I've mentioned here before):

(from http://www.scripophily.com/)

Though I remember this image more vividly, and with reds, and I think from my childhood. Notice how he's holding a box with another Quaker Oats man just like him on it, and he's holding a box, ad infinitum.

The laughing cow is another food-related one (see http://lunettesrouges.blog.lemonde.fr/files/2007/10/mise-en-abyme.119332...).

Also popular in the visual arts (Dali's La Guerre, see http://www.ecriture-art.com/art/dalilaguerre.jpg).

And literature (the play within a play of Hamlet, footnotes to a poem in Pale Fire which actually constitute the narrative etc.). And film (Synecdoche, New York is probably the best example, but it also happens in Adaptation and more recently in Inception: dreams within dreams, reflecting and influencing each other).

And obviously in nature and mathematics we have fractals. And in computer science recursive functions. And so on...

So, quite interesting, occasionally mind bending.

I wondered whether I could extend this idea to web servers: could a web server present a page; and on that page, a link which would start another web server and load a page from it; the latter page being embedded in the first page, and also presenting a link which would start another web server then load a page from it; ad infinitum...

So I wrote such a thing in Ruby. It's attached to this blog entry. Here's a screenshot:

It could carry on until the resources of the computer ran out (here I started 19 web servers). It uses jQuery to load the content from the next web server into an iframe inside the current page. You need rack, backports, and mongrel to run it.

Just for fun.

Rationalisation

I'm working my way down to a single hosting company (currently I have a Dreamhost account and a Site5 account; I'm getting rid of the Dreamhost account, not because it's worse, but because I've got this blog on Site5 and it's more complicated to move).

I'm also expiring some of my domains (flickrlilli.org.uk among them), closing down various svn front-ends I had setup (I just use github or gitorious in future), and pointing all my DNS entries to one place with one set of contact details.

And I've closed down advertising on my site, as I'm effectively shutting down my moochlabs business for the time being. It made me a bit sad to close down http://moochlabs.com/; but, really, I'm not interested in any work outside my day job at the moment.

I also need to move my network backups somewhere. Can anyone suggest a good, Linux-friendly backup solution? A few years ago the options were limited, but I'm guessing things have improved since.

I am also thinking of closing down one of my many email accounts (my moochlabs one) which still gets quite a bit of mail. Need to do some unsubscribing there, too.

Need to simplify...

Writing the Clutter cookbook

I'm almost exclusively working on the Clutter cookbook at the moment, and I keep meaning to write about what it's like to spend your time writing. I'm not sure what's driving this need to explain myself. I think it's partly because I feel a bit unproductive at times, despite working pretty hard, and I feel like I need to understand why.

Perhaps if I explain the pattern of my work week. It goes something like this:

  • Start the week thinking about which part of the Clutter API to write about. Clutter is pretty vast (well, not the API so much as what it makes possible) and flexible (so you have choices about how to implement a particular feature, animation, effect, UI element etc.). I am still finding stuff in there I haven't noticed before: new functions, configuration options I haven't noticed, whole new chunks of API (it's evolving like nobody's business). But at least I put together a plan with the Clutter maintainer, Emmanuele a while back, which puts some structure and priority around which things which are important.
  • I then try to come up with a recipe idea to illustrate part of the API, or an interesting topic, or to answer a question I've noticed on the mailing lists or IRC channel. The idea might be something like "reusing an animation with different UI elements", or "handling mouse button presses", something like that. I may also look around at other treatments of the same thing in other cookbooks, tutorials etc., on the web and in O'Reilly Safari; perhaps even try to find videos of a particular UI effect (e.g. today I was looking at cover flow videos, implementations, patent applications [can I even write about that kind of effect?]).
  • Then I try to write some example code to get a feel for the API. This might involve talking to the Clutter developers on IRC about how something works, or maybe sending something to the mailing list. Occasionally I find bugs and log them (this can suck up a lot of time as I try to do as much due diligence as possible before logging anything, and provide decent reproducible test cases if possible). I frequently need to write maybe half a dozen small programs and perhaps a small application to try stuff out (like: "what happens if I put this UI element over this one?", "how does the height of an element get reported if it's moved away from the view point (into the z axis)?", "If I set this property, how does that affect the object's behaviour in this context?" and so on).
    (The code I'm writing is in C, which I admit is a bit of a struggle. I'm just about getting to grips with it now.)
  • At the same time as I'm writing this code, I'm maintaining my own git branches for each recipe I write, as they have to be kept isolated from each so they can easily be merged in one at a time (hopefully). This means keeping up to date with Clutter as it's being developed. So I'm also learning git (which I've never used a lot before) to pull changes in from Clutter master to my branches (and still sometimes screw it up).
  • While I'm doing that, I'm also starting to think about this part of the API from a developer perspective: Are there alternative ways to do this in Clutter? Why should I use this approach? Why not this other approach? I start putting notes together about the code I'm writing, very rough to start with.
    At this point, I quite often find myself paralysed as I start writing the text for the recipe. Writing text is much harder than writing code, at least for me; particularly writing text about code. (I can write code until the cows come home, but writing text is much harder: which is why most open source projects have lots of code and very little, mostly poor documentation.) Sometimes, finding a decent "story" to tell about the recipe or piece of code can be frustratingly hard (like what I've experienced today when approaching ClutterAnimator :) ), and I find myself suffering what you might call "writer's block". At which point I make several false starts, write free-form pieces trying to articulate what I'm doing, what I'm explaining, just write anything at all to try to shift the block. Sometimes I can be blocked like this for half a day; frustrating, unproductive, prevaricating, maddening half of a day. Sometimes the best thing to do is take a break, go for a walk, do some admin or research on something else altogether. Then before I know it, thankfully, the next day everything slots into place again, and I can write again.
  • At some point while I'm putting tangible paragraphs together in my rough draft, I move it over to the Docbook template for the cookbook. This means putting XML mark-up and formatting around what I've written so far. This then gets checked in with the code; edits are then checked in as I go along; occasionally I'll merge edits together (thankyou, git rebase -i) to make the development history less convoluted.
    I also take any screenshots and video (the latter using gtk-recordMyDesktop) I need and incorporate those into the XML template.
  • Eventually, I get something together and end up with a first draft. Then I leave it for at least half a day before I go through it again, cleaning up the text and making sure my branch is spick and span.
    The process of iterating over the recipe to improve the text is something miraculous to me: I don't do it consciously, but somehow I can read text and rewrite it to read better. I don't know how I do it, to be honest. Which is good, because it means I've basically turned the skill into a habit; but that in turn makes it difficult to reflect on. I don't think I could teach it to anyone either, as I don't explicitly understand the unconscious rules I'm applying.
  • Finally, I submit the recipe as a bug to the Clutter bugzilla. I typically post a bug marked as an enhancement request (e.g. http://bugzilla.clutter-project.org/show_bug.cgi?id=2288), along with a link to my git branch (e.g. http://gitorious.org/clutter-cookbook/clutter-cookbook/commits/cookbook-...). At this point, Emmanuele may come back to me with some requests for changes or comment on the bug; I try to respond as quickly as possible, and put a note on the bug when I'm done. At which point, hopefully, Emmanuele merges the work into Clutter master and the recipe is complete.
    In an average week, I can turn out one or two recipes. If I'm trying to write an introduction to some Clutter concept (e.g. last week I was writing an introduction to ClutterScript), it might be slower, as I have to understand the scope of the concept and find a way to communicate it.

It's the blockages which frustrate and shame me. I wish they didn't happen (they are pretty depressing too), but I think they might actually be an essential part of the "creative process". The miracle of copy-editing makes up for it :).

Why upgrading to Fedora 13 was a pain in the backside

I resist upgrading my work machine as much as possible, as whenever I do, everything I rely on stops working properly. A few notes on my particular pains this time round as I upgraded to Fedora Core (FC) 13:

  • SELinux is an utter pain. And for some reason it's difficult to turn off in FC 13 as the SELinux graphical config tool isn't installed by default. The package you need is policycoreutils-gui, which will enable you to disable SELinux easily.
    Josh's suggestion is simpler: "edit /etc/selinux/config by hand and set SELINUX= line from enforcing to disabled".
  • The GNOME menus have ceased to be editable by default (there are lots of things there I don't use very often, and don't want clogging up my menus). You need to install alacarte to be able to edit them easily.
  • I like to be able to use sudo, so I uncommented this line in /etc/sudoers:
    %wheel ALL=(ALL) ALL
    and added my user to the wheel group:
    usermod -G wheel -a ell
  • mp3 and other restricted codecs are not available by default. To get these, you can do:
    sudo rpm -ivh http://download1.rpmfusion.org/free/fedora/rpmfusion-free-release-stable.noarch.rpm
    sudo yum install gstreamer-plugins-bad gstreamer-ffmpeg gstreamer-plugins-ugly -y
  • Personally (because I'm set in my ways), I like quodlibet and grip for music (I know how to configure them to suit my taste; and yes, I know they're both pretty old hat). So I tend to install these next. You can also install lame if you want to be able to rip CDs to mp3.
  • I like pidgin better than empathy. Still.
  • I need ruby, ruby-devel and rubygems. At least I don't have to build rubygems any more on modern distros.
  • I need the Java plugin for Firefox:
    sudo yum install java-1.6.0-openjdk-plugin
  • Installed other tools I use quite a bit:
    sudo yum install wget git
  • I've got used to using the gedit plugin which strips trailing space when you save a file:
    mkdir ~/.gnome2/gedit/plugins/
    cd ~/.gnome2/gedit/plugins/
    wget http://users.tkk.fi/~otsaloma/gedit/trailsave.py
    wget http://users.tkk.fi/~otsaloma/gedit/trailsave.gedit-plugin
    It turns up as Save without trailing space in gedit's plugins list.

So what's improved in FC13? Erm...

  • Shotwell is quite a nice photo manager.
  • The system boots slightly faster.
  • The volume settings are more sane, so I don't have to manually keep turning up my speakers between tracks (not sure what the technical term is, but the range from 0 to maximum across the software settings covers a greater range of volumes - if that makes sense).

That's about it. (My main reason for upgrading is so I can more easily build other people's software, rather than for application upgrades.)

There would probably be more if I wasn't so old fashioned about the applications I use...

Using wget to mirror a website

Occasionally you need to mirror a website (or a directory inside one). If you've only got HTTP access, there are tools like httrack which are pretty good (albeit pretty ugly) at doing this. However, as far as I can tell, you can't use httrack on a password-protected website.

curl can probably do this too, and supports authentication, but it wasn't obvious.

So I ended up using wget, as it supports mirroring and credentials. But the issue here is that wget plays nice and respects robots.txt; which can actually prevent you mirroring a site you own. And nothing in the man page explains how to ignore robots.txt.

Eventually, I came up with this incantation, which works for me (access to password-protected site, full mirror, ignoring robots.txt):

wget -e robots=off --wait 1 -x --user=xxx --password=xxx -m -k http://domain.to.mirror/

where:

  • -e robots=off obviously disables robots
  • --wait 1 forces a pause between gets (so the site doesn't get hammered)
  • --user and --password: self-evident
  • -x creates a local directory structure which "mirrors" (see what I did there?) the directory structure on the site you're mirroring
  • -m turns on mirror mode: "turns on recursion and time-stamping, sets infinite recursion depth and keeps FTP directory listings" (from the man page)
  • -k converts links after download so that URLs in the mirrored files reference local files

Don't use it carelessly on someone else's website, as they might get angry...

An unpleasant experience

A few years ago, I wrote a Rails (1.0.0) application for Nicola (my wife), to help her with her PhD research. It ran on her Linux laptop, happily, for those few years.

However, once the new laptop has arrived, I knew I'd have to migrate the application from Linux to Windows; I also wanted to avoid having to update the application for a newer version of Rails. How painful could it be? Fairly.

First I needed an old MySQL server (in case the API has changed), 5.0.15 to be precise. It is practically impossible to find archived downloads on the MySQL website, but I got there eventually.

Next I needed to get an old Ruby (1.8.4) for Windows. Again, virtually impossible to find old versions of Ruby with an installer. When I first did this, there was a Ruby 1.8.4 One-Click Installer for Windows, which seems to have disappeared. I finally tracked it down to some website run off some bloke's back somewhere out East.

Then, I needed Rails 1.0.0. For whatever reason, the Ruby I installed couldn't get Rails off the official gems repository (probably because the gem repo format changed). So I installed rails 1.0.0 on a different machine, created a new Rails project, then froze the 1.0.0 gems into it; then copied the frozen gems over to my app on the new machine. Phew.

Finally, I'd used RedCloth in the app. However, after a couple of attempts, I decided it was easier to rip it out than try to install it on Windows. So I did some surgery.

Add to that the fact that Nicola had forgotten her password (Firefox had been saving it), so I had to manually edit the db to add one; plus no decent text editor on Windows 7; plus MySQL not removing its service properly when I installed the wrong version then uninstalled it (sc delete MySQL removes errant services, by the way); plus Windows 7 making it difficult to get an administrator command prompt; etc. etc..

So overall a frustrating experience, but I did finally get there.

(On top of that, I also migrated several thousand POP-ped emails from Thunderbird 2 on Linux to Thunderbird 3 on Windows: I thought there would be an import wizard which would know what to do, but I saw no sign of it. And moved all her data over and installed OpenOffice. Entertainment all round.)

Once I've got over my trauma, I will provide links to where to find ancient versions of apps and libraries. Perhaps I should be an archaeologist.

A script for parsing work log files

Attached is my Ruby script for parsing log files I keep at work. I have to complete a weekly report, and this forms the basis of that; as I don't keep regular office hours (I flexi-work around child care), it also helps me keep track of the hours I've worked.

The basic principle of operation is as follows:

  1. I create a file for each working week, called something like week45.log
  2. During the week, I record bits of activity I do (see below); I also note down stuff I plan to do next (again, see below)
  3. At the end of the week, I run parse_work_log <file name> > summary.out on the file to produce a log of what I've done
  4. If anything goes wrong, I tend to edit the work log and regenerate, so I can just keep the log (not the summary)
  5. I cut and paste from the summary.out file into an email I send round

The format of the file is deliberately simple to make it easy to maintain; there are a handful of formatting rules. An example is shown below.

**********
2009-12-21

09:30-12:00    Researching this and that #research
12:00-13:00    -Lunch
13:00-14:00    More research
14:00-18:00    Writing some application #coding

**********
2009-12-22

09:30-10:00    Admin #Admin
10:00-10:15    -Break
10:00-12:00    Found out something rather marvellous #Very important research
12:00-12:45    -Lunch
12:45-18:00    Writing another application #coding

**********
+NEXT Have lots of fun banging my head on a brick wall
+NEXT Reinstall my operating system

Which, when parsed, produces this on stderr:

*************************************

Worked 15.25 hours

And this on stdout:

*************************************
This week:

Admin:

  * Admin

Very important research:

  * Found out something rather marvellous

coding:

  * Writing some application
  * Writing another application

research:

  * Researching this and that

*************************************
Next:

  * Have lots of fun banging my head on a brick wall
  * Reinstall my operating system

Notes on formatting:

  • The asterisks and dates are just there to make it more readable - they're basically ignored
  • An entry is a single line with the format HH:MM-HH:MM <...whitespace...> <text> <#optional tag>\n
  • The time span for an entry is added to the total time, unless the entry text contains -Lunch or -Break
  • # creates a tagged entry which gets included in the report; it appears as a bullet point with the tag as its heading; any entries with the same tag get aggregated under a single heading; tags and entries appear in the order they occur in the file
  • Any line starting with +NEXT gets listed in the Next section at the end; tags don't work on this (could, but don't at the moment)

It is pretty primitive, but it does the job for me.

Installation: there isn't any, really. It works from the command line and needs Ruby. The licence? BSD, I guess.

An introduction (of sorts) to JavaScript desktop application development with Gjs and Clutter

This turned into a pretty long blog entry. To help you decide whether you want to stick it out, it's about:

  • My experience with C development for Moblin
  • JavaScript for desktop applications
  • Gjs, GObject introspection, and GIR repository installation
  • Running JavaScript Clutter applications using gjs
  • Interesting movements in the JavaScript world

Background

I started work at Intel's Open Source Technology Centre 6 weeks ago (just realised I haven't written about that here yet), working on the Moblin SDK. Moblin is a Linux-based platform for mobile devices (netbooks, UMPCs, that sort of thing); my role in the project is working as part of the SDK team - basically trying to help third-party developers outside Intel develop software which runs on Moblin. So far, this has involved learning as much about the Moblin stack and ecosystem as possible, as well as helping organise and add to the content on Moblin-related websites. (It's challenging, exciting work and I'm thoroughly enjoying it so far.)

Currently, software development on Moblin is comparable to generic Linux development: languages like Python, Ruby, C++, Perl, Java, C# (via Mono) etc. are all available. However, if you want to make use of the full range of Moblin libraries (like our stuff for managing media metadata or interacting with social networking sites), and combine them with Clutter (our GUI toolkit), the best approach (at the moment) is to program in C. While many of the Moblin libraries have bindings to other languages (like Python and Perl), C gives you the best, most consistent access to all of them (as they're all written in C). You'll also find Moblin development easier if you're familiar with GNOME and glib, both of which are fairly C-centric.

My background isn't in low-level system programming. I have been learning C since starting at Intel, and have enjoyed it thoroughly, but there are several aspects of it I could live without:

  • Memory management is my main bugbear. I really don't want to have to care about allocating memory for data structures, then cleaning up when I'm finished with them. Learning how to (still learning...) has definitely enhanced my understanding of how programs actually work under the bonnet, but dealing with memory directly is not, in general, fun. I'd rather the runtime dealt with it.
  • autotools (aka the GNU Build System) are not straightforward, especially if you're used to build tools like Ant and Rake (or even Maven). I know they are extremely powerful and flexible, and ubiquitous for open source projects, but I defy anyone to tell me they are simple, easy to learn, or well documented. In fact, the autotools (automake, autoconf) actually wrap other tools (make) which are even more complicated. This is partly a consequence of the job they do (making it possible to compile software across different platforms), but means they are not approachable. See the diagram on the autools Wikipedia page to get an idea of how complicated they are.
  • Pseudo object oriented programming (in C) isn't really as pleasant as full OOP (in a language like Ruby). GObject for C (part of GLib) gives you some of the facilities of full OOP, but (as far as I understand it) it's not possible to encapsulate data with the methods which act upon it. It also seems tremendously complicated. Even with GObject, you are still basically doing imperative programming, so encapsulation relies on namespacing and (kind of) casting objects to the right class before passing them to a function (as classes don't seem to know about their parent class, as such). Having said all this, one smart feature GObject does support is introspection, which makes it possible to automate binding other languages to a C library.

So, with my background, and with the goal of making Moblin development easy and attractive, I am keen to find alternatives to having to program in C all the time. Dynamic, interpreted languages (like Ruby or JavaScript) seem to me to be better suited to exploratory, iterative programming: the kind of programming most people do most of the time. This is a goal shared by the GObject Introspection project:

C is good for graphics, multimedia, and lower level systems work. However, writing complex software is difficult and error-prone without garbage collection. A managed runtime such as JavaScript, Python, Java, Lua, .NET, Scheme etc. makes a lot of sense for non-fast-path application logic such as configuration, layout, dialogs, etc. ... Thus, one of the major goals of the GObject introspection project is to be a convenient bridge between these two worlds, and allow you to choose the right tool for the job, rather than being limited inside one or the other. (from http://live.gnome.org/GObjectIntrospection)

GObject Introspection is already being used in GNOME development, to generate JavaScript bindings for the GNOME libraries: the next version of the GNOME desktop (in GNOME 3), GnomeShell, uses JavaScript extensively (calling Clutter, the Moblin graphics library, incidentally). Gjs is the name of the project producing the bindings, as well as being the home of the JavaScript engine itself (also called gjs, and based on Mozilla's implementation of JavaScript in C, SpiderMonkey).

JavaScript is an interesting language. I've used it in web applications for quite a long time (since about 2000), but never entertained the idea of using it for anything other than client-side web programming. Occasionally I'd come across server-side JavaScript (persevere), JavaScript implementations like Rhino, and even wrote some ASP code in JScript (as Microsoft called it) a few years ago. Frameworks like jQuery and the thorough integration of JavaScript with Rails meant that I've done more of it in recent months, but I never thought of using it as a general purpose language, or one for desktop development.

Looking for an alternative to C, and hearing from my colleagues about JavaScript, made me decide to get a feel for Gjs et al, as well as write something to run on Moblin. I decided to write a JavaScript application which made use of the Moblin graphics library, Clutter. Eventually, I ended up successfully writing a JavaScript implementation of tic-tac-toe, using Clutter for the user interface, and even including some simple animation. As an application, it is a bit scrappy (the code is attached), but as a learning aid, doing the project was very useful. It wasn't an easy journey, but it was an eventually satisfying one.

Using JavaScript for the not-web

I did my development work on a Fedora Core 11 laptop, with an Intel chipset.

I tried a variety of ways to install all the pieces I needed for JavaScript development with Gjs, GObject Introspection, GNOME libraries, and Moblin libraries. Even getting an idea of what all the pieces do is painful, and the documentation is pretty woeful. I ended up doing lots of source code grep-ing and googling.

In the end, it turns out that the following packages are available for Fedora Core:

  • gobject-introspection: This provides tools and APIs for working with GIR XML files and typelib (binary versions of the GIR files): these are two formats for storing introspection data about GObject classes (basically, mapping the API of a C library into language-neutral descriptions of the APIs). The metadata for several common libraries (like GLib) is part of this package.
  • gir-repository: This provides more introspection metadata about other common libraries (like GTK+ and DBus-GLib)
  • gjs: This enables you to use the gobject-introspection data to access C libraries from JavaScript (i.e. it's the JavaScript bindings for GNOME libraries).

Now, unfortunately, the versions in the repositories for Fedora 11 are out of date: generating the Clutter bindings requires gobject-introspection-1.0, which isn't available. Plus, this code is so new that it's changing very rapidly, and you probably need the latest version from the source repository to get stuff to work.

To compile all these bits, you're going to need the basic build tools. On Fedora, that means this lot:

$ sudo yum install git flex bison gnome-common libgnome-devel libffi-devel \
    python-devel libtool automake autoconf make gtk-doc xulrunner-devel

(And maybe others: I lost track. But if you're trying to do this yourself, you'll probably know what to do if something's missing. Anyway, Josh is going to sort some packages out before long, hopefully. If you know a better way, let me know.)

Once you've got those installed, though, you should be able to build everything from source fairly easily.

As we're installing into /usr/local, first thing to do is make sure the compiler/linker can find your custom-compiled packages. In your ~/.bashrc file, add this line:

export PKG_CONFIG_PATH=$PKG_CONFIG_PATH:/usr/local/lib/pkgconfig

This tells the pkg-config tool (used by autotools to locate libraries and headers) where your custom installations are. Then reload your bash settings with:

$ source ~/.bashrc

to make sure they're picked up. Any future bash sessions will use this setting. Now you're ready to build.

gobject-introspection:

$ git clone git://git.gnome.org/gobject-introspection
$ cd gobject-introspection
$ ./autogen.sh --prefix=/usr/local
$ make
$ sudo make install

gir-repository:

$ git clone git://git.gnome.org/gir-repository
$ cd gir-repository
$ ./autogen.sh --prefix=/usr/local
$ make
$ sudo make install

gjs:

$ git clone git://git.gnome.org/gjs
$ cd gjs
$ ./autogen.sh --prefix=/usr/local
$ make
$ sudo make install

You can check gjs is working by doing:

$ /usr/local/bin/gjs
gjs> 1+1
2
gjs>

It's a good idea to add /usr/local/bin to your path, again in ~/.bashrc:

export PATH=$PATH:/usr/local/bin

(and source ~/.bashrc to pick it up if necessary)

To compile Clutter itself, you'll also need these library headers:

$ sudo yum install glib2-devel mesa-libGL-devel libXext-devel \
    libXfixes-devel libXdamage-devel pango-devel cairo-devel

(Again, maybe others too.)

Once you've got those too, you can checkout Clutter using git, and build it with introspection turned on:

$ git clone git://git.clutter-project.org/clutter
$ cd clutter
$ ./autogen.sh --prefix=/usr/local --enable-introspection
$ make
$ sudo make install

The final step is one which doesn't appear to be documented anywhere, but which is utterly vital: without it, gjs can't find any of the introspection metadata, and won't be able to call any of the C libraries through their JavaScript bindings. Add this line to your ~/.bashrc file:

export GI_TYPELIB_PATH=$GI_TYPELIB_PATH:/usr/local/share/gir-1.0/

(Again, use source if necessary.)

Testing gjs with Clutter

To test the install, and make sure the Clutter JavaScript bindings are working, put this code into a file test.js:

const Clutter = imports.gi.Clutter;
Clutter.init (0, null);
let stage = Clutter.Stage.get_default ();
stage.title = "Test";
stage.set_color(new Clutter.Color( {red:150, blue:0, green:0, alpha:255} ));
stage.show ();
Clutter.main ();
stage.destroy ();

Run it from a command line with:

$ gjs test.js

You should see something like this:

If this works, you should be able to run my tic-tac-toe (semi-)implementation, linked at the end of this blog entry. To run it, copy the two files into a directory, remove the .txt suffixes, then get a command line in that directory and run:

$ gjs ox.js

There's no AI (so you'll have to play both sides), but notice the use of a scale animation as each move is written to the board. Also interesting is how you can use anonymous JavaScript functions to define callbacks for signals.

I've not experimented extensively, beyond calling a few bits of the Clutter and Netbook Toolkit APIs. If you want more examples, have a look at the GnomeShell tests and UI code. The mx tests are another source of sample code I used.

Another tip: if you're trying to work out what's available in the JavaScript bindings, there's unfortunately no nice way to do it at the moment. Your only recourse is to grep the XML GIR files, which are located in:

/usr/local/share/gir-1.0/

Reading these is a bit of a chore, and I also found it difficult to figure out what was in the API. For example, if you're trying to use a Clutter constant like CLUTTER_X_AXIS, the GIR file has this entry:

<namespace name="Clutter"
             version="1.0"
             shared-library="libclutter-glx-1.0.so.0"
             c:prefix="Clutter">

... loads of cruft ...

  <enumeration name="RotateAxis"
                  doc="Axis of a rotation."
                  version="0.4"
                  glib:type-name="ClutterRotateAxis"
                  glib:get-type="clutter_rotate_axis_get_type"
                  c:type="ClutterRotateAxis">

    <member name="x_axis"
               value="0"
               c:identifier="CLUTTER_X_AXIS"
               glib:nick="x-axis"/>

  </enumeration>

... loads more cruft ...

</namespace>

So, to reference the CLUTTER_X_AXIS constant, my first thought was look up the member element with a c:identifier corresponding to the constant I want; then use the path from the namespace, through the enumeration name, to the member name, i.e.:

Clutter.RotateAxis.x_axis

But in fact it's:

Clutter.RotateAxis.X_AXIS

(the name attribute, capitalised).

I also found that some methods and classes in the GIR for GLib didn't work (like GLib.printf). I'm sure there's a good reason why, it's just I couldn't work it out.

What's missing?

I spent quite a few hours figuring this stuff out, and stumbled a lot along the way. Partly because I'm not a C programmer, partly because I'm new to GNOME, I'm sure. But I think there are a few things which would have improved my experience:

  • Decent documentation, particularly of the JavaScript APIs generated for C libraries like GLib - at the moment, working out what's going to be available in the JavaScript bindings is very tedious
  • An easy installation process (see above) - largely though because I'm using libraries which are too bleeding edge, just because they're the only ones which worked well
  • An intelligible module system, for modularising code - at the moment my application will only run from the directory where the files are, as I've yet to work out how to get the path to the directory containing the script programmatically; I'm not sure how you'd organise large groups of files spread over lots of directories
  • A decent packaging system with dependency tracking, so that you can distribute JS apps and know they'll work
  • Functions to make developers' lives easier, like a decent REPL (gjs doesn't even have a print function - there is a patch to gjs which will give you that - see here: http://bugzilla-attachments.gnome.org/attachment.cgi?id=135898 - but you'll have to patch manually at the moment to get it)

And finally, it might be worth taking a look at Seed, which is an alternative JavaScript implementation, but one which still understands GObject introspection. Seed is interesting in that it seems to provide more niceties, like a better REPL environment, more documentation, and a fuller standard library (filesystem and environment interfaces in particular).

What's next for JavaScript?

It looks as if the JavaScript world is hotting up at the moment. This is a recent news report on the state of JavaScript:

http://arstechnica.com/web/news/2009/12/commonjs-effort-sets-javascript-...

It mentions the CommonJS standardisation effort, which is attempting to resolve some of the shortcomings of JavaScript as a general purpose language.

Reading through the CommonJS wiki, I was particularly interested in Narwhal, which resolves some of the issues I mentioned in the last section: it includes a package manager, module system, and standard library. It also provides support for different JavaScript engine back-ends: currently this includes a SpiderMonkey adapter. Given that Gjs is broadly based on SpiderMonkey, it seems likely that creating a Gjs back-end for Narwhal wouldn't be too onerous.

One other thing which could potentially be useful in Narwhal is the availability of separate Narwhal environments (called "seas") with their own set of packages. This could help isolate applications from each other in an environment like Moblin, where you want third parties to be able to develop applications without trampling on each other's libraries.

Another tool of interest is jake, a port of Ruby rake to JavaScript, which seems to be optimised to work with Narwhal. This could provide a reasonable alternative to autotools for the simpler build requirements of a JavaScript application (where there's no need for a compile step or library linking).

A combination of Narwhal (packaging/modules), with the power of Gjs binding to pretty much any C library, would make an attractive environment to develop in.

I should also mention node.js, server-side JavaScript primarily designed for building network programs, but which incorporates a CommonJS module system. It's built on Google's V8 JavaScript engine. It's also interesting because it is designed to be highly performant and memory-efficient, and has an interesting event-driven I/O model, like EventMachine or Twisted.

I'm definitely looking forward to seeing what happens next.

Back on Fedora

A few years ago, I used to work on RedHat Linux, then Fedora: my first Linux machine ran RedHat Linux. Then I got sick of things breaking every time I upgraded (on one traumatic occasion, my audio stopped working after a Fedora upgrade) and switched to Ubuntu.

But in my new job, I need Linux, but also need to encrypt my laptop's hard drive. I had a go at doing this with Ubuntu, with disastrous results. Didn't really know what I was doing (I did manage to encrypt the hard drive, but couldn't figure out how to mount it during boot). Fedora makes this simple, though. So I moved across, and have to say I'm pretty glad I did. It's very similar to Ubuntu in many ways, and I don't feel like I'm missing anything. My main annoyance was SELinux, which just wanted to stop me having any kind of fun with my computer; so I switched it off.

So, if you need to PGP encrypt your hard drive, but currently use Ubuntu, have a look at Fedora instead.

Playing mp3s on Moblin (2.1)

I have an EeePC with Moblin 2.1 (release candidate) installed on it (via the packages in http://repo.moblin.org/moblin/releases/2.1/ia32/os/). By default, you don't get an mp3 decoder with this distribution. It wasn't obvious (when I googled for it) how to install the right GStreamer plugins: several blog entries suggested a variety of pretty hacky methods and work-arounds.

Then I chanced on a blog entry which mentioned that Fluendo have a free legally-downloadable RPM of their own mp3 encoder; I remember someone at work mentioning it too. I downloaded and installed this onto my netbook with no difficulties. You have to register for an account and go through a faux shopping basket to get it, but it is fairly painless. Here's the product page URL:

http://www.fluendo.com/shop/product/fluendo-mp3-decoder/

Syndicate content