I want GtkBuilder+JavaScript

While having coffee with some friends a few weeks ago, I kept coming back to the thought that I need to be able to do small amounts of scripting within GtkBuilder. Especially if I'm going to switch to that from hard coding UIs in C. I figured it would take some hacking to GtkBuilder to do what I wanted. Well, it turns out not. I came to the revelation late last night, in bed, and hacked it up this morning.

First, we create GScriptJs which is a thin wrapper around Gjs. Mostly, just to be able to create an object from within the GtkBuilder file. Then, we create a custom connect func that will look for a given function in the script and attach it to the requested signal. All in all, very few lines of code. I'm pleasantly surprised.

Example GtkBuilder+JavaScript

<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object class="GScriptJs" id="script">
    <property name="script">
const Gtk = imports.gi.Gtk;

function onClicked() {
  let w = new Gtk.Window();
  w.set_default_size(320, 240);
  w.present();
}

function onQuit() {
  Gtk.main_quit();
}
    </property>
  </object>
  <object class="GtkWindow" id="window">
    <signal name="delete-event" handler="onQuit" swapped="no"/>

Example GtkBuilderConnectFunc

static void
connect_func (GtkBuilder    *builder,
              GObject       *object,
              const gchar   *signal_name,
              const gchar   *handler_name,
              GObject       *connect_object,
              GConnectFlags  flags,
              gpointer       user_data)
{
    const gchar *script_name = user_data;
    GScriptJs *script;
    GClosure *closure;

    g_return_if_fail(script_name != NULL);
    g_return_if_fail(connect_object == NULL); /* TODO */

    script = G_SCRIPT_JS(gtk_builder_get_object(builder, script_name));
    if (!script) {
        g_critical("Cannot locate script %s", script_name);
        return;
    }

    closure = g_script_js_get_function(script, handler_name);
    if (!closure) {
        g_critical("Cannot locate function %s", handler_name);
        return;
    }

    g_signal_connect_closure(object, signal_name, closure,
                             !!(flags & G_CONNECT_AFTER));
}

Get the code at https://github.com/chergert/gtkbuilderscript.

-- Christian Hergert 2011-04-24

Back to Index