Foundations

Architecture Notes

This page is the code-grounded architecture summary for the current nappgui_src checkout. It explains the real library graph, startup path, backend seam, layout model, data binding path, and platform/runtime boundaries as they exist in the repository today.

Verified Commit 2b0099603323ae7a35b8ee6998d35af94f5b16c8
Commit Date 2026-03-17
Version 1.6.1
Scope core + draw2d + gui + osgui + osapp
Every architectural statement on this page was verified directly against the checked-out source tree. The local repository state is the source of truth for this document.

Relevant Source Files

What NAppGUI Is

NAppGUI is a cross-platform C SDK for native desktop applications on Windows, macOS, and Linux. At the public include level, src/nappgui.h exposes the application bootstrap surface from osapp and the high-level widget surface from gui.

The repository is not just one GUI library. It is a stack of runtime, drawing, GUI, backend, packaging, and helper libraries plus a build-time resource compiler. That distinction matters because the public API feels unified while the internal module graph is deliberately split.

  • Base/runtime: sewer, osbs, core
  • Graphics and GUI: geom2d, draw2d, osgui, gui, osapp
  • Optional support: encode, inet, ogl3d
  • Build-time tooling: tools/nrc

Real Library Stack

The checked-in CMake targets show a layered dependency chain rather than one monolithic framework. The important edge is that gui does not directly depend on osgui; both depend on draw2d, and osapp is the layer that joins them.

Library Main Role Depends On
sewer Low-level utilities, assertions, memory helpers, and support code. None
osbs OS basic services. sewer
core Containers, heap, streams, events, DBind, and resource packs. osbs
geom2d Geometry primitives and math. core
draw2d Drawing types, images, fonts, and the base GuiCtx interface. geom2d
osgui Native GUI backend implementation. draw2d
gui High-level GUI composition and controls. draw2d
osapp Application bootstrap and platform runloop integration. osgui, gui
encode Serialization and encoding helpers. core
inet HTTP and network layer. encode
ogl3d Platform OpenGL context management. sewer

Public Bootstrap and Runtime Ownership

The canonical desktop application shape is the osmain(...) macro family, not a hand-written sequence ending in osapp_run(). The demos define creation and destruction callbacks, include osapp/osmain.h, and end the translation unit with osmain(...).

At runtime, osmain_imp performs the real bootstrap: osgui_start(), gui_start(), native GUI context creation through osguictx(), guictx_set_current(...), and entry into the internal _osapp_run(...) loop. Shutdown unwinds in the reverse order through gui_finish() and osgui_finish().

  1. Write i_create and i_destroy callbacks.
  2. Include osapp/osmain.h.
  3. Use osmain(i_create, i_destroy, "", App).
  4. Let the runtime own backend startup, context install, runloop entry, and shutdown.

GuiCtx: The Backend Abstraction Layer

GuiCtx is the key seam that explains how the high-level gui library avoids a direct dependency on one platform backend. The interface lives under draw2d and consists of function-pointer tables for control creation, sizing, windows, menus, cursors, drawing, and event/listener hooks.

In practice this is an internal backend contract, not a standalone public subsystem. The repository currently ships one concrete provider: the native backend created by osguictx() in osgui. References to possible future alternative contexts are architectural direction, not second shipped backends.

  • gui owns composition: widget trees, layouts, and higher-level behavior.
  • GuiCtx owns backend hooks: native controls, sizing, window operations, and event bridge points.
  • osgui supplies the implementation: the real shipped context is the native one.

UI Composition Model

Layout

Layout is the core recursive composition structure. Each cell can hold either a GuiComponent or a nested Layout, and the internal state tracks row and column dimensions, cell padding, alignment, visibility, background/stroke colors, DBind metadata, and bound objects.

The internal comments above _layout_compose() describe a two-phase sizing model: _layout_natural() computes natural sizes and _layout_expand() distributes the available space. After composition, _layout_locate() applies the final geometry to controls and sublayouts.

Panel

A Panel is a layout host, not just a single-layout wrapper. Internally it owns ArrPt(Layout) *layouts plus visible_layout and active_layout, which allows one panel to keep multiple layout trees and switch the visible one.

Window

