1484717126
kd@ 1/17/2017

A Compulsive Minimalist’s Hello World For GJS

The official Hello World is a bit long, involves an embedded web browser, and mixes in a combination of necessary and un-necessary things. So- what is the least amount of code for GJS Hello World?

The command line

The all-text Hello World is a good start, if a little un-exciting. The point of all this is to write graphical applications. Still, it’s as short as you can get-

    #!/usr/bin/gjs
    print("Hello World");

There’s also a built-in log function, which goes to stderr by default, and adds some decoration

$ gjs -c 'log("hello world")'
Gjs-Message: JS LOG: hello world

A graphical display

    #!/usr/bin/gjs

    const Gtk = imports.gi.Gtk;
    const Lang = imports.lang;

    const Application = new Lang.Class ({
        Name: 'Application',
        _init: function() {
            this.application = new Gtk.Application();

            this.application.connect('activate', Lang.bind(this, this._onActivate));
        },

        _onActivate: function() {
            this._MyWindow = new Gtk.Window({title: "Hello"});
            this._MyWindow.add(new Gtk.Label({ label: "World" }));

            this._MyWindow.show_all();
            this.application.add_window(this._MyWindow);
        }
    });

    (new Application()).application.run(ARGV);

There is a lot, as they say, to unpack here. Let’s start where the starting is good though-

    const Gtk = imports.gi.Gtk;

This is pretty straightforward. This is how you use the module system. gi, I suspect, stands for GObject Introspection, though I can’t find it written down anywhere. Gtk is the Gnome graphical toolkit, and you’re going to use it anywhere you do anything graphical.

    const Lang = imports.lang;

So, we’re in Javascript, which has its own peculiar prototype system for doing object oriented things, but we’re interested in interop with Gnome and its tooling. So we need a layer somewhere to let us work with that. That’s Lang. It provides Lang.bind, which lets you have callbacks with a this object that makes sense, and Lang.Class, which lets you build GObject-compatible classes. This is also going to be in everything.

    const Application = new Lang.Class ({
        Name: 'Application',

This is the minimum amount you need to build a class. new Lang.Class({Name: "XYZ"}) works, new Lang.Class() does not. I haven’t really tested it, but I strongly suspect that the Name attribute matters.

        _init: function() {
            this.application = new Gtk.Application();
            this.application.connect('activate', Lang.bind(this, this._onActivate));
        }

This is a Lang-layer constructor. You’re registering a callback (or really, a Gtk-layer constructor), for later.

        _onActivate: function() {
            this._MyWindow = new Gtk.Window({title: "Hello"});
            this._MyWindow.add(new Gtk.Label({ label: "World" }));

            this._MyWindow.show_all();
            this.application.add_window(this._MyWindow);
        }

If you’ve worked with Gtk, or other desktop UI libraries before, this should seem pretty familiar. Build a window, give it a title, put a Label (a box with text) in it, turn them on.

    (new Application()).application.run(ARGV);

This is sort of ugly short hand for golfing purposes. Still, at 23 lines, we’re doing pretty good. Not much you could get rid of and still get a window.

new Application() does what you think- builds your class, and runs your constructor. It does not, however, kick off Gtk. .application.run(ARGV) does that. It’s worth noting that when writing a Gtk app, you are not writing a script, that starts at main and goes until completion. You’re writing a series of callbacks, that will get called by the “main loop” when it’s ready. If you’re familiar with web development, this may sound a lot like an explanation of how node.js works.

If you’re looking for proper documentation, with useful examples, the platform demos are where it’s at.