Copyright (C) 1998-1999, Emmanuel Briot, Joel Brobecker, Arnaud Charlet
This document may be copied, in whole or in part, in any form or by any means, as is or with alterations, provided that (1) alterations are clearly marked as alterations and (2) this copyright notice is included unmodified in any copy.
The home page for GtkAda, that will always contain the latest news for this binding, is
The home page for gtk is
This is GtkAda version 1.2.4. This package is an Ada95 graphical library for the Gimp Toolkit, which means this is a set of packages to allow you to easily create some graphical interfaces under X11 and Win32, using Ada95 as a programming language.
From now on, major version numbers will follow Gtk+ (e.g 1.2, 1.3),
meaning that stable versions of GtkAda will have major number 1.2 and
development versions will have number 1.3.
Every widget from gtk 1.2 has been implemented, and the test
program found in the gtk release has been reimplemented in Ada (have a
look at the testgtk/
directory).
This binding was tested on the following systems:
using the following compilers:
the following versions of gtk:
and the following versions of glade:
Although versions up to 0.2.1 were compatible with Gtk-1.0, this one is Gtk-1.2 specific. If you are looking for a binding to Gtk-1.0, please consider downloading GtkAda 0.2.1.
If you manage to use it on other systems (which should probably be straightforward - just recompile GtkAda), please let us know so that we can add to the above list.
This documentation is largely inspired from the Gtk+ documentation written by Ian Main and Tony Gale.
GtkAda uses extensively the object oriented programming capabilities, access to subprograms, exceptions and genericity (in particular to define and handle callbacks) provided by Ada 95. As a result, this library provides a secure, easy to use and extensible toolset.
A complete example of the use of GtkAda is provided at the end of this document.
To build and install GtkAda, simply do the following steps:
You then have to make sure that the dynamic library libgtkada
is known by your system, by typically running ldconfig
,
editing /etc/ld.conf
or add the path that contains libgtkada
(by default /usr/local/lib
, or $prefix/lib
if you specified
the --prefix
option during the configure step) to your
LD_LIBRARY_PATH
A script, gtkada-config
, is provided to simplify the build of an
application:
gnatmake <main-file> `gtkada-config`
There are three major libraries: GTK, GDK and GLIB. GTK is based on GDK and GLIB, GDK is based on GLIB and the underlying windowing library (X-Window or Win32).
+---------------------------------------------+ | Your Application | | +-----------------------------+ | | GTK | | +-------+-----------------------------+ | | GDK | +-------+--------------+--+-------------------+ | GLIB | | X-Window / Win32 | +----------------------+ +-------------------+
GTK is the interface you will use most, but it is sometimes needed to use directly GDK and GLIB.
The Gtk components (resp. Gdk and Glib) are available in packages whose
name start with Gtk_
(resp. Gdk_
and Glib
).
GtkAda uses an object oriented approach of the components (called `widget'), whose hierarchy is given in the following section.
The simple rule followed by GtkAda to implement each widget is the following:
Given a widget Gtk_Xxx
, its definition can be found in the package
Gtk.Xxx
in the file gtk-xxx.ads
.
For example, the Gtk_Text
type is defined in package
Gtk.Text
located in the file gtk-text.ads
.
Here is the complete hierarchy of Gtk widgets:
1 Gtk_Data 2 Gtk_Tooltips 2 Gtk_Adjustment 1 Gtk_Widget 2 Gtk_Calendar 2 Gtk_Container 3 Gtk_Bin 4 Gtk_Alignment 4 Gtk_Event_Box 4 Gtk_Frame 5 Gtk_Aspect_Frame 4 Gtk_Handle_Box 4 Gtk_Invisible 4 Gtk_Item 5 Gtk_List_Item 5 Gtk_Menu_Item 6 Gtk_Check_Menu_Item 7 Gtk_Radio_Menu_Item 6 Gtk_Tearoff_Menu_Item 5 Gtk_Tree_Item 4 Gtk_Viewport 4 Gtk_Window 5 Gtk_Color_Selection_Dialog 5 Gtk_Dialog 6 Gtk_Input_Dialog 5 Gtk_File_Selection 5 Gtk_Font_Selection_Dialog 5 Gtk_Plug 3 Gtk_Box 4 Gtk_Button_Box 5 Gtk_Vbutton_Box 5 Gtk_Hbutton_Box 4 Gtk_Color_Selection 4 Gtk_Combo 4 Gtk_Gamma_Curve 4 Gtk_Status_Bar 3 Gtk_Button 4 Gtk_Option_Menu 4 Gtk_Toggle_Button 5 Gtk_Check_Button 6 Gtk_Radio_Button 3 Gtk_Clist 4 Gtk_Ctree 3 Gtk_Fixed 3 Gtk_Layout 3 Gtk_List 3 Gtk_Menu_Shell 4 Gtk_Menu 4 Gtk_Menu_Bar 3 Gtk_Notebook 4 Gtk_Font_Selection 3 Gtk_Packer 3 Gtk_Paned 3 Gtk_Scrolled_Window 3 Gtk_Socket 3 Gtk_Toolbar 3 Gtk_Table 3 Gtk_Tree 2 Gtk_Drawing_Area 3 Gtk_Curve 2 Gtk_Editable 3 Gtk_Entry 4 Gtk_Spin_Button 3 Gtk_Text 2 Gtk_Misc 3 Gtk_Arrow 3 Gtk_Image 3 Gtk_Label 4 Gtk_Accel_Label 4 Gtk_Tips_Query 3 Gtk_Pixmap 2 Gtk_Preview 2 Gtk_Preview_Info 2 Gtk_Progress 3 Gtk_Progress_Bar 2 Gtk_Range 3 Gtk_Scale 3 Gtk_Scrollbar 2 Gtk_Ruler 2 Gtk_Separator
The number represents the type's depth in the hierarchy.
The almost full set of widget that comes with Gtk 1.2 has been bound, and you should be able to use all of these widgets from your Ada program.
Although it is not quite complete yet, the Gdk binding (the low level layer) will probably not evolve soon, unless some people (why not you?) send us patches, or at least ask for specific functions.
The specs have been evolving a lot since version 0.5, but things should really stabilize now. We hope that the changes in the next versions will not break existing code, but we certainly can not guaranty anything.
We have tried to adopt a consistent naming scheme for Ada identifiers:
Gtk_Button Gtk_Color_Selection_Dialog
gtk_
and the widget name, e.g
gtk_misc_set_padding -> Set_Padding gtk_toggle_button_set_state -> Set_State
WARNING: all the generic functions allocate some memory for internal structures. This memory is freed by gtk itself, by calling some Ada functions. Therefore the generic packages have to be instanciated at library level, not inside a subprogram, so that the functions are still defined when gtk needs to free the memory.
Typically, a window is created in which one can insert a box containing either:
Each component is a widget (Window Gadget), even the windows.
A signal is `emited' by a widget when an action is performed by the
user on this widget. If the widget has one or more procedures attached
to this signal, they are then executed.
Such procedure will be called callback
in this document.
To associate a callback to a widget, you have to connect this callback to
the specific widget, specifying which signal will be handled. This is
done with the Connect
function.
Depending on their type, the widgets can emit zero (e.g Gtk_Label
),
one or several different signals.
A signal is identified by a string, e.g
For a specific widget, you can connect several callbacks on the same signal. They will be executed in the order in which they have been connected.
One single callback can be connected several times on the same widget and even on different widgets.
The choice made by GtkAda to use generics may look complicated but is actually simple to use and more important, ensures type checking.
For example, you can connect to a Gtk_Button
an action to
execute each time the button is clicked (signal "clicked"
).
Here is how to do it:
declare Button : Gtk.Button.Gtk_Button; Cb_Id : Glib.Guint; begin Gtk.Button.Gtk_New (Button => Button, Label => "Load"); Cb_Id := Callbacks.Button_Callback.Connect ( Obj => Button, -- the emitting widget Name => "clicked", -- the generated signal Func => Callbacks.Load'Access); -- the signal handler end;
The package Button_Callback
is an instanciation of the
package Gtk.Signal.Void_Callback
with the type Gtk.Button.Gtk_Button
.
This package defines an access type to a procedure
Button_Callback.Callback
and the corresponding connect function
Button_Callback.Connect
.
The callbacks provided to this function have to respect the
Button_Callback.Callback
type. Below is an example of how to declare
this package.
with Gtk.Signal; with Gtk.Button; package Callbacks is -- Define callbacks that apply on the widget that detected the -- corresponding signal. -- These callbacks have only one parameter: the widget itself package Button_Callback is new Gtk.Signal.Void_Callback (Widget_Type => Gtk.Button.Gtk_Button_Record); -- Which is equivalent to: -- package Button_Callback is -- -- type Callback is access procedure -- (Widget : access Gtk.Button.Gtk_Button_Record); -- -- Definition of the Callback type -- -- function Connect -- (Obj : access Gtk.Button.Gtk_Button_Record'Class; -- Name : in String; -- Func : in Callback; -- After : in Boolean := False) -- return Guint; -- -- Connect a callback to a button -- -- end Button_Callback; procedure Load (Widget : access Gtk.Button.Gtk_Button_Record); -- The callback procedure end Callbacks;
Callbacks.Load
is a procedure that can be used to handle a signal
since its profile conforms with Button_Callback.Callback
.
Note that Callbacks
must be declared at the library level
to ensure its lifetime and the presence of its variables during the execution
of the application. This is needed so that GtkAda can take care of freeing
memory.
Although GtkAda tries to check whether you gave enough arguments to your callback handlers, it is of course easier if you know what gtk+ expects! The easiest way to find out is to look at the C header files. Each widget is described in its own C file, and has two C structures associated with it. One of them is the "class" structure, and contains a serie of pointers to functions. Each of these functions has the same name as the signal name, and the arguments are the one that are expected in the handlers.
For instance, consider the following extract from gtkbutton.h:
struct _GtkButtonClass { GtkBinClass parent_class; void (* pressed) (GtkButton *button); void (* released) (GtkButton *button); void (* clicked) (GtkButton *button); void (* enter) (GtkButton *button); void (* leave) (GtkButton *button); };
This means that the Gtk_Button widget redefines five new signals, called
respectively "pressed"
, "release"
, ...
Each of them expects a handler looking like:
procedure Pressed_Handler (Button : access Gtk_Button_Record; Data : ...);
The type of Data is given by one of the generic parameters to the packages in Gtk.Signal.
For more information on how signals work, we recommand having a look at the book [1].
You need to perform some initializations to start a GtkAda application:
-- predefined units of the library with Gtk.Rc; with Gtk.Main; with Gtk.Enums; with Gtk.Window; ... -- My units with Callbacks; ... procedure Application is procedure Create_Window is ... begin -- Set the locale specific datas (e.g time and date format) Gtk.Main.Set_Locale; -- Initializes GtkAda Gtk.Main.Init; -- Load the resources Gtk.Rc.Parse ("application.rc"); -- Create the main window Create_Window; -- Signal handling loop Gtk.Main.Main; end Application;
the Create_Window
procedure looks like
procedure Create_Window is Main_Window : Gtk.Window.Gtk_Window; ... begin Gtk.Window.Gtk_New (Window => Main_Window, The_Type => Gtk.Enums.Window_Toplevel); -- From Gtk.Widget: Gtk.Window.Set_Title (Window => Main_Window, Title => "Editor"); -- Construct the window and connect various callbacks ... Gtk.Window.Show_All (Main_Window); end Create_Window;
This section describes briefly how to use the GTK toolset. This is largely inspired from the GTK+ documentation. It is recommended that you read this documentation for all general GTK topics.
The GTK toolkit is based on two lower level layers: GDK and Glib. It is sometimes needed to call these layers directly. See section Description of the GDK hierarchy for a brief description of these packages.
Each widget is declared in a separate package. The file, package and
type names can be automatically retrieved from one another. For example,
the type Gtk_Text
is defined in the package Gtk.Text
which
is defined in the file gtk-text.ads
.
You may want to look at the sources themselves to find informations on a specific widget.
These procedures are described in the order in which they should be called:
Set_Locale
must be called first. It sets the various datas specific to
your location, e.g time, date, decimal formats.
procedure Set_Locale;
Init
initializes the Gtk engine. Among other things, it
parses the arguments provided on the command line.
procedure Init;
procedure Main;
procedure Main_Quit;
This section describes three of the generic packages provided by
Gtk.Signal
.
You can connect as many callback per signal and widgets as needed.
For a given widget and signal, the various callbacks will be executed
in the order in which they have been connected.
On the other hand, a same callback routine can be connected to several
widgets and signals.
The Connect
function returns an integer (Glib.Guint
) that
identifies the connection, allowing you to destroy it later by giving
this identifier and the appropriate widget.
It is also possible to destroy all the connections to a widget.
The first package (Void_Callback
) provides a way to create callbacks
that have no specific parameter other than the emitting widget:
generic type Base_Type is new Gtk.Object.Gtk_Object_Record with private; package Void_Callback is type Callback is access procedure (Widget : access Base_Type); function Connect (Obj : access Base_Type'Class; Name : in String; Func : in Callback; After : in Boolean := False) return Guint; end Void_Callback;
The callback procedure that can be connected with the Connect
function
must follow the profile defined by the Callback
type.
The object parameter will be the widget that emitted the signal.
For the Connect
function, the parameters are:
"clicked", "destroy", "delete_event"
, ...),
The second package (Callback
) whose callbacks accept an additional
data dynamically allocated during the call to Connect
and whose
initial value is set by the Func_Data
parameter
generic type Base_Type is new Gtk.Object.Gtk_Object_Record with private; type Data_Type (<>) is private; -- The type of the data for the callback -- This type need not be an access type (as opposed as what -- happens in C). A new access is created by the connect function. package Callback is type Callback is access procedure (Widget : access Base_Type; Data : in Data_Type); -- Callback function for Signal_Connect below function Connect (Obj : access Base_Type'Class; Name : in String; Func : in Callback; Func_Data : in Data_Type; After : in Boolean := False) return Guint; end Callback;
The last package Object_Callback
provides callbacks that can be connected to any kind of widget.
(the Obj
parameter can be any kind of object),
but the callback parameter, as for previous packages will still have to
be the same as the one specified during the instanciation.
At run time, the callback will get the widget parameter
Slot_Object
that has been given to Connect
.
This is for example useful when you need to handle a button click depending on the window that contains the button instead of the button itself.
generic type Base_Type is new Gtk.Object.Gtk_Object_Record with private; package Object_Callback is type Callback is access procedure (Object : access Base_Type); function Connect (Obj : access Gtk.Object.Gtk_Object_Record'Class; Name : in String; Func : in Callback; Slot_Object : access Base_Type'Class; After : in Boolean := False) return Guint; end Object_Callback;
Here a sample code extracted from a text editor that corresponds to the
text loading operation.
The Callbacks.Load
procedure is a callback executed when the user
clicks on the "Load" button. This callback will create the file selection
window (Gtk_File_Selection
) and make it modal to force the user to
select a file before continuing to work.
When the user clicks on the "Ok" button of the file selection window,
the Callbacks.Ok
procedure is called with the parameter selection
window.
with Gtk.Button; package Callbacks is procedure Load (Widget : in out Gtk.Button.Gtk_Button); -- Callback for the ``Load'' button of the text editor end Callbacks; with Gtk.Signal, Gtk.Window, Gtk.Main; with Gtk.Widget, Gtk.File_Selection, Glib; with Editor; package body Callbacks is package Files_Cb is new Gtk.Signal.Object_Callback (Gtk.File_Selection.Gtk_File_Selection); -- A callback of type File_Cb.Callback corresponding to the -- Cancel button of the file selection window. procedure Cancel (Files : access Gtk.File_Selection.Gtk_File_Selection_Record) is begin -- Hide the file selection window Gtk.File_Selection.Hide (Files); -- This window is no longer modal Gtk.Main.Grab_Remove (Files); end Cancel; -- A callback of type File_Cb.Callback corresponding to the ``OK'' -- button of the file selection window. procedure Ok (Files : access Gtk.File_Selection.Gtk_File_Selection_Record) is begin Editor.Load (Gtk.File_Selection.Get_Filename (Files)); Gtk.File_Selection.Hide (Files); Gtk.Main.Grab_Remove (Files); end Ok; -- Internal procedure to initialize a Gtk_File_Selection procedure Initialize_File_Selection (Files : access Gtk.File_Selection.Gtk_File_Selection_Record; Label : String; OK_CB : Files_Cb.Callback) is Cb_Id : Glib.Guint; begin Gtk.File_Selection.Gtk_New (Files, Label); -- Hide the create/remove buttons Gtk.File_Selection.Hide_Fileop_Buttons (Files); Cb_Id := Files_Cb.Connect ( Obj => Gtk.File_Selection.Get_Ok_Button (Files), -- The signal applies to the OK button Name => "clicked", -- Event to detect Func => OK_CB, -- Callback procedure Slot_Object => Files); -- Parameter given to the callback Cb_Id := Files_Cb.Connect ( Obj => Gtk.File_Selection.Get_Cancel_Button (Files), Name => "clicked", Func => Cancel'access, Slot_Object => Files); end Initialize_File_Selection; -- The file selection window Input_File_Sel : Gtk.File_Selection.Gtk_File_Selection; Input_File_Sel_Existe : Boolean := False; -- The ``Load'' callback body procedure Load (Widget : access Gtk.Button.Gtk_Button_Record) is begin if not Input_File_Sel_Existe then Initialize_File_Selection (Input_File_Sel, "File to load ?", OK'Access); Input_File_Sel_Existe := True; end if; Gtk.Main.Grab_Add (Input_File_Sel); -- Show the file selection window Gtk.File_Selection.Show (Input_File_Sel); end Load; end Callbacks;
Two procedures to destroy a specific or any connection.
procedure Disconnect (Object : access Gtk.Object.Gtk_Object_Record'Class; Handler_Id : in Guint); procedure Handlers_Destroy (Obj : access Object.Gtk_Object_Record'Class);
type Gtk_Tooltips_Record is new Gtk.Data.Gtk_Data_Record with private; type Gtk_Tooltips is access all Gtk_Tooltips_Record'Class;
The message hint that pops up in a little window when the mouse stay on a widget long enough without moving.
type Gtk_Adjustment_Record is new Data.Gtk_Data_Record with private; type Gtk_Adjustment is access all Gtk_Adjustment_Record'Class;
These objects allow you to create a link between a scrollbar and a scrollable widget (text, scrolled_window).
type Gtk_Widget_Record is new Object.Gtk_Object_Record with null record; type Gtk_Widget is access all Gtk_Widget_Record'Class;
Root of the widget tree. Here are a few useful primitives that are inherited by all the widgets.
procedure Destroy (Widget : access Gtk_Widget_Record);
procedure Set_Name (Widget : access Gtk_Widget_Record; Name : in String);
Widget
is displayed
procedure Show (Widget : access Gtk_Widget_Record);
Widget
and its child widgets are displayed
procedure Show_All (Widget : access Gtk_Widget_Record);
Widget
.
procedure Hide (Widget : access Gtk_Widget_Record);
Gdk.Color.White
)
function Get_Colormap (Widget : access Gtk_Widget_Record) return Gdk_Colormap; function Get_Default_Colormap return Gdk_Colormap; procedure Set_Default_Colormap (Widget : access Gtk_Widget_Record; Cmap : Gdk_Colormap);
procedure Realize (Widget : access Gtk_Widget_Record); procedure Unrealize (Widget : access Gtk_Widget_Record); function Realized_Is_Set (Widget : access Gtk_Widget_Record'Class) return Boolean;You need to use
Realize
when for example you want to insert text in a
Gtk_Text
before calling Show
.
procedure Set_Sensitive (Widget : access Gtk_Widget_Record; Sensitive : in Boolean := True);
Set_Sensitive
can be used to temporarily disable a button or a
container. When it is not sensitive, its visual aspect changes.
function Toplevel_Is_Set (Widget : access Gtk_Widget_Record'Class) return Boolean;
function Get_Parent (Widget : access Gtk_Widget_Record) return Gtk_Widget;
Gdk_Window
) associated with a widget:
function Get_Window (Widget : access Gtk_Widget_Record) return Gdk.Window.Gdk_Window;
type Gtk_Label_Record is new Misc.Gtk_Misc_Record with private; type Gtk_Label is access all Gtk_Label_Record'Class;
To display and then modify a simple string.
A Gtk_Label
can emit no signal (see Event_Box
if you want to
connect a signal)
Create a new label
procedure Gtk_New (Label : out Gtk_Label; Str : in String);
Change the label string
procedure Set_Text (Label : access Gtk_Label_Record; Str : in String);
type Gtk_Scrollbar_Record is new Gtk.GRange.Gtk_Range_Record with private; type Gtk_Scrollbar is access all Gtk_Scrollbar_Record'Class;
Horizontal or vertical scrollbars that can be associated with the
Widget
you want to scroll using
Adjustment
(see, eg Gtk.Text.Get_Vadj
).
procedure Gtk_New_Hscrollbar (Widget : out Gtk_Scrollbar; Adjustment : in Gtk.Adjustment.Gtk_Adjustment); procedure Gtk_New_Vscrollbar (Widget : out Gtk_Scrollbar; Adjustment : in Gtk.Adjustment.Gtk_Adjustment);
type Gtk_Drawing_Area_Record is new Gtk.Widget.Gtk_Widget_Record with private; type Gtk_Drawing_Area is access all Gtk_Drawing_Area_Record'Class; procedure Gtk_New (Widget : out Gtk_Drawing_Area); procedure Size (Darea : access Gtk_Drawing_Area_Record; Width : in Glib.Gint; Height : in Glib.Gint);
You can get the Gdk_Window
associated with a widget to draw in it
using the GDK primitives of Gdk_Drawable
which is a subtype
of Gdk_Window
, see the GDK section.
This window exists only when the widget is actually realized, e.g after the
call to Realize
or Show
of the Gtk_Drawing_Area
.
It is possible to draw in the initialization procedure after the procedure
Show
or when the Gtk.Main.Main
loop is running,
on the "configure_event"
signal.
A Gtk_Drawing_Area
is a very low level object,
in particular when it is hidden by another window and then exposed, it
is not redrawn automatically. It is up to the application to handle the
expose event, by connecting a callback on the
"expose_event"
signal.
To manipulate text.
type Gtk_Text_Record is new Gtk.Editable.Gtk_Editable_Record with private; type Gtk_Text is access all Gtk_Text_Record'Class;
End of line are marked by a Ascii.LF
. When the application
modifies the text (using, e.g Insert
), it can first freeze it
(Freeze
) to prevent any change from the user and any automatic
update of the display, then unfreeze it (Thaw
) to allow the user
to interact again.
procedure Gtk_New (Widget : out Gtk_Text; Hadj : access Gtk.Adjustment.Gtk_Adjustment_Record'Class := Gtk.Adjustment.Null_Adjustment; Vadj : access Gtk.Adjustment.Gtk_Adjustment_Record'Class := Gtk.Adjustment.Null_Adjustment); procedure Freeze (Text : access Gtk_Text_Record); procedure Thaw (Text : access Gtk_Text_Record); function Get_Hadj (Widget : access Gtk_Text_Record) return Gtk.Adjustment.Gtk_Adjustment; function Get_Vadj (Widget : access Gtk_Text_Record) return Gtk.Adjustment.Gtk_Adjustment; function Get_Length (Text : in Gtk_Text) return Guint; procedure Insert (Text : access Gtk_Text_Record; Font : in Gdk.Font.Gdk_Font'Class; Fore : in Gdk.Color.Gdk_Color; Back : in Gdk.Color.Gdk_Color; Chars : in String; Length : in Gint);
By default, the text shown is not modifiable by the user. To change this,
use the Set_Editable
procedure:
procedure Set_Editable (Text : access Gtk_Text_Record; Editable : in Boolean);
To avoid cutting words at the end of a line:
procedure Set_Word_Wrap (Text : access Gtk_Text_Record; Word_Wrap : in Boolean);
Also inherits primitives from Gtk.Editable.Gtk_Editable
:
procedure Delete_Text (Editable : access Gtk_Editable_Record; Start_Pos : in Gint; End_Pos : in Gint); -- e.g Glib.Gint (Get_Length (...))
function Get_Current_Pos (Widget : access Gtk_Editable_Record) return Guint;
type Gtk_Container_Record is new Gtk.Widget.Gtk_Widget_Record with private; type Gtk_Container is access all Gtk_Container_Record'Class;
General notion that permits to create a hierarchical structure of widgets, such
as Gtk_Box, Gtk_Table, Gtk_EventBox
, ...
To add/remove a widget in a Gtk_Container
:
procedure Add (Container : access Gtk_Container_Record; Widget : access Gtk.Widget.Gtk_Widget_Record'Class); procedure Remove (Container : access Gtk_Container_Record; Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
The procedures Pack_Start
and Pack_End
of Gtk_Box
and
Attach
of Gtk_Table
let you add widgets and specify their
position.
To set the width of the border around the Gtk_Container
:
procedure Border_Width (Container : access Gtk_Container_Record; Border_Width : in Gint);
type Gtk_Table_Record is new Gtk.Container.Gtk_Container_Record with private; type Gtk_Table is access all Gtk_Table_Record'Class;
To group widgets in a table. The same widget can cover several boxes of the table. The size of the boxes depends on what they contain.
procedure Gtk_New (Widget : out Gtk_Table; Rows : in Glib.Gint; Columns : in Glib.Gint; Homogeneous : in Boolean);
If Homogeneous
is True, all the boxes will have the same size, determined
by the largest widget and the longest widget.
Otherwise, the width of a column (resp. heigh of a row) will be determined
by the largest widget of the column.
To attach a widget to a table
procedure Attach (Table : access Gtk_Table_Record; Child : access Gtk.Widget.Gtk_Widget_Record'Class; Left_Attach : in Gint; Right_Attach : in Gint; Top_Attach : in Gint; Bottom_Attach : in Gint; Xoptions : in Gtk_Attach_Options; Yoptions : in Gtk_Attach_Options; Xpadding : in Gint; Ypadding : in Gint); procedure Attach_Defaults (Table : access Gtk_Table_Record; Widget : access Gtk.Widget.Gtk_Widget_Record'Class; Left_Attach : in Gint; Right_Attach : in Gint; Top_Attach : in Gint; Bottom_Attach : in Gint);
Attach the widget Child
to the position indicated by
Left_Attach, Right_Attach, Top_Attach
and
Bottom_Attach
.
These indexes start from 0 to the number of column or rows specified at
table creation. The origin (0, 0) of the frontiers is located in upper left.
0 1 2 0+----------+----------+ | | | 1+----------+----------+ | | | 2+----------+----------+
The values of Xoptions
and Yoptions
can be a logical or of
several values:
Xpadding
and Ypadding
give the widths in pixels of the
free space reserved around the widget.
For the Attach_Defaults
procedure, the default values of Xoptions
and Yoptions
are equals to Expand or Fill
and those of
Xpadding
and Ypadding
are 0.
type Gtk_Scrolled_Window_Record is new Container.Gtk_Container_Record with private; type Gtk_Scrolled_Window is access all Gtk_Scrolled_Window_Record'Class;
To create a scrollable zone in which you can put any kind of widget, like e.g a table of buttons. If the window is too small, all the widgets won't be visible, but they will remain accessible using the scrollbars.
procedure Gtk_New (Scrolled_Window : out Gtk_Scrolled_Window; Hadjustment : access Adjustment.Gtk_Adjustment_Record'Class := Adjustment.Null_Adjustment; Vadjustment : access Adjustment.Gtk_Adjustment_Record'Class := Adjustment.Null_Adjustment);
Create a Gtk_Scrolled_Window
by optionally specifying adjustment rules.
To get the adjustment rules (to attach scrollbars).
function Get_Hadjustment (Scrolled_Window : access Gtk_Scrolled_Window_Record) return Adjustment.Gtk_Adjustment; function Get_Vadjustment (Scrolled_Window : access Gtk_Scrolled_Window_Record) return Adjustment.Gtk_Adjustment;
type Gtk_Notebook_Record is new Gtk.Container.Gtk_Container_Record with private; type Gtk_Notebook is access all Gtk_Notebook_Record'Class;
The NoteBook Widget is a collection of pages that overlap each other, each page containing different information. This widget has become more common lately in GUI programming, and it is a good way to show blocks of similar information that warrant separation in their display.
type Gtk_Box_Record is new Gtk.Container.Gtk_Container_Record with private; type Gtk_Box is access all Gtk_Box_Record'Class; subtype Gtk_Vbox is Gtk_Box; subtype Gtk_Hbox is Gtk_Box;
Horizontal (Gtk_New_Hbox
) and vertical (Gtk_New_Vbox
) boxes
that can contain several widgets.
you can add widgets from
Pack_Start
)
Pack_End
)
procedure Gtk_New_Vbox (Box : in out Gtk_Box; Homogeneous : in Boolean; Spacing : in Gint); procedure Initialize_Vbox (Box : access Gtk_Box_Record'Class; Homogeneous : in Boolean; Spacing : in Gint); procedure Gtk_New_Hbox (Box : in out Gtk_Box; Homogeneous : in Boolean; Spacing : in Gint); procedure Initialize_Hbox (Box : access Gtk_Box_Record'Class; Homogeneous : in Boolean; Spacing : in Gint); procedure Pack_Start (In_Box : access Gtk_Box_Record; Child : access Gtk.Widget.Gtk_Widget_Record'Class; Expand : in Boolean := True; Fill : in Boolean := True; Padding : in Gint := 0); procedure Pack_End (In_Box : access Gtk_Box_Record; Child : access Gtk.Widget.Gtk_Widget_Record'Class; Expand : in Boolean := True; Fill : in Boolean := True; Padding : in Gint := 0);
See section Package Gtk.Table
type Gtk_Button_Record is new Bin.Gtk_Bin_Record with private; type Gtk_Button is access all Gtk_Button_Record'Class;
A simple button with a label and signals (e.g clicked
).
type Gtk_Toggle_Button_Record is new Gtk.Button.Gtk_Button_Record with private; type Gtk_Toggle_Button is access all Gtk_Toggle_Button_Record'Class;
Toggle buttons are very similar to normal buttons, except they will always be in one of two states, alternated by a click. They may be depressed, and when you click again, they will pop back up. Click again, and they will pop back down.
type Gtk_Check_Button_Record is new Toggle_Button.Gtk_Toggle_Button_Record with private; type Gtk_Check_Button is access all Gtk_Check_Button_Record'Class;
Check buttons inherit many properties and functions from the the toggle buttons above, but look a little different. Rather than being buttons with text inside them, they are small squares with the text to the right of them. These are often seen for toggling options on and off in applications.
type Gtk_Event_Box_Record is new Gtk.Bin.Gtk_Bin_Record with private; type Gtk_Event_Box is access all Gtk_Event_Box_Record'Class;
To associate a callback or clip a widget that is not able to do it, like labels for example. Note that this container can have only one child.
procedure Gtk_New (Widget : out Gtk_Event_Box);
This widget is a child of Gtk_Container
and inherits in particular of:
procedure Add (Container : access Gtk_Container_Record; Widget : access Gtk.Widget.Gtk_Widget_Record'Class);
type Gtk_Window_Record is new Bin.Gtk_Bin_Record with private; type Gtk_Window is access all Gtk_Window_Record'Class;
The base window, emits the signals "destroy", "delete_event"
.
type Gtk_File_Selection_Record is new Gtk.Window.Gtk_Window_Record with private; type Gtk_File_Selection is access all Gtk_File_Selection_Record'Class;
To select a file in the directories tree. Nothing special to know about
it, just use it!
There are three buttons Ok, Cancel and Help
.
You can modify these buttons (e.g change the labels, connect callbacks, ...)
with the various Get_..._Button
functions.
procedure Gtk_New (File_Selection : out Gtk_File_Selection; Title : in String);
To associate a callback with the buttons of the file selector:
function Get_Ok_Button (File_Selection : access Gtk_File_Selection_Record) return Gtk.Button.Gtk_Button; function Get_Cancel_Button (File_Selection : access Gtk_File_Selection_Record) return Gtk.Button.Gtk_Button;
To consult or set the filename:
function Get_Filename (File_Selection : access Gtk_File_Selection_Record) return String; procedure Set_Filename (File_Selection : access Gtk_File_Selection_Record; Filename : in String);
To hide the file manipulation buttons (destruction, ...):
procedure Hide_Fileop_Buttons (File_Selection : access Gtk_File_Selection_Record);
This package defines all the enumerated types used by the GTK hierarchy.
GTK is based on a lower level layer called GDK that contains some simple drawing and window primitives.
Color types and table of colors:
type Gdk_Color is private; type Gdk_Colormap is new Root_Type with private;
Allows one to get black and white colors by asking the
Gdk_Colormap
of a widget:
function White (Colormap : in Gdk_Colormap) return Gdk_Color; function Black (Colormap : in Gdk_Colormap) return Gdk_Color; Wrong_Color : exception;
See for example Get_Default_Colormap
.
You can of course create your own colors (provided your screen can display them), by calling the following functions :
declare Color : Gdk_Color; Name : String := "brown"; -- the name of the color to be created begin -- First, create a color from its name Color := Gdk.Color.Parse (Name); Gdk.Color.Alloc (Gtk.Widget.Get_Default_Colormap, Color); -- Or create a color from its values Gdk.Color.Set_Rgb (Color, Red => 20000, Green => 20000, Blue => 65500); Gdk.Color.Alloc (Gtk.Widget.Get_Default_Colormap, Color); end;
type Gdk_Point is private;
Used to describe polygons.
type Gdk_Points_Array is array (Positive range <>) of Gdk_Point; function Get_X (Point : in Gdk_Point) return Glib.Gint16; function Get_Y (Point : in Gdk_Point) return Glib.Gint16; procedure Set_X (Point : in out Gdk_Point; X : Glib.Gint16); procedure Set_Y (Point : in out Gdk_Point; Y : Glib.Gint16);
type Gdk_Window is new Root_Type with private;
To clear a window (e.g before drawing ):
procedure Clear (Window : in out Gdk_Window);
subtype Gdk_Drawable is Gdk.Window.Gdk_Window;
procedure Draw_Rectangle (Drawable : in Gdk_Drawable'Class; Gc : in Gdk.GC.Gdk_GC'Class; Filled : in Boolean := False; X : in Gint; Y : in Gint; Width : in Gint; Height : in Gint); procedure Draw_Point (Drawable : in Gdk_Drawable'Class; Gc : in Gdk.GC.Gdk_GC'Class; X : in Gint; Y : in Gint); procedure Draw_Line (Drawable : in Gdk_Drawable'Class; procedure Draw_Line (Drawable : in Gdk_Drawable'Class; Gc : in Gdk.GC.Gdk_GC'Class; X1 : in Gint; Y1 : in Gint; X2 : in Gint; Y2 : in Gint); procedure Draw_Arc (Drawable : in Gdk_Drawable'Class; Gc : in Gdk.GC.Gdk_GC'Class; Filled : in Boolean := False; X : in Gint; Y : in Gint; Width : in Gint; Height : in Gint; Angle1 : in Gint; Angle2 : in Gint); procedure Draw_Polygon (Drawable : in Gdk_Drawable'Class; Gc : in Gdk.GC.Gdk_GC'Class; Filled : in Boolean; Points : in Gdk.Point.Gdk_Points_Array); procedure Draw_Text (Drawable : in Gdk_Drawable'Class; Font : in Gdk.Font.Gdk_Font; Gc : in Gdk.GC.Gdk_GC; X : in Glib.Gint; Y : in Glib.Gint; Text : in String);
for all the procedures (in particular Draw_Arc
), the parameters are:
Gdk.Font.Load
.
For example:
Gdk.Font.Load (Font, "-adobe-courier-medium-i-*-*-15-*-*-*-*-*-*-*");
A Gdk_GC
is a graphic context that must be associated, during its
creation, with a Gdk_Window
, and which is needed for each drawing
primitive of Gdk_Drawable
.
A Gdk_GC
let you, for example, set the colors to use for a drawing.
type Gdk_GC is new Root_Type with private; procedure Gdk_New (GC : out Gdk_GC; Window : in Gdk.Window.Gdk_Window'Class); procedure Destroy (GC : in out Gdk_GC); procedure Set_Foreground (GC : in out Gdk_GC; Color : in Gdk.Color.Gdk_Color); procedure Set_Background (GC : in out Gdk_GC; Color : in Gdk.Color.Gdk_Color); procedure Set_Font (GC : in out Gdk_GC; Font : in Gdk.Font.Gdk_Font'Class);
A font describes the graphical aspect of the characters, their size, kind, ....
Under X11
, each font has a name of the form:
"-adobe-courier-medium-i-*-*-15-*-*-*-*-*-*-*"
The X command xfontsel
lets you select a font and build its associated
name automatically.
type Gdk_Font is new Root_Type with private; procedure Load (Font : out Gdk_Font; Font_Name : in String); procedure Fontset_Load (Font : out Gdk_Font; Fontset_Name : in String); function Id (Font : in Gdk_Font) return Gint; function "=" (Fonta, Fontb : in Gdk_Font) return Boolean; function String_Width (Font : in Gdk_Font; Str : in String) return Gint; function Text_Width (Font : in Gdk_Font; Text : in String) return Gint; function Char_Width (Font : in Gdk_Font; Char : in Character) return Gint; function String_Measure (Font : in Gdk_Font; Str : in String) return Gint; function Text_Measure (Font : in Gdk_Font; Text : in String) return Gint; function Char_Measure (Font : in Gdk_Font; Char : in Character) return Gint;
Width
gives the sum of the characters' widths,
Measure
gives a value similar to Width
except that it takes
into account the attributes of the font (e.g italic
).
To select a drawing area, use a Gtk_Drawing_Area
widget.
The drawing procedures apply to the Gdk window
(see Gdk_Window
and Gdk_Drawable
) of the
Gtk_Drawing_Area
widget via a graphic context (see Gtk_Gc
).
Typically the code will look like:
with Glib; with Gdk.Window; with Gdk.Drawable; with Gdk.GC; with Gdk.Font; procedure Draw (Drawing : in out Gtk.Drawing_Area.Gtk_Drawing_Area) is Gdkw : Gdk.Window.Gdk_Window; GC : Gdk.GC.Gdk_GC; Font : Gdk.Font.Gdk_Font; use type Glib.Gint; begin -- Get the Gdk window Gdkw := Gtk.Drawing_Area.Get_Window (Drawing) ; -- Clear the window GDK.Window.Clear (Gdkw) ; -- Create a graphic context associated with this window Gdk.GC.Gdk_New (GC, Gdkw); -- Draw a line in this window Gdk.Drawable.Draw_Line (Drawable => Gdkw, GC => GC, X1 => 0, Y1 => 0, X2 => 100, Y2 => 100); -- Draw an arc Gdk.Drawable.Draw_Arc (Drawable => Gdkw, Gc => gc, Filled => True, X => 100, Y => 100, Width => 200, Height => 100, Angle1 => 0 * 64, Angle2 => 270 * 64); -- Ask for a given font Gdk.Font.Load (Font, "-adobe-courier-medium-i-*-*-15-*-*-*-*-*-*-*"); Gdk.Drawable.Draw_Text (Drawable => Gdkw, Font => Font, Gc => gc, X => 50, Y => 50, Text => "Hello World"); Gdk.Font.Destroy (Font); Gdk.GC.Destroy (GC); end Draw;
Glib is the low-level layer and provides various types such as
Gint, Guint
, ....
It also provides access to lists and double-linked lists. Some functions in GtkAda return lists of Widgets or lists of integer, so it might be useful to know how to traverse the list.
Here are the functions available (note that the packages in Glib are generics that you need to instanciate first).
function First (List : in out Glist); function Next (List : in Glist) return Glist; function Last (List : in Glist) return Glist;
These three functions allow you to traverse the list: get the first
element, then loop while the current element is different from Last.
For instance, here is how you would get the selection in a
Gtk_List
widget:
declare use type Widget_List.Glist; Selection : Widget_List.Glist := Gtk.List.Get_Selection (Widget); Current : Widget_List.Glist := Widget_List.First (Selection); Item : Gtk_Widget; begin while Current /= Widget_List.Last (Selection) loop Item := Widget_List.Get_Data (Current); -- use Item however you want Current := Widget_List.Next (Current); end loop; end;
Resource files let you parametrize the aspect of the widgets of a GtkAda application without having to recompile it.
A resource file needs to be loaded (Gtk.Rc.Parse
) before setting
the corresponding window.
In this file, it is possible to specify the visual characteristics of the
widgets (colors, fonts, ...).
Under X, the xfontsel
command allows you to easily select a font.
The FontSelection widget is also a simple way to select fonts.
Here is an example of a resource file:
# application.rc # # resource file for "Application" # Buttons style style "button" { # BackGround Colors # Red Green Blue bg[PRELIGHT] = { 0.0, 0.75, 0.0 } # Green when the mouse is on # the button bg[ACTIVE] = { 0.75, 0.0, 0.0 } # Red on click # ForeGround Colors # Red Green Blue fg[PRELIGHT] = { 1.0, 1.0, 1.0 } # White when the mouse is on # the button fg[ACTIVE] = { 1.0, 1.0, 1.0 } # White on click } # All the buttons will have the style "button" widget_class "*GtkButton*" style "button" # Text style style "text" { font = "-adobe-courier-medium-r-normal-*-15-*-*-*-*-*-*-*" text[NORMAL] = { 0.0, 0.0, 0.0 } # black fg[NORMAL] = { 0.0, 0.0, 0.0 } # black base[NORMAL] = { 1.0, 1.0, 1.0 } # white : background color } # All Gtk_Text will have the "text" style widget_class "*GtkText" style "text"
New since version 0.6, GtkAda has now a basic support for creating new widgets directly in Ada (although you can't create your own signals yet, we are still working on it).
Since GtkAda has an object oriented conception (well, at least you can
program by extension), it is easy, if you want to associate your
own data with a widget, to create your own type. See the
examples below. You should also have a look at the testgtk/
directory.
We provide a Perl script to help you create a binding to a C widget (this is the script we have used ourselves). This will not fully automate the process, although it should really speed things up. You will probably need less than 15 min to create a new binding once you will get used to the way GtkAda works. Note that your C file should have the same format as the one used by Gtk+ itself, as far as indentation and style are concerned.
Here are the steps to create a new binding:
generate.pl
script the C header file
$ perl generate.pl ../include/gtk/gtkbutton.h > temporary Create a function for the field child (of type GtkWidget*) [n]? Create a function for the field in_button (of type guint) [n]? Create a function for the field button_down (of type guint) [n]?
$ gnatchop temporaryThis should create two Ada files (specification and body)
The 1.2 series of Gtk+ are now thread safe. The usage of tasks inside programs using this toolkit should not cause any problem provided that you protect your Gtk calls with Gdk.Threads.Enter/ Leave and that your windowing system (e.g X) is thread-safe.
We recommend however that you read the section related to this topic in the GTK+ documentation.
This library is still considered beta code, and it is thus likely that you will find bugs. We have tried to test it as much as possible, essentially by converting the testgtk.c file found in the gtk distribution. We have been able to rewrite nearly all the tests. Please have a look at the testgtk, which can give you a lot of examples of how to use this toolkit.
For more general questions about gtk itself, please ask your questions to the gtk mailing list. The authors of this toolkit are far from being specialists of gtk, as it was one of our first projects with gtk.
There are two kinds of problems you can encounter:
g_log
. Then run your program as usual,
using the run
command. Then send us the result of the where
command. Here is a summary:
$ gnatmake -f -g <your_program_name> `gtkada-config` $ gdb <your_program_name> (gdb) break main (gdb) run (gdb) break g_log (gdb) continue .... (gdb) where
To report errors, if you are a supported user of GNAT, send a mail to
mailto:report@gnat.com, otherwise send a mail to the authors
(mailto:gtkada@ada.eu.org) explaining exactly what your
are doing, what is the expected result and what you actually
get. Please include the required sources to reproduce the problem, in
a format usable by gnatchop
(basically, insert all the required
sources at the end of the mail). Please try to provide a subset of
your sources as small as possible.
Of course, we will welcome any patch you can provide, so that this toolkit is as useful as possible.
GtkAda has been designed from the beginning to provide a full Object oriented layer over gtk+. This means that features such as type extension, dynamic dispatching, ... are made available through the standard Ada language.
This section will describe both how things work and how you can extend existing widgets or even create your own.
Every widget in GtkAda is a tagged type, which has a number of primitive subprograms, that are known by all its children.
This means that, as opposed to what you see in C code, you don't have (well most of the time you don't) to explictly cast types, and even when you have to, Ada always makes sure that the conversion is valid.
Thus your programs are much safer, and most errors are found at compile time, as is usually the case with Ada.
For instance, if you create a table, put some widgets in it, and then, later in your program, try to access these widgets, then you do not need to know beforehand what their type is, when and by whom they were created, ... You simply ask for the children of the table, and you get in return a tagged type that contains all the information you need. You can even use dynamic dispatching without ever having to cast to a known type.
This makes GtkAda a very powerful tool for designing graphical interfaces.
If you think one of the standard widgets is nice, but would be even better if it was drawing itself in a slighlty different way, of if it could contain some other data that you need in your application, there is a very simple way to do it: just create a new type that extends the current one (see the section See section Using tagged types to extend Gtk widgets below.
Maybe you want to create your own brand new widget, that knows how to draw itself, how to react to events, ... and you want to be able to reuse it anytime you need ? Once again, using the standard Ada features, you can simply create a new tagged type and teach it how to interact with the user. See the section See section Creating new widgets in Ada below.
There are basically three kinds of widgets that you can use with GtkAda:
GtkAda will always be able to find and/or create a valid tagged type in the first case, no matter if you explicitly created the widget or if it was created automatically by gtk+. For instance, if you created a widget in Ada, put it in a table, and later on extracted it from the table, then you will still have the same widget.
The second case above is twofold: if the widget was explictly created by you, or at least by GtkAda, then it will always be and remain associated with a correct Ada type.
However, if the widget was created implicitly (for instance every time you create a Gtk_Button, a Gtk_Label is also created for the text displayed), then GtkAda is not, by default, able to create the corresponding Ada type. Instead, it will create a Gtk_Widget, and you will thus have to do some Uncheck_Cast to convert it back to the type you want and expect.
In the third case (imported C widgets), GtkAda is not, by default, able to create the corresponding Ada type.
The solution we suggest to solve these two issues is to 'with' the Gtk.Type_Conversion unit. In that case, every standard widget, no matter who created them, will always be correctly converted to an appropriate Ada type. So, basically, if you put the following in your main unit:
with Gtk.Type_Conversion; begin Gtk.Main.Init; Gtk.Type_Conversion.Init; ... end
then you can safely get the children of any widget (table, boxes, ...) and be sure you have the right Ada type. You won't need to explictly convert your widget to something else.
However, 'with'ing this unit means that your application will depend on every package of GtkAda, which is a little bit heavier, and explains why this is not the default. We do recommend to use it if it is not extremely important for you whether your application depends on all the packages of GtkAda.
The case of imported C widgets is a little bit trickier. Since GtkAda does not know anything about them when it is build, it can't convert magically the C widgets to Ada widgets. This is your job to teach GtkAda how to do the conversion.
We thus provide a 'hook' function, that you need to modify. This function is defined in the package Gtk.Type_Conversion. It is a function that takes a string with the name of the C widget (ex/ "GtkButton"), and expects a newly allocated pointer in return. If you don't know this type either, simply return null.
GtkAda 0.6 is an almost complete rewrite of GtkAda. Whereas widgets used to be record types, they now are implemented as access types. This change has two benefits:
Your existing code might have to be modified a little though (sorry about that, this is for the better!).
Gtk_New
now creates access types (and allocate memory for
them), you do not have to free this memory yourself. This is
automatically taken care of by gtk itself, which is one of the
strong points of the new scheme.
package My_Cb is new Signal.Void_Callback (Gtk_Widget_Record); ^^^^^^^Then you have to modify the spec of the subprogram iself:
procedure My_Func (Button : access Gtk.Button.Gtk_Button_Record; Data : in Gint);Note that the first parameter is an anonymous access to a record type, and the second parameter is an "in" parameter.
The last things that have changed in this new version of the toolkit are some of the names of the parameters in the subprograms. This is part of a major cleanup we are doing so that things can be more homogeneous within GtkAda.
Since version 0.6 of this toolkit, it is possible to associate your
own data with existing widgets, simply by creating new types. This
section will show you a simple example, but you should rather read the
source code in testgtk/ where we used this feature instead of using
user_data
as in the C version.
type My_Button_Record is new Gtk_Button_Record with record -- whatever data you want to associate with your button end record; type My_Button is access all My_Button_Record'Class;
With the above statements, your new type is defined. Every function
available for Gtk_Button
is also available for My_Button
.
Of course, as with every tagged type in Ada, you can create your own
primitive functions, with the following prototype:
procedure My_Primitive_Func (Myb : access My_Button_Record);
To instanciate an object of type My_Button
in your application, do
the following:
declare Myb : My_Button; begin Myb := new My_Button_Record; Initialize (Myb); -- from Gtk.Button end;
The first line creates the Ada type, whereas the Initialize
call
actually creates the C widget and associates it with the Ada type.
With GtkAda, you can now create widgets directly in Ada. These new widgets can be used directly, as if they were part of gtk itself.
Creating new widgets is a way to create reuseable components. You can apply to them the same functions as would for any other widget, such as Show, Hide, ...
This section will present how to create two types of widgets, composite widgets and widgets created from scratch. Two examples are provided with GtkAda, in the directories `examples/composite_widget' and `examples/base_widget'. Please also refer to the gtk+ tutorial, that describes the basic mechanisms that you need to know to create a widget (even if the Ada code is really different from the C code...)
A composite widget is a widget that does not do much by itself. This is
more a collection of subwidgets, grouped into a more general entity.
For instance, among the standard widgets, Gtk_File_Selection
and Gtk_Font_Selection
belong to this category.
The good news is that there is nothing special to know. Just create a
new tagged type, that extends one of the standard widgets (or even another
of your own widgets), provide a Gtk_New
function that allocates
memory for this widget, and call the Initialize
function that does
the actual creation of the widget and the subwidgets.
There is only one thing to do: Initialize
should the call the
parent class's Initialize
function, to create the underlying C
widget.
The example directory `examples/composite_widget' reimplements the
Gtk_Dialog
widget as was written in C by the creators of gtk+.
First, an important note: please do not read this if this is your first time using GtkAda, or if you don't really understand the signal mechanism. Creating a nice and working widget really takes a lot of messing with the low level signals.
Creating a widget from scratch is what you want to do if your widget should be drawn in a special way, should create and emit new signals, ... The example we give in `examples/base_widget' is a small target, on which the user can click, and that sends one of two signals "bullseye" or "missed" depending on where the user has clicked.
Once again, the only two functions that you must create are Gtk_New
and Initialize
.
This time, Initialize
has to do two things:
Parent_Package.Initialize (Widget); -- The above line calls the Initialize function from the parent. -- This creates the underlying C widget, which we are going to -- modify with the following call: Gtk.Object.Initialize_Class_Record (Widget, Signals, Class_Record); -- This initializes the "class record" for the widget and -- creates the signals.
In the above example, the new part is the second call. It takes three arguments:
Signals : Gtk.Object.Signal_Array (0 .. 1) := (0 => new String'("bullseye" & Ascii.NUL), 1 => new String'("missed" & Ascii.NUL));This will create two signals, named "bullseye" and "missed", whose callbacks do not take any argument (apart from the usual user's data). This is the only restriction from GtkAda compared to gtk+: all the callbacks are created automatically, but you can not specify additionnal parameters that are sent automatically by GtkAda.
Initialize_Class_Record
is provided to initialize the
"class record". As we said, there should be only one such record per widget
type. This parameter "Class_Record" will point to this records, once it is
created, and will be reused for every instanciation of the widget.
Then of course Initialize
should set up some signal handlers for
the functions you want to redefine.
Three signals are especially useful:
procedure Size_Request (Widget : access My_Widget_Record; Requisition : in out Gtk.Widget.Gtk_Requisition);This function should modify Requisition to specify what would be the ideal size of the widget. This might not be the exact size that will be set, since some containers might decide to enlarge or to shrink it.
procedure Size_Allocate (Widget : access My_Widget_Record; Allocation : in out Gtk.Widget.Gtk_Allocation)This function should take the responsability to move the widget, using for instance
Gdk.Window.Move_Resize
.
GtkAda now comes with a support for the GUI builder Glade (this is not the glade released with Gnat for distributed systems). Not all widgets are supported yet, but we eventually hope to have all of them. If you really need one, it is easy to add the two required functions ... (and to send us patches...)
We actually provide two versions: a dynamic one and a static one. In both cases, you first need to get and install glade (http://glade.pn.org). Then start a new project (or edit an old one). It is easy enough to use, simply select the widget you want to add to your interface, and click!
Starting from version 0.4.1 of Glade, you can directly create Ada files from Glade by selection Ada95 as the language for your project. By doing so, you will tell Glade to call gate internally when using the "Write Source Code" functionality.
The most important file created by Gate is called
callback_<project_name>.adb
.
It contains stubs for all the callbacks you declared in Glade.
Note that you can easily go back to Glade any time, modify your interface,
and have GATE re-generate a set of files. All your modifications will be
kept in the new files. For that, GATE creates a directory .gate/
in the
current directory. Please do not delete it if you want GATE to be able to
keep your changes from one version to the next.
Also note that to be able to keep track of your modifications, gate
relies on patch
and diff
being available on your system.
If you don't have a working set of diff/patch
, configure
will simply replace them by null operations.
GATE and DGATE currently don't support all widgets and properties available
under Glade. To help you identify which widgets are not supported, GATE will
generate a comment in the create_<widget>.adb
file that looks like:
-- WARNING: Unsupported widget GtkImage (image1)
Which means that while generating the file, GATE detected an unsupported widget (in this case GtkImage) whose name is image1. If you get such warnings, your file may or may not compile properly, but you won't get the complete widget hierarchy at run time.
Feel free to send us (see "How to report bugs") the XML file that causes this problem. We don't guarantee a rapid fix for each particular problem, but receiving real examples of missing functionnalities will certainly help implementing them faster.
Similarly, DGATE generates a warning to the standard output when encountering an unsupported widget:
GtkAda-WARNING **: Unsupported widget GtkImage (image1)
Here is the list of widgets that are currently not supported by GATE/DGATE.
A window is created with 3 buttons that shows the 3 different types of
callbacks provided.
One interesting thing is that Callbacks.Bye
is
connected three times: on the "Quit"
button and two times on the
main window.
with Gtk.Signal; with Gtk.Button; with Gtk.Window; package Callbacks is package Button_Callback is new Gtk.Signal.Void_Callback (Widget_Type => Gtk.Button.Gtk_Button_Record); procedure Increment (Widget : access Gtk.Button.Gtk_Button_Record); package Button_Message is new Gtk.Signal.Callback (Widget_Type => Gtk.Button.Gtk_Button_Record, Data_Type => String); procedure Message (Widget : access Gtk.Button.Gtk_Button_Record; Data : in String); package Window_Callback is new Gtk.Signal.Object_Callback (Widget_Type => Gtk.Window.Gtk_Window_Record); procedure Bye (Window : access Gtk.Window.Gtk_Window_Record); end Callbacks; with Gtk.Main; with Ada.Text_Io; package body Callbacks is Counter : Natural := 0; procedure Increment (Widget : access Gtk.Button.Gtk_Button_Record) is begin Counter := Counter + 1; Ada.Text_Io.Put_Line (Natural'Image (Counter)); end Increment; procedure Message (Widget : access Gtk.Button.Gtk_Button_Record; Data : in String) is begin Ada.Text_Io.Put_Line (Data); end Message; procedure Bye (Window : access Gtk.Window.Gtk_Window_Record) is begin Gtk.Window.Destroy (Window); Gtk.Main.Main_Quit; end Bye; end Callbacks; with Gtk.Rc; with Gtk.Main; with Gtk.Enums; with Gtk.Window; with Gtk.Box; with Gtk.Label; with Gtk.Button; with Callbacks; with Glib; procedure Example is procedure Fix_Label (Box : access Gtk.Box.Gtk_Box_Record; Str : String) is Label : Gtk.Label.Gtk_Label; begin Gtk.Label.Gtk_New (Label => Label, Str => Str); Gtk.Box.Pack_Start (In_Box => Box, Child => Label, Expand => False, Fill => False); end Fix_Label; procedure Create_Box (W : access Gtk.Window.Gtk_Window_Record; Str : String) is Box : Gtk.Box.Gtk_Box; Button : Gtk.Button.Gtk_Button; Cb_Id : Glib.Guint; begin Gtk.Box.Gtk_New_Vbox (Widget => Box, Homogeneous => True, Spacing => 0); Gtk.Window.Add (Container => W, Widget => Box); Fix_Label (Box, Str); Gtk.Button.Gtk_New (Widget => Button, Label => "Increment"); Gtk.Box.Pack_Start (In_Box => Box, Child => Button); Cb_Id := Callbacks.Button_Callback.Connect (Obj => Button, Name => "clicked", Func => Callbacks.Increment'Access); Gtk.Button.Gtk_New (Widget => Button, Label => "Message"); Gtk.Box.Pack_Start (In_Box => Box, Child => Button); Cb_Id := Callbacks.Button_Message.Connect (Obj => Button, Name => "clicked", Func => Callbacks.Message'Access, Func_Data => "Button message clicked"); Gtk.Button.Gtk_New (Widget => Button, Label => "Quit"); Gtk.Box.Pack_Start (In_Box => Box, Child => Button); Cb_Id := Callbacks.Window_Callback.Connect (Obj => Button, Name => "clicked", Func => Callbacks.Bye'Access, Slot_Object => W); end Create_Box; procedure Window is Main_Window : Gtk.Window.Gtk_Window; Cb_Id : Glib.Guint; begin Gtk.Window.Gtk_New (Window => Main_Window, The_Type => Gtk.Enums.Window_Toplevel); -- Inherited from Gtk.Widget: Gtk.Window.Set_Title (Window => Main_Window, Title => "Some Title"); Create_Box (Main_Window, "my box") ; -- Connect the Callbacks Cb_Id := Callbacks.Window_Callback.Connect (Obj => Main_Window, Name => "destroy", Func => Callbacks.Bye'Access, Slot_Object => Main_Window); Cb_Id := Callbacks.Window_Callback.Connect (Obj => Main_Window, Name => "delete_event", Func => Callbacks.Bye'Access, Slot_Object => Main_Window); Gtk.Window.Show_All (Main_Window); end Window; begin Gtk.Main.Set_Locale; Gtk.Main.Init; Gtk.Rc.Parse ("example.rc"); Window; Gtk.Main.Main; end Example;
We recommand the following documents. Most of them were written with C in mind, but should be easily adapted most of the time after you read the rest of this document.
Gdk.Event
.
It is worth noting that this book has been published under the Open
Publication License. You can get an electronic copy of it at
http://www.opencontent.org/.
This document was generated on October, 21 1999 using texi2html 1.56k.