A Gtk4 binding for GNU Modula.

Eric Streit 5d00f623e5 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días
demos 61d3d29ae9 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días
examples 0a7848e256 feat: expressions, constraints, shortcuts, Graphene/GtkSnapshot hai 3 días
lib 0a7848e256 feat: expressions, constraints, shortcuts, Graphene/GtkSnapshot hai 3 días
src 61d3d29ae9 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días
tests 61d3d29ae9 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días
tools 0418ccb46e m2-GTK4 v1.0.0: GNU Modula-2 bindings for GTK4 (+ libadwaita) hai 3 días
.gitignore 61d3d29ae9 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días
Makefile 61d3d29ae9 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días
README.md 61d3d29ae9 feat: m2 gtk-demo browser (demos/) with five ported demos hai 3 días

README.md

m2-GTK4

GNU Modula-2 bindings for GTK4 and libadwaita, for gm2 (GCC 16 / GNU Modula-2) on Linux.

m2-GTK4 is a hand-written set of DEFINITION MODULE FOR "C" bindings — one module per GTK/GIO/libadwaita class — plus a small pure-Modula-2 helper layer, a test suite, runnable examples, and a generator that can emit broad binding coverage from GObject-Introspection .gir XML.

It is compiled in the ISO dialect (-fiso).

Verified with gm2 16.0.1 (experimental), GTK 4.18.6 and libadwaita 1.7.6.

Features

  • 159 hand-written binding modules across GLib, GObject, Gio, GTK4 and libadwaita — windows, widgets, inputs, containers, model-backed views, actions/menus/accelerators, dialogs, CSS, drawing (Cairo/Pango), rich text, gestures, drag-and-drop, media, OpenGL, printing, expressions/constraints/shortcuts, settings, and more.
  • Pure-Modula-2 helpers: GtkUtils (string/number conversion, Connect, SetAccel, ownership and GError helpers) and GtkClosures (per-connection signal contexts with cleanup).
  • 41 tests, 26 runnable examples, and an m2 gtk-demo browser (demos/) modelled on GTK's own gtk4-demo.
  • Generator + verifier: tools/gir2def.py turns a .gir file into .def files; tools/gir_verify.py checks every generated identifier against the installed library. Verified clean across 8602 identifiers.

Requirements

  • gm2 (tested: 16.0.1 experimental)
  • GTK4 development files (pkg-config --cflags --libs gtk4, tested 4.18.6)
  • libadwaita development files (pkg-config --cflags --libs libadwaita-1, tested 1.7.6) — optional; enables the Adw* modules, test_adw and the adw example. The build detects them automatically.
export PATH=$HOME/bin/Modula2/Gm2/bin:$PATH

Build and test

make                 # build all tests, examples and the demo browser into build/
./tests/run_tests.sh # run the test suite

make check is make tests plus the runner script. GUI tests are skipped automatically when neither DISPLAY nor WAYLAND_DISPLAY is set. The runner also compiles a private GSettings schema into build/schemas so test_gio can exercise GSettings without touching real user settings.

Run an example:

./build/examples/hello
./build/examples/adw

Quick start

MODULE hello ;

FROM Gio IMPORT g_application_run;
FROM GtkApplication IMPORT gtk_application_new;
FROM GtkWindow IMPORT gtk_application_window_new, gtk_window_set_title,
   gtk_window_set_default_size, gtk_window_set_child, gtk_window_present;
FROM GtkLabel IMPORT gtk_label_new;
FROM GtkUtils IMPORT Connect;
FROM SYSTEM IMPORT ADDRESS, ADR;

PROCEDURE OnActivate (application: ADDRESS; data: ADDRESS);
VAR window, label: ADDRESS;
BEGIN
   window := gtk_application_window_new(application);
   gtk_window_set_title(window, "Hello");
   gtk_window_set_default_size(window, 360, 120);
   label := gtk_label_new("Hello, GNU Modula-2 + GTK4!");
   gtk_window_set_child(window, label);
   gtk_window_present(window)
