Table of Contents
The Problem
GTK is a popular library to build portable GUI (Graphical User Interface) written in C and an Ada binding (GTKAda) is available on Adacore Libre site.
As of 2012, there is the support of the interactive GTK builder Glade3. We describe a basic example of the different steps needed to build a “hello world” with Glade3.
Prerequisite
You must have GTKAda installed and the environnement variable GPR_PROJECT_PATH set to find the project file gtkada.gpr For Windows, GPR_PROJECT_PATH should look like :
C:\GNAT\2012\lib\gnat;C:\GtkAda\lib\gnat (if you used the default locations)
Creating the XML description file
Glade3 generates interactively XML files that describes the UI. Our basic UI will contain a Main_Window with a Label. We must take care of the termination by declaring a signal “destroy” in Main_Window to quit the app, otherwise the program will not end when we close the window.
glade3 output : simple.glade
<?xml version="1.0" encoding="UTF-8"?> <interface> <requires lib="gtk+" version="2.18"/> <!-- interface-naming-policy project-wide --> <object class="GtkWindow" id="main_window"> <property name="width_request">400</property> <property name="height_request">100</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="title" translatable="yes">Glade 3 simple demo with Ada</property> <property name="resizable">False</property> <property name="window_position">center</property> <signal name="destroy" handler="Main_Quit" swapped="no"/> <child> <object class="GtkLabel" id="some_label"> <property name="width_request">200</property> <property name="height_request">50</property> <property name="visible">True</property> <property name="can_focus">False</property> <property name="label" translatable="yes">Hello from Glade 3 ;-)</property> </object> </child> </object> </interface>
Ada code
First, we declare the handler/callback that will be attached to the “destroy” signal. The callbacks must be in a package, otherwise you run into accessibility errors.
The Gobject event “destroy” is handled by “Main_Quit” in XML, and “Main_Quit” is implemented by the Ada procedure Simple_Callbacks.Quit.
The logical connection is :
signal : GTKObject.destroy => Handler name : "Main_Quit" => Ada callback : Simple_Callbacks.Quit
Callback spec : simple_callbacks.ads
with Gtkada.Builder; use Gtkada.Builder; package Simple_Callbacks is procedure Quit (Object : access Gtkada_Builder_Record'Class); end Simple_Callbacks;
Callback body : simple_callbacks.adb
with Gtk.Main; package body Simple_Callbacks is procedure Quit (Object : access Gtkada_Builder_Record'Class) is pragma Unreferenced (Object); begin Gtk.Main.Main_Quit; end Quit; end Simple_Callbacks;
Main program : simple_glade3.adb
Read the XML description, register the termination handler, connect, start the Gtk.Main.Main loop, and that's it.
with Gtk; use Gtk; with Gtk.Main; use Gtk.Main; with Glib.Error; use Glib.Error; with Gtk.Widget; use Gtk.Widget; with Ada.Text_IO; with Gtkada.Builder; use Gtkada.Builder; -- the following package is user defined. with Simple_Callbacks; use Simple_Callbacks; procedure Simple_Glade3 is Builder : Gtkada_Builder; Error : Glib.Error.GError; begin Gtk.Main.Init; -- Step 1: create a Builder and add the XML data, Gtk_New (Builder); Error := Add_From_File (Builder, "simple.glade"); if Error /= null then Ada.Text_IO.Put_Line ("Error : " & Get_Message (Error)); Error_Free (Error); return; end if; -- Step 2: add calls to "Register_Handler" to associate your -- handlers with your callbacks. Register_Handler (Builder => Builder, Handler_Name => "Main_Quit", -- from XML file <signal handler=..> Handler => Simple_Callbacks.Quit'Access); -- Step 3: call Do_Connect. Once to connect all registered handlers Do_Connect (Builder); -- Find our main window, then display it and all of its children. Gtk.Widget.Show_All (Get_Widget (Builder, "main_window")); Gtk.Main.Main; -- Step 4: when the application terminates or all Windows described through -- your builder should be closed, call Unref to free memory -- associated with the Builder. Ada.Text_IO.Put_Line ("The demo is over"); Unref (Builder); end Simple_Glade3;
Project file : simple.gpr
with "gtkada"; project Simple is type Gtkada_Kind_Type is ("static", "relocatable"); Library_Type : Gtkada_Kind_Type := external ("LIBRARY_TYPE", "static"); for Source_Dirs use ("src"); for Object_Dir use "obj"; for Exec_Dir use "."; for Main use ("simple_glade3.adb"); package Builder is for Default_Switches ("ada") use ("-s"); end Builder; package Compiler is for Default_Switches ("ada") use ("-O2", "-gnat05"); end Compiler; package Linker is -- for Windows production only ;; remove for Linux / Mac / Win debug for Default_Switches ("ada") use ("-mwindows"); end Linker; end Simple;
The final result
Credits
This page was adapted from codes of Pascal Pignard in Utilisation de la bibliothèque graphique GTKAda (mai 2012) and a post of Brian Drummond from GTKAda archives. GtkAda builder example
More
Complete demo programs available from Sourceforge
- Lorenz chaotic attractor : Drawing demo with GTK timer loop.
- Julia set : GTK interface mixed with Ada tasking.
- For RAD, gate3 is an Ada code sketcher : you build the User Interface with glade3.8, and gate3 generates an Ada prototype that is a valid Ada code.