| .. | ||
| platform | ||
| thirdparty | ||
| apiref.dhs | ||
| arch.dhs | ||
| dvxApp.c | ||
| dvxApp.h | ||
| dvxComp.c | ||
| dvxComp.h | ||
| dvxCur.h | ||
| dvxDialog.c | ||
| dvxDlg.h | ||
| dvxDraw.c | ||
| dvxDraw.h | ||
| dvxFont.h | ||
| dvxImage.c | ||
| dvxImageWrite.c | ||
| dvxMem.h | ||
| dvxPal.h | ||
| dvxPrefs.c | ||
| dvxPrefs.h | ||
| dvxRes.h | ||
| dvxResource.c | ||
| dvxTypes.h | ||
| dvxVideo.c | ||
| dvxVideo.h | ||
| dvxWgt.h | ||
| dvxWgtP.h | ||
| dvxWm.c | ||
| dvxWm.h | ||
| Makefile | ||
| README.md | ||
| sysdoc.dhs | ||
| widgetClass.c | ||
| widgetCore.c | ||
| widgetEvent.c | ||
| widgetLayout.c | ||
| widgetOps.c | ||
| widgetScrollbar.c | ||
DVX Core Library (libdvx.lib)
The core GUI infrastructure for DVX, built as a DXE3 module. Provides
VESA video setup, 2D drawing primitives, dirty-rectangle compositing,
a window manager with Motif-style chrome, and the widget infrastructure
(layout engine, event dispatch, class registration). Individual widget
type implementations live in ../widgets/ as separate .wgt DXE
modules that register themselves at runtime via wgtRegisterClass().
Core knows nothing about individual widget types. There is no WidgetTypeE enum, no widget union, and no per-widget structs in dvxWidget.h. All widget-specific behavior is dispatched through the WidgetClassT dispatch table.
5-Layer Architecture
| Layer | Header | Source | Description |
|---|---|---|---|
| 1. Video | dvxVideo.h |
dvxVideo.c |
VESA VBE init, LFB mapping, backbuffer, pixel format, packColor() |
| 2. Draw | dvxDraw.h |
dvxDraw.c |
Rect fills, bevels, text, bitmap cursors, focus rects, lines |
| 3. Compositor | dvxComp.h |
dvxComp.c |
Dirty rect tracking, merge, clip, LFB flush |
| 4. Window Manager | dvxWm.h |
dvxWm.c |
Window stack, chrome, drag/resize, menus, scrollbars, hit test |
| 5. Application | dvxApp.h |
dvxApp.c |
Event loop, input polling, color schemes, wallpaper, public API |
Additional modules built into libdvx.lib:
| Header | Source | Description |
|---|---|---|
dvxDialog.h |
dvxDialog.c |
Modal message box and file open/save dialogs |
dvxPrefs.h |
dvxPrefs.c |
INI-based preferences (read/write with typed accessors) |
dvxResource.h |
dvxResource.c |
Resource system -- icons, text, and binary data appended to DXE files |
dvxMem.h |
(header only) | Per-app memory tracking API declarations |
dvxWidget.h |
widgetClass.c, widgetCore.c, widgetEvent.c, widgetLayout.c, widgetOps.c, widgetScrollbar.c |
Widget infrastructure |
dvxWidgetPlugin.h |
(header only) | Plugin API for widget DXE modules |
| -- | dvxImage.c |
Image loading via stb_image (BMP, PNG, JPEG, GIF) |
| -- | dvxImageWrite.c |
PNG export via stb_image_write |
Source Files
| File | Description |
|---|---|
dvxVideo.c |
VESA mode negotiation, LFB mapping via DPMI, backbuffer alloc, packColor() |
dvxDraw.c |
rectFill(), rectCopy(), drawBevel(), drawText(), drawTextN(), drawTermRow(), cursor rendering |
dvxComp.c |
dirtyListAdd(), dirtyListMerge(), flushRect(), rectIntersect() |
dvxWm.c |
Window create/destroy, Z-order, chrome drawing, drag/resize, menu bar, scrollbars, minimize/maximize |
dvxApp.c |
dvxInit(), dvxRun(), dvxUpdate(), dvxCreateWindow(), color schemes, wallpaper, screenshots |
dvxDialog.c |
dvxMessageBox(), dvxFileDialog() -- modal dialogs with own event loops |
dvxPrefs.c |
prefsLoad(), prefsSave(), typed get/set for string/int/bool |
dvxResource.c |
dvxResOpen(), dvxResRead(), dvxResFind(), dvxResClose() -- resource system |
dvxImage.c |
dvxLoadImage(), dvxLoadImageFromMemory() -- stb_image loader, converts to native pixel format |
dvxImageWrite.c |
dvxSaveImage() -- PNG writer for screenshots |
widgetClass.c |
wgtRegisterClass(), wgtRegisterApi(), wgtGetApi(), class table |
widgetCore.c |
Widget allocation, tree ops, focus management, clipboard, hit testing, cursor blink |
widgetEvent.c |
widgetOnMouse(), widgetOnKey(), widgetOnPaint(), widgetOnResize(), scrollbar management |
widgetLayout.c |
Two-pass flexbox layout: bottom-up calcMinSize, top-down space allocation with weights |
widgetOps.c |
wgtPaint(), wgtLayout(), wgtInitWindow(), text get/set, invalidation |
widgetScrollbar.c |
Scrollbar drawing (H/V), thumb calculation, hit testing, drag update |
Public Headers
| Header | Purpose |
|---|---|
dvxTypes.h |
All shared types: DisplayT, RectT, BlitOpsT, BevelStyleT, BitmapFontT, ColorSchemeT, WindowT, MenuT, ScrollbarT, CursorT, PopupStateT |
dvxVideo.h |
videoInit(), videoShutdown(), packColor(), setClipRect(), resetClipRect() |
dvxDraw.h |
All drawing functions: rectFill(), drawBevel(), drawText(), drawTextN(), drawTermRow(), etc. |
dvxComp.h |
Dirty list operations: dirtyListAdd(), dirtyListMerge(), flushRect(), rectIntersect() |
dvxWm.h |
Window management: wmCreateWindow(), wmDestroyWindow(), wmRaiseWindow(), menus, scrollbars, chrome |
dvxApp.h |
Application API: dvxInit(), dvxRun(), dvxUpdate(), dvxCreateWindow(), color schemes, wallpaper, image I/O |
dvxDialog.h |
Modal dialogs: dvxMessageBox(), dvxFileDialog() |
dvxPrefs.h |
INI preferences: prefsLoad(), prefsSave(), typed accessors |
dvxResource.h |
Resource system: dvxResOpen(), dvxResRead(), dvxResFind(), dvxResClose() |
dvxMem.h |
Per-app memory tracking: dvxMalloc(), dvxFree(), dvxMemGetAppUsage(), etc. |
dvxWidget.h |
Widget system public API: WidgetT, WidgetClassT, size tags, layout, API registry, wclsFoo() dispatch helpers |
dvxWidgetPlugin.h |
Plugin API for widget DXE authors: tree ops, focus, scrollbar helpers, shared state |
dvxFont.h |
Embedded 8x14 and 8x16 bitmap font data (CP437) |
dvxCursor.h |
Mouse cursor AND/XOR mask data (arrow, resize H/V/diag, busy) |
dvxPalette.h |
Default 256-color VGA palette for 8-bit mode |
Platform Layer
| File | Description |
|---|---|
platform/dvxPlatform.h |
Platform abstraction API (video, input, spans, DXE, crash recovery, memory tracking) |
platform/dvxPlatformDos.c |
DJGPP/DPMI implementation (VESA VBE, INT 33h mouse, INT 16h keyboard, asm spans) |
The platform layer is compiled into dvx.exe (the loader), not into
libdvx.lib. Platform functions are exported to all DXE modules via
platformRegisterDxeExports().
Third-Party Libraries
| File | Description |
|---|---|
thirdparty/stb_image.h |
Image loading (implementation compiled into dvxImage.c) |
thirdparty/stb_image_write.h |
PNG writing (implementation compiled into dvxImageWrite.c) |
thirdparty/stb_ds.h |
Dynamic arrays/hash maps (implementation in loader, exported to all DXEs) |
Dynamic Limits
All major data structures grow dynamically via realloc. There are no fixed-size limits for:
- Windows --
WindowStackT.windowsis a dynamic array - Menus --
MenuBarT.menusandMenuT.itemsare dynamic arrays - Accelerator entries --
AccelTableT.entriesis a dynamic array - Dirty rectangles --
DirtyListT.rectsis a dynamic array - Submenu depth --
PopupStateT.parentStackis a dynamic array
The only fixed-size buffers remaining are per-element string fields
(MAX_TITLE_LEN = 128, MAX_MENU_LABEL = 32, MAX_WIDGET_NAME = 32)
and the system menu (SYS_MENU_MAX_ITEMS = 10).
Resource System
Resources are appended to DXE3 files (.app, .wgt, .lib) after the normal DXE content. The DXE loader never reads past the DXE header, so appended data is invisible to dlopen.
File layout:
[DXE3 content]
[resource data entries] -- sequential, variable length
[resource directory] -- fixed-size entries (48 bytes each)
[footer] -- magic + directory offset + count (16 bytes)
Resource Types
| Define | Value | Description |
|---|---|---|
DVX_RES_ICON |
1 | Image data (BMP icon: 16x16, 32x32, etc.) |
DVX_RES_TEXT |
2 | Null-terminated string (author, copyright, etc.) |
DVX_RES_BINARY |
3 | Arbitrary binary data (app-specific) |
Resource API
| Function | Description |
|---|---|
dvxResOpen(path) |
Open a resource handle by reading the footer and directory. Returns NULL if no resources. |
dvxResRead(h, name, outSize) |
Find a resource by name and read its data into a malloc'd buffer. Caller frees. |
dvxResFind(h, name) |
Find a resource by name and return its directory entry pointer. |
dvxResClose(h) |
Close the handle and free associated memory. |
Key Types
| Type | Description |
|---|---|
DvxResDirEntryT |
Directory entry: name[32], type, offset, size, reserved (48 bytes) |
DvxResFooterT |
Footer: magic (0x52585644 = "DVXR"), dirOffset, entryCount, reserved (16 bytes) |
DvxResHandleT |
Runtime handle: path, entries array, entry count |
Memory Tracking (dvxMem.h)
Per-app memory tracking wraps malloc/free/calloc/realloc/strdup with a small header per allocation that records the owning app ID and size. DXE code does not need to include dvxMem.h -- the DXE export table maps the standard allocator names to these wrappers transparently.
| Function | Description |
|---|---|
dvxMalloc(size) |
Tracked malloc |
dvxCalloc(nmemb, size) |
Tracked calloc |
dvxRealloc(ptr, size) |
Tracked realloc |
dvxFree(ptr) |
Tracked free (falls through to real free on non-tracked pointers) |
dvxStrdup(s) |
Tracked strdup |
dvxMemSnapshotLoad(appId) |
Record baseline memory for leak detection |
dvxMemGetAppUsage(appId) |
Query current memory usage for an app (bytes) |
dvxMemResetApp(appId) |
Free all allocations charged to an app |
The global dvxMemAppIdPtr pointer is set by the shell to
&ctx->currentAppId so the allocator knows which app to charge.
WidgetT Structure
The WidgetT struct is generic -- no widget-specific fields or union:
typedef struct WidgetT {
int32_t type; // assigned by wgtRegisterClass()
const struct WidgetClassT *wclass; // dispatch table pointer
char name[MAX_WIDGET_NAME];
// Tree linkage
struct WidgetT *parent, *firstChild, *lastChild, *nextSibling;
WindowT *window;
// Geometry (relative to window content area)
int32_t x, y, w, h;
int32_t calcMinW, calcMinH; // computed minimum size
// Size hints (tagged: wgtPixels/wgtChars/wgtPercent, 0 = auto)
int32_t minW, minH, maxW, maxH;
int32_t prefW, prefH;
int32_t weight; // extra-space distribution (0 = fixed)
// Container properties
WidgetAlignE align;
int32_t spacing, padding; // tagged sizes
// Colors (0 = use color scheme defaults)
uint32_t fgColor, bgColor;
// State
bool visible, enabled, readOnly, focused;
char accelKey;
// User data and callbacks
void *userData;
void *data; // widget-private data (allocated by widget DXE)
const char *tooltip;
MenuT *contextMenu;
void (*onClick)(struct WidgetT *w);
void (*onDblClick)(struct WidgetT *w);
void (*onChange)(struct WidgetT *w);
void (*onFocus)(struct WidgetT *w);
void (*onBlur)(struct WidgetT *w);
} WidgetT;
WidgetClassT Dispatch Table
WidgetClassT is an ABI-stable dispatch table. Method IDs are fixed constants that never change -- adding new methods appends new IDs without shifting existing ones. Widget DXEs compiled against an older DVX version continue to work unmodified.
#define WGT_CLASS_VERSION 1 // bump on breaking ABI change
#define WGT_METHOD_MAX 32 // room for future methods
typedef struct WidgetClassT {
uint32_t version;
uint32_t flags;
void *handlers[WGT_METHOD_MAX];
} WidgetClassT;
Method ID Table
21 methods are currently defined (IDs 0--20). WGT_METHOD_MAX is 32, leaving room for 11 future methods without a version bump.
| ID | Method ID | Signature | Purpose |
|---|---|---|---|
| 0 | WGT_METHOD_PAINT |
void (w, d, ops, font, colors) |
Render the widget |
| 1 | WGT_METHOD_PAINT_OVERLAY |
void (w, d, ops, font, colors) |
Render overlay (dropdown popup) |
| 2 | WGT_METHOD_CALC_MIN_SIZE |
void (w, font) |
Compute minimum size (bottom-up pass) |
| 3 | WGT_METHOD_LAYOUT |
void (w, font) |
Position children (top-down pass) |
| 4 | WGT_METHOD_GET_LAYOUT_METRICS |
void (w, font, pad, gap, extraTop, borderW) |
Return padding/gap for box layout |
| 5 | WGT_METHOD_ON_MOUSE |
void (w, root, vx, vy) |
Handle mouse click |
| 6 | WGT_METHOD_ON_KEY |
void (w, key, mod) |
Handle keyboard input |
| 7 | WGT_METHOD_ON_ACCEL_ACTIVATE |
void (w, root) |
Handle accelerator key match |
| 8 | WGT_METHOD_DESTROY |
void (w) |
Free widget-private data |
| 9 | WGT_METHOD_ON_CHILD_CHANGED |
void (parent, child) |
Notification when a child changes |
| 10 | WGT_METHOD_GET_TEXT |
const char *(w) |
Return widget text |
| 11 | WGT_METHOD_SET_TEXT |
void (w, text) |
Set widget text |
| 12 | WGT_METHOD_CLEAR_SELECTION |
bool (w) |
Clear text/item selection |
| 13 | WGT_METHOD_CLOSE_POPUP |
void (w) |
Close dropdown popup |
| 14 | WGT_METHOD_GET_POPUP_RECT |
void (w, font, contentH, popX, popY, popW, popH) |
Compute popup rectangle |
| 15 | WGT_METHOD_ON_DRAG_UPDATE |
void (w, root, x, y) |
Mouse move during drag |
| 16 | WGT_METHOD_ON_DRAG_END |
void (w, root, x, y) |
Mouse release after drag |
| 17 | WGT_METHOD_GET_CURSOR_SHAPE |
int32_t (w, vx, vy) |
Return cursor ID for this position |
| 18 | WGT_METHOD_POLL |
void (w, win) |
Periodic polling (AnsiTerm comms) |
| 19 | WGT_METHOD_QUICK_REPAINT |
int32_t (w, outY, outH) |
Fast incremental repaint |
| 20 | WGT_METHOD_SCROLL_CHILD_INTO_VIEW |
void (parent, child) |
Scroll to make a child visible |
Typed Dispatch Helpers
Each wclsFoo() inline function extracts a handler by stable method
ID, casts it to the correct function pointer type, and calls it with
a NULL check. This gives callers type-safe dispatch with the same
codegen as a direct struct field call.
| Helper | Wraps Method ID |
|---|---|
wclsHas(w, methodId) |
Check if a method is implemented (non-NULL) |
wclsPaint(w, d, ops, font, colors) |
WGT_METHOD_PAINT |
wclsPaintOverlay(w, d, ops, font, colors) |
WGT_METHOD_PAINT_OVERLAY |
wclsCalcMinSize(w, font) |
WGT_METHOD_CALC_MIN_SIZE |
wclsLayout(w, font) |
WGT_METHOD_LAYOUT |
wclsGetLayoutMetrics(w, font, pad, gap, extraTop, borderW) |
WGT_METHOD_GET_LAYOUT_METRICS |
wclsOnMouse(w, root, vx, vy) |
WGT_METHOD_ON_MOUSE |
wclsOnKey(w, key, mod) |
WGT_METHOD_ON_KEY |
wclsOnAccelActivate(w, root) |
WGT_METHOD_ON_ACCEL_ACTIVATE |
wclsDestroy(w) |
WGT_METHOD_DESTROY |
wclsOnChildChanged(parent, child) |
WGT_METHOD_ON_CHILD_CHANGED |
wclsGetText(w) |
WGT_METHOD_GET_TEXT |
wclsSetText(w, text) |
WGT_METHOD_SET_TEXT |
wclsClearSelection(w) |
WGT_METHOD_CLEAR_SELECTION |
wclsClosePopup(w) |
WGT_METHOD_CLOSE_POPUP |
wclsGetPopupRect(w, font, contentH, popX, popY, popW, popH) |
WGT_METHOD_GET_POPUP_RECT |
wclsOnDragUpdate(w, root, x, y) |
WGT_METHOD_ON_DRAG_UPDATE |
wclsOnDragEnd(w, root, x, y) |
WGT_METHOD_ON_DRAG_END |
wclsGetCursorShape(w, vx, vy) |
WGT_METHOD_GET_CURSOR_SHAPE |
wclsPoll(w, win) |
WGT_METHOD_POLL |
wclsQuickRepaint(w, outY, outH) |
WGT_METHOD_QUICK_REPAINT |
wclsScrollChildIntoView(parent, child) |
WGT_METHOD_SCROLL_CHILD_INTO_VIEW |
WidgetClassT Flags
| Flag | Value | Description |
|---|---|---|
WCLASS_FOCUSABLE |
0x0001 | Can receive keyboard focus |
WCLASS_BOX_CONTAINER |
0x0002 | Uses VBox/HBox layout algorithm |
WCLASS_HORIZ_CONTAINER |
0x0004 | Lays out children horizontally |
WCLASS_PAINTS_CHILDREN |
0x0008 | Widget handles child rendering |
WCLASS_NO_HIT_RECURSE |
0x0010 | Hit testing stops here |
WCLASS_FOCUS_FORWARD |
0x0020 | Accel hit forwards focus to next focusable |
WCLASS_HAS_POPUP |
0x0040 | Has dropdown popup overlay |
WCLASS_SCROLLABLE |
0x0080 | Accepts mouse wheel events |
WCLASS_SCROLL_CONTAINER |
0x0100 | Scroll container (ScrollPane) |
WCLASS_NEEDS_POLL |
0x0200 | Needs periodic polling |
WCLASS_SWALLOWS_TAB |
0x0400 | Tab key goes to widget, not focus nav |
WCLASS_RELAYOUT_ON_SCROLL |
0x0800 | Full relayout on scrollbar drag |
WCLASS_PRESS_RELEASE |
0x1000 | Click = press+release (buttons) |
WCLASS_ACCEL_WHEN_HIDDEN |
0x2000 | Accel matching works when invisible |
Widget Registration
Each widget DXE exports wgtRegister(), called by the loader after
dlopen. The WidgetClassT uses the handlers[] array indexed by
method IDs:
static int32_t sButtonType;
static const WidgetClassT sButtonClass = {
.version = WGT_CLASS_VERSION,
.flags = WCLASS_FOCUSABLE | WCLASS_PRESS_RELEASE,
.handlers = {
[WGT_METHOD_PAINT] = buttonPaint,
[WGT_METHOD_CALC_MIN_SIZE] = buttonCalcMinSize,
[WGT_METHOD_ON_MOUSE] = buttonOnMouse,
[WGT_METHOD_ON_KEY] = buttonOnKey,
[WGT_METHOD_DESTROY] = buttonDestroy,
[WGT_METHOD_GET_TEXT] = buttonGetText,
[WGT_METHOD_SET_TEXT] = buttonSetText,
[WGT_METHOD_ON_ACCEL_ACTIVATE] = buttonAccelActivate,
}
};
static const ButtonApiT sApi = { .create = buttonCreate };
void wgtRegister(void) {
sButtonType = wgtRegisterClass(&sButtonClass);
wgtRegisterApi("button", &sApi);
}
Per-Widget API Registry
The monolithic WidgetApiT is gone. Each widget registers a small API
struct under a name via wgtRegisterApi(). Callers retrieve it via
wgtGetApi() and cast to the widget-specific type. Per-widget headers
(e.g. widgetButton.h) provide typed accessors and convenience macros:
// widgetButton.h
typedef struct {
WidgetT *(*create)(WidgetT *parent, const char *text);
} ButtonApiT;
static inline const ButtonApiT *dvxButtonApi(void) {
static const ButtonApiT *sApi;
if (!sApi) { sApi = (const ButtonApiT *)wgtGetApi("button"); }
return sApi;
}
#define wgtButton(parent, text) dvxButtonApi()->create(parent, text)
Tagged Size Values
Size hints encode both unit type and numeric value in a single int32_t:
| Macro | Encoding | Example |
|---|---|---|
wgtPixels(v) |
Bits 31:30 = 00 | w->minW = wgtPixels(200); |
wgtChars(v) |
Bits 31:30 = 01 | w->minW = wgtChars(40); |
wgtPercent(v) |
Bits 31:30 = 10 | w->minW = wgtPercent(50); |
0 |
-- | Auto (use computed minimum) |
Layout Algorithm
Two-pass flexbox-like layout:
- Bottom-up (
calcMinSize): Each widget computes its minimum size. Containers sum children along the main axis, max across the cross axis. - Top-down (
layout): Available space is allocated to children. Extra space beyond minimum is distributed proportionally to weights.weight=0means fixed size,weight=100is the default flexible weight.
Cross-Axis Centering
When a child widget has a maxW (in a VBox) or maxH (in an HBox)
that constrains it smaller than the available cross-axis space, the
layout engine automatically centers the child on the cross axis. This
means setting maxW or maxH on a child inside a container will both
cap its size and center it within the remaining space.
Image Loading
Two image loading functions are available:
| Function | Description |
|---|---|
dvxLoadImage(ctx, path, outW, outH, outPitch) |
Load from a file path |
dvxLoadImageFromMemory(ctx, data, dataLen, outW, outH, outPitch) |
Load from a memory buffer (e.g. resource data) |
Both convert to the display's native pixel format. Caller frees the
returned buffer with dvxFreeImage(). Supported formats: BMP, PNG,
JPEG, GIF (via stb_image).
Exported Symbols
libdvx.lib exports symbols matching these prefixes:
dvx*, wgt*, wm*, prefs*, rect*, draw*, pack*, text*, setClip*,
resetClip*, stbi*, stbi_write*, dirtyList*, widget*,
accelParse*, clipboard*, multiClick*,
sCursor*, sDbl*, sDebug*, sClosed*, sFocused*, sKey*,
sOpen*, sDrag*, sClosed*, sKey*
Build
make # builds bin/libs/libdvx.lib + bin/libs/libdvx.dep
make clean # removes objects and library
Depends on: libtasks.lib (via libdvx.dep).