GTK

Multi-platform GUI toolkit serving as foundation for GNOME desktop environment. High customizability through object-oriented design and theming system. Rich accessibility support and internationalization features.

DesktopCross-platformCGObjectLinuxUnixGUI

GitHub Overview

GNOME/gtk

Read-only mirror of https://gitlab.gnome.org/GNOME/gtk

Stars1,561
Watchers79
Forks389
Created:June 3, 2012
Language:C
License:Other

Topics

None

Star History

GNOME/gtk Star History
Data as of: 7/15/2025, 10:54 PM

Framework

GTK

Overview

GTK is a cross-platform GUI toolkit that serves as the foundation for the GNOME desktop environment. Developed in C and built on the GObject type system, it occupies a standard position in desktop application development for Linux/Unix systems.

Details

As of 2025, GTK 4 is provided as a stable version, representing a mature GUI framework with over 30 years of history. It is used in major Linux desktop environments such as GNOME, XFCE, and LXDE, and serves as the foundation for many open-source applications.

Key features of GTK:

  • Native Performance: High-performance native execution through C language
  • Rich Widgets: Comprehensive set of GUI components
  • Theme Support: Flexible customization through CSS-like style system
  • Accessibility: Excellent accessibility support via AT-SPI
  • Internationalization: Complete i18n/l10n support
  • Cross-platform: Runs on Linux, Windows, and macOS

As of 2025, many major applications including Firefox, GIMP, LibreOffice (partially), and VS Code adopt GTK.

Advantages & Disadvantages

Advantages

  • Linux Integration: Complete native experience on Linux/UNIX systems
  • High Performance: Optimized performance through C language
  • Stability: High stability from over 30 years of proven track record
  • Rich Features: Comprehensive widget set and layout managers
  • Free Software: Free usage under LGPL license
  • Community: Large and active development community
  • Documentation: Abundant official documentation and tutorials
  • Language Bindings: Multi-language bindings for Python, Rust, Vala, etc.

Disadvantages

  • Learning Curve: Requires understanding of C language and GObject system
  • Windows/macOS Experience: Limited native look & feel
  • Development Tools: Limited IDE support compared to Qt and others
  • Packaging: Complex distribution across platforms
  • Modern UI: Limited adaptation to latest UI design trends
  • Memory Usage: Overhead due to GObject system

Key Links

Code Examples

Basic GTK Application

// main.c
#include <gtk/gtk.h>

static void
print_hello (GtkWidget *widget,
             gpointer   data)
{
  g_print ("Hello World\n");
}

static void
activate (GtkApplication *app,
          gpointer        user_data)
{
  GtkWidget *window;
  GtkWidget *button;
  GtkWidget *box;

  // Create main window
  window = gtk_application_window_new (app);
  gtk_window_set_title (GTK_WINDOW (window), "GTK Hello World");
  gtk_window_set_default_size (GTK_WINDOW (window), 300, 200);

  // Create layout container
  box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
  gtk_widget_set_halign (box, GTK_ALIGN_CENTER);
  gtk_widget_set_valign (box, GTK_ALIGN_CENTER);

  gtk_window_set_child (GTK_WINDOW (window), box);

  // Create button
  button = gtk_button_new_with_label ("Hello World");

  // Connect signals
  g_signal_connect (button, "clicked", G_CALLBACK (print_hello), NULL);
  g_signal_connect_swapped (button, "clicked", G_CALLBACK (gtk_window_destroy), window);

  gtk_box_append (GTK_BOX (box), button);

  // Show window
  gtk_window_present (GTK_WINDOW (window));
}

