GTK4 Programming in C - Part 1 Getting Started Written by Alan Crispin Introduction This article is the first in a series on how to develop GTK4 applications using C. Some small programs will be developed to show how GTK4 and associated libraries can be used for Graphical User Interface (GUI) programming. In this first article, GTK4 is introduced. It shows how to install GTK4, the C compiler, and the GNU Make build automation tool. A small demo application is developed to demonstrate how to create a window and use button and label widgets. A screenshot is shown below. Throughout this series, Ubuntu 24.04 will be used which uses GTK4 version GTK4.14. The series assumes that the reader has a working knowledge of the C programming language. There are many online tutorials and videos on C programming. The full source code for this project can be downloaded using the web link below. https://github.com/crispinprojects/fullcircle GTK4 GTK4 is a library for creating graphical user interfaces which is widely available in Linux distribution repositories. It is a portable toolkit meaning that if applications are written for one platform they can be ported to another. Linux, of course, is the preferred platform. Although C will be used in these articles, GTK4 has bindings for other programming languages. GTK is licensed under the GNU Library General Public License v2. GTK4 uses the GObject library which provides object-oriented programming (OOP) features by using function-like macros. In OOP, constructors are used to initialise a new object from a specific class. This means that when you use the GTK4 API, it provides a list of classes with their constructors, properties, methods and signals. Widgets are the fundamental building blocks when creating a GTK4 Graphical User Interface (GUI) application. Widgets are pre-built user interface elements such as labels, text entries and buttons. GtkWidget is the base class for all widgets. Every widget derives from GtkWidget. It provides a common set of properties, methods and signals to ensure consistency and styling of widgets. GTK4 API The GTK4 API information is an essential resource when developing a GTK application providing information about constructors, properties, methods and signals of an object. See the GTK4 API external link below. Properties represent the data or state of an object. Methods are functions associated with an object. Signals notify the program that something has happened to the object and invariably signals are connected to callback functions to take some appropriate action. The function macro g_signal_connect() is used to connect a callback function to a signal for a particular object. For example, the API information on the button class reveals that it has a constructor called gtk_button_new_with_label(), a property called has-frame and a signal called “clicked”. The “clicked” signal is emitted when the button has been pressed and released (activated). The has-frame property has getter and setter methods called gtk_button_get_has_frame() and gtk_button_set_has_frame() respectively. Install GTK4 To build GTK applications from source, it is necessary to install the libgtk-4-dev package which contains the header and development files for the GTK4 library. When the package libgtk-4-dev is installed, other libraries such as GLib and Gio are also installed. GLib offers various data structures, string manipulation, and file handling functions that are commonly used in C programming. The Gio library provides classes for general purpose input/output, networking and D-bus support. The build-essential meta-package is also needed which contains a collection of essential software tools and libraries required for building and compiling applications from source code. This includes the GNU Compiler Collection (GCC) for C and C++ programming, together with GNU Make which is a build automation tool that can manage the build process of a project. With Ubuntu 24.04 the following packages need to be installed using the terminal commands below. sudo apt update sudo apt install build-essential sudo apt install libgtk-4-dev A number of different code editors can be used when developing GTK applications including Geany and GNOME Builder. Geany can be installed using the Ubuntu App Center. Geany has an integrated terminal and a sidebar that has a symbols tab. This is very useful as it shows a list of symbols (functions, classes and variables) found within the current open file. This list can be filtered. With Ubuntu 24.04 the latest version of GNOME Builder is installed using Flatpak. A tutorial on how to install Flatpak on Ubuntu is in the external links below. GNOME Builder can be used for developing both GTK4 and GNOME applications. In this series of articles, GNOME (libadwaita) applications are not being developed. Some feature highlights of GNOME Builder include browser pages so that GTK4 API information can be displayed within the IDE, code completion, integral terminal, build, rebuild, clean, and run command menu items. First Application Open the main.c file in the download. It shows how to use GTK4 to create a window containing label and button widgets positioned using a box layout container. A GTK4 program must start with the directive #include . This includes all of the widgets, variables, functions and structures available in the GTK4 toolkit together with files from other libraries that GTK4 depends on. The main function is the entry point for the program and is used to create a GtkApplication object and run it. The pointer called “app” is declared and initialised using the gtk_application_new() constructor. The function macro g_signal_connect() connects the “activate” signal to the activate() function. The activate signal is emitted when the application is started with g_application_run() which takes the command-line arguments. The g_object_unref() method is called on the GtkApplication app pointer when the application is closed. Notice that “org.gkt.demo” is the application ID. As an aside, GTK and GNOME make use of “reverse DNS” style identifiers for applications and a desktop file should be named using the application ID. That is .desktop. #include static void button_clicked (GtkButton *button, gpointer user_data) { GtkWidget *label =user_data; gtk_label_set_text(GTK_LABEL(label),"Button Clicked"); } static void activate (GtkApplication* app, gpointer user_data) { GtkWidget *window; GtkWidget *button; GtkWidget *label; GtkWidget *box; window = gtk_application_window_new (app); gtk_window_set_title (GTK_WINDOW (window), "Hello Window"); gtk_window_set_default_size (GTK_WINDOW (window),400, 100); label =gtk_label_new("GTK4 Programming in C"); box =gtk_box_new(GTK_ORIENTATION_VERTICAL,1); gtk_window_set_child (GTK_WINDOW (window), box); button = gtk_button_new_with_label ("Click Me"); gtk_button_set_has_frame(GTK_BUTTON(button),FALSE); g_signal_connect (GTK_BUTTON (button),"clicked", G_CALLBACK (button_clicked),label); gtk_box_append(GTK_BOX(box), label); gtk_box_append(GTK_BOX(box), button); gtk_window_present(GTK_WINDOW (window)); } int main (int argc, char **argv) { GtkApplication *app; int status; app = gtk_application_new ("org.gtk.demo", G_APPLICATION_DEFAULT_FLAGS); g_signal_connect (app, "activate", G_CALLBACK (activate), NULL); status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); return status; } In the activate() function, a GTK window is created using the gtk_application_window_new() constructor. The window title “Hello Window” is set using gtk_window_set_title(). In GTK, GTK_WINDOW() is a macro that performs a type cast to convert a GtkWidget pointer to a GtkWindow pointer. The window size is set using gtk_window_set_default_size() and a window is displayed using gtk_window_present(). Button, label and box GtkWidget pointers are declared. The label widget is created using the gtk_label_new() constructor and its text set to “GTK4 Programming in C”. The button widget is created using the gtk_button_new_with_label() constructor with the button label text set to “Click Me”. The box layout container is created using the gtk_box_new() constructor and its orientation is set to vertical and is used to arrange child widgets (e.g. the label and button in this example). The gtk_box_append() method is used to add the label and then the button to the box container. The gtk_window_set_child() function is used to add the box to the window. The button property “has-frame” is set to FALSE using the setter function gtk_button_set_has_frame(). Then g_signal_connect() is used to connect a callback function called button_clicked() to the “clicked” signal of the button. The function arguments of the button clicked callback function are the GtkButton and a gpointer. A gpointer (generic pointer) is an untyped pointer meaning that it is not associated with any data type and so requires casting. It has to be explicitly cast to the correct specific pointer type or else the compiler does not know how to interpret it. In this case the gpointer is the label widget. In the callback function the macro GTK_LABEL() casts the GtkWidget label pointer obtained from the gpointer user_data to a GtkLabel. The gtk_label_set_text() method then sets the label text to “Button Clicked”. When the button is clicked the text in the label changes to “Button Clicked”. There are macros similar to GTK_LABEL for almost every widget such GTK_ENTRY(object) which casts the object to GtkEntry*. A GtkEntry allows a user to input and edit a single line of text. These macros are a cornerstone of how GTK implements object oriented programming and type safety in the C language. Makefile GNU Make is a build automation tool that manages the build process of a project. The overall objective is to create a Makefile to build the project executable with the GKT4 libraries and headers. Make and other build systems are used in software development because they recompile files only if changes have been made which is important for large projects having many source code files. An explanation of the Makefile for this GTK4 project is contained in the code download and so only how to use it is covered here. To use the Makefile to compile the demo project, open a terminal in the project directory and run the "make" command. The beauty of using GNU Make is that just one command is needed to build the project. make To run the demo executable, use the command shown below (i.e. dot forward slash followed by the program name). ./demo The Makefile contains a target called ‘clean’ which will delete the executable and any object files so that a fresh build can be performed using the source code files which remain untouched. Running “make clean” at the command line removes the object file and the executable. External links GTK Toolkit https://www.gtk.org/ GTK4 API https://docs.gtk.org/gtk4/ C programming Code Vault https://www.youtube.com/@CodeVault An Introduction to Makefiles https://www.gnu.org/software/make/manual/html_node/Introduction.html Geany is a lightweight source-code editor. https://www.geany.org/ GNOME Builder is an IDE for writing GTK and GNOME-based software https://gitlab.gnome.org/GNOME/gnome-builder Flatpak on Ubuntu: The Right Way to Set It Up and Use It https://www.youtube.com/watch?v=Pk_GeN5OC68 Alan is retired and a Linux enthusiast. He has worked in education and with industry and has used many programming languages including C, C++, Delphi and Java. His Linux projects can be found on his Github page https://github.com/crispinprojects.