November 2, 2012

GTK2 interfaces via Ruby and Glade

I tried using Glade for a while and decided that it was not for me. I much prefer having a single ruby script to keep track of. I keep these notes around to aid me when I have to maintain legacy code.

Glade itself is a WYSIWYG GUI designer for GTK. As near as I can tell, it is ruby agnostic and produces as output a "project.glade" file, which is just XML. This should make it possible to edit previously generated "glade" files, making additions, changing layout, and so forth. We shall see.

The version of glade I find installed by default on my machine (now running Fedora 17) is Glade 3.12.2.

Getting this hooked up to ruby involves pulling in the libglade2 module and then instantiating your GUI via:

require 'libglade2'
@glade = GladeXML.new($glade_path) {|handler| method(handler)}
However, when I use the current glade to create a trivial glade file and do the above ruby-libglade2 thing on it, I get:
libglade-WARNING **:Expected <glade-interface>.  Got <interface>.
libglade-WARNING **:did not finish in PARSER_FINISH state
in `initialize': could not load glade file /home/tom/bang.glade (IOError)
The IOError part is misleading, the file is there and it is readable, the problem is that libglade does not like it. And when I look at some previosly generated glade files they have lines like this at the start, not just <interface> like I am now getting.
<glade-interface>
<requires lib="gnome"/>
The word is that this is a GtkBuilder file and not a Glade file (never mind the ".glade" extension). Apparently GtkBuilder has replaced libglade (which is now deprecated). Both glade files and GtkBuilder files are both XML files, just different.

To use a builder file with ruby, you do this:

require 'rubygems'
require 'gtk2'
# require 'libglade2' #you don't need this anymore

builder = Gtk::Builder.new
builder.add_from_file(file)
builder.connect_signals {|handler| method(handler) }
GtkBuilder is now a part of GTK (but of course they couldn't just adopt libglade, they had to burnish and rename it).

Also, after Glade 3.8, (i.e. with version 3.10 and later) support for libglade was removed. This means if you want to work with an old libglade project (which we do), you have two choices:

The conversion script from glade to "builder" format is an official part of the GTK distribution, and is called gtk-builder-convert. And, by golly, it is right there on my Fedora 17 system! To run it, do:

gtk-builder-convert  oldfile.glade newfile.xml
Apparently the ".xml" extension is conventional for builder files. Once this file conversion is done, the trick is changing the calls in the ruby code itself to use the new builder API. See: The API in short seems to be to initialize via:
@builder = Gtk::Builder.new
@builder.add_from_file "path/to/gui.xml"
@builder.connect_signals { |h| method(h) }
Then to find an individual widget:
w = @builder.get_object("name")
To get an array of all widgets:
w_all = @builder.objects
Rumor has it that all widgets start out not visible, so you need to do w.show on each. Maybe show_all on the appropriate top level widget would do.
Feedback? Questions? Drop me a line!

Tom's Computer Info / tom@mmto.org