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.