END OnActivate;

VAR app: ADDRESS;
BEGIN
   app := gtk_application_new("org.example.Hello", 0);
   Connect(app, "activate", ADR(OnActivate), NIL);
   g_application_run(app, 0, NIL)
END hello.

Compile a program against the bindings (the helper objects must be built first):

gm2 -fiso -Isrc -Ilib myprog.mod \
    build/objs/GtkUtils.o build/objs/GtkClosures.o -o myprog \
    $(pkg-config --cflags --libs gtk4)

Examples

Example Shows
hello the canonical application + window + label
counter button signal updating a label
inputs entry, check button, switch, scale
containers grid, stack/switcher, notebook, scrolled window
actions menu bar + app/window actions + accelerators
headerbar header bar, menu button, connected button
editor search entry, text view, drop-down, spin button
layouts frame, expander, paned, overlay, list box
files native file dialog → GFile
views GtkListView / GtkGridView / GtkColumnView from a store
builder load a window from a .ui file with GtkBuilder
feedback progress bar, spinner, separator, image
styling CSS provider and per-widget CSS classes
popover popover and menu popover
dialogs GtkAlertDialog and GtkColorDialog
drawing GtkDrawingArea + Cairo + Pango
demo searchable demo browser (filter model + stack of pages)
gestures click/drag gestures on a drawing area
customwidget custom GtkWidget and GdkPaintable via the C shim
customlayout custom GtkLayoutManager via the C shim
gl OpenGL clearing inside a GtkGLArea
richtext Pango markup, marks and entry completion in a text view
snapshot custom GdkPaintable drawn with GtkSnapshot + Graphene
media GdkTexture in a GtkPicture, plus GtkVideo
clipboard copy/paste text through GdkClipboard
adw libadwaita preferences app (toolbar view, rows, toast, about)

m2 gtk-demo (demos/)

A small Modula-2 port of GTK's gtk4-demo, mirroring its structure: a browser window with a searchable sidebar of demos, where activating a row opens the demo in its own window.

File Role
demos/GtkDemo.def / .mod the demo registry (title, keywords, build function)
demos/DemoImpl.def / .mod the demo implementations
demos/m2gtkdemo.mod the browser application (GtkApplication + sidebar + search)

The demos are simplified ports of the C originals in gtk/demos/gtk-demo: Links (links.c, markup hyperlinks + activate-link), List Box (listbox.c), Flow Box (flowbox.c, colour swatches drawn with gdk_rgba_parse + gdk_cairo_set_source_rgba), Expander (expander.c) and CSS Basics (css_basics.c, live CSS editing through a GtkCssProvider). Each demo follows the gtk-demo convention — a build procedure that creates its window once, then toggles its visibility — so the registry in GtkDemo is just a table of PROCEDURE (ADDRESS) : ADDRESS.

make demos
./build/demos/m2gtkdemo

Module reference

Core runtime

Module C header Contents
GLib <glib.h> base types, main loop, timeouts, memory, clock
GObject <glib-object.h> ref/unref, GType, g_object_new, signals, properties
Gio <gio/gapplication.h> GApplication flags, run/quit/hold
GVariant <glib/gvariant.h> boolean/string/int32 values, refcount
GError <glib/gerror.h> error value (message/domain/code)
GioError <gio/gioerror.h> GIO error domain and codes
Gtk <gtk/gtk.h> gtk_init, version helpers
Gdk <gdk/gdkdisplay.h> default display, GdkRGBA
GtkEnums <gtk/gtkenums.h> orientation, alignment, wrap, selection, position

GIO objects and models