window_panel(...) wraps the supplied panel in an internal 1x1 layout and installs that as the window's root layout. Resize behavior then flows through the layout engine: the sizing event composes the constrained result size, and the size event locates the layout tree.

Events and Data Binding

Event System

NAppGUI uses a lightweight typed listener model from core/event.h and core/event.cpp. Events carry sender, parameter, result, and type information, and debug builds track type names and assert correctness. This is not a generic reactive graph; it is a callback system used broadly across the GUI and runtime layers.

DBind and Layout Binding

DBind is runtime metadata for structs, enums, binary payloads, and containers. The GUI layer builds on it through layout_dbind(...), layout_dbind_obj(...), cell_dbind(...), and layout_dbind_update(...) to connect controls and layout cells to object fields.

When a bound control edits a field, gbind.c raises ekGUI_EVENT_OBJCHANGE. Handlers can inspect the pending edit through EvBind, accept or reject it, and trigger a revert when needed. Accepted changes then refresh the affected bound controls through the layout binding machinery.

Native Controls vs Custom-Drawn Controls

NAppGUI is not only a thin wrapper over native widgets. Many controls map directly onto platform controls in osgui, including common buttons, edits, combos, popups, sliders, progress bars, and windows.

Several visible controls are instead implemented as custom View-based widgets using the ekGUI_TYPE_CUSTOMVIEW backend slot. Verified examples in this checkout include label, imageview, listbox, and tableview. That distinction matters when documenting behavior, portability, and styling expectations.

Platform Backends

Windows

The current Windows backend is Win32 plus GDI and GDI+ drawing. This checkout contains extensive Gdiplus:: usage and explicit comments describing GDI/GDI+ paths rather than a Direct2D renderer. Optional web support uses WebView2 when enabled.

macOS

The macOS backend is native Cocoa/AppKit. Drawing lives in the Objective-C draw2d path, and optional web content support uses WKWebView when the deployment target and build options allow it.

Linux

The Linux backend uses GTK3 for the native widget layer. Drawing and text go through the GTK, Cairo, and Pango path, and optional web support uses WebKitGTK when found at configure time.

Build, Packaging, and Resources

The root build uses CMake and exposes the main options NAPPGUI_SHARED, NAPPGUI_DEMO, and NAPPGUI_WEB. The tree also includes the nrc resource compiler under tools/nrc, which the build invokes to generate embedded resource code and, in packed mode, runtime bundles.

Resource handling supports two delivery modes: embedded resources compiled into generated C code and packed resource bundles loaded at runtime. The GUI layer exposes registration through gui_respack(...) and language selection through gui_language(...).

One packaging detail is easy to miss in the exported CMake config: NAPPGUI_LIBRARIES covers the main application stack, but not every optional repository target. In this checkout, inet and ogl3d exist as build targets without being part of that exported convenience variable.

Key Verified Architecture Points

  • Panel can host multiple layouts and switch the visible one.
  • window_panel(...) wraps the panel in an internal 1x1 layout.
  • gui does not directly depend on osgui; both depend on draw2d, and osapp joins them.
  • The canonical desktop app entry is osmain(...), while _osapp_run(...) is internal.
  • The Windows backend in this checkout uses GDI/GDI+, not Direct2D.
  • The shipped GuiCtx provider is the native osgui implementation.
  • The repository includes encode, inet, ogl3d, and the nrc tool as practical architecture subsystems.
  • Several visible controls are custom-drawn View-based widgets rather than native controls.
  • The resource system is a first-class subsystem with embedded and packed modes.

Recommended Reading Order In The Source Tree

For a fast codebase walkthrough, this order gives a reliable mental model from public surface down to runtime and tooling:

  1. src/nappgui.h
  2. demo/hello/main.c
  3. src/osapp/osapp.h and src/osapp/osapp.c
  4. src/draw2d/guictx.hxx and src/osgui/osguictx.c
  5. src/gui/layout.c, src/gui/panel.c, and src/gui/window.c
  6. src/core/event.h, src/core/dbind.h, src/gui/layout.h, and src/gui/gbind.c
  7. prj/NAppTarget.cmake and tools/nrc

That path moves from public API, to actual app startup, to backend abstraction, to layout/composition, to binding/events, and finally to build/resource tooling.