About
Side Projects
Blog
2019-08-24

Deen with Basic GTK+ UI

I have recently wanted to experiment with a small GTK+ GUI project in the C language and decided that I would add a simple UI onto my deen tool. I never worked with GTK+ before so it was all new to me.

Putting Together a GTK+ Application

GTK Flow

The Glade tool is used to layout and design the user interface of the application. The Glade tool produces an XML file.

Another XML “resource” file references the Glade XML file as well as any other resources such as icons that are used in the application.

The resource XML file is then processed by the glib-compile-resources tool that is part of the GTK+ tools. This yields a .c and .h file that contain static byte arrays for the binary data of the various resources described in the XML file. Functions are provided by GTK+ that read from resources such as;

In this way it seems less necessary to ship the application binary with an entourage of additional files or create something like a “bundle” in OPENSTEP for the application.

Some GTK+ Widgets have “signals”. The signals are things that can happen to the Widget. For example the GtkButton has a signal clicked and this signal arises when the user clicks on the button. Signals can have handlers. A handler corresponds to a C function and that C function is called when the signal occurs. In this case, using this mechanic, a C function is able to be invoked when the user clicks on the button.

All GTK+ Widgets can have an identifier. This identifier is a short string and is used in the C logic to find the Widget. In this way it is possible to reference a Widget, manipulate it etc… from the C logic.

Finally both the hand-coded and generated C files are compiled and linked and the resultant binary can be run to show the new user interface. To build this binary, download the [source](deen and issue the command make deen-ggtk. I assume that the build will only succeed on the Linux platform and has not been tested on Windows.

State

The state of the running application is held in global structures. This includes internal data for running the application as well as pointers to Widgets in the user interface and other GTK+ related elements such as objects in the text engine.

Foreground and Background Threads

GTK Flow

Part of using the Deen program is installing the data from the Ding project. The intention is that the user will download the data, decompress it and choose the Ding data file (typically called de-en.txt) in the Deen user interface.

The installation process then runs in a background thread. GTK+ along with most other GUI systems does not allow a background thread to cause change in the GUI layer of the application. GUI changes or interactions should happen on the “main” thread. To achieve this in the GTK+ environment, one uses the g_idle_add(..) function like this;

g_idle_add(deen_ggtk_install_error_report_on_idle, NULL);

This can be read as; run the deen_ggtk_install_error_report_on_idle function with the argument NULL on the main thread next time that the main thread is idle.

Layout Madness

Another interesting aspect of writing a GTK+ application is understanding how to layout the Widgets into a cohesive user interface. Aside from OPENSTEP’s layout mechanism, I have never found GUI layout to be enormously intuitive and GTK+ is no exception. Possibly it becomes more obvious with time.

Glade Layout

The layout from the Glade application is shown above. The application has one main window with three different views. To contain the three views I have used a GtkStack at the top level. This contains the three views for three purposes;

The GTK+ function gtk_stack_set_visible_child_name(..) is used to switch the GtkStack between the three different views.

Achieving the desired layout of the various buttons and other Widgets was the result of much ‘fiddling’. A type of container called GtkBox has been used to effect to layout Widgets either horizontally or vertically. I looked around some other Gnome applications’ Glade files to get some inspiration as to how various layouts might be best achieved.

Pango and Text

GTK+ provides a Widget GtkTextView which owns another “object” called GtkTextStorage. GtkTextStorage is a container for text that is able to be attributed with “tags”. This is a bit like NSTextStorage in OPENSTEP. It is possible to append or insert text with “tags” and those tags cover aspects such as; foreground colour, background colour, font, tabs etc…

Search

The GtkTextStorage references locations in text using instances of GtkTextIter. These “iters” are invalidated by any change in the text. It is possible to use a “mark” object instead which acts more like a placeholder that moves with any changes in the text. “iters” are more like working pointers into the text that are used for executing point-in-time changes. These nuances and behaviours are part of the Pango text engine that GTK+ uses.

The GtkTextStorage to show the search results is wrapped in a GtkScrolledWindow to get a scrollbar on the side.

Allocation and Freeing Objects

When working with GTK+, one is often working with or creating quasi-objects. GTK+ often provides “new” functions to create GTK+ objects and in the documentation there is typically some guidance as to how to free those later if necessary.

Unexpected Wins

A couple of nice side-effects have happened as a result of this work.

Indexing Speed

Writing the indexing data into Deen’s sqlite database was typically slow. I probably should have but did not realise that this was because each INSERT was closing a transaction. Instead I wrapped a transaction around all of the INSERT statements and as a result, the indexing process has gone from incredibly slow to reasonably fast.

Icon

The previous icon was drawn for an earlier version on the Haiku-OS using the HVIF file format. In order to get a version for this GTK+ application I have re-drawn the icon as an SVG. This was done with the open-source InkScape tool.

Conclusion

It is not too hard to create GTK+ applications on Linux; easier than I had anticipated and the tooling is also quite workable.