int
main (int    argc,
      char **argv)
{
  GtkApplication *app;
  int status;

  app = gtk_application_new ("org.example.HelloWorld", 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;
}

UI Design using GtkBuilder

<!-- interface.ui -->
<?xml version="1.0" encoding="UTF-8"?>
<interface>
  <object id="window" class="GtkWindow">
    <property name="title">GTK Builder Example</property>
    <property name="default-width">400</property>
    <property name="default-height">300</property>
    <child>
      <object id="main_box" class="GtkBox">
        <property name="orientation">vertical</property>
        <property name="spacing">10</property>
        <property name="margin-top">20</property>
        <property name="margin-bottom">20</property>
        <property name="margin-start">20</property>
        <property name="margin-end">20</property>
        
        <child>
          <object id="header_label" class="GtkLabel">
            <property name="label">GTK Builder Demo</property>
            <property name="halign">center</property>
            <style>
              <class name="title-1"/>
            </style>
          </object>
        </child>
        
        <child>
          <object id="input_frame" class="GtkFrame">
            <property name="label">Input Area</property>
            <child>
              <object id="input_grid" class="GtkGrid">
                <property name="margin-top">10</property>
                <property name="margin-bottom">10</property>
                <property name="margin-start">10</property>
                <property name="margin-end">10</property>
                <property name="row-spacing">10</property>
                <property name="column-spacing">10</property>
                
                <child>
                  <object id="name_label" class="GtkLabel">
                    <property name="label">Name:</property>
                    <property name="halign">end</property>
                    <layout>
                      <property name="column">0</property>
                      <property name="row">0</property>
                    </layout>
                  </object>
                </child>
                
                <child>
                  <object id="name_entry" class="GtkEntry">
                    <property name="placeholder-text">Enter your name</property>
                    <property name="hexpand">true</property>
                    <layout>
                      <property name="column">1</property>
                      <property name="row">0</property>
                    </layout>
                  </object>
                </child>
                
                <child>
                  <object id="message_label" class="GtkLabel">
                    <property name="label">Message:</property>
                    <property name="halign">end</property>
                    <property name="valign">start</property>
                    <layout>
                      <property name="column">0</property>
                      <property name="row">1</property>
                    </layout>
                  </object>
                </child>
                
                <child>
                  <object id="message_textview" class="GtkTextView">
                    <property name="height-request">100</property>
                    <property name="hexpand">true</property>
                    <property name="vexpand">true</property>
                    <layout>
                      <property name="column">1</property>
                      <property name="row">1</property>
                    </layout>
                  </object>
                </child>
                
              </object>
            </child>
          </object>
        </child>
        
        <child>
          <object id="button_box" class="GtkBox">
            <property name="orientation">horizontal</property>
            <property name="spacing">10</property>
            <property name="halign">center</property>
            
            <child>
              <object id="submit_button" class="GtkButton">
                <property name="label">Submit</property>
                <style>
                  <class name="suggested-action"/>
                </style>
              </object>
            </child>
            
            <child>
              <object id="clear_button" class="GtkButton">
                <property name="label">Clear</property>
              </object>
            </child>
            
          </object>
        </child>
        
        <child>
          <object id="output_frame" class="GtkFrame">
            <property name="label">Output</property>
            <child>
              <object id="output_label" class="GtkLabel">
                <property name="label">Results will be displayed here</property>
                <property name="margin-top">10</property>
                <property name="margin-bottom">10</property>
                <property name="margin-start">10</property>
                <property name="margin-end">10</property>
                <property name="wrap">true</property>
                <property name="selectable">true</property>
              </object>
            </child>
          </object>
        </child>
        
      </object>
    </child>
  </object>
</interface>
// builder_app.c
#include <gtk/gtk.h>

typedef struct {
    GtkWidget *window;
    GtkWidget *name_entry;
    GtkWidget *message_textview;
    GtkWidget *output_label;
    GtkTextBuffer *text_buffer;
} AppWidgets;

static void
on_submit_clicked (GtkButton *button, AppWidgets *widgets)
{
    const char *name;
    char *message;
    char *output_text;
    GtkTextIter start, end;
    
    // Get name
    name = gtk_editable_get_text (GTK_EDITABLE (widgets->name_entry));
    
    // Get message
    gtk_text_buffer_get_bounds (widgets->text_buffer, &start, &end);
    message = gtk_text_buffer_get_text (widgets->text_buffer, &start, &end, FALSE);
    
    // Create output text
    if (strlen (name) > 0 && strlen (message) > 0) {
        output_text = g_strdup_printf ("Name: %s\nMessage: %s", name, message);
    } else {
        output_text = g_strdup ("Please enter both name and message.");
    }
    
    // Display result
    gtk_label_set_text (GTK_LABEL (widgets->output_label), output_text);
    
    g_free (message);
    g_free (output_text);
}

static void
on_clear_clicked (GtkButton *button, AppWidgets *widgets)
{
    // Clear fields
    gtk_editable_set_text (GTK_EDITABLE (widgets->name_entry), "");
    gtk_text_buffer_set_text (widgets->text_buffer, "", -1);
    gtk_label_set_text (GTK_LABEL (widgets->output_label), "Results will be displayed here");
}

static void
activate (GtkApplication *app, gpointer user_data)
{
    AppWidgets *widgets = g_new0 (AppWidgets, 1);
    GtkBuilder *builder;
    GtkWidget *submit_button, *clear_button;
    GError *error = NULL;

    // Load UI with Builder
    builder = gtk_builder_new ();
    if (!gtk_builder_add_from_file (builder, "interface.ui", &error)) {
        g_printerr ("Error loading UI file: %s\n", error->message);
        g_error_free (error);
        return;
    }

    // Get widgets
    widgets->window = GTK_WIDGET (gtk_builder_get_object (builder, "window"));
    widgets->name_entry = GTK_WIDGET (gtk_builder_get_object (builder, "name_entry"));
    widgets->message_textview = GTK_WIDGET (gtk_builder_get_object (builder, "message_textview"));
    widgets->output_label = GTK_WIDGET (gtk_builder_get_object (builder, "output_label"));
    submit_button = GTK_WIDGET (gtk_builder_get_object (builder, "submit_button"));
    clear_button = GTK_WIDGET (gtk_builder_get_object (builder, "clear_button"));

    // Get TextBuffer
    widgets->text_buffer = gtk_text_view_get_buffer (GTK_TEXT_VIEW (widgets->message_textview));

    // Associate application with window
    gtk_window_set_application (GTK_WINDOW (widgets->window), app);

    // Connect signals
    g_signal_connect (submit_button, "clicked", G_CALLBACK (on_submit_clicked), widgets);
    g_signal_connect (clear_button, "clicked", G_CALLBACK (on_clear_clicked), widgets);

    // Show window
    gtk_window_present (GTK_WINDOW (widgets->window));

    // Clean up builder
    g_object_unref (builder);
}

int
main (int argc, char *argv[])
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.example.BuilderApp", 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;
}

