rtyler

Using Glade3 with GtkAda

I have been a hobby hacker for my entire adult life, and a bit before that too. When your profession is making software, or even making open source software, the joy from hobby-hacking can diminish or even disappear. One of the things I learned from burning out was that, if I am going to continue to enjoy hacking as a personal hobby, I would need to pursue "frivolous hacking."

Frivolous hacking:

Hacking on something for no practical or otherwise useful reason.

Late last week I was struck with the desire to play around with GtkAda. Ada has long been a hobby language for me, but I have never gotten the desire to make a GUI-based application. For this weekend's frivolous hacking, I created arun a simple Ada Command Runner with GtkAda and Glade 3.

Arun


The primary reason to use Glade, in my opinion, is that it's 2017 and hand-coding interface components is beyond tedious. At a high level, Glade provides a WYSIWYG approach for defining the various interface components a program requires, exports that as an XML file which can later be loaded by the program at runtime.

Glade3 for arun

Prerequisites

My first attempt relied on using the Glade3 and GtkAda packages which exist for Debian-based systems. Unfortunately libgtkada2.24.4-dev binds to Gtk+ version 2, rather than Gtk+ version 3, which Glade3 targets.

Instead of native packages, you can also download GtkAda from AdaCore directly. Opting for this route I was disappointed to learn that the file named gtkada-gpl-2016-x86_64-linux-bin.tar.gz isn't actually a set of binaries but just a source tarball which must be built and installed. At first, that didn't work for me either! A bug in that source tarball leaves a user like me with one of two options:

  1. Configure the installation with ./configure --with-GL=no
  2. Grab the latest (fc8b2f9 at this time) from GitHub: git://github.com/AdaCore/GtkAda.git

I opted for the latter and within short order (make -j4!) I had fresh installation of GtkAda on my system.

Writing an app

Fortunately the Ada DK wiki has an example I could start from, which covers the basics of building a GUI with Glade3 in GtkAda. After cribbing some Ada code from the wiki page, I found another stumbling block, it wouldn't compile.

Turns out some APIs had changed since the page was originally written, but as luck would have it Stack Overflow had the answer.

Without going into too much detail on how to use GtkAda, this version of the Arun.Main procedure demonstrates a basic version of loading and starting a Glade3-based GtkAda app:

Gtk.Main.Init;
Gtk_New (Builder);

-- Load `arun.glade` which contains the interface definition
Return_Code := Add_From_File (Builder  => Builder,
                              Filename => "arun.glade",
                              Error    => Error'Access);

if Error /= null then
   Put_Line ("Error : " & Get_Message (Error));
   Error_Free (Error);
   return;
end if;

-- Register a signal handler for when
-- the "Main_Quit" signal is fired
Register_Handler (Builder      => Builder,
                  Handler_Name => "Main_Quit",
                  Handler      => Arun.Handlers.Quit'Access);

Do_Connect (Builder);

-- Get the Gtk_Widget object from the Gtkada.Builder API
-- for our commandWindow so it will be shown.
Gtk.Widget.Show_All (
    Gtk_Widget (Gtkada.Builder.Get_Object (Builder, "commandWindow")));

Gtk.Main.Main;
Unref (Builder);

With the arun binary compiled, I decided to try it out:

obj % ./arun
Starting arun
Error : Failed to open file 'arun.glade': No such file or directory
obj %

As one might expect, there is a downside to loading files at executable runtime.

Another Stack Overflow answer introduced me to the glib-compile-resources executable, which provides the solution for loading the .glade file at runtime in a more portable way. Instead of referring to a .glade file, glib-compile-resources creates a C file which can be compiled and linked into the application. Of course, this adds some more build-time complexity, as glib-compile-resources needs to be called, the C file needs to be compiled, and then the object file must be linked into the resulting binary.

With the Makefile put together, instead of Add_From_File the application uses Add_From_Resource as is demonstrated in this commit. With a resource the binary can then be distributed without the .glade file:

obj % ./arun
Starting arun
Searching for x
Searching for xeye
Searching for xeyes
Looking for an executable in /home/tyler/.rvm/gems/ruby-2.1.5/bin
Looking for an executable in /home/tyler/.rvm/gems/ruby-2.1.5@global/bin
Looking for an executable in /home/tyler/.rvm/rubies/ruby-2.1.5/bin
Looking for an executable in /home/tyler/bin
Looking for an executable in /home/tyler/scratch/bin
Looking for an executable in /home/tyler/.rvm/bin
Looking for an executable in /home/tyler/scratch/node_modules/.bin
Looking for an executable in /home/tyler/scratch/ada/gnat-gpl-2016-x86_64-linux-bin/bin
Looking for an executable in /home/tyler/scratch/ada/spark-gpl-2016-x86_64-linux-bin/bin
Looking for an executable in /home/tyler/bin
Looking for an executable in /usr/local/bin
Looking for an executable in /usr/bin
Found executable at /usr/bin/xeyes
Should Execute: xeyes
Spawning /usr/bin/xeyes
obj %

Suffice it to say, using GtkAda isn't difficult per se, it's only difficult to use when there are toolchain specific idiosyncrasies that are hard to Google. Aside from that challenge, I far prefer writing GtkAda rather than "pure" Gtk+ with C or C++.

Of course I don't expect anybody else to find my code useful, nor do I have lofty ambitions about it, thereby meeting my "frivolous hacking" requirement!

comments powered by Disqus