-
Notifications
You must be signed in to change notification settings - Fork 44
gtk_hl: a high level interface for gtk fortran
This document describes a higher-level interface to the gtk-fortran package. The aim of this module to to make the development of widget interfaces somewhat less intimidating to the typical scientific programmer. The two main drivers of this have been: the widget routines in IDL (Interactive Data Language http://www.ittvis.com/) which allow the development of complex GUIs with a much simpler interface than that in plain GTK; and the Pilib project (web site now defunct) which was an earlier attempt to build a widget toolkit for Fortran but which is now essentially defunct.
The intent is not to replace the lower-level Gtk calls, but to supplement them by bundled routines that allow widget elements to be constructed in fewer lines of code. The majority of the routines provided are constructors, however when setting or getting values involves multiple calls, then such routines are also provided.
Not all the possible widgets are covered, nor are all the possible options. However most things likely to be needed for setting up and monitoring progress in a scientific program are covered.
The following simple example shows the comparison between the standard interface and the high-level interface in setting up an ``Apply'' button for a program:
- Standard:
-
abut = gtk_button_new_with_label("Apply"//cnull) call g_signal_connect(abut, "clicked", c_funloc(run_it), & & NULL) call gtk_widget_set_tooltip_text(abut, "Run the analysis"//cnull) call gtk_widget_set_sensitive(abut, FALSE)
- High Level:
-
abut = hl_gtk_button_new("Apply"//cnull, sensitive=FALSE, & & clicked=c_funloc(run_it), tooltip="Run the analysis"//cnull)
While this example only reduces four calls to one, in other cases (particularly where the GtkTreeView is involved) many tens of lines may be saved.
It will be seen that this interface makes heavy use of Fortran's optional argument system to allow the user to set those properties he needs while letting others take their default values without having to pass large numbers of unnecessary dummy values.
The `gtk_hl` interface depends on the low-level Gtk-Fortran interfaces and on GTK (currently it's being developed against version 2.24 and 3.4). While there may be differences between the low-level calls between GTK versions 2 and 3, these should be papered-over by the high level interface.To use the high level interface in your program, it is necessary to
include the gtk_hl
module in your code. Note that because this
already includes gtk_sup
and
iso_c_binding
you do not need to include them explicitly,
doing so will only slow down compilation. The example below
shows the essential elements to make
gtk_hl
available. Because it only includes those items from gtk
that it needs internally, you will still need to include the relevant items from gtk
in your code. The gtk-2-fortran-modscan
or gtk-3-fortran-modscan
command can be used to scan the code, or it may be easier just to try compiling and linking and add the missing definitions as the compiler finds them (depends on the size of the code).
module handlers
use gtk_hl
use gtk, only: ...
! Any other modules, e.g. gdk g ...
implicit none
contains
.
.
.
end module handlers
program my_gui_app
use handlers
implicit none
.
.
.
end program my_gui_app
If you need to add drawing area(s) to your application, then you also need a
use gtk_draw_hl
line in your program.
Arguments are passed in the same forms as for the low-level interface. While it would in principle be possible to simplify the calls, there are two problems:- This could not be done in the signal handlers as these must be called directly from the underlying Gtk libraries.
- It would then make the mixing of high and low level calls look different, and thus be likely to introduce more errors than leaving the C-compatibility constructs exposed.
The argument conventions described below also apply to the low-level interface.
- Widgets, lists and other Gtk objects
- These are declared as being `type(c_ptr)`. Normally you do not need to do anything with these apart from passing them to and from Gtk.
- gpointer
- When an argument is of type `gpointer` in raw Gtk, then the value may be of any type but it must be declared with the `target` attribute, and then passed to the routine as `c_loc(variable)`.
- Integers
- Integer variables are declared as `integer(kind=c_int)` for `gint`, `integer(kind=c_long)` for `glong` or `integer(kind=c_short)` for `gshort`. Passing by value or reference is handled by the low-level interface and Fortran's C interoperability system. There are a small number of cases where an explicit 8, 16 or 64-bit integer is needed, in these cases the `c_int8_t`, `c_int16_t` or `c_int64_t` kinds should be used.
- Reals
- Real variables are declared as either `real(kind=c_double)` for `gdouble` arguments or `real(kind=c_float)` for `gfloat`. Other issues are as for integers.
- Booleans
- The boolean type used by Gtk (`gboolean`) is **NOT** the same thing as a C `bool` type, therefore any boolean variable should be declared as `integer(kind=c_int)` but only be given the pre-defined values `TRUE` or `FALSE`. Fortran logical types should not be used.
- Strings
- Character strings are handled in very different ways in Fortran and C. In C, they are just an array of characters terminated by a null character, in Fortran a length value is passed as well and there is no terminator. If a character constant is passed to a routine it should be written as `"I am a compatible string"//CNULL`, and a character variable should be passed as `trim(string)//CNULL`. String arguments to handler routines should be declared as `character(kind=c_char), dimension(*)`. A normal character variable passed to a dummy argument with the C-compatible form is accepted by the interface-matching rules, but it will confuse the selection of overloaded names (at least in `gfortran`), for this reason character arguments to overloaded routines are declared in the "Fortran" way. Character arrays, are declared internally in the _Fortran_ way, and the high-level interface routines handle the conversions.
- Characters
- Character (`gchar` or `guchar`) arguments are not seen by C in at all the same way as strings. And although a scalar character constant of variable of length 1 is passed in a way that C understands, a substring expression of length 1 is not. For this reason and also because of some changes in the handling of character `gvalue` types in glib 2.32, all character arguments are treated as 8 bit integers so to pass the character `'a'` to a GTK routine you should pass `ichar('a',c_int8_t)`.
- Routines
- If a function or subroutine is to be passed as an argument (e.g. a signal callback routine) then it must be defined with the `bind(c)` attribute, and it is passed as `c_funloc(procedure)`.
When a high-level routine provides an argument to set a signal handler,
the argument name is just the signal name with hyphens (-
)
replaced with underscores (_
). The user data argument is simply
data
if only a single signal is handled, and
data_
<signal name> when several are present.
Callback routines (also known as signal handlers or event handlers) are called when an action is performed on a widget (e.g. clicking a button). They are usually (though not always) subroutines (details of all signals and their requirements can be found in the Gtk documentation page at http://www.gtk.org/documentation.html). Generally callbacks fall into 2 categories:
- Gtk Signals
- Here there are usually just 2 arguments to the subroutine,
the widget emitting the signal and a user data value, so a suitable
declaration would be.
subroutine my_handler(widget, gdata) bind(c) type(c_ptr), value :: widget, gdata
The
gdata
argument is the data that was passed when the signal was attached, it may be of any type and can be used in any way the user thinks fit, values may be passed both into and out of the handler by this means, and the value does not even need to be C-interoperable. To access its contents you must declare a fortran pointer to the appropriate type and use thec_f_pointer
subroutine to convert the pointer. In the example below, the data is just an integer.integer, pointer :: fdata if (c_associated(gdata)) then call c_f_pointer(gdata, fdata) . . ! Do stuff with the data . endif
Note that you don't need to re-attach the Fortran values in any way after manipulating them.
- Gdk Events
- Signals passed from the Gdk drawing system (including GdkPixbuf and Cairo) have associated event structures which are passed as a second argument to the callback, so the declaration becomes: ```fortran subroutine my_event_handler(widget, event, gdata) bind(c) type(c_ptr), value :: widget, event, gdata ``` The event structure definitions are provided in the `gdk_events` module.
There is a separate high level drawing interface gtk_draw_hl
that provides a bundled drawable widget with automatic expose event repair. To use this you need to have:
use gtk_draw_hl
in your program. If you want to do more than very basic event processing you will also need gdk_events
.
If the plplot
libraries are installed with Fortran95 support, then an integration module is provided to allow them to draw to a gtk drawing surface. Plplot integration.
The interfaces to the individual routines are listed on the Highlevel-API page.
The supplemental routines and definitions are described in the Supplementary routines page.
The high level drawing interface is described in the High level drawing api page. NOTE There was a major change to the drawing API on 1 July 2011. This was to change the backing store from using a GdkPixbuf to a Cairo Image Surface, which facilitates updating plots rather than redrawing them.
- Installation
- My first gtk-fortran application
- Drawing an image in a PNG file (without GUI)
- A program also usable without GUI
- Using Glade3 and gtkf-sketcher (GTK 3)
- Using gtk-fortran as a fpm dependency
- Debugging with GtkInspector
- Learning from examples
- Video tutorials
- How to start my own project from a gtk-fortran example
- git basics
- CMake basics
- Alternatives to CMake
- How to migrate to GTK 4
- How to contribute to gtk-fortran
- How to hack the cfwrapper