# The MIT License (MIT)
#
# Copyright (C) 2026 Scott Duensing
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to
# deal in the Software without restriction, including without limitation the
# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
# sell copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
# IN THE SOFTWARE.

.section Architecture
.topic arch.overview
.title DVX Architecture Overview
.toc 0 System Overview
.default
.index DVX
.index Architecture
.index DJGPP
.index DPMI

.h1 DVX Architecture Overview

DOS Visual eXecutive -- A Windowing GUI for DJGPP/DPMI

DVX (DOS Visual eXecutive) is a complete windowing GUI compositor targeting DJGPP/DPMI on DOS. It provides overlapping windows with Motif-style chrome, a retained-mode widget toolkit, cooperative multitasking of DXE-loaded applications, and a dirty-rectangle compositor optimized for 486/Pentium hardware.

.h2 Key Design Constraints

.list
.item VESA VBE 2.0+ LFB only -- no bank switching. If the hardware cannot provide a linear framebuffer, initialization fails.
.item 486 baseline -- all hot paths are written to be fast on a 486, with Pentium-specific paths where the gain is significant.
.item Single-tasking cooperative model -- applications yield the CPU via tsYield(); there is no preemptive scheduler.
.item A single emulator is the trusted reference platform for testing; any bugs observed there are treated as DVX bugs.
.item No external font or cursor files -- all bitmaps are compiled in as static const data.
.endlist

The runtime environment consists of a bootstrap loader (dvx.exe) that loads core DXE libraries, widget plugins, and the shell, which in turn loads and manages DXE application modules.

.h2 Contents

.link arch.layers Five-Layer Architecture
.link arch.pipeline Display Pipeline
.link arch.windows Window System
.link arch.widgets Widget System
.link arch.dialogs Modal Dialogs
.link arch.resources Resource System
.link arch.prefs Preferences System
.link arch.memtrack Per-App Memory Tracking
.link arch.dxe DXE Module System
.link arch.events Event Model
.link arch.fonts Font System
.link arch.colors Color System
.link arch.platform Platform Layer
.link arch.build Build System

.topic arch.layers
.title Five-Layer Architecture
.toc 1 Five-Layer Architecture
.index Layers
.index dvxVideo
.index dvxDraw
.index dvxComp
.index dvxWm
.index dvxApp

.h1 Five-Layer Architecture

DVX is organized into five layers, each implemented as a single .h/.c pair. Every header includes dvxTypes.h (the shared type definitions) to avoid circular dependencies. The layers are strictly stacked: each layer depends only on the layers below it.

.code
 Applications (DXE .app modules)
 ==================================================
 |                                                |
 |  +------------------------------------------+  |
 |  |  Layer 5: dvxApp  (Application API)      |  |  dvxApp.h / dvxApp.c
 |  |  Event loop, window creation, public API  |  |
 |  +------------------------------------------+  |
 |  |  Layer 4: dvxWm   (Window Manager)       |  |  dvxWm.h / dvxWm.c
 |  |  Window stack, chrome, drag, resize      |  |
 |  +------------------------------------------+  |
 |  |  Layer 3: dvxComp  (Compositor)          |  |  dvxComp.h / dvxComp.c
 |  |  Dirty rect tracking, merge, LFB flush   |  |
 |  +------------------------------------------+  |
 |  |  Layer 2: dvxDraw  (Drawing Primitives)  |  |  dvxDraw.h / dvxDraw.c
 |  |  Rects, bevels, text, blits, cursors     |  |
 |  +------------------------------------------+  |
 |  |  Layer 1: dvxVideo (Video Backend)       |  |  dvxVideo.h / dvxVideo.c
 |  |  VESA VBE, LFB mapping, pixel format     |  |
 |  +------------------------------------------+  |
 |                                                |
 |  +------------------------------------------+  |
 |  |  Platform Layer (dvxPlat.h)              |  |  dvxPlatformDos.c
 |  |  OS-specific: video, input, asm spans    |  |
 |  +------------------------------------------+  |
 |                                                |
 |  +------------------------------------------+  |
 |  |  Shared Types (dvxTypes.h)               |  |
 |  |  DisplayT, WindowT, RectT, ColorSchemeT  |  |
 |  +------------------------------------------+  |
 ==================================================
.endcode

.h2 Layer Summary

.table
  Layer               Header         Responsibility
  -----               ------         --------------
  1 - Video           dvxVideo.h     VESA VBE mode negotiation, LFB mapping via DPMI, backbuffer allocation, packColor() (RGB to native pixel format), display-wide clip rectangle.
  2 - Draw            dvxDraw.h      All 2D drawing: rectFill, rectCopy, drawBevel, drawText/drawTextN, drawMaskedBitmap (cursor), drawTermRow (batch terminal row). Stateless beyond clip rect. Dispatches hot inner loops through BlitOpsT function pointers.
  3 - Compositor      dvxComp.h      Dirty rectangle tracking (dirtyListAdd), pairwise merge of overlapping rects (dirtyListMerge), and flushRect to copy dirty regions from backBuf to LFB.
  4 - Window Manager  dvxWm.h        Window lifecycle, Z-order stack, chrome drawing (title bars, bevels, close/minimize/maximize gadgets), hit testing, drag/resize, menu bars, scrollbars, system menu, keyboard move/resize, minimized icon bar.
  5 - Application     dvxApp.h       Public API aggregating all layers into AppContextT. Provides dvxInit/dvxShutdown, dvxRun/dvxUpdate, window creation helpers, image loading, clipboard, accelerator tables, theme management, wallpaper, video mode switching, screenshot capture.