Drawing and Canvas Application

// drawing_app.c
#include <gtk/gtk.h>

/* Surface for drawing */
static cairo_surface_t *surface = NULL;

static void
clear_surface (void)
{
    cairo_t *cr;

    cr = cairo_create (surface);
    cairo_set_source_rgb (cr, 1, 1, 1);  // Fill with white
    cairo_paint (cr);
    cairo_destroy (cr);
}

/* Drawing area resize */
static void
resize_cb (GtkWidget *widget,
           int        width,
           int        height,
           gpointer   data)
{
    if (surface) {
        cairo_surface_destroy (surface);
        surface = NULL;
    }

    if (gtk_native_get_surface (gtk_widget_get_native (widget))) {
        surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32,
                                              gtk_widget_get_width (widget),
                                              gtk_widget_get_height (widget));
        clear_surface ();
    }
}

/* Draw callback */
static void
draw_cb (GtkDrawingArea *drawing_area,
         cairo_t        *cr,
         int             width,
         int             height,
         gpointer        data)
{
    cairo_set_source_surface (cr, surface, 0, 0);
    cairo_paint (cr);
}

/* Draw with brush */
static void
draw_brush (GtkWidget *widget, double x, double y)
{
    cairo_t *cr;

    if (surface == NULL)
        return;

    cr = cairo_create (surface);

    cairo_rectangle (cr, x - 3, y - 3, 6, 6);
    cairo_fill (cr);

    cairo_destroy (cr);

    /* Update drawing area */
    gtk_widget_queue_draw (widget);
}

/* Drag begin */
static void
drag_begin (GtkGestureDrag *gesture,
            double          x,
            double          y,
            GtkWidget      *area)
{
    draw_brush (area, x, y);
}

/* Drag update */
static void
drag_update (GtkGestureDrag *gesture,
             double          x,
             double          y,
             GtkWidget      *area)
{
    double start_x, start_y;
    gtk_gesture_drag_get_start_point (gesture, &start_x, &start_y);
    draw_brush (area, start_x + x, start_y + y);
}

/* Right click to clear */
static void
pressed (GtkGestureClick *gesture,
         int              n_press,
         double           x,
         double           y,
         GtkWidget       *area)
{
    clear_surface ();
    gtk_widget_queue_draw (area);
}

/* Cleanup on window close */
static void
close_window (void)
{
    if (surface)
        cairo_surface_destroy (surface);
}

static void
activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *frame;
    GtkWidget *drawing_area;
    GtkGesture *drag;
    GtkGesture *press;

    // Create main window
    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Drawing Application");
    gtk_window_set_default_size (GTK_WINDOW (window), 600, 400);

    g_signal_connect (window, "destroy", G_CALLBACK (close_window), NULL);

    // Create frame
    frame = gtk_frame_new (NULL);
    gtk_window_set_child (GTK_WINDOW (window), frame);

    // Create drawing area
    drawing_area = gtk_drawing_area_new ();
    gtk_widget_set_size_request (drawing_area, 100, 100);

    gtk_frame_set_child (GTK_FRAME (frame), drawing_area);

    // Set draw callback
    gtk_drawing_area_set_draw_func (GTK_DRAWING_AREA (drawing_area), draw_cb, NULL, NULL);

    // Connect resize signal
    g_signal_connect_after (drawing_area, "resize", G_CALLBACK (resize_cb), NULL);

    // Set up drag gesture (left button)
    drag = gtk_gesture_drag_new ();
    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (drag), GDK_BUTTON_PRIMARY);
    gtk_widget_add_controller (drawing_area, GTK_EVENT_CONTROLLER (drag));
    g_signal_connect (drag, "drag-begin", G_CALLBACK (drag_begin), drawing_area);
    g_signal_connect (drag, "drag-update", G_CALLBACK (drag_update), drawing_area);

    // Set up click gesture (right button)
    press = gtk_gesture_click_new ();
    gtk_gesture_single_set_button (GTK_GESTURE_SINGLE (press), GDK_BUTTON_SECONDARY);
    gtk_widget_add_controller (drawing_area, GTK_EVENT_CONTROLLER (press));
    g_signal_connect (press, "pressed", G_CALLBACK (pressed), drawing_area);

    // Show window
    gtk_window_present (GTK_WINDOW (window));
}

int
main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.example.DrawingApp", 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;
}

ListView and Model

// listview_app.c
#include <gtk/gtk.h>

/* Data item structure */
typedef struct {
    GObject parent_instance;
    char *name;
    char *description;
    int priority;
} TaskItem;

typedef struct {
    GObjectClass parent_class;
} TaskItemClass;

G_DEFINE_TYPE (TaskItem, task_item, G_TYPE_OBJECT)

static void
task_item_finalize (GObject *object)
{
    TaskItem *item = (TaskItem *)object;
    g_free (item->name);
    g_free (item->description);
    G_OBJECT_CLASS (task_item_parent_class)->finalize (object);
}

static void
task_item_class_init (TaskItemClass *class)
{
    G_OBJECT_CLASS (class)->finalize = task_item_finalize;
}

static void
task_item_init (TaskItem *item)
{
    // Initialization
}

static TaskItem *
task_item_new (const char *name, const char *description, int priority)
{
    TaskItem *item = g_object_new (task_item_get_type (), NULL);
    item->name = g_strdup (name);
    item->description = g_strdup (description);
    item->priority = priority;
    return item;
}

/* List item setup */
static void
setup_listitem (GtkSignalListItemFactory *factory,
                GtkListItem              *list_item)
{
    GtkWidget *box, *name_label, *desc_label, *priority_label;

    box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 4);
    gtk_widget_set_margin_top (box, 8);
    gtk_widget_set_margin_bottom (box, 8);
    gtk_widget_set_margin_start (box, 12);
    gtk_widget_set_margin_end (box, 12);

    name_label = gtk_label_new (NULL);
    gtk_label_set_xalign (GTK_LABEL (name_label), 0.0);
    gtk_widget_add_css_class (name_label, "heading");
    
    desc_label = gtk_label_new (NULL);
    gtk_label_set_xalign (GTK_LABEL (desc_label), 0.0);
    gtk_widget_add_css_class (desc_label, "dim-label");
    
    priority_label = gtk_label_new (NULL);
    gtk_label_set_xalign (GTK_LABEL (priority_label), 1.0);
    gtk_widget_add_css_class (priority_label, "caption");

    gtk_box_append (GTK_BOX (box), name_label);
    gtk_box_append (GTK_BOX (box), desc_label);
    gtk_box_append (GTK_BOX (box), priority_label);

    gtk_list_item_set_child (list_item, box);

    g_object_set_data (G_OBJECT (list_item), "name_label", name_label);
    g_object_set_data (G_OBJECT (list_item), "desc_label", desc_label);
    g_object_set_data (G_OBJECT (list_item), "priority_label", priority_label);
}

/* List item data binding */
static void
bind_listitem (GtkSignalListItemFactory *factory,
               GtkListItem              *list_item)
{
    GtkWidget *name_label, *desc_label, *priority_label;
    TaskItem *item;
    char *priority_text;

    item = gtk_list_item_get_item (list_item);

    name_label = g_object_get_data (G_OBJECT (list_item), "name_label");
    desc_label = g_object_get_data (G_OBJECT (list_item), "desc_label");
    priority_label = g_object_get_data (G_OBJECT (list_item), "priority_label");

    gtk_label_set_text (GTK_LABEL (name_label), item->name);
    gtk_label_set_text (GTK_LABEL (desc_label), item->description);
    
    priority_text = g_strdup_printf ("Priority: %d", item->priority);
    gtk_label_set_text (GTK_LABEL (priority_label), priority_text);
    g_free (priority_text);
}

static void
activate (GtkApplication *app, gpointer user_data)
{
    GtkWidget *window;
    GtkWidget *scrolled_window;
    GtkWidget *list_view;
    GListStore *model;
    GtkListItemFactory *factory;
    GtkSingleSelection *selection_model;

    // Create main window
    window = gtk_application_window_new (app);
    gtk_window_set_title (GTK_WINDOW (window), "Task List");
    gtk_window_set_default_size (GTK_WINDOW (window), 400, 600);

    // Create scrolled window
    scrolled_window = gtk_scrolled_window_new ();
    gtk_window_set_child (GTK_WINDOW (window), scrolled_window);

    // Create list model
    model = g_list_store_new (task_item_get_type ());

    // Add sample data
    g_list_store_append (model, task_item_new ("Create Documentation", "Write technical specifications for the project", 1));
    g_list_store_append (model, task_item_new ("Code Review", "Review team member's code", 2));
    g_list_store_append (model, task_item_new ("Bug Fix", "Fix reported bugs", 1));
    g_list_store_append (model, task_item_new ("New Feature", "Implement user authentication feature", 3));
    g_list_store_append (model, task_item_new ("Write Tests", "Create unit tests and E2E tests", 2));

    // Create selection model
    selection_model = gtk_single_selection_new (G_LIST_MODEL (model));

    // Create list item factory
    factory = gtk_signal_list_item_factory_new ();
    g_signal_connect (factory, "setup", G_CALLBACK (setup_listitem), NULL);
    g_signal_connect (factory, "bind", G_CALLBACK (bind_listitem), NULL);

    // Create list view
    list_view = gtk_list_view_new (GTK_SELECTION_MODEL (selection_model), factory);
    gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window), list_view);

    // Show window
    gtk_window_present (GTK_WINDOW (window));
}

int
main (int argc, char **argv)
{
    GtkApplication *app;
    int status;

    app = gtk_application_new ("org.example.TaskListApp", 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;
}

CSS Styling

/* style.css */
@import url("resource:///org/gtk/libgtk/theme/Adwaita/gtk.css");

.main-window {
  background-color: #f6f5f4;
  color: #2e3436;
}

.title-1 {
  font-size: 2em;
  font-weight: bold;
  color: #1c71d8;
  margin-bottom: 1em;
}

.card {
  background-color: white;
  border-radius: 12px;
  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24);
  margin: 12px;
  padding: 16px;
}

.header-bar {
  background: linear-gradient(to bottom, #3584e4, #1c71d8);
  color: white;
}

.sidebar {
  background-color: #fafafa;
  border-right: 1px solid #d3d3d3;
  min-width: 250px;
}

.content-area {
  padding: 20px;
  background-color: white;
}

.suggested-action {
  background: linear-gradient(to bottom, #57e389, #33d17a);
  color: white;
  border: none;
  border-radius: 6px;
  padding: 8px 16px;
  font-weight: bold;
}

.suggested-action:hover {
  background: linear-gradient(to bottom, #33d17a, #26a269);
}

.destructive-action {
  background: linear-gradient(to bottom, #f66151, #e01b24);
  color: white;
  border: none;
  border-radius: 6px;
  padding: 8px 16px;
  font-weight: bold;
}

.destructive-action:hover {
  background: linear-gradient(to bottom, #e01b24, #a51d2d);
}

.entry {
  border: 1px solid #d3d3d3;
  border-radius: 6px;
  padding: 8px 12px;
  background-color: white;
}

.entry:focus {
  border-color: #3584e4;
  box-shadow: 0 0 0 2px rgba(53, 132, 228, 0.3);
}

.frame {
  border: 1px solid #d3d3d3;
  border-radius: 6px;
  background-color: white;
}

.frame > label {
  color: #5e5c64;
  font-weight: bold;
  padding: 0 6px;
  background-color: white;
}

listview row {
  border-bottom: 1px solid #f0f0f0;
  padding: 8px;
}

listview row:hover {
  background-color: rgba(53, 132, 228, 0.1);
}

listview row:selected {
  background-color: #3584e4;
  color: white;
}

.dim-label {
  opacity: 0.65;
}

.caption {
  font-size: 0.8em;
  opacity: 0.75;
}

.status-bar {
  background-color: #f0f0f0;
  border-top: 1px solid #d3d3d3;
  padding: 4px 8px;
}

.toolbar {
  background: linear-gradient(to bottom, #fafafa, #ededed);
  border-bottom: 1px solid #d3d3d3;
  padding: 6px;
}

.circular {
  border-radius: 50%;
}

.warning {
  color: #e5a50a;
}

.error {
  color: #e01b24;
}

.success {
  color: #26a269;
}

Meson Build Configuration

# meson.build
project('gtk-demo-app', 'c',
  version : '1.0.0',
  default_options : ['warning_level=3',
                     'c_std=c11'])

# Dependencies
gtk_dep = dependency('gtk4')
glib_dep = dependency('glib-2.0')

# Resource file processing
gnome = import('gnome')

resources = gnome.compile_resources('app-resources',
  'resources.gresource.xml',
  source_dir: 'resources')

# Executable
executable('gtk-demo-app',
  ['main.c', 'window.c'] + resources,
  dependencies : [gtk_dep, glib_dep],
  install : true)

# Desktop file
install_data('org.example.GtkDemoApp.desktop',
  install_dir : get_option('datadir') / 'applications')

# Icon
install_data('icons/org.example.GtkDemoApp.svg',
  install_dir : get_option('datadir') / 'icons/hicolor/scalable/apps')
<!-- resources.gresource.xml -->
<?xml version="1.0" encoding="UTF-8"?>
<gresources>
  <gresource prefix="/org/example/GtkDemoApp">
    <file preprocess="xml-stripblanks">ui/window.ui</file>
    <file preprocess="xml-stripblanks">ui/preferences.ui</file>
    <file>css/style.css</file>
    <file>icons/preferences-symbolic.svg</file>
    <file>icons/help-symbolic.svg</file>
  </gresource>
</gresources>

Build and Installation

# Configure Meson project
meson setup builddir

# Build
meson compile -C builddir

# Run tests
meson test -C builddir

# Install
meson install -C builddir

# Run for development
./builddir/gtk-demo-app

# Clean build
rm -rf builddir
meson setup builddir
meson compile -C builddir

Compilation using pkg-config

# Compile single file
gcc -o hello `pkg-config --cflags --libs gtk4` hello.c

# Compile multiple files
gcc -o myapp `pkg-config --cflags --libs gtk4` main.c window.c

# Debug build
gcc -g -O0 -o myapp `pkg-config --cflags --libs gtk4` *.c

# Optimized build
gcc -O2 -o myapp `pkg-config --cflags --libs gtk4` *.c

Platform-specific Considerations

Linux

  • Easy installation via package managers
  • Rich themes and icon sets
  • Full Wayland protocol support
  • System integration (desktop files, DBus)

Windows

  • Development environment setup with MSYS2 or Vcpkg
  • Interoperability with Windows API
  • HiDPI support
  • MSI installer creation

macOS

  • Installation via Homebrew
  • macOS look & feel adjustments
  • App Bundle packaging
  • Adapting to macOS-specific UI/UX guidelines