GTK+

GTK+ is a multi-platform widget toolkit for the implementation of graphical user interfaces on Linux, Unix, macOS, and Windows. It is mainly developed by The GNOME Project. GTK+ is written in C, and bindings for various programming languages exist. gtk-fortran is a binding for modern Fortran, licenced under GNU GPLv3 with GCC Runtime Library Exception, that permits closed-source software.

Compilation

Compile gtk-fortran with:

$ git clone https://github.com/vmagnin/gtk-fortran
$ cd gtk-fortran/
$ mkdir build && cd build/
$ cmake ..
$ make

If multiple Fortran compilers are installed, a specific one can be forced with the -DCMAKE_Fortran_COMPILER option, for example:

$ cmake -DCMAKE_Fortran_COMPILER=gfortran8 -DCMAKE_INSTALL_RPATH=/usr/local/lib/gcc8/ ..

The compiled static library libgtk-2-fortran.a and the *.mod files for linking are then located in gtk-fortran/build/src/.

Example

gtk-fortran
Fig. 1: Simple GTK+ 2.0 application with gtk-fortran

The demo application (fig. 1) shows how to add widgets to a GTK+ window and connect these with signal handlers. Further examples can be found in gtk-fortran/examples/.

Due to the size of the GTK+ Fortran interface, it is recommended to import only actually used parameters and procedures from the gtk module, in order to reduce compilation time.

! demo.f90
module handlers
contains
    function hello(widget, gdata)
        use, intrinsic :: iso_c_binding, only: c_ptr, c_int
        use :: gtk, only: FALSE
        implicit none
        type(c_ptr), value :: widget
        type(c_ptr), value :: gdata
        integer(c_int)     :: hello

        print '(a)', 'Hello, World!'
        hello = FALSE
    end function hello

    subroutine destroy(widget, gdata)
        use, intrinsic :: iso_c_binding, only: c_ptr
        use :: gtk, only: gtk_main_quit
        implicit none
        type(c_ptr), value :: widget
        type(c_ptr), value :: gdata

        call gtk_main_quit()
    end subroutine destroy
end module handlers

program main
    use, intrinsic :: iso_c_binding, only: c_funloc, c_int, C_NULL_CHAR, c_ptr
    use :: gtk, only: FALSE, GTK_WINDOW_TOPLEVEL, TRUE, g_signal_connect, &
                      gtk_box_pack_start, gtk_button_new_with_label, &
                      gtk_container_add, gtk_container_set_border_width, &
                      gtk_hbox_new, gtk_init, gtk_main, gtk_widget_show, &
                      gtk_window_new, gtk_window_set_default_size, &
                      gtk_window_set_title
    use :: handlers
    implicit none
    type(c_ptr) :: window
    type(c_ptr) :: box
    type(c_ptr) :: button

    call gtk_init()

    ! Create window.
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL)
    call gtk_window_set_default_size(window, 200, 100)
    call gtk_window_set_title(window, 'GTK+ Fortran' // C_NULL_CHAR)
    call gtk_container_set_border_width(window, 10 _c_int)
    call g_signal_connect(window, 'destroy' // C_NULL_CHAR, c_funloc(destroy))

    ! Create widget container.
    box = gtk_hbox_new(TRUE, 10 _c_int);
    call gtk_container_add(window, box)

    ! Create widget.
    button = gtk_button_new_with_label('click me' // C_NULL_CHAR)
    call gtk_box_pack_start(box, button, FALSE, FALSE, 10 _c_int)
    call g_signal_connect(button, 'clicked' // C_NULL_CHAR, c_funloc(hello))
    call gtk_widget_show(button)

    ! Show widget and window.
    call gtk_widget_show(box)
    call gtk_widget_show(window)

    call gtk_main()
end program main

Compile and run the demo application with:

$ gfortran8 -Wl,-rpath=/usr/local/lib/gcc8/ -I./gtk-fortran/build/src/ \
  -L./gtk-fortran/build/src/ `pkg-config --cflags gtk+-2.0` -o demo \
  demo.f90 ./gtk-fortran/build/src/libgtk-2-fortran.a `pkg-config --libs gtk+-2.0`
$ ./demo

References