|
@@ -1,212 +1,63 @@
|
|
|
-# m2-GTK4 — GTK4 bindings for GNU Modula-2
|
|
|
|
|
-
|
|
|
|
|
-Thin `DEFINITION MODULE FOR "C"` bindings of **GTK 4** for `gm2`
|
|
|
|
|
-(GCC 16 / GNU Modula-2), plus a small pure-Modula-2 helper layer.
|
|
|
|
|
-
|
|
|
|
|
-The first slice covers the canonical GTK4 application shape
|
|
|
|
|
-(`GtkApplication` + `GtkWindow` + `GtkLabel` / `GtkButton` / `GtkBox`),
|
|
|
|
|
-a working `"activate"` / `"clicked"` signal path, and the GLib/GObject
|
|
|
|
|
-runtime underneath it. The second slice adds the common input widgets:
|
|
|
|
|
-`GtkEntry`/`GtkEditable`, `GtkCheckButton`, `GtkSwitch`, `GtkScale`
|
|
|
|
|
-(`GtkRange`), plus a shared `GtkEnums` module. The third slice adds the
|
|
|
|
|
-layout containers: `GtkGrid`, `GtkStack` + `GtkStackSwitcher`,
|
|
|
|
|
-`GtkNotebook`, `GtkScrolledWindow`. The fourth slice adds actions,
|
|
|
|
|
-menus and accelerators: GIO's `GAction` / `GActionMap` /
|
|
|
|
|
-`GSimpleAction`, `GMenu` / `GMenuModel` / `GVariant`, plus
|
|
|
|
|
-`GtkApplicationWindow` and `GtkPopoverMenuBar`. The fifth slice switches
|
|
|
|
|
-the project to the ISO dialect (`-fiso`) and adds per-connection signal
|
|
|
|
|
-closures (`GtkClosures`) and window chrome (`GtkHeaderBar`,
|
|
|
|
|
-`GtkMenuButton`, `gtk_window_set_titlebar`). The sixth slice adds more
|
|
|
|
|
-inputs: `GtkSpinButton`, `GtkSearchEntry`, `GtkDropDown` (with
|
|
|
|
|
-`GtkStringList` / `GListModel`) and `GtkTextView` + `GtkTextBuffer`.
|
|
|
|
|
-The seventh slice adds more containers: `GtkFrame`, `GtkExpander`,
|
|
|
|
|
-`GtkPaned`, `GtkOverlay`, `GtkListBox` (+ `GtkListBoxRow`). The eighth
|
|
|
|
|
-slice adds GIO extras: `GListStore` (+ `GtkStringObject`), `GFile`,
|
|
|
|
|
-`GtkFileDialog` and `GSettings` (+ `GSettingsSchema`). The ninth slice
|
|
|
|
|
-adds model-backed views: `GtkListView`, `GtkGridView`, `GtkColumnView`
|
|
|
|
|
-(+ `GtkColumnViewColumn` / `GtkColumnViewCell`), the selection models
|
|
|
|
|
-`GtkSingleSelection` / `GtkNoSelection`, and the
|
|
|
|
|
-`GtkSignalListItemFactory` / `GtkListItem` pair. A
|
|
|
|
|
-[`tools/gir2def.py`](#generator-broad-coverage) generator additionally
|
|
|
|
|
-emits broad `.def` coverage from GObject-Introspection `.gir` XML.
|
|
|
|
|
-A tenth slice adds **libadwaita** (AdwApplication, header/toolbar,
|
|
|
|
|
-preferences rows, toast, about/message dialogs) and **GError** handling
|
|
|
|
|
-plus an ownership helper layer.
|
|
|
|
|
-
|
|
|
|
|
-Verified with gm2 16.0.1 (experimental) and GTK 4.18.6 on Linux.
|
|
|
|
|
-
|
|
|
|
|
-## Status
|
|
|
|
|
|
|
+# m2-GTK4
|
|
|
|
|
|
|
|
-| Module | C header | Contents |
|
|
|
|
|
-|---|---|---|
|
|
|
|
|
-| `GLib` | `<glib.h>` | base C types, `GMainLoop`, timeouts/idle sources, memory, strings, clock |
|
|
|
|
|
-| `GObject` | `<glib-object.h>` | `ref`/`unref`, `GType`, `g_object_new`, `g_signal_connect_data`, handler disconnect, properties |
|
|
|
|
|
-| `Gio` | `<gio/gapplication.h>` | `GApplication` flags, `run`/`quit`/`hold`/`release` |
|
|
|
|
|
-| `Gtk` | `<gtk/gtk.h>` | `gtk_init`, library version helpers |
|
|
|
|
|
-| `GtkApplication` | `<gtk/gtkapplication.h>` | create/add/remove windows |
|
|
|
|
|
-| `GtkWidget` | `<gtk/gtkwidget.h>` | visibility, sensitivity, margins, expand, align, size |
|
|
|
|
|
-| `GtkWindow` | `<gtk/gtkwindow.h>` | create, title, size, child, present/close/destroy |
|
|
|
|
|
-| `GtkBox` | `<gtk/gtkbox.h>` | orientation, append/prepend/remove, spacing |
|
|
|
|
|
-| `GtkLabel` | `<gtk/gtklabel.h>` | text, markup |
|
|
|
|
|
-| `GtkButton` | `<gtk/gtkbutton.h>` | label buttons |
|
|
|
|
|
-| `GtkEnums` | `<gtk/gtkenums.h>` | orientation, alignment, position constants |
|
|
|
|
|
-| `GtkEditable` | `<gtk/gtkeditable.h>` | text get/set, editable, alignment, selection |
|
|
|
|
|
-| `GtkEntry` | `<gtk/gtkentry.h>` | placeholder, max length, visibility, progress |
|
|
|
|
|
-| `GtkCheckButton` | `<gtk/gtkcheckbutton.h>` | active, label, inconsistent |
|
|
|
|
|
-| `GtkSwitch` | `<gtk/gtkswitch.h>` | active / state |
|
|
|
|
|
-| `GtkRange` | `<gtk/gtkrange.h>` | numeric value (base of GtkScale) |
|
|
|
|
|
-| `GtkScale` | `<gtk/gtkscale.h>` | slider, digits, value position |
|
|
|
|
|
-| `GtkGrid` | `<gtk/gtkgrid.h>` | cell attach, spacing, homogeneous |
|
|
|
|
|
-| `GtkStack` | `<gtk/gtkstack.h>` | named/titled pages, visible child, transitions |
|
|
|
|
|
-| `GtkStackSwitcher` | `<gtk/gtkstackswitcher.h>` | button row that drives a stack |
|
|
|
|
|
-| `GtkNotebook` | `<gtk/gtknotebook.h>` | tabbed pages |
|
|
|
|
|
-| `GtkScrolledWindow` | `<gtk/gtkscrolledwindow.h>` | scrollable viewport, policy |
|
|
|
|
|
-| `GtkApplicationWindow` | `<gtk/gtkapplicationwindow.h>` | app window, window-scoped actions, show-menubar |
|
|
|
|
|
-| `GtkPopoverMenuBar` | `<gtk/gtkpopovermenubar.h>` | in-window menu bar from a model |
|
|
|
|
|
-| `GtkHeaderBar` | `<gtk/gtkheaderbar.h>` | title widget, pack start/end, title buttons, decoration layout |
|
|
|
|
|
-| `GtkMenuButton` | `<gtk/gtkmenubutton.h>` | button that pops up a menu model |
|
|
|
|
|
-| `GAction` | `<gio/gaction.h>` | activate, name, enabled, state |
|
|
|
|
|
-| `GActionMap` | `<gio/gactionmap.h>` | add / lookup / remove named actions |
|
|
|
|
|
-| `GSimpleAction` | `<gio/gsimpleaction.h>` | parameterless and stateful actions |
|
|
|
|
|
-| `GMenu` | `<gio/gmenu.h>` | GMenu + GMenuItem builder |
|
|
|
|
|
-| `GMenuModel` | `<gio/gmenumodel.h>` | model item count |
|
|
|
|
|
-| `GVariant` | `<glib/gvariant.h>` | boolean / string / int32 values |
|
|
|
|
|
-| `GtkSpinButton` | `<gtk/gtkspinbutton.h>` | numeric entry, range/increments/digits/wrap |
|
|
|
|
|
-| `GtkSearchEntry` | `<gtk/gtksearchentry.h>` | search-styled entry, placeholder |
|
|
|
|
|
-| `GListModel` | `<gio/glistmodel.h>` | indexed model interface |
|
|
|
|
|
-| `GtkStringList` | `<gtk/gtkstringlist.h>` | simple string model |
|
|
|
|
|
-| `GtkDropDown` | `<gtk/gtkdropdown.h>` | choose one item from a model |
|
|
|
|
|
-| `GtkTextIter` | `<gtk/gtktextiter.h>` | opaque 80-byte iterator (by address) |
|
|
|
|
|
-| `GtkTextBuffer` | `<gtk/gtktextbuffer.h>` | text model for a text view |
|
|
|
|
|
-| `GtkTextView` | `<gtk/gtktextview.h>` | multi-line text widget |
|
|
|
|
|
-| `GtkFrame` | `<gtk/gtkframe.h>` | labelled border around one child |
|
|
|
|
|
-| `GtkExpander` | `<gtk/gtkexpander.h>` | collapsible section |
|
|
|
|
|
-| `GtkPaned` | `<gtk/gtkpaned.h>` | two panes with a draggable divider |
|
|
|
|
|
-| `GtkOverlay` | `<gtk/gtkoverlay.h>` | stack overlays on a main child |
|
|
|
|
|
-| `GtkListBox` | `<gtk/gtklistbox.h>` | vertical row list + `GtkListBoxRow` |
|
|
|
|
|
-| `GListStore` | `<gio/gliststore.h>` | in-memory list model |
|
|
|
|
|
-| `GtkStringObject` | `<gtk/gtkstringobject.h>` | GObject string wrapper (item type) |
|
|
|
|
|
-| `GtkSignalListItemFactory` | `<gtk/gtksignallistitemfactory.h>` | setup/bind/teardown item factory |
|
|
|
|
|
-| `GtkListItem` | `<gtk/gtklistitem.h>` | per-row object passed to a factory |
|
|
|
|
|
-| `GtkSelectionModel` | `<gtk/gtkselectionmodel.h>` | selection interface for a view |
|
|
|
|
|
-| `GtkSingleSelection` | `<gtk/gtksingleselection.h>` | zero/one selected item |
|
|
|
|
|
-| `GtkNoSelection` | `<gtk/gtknoselection.h>` | display-only (no selection) |
|
|
|
|
|
-| `GtkListView` | `<gtk/gtklistview.h>` | model-driven list |
|
|
|
|
|
-| `GtkGridView` | `<gtk/gtkgridview.h>` | model-driven wrapping grid |
|
|
|
|
|
-| `GtkColumnView` | `<gtk/gtkcolumnview.h>` | model-driven multi-column table |
|
|
|
|
|
-| `GtkColumnViewColumn` | `<gtk/gtkcolumnviewcolumn.h>` | one column |
|
|
|
|
|
-| `GtkColumnViewCell` | `<gtk/gtkcolumnviewcell.h>` | column cell (`GtkListItem` subclass) |
|
|
|
|
|
-| `GFile` | `<gio/gfile.h>` | path/URI file handle |
|
|
|
|
|
-| `GtkFileDialog` | `<gtk/gtkfiledialog.h>` | async native open/save/folder dialog |
|
|
|
|
|
-| `GSettings` | `<gio/gsettings.h>` | typed schema keys |
|
|
|
|
|
-| `GSettingsSchema` | `<gio/gsettingsschema.h>` | schema lookup / key check |
|
|
|
|
|
-| `GError` | `<glib/gerror.h>` | error value (message/domain/code) |
|
|
|
|
|
-| `GioError` | `<gio/gioerror.h>` | GIO error domain and codes |
|
|
|
|
|
-| `AdwApplication` | `<libadwaita-1/adw-application.h>` | Adwaita application |
|
|
|
|
|
-| `AdwApplicationWindow` | `<libadwaita-1/adw-application-window.h>` | Adwaita window |
|
|
|
|
|
-| `AdwHeaderBar` | `<libadwaita-1/adw-header-bar.h>` | header bar |
|
|
|
|
|
-| `AdwToolbarView` | `<libadwaita-1/adw-toolbar-view.h>` | top/bottom bars + content |
|
|
|
|
|
-| `AdwPreferencesPage` | `<libadwaita-1/adw-preferences-page.h>` | page of groups |
|
|
|
|
|
-| `AdwPreferencesGroup` | `<libadwaita-1/adw-preferences-group.h>` | titled group of rows |
|
|
|
|
|
-| `AdwPreferencesRow` | `<libadwaita-1/adw-preferences-row.h>` | base row (title) |
|
|
|
|
|
-| `AdwActionRow` | `<libadwaita-1/adw-action-row.h>` | row with subtitle/prefix/suffix |
|
|
|
|
|
-| `AdwSwitchRow` | `<libadwaita-1/adw-switch-row.h>` | row with a switch |
|
|
|
|
|
-| `AdwEntryRow` | `<libadwaita-1/adw-entry-row.h>` | row with an entry |
|
|
|
|
|
-| `AdwComboRow` | `<libadwaita-1/adw-combo-row.h>` | row with a drop-down |
|
|
|
|
|
-| `AdwExpanderRow` | `<libadwaita-1/adw-expander-row.h>` | row that expands |
|
|
|
|
|
-| `AdwStatusPage` | `<libadwaita-1/adw-status-page.h>` | placeholder page |
|
|
|
|
|
-| `AdwToast` | `<libadwaita-1/adw-toast.h>` | transient notification |
|
|
|
|
|
-| `AdwToastOverlay` | `<libadwaita-1/adw-toast-overlay.h>` | toast host |
|
|
|
|
|
-| `AdwBanner` | `<libadwaita-1/adw-banner.h>` | dismissible info bar |
|
|
|
|
|
-| `AdwClamp` | `<libadwaita-1/adw-clamp.h>` | max-size centred container |
|
|
|
|
|
-| `AdwAboutWindow` | `<libadwaita-1/adw-about-window.h>` | about dialog |
|
|
|
|
|
-| `AdwMessageDialog` | `<libadwaita-1/adw-message-dialog.h>` | message / confirm dialog |
|
|
|
|
|
-| `GtkUtils` (`lib/`) | — | `CStrToM2`, `StrAppend`, `IntToStr`, `Connect`, `SetAccel`, `Unref`, `Free`, `ErrorMessage`, `ClearError` |
|
|
|
|
|
-| `GtkClosures` (`lib/`) | — | per-connection signal contexts (`Connect2`/`Connect3`, owned variants) |
|
|
|
|
|
-
|
|
|
|
|
-## Layout
|
|
|
|
|
|
|
+GNU Modula-2 bindings for **GTK4** and **libadwaita**, for `gm2`
|
|
|
|
|
+(GCC 16 / GNU Modula-2) on Linux.
|
|
|
|
|
|
|
|
-```text
|
|
|
|
|
-m2-GTK4/
|
|
|
|
|
- src/ FOR "C" .def bindings (one per GTK/GIO object)
|
|
|
|
|
- lib/ pure-M2 helpers built on the bindings (GtkUtils, GtkClosures)
|
|
|
|
|
- tests/ gm2 smoke tests + run_tests.sh (+ a private GSettings schema)
|
|
|
|
|
- examples/ runnable GTK4 programs (hello, counter, ...)
|
|
|
|
|
- tools/ gir2def.py (GIR -> .def generator) + run_gir_check.sh
|
|
|
|
|
- gen/ generator output (git-ignored)
|
|
|
|
|
- build/ generated binaries (git-ignored)
|
|
|
|
|
-```
|
|
|
|
|
|
|
+`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`).
|
|
|
|
|
|
|
|
-## Prerequisites
|
|
|
|
|
|
|
+Verified with `gm2` 16.0.1 (experimental), GTK 4.18.6 and libadwaita 1.7.6.
|
|
|
|
|
|
|
|
-- `gm2` (tested: 16.0.1 experimental, `~/bin/Modula2/Gm2/bin/gm2`)
|
|
|
|
|
-- GTK4 dev files (`pkg-config --cflags --libs gtk4`, tested: 4.18.6)
|
|
|
|
|
-- libadwaita dev 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.
|
|
|
|
|
|
|
+## Features
|
|
|
|
|
|
|
|
-The build uses the **ISO dialect** (`-fiso`). That is required for
|
|
|
|
|
-`SYSTEM.CAST` and for `NEW`/`DISPOSE` (which need `ALLOCATE`/`DEALLOCATE`
|
|
|
|
|
-from the ISO `Storage` module), both used by `GtkClosures`. `make`
|
|
|
|
|
-passes `-fiso` by default.
|
|
|
|
|
|
|
+- **82 hand-written binding modules** across GLib, GObject, Gio, GTK4 and
|
|
|
|
|
+ libadwaita — windows, widgets, inputs, containers, model-backed views,
|
|
|
|
|
+ actions/menus/accelerators, dialogs, 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).
|
|
|
|
|
+- **16 tests** and **11 runnable examples**.
|
|
|
|
|
+- **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.
|
|
|
|
|
|
|
|
```sh
|
|
```sh
|
|
|
export PATH=$HOME/bin/Modula2/Gm2/bin:$PATH
|
|
export PATH=$HOME/bin/Modula2/Gm2/bin:$PATH
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## Build & test
|
|
|
|
|
|
|
+## Build and test
|
|
|
|
|
|
|
|
```sh
|
|
```sh
|
|
|
-make # tests + examples -> build/
|
|
|
|
|
-./tests/run_tests.sh
|
|
|
|
|
-./build/examples/hello
|
|
|
|
|
-./build/examples/counter
|
|
|
|
|
-./build/examples/inputs
|
|
|
|
|
-./build/examples/containers
|
|
|
|
|
-./build/examples/actions
|
|
|
|
|
-./build/examples/headerbar
|
|
|
|
|
-./build/examples/editor
|
|
|
|
|
-./build/examples/layouts
|
|
|
|
|
-./build/examples/files
|
|
|
|
|
-./build/examples/views
|
|
|
|
|
-./build/examples/adw
|
|
|
|
|
|
|
+make # build all tests and examples into build/
|
|
|
|
|
+./tests/run_tests.sh # run the test suite
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-`make check` is `make tests` + the runner script. The GUI tests are
|
|
|
|
|
|
|
+`make check` is `make tests` plus the runner script. GUI tests are
|
|
|
skipped automatically when neither `DISPLAY` nor `WAYLAND_DISPLAY` is
|
|
skipped automatically when neither `DISPLAY` nor `WAYLAND_DISPLAY` is
|
|
|
-set. The runner also compiles `tests/schemas/*.gschema.xml` into
|
|
|
|
|
-`build/schemas` and points `GSETTINGS_SCHEMA_DIR` at it, so `test_gio`
|
|
|
|
|
-can exercise `GSettings` without touching real user settings.
|
|
|
|
|
-
|
|
|
|
|
-## Generator (broad coverage)
|
|
|
|
|
|
|
+set. The runner also compiles a private GSettings schema into
|
|
|
|
|
+`build/schemas` so `test_gio` can exercise `GSettings` without touching
|
|
|
|
|
+real user settings.
|
|
|
|
|
|
|
|
-The hand-written modules in `src/` are the idiomatic API. For breadth,
|
|
|
|
|
-`tools/gir2def.py` generates `FOR "C"` `.def` files directly from
|
|
|
|
|
-GObject-Introspection `.gir` XML:
|
|
|
|
|
|
|
+Run an example:
|
|
|
|
|
|
|
|
```sh
|
|
```sh
|
|
|
-make gir # Gtk-4.0 -> gen/ (301 modules, ~3.7k procedures)
|
|
|
|
|
-make gir GIR=Gio-2.0 # any namespace
|
|
|
|
|
-make gir-check # generate + compile/link a sample
|
|
|
|
|
|
|
+./build/examples/hello
|
|
|
|
|
+./build/examples/adw
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-It emits one module per class/interface/record (named `<Namespace><Name>`,
|
|
|
|
|
-e.g. `GtkButton`), namespace functions in `<Namespace>Functions.def`, and
|
|
|
|
|
-enums/bitfields in `<Namespace>Enums.def`. Procedure names are the exact
|
|
|
|
|
-GIR `c:identifier`, so the output links straight against the C library.
|
|
|
|
|
-All 633 generated modules across Gtk/GLib/Gio/Adw parse under `gm2 -fiso`.
|
|
|
|
|
-
|
|
|
|
|
-`make gir-verify` closes the loop by checking that every generated
|
|
|
|
|
-identifier actually exists as an exported symbol in the installed
|
|
|
|
|
-library (via `nm`); it reports 0 unexpected across Gtk, GLib, Gio and
|
|
|
|
|
-Adw (a short allowlist covers macros/deprecated no-ops).
|
|
|
|
|
-
|
|
|
|
|
-See `tools/README.md` for the type mapping and the known limits (value
|
|
|
|
|
-structs are opaque, signals/properties are not generated, variadics and
|
|
|
|
|
-`GError**` are dropped). Output goes to `gen/` and is meant to be
|
|
|
|
|
-cherry-picked, not to replace `src/`.
|
|
|
|
|
-
|
|
|
|
|
-## Usage
|
|
|
|
|
|
|
+## Quick start
|
|
|
|
|
|
|
|
```modula2
|
|
```modula2
|
|
|
MODULE hello ;
|
|
MODULE hello ;
|
|
@@ -238,184 +89,161 @@ BEGIN
|
|
|
END hello.
|
|
END hello.
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-Compile a program against the bindings:
|
|
|
|
|
|
|
+Compile a program against the bindings (the helper objects must be built
|
|
|
|
|
+first):
|
|
|
|
|
|
|
|
```sh
|
|
```sh
|
|
|
-gm2 -fiso -Isrc -Ilib myprog.mod build/objs/GtkUtils.o \
|
|
|
|
|
- build/objs/GtkClosures.o -o myprog \
|
|
|
|
|
|
|
+gm2 -fiso -Isrc -Ilib myprog.mod \
|
|
|
|
|
+ build/objs/GtkUtils.o build/objs/GtkClosures.o -o myprog \
|
|
|
$(pkg-config --cflags --libs gtk4)
|
|
$(pkg-config --cflags --libs gtk4)
|
|
|
```
|
|
```
|
|
|
|
|
|
|
|
-## How it was built, step by step
|
|
|
|
|
-
|
|
|
|
|
-**Step 0 — feasibility spike.** Before writing anything, the riskiest
|
|
|
|
|
-interop points were proved against the real library: creating a GTK4
|
|
|
|
|
-window from Modula-2, running the GLib main loop, and invoking a
|
|
|
|
|
-Modula-2 procedure from C as a `GSourceFunc`. This fixed the design.
|
|
|
|
|
-
|
|
|
|
|
-**Step 1 — discover the GNU Modula-2 ↔ C rules.** See the next section.
|
|
|
|
|
-These rules decide every line of a binding `.def`.
|
|
|
|
|
-
|
|
|
|
|
-**Step 2 — GLib and GObject.** Everything else sits on the base types,
|
|
|
|
|
-the main loop and the signal machinery, so these came first.
|
|
|
|
|
-
|
|
|
|
|
-**Step 3 — application and window.** `GtkApplication` + `GApplication`
|
|
|
|
|
-drive the loop; `GtkWindow` gives something to show. Using
|
|
|
|
|
-`gtk_application_window_new(app)` (not `gtk_window_new()`) is what
|
|
|
|
|
-keeps the application alive while the window is open.
|
|
|
|
|
-
|
|
|
|
|
-**Step 4 — widgets and layout.** `GtkBox`, `GtkLabel`, `GtkButton`, and
|
|
|
|
|
-the per-widget `GtkWidget` layout helpers.
|
|
|
|
|
-
|
|
|
|
|
-**Step 5 — helpers and signal ergonomics.** `GtkUtils.Connect` wraps the
|
|
|
|
|
-`g_signal_connect` macro (which has no C symbol) by calling the real
|
|
|
|
|
-`g_signal_connect_data`; `CStrToM2` and `IntToStr` handle the
|
|
|
|
|
-string/number conversions GTK code always needs.
|
|
|
|
|
-
|
|
|
|
|
-**Step 6 — tests and examples.** A headless GLib loop test, a
|
|
|
|
|
-version/link test, a widget + signal round-trip test, and an
|
|
|
|
|
-application test; plus `hello` and `counter` examples.
|
|
|
|
|
-
|
|
|
|
|
-**Step 7 — input widgets.** `GtkEnums` was extracted as the shared home
|
|
|
|
|
-for enum constants, then `GtkEditable`/`GtkEntry`,
|
|
|
|
|
-`GtkCheckButton`, `GtkSwitch`, `GtkRange`/`GtkScale` were added,
|
|
|
|
|
-with a `test_inputs` round-trip test and the `inputs` example. This
|
|
|
|
|
-step also pinned down the real-number mapping (`REAL` = C `double`).
|
|
|
|
|
-
|
|
|
|
|
-**Step 8 — layout containers.** `GtkGrid`, `GtkStack` +
|
|
|
|
|
-`GtkStackSwitcher`, `GtkNotebook` and `GtkScrolledWindow`, with a
|
|
|
|
|
-`test_containers` test and the `containers` example (a notebook whose
|
|
|
|
|
-pages are a grid, a switcher-driven stack, and a scrolled list).
|
|
|
|
|
-
|
|
|
|
|
-**Step 9 — actions, menus, accelerators.** GIO's action/menu stack
|
|
|
|
|
-(`GAction`, `GActionMap`, `GSimpleAction`, `GMenu`, `GMenuModel`,
|
|
|
|
|
-`GVariant`), `GtkApplicationWindow`, and `GtkPopoverMenuBar`, wired
|
|
|
|
|
-together in the `actions` example (menu bar + app/win actions +
|
|
|
|
|
-Ctrl+N/Q/B accelerators via `GtkUtils.SetAccel`) and checked by
|
|
|
|
|
-`test_actions`.
|
|
|
|
|
-
|
|
|
|
|
-**Step 10 — ISO dialect and per-connection closures.** The project was
|
|
|
|
|
-switched to `-fiso`, which provides `SYSTEM.CAST` and intrinsic
|
|
|
|
|
-`NEW`/`DISPOSE` (with `Storage`'s `ALLOCATE`/`DEALLOCATE`). That made
|
|
|
|
|
-the `GtkClosures` module possible: each signal connection gets its own
|
|
|
|
|
-heap context holding the handler and payload, a trampoline forwards the
|
|
|
|
|
-call, and a GClosure destroy notify frees the context - and optionally
|
|
|
|
|
-the payload - on disconnect or finalize. Covered by `test_closure`.
|
|
|
|
|
-
|
|
|
|
|
-**Step 11 — header bar and window controls.** `GtkHeaderBar`,
|
|
|
|
|
-`GtkMenuButton`, and `gtk_window_set_titlebar()` were added, then
|
|
|
|
|
-combined in the `headerbar` example (title widget, a connected "New"
|
|
|
|
|
-button packed start, a menu button packed end) and checked by
|
|
|
|
|
-`test_headerbar`.
|
|
|
|
|
-
|
|
|
|
|
-**Step 12 — more inputs.** `GtkSpinButton`, `GtkSearchEntry`,
|
|
|
|
|
-`GtkStringList` + `GListModel`, `GtkDropDown`, and `GtkTextView` +
|
|
|
|
|
-`GtkTextBuffer` with an opaque 80-byte `GtkTextIter` marshalled by
|
|
|
|
|
-address. Checked by `test_inputs2` and shown in the `editor` example
|
|
|
|
|
-(search entry, text view, wrap-mode drop-down, padding spin button).
|
|
|
|
|
-
|
|
|
|
|
-**Step 13 — more containers.** `GtkFrame`, `GtkExpander`, `GtkPaned`,
|
|
|
|
|
-`GtkOverlay`, and `GtkListBox` + `GtkListBoxRow` (with
|
|
|
|
|
-`GtkSelectionMode` in `GtkEnums`). Checked by `test_containers2` and
|
|
|
|
|
-shown in the `layouts` example (a paned split, frame/expander on the
|
|
|
|
|
-left, overlay + list box on the right, `row-activated` via
|
|
|
|
|
-`GtkClosures.Connect3`).
|
|
|
|
|
-
|
|
|
|
|
-**Step 14 — GIO extras.** `GListStore` + `GtkStringObject` (a concrete
|
|
|
|
|
-list model), `GFile`, the asynchronous `GtkFileDialog`, and `GSettings`
|
|
|
|
|
-+ `GSettingsSchema`. Checked by `test_gio` (headless) and
|
|
|
|
|
-`test_filedialog`; shown in the `files` example (button -> native open
|
|
|
|
|
-dialog -> `open_finish` -> `GFile` basename). The GSettings test uses a
|
|
|
|
|
-private schema compiled by the runner.
|
|
|
|
|
-
|
|
|
|
|
-**Step 15 — model-backed views.** `GtkSignalListItemFactory` +
|
|
|
|
|
-`GtkListItem`, the selection models `GtkSingleSelection` /
|
|
|
|
|
-`GtkNoSelection`, and the views `GtkListView`, `GtkGridView`,
|
|
|
|
|
-`GtkColumnView` (+ `GtkColumnViewColumn`, `GtkColumnViewCell`). Checked
|
|
|
|
|
-by `test_views`, which presents a window and asserts (from the main
|
|
|
|
|
-loop) that the factory "setup"/"bind" callbacks ran, and shown in the
|
|
|
|
|
-`views` example (one store feeding list, grid and column views).
|
|
|
|
|
-
|
|
|
|
|
-**Step 16 — generator verification.** `tools/gir_verify.py` collects every
|
|
|
|
|
-`c:identifier` that `gir2def.py` would emit and checks it against the
|
|
|
|
|
-exported symbols of the libraries `pkg-config` links for the namespace
|
|
|
|
|
-(symbol-version suffixes stripped). `make gir-verify` reports 0
|
|
|
|
|
-unexpected across Gtk/GLib/Gio/Adw, with a small allowlist for GIR-listed
|
|
|
|
|
-macros and per-module ABI functions. `tools/run_gir_check.sh` also
|
|
|
|
|
-bulk-parses every generated module.
|
|
|
|
|
-
|
|
|
|
|
-**Step 17 — libadwaita.** Curated `Adw*` modules (application, window,
|
|
|
|
|
-header bar, toolbar view, preferences page/group and the action/switch/
|
|
|
|
|
-entry/combo/expander rows, status page, toast/overlay, banner, clamp,
|
|
|
|
|
-about and message dialogs), checked by `test_adw` and shown in the `adw`
|
|
|
|
|
-example. libadwaita is optional in the build.
|
|
|
|
|
-
|
|
|
|
|
-**Step 18 — GError and ownership.** `GError` (with its public struct
|
|
|
|
|
-layout) and `GioError` (domain + codes), plus `GtkUtils.Unref`/`Free`/
|
|
|
|
|
-`ErrorMessage`/`ClearError` and a documented ownership discipline.
|
|
|
|
|
-Checked by `test_gerror` (a real `GIO_ERROR_NOT_FOUND` from
|
|
|
|
|
-`g_file_delete`).
|
|
|
|
|
-
|
|
|
|
|
-## GNU Modula-2 interop rules learned
|
|
|
|
|
-
|
|
|
|
|
-1. Declare the module `DEFINITION MODULE FOR "C" Name ;` and list every
|
|
|
|
|
- export in `EXPORT UNQUALIFIED`. Without `EXPORT UNQUALIFIED` the
|
|
|
|
|
- compiler prefixes symbols with `Module_`, and the link fails.
|
|
|
|
|
-2. Formal parameters in a **procedure type** must be unnamed:
|
|
|
|
|
- `GSourceFunc = PROCEDURE (ADDRESS) : INTEGER;` (named parameters are
|
|
|
|
|
- a syntax error in gm2's default dialect).
|
|
|
|
|
-3. A function result that callers may ignore is declared `: [ T ]`
|
|
|
|
|
- (e.g. `PROCEDURE g_timeout_add (...) : [ guint ];`). Without the
|
|
|
|
|
- brackets, ignoring the result is a hard error. This also works in
|
|
|
|
|
- ordinary modules — `GtkUtils.Connect` uses it.
|
|
|
|
|
-4. `ARRAY OF CHAR` maps onto `char *`, so string literals and `CHAR`
|
|
|
|
|
- arrays can be passed straight to `const char *` parameters.
|
|
|
|
|
-5. `VAR` record/string parameters map onto `T *`; opaque handles
|
|
|
|
|
- (`GObject *`, `GtkWidget *`, ...) travel as `ADDRESS` (use `NIL` to
|
|
|
|
|
- test for `NULL`).
|
|
|
|
|
-6. `BOOLEAN` is not `gboolean`: pass `INTEGER` with `GLib.gTrue` /
|
|
|
|
|
- `GLib.gFalse`, or use `INTEGER` directly.
|
|
|
|
|
-7. A top-level Modula-2 procedure is a plain C function pointer; pass
|
|
|
|
|
- it directly to a callback-typed parameter, or use `ADR(proc)` where
|
|
|
|
|
- the binding takes an `ADDRESS`/`GCallback`.
|
|
|
|
|
-8. **Real numbers:** gm2 `REAL` is 8 bytes and matches C `double`;
|
|
|
|
|
- gm2 `SHORTREAL` is 4 bytes and matches C `float`; gm2 `LONGREAL` is
|
|
|
|
|
- 16 bytes and matches nothing in GTK. Use `REAL` for `gdouble` /
|
|
|
|
|
- `double` (e.g. `GtkRange` values, `GtkScale` ranges).
|
|
|
|
|
-9. Beware `*)` and `(*` inside comments — they close/open a comment
|
|
|
|
|
- early. Write `void ptr`, not `void *`, in prose.
|
|
|
|
|
-10. gm2 has no pointer arithmetic and its `T(x)` cast requires equal
|
|
|
|
|
- sizes; `CStrToM2` therefore copies with libc `strncpy` instead of
|
|
|
|
|
- walking a `char *`.
|
|
|
|
|
-11. `GVariant` values from `g_variant_new_*` are *floating*: ownership
|
|
|
|
|
- transfers to the callee (e.g. `g_simple_action_new_stateful`).
|
|
|
|
|
- Values returned by `g_action_get_state()` / `g_variant_get_*` own a
|
|
|
|
|
- reference and must be released with `g_variant_unref()`.
|
|
|
|
|
-12. **ISO dialect.** Compiled with `-fiso`: `CAST(T, expr)` (ISO
|
|
|
|
|
- `SYSTEM`) and `NEW`/`DISPOSE` (with `Storage`'s
|
|
|
|
|
- `ALLOCATE`/`DEALLOCATE`) are available there but not in PIM.
|
|
|
|
|
-13. When a parameter is typed as a **procedure type**, pass the procedure
|
|
|
|
|
- directly (`Connect2(b, "clicked", OnClick, ...)`), not `ADR(OnClick)`
|
|
|
|
|
- — gm2 type-checks it. Use `ADR(proc)` only where the parameter is a
|
|
|
|
|
- plain `ADDRESS` / `GCallback`.
|
|
|
|
|
-14. A large opaque C struct that is always passed by address (e.g.
|
|
|
|
|
- `GtkTextIter`) can be modelled as a record of `ADDRESS` words sized
|
|
|
|
|
- to `sizeof` it: that gives the right size *and* 64-bit alignment.
|
|
|
|
|
- `GtkTextIter` is 80 bytes, hence `ARRAY [0..9] OF ADDRESS`.
|
|
|
|
|
-
|
|
|
|
|
-## Roadmap
|
|
|
|
|
-
|
|
|
|
|
-The original roadmap is complete: GLib/GObject core, widgets, inputs,
|
|
|
|
|
-containers, actions/menus/accelerators, header bars, GIO extras,
|
|
|
|
|
-model-backed views, and the GIR generator are all in. On top of that:
|
|
|
|
|
-generator verification (`make gir-verify`), curated **libadwaita**, and
|
|
|
|
|
-**GError** + ownership helpers.
|
|
|
|
|
-
|
|
|
|
|
-Possible next steps:
|
|
|
|
|
-
|
|
|
|
|
-1. Hand-curate more of the generated surface (signals, properties,
|
|
|
|
|
- value-struct records, `GtkCssProvider` styling).
|
|
|
|
|
-2. Turn the generator's `ADDRESS` placeholders into cross-module type
|
|
|
|
|
- aliases and `[ ]`/`VAR` refinements using the GIR annotations.
|
|
|
|
|
-3. Grow the test suite around the newly generated modules.
|
|
|
|
|
-4. Prune/promote useful `gen/` output into `src/` as it proves out.
|
|
|
|
|
|
|
+## 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 |
|
|
|
|
|
+| `adw` | libadwaita preferences app (toolbar view, rows, toast, about) |
|
|
|
|
|
+
|
|
|
|
|
+## 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 |
|
|
|
|
|
+| `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 |
|
|
|
|
|
+| `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 |
|
|
|
|
|
+| `GtkHeaderBar`, `GtkMenuButton`, `GtkPopoverMenuBar` | window chrome and menus |
|
|
|
|
|
+| `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 (pure Modula-2, in `lib/`)
|
|
|
|
|
+
|
|
|
|
|
+| Module | Contents |
|
|
|
|
|
+|---|---|
|
|
|
|
|
+| `GtkUtils` | `CStrToM2`, `StrAppend`, `IntToStr`, `Connect`, `SetAccel`, `Unref`, `Free`, `ErrorMessage`, `ClearError` |
|
|
|
|
|
+| `GtkClosures` | `Connect2`/`Connect3` (and owned variants) for per-connection signal state |
|
|
|
|
|
+
|
|
|
|
|
+## 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:
|
|
|
|
|
+
|
|
|
|
|
+```modula2
|
|
|
|
|
+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:
|
|
|
|
|
+
|
|
|
|
|
+```sh
|
|
|
|
|
+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
|
|
|
|
|
+
|
|
|
|
|
+```text
|
|
|
|
|
+m2-GTK4/
|
|
|
|
|
+ src/ FOR "C" .def bindings (one per GTK/GIO/Adw object)
|
|
|
|
|
+ lib/ pure-M2 helpers (GtkUtils, GtkClosures)
|
|
|
|
|
+ tests/ gm2 tests + run_tests.sh (+ a private GSettings schema)
|
|
|
|
|
+ examples/ runnable GTK4 / libadwaita programs
|
|
|
|
|
+ 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.
|