Read the announcement: GTKX 1.4: Introducing @gtkx/navigation.
New Features
@gtkx/navigationbrings React Navigation to native Adwaita widgets — The new, separately installed package builds on React Navigation 7's core and routers without a React Native dependency.createStackNavigatorrenders anAdwNavigationView,createTabNavigatorrenders anAdwViewStackwith native switchers,createDrawerNavigatorrenders anAdwOverlaySplitView, andcreateSplitViewNavigatorrenders an adaptiveAdwNavigationSplitView. It includesNavigationContainer, typed params and routes, dynamic and static configuration, nested navigators, native headers and back controls, lazy screens, transition/tab/drawer events, guarded native pops, refs, actions, hooks, and live Adwaita dark/high-contrast theme state. AddAdw-1tolibrariesbefore codegen. (#557)- Opt-in v2 resource imports —
future.v2ResourceImportsreplaces the#data/*import map with relative, query-suffixed imports.?resourcebundles an asset and returns its GResource path, with?resource=/exact/pathfor an explicit path;?iconbundles an SVG, PNG, or XPM into the application's private icon theme and returns its icon name;?urlis available when an API needs a file; and relative.gschema.xmlimports remain typed without a query. Assets and icons from dependencies work too, including lazy and side-effect-only imports. Development refreshes changed, added, and deleted resources, while production emits an automatically registeredgtkx.gresource. The resource prefix derives fromapplicationId, is exported asresourceBasePathbyvirtual:gtkx-config, and becomes the default application elementresourceBasePath. New scaffolds enable the flag. (#575) - Application icons become a project-wide build input — The new top-level
applicationIconsetting accepts one SVG, PNG, or XPM file or a complete icon-theme tree. When it is omitted, GTKX uses a matching<applicationId>.svg,.png, or.xpmfrom the project root if exactly one exists; multiple matches require an explicit choice, and no match leaves the icon unset. Development, builds, and every deployment target now use the same source; theme sizes and variants survive packaging, and AppImage selects the best application-context icon. (#575) - Controlled
GtkListBoxselection —GtkListBoxgains aselectedIndexprop.-1ornullclears the selection, a row that has not mounted yet is selected when it appears, and GTKX suppresses therow-selectedcaused by its own write. If GTK changes a controlled selection, GTKX restores the requested row on the next microtask without requiring a React render. A fractional index throws. (#560, #566) - Explicit minimum native-library versions in packages —
deploy.minimumLibraryVersionsadds Debian and RPM constraints for the generated GTK and libadwaita dependencies. For example,{ "Gtk-4.0": "4.14" }produceslibgtk-4-1 (>= 4.14)andgtk4 >= 4.14; versions may include a patch segment. Codegen records the expanded library inventory, so deploy still identifies the libraries an app bound when the config useslibraries: "*"or the deployment skips its build. (#561, #566) - Pre-bound native struct fields —
t.fieldandt.fieldAtcompile a struct-field descriptor once and expose reusable fixed-offset and strided accessors. Generated/runtime consumers no longer reparse the descriptor on every read and write, and Cairo uses the new path for its buffer and record access. (#558)
Breaking Changes
deploy.iconsmoves to top-levelapplicationIcon— Move the same file or icon-theme path besideapplicationId. Config validation now rejectsdeploy.icons; the top-level setting lets development, builds, and deployment consume one source. Projects that relied on 1.3's implicitdata/iconsdirectory must now setapplicationIcon: "data/icons"or place exactly one application-ID-named image in the project root. Deploying without an icon still fails. (#575)- Non-GTK package dependencies become explicit — Automatic Debian and RPM mappings remain for
Gtk-4.0andAdw-1. GtkSourceView, WebKitGTK, and every other GIR library must now be named underdeploy.depends, avoiding an incorrect guess about a distribution's package name. (#566) - Opting into v2 resource imports requires a source migration — Remove the package
importsentry for#data/*; replace asset imports with relative?resource,?icon, or?urlimports; import schemas relatively without a query; and prependresource://only where an API requires a URI, because?resourcereturns a path. A bare relative asset import deliberately fails while the flag is on. Legacy#data/*imports continue to work while the flag is off. (#575) - Application resource paths follow the configured application ID —
GtkApplicationandAdwApplicationnow defaultresourceBasePathto the path derived fromgtkx.config.ts'sapplicationId. If an application element overridesapplicationId, also passresourceBasePathwhen it should use a different resource tree. (#575) - Deploy build metadata is unified and versioned —
dist/gtkx-packages.jsonis replaced bydist/gtkx-schemas.json, which records both schemas and package metadata under a versioned format. Agtkx deploy --skip-buildagainst a build made by GTKX 1.3 must be rebuilt once with 1.4. (#575) - Registered signal declarations use GLib spellings —
registerClass({ signals })now rejects uppercase letters in signal keys. Rename a declaration such asdataChangedtodata-changedordata_changed; JavaScript default-handler methods remain camel-cased, such asonDataChanged. (#566) - Borrowed callback structs expire with the native call — A boxed or plain struct lent by C now aliases the caller's memory, so writes made during the callback reach the caller and reads or writes after the callback returns throw. Code that retained a callback-owned record must copy the data it needs while the callback is active. (#558)
- Unsafe Cairo ownership APIs are removed —
ScaledFont.textToGlyphs,FontFace.createForFtFace,FontFace.createForPattern,Surface.mapToImage, andSurface.unmapImageare omitted because their allocation or borrow contracts cannot be represented safely by independently owned wrappers. Use PangoCairo for shaping and rich text layout, and modify a surface by drawing through itsContextrather than mapping it.
Bug Fixes
- Fixed popped navigation pages remaining retained, stack animation flags settling incorrectly, a closed drawer's
goBackignoring route history, split views revealing an empty pane, and a closing stack page rendering stale params. Navigator factory return types now distinguish dynamic and static configurations correctly. (#566) - Fixed controlled selection and route props trying to restore GTK state inside the same event that changed it. Drift is now corrected after the event, avoiding reentrant disagreement between GTK and React state. (#566)
- Fixed prop, property, notify-detail, signal, and handler resolution for names escaped by codegen and names with digit boundaries such as
enable-2d-canvas-acceleration. Signals declared on registered classes now work as JSXonXprops, while an unknown handler prop fails deterministically. (#557, #566) - Fixed commit-time signal suppression hiding every
notifyemitted during a prop write. GTKX now suppresses only the property it writes, so a secondary property that the widget changes in reaction still reaches itsonNotifyXhandler. (#557, #566) - Fixed boxed native outputs whose registered GType is represented as a plain pointer, such as
Gsk.RenderReplay, failing to use the GIR-declared release function on every decoding path. (#566) - Fixed lent boxed and plain-struct callback parameters being copied or left usable after their native lifetime. Mutations now reach the native caller while the callback is active and stale wrappers are rejected afterwards. (#558)
- Fixed map and accessibility watchers remaining connected after their element was destroyed. (#566)
Full changelog: v1.3.0...v1.4.0