.endtable

.topic arch.pipeline
.title Display Pipeline
.toc 1 Display Pipeline
.index Display Pipeline
.index Backbuffer
.index Linear Framebuffer
.index LFB
.index Dirty Rects
.index Double Buffer
.index Compositing

.h1 Display Pipeline

The double-buffer strategy is the single most important performance decision in DVX. All drawing goes to a system RAM backbuffer (DisplayT.backBuf); only dirty rectangles are flushed to the linear framebuffer (DisplayT.lfb) in video memory.

This matters because writes to video memory over the PCI bus are 10-50x slower than writes to main RAM on 486/Pentium hardware for random-access patterns.

.h2 Per-Frame Compositing Pipeline

.code
  1. Input poll (mouse, keyboard)
         |
  2. Event dispatch (focus window callbacks)
         |
  3. Layers call dirtyListAdd() for changed regions
         |
  4. dirtyListMerge() consolidates overlapping rects
         |
  5. For each merged dirty rect:
     a. Clip and redraw desktop background (or wallpaper)
     b. For each window (back-to-front, painter's algorithm):
        - wmDrawChrome()   -- frame, title bar, gadgets, menu bar
        - wmDrawContent()  -- blit per-window content buffer
        - wmDrawScrollbars()
     c. Draw minimized window icons
     d. Draw popup menus / tooltips (overlay pass)
     e. Draw software mouse cursor
         |
  6. flushRect() -- copy each dirty rect from backBuf to LFB
         |
  7. Yield (platformYield)
.endcode

.h2 Key Data Structures

.index DisplayT
.index BlitOpsT
.index DirtyListT

DisplayT -- Central display context: width, height, pitch, pixel format, LFB pointer, backbuffer pointer, palette, clip rectangle. Passed by pointer through every layer -- no globals.

BlitOpsT -- Vtable of span fill/copy function pointers resolved at init time for the active pixel depth. On DOS these dispatch to hand-written rep stosl / rep movsd asm inner loops.

DirtyListT -- Fixed-capacity dynamic array of RectT. Linear scanning for merge candidates is cache-friendly at typical sizes (under 128 rects). If the list fills up, the compositor merges aggressively or falls back to full-screen repaint.

.h2 Why This Works on a 486

.list
.item A full 640x480x32bpp frame is 1.2 MB -- far too much to flush every frame over a slow PCI bus.
.item A typical dirty region during normal interaction (typing, menu open) is a few KB.
.item Merging overlapping dirty rects into larger rects reduces per-rect overhead and improves bus utilization.
.item Per-window content buffers persist across frames, so windows don't repaint on expose -- only when their own content changes.
.endlist

.topic arch.windows
.title Window System
.toc 1 Window System
.index Window
.index WindowT
.index Z-Order
.index Chrome
.index Hit Testing
.index Menu System
.index Minimized Windows

.h1 Window System

.h2 WindowT Structure

Each WindowT is the central object of the window manager. Key fields:

.table
  Field Group                              Purpose
  -----------                              -------
  Geometry (x, y, w, h)                   Outer frame rectangle (including chrome).
  Content area (contentX/Y/W/H)           Computed from frame minus chrome. Where application content lives.
  Content buffer (contentBuf, contentPitch) Per-window backbuffer in native pixel format. Persists across frames.
  Chrome state (menuBar, vScroll, hScroll) Optional menu bar and scrollbars. Affect content area computation.
  Widget tree (widgetRoot)                 Root of the retained-mode widget tree (NULL if using raw callbacks).
  Callbacks                                onPaint, onKey, onKeyUp, onMouse, onResize, onClose, onMenu, onScroll, onFocus, onBlur, onCursorQuery.
.endtable

.h2 Window Stack (Z-Order)

.index Window Stack

WindowStackT is an array of WindowT* ordered front-to-back: index count-1 is the topmost window. This allows:

.list
.item Back-to-front iteration for painting (painter's algorithm).
.item Front-to-back iteration for hit testing (first hit wins).
.item Reordering by pointer swap (no copying of large WindowT structs).
.endlist

Only one drag/resize/scroll operation can be active system-wide at a time (single mouse), so that state lives on the stack, not on individual windows.

.h2 Chrome Layout

.code
  +-------------------------------------------+
  |  4px outer border (raised bevel)          |
  |  +-------------------------------------+  |
  |  | [X] Title Bar Text     [_] [^] [X]  |  |  20px title height
  |  +-------------------------------------+  |
  |  | 2px inner border                    |  |
  |  +-------------------------------------+  |
  |  | Menu Bar (optional, 20px)           |  |
  |  +-------------------------------------+  |
  |  |                                     |  |
  |  |          Content Area               |  |
  |  |                                     |  |
  |  |                               |  S  |  |  S = vertical scrollbar
  |  |                               |  B  |  |      (16px wide)
  |  +-------------------------------------+  |
  |  |  Horizontal Scrollbar (optional)    |  |  16px tall
  |  +-------------------------------------+  |
  |  4px outer border                         |
  +-------------------------------------------+
.endcode

Chrome constants are compile-time defines:

.code
  CHROME_BORDER_WIDTH   = 4px
  CHROME_TITLE_HEIGHT   = 20px
  CHROME_INNER_BORDER   = 2px
  CHROME_MENU_HEIGHT    = 20px
  SCROLLBAR_WIDTH       = 16px
  CHROME_CLOSE_BTN_SIZE = 16px
.endcode

.h2 Hit Test Regions

wmHitTest() iterates the stack front-to-back and returns a hit-part identifier: HIT_CONTENT, HIT_TITLE, HIT_CLOSE, HIT_RESIZE, HIT_MENU, HIT_VSCROLL, HIT_HSCROLL, HIT_MINIMIZE, HIT_MAXIMIZE. Resize edge detection returns a bitmask of RESIZE_LEFT, RESIZE_RIGHT, RESIZE_TOP, RESIZE_BOTTOM (corners combine two edges).

.h2 Menu System

.index Menus
.index Submenus

Menus use fixed-size inline char buffers for labels (MAX_MENU_LABEL = 32, no heap strings). Both menus per bar and items per menu are stored in dynamic arrays that grow on demand. Supports cascading submenus via MenuItemT.subMenu pointer. Item types: normal, checkbox, radio. Separators are non-interactive items. The popup state (PopupStateT) tracks a stack of parent frames for cascading submenu nesting.

.h2 Minimized Windows

Minimized windows display as 64x64 icons at the bottom of the screen with beveled borders, similar to a classic desktop icon bar. Icons show a scaled-down preview of the window's content buffer, refreshed one per frame in a round-robin fashion to amortize the scaling cost.

.topic arch.widgets
.title Widget System
.toc 1 Widget System
.index Widgets
.index WidgetT
.index WidgetClassT
.index Layout Engine
.index Widget API

.h1 Widget System

The widget system (dvxWgt.h) is a retained-mode toolkit layered on top of the window manager. Widgets form a tree rooted at a per-window VBox container.

.h2 WidgetT Base Structure

Every widget shares the same WidgetT struct. The type field is a runtime-assigned integer ID. The wclass pointer references the widget's WidgetClassT vtable. Widget-specific private data is stored in w->data (opaque void*).

Tree linkage: parent, firstChild, lastChild, nextSibling. No prevSibling -- this halves pointer overhead and removal is still O(n) for typical tree depths of 5-10.

.h2 Layout Engine

.index Layout
.index Flexbox

Two-pass flexbox-like algorithm:

.list
.item Bottom-up (calcMinSize) -- compute minimum sizes for every widget, starting from leaves.
.item Top-down (layout) -- allocate space within available bounds, distributing extra space according to weight values (0 = fixed, 100 = normal stretch).
.endlist

Size hints use a tagged encoding: the top 2 bits of an int32_t select the unit (pixels, character widths, or percentage of parent), the low 30 bits hold the value. Macros: wgtPixels(v), wgtChars(v), wgtPercent(v).

.h2 Widget Class Dispatch (WidgetClassT)

Each widget type provides a WidgetClassT with a handlers[] array indexed by stable method IDs. Method IDs are never reordered or reused -- new methods append at the end. This provides ABI-stable dispatch so that widget DXEs compiled against an older DVX version continue to work.

Methods include: PAINT, PAINT_OVERLAY, CALC_MIN_SIZE, LAYOUT, ON_MOUSE, ON_KEY, ON_ACCEL_ACTIVATE, DESTROY, GET_TEXT, SET_TEXT, POLL, and more (21 defined, room for 32).

.h3 Class Flags

.table
  Flag                    Meaning
  ----                    -------
  WCLASS_FOCUSABLE        Can receive keyboard focus (Tab navigation)
  WCLASS_HORIZ_CONTAINER  Lays out children horizontally (HBox)
  WCLASS_PAINTS_CHILDREN  Widget handles child rendering itself
  WCLASS_SCROLLABLE       Accepts mouse wheel events
  WCLASS_SCROLL_CONTAINER ScrollPane -- scrolling viewport
  WCLASS_NEEDS_POLL       Needs periodic polling (e.g. AnsiTerm comms)
  WCLASS_SWALLOWS_TAB     Tab key goes to widget, not focus navigation
  WCLASS_PRESS_RELEASE    Click = press + release (buttons)
.endtable

.h2 Available Widget Types

Each widget is a separate .wgt DXE module. 29 widget types are included:

.table
  Widget                  Description
  ------                  -----------
  Box (VBox/HBox)         Vertical and horizontal layout containers
  Button                  Clickable push button with label
  Canvas                  Raw drawing surface for custom painting
  Checkbox                Boolean toggle with checkmark
  ComboBox                Text input with dropdown list
  DataCtrl                Data-bound control for database operations
  DbGrid                  Database grid (tabular data display)
  Dropdown                Dropdown selection list
  Image                   Static image display
  ImageButton             Button with bitmap icon
  Label                   Static text label
  ListBox                 Scrollable selection list
  ListView                Multi-column list with headers and sorting
  ProgressBar             Determinate progress indicator
  Radio                   Radio button (mutual exclusion group)
  ScrollPane              Scrollable viewport container
  Separator               Visual divider line
  Slider                  Value selection via draggable thumb
  Spacer                  Empty space for layout
  Spinner                 Numeric input with up/down arrows
  Splitter                Resizable split pane
  StatusBar               Window status bar with sections
  TabControl              Tabbed page container
  Terminal (AnsiTerm)     ANSI terminal emulator widget
  TextInput               Single-line text entry field
  Timer                   Periodic timer events
  Toolbar                 Toolbar with icon buttons
  TreeView                Hierarchical tree display
  WrapBox                 Flow layout (wrapping horizontal container)
.endtable

.h2 Widget API Registry

Each widget DXE registers a small API struct under a name during wgtRegister(). Callers retrieve it via wgtGetApi("button") and cast to the widget-specific API type. Per-widget headers provide typed accessors so callers avoid manual casts. Adding a new widget requires zero changes to the core.

.h2 Widget Interface Descriptors (WgtIfaceT)

.index WgtIfaceT

Each widget can register an interface descriptor that describes its BASIC-facing properties, methods, and events. These descriptors are used by the form runtime and IDE for generic dispatch and property panel enumeration. Properties have typed getters/setters (WGT_IFACE_STRING, WGT_IFACE_INT, WGT_IFACE_BOOL, WGT_IFACE_ENUM).

.topic arch.dialogs
.title Modal Dialogs
.toc 1 Modal Dialogs
.index Dialogs
.index Message Box
.index File Dialog
.index Input Box

.h1 Modal Dialogs (dvxDlg.h)

Pre-built modal dialog boxes block the caller and run their own event loop via dvxUpdate() until the user dismisses them. Each dialog sets ctx->modalWindow to prevent input from reaching other windows while open.

.h2 Dialog Types

.table
  Function              Purpose
  --------              -------
  dvxMessageBox         Generic message box with button/icon flags (MB_OK, MB_YESNO, MB_ICONERROR, etc.)
  dvxErrorBox           Shortcut for MB_OK + MB_ICONERROR
  dvxInfoBox            Shortcut for MB_OK + MB_ICONINFO
  dvxFileDialog         File open/save dialog with directory navigation and filter dropdown
  dvxInputBox           Single-line text input with OK/Cancel
  dvxIntInputBox        Integer input with spinner, clamp range, and step
  dvxChoiceDialog       List selection with OK/Cancel
  dvxPromptSave         Canonical "Save changes?" Yes/No/Cancel dialog
.endtable

.h2 Flag Encoding

dvxMessageBox flags split into two nibbles: button configuration (low) and icon type (high). This matches the Win16 MessageBox() convention so OR'd flags read naturally:

.code
dvxMessageBox(ctx, "Confirm", "Delete file?", MB_YESNO | MB_ICONQUESTION);
.endcode

Return values are ID_OK / ID_CANCEL / ID_YES / ID_NO / ID_RETRY.

.topic arch.resources
.title Resource System
.toc 1 Resource System
.index Resources
.index DXE Resources
.index DvxResHandleT

.h1 Resource System (dvxRes.h)

Resources are appended to DXE3 files (.app, .wgt, .lib) after the normal DXE content. The DXE loader never reads past the DXE header, so the appended data is invisible to dlopen. Every DXE can carry its own icons, text strings, and binary data without separate resource files.

.h2 On-Disk Layout

.code
[DXE3 content]           -- untouched, loaded by dlopen
[resource data entries]  -- sequential, variable length
[resource directory]     -- fixed-size entries (48 bytes each)
[footer]                 -- magic + directory offset + count (16 bytes)
.endcode

Readers start from the end: seek to EOF - sizeof(footer), verify the magic (DVX_RES_MAGIC = "DVXR"), then seek to the directory. Entries are sorted at open time so lookups are O(log n) via bsearch.

.h2 Types

.table
  Type ID           Value   Payload
  -------           -----   -------
  DVX_RES_ICON      1       Image data (BMP or PNG, typically 16x16 or 32x32 icons)
  DVX_RES_TEXT      2       Null-terminated string (localisable UI text, author, copyright)
  DVX_RES_BINARY    3       Arbitrary data (app-specific)
.endtable

.h2 Runtime API

.table
  Function           Description
  --------           -----------
  dvxResOpen         Open a handle by reading the footer and directory
  dvxResRead         Look up a resource by name and read its data into a malloc'd buffer
  dvxResFind         Look up a resource's directory entry (no data copy)
  dvxResClose        Release the handle
  dvxResAppend       Append a new resource to a DXE file
  dvxResRemove       Remove a resource by name
.endtable

The dvxApp.h wrappers (dvxResLoadIcon, dvxResLoadText, dvxResLoadData) combine open + read + close for the common case.

.topic arch.prefs
.title Preferences System
.toc 1 Preferences System
.index Preferences
.index INI files
.index PrefsHandleT

.h1 Preferences System (dvxPrefs.h)

Handle-based API over classic INI files. Multiple files can be open at once. Each prefsLoad / prefsCreate returns a PrefsHandleT opaque pointer passed to subsequent calls and freed with prefsClose. The system INI lives at DVX_INI_PATH = "CONFIG\\DVX.INI".

.h2 Usage Pattern

.code
PrefsHandleT *h = prefsLoad(DVX_INI_PATH);
int32_t  w      = prefsGetInt(h, "video", "width", 640);
bool     sound  = prefsGetBool(h, "audio", "enable", true);
const char *bg  = prefsGetString(h, "desktop", "wallpaper", "");

prefsSetInt(h, "video", "width", 800);
prefsSave(h);
prefsClose(h);
.endcode

Boolean getters recognise "true"/"yes"/"1" and "false"/"no"/"0" (case-insensitive). If the file does not exist, prefsLoad still returns a valid empty handle with the path captured so prefsSave can write a new file.

.topic arch.memtrack
.title Per-App Memory Tracking
.toc 1 Per-App Memory Tracking
.index Memory Tracking
.index dvxMalloc
.index dvxFree

.h1 Per-App Memory Tracking (dvxMem.h)

All allocations route through dvxMalloc/dvxFree wrappers that prepend a 16-byte header recording the owning app ID and allocation size. The Task Manager displays per-app memory usage, and leaks are detected at app termination.

.h2 Transparent Interception

DXE code does NOT need to include dvxMem.h. The DXE export table maps malloc / free / calloc / realloc / strdup to the dvxXxx wrappers, so standard C code is tracked automatically.

Explicit use (e.g. in the Task Manager) can include dvxMem.h to call:

.table
  Function               Purpose
  --------               -------
  dvxMemSnapshotLoad     Baseline a newly-loaded app's memory state
  dvxMemGetAppUsage      Query current bytes allocated for an app
  dvxMemResetApp         Free every tracked allocation charged to an app
.endtable

The dvxMemAppIdPtr pointer is set by the shell to &ctx->currentAppId so the allocator always knows which app to charge.

.topic arch.dxe
.title DXE Module System
.toc 1 DXE Module System
.index DXE
.index DXE3
.index Modules
.index Dynamic Loading

.h1 DXE Module System

DVX uses DJGPP's DXE3 (Dynamic eXtension) format for all loadable modules. DXE3 supports RTLD_GLOBAL symbol sharing -- symbols exported by one module are visible to all subsequently loaded modules. This is critical: widget DXEs call core API functions (e.g. rectFill, wgtInvalidate) that are exported by the core library DXE.

.h2 Module Types

.table
  Extension  Directory   Purpose                                             Examples
  ---------  ---------   -------                                             --------
  .lib       LIBS/       Core libraries loaded first. Provide infrastructure APIs.  libtasks.lib, libdvx.lib, dvxshell.lib
  .wgt       WIDGETS/    Widget type plugins. Each exports wgtRegister().    button.wgt, listview.wgt, terminal.wgt
  .app       APPS/*/     Application modules. Each exports appDescriptor and appMain(). Loaded on demand by the shell.  progman.app, notepad.app, cpanel.app
.endtable

.h2 Boot Sequence

.index Boot Sequence

.code
  dvx.exe (loader)
     |
     +-- Enter VGA mode 13h, display splash screen with progress bar
     |
     +-- Scan LIBS/ for *.lib, WIDGETS/ for *.wgt
     |
     +-- Read .dep files for each module (dependency base names)
     |
     +-- Topological sort: load modules in dependency order
     |     - dlopen() with RTLD_GLOBAL
     |     - Each .wgt that exports wgtRegister() has it called
     |
     +-- Find and call shellMain() (exported by dvxshell.lib)
           |
           +-- dvxInit() -- video mode, input, font, colors, cursors
           |
           +-- Load desktop app (progman.app)
           |
           +-- Main loop:
                 dvxUpdate() -> tsYield() -> shellReapApps()
.endcode

.h2 Application Lifecycle

Two kinds of DXE apps:

.h3 Callback-only (hasMainLoop = false)

appMain() creates windows, registers callbacks, and returns. The app lives through GUI callbacks driven by the shell's main loop. Lifecycle ends when the last window is closed. No extra task stack needed -- simpler and cheaper.

.h3 Main-loop (hasMainLoop = true)

A dedicated cooperative task is created. appMain() runs in that task with its own loop, calling tsYield() to share CPU. Needed for apps with continuous work (terminal emulators, games). Lifecycle ends when appMain() returns.

.h2 Crash Recovery

.index Crash Recovery

The platform layer installs signal handlers for SIGSEGV, SIGFPE, SIGILL. On crash, the handler logs platform-specific diagnostics (register dump on DJGPP), then longjmps back to the shell's main loop. The crashed app is killed; other apps and the shell survive. This provides Windows 3.1-style fault tolerance.

.h2 Per-App Memory Tracking

.index Memory Tracking

All allocations route through dvxMalloc/dvxFree wrappers that prepend a 16-byte header recording the owning app ID and allocation size. The Task Manager displays per-app memory usage, and leaks are detected at app termination.

.topic arch.events
.title Event Model
.toc 1 Event Model
.index Events
.index Input
.index Mouse
.index Keyboard
.index Polling
.index Cooperative

.h1 Event Model

DVX uses a cooperative polling model. The main loop (dvxRun / dvxUpdate) runs this cycle each frame:

.list
.item Poll mouse -- platformMousePoll() returns position and button bitmask. Compare with previous frame for press/release edge detection.
.item Poll keyboard -- platformKeyboardRead() returns ASCII + scancode. Non-blocking; returns false if buffer is empty.
.item Dispatch to focused window -- the event loop fires window callbacks (onKey, onMouse, etc.) on the focused window. If the window has a widget tree, the widget system's installed handlers dispatch to individual widgets.
.item Compositor pass -- merge dirty rects, composite, flush to LFB.
.item Yield -- platformYield() or idle callback.
.endlist

.h2 Event Dispatch Chain

.index Event Dispatch

.code
  Mouse/Keyboard Input
       |
  Global handlers (Ctrl+Esc, modal filter)
       |
  Accelerator table check (focused window)
       |
  Window callback (onMouse / onKey)
       |
  [If widget tree installed:]
       |
  widgetOnMouse / widgetOnKey
       |
  Widget hit test (widgetHitTest)
       |
  wclsOnMouse / wclsOnKey (vtable dispatch)
       |
  Universal callbacks (onClick, onChange, etc.)
.endcode

.h2 Accelerator Tables

.index Accelerator Tables

Per-window accelerator tables map key + modifier combinations to command IDs. The runtime normalizes key/modifier at registration time (uppercase key, strip shift from modifiers) so matching at dispatch time is two integer comparisons per entry. Matched accelerators fire the window's onMenu callback with the command ID, unifying the menu and hotkey code paths.

.h2 Mouse Cursor

.index Cursor

Software-rendered cursor using the classic AND/XOR mask approach. Seven cursor shapes are compiled in: arrow, horizontal resize, vertical resize, NW-SE diagonal resize, NE-SW diagonal resize, busy (hourglass), and crosshair. The cursor is painted into the backbuffer on top of the composited frame and the affected region is flushed to the LFB each frame.

.h2 Double-Click Detection

.index Double-Click

Timestamp-based: two clicks on the same target (title bar, minimized icon, close gadget) within the configurable double-click interval trigger the double-click action. Separate tracking for each target type.

.topic arch.fonts
.title Font System
.toc 1 Font System
.index Fonts
.index Bitmap Font
.index BitmapFontT
.index Text Rendering
.index CP437

.h1 Font System

DVX uses fixed-width 8-pixel-wide bitmap fonts only. One size is provided: 8x16, matching the standard VGA ROM font and CP437 encoding (256 glyphs).

.h2 BitmapFontT

.code
  typedef struct {
      int32_t        charWidth;    // fixed width per glyph (always 8)
      int32_t        charHeight;   // 16
      int32_t        firstChar;    // typically 0
      int32_t        numChars;     // typically 256
      const uint8_t *glyphData;    // packed 1bpp, charHeight bytes per glyph
  } BitmapFontT;
.endcode

Design rationale:

.list
.item Character positions are pure multiplication (x = col * 8).
.item Glyph lookup is a single array index.
.item Each scanline of a glyph is exactly one byte (1bpp at 8 pixels wide).
.item No glyph-width tables, kerning, or per-character positioning needed.
.item 8-pixel width aligns with byte boundaries -- no bit shifting in per-scanline rendering.
.endlist

.h2 Text Rendering Functions

drawChar() -- Renders a single character. Supports opaque (background fill) and transparent modes.

drawTextN() -- Optimized batch rendering for a known character count. Clips once for the entire run, fills background in a single rectFill, then overlays glyph foreground pixels. Significantly faster than per-character rendering for long runs.

drawTermRow() -- Renders an 80-column terminal row in a single pass, with per-cell foreground/background from a 16-color palette, blink attribute support, and cursor rendering. Exists because per-character terminal rendering is unacceptably slow on target hardware.

drawTextAccel() -- Renders text with & accelerator markers. The character after & is underlined to indicate the keyboard shortcut.

.h2 Performance Optimization

AppContextT stores a fixed-point 16.16 reciprocal of font.charHeight (charHeightRecip) so that dividing by charHeight (for pixel-to-row conversion in terminal/text widgets) becomes a multiply+shift instead of an integer divide, which costs 40+ cycles on a 486.

.topic arch.colors
.title Color System
.toc 1 Color System
.index Colors
.index Pixel Format
.index PixelFormatT
.index ColorSchemeT
.index Theming
.index Bevel

.h1 Color System

.h2 Pixel Format

PixelFormatT describes the active VESA mode's pixel encoding. Populated once from the VBE mode info block. Stores shift, mask, and bit count for each channel so packColor() can convert RGB to native format with shift-and-mask arithmetic -- no per-pixel computation.

Supported depths:

.table
  Depth    Bytes/Pixel  Notes
  -----    -----------  -----
  8 bpp    1            Palette mode. Nearest-index via 6x6x6 color cube + grey ramp.
  15 bpp   2            5-5-5 RGB (1 bit unused).
  16 bpp   2            5-6-5 RGB.
  32 bpp   4            8-8-8 RGB (8 bits unused).
.endtable

.h2 ColorSchemeT -- Theming

All 20 UI colors are pre-packed into display pixel format at init time. Every color is a uint32_t that can be written directly to the framebuffer with zero per-pixel conversion. The scheme must be regenerated on video mode change, but mode changes require re-init anyway.

Color roles mirror classic Motif/Windows 3.x conventions:

.list
.item desktop -- desktop background
.item windowFace, windowHighlight, windowShadow -- window chrome bevel triplet
.item activeTitleBg/Fg, inactiveTitleBg/Fg -- focused vs. unfocused title bar
.item contentBg/Fg -- window content area
.item menuBg/Fg, menuHighlightBg/Fg -- menus
.item buttonFace -- button background
.item scrollbarBg/Fg/Trough -- scrollbar components
.item cursorFg/Bg -- mouse cursor colors
.endlist

Source RGB values are kept in AppContextT.colorRgb[] for theme save/load. Themes are stored as INI files with a [colors] section. The API provides dvxLoadTheme(), dvxSaveTheme(), dvxSetColor(), and dvxResetColorScheme().

.h2 Bevel Styles

Bevels are the defining visual element of the Motif aesthetic. Convenience macros create bevel style descriptors by swapping highlight and shadow colors:

.code
  BEVEL_RAISED(colorScheme, borderWidth)       -- raised 3D look
  BEVEL_SUNKEN(colorScheme, face, borderWidth) -- sunken/inset look
  BEVEL_TROUGH(colorScheme)                    -- 1px scrollbar trough
  BEVEL_SB_BUTTON(colorScheme)                 -- scrollbar button
.endcode

.topic arch.platform
.title Platform Layer
.toc 1 Platform Layer
.index Platform Layer
.index dvxPlat.h
.index VESA
.index VBE
.index INT 33h
.index INT 16h
.index Assembly
.index rep stosl
.index rep movsd

.h1 Platform Layer

All OS-specific and CPU-specific code is isolated behind platform/dvxPlat.h. To port DVX, implement a new dvxPlatformXxx.c against this header.

.h2 Implementations

.table
  File                Target        Details
  ----                ------        -------
  dvxPlatformDos.c    DJGPP/DPMI    Real VESA VBE, INT 33h mouse, INT 16h keyboard, rep movsd/rep stosl asm spans, DPMI physical memory mapping for LFB, INT 9 hook for key-up, CuteMouse Wheel API.
.endtable

.h2 Abstraction Areas

.h3 Video

platformVideoInit() -- mode probe and framebuffer setup. platformVideoShutdown() -- restore previous mode. platformVideoEnumModes() -- enumerate available modes.

.h3 Framebuffer Flush

platformFlushRect() -- copy dirty rect from backBuf to LFB. On DOS, each scanline uses rep movsd for near-optimal aligned 32-bit writes over the PCI bus.

.h3 Optimized Memory Spans

Six functions: platformSpanFill8/16/32() and platformSpanCopy8/16/32(). Called once per scanline of every rectangle fill, blit, and text draw. On DOS these use inline assembly for critical inner loops.

.h3 Mouse Input

Polling model. platformMousePoll() returns position and button bitmask. Wheel support via CuteMouse API.

.h3 Keyboard Input

platformKeyboardRead() -- non-blocking key read. platformKeyUpRead() -- key release detection (requires INT 9 hook on DOS). platformAltScanToChar() -- scancode-to-ASCII lookup for Alt+key combinations.

.h3 Crash Recovery

platformInstallCrashHandler() -- signal handlers + longjmp for fault tolerance.

.h3 DXE Support

platformRegisterDxeExports() -- register C runtime and platform symbols for DXE resolution. platformRegisterSymOverrides() -- register function pointer overrides for module loader.

.topic arch.build
.title Build System
.toc 1 Build System
.index Build
.index Makefile
.index Cross-Compilation
.index dxe3gen
.index mkcd.sh
.index ISO

.h1 Build System

.h2 Cross-Compilation

DVX is cross-compiled from Linux using a DJGPP cross-compiler (i586-pc-msdosdjgpp-gcc). The top-level Makefile orchestrates building all subsystems in dependency order.

.code
  make               -- build everything
  ./mkcd.sh          -- build + create ISO for the target emulator
.endcode

.h2 Build Targets

.code
  all: core tasks loader texthelp listhelp tools widgets shell taskmgr serial sql apps
.endcode

.table
  Target     Output                    Description
  ------     ------                    -----------
  core       bin/libs/libdvx.lib       GUI core library (draw, comp, wm, app, widget infrastructure)
  tasks      bin/libs/libtasks.lib     Cooperative task switcher
  loader     bin/dvx.exe               Bootstrap loader (the DOS executable)
  widgets    bin/widgets/*.wgt         29 widget type plugins
  shell      bin/libs/dvxshell.lib     DVX Shell (app management, desktop)
  taskmgr    bin/libs/taskmgr.lib      Task Manager (loaded as a separate DXE)
  texthelp   shared library            Shared text editing helpers (clipboard, word boundaries)
  listhelp   shared library            Shared dropdown/list helpers
  apps       bin/apps/*/*.app          Application modules (progman, notepad, clock, etc.)
  tools      bin/dvxres                Resource compiler (runs on Linux, builds resource sections into DXEs)
  serial     serial DXE libs           UART driver, HDLC packets, security, seclink
  sql        SQL DXE lib               SQLite integration
.endtable

.h2 DXE3 Build Process

Each DXE module is compiled to an object file with GCC, then linked with dxe3gen:

.code
  # Compile
  i586-pc-msdosdjgpp-gcc -O2 -march=i486 -mtune=i586 -c -o widget.o widget.c

  # Link as DXE (exports all non-static symbols)
  dxe3gen -o widget.wgt -U widget.o

  # Optionally append resources
  dvxres build widget.wgt widget.res
.endcode

The -E flag specifies exported symbols (prefixed with underscore per DJGPP convention). -U marks unresolved symbols as OK (they'll be resolved at load time from previously loaded DXEs).

.h2 Deployment (mkcd.sh)

.list
.item Runs make all.
.item Verifies critical outputs exist (dvx.exe, libtasks.lib, libdvx.lib, dvxshell.lib).
.item Counts widget modules.
.item Creates an ISO 9660 image from bin/ using mkisofs: -iso-level 1 (strict 8.3 filenames for DOS), -J (Joliet extensions for long names), -V DVX (volume label).
.item Places the ISO at the target emulator's CD-ROM mount path.
.endlist

.h2 Compiler Flags

.code
  -O2                  Optimization level 2
  -march=i486          486 instruction set baseline
  -mtune=i586          Optimize scheduling for Pentium
  -Wall -Wextra        Full warnings
.endcode

.h2 Directory Layout

.code
  dvxgui/
  +-- core/              Core library sources (dvxVideo, dvxDraw, dvxComp, dvxWm, dvxApp, widget infra)
  |   +-- platform/      Platform abstraction (dvxPlat.h, dvxPlatformDos.c, dvxPlatformUtil.c)
  |   +-- thirdparty/    stb_image, stb_ds, stb_image_write
  +-- loader/            Bootstrap loader (dvx.exe)
  +-- tasks/             Cooperative task switcher (libtasks.lib)
  +-- shell/             DVX Shell (dvxshell.lib)
  +-- widgets/           Widget DXE modules (*.wgt), each in its own subdirectory
  |   +-- box/           VBox/HBox layout containers
  |   +-- button/        Push button
  |   +-- textInput/     Text entry field
  |   +-- listView/      Multi-column list
  |   +-- ...            (29 widget types total)
  +-- texthelp/          Shared text editing helpers
  +-- listhelp/          Shared dropdown/list helpers
  +-- apps/              Application DXE modules (*.app)
  |   +-- progman/       Program Manager (desktop)
  |   +-- notepad/       Text editor
  |   +-- cpanel/        Control Panel
  |   +-- imgview/       Image viewer
  |   +-- clock/         Clock
  |   +-- dvxdemo/       Demo / showcase app
  |   +-- dvxbasic/      DVX BASIC compiler and VM
  +-- tools/             Build tools (dvxres resource compiler)
  +-- rs232/             ISR-driven UART driver
  +-- packet/            HDLC framing, CRC-16, sliding window
  +-- security/          DH key exchange, XTEA cipher, DRBG RNG
  +-- seclink/           Encrypted channel wrapper
  +-- serial/            Combined serial stack DXE
  +-- proxy/             Linux proxy (emulator <-> secLink <-> telnet)
  +-- sql/               SQLite integration
  +-- bin/               Build output (dvx.exe, libs/, widgets/, apps/, config/)
  +-- obj/               Intermediate object files
  +-- docs/              Documentation
.endcode