Module Contents
GListModel, GListStore indexed models; in-memory store
GtkStringList, GtkStringObject string model / item
GMenu, GMenuModel, GSimpleAction, GAction, GActionMap menus and actions
GtkFilterListModel, GtkCustomFilter, GtkSortListModel, GtkCustomSorter M2-callback filter/sort models
GtkExpression, GtkStringSorter, GtkNumericSorter, GtkStringFilter, GtkBoolFilter expression-based sorters/filters
GtkConstraintLayout, GtkConstraint, GtkConstraintGuide constraint layout
GtkShortcut, GtkShortcutController keyboard shortcuts
Graphene, GtkSnapshot geometry records and snapshot rendering
GtkMultiSelection, GtkBitset multiple selection and bitsets
GtkTreeListModel, GtkTreeListRow, GtkTreeExpander tree models and expanders
GtkDirectoryList, GtkBookmarkList directory / bookmark models
GtkDropTarget, GtkDragSource, GdkContentProvider, GdkClipboard drag-and-drop and clipboard
GdkTexture, GdkPixbuf, GtkVideo, GtkMediaFile, GtkMediaStream images and media
GtkGLArea, GdkGLContext, GL OpenGL rendering (-lGL)
GtkPrintOperation, GtkPrintSettings, GtkPageSetup, GtkPrintContext printing
GFile, GtkFileDialog file handles and the native dialog
GSettings, GSettingsSchema typed settings and schema lookup

GTK widgets and views

Module Contents
GtkApplication, GtkApplicationWindow, GtkWindow, GtkWidget application and windows
GtkBox, GtkGrid, GtkFrame, GtkExpander, GtkPaned, GtkOverlay, GtkNotebook, GtkStack, GtkStackSwitcher, GtkScrolledWindow layout containers
GtkLabel, GtkButton, GtkCheckButton, GtkSwitch, GtkScale, GtkRange, GtkSpinButton, GtkEntry, GtkEditable, GtkSearchEntry, GtkDropDown controls
GtkTextView, GtkTextBuffer, GtkTextIter multi-line text
GtkTextTag, GtkTextTagTable, GtkTextMark, GtkEntryBuffer rich-text tags, marks and entry buffer
GtkEntryCompletion entry completion (deprecated; GtkTreeModel-based)
GtkAdjustment, GtkProgressBar, GtkSpinner, GtkSeparator, GtkImage value model and feedback/decoration widgets
GtkHeaderBar, GtkMenuButton, GtkPopoverMenuBar window chrome and menus
GtkPopover, GtkPopoverMenu popovers and menu popovers
GtkBuilder load widget trees from .ui XML (with GError)
GtkAlertDialog, GtkColorDialog modern alert and colour dialogs
GtkCssProvider, GtkStyleContext CSS styling for the display
GtkStackSidebar, GtkSearchBar, GtkRevealer, GtkAspectFrame sidebar/search/animation/layout helpers
GtkFlowBox, GtkFixed, GtkPicture, GtkToggleButton, GtkLinkButton, GtkCalendar, GtkLevelBar, GtkScrollbar reflowing grid, fixed/abs, image, toggle/link, date, level, scrollbar
GtkAssistant, GtkIconView, GtkEmojiChooser wizard, icon grid (deprecated), emoji picker
GtkEventController, GtkGestures event controllers and gestures (click/drag/swipe/zoom/rotate/pan/long-press)
GtkDrawingArea + Cairo + Pango + PangoCairo custom drawing with Cairo and text layout
GtkListBox, GtkListView, GtkGridView, GtkColumnView, GtkColumnViewColumn, GtkColumnViewCell, GtkListItem, GtkSignalListItemFactory, GtkSelectionModel, GtkSingleSelection, GtkNoSelection lists, grids and tables

libadwaita

Module Contents
AdwApplication, AdwApplicationWindow Adwaita application and window
AdwHeaderBar, AdwToolbarView header bar and toolbar view
AdwPreferencesPage, AdwPreferencesGroup, AdwPreferencesRow preferences layout
AdwActionRow, AdwSwitchRow, AdwEntryRow, AdwComboRow, AdwExpanderRow settings rows
AdwStatusPage, AdwBanner, AdwClamp status/banner/clamp
AdwToast, AdwToastOverlay transient notifications
AdwAboutWindow, AdwMessageDialog about and message dialogs

Helpers and the C shim (lib/)

Module Contents
GtkUtils CStrToM2, StrAppend, IntToStr, Connect, SetAccel, Unref, Free, ErrorMessage, ClearError
GtkClosures Connect2/Connect3 (and owned variants) for per-connection signal state
M2GtkShim (lib/m2gtkshim.c) C shim for GObject subclassing: a custom GtkWidget, GdkPaintables (Cairo- and snapshot-based), a generic GListModel, and a custom GtkLayoutManager, all driven by Modula-2 callbacks

Signals, ownership and errors

GObject.g_signal_connect_data() is the real function behind the g_signal_connect() macro. For the common case use the helpers:

Connect(button, "clicked", ADR(OnClicked), NIL);          (* GtkUtils *)
Connect2(row, "activated", OnActivate, state);            (* GtkClosures: own state *)
Connect3(dropdown, "notify::selected", OnSelected, NIL);  (* 3-argument form *)

Modula-2 has no destructors, so follow the C transfer rules:

  • GObject handles → GtkUtils.Unref (g_object_unref);
  • strings from getters (g_file_get_basename, g_settings_get_string, …) → GtkUtils.Free (g_free);
  • GError values → GtkUtils.ClearError, and read them with GtkUtils.ErrorMessage;
  • GVariant from g_variant_get_* / g_action_get_state → g_variant_unref, while g_variant_new_* are floating.

Dialect and binding notes

The build uses the ISO dialect (-fiso). Things worth knowing:

  • CAST and NEW/DISPOSE (with Storage.ALLOCATE/DEALLOCATE) come from ISO, not PIM.
  • EXPORT UNQUALIFIED makes the C symbol match the Modula-2 name.
  • Formal parameters in a procedure type are unnamed: GSourceFunc = PROCEDURE (ADDRESS) : INTEGER;.
  • An ignorable result is declared : [ T ]; otherwise ignoring it is an error.
  • gm2 REAL is C double; SHORTREAL is float; avoid LONGREAL.
  • Pass a procedure directly where the parameter is a procedure type, and ADR(proc) where the parameter is ADDRESS/GCallback.
  • ARRAY OF CHAR maps to char *; VAR parameters map to T *; opaque handles travel as ADDRESS.
  • Inside comments, avoid *) and (* (write void ptr, not void *).
  • A large opaque struct always passed by address (e.g. GtkTextIter, 80 bytes) can be modelled as ARRAY [0..N] OF ADDRESS.

Generator (broad coverage)

For breadth beyond the hand-written modules, tools/gir2def.py emits FOR "C" .def files from GObject-Introspection .gir XML:

make gir                  # Gtk-4.0 -> gen/
make gir GIR=Adw-1        # any namespace
make gir-check            # generate, parse every module, link a sample
make gir-verify           # check every identifier exists in the library

It produces one module per class/interface/record, namespace functions in <Namespace>Functions.def, and enums in <Namespace>Enums.def; procedure names are the exact GIR c:identifier. Across Gtk/GLib/Gio/Adw, 633 generated modules parse under gm2 -fiso and all 8602 identifiers resolve in the installed libraries. Output goes to gen/ (git-ignored) and is meant to be cherry-picked, not to replace src/. See tools/README.md for the type mapping and limits.

Repository layout

m2-GTK4/
  src/        FOR "C" .def bindings (one per GTK/GIO/Adw object)
  lib/        helpers (GtkUtils, GtkClosures) + C shim (m2gtkshim.c)
  tests/      gm2 tests + run_tests.sh (+ a private GSettings schema)
  examples/   runnable GTK4 / libadwaita programs
  demos/      the m2 gtk-demo browser (registry + demos + application)
  tools/      gir2def.py, gir_verify.py, run_gir_check.sh
  gen/        generator output (git-ignored)
  build/      generated binaries (git-ignored)

License

No license has been chosen yet; there is no LICENSE file in this repository.