39 KiB
DVX GUI Library (libdvx.a)
The core GUI compositor library for DVX. Provides VESA video setup,
2D drawing primitives, dirty-rectangle compositing, a full window
manager with Motif-style chrome, and a 32-type widget toolkit with
automatic layout. Applications include dvxApp.h (which pulls in all
lower layers) and optionally dvxWidget.h for the widget system.
Architecture
The library is organized in five layers, each a .h/.c pair. Higher
layers depend on lower ones but never the reverse.
Layer 5 dvxApp Event loop, mouse/keyboard input, public API
Layer 4 dvxWm Window stack, chrome, drag, resize, focus, menus
Layer 3 dvxComp Dirty rectangle list, merge, LFB flush
Layer 2 dvxDraw Spans, rects, bevels, text, bitmaps (asm inner loops)
Layer 1 dvxVideo VESA init, LFB mapping, backbuffer, pixel format
dvxWidget Widget/layout system (optional, standalone)
File Structure
Core Layers
| File | Purpose |
|---|---|
dvxVideo.h/.c |
Layer 1: VESA VBE mode negotiation, LFB mapping, system RAM backbuffer, pixel format discovery, color packing |
dvxDraw.h/.c |
Layer 2: Rectangle fills, bitmap blits, text rendering, bevels, lines, cursor/icon rendering |
dvxComp.h/.c |
Layer 3: Dirty rectangle tracking, merge, backbuffer-to-LFB flush |
dvxWm.h/.c |
Layer 4: Window lifecycle, Z-order stack, chrome drawing, hit testing, drag/resize/scroll |
dvxApp.h/.c |
Layer 5: AppContextT, event loop, window creation, color scheme, wallpaper, screenshots |
Supporting Files
| File | Purpose |
|---|---|
dvxTypes.h |
Shared type definitions used by all layers (PixelFormatT, DisplayT, WindowT, ColorSchemeT, etc.) |
dvxWidget.h |
Widget system public API (32 widget types, layout, events) |
dvxDialog.h/.c |
Modal dialogs (message box, file open/save) |
dvxPrefs.h/.c |
INI-based preferences system (read/write with typed accessors) |
dvxFont.h |
Embedded 8x16 VGA bitmap font glyph data (CP437, 256 glyphs) |
dvxCursor.h |
Mouse cursor bitmask data (5 shapes: arrow, resize H/V/NWSE/NESW) |
dvxPalette.h |
Default VGA palette for 8-bit mode |
dvxIcon.c |
stb_image implementation unit (BMP/PNG/JPEG/GIF loading) |
dvxImageWrite.c |
stb_image_write implementation unit (PNG export) |
Platform Abstraction
| File | Purpose |
|---|---|
platform/dvxPlatform.h |
OS/CPU-neutral interface: video, input, span ops, filesystem |
platform/dvxPlatformDos.c |
DOS/DJGPP: VESA, DPMI, INT 16h/33h, rep stosl/movsd asm spans |
To port DVX to a new platform, implement a new dvxPlatformXxx.c
against platform/dvxPlatform.h and swap it in the Makefile. No other
files need modification.
Widget System
| File | Purpose |
|---|---|
widgets/widgetInternal.h |
Shared internal header: vtable type, constants, cross-widget prototypes |
widgets/widgetClass.c |
Widget class table: one WidgetClassT vtable entry per type |
widgets/widgetCore.c |
Allocation, tree ops, hit testing, flag-based type queries |
widgets/widgetLayout.c |
Two-pass layout engine (measure + arrange) |
widgets/widgetEvent.c |
Mouse, keyboard, scroll, resize, and paint event dispatch |
widgets/widgetOps.c |
Paint dispatcher, public operations (wgtFind, wgtDestroy, etc.) |
widgets/widget*.c |
One file per widget type (button, checkbox, slider, etc.) |
Each widget type is self-contained in its own .c file. Dispatch for
paint, layout, mouse, keyboard, getText/setText, and destroy is driven
by a per-type vtable (WidgetClassT) rather than switch statements.
Adding a new widget type requires only a new .c file and an entry in
the class table.
Third Party
| File | Purpose |
|---|---|
thirdparty/stb_image.h |
Single-header image loader (BMP, PNG, JPEG, GIF) |
thirdparty/stb_image_write.h |
Single-header image writer (PNG) |
Building
Requires the DJGPP cross-compiler (i586-pc-msdosdjgpp-gcc).
make # builds ../lib/libdvx.a
make clean # removes obj/ and lib/
Set DJGPP_PREFIX in the Makefile if your toolchain is installed
somewhere other than ~/djgpp/djgpp.
Quick Start
Minimal window (raw drawing)
#include "dvxApp.h"
static void onPaint(WindowT *win, RectT *dirty) {
AppContextT *ctx = (AppContextT *)win->userData;
const BlitOpsT *ops = dvxGetBlitOps(ctx);
const DisplayT *d = dvxGetDisplay(ctx);
uint32_t blue = packColor(d, 0, 0, 200);
for (int32_t y = 0; y < win->contentH; y++) {
ops->spanFill(win->contentBuf + y * win->contentPitch,
blue, win->contentW);
}
}
int main(void) {
AppContextT ctx;
if (dvxInit(&ctx, 1024, 768, 16) != 0) {
return 1;
}
WindowT *win = dvxCreateWindow(&ctx, "Hello", 100, 100, 300, 200, true);
win->userData = &ctx;
win->onPaint = onPaint;
RectT r = {0, 0, win->contentW, win->contentH};
win->onPaint(win, &r);
dvxRun(&ctx);
dvxShutdown(&ctx);
return 0;
}
Widget-based window
#include "dvxApp.h"
#include "dvxWidget.h"
static void onButtonClick(WidgetT *w) {
WidgetT *root = w;
while (root->parent) root = root->parent;
WidgetT *lbl = wgtFind(root, "status");
if (lbl) {
wgtSetText(lbl, "Clicked!");
wgtInvalidate(lbl);
}
}
int main(void) {
AppContextT ctx;
dvxInit(&ctx, 1024, 768, 16);
WindowT *win = dvxCreateWindow(&ctx, "Widgets", 100, 100, 260, 200, true);
win->userData = &ctx;
WidgetT *root = wgtInitWindow(&ctx, win);
WidgetT *lbl = wgtLabel(root, "Ready.");
wgtSetName(lbl, "status");
wgtHSeparator(root);
WidgetT *row = wgtHBox(root);
wgtLabel(row, "Name:");
wgtTextInput(row, 64);
WidgetT *btn = wgtButton(root, "Go");
btn->onClick = onButtonClick;
wgtInvalidate(root);
dvxRun(&ctx);
dvxShutdown(&ctx);
return 0;
}
Application API (dvxApp.h)
Lifecycle
int32_t dvxInit(AppContextT *ctx, int32_t requestedW,
int32_t requestedH, int32_t preferredBpp);
Initialize VESA video, input, fonts, color scheme, and cursors. Finds a mode matching the requested resolution and bit depth. Returns 0 on success, -1 on failure.
void dvxRun(AppContextT *ctx);
Enter the main event loop. Handles mouse, keyboard, window management,
compositing, and LFB flush. Returns when dvxQuit() is called.
bool dvxUpdate(AppContextT *ctx);
Process one iteration of the event loop. Returns true if still
running, false when exit requested. Use instead of dvxRun() when
embedding the GUI in an existing main loop.
void dvxShutdown(AppContextT *ctx);
Restore text mode, release LFB mapping, free the backbuffer.
void dvxQuit(AppContextT *ctx);
Request exit from the main loop.
Video Mode
int32_t dvxChangeVideoMode(AppContextT *ctx, int32_t requestedW,
int32_t requestedH, int32_t preferredBpp);
Switch to a new video mode live. Reallocates the backbuffer, all window content buffers, repacks colors, rescales wallpaper, and repositions windows. Returns 0 on success, -1 on failure (old mode restored).
const VideoModeInfoT *dvxGetVideoModes(const AppContextT *ctx,
int32_t *count);
Return the list of available VESA modes (enumerated at init).
Windows
WindowT *dvxCreateWindow(AppContextT *ctx, const char *title,
int32_t x, int32_t y, int32_t w, int32_t h,
bool resizable);
WindowT *dvxCreateWindowCentered(AppContextT *ctx, const char *title,
int32_t w, int32_t h, bool resizable);
void dvxDestroyWindow(AppContextT *ctx, WindowT *win);
After creation, set win->userData and install callbacks:
| Callback | Signature | When Called |
|---|---|---|
onPaint |
void (WindowT *win, RectT *dirtyArea) |
Content needs redrawing |
onKey |
void (WindowT *win, int32_t key, int32_t mod) |
Key press (focused window) |
onMouse |
void (WindowT *win, int32_t x, int32_t y, int32_t buttons) |
Mouse event in content area |
onResize |
void (WindowT *win, int32_t newW, int32_t newH) |
Window resized by user |
onClose |
void (WindowT *win) |
Close button double-clicked |
onMenu |
void (WindowT *win, int32_t menuId) |
Menu item selected or accelerator triggered |
onScroll |
void (WindowT *win, ScrollbarOrientE orient, int32_t value) |
Scrollbar moved |
Mouse/key coordinates are relative to the content area. buttons is
a bitmask: MOUSE_LEFT (1), MOUSE_RIGHT (2), MOUSE_MIDDLE (4).
Example:
static void onClose(WindowT *win) {
AppContextT *ctx = (AppContextT *)win->userData;
dvxDestroyWindow(ctx, win);
}
WindowT *win = dvxCreateWindow(&ctx, "My Window", 50, 50, 400, 300, true);
win->userData = &ctx;
win->onClose = onClose;
win->onPaint = myPaintHandler;
Window Properties
Set directly on WindowT after creation:
| Field | Type | Default | Description |
|---|---|---|---|
maxW |
int32_t |
-1 | Maximum width when maximized (-1 = screen width) |
maxH |
int32_t |
-1 | Maximum height when maximized (-1 = screen height) |
modal |
bool |
false | When true, only this window receives input |
userData |
void * |
NULL | Application data pointer |
Window Operations
void dvxSetTitle(AppContextT *ctx, WindowT *win, const char *title);
int32_t dvxSetWindowIcon(AppContextT *ctx, WindowT *win, const char *path);
void dvxMinimizeWindow(AppContextT *ctx, WindowT *win);
void dvxMaximizeWindow(AppContextT *ctx, WindowT *win);
void dvxFitWindow(AppContextT *ctx, WindowT *win);
dvxFitWindow resizes the window to exactly fit its widget tree's
computed minimum size (plus chrome). Useful for dialog boxes.
Window Arrangement
dvxCascadeWindows(&ctx); // staggered diagonal cascade
dvxTileWindows(&ctx); // NxM grid fill
dvxTileWindowsH(&ctx); // side-by-side, equal width
dvxTileWindowsV(&ctx); // stacked, equal height
Invalidation
void dvxInvalidateRect(AppContextT *ctx, WindowT *win,
int32_t x, int32_t y, int32_t w, int32_t h);
void dvxInvalidateWindow(AppContextT *ctx, WindowT *win);
Mark a region (or the entire content area) as needing repaint. The compositor flushes dirty rectangles to the LFB on the next frame.
Content Buffer
Each window has a persistent content backbuffer in display pixel format:
| Field | Description |
|---|---|
contentBuf |
Pixel data in native display format |
contentPitch |
Bytes per scanline |
contentW |
Width in pixels |
contentH |
Height in pixels |
Paint callbacks write directly into contentBuf. The compositor copies
visible portions to the screen backbuffer, then flushes dirty rects to
the LFB.
Clipboard
dvxClipboardCopy("Hello", 5);
int32_t len;
const char *text = dvxClipboardGet(&len);
Process-wide static buffer. Adequate for copy/paste within DVX on single-tasking DOS.
Screenshots
dvxScreenshot(&ctx, "screen.png"); // entire screen
dvxWindowScreenshot(&ctx, win, "window.png"); // single window content
Converts from native pixel format to RGB for the PNG encoder.
Image Loading
uint8_t *dvxLoadImage(const AppContextT *ctx, const char *path,
int32_t *outW, int32_t *outH, int32_t *outPitch);
void dvxFreeImage(uint8_t *data);
int32_t dvxSaveImage(const AppContextT *ctx, const uint8_t *data,
int32_t w, int32_t h, int32_t pitch, const char *path);
Load BMP/PNG/JPEG/GIF files and convert to the display's native pixel format. Save native-format pixel data to PNG.
Accessors
DisplayT *dvxGetDisplay(AppContextT *ctx);
const BlitOpsT *dvxGetBlitOps(const AppContextT *ctx);
const BitmapFontT *dvxGetFont(const AppContextT *ctx);
const ColorSchemeT *dvxGetColors(const AppContextT *ctx);
Mouse Configuration
void dvxSetMouseConfig(AppContextT *ctx, int32_t wheelDir,
int32_t dblClickMs, int32_t accelThreshold);
wheelDir: 1 = normal, -1 = reversed.
dblClickMs: double-click speed in milliseconds.
accelThreshold: double-speed threshold in mickeys/sec (0 = unchanged).
Color System
DVX uses a 20-color scheme that controls the entire UI appearance. All colors are pre-packed into native pixel format at init time for zero-cost per-pixel rendering.
ColorSchemeT Fields
| Field | Usage |
|---|---|
desktop |
Desktop background fill |
windowFace |
Window frame fill |
windowHighlight |
Bevel light edge (top/left) |
windowShadow |
Bevel dark edge (bottom/right) |
activeTitleBg / activeTitleFg |
Focused window title bar |
inactiveTitleBg / inactiveTitleFg |
Unfocused window title bar |
contentBg / contentFg |
Window content area defaults |
menuBg / menuFg |
Menu bar and popup menus |
menuHighlightBg / menuHighlightFg |
Highlighted menu item |
buttonFace |
Push button interior |
scrollbarBg / scrollbarFg / scrollbarTrough |
Scrollbar elements |
cursorFg / cursorBg |
Mouse cursor colors |
ColorIdE Enum
Each color has an integer ID for programmatic access:
ColorDesktopE, ColorWindowFaceE, ColorWindowHighlightE,
ColorWindowShadowE, ColorActiveTitleBgE, ColorActiveTitleFgE,
ColorInactiveTitleBgE, ColorInactiveTitleFgE, ColorContentBgE,
ColorContentFgE, ColorMenuBgE, ColorMenuFgE, ColorMenuHighlightBgE,
ColorMenuHighlightFgE, ColorButtonFaceE, ColorScrollbarBgE,
ColorScrollbarFgE, ColorScrollbarTroughE, ColorCursorFgE,
ColorCursorBgE, ColorCountE
Color API
void dvxSetColor(AppContextT *ctx, ColorIdE id, uint8_t r, uint8_t g, uint8_t b);
void dvxGetColor(const AppContextT *ctx, ColorIdE id, uint8_t *r, uint8_t *g, uint8_t *b);
void dvxApplyColorScheme(AppContextT *ctx);
void dvxResetColorScheme(AppContextT *ctx);
Theme Files
Theme files are INI-format with a [colors] section containing RGB
values for each of the 20 color IDs:
bool dvxLoadTheme(AppContextT *ctx, const char *filename);
bool dvxSaveTheme(const AppContextT *ctx, const char *filename);
const char *dvxColorName(ColorIdE id); // INI key name
const char *dvxColorLabel(ColorIdE id); // human-readable label
Bundled themes: cde.thm, geos.thm, win31.thm.
Wallpaper System
bool dvxSetWallpaper(AppContextT *ctx, const char *path);
void dvxSetWallpaperMode(AppContextT *ctx, WallpaperModeE mode);
Three display modes:
| Mode | Enum | Description |
|---|---|---|
| Stretch | WallpaperStretchE |
Bilinear scaling to fill screen; ordered dithering for 16bpp |
| Tile | WallpaperTileE |
Repeating pattern from top-left |
| Center | WallpaperCenterE |
Centered with desktop color fill around edges |
The wallpaper is pre-rendered to screen dimensions in native pixel
format. Pass NULL to dvxSetWallpaper to clear. The wallpaper path is
stored so the image can be reloaded after a video mode change.
Supported formats: BMP, PNG, JPEG, GIF (via stb_image).
Preferences System (dvxPrefs.h)
INI-based configuration with typed read/write accessors and caller-supplied defaults.
bool prefsLoad(const char *filename);
bool prefsSave(void);
bool prefsSaveAs(const char *filename);
void prefsFree(void);
const char *prefsGetString(const char *section, const char *key, const char *defaultVal);
int32_t prefsGetInt(const char *section, const char *key, int32_t defaultVal);
bool prefsGetBool(const char *section, const char *key, bool defaultVal);
void prefsSetString(const char *section, const char *key, const char *value);
void prefsSetInt(const char *section, const char *key, int32_t value);
void prefsSetBool(const char *section, const char *key, bool value);
void prefsRemove(const char *section, const char *key);
Only one file may be loaded at a time. If the file is missing or a key
is absent, getters return the caller-supplied default silently. Boolean
values recognize true/yes/1 and false/no/0.
Menu System
Menu Bars
MenuBarT *wmAddMenuBar(WindowT *win);
MenuT *wmAddMenu(MenuBarT *bar, const char *label);
void wmAddMenuItem(MenuT *menu, const char *label, int32_t id);
void wmAddMenuCheckItem(MenuT *menu, const char *label, int32_t id, bool checked);
void wmAddMenuRadioItem(MenuT *menu, const char *label, int32_t id, bool checked);
void wmAddMenuSeparator(MenuT *menu);
MenuT *wmAddSubMenu(MenuT *parentMenu, const char *label);
The & prefix marks accelerator keys -- "&File" means Alt+F opens
the menu. Up to 8 menus per bar, 16 items per menu, submenus nested up
to 4 levels deep.
After adding menus, call wmUpdateContentRect(win) and
wmReallocContentBuf(win, &ctx.display) to adjust the content area.
Example:
MenuBarT *bar = wmAddMenuBar(win);
MenuT *fileMenu = wmAddMenu(bar, "&File");
wmAddMenuItem(fileMenu, "&New", CMD_NEW);
wmAddMenuItem(fileMenu, "&Open...", CMD_OPEN);
wmAddMenuSeparator(fileMenu);
wmAddMenuItem(fileMenu, "E&xit", CMD_EXIT);
MenuT *viewMenu = wmAddMenu(bar, "&View");
wmAddMenuCheckItem(viewMenu, "Tool&bar", CMD_TOOLBAR, true);
wmAddMenuRadioItem(viewMenu, "&Small", CMD_SMALL, false);
wmAddMenuRadioItem(viewMenu, "&Large", CMD_LARGE, true);
MenuT *zoomMenu = wmAddSubMenu(viewMenu, "&Zoom");
wmAddMenuItem(zoomMenu, "Zoom &In", CMD_ZOOM_IN);
wmAddMenuItem(zoomMenu, "Zoom &Out", CMD_ZOOM_OUT);
wmUpdateContentRect(win);
wmReallocContentBuf(win, &ctx.display);
Context Menus
Right-click menus attached to windows or widgets:
MenuT *ctxMenu = wmCreateMenu();
wmAddMenuItem(ctxMenu, "Cu&t", CMD_CUT);
wmAddMenuItem(ctxMenu, "&Copy", CMD_COPY);
wmAddMenuItem(ctxMenu, "&Paste", CMD_PASTE);
win->contextMenu = ctxMenu;
// Widget-level context menu
WidgetT *lb = wgtListBox(root);
lb->contextMenu = wmCreateMenu();
wmAddMenuItem(lb->contextMenu, "&Delete", CMD_DELETE);
Context menus route through the window's onMenu callback. The caller
owns the MenuT allocation (free with wmFreeMenu()).
Accelerator Tables
Keyboard shortcuts routed through onMenu:
AccelTableT *accel = dvxCreateAccelTable();
dvxAddAccel(accel, 'N', ACCEL_CTRL, CMD_NEW);
dvxAddAccel(accel, 'O', ACCEL_CTRL, CMD_OPEN);
dvxAddAccel(accel, 'S', ACCEL_CTRL, CMD_SAVE);
dvxAddAccel(accel, KEY_F1, 0, CMD_HELP);
win->accelTable = accel;
Modifier constants: ACCEL_SHIFT (0x03), ACCEL_CTRL (0x04),
ACCEL_ALT (0x08).
Key constants for extended keys: KEY_F1--KEY_F12, KEY_INSERT,
KEY_DELETE, KEY_HOME, KEY_END, KEY_PGUP, KEY_PGDN.
Up to 32 entries per table. Free with dvxFreeAccelTable().
Scrollbars
ScrollbarT *wmAddVScrollbar(WindowT *win, int32_t min, int32_t max, int32_t pageSize);
ScrollbarT *wmAddHScrollbar(WindowT *win, int32_t min, int32_t max, int32_t pageSize);
After adding scrollbars, call wmUpdateContentRect(win) and
wmReallocContentBuf(win, &ctx.display). The onScroll callback fires
when the user drags the thumb or clicks arrow buttons / trough.
Widget-managed windows handle their own scrollbars automatically -- do not add them manually to widget windows.
Dialogs (dvxDialog.h)
Message Box
int32_t result = dvxMessageBox(&ctx, "Confirm",
"Are you sure?", MB_YESNO | MB_ICONQUESTION);
if (result == ID_YES) {
dvxQuit(&ctx);
}
Button flags: MB_OK, MB_OKCANCEL, MB_YESNO, MB_YESNOCANCEL,
MB_RETRYCANCEL.
Icon flags: MB_ICONINFO, MB_ICONWARNING, MB_ICONERROR,
MB_ICONQUESTION.
Return values: ID_OK, ID_CANCEL, ID_YES, ID_NO, ID_RETRY.
File Dialog
static const FileFilterT filters[] = {
{"All Files (*.*)", "*.*"},
{"Text Files (*.txt)", "*.txt"},
{"Bitmap Files (*.bmp)", "*.bmp"}
};
char path[260];
if (dvxFileDialog(&ctx, "Open File", FD_OPEN, NULL,
filters, 3, path, sizeof(path))) {
// path contains the selected filename
}
Flags: FD_OPEN, FD_SAVE. Pass NULL for initialDir to use the
current directory. Filename validation is platform-specific (8.3 on DOS).
Video and Drawing (dvxVideo.h, dvxDraw.h)
Lower-level APIs. Application code typically only needs packColor.
Color Packing
uint32_t packColor(const DisplayT *d, uint8_t r, uint8_t g, uint8_t b);
Pack RGB into the display's native pixel format. For 8-bit mode, returns the nearest palette index.
Clip Rectangle
void setClipRect(DisplayT *d, int32_t x, int32_t y, int32_t w, int32_t h);
void resetClipRect(DisplayT *d);
Rectangle Operations
void rectFill(DisplayT *d, const BlitOpsT *ops,
int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
void rectCopy(DisplayT *d, const BlitOpsT *ops,
int32_t dstX, int32_t dstY, const uint8_t *srcBuf,
int32_t srcPitch, int32_t srcX, int32_t srcY,
int32_t w, int32_t h);
Bevel Drawing
void drawBevel(DisplayT *d, const BlitOpsT *ops,
int32_t x, int32_t y, int32_t w, int32_t h,
const BevelStyleT *style);
Convenience macros for common bevel styles:
BEVEL_RAISED(cs, bw)-- standard raised (buttons, window frames)BEVEL_SUNKEN(cs, face, bw)-- sunken (text fields, list boxes)BEVEL_TROUGH(cs)-- scrollbar trough (1px sunken)BEVEL_SB_BUTTON(cs)-- scrollbar arrow button (1px raised)
Text Rendering
void drawText(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font,
int32_t x, int32_t y, const char *text,
uint32_t fg, uint32_t bg, bool opaque);
void drawTextN(DisplayT *d, const BlitOpsT *ops, const BitmapFontT *font,
int32_t x, int32_t y, const char *text, int32_t count,
uint32_t fg, uint32_t bg, bool opaque);
int32_t textWidth(const BitmapFontT *font, const char *text);
drawTextN is the fast path for bulk rendering -- computes clip bounds
once and fills the background in a single pass.
void drawTextAccel(DisplayT *d, const BlitOpsT *ops,
const BitmapFontT *font, int32_t x, int32_t y,
const char *text, uint32_t fg, uint32_t bg, bool opaque);
int32_t textWidthAccel(const BitmapFontT *font, const char *text);
char accelParse(const char *text);
Text with & accelerator markers. The character after & is
underlined. && produces a literal &.
Terminal Row Rendering
void drawTermRow(DisplayT *d, const BlitOpsT *ops,
const BitmapFontT *font, int32_t x, int32_t y,
int32_t cols, const uint8_t *lineData,
const uint32_t *palette, bool blinkVisible,
int32_t cursorCol);
Renders an entire 80-column terminal row in one call. lineData points
to (char, attr) byte pairs. Much faster than per-character rendering.
Lines and Focus
void drawHLine(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y, int32_t w, uint32_t color);
void drawVLine(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y, int32_t h, uint32_t color);
void drawFocusRect(DisplayT *d, const BlitOpsT *ops, int32_t x, int32_t y, int32_t w, int32_t h, uint32_t color);
drawFocusRect draws a dotted rectangle (alternating pixels) for
keyboard focus indicators.
Compositor (dvxComp.h)
void dirtyListInit(DirtyListT *dl);
void dirtyListAdd(DirtyListT *dl, int32_t x, int32_t y, int32_t w, int32_t h);
void dirtyListMerge(DirtyListT *dl);
void dirtyListClear(DirtyListT *dl);
void flushRect(DisplayT *d, const RectT *r);
bool rectIntersect(const RectT *a, const RectT *b, RectT *result);
bool rectIsEmpty(const RectT *r);
The compositing pipeline each frame:
- Layers above call
dirtyListAdd()for changed regions dirtyListMerge()consolidates overlapping/adjacent rects- For each merged dirty rect, redraw desktop then each window (back-to-front, painter's algorithm)
flushRect()copies each dirty rect from backBuf to the LFB
Up to 128 dirty rects per frame (MAX_DIRTY_RECTS).
Window Manager (dvxWm.h)
Window Stack
Windows are stored in an array of pointers ordered front-to-back: index
count-1 is the topmost window. The compositor iterates back-to-front
for painting and front-to-back for hit testing.
void wmInit(WindowStackT *stack);
WindowT *wmCreateWindow(WindowStackT *stack, DisplayT *d, const char *title,
int32_t x, int32_t y, int32_t w, int32_t h, bool resizable);
void wmDestroyWindow(WindowStackT *stack, WindowT *win);
void wmRaiseWindow(WindowStackT *stack, DirtyListT *dl, int32_t idx);
void wmSetFocus(WindowStackT *stack, DirtyListT *dl, int32_t idx);
Hit Testing
int32_t wmHitTest(const WindowStackT *stack, int32_t mx, int32_t my, int32_t *hitPart);
Returns the stack index and hit region:
HIT_CONTENT, HIT_TITLE, HIT_CLOSE, HIT_RESIZE, HIT_MENU,
HIT_VSCROLL, HIT_HSCROLL, HIT_MINIMIZE, HIT_MAXIMIZE,
HIT_NONE.
Window Operations
void wmMaximize(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, WindowT *win);
void wmMinimize(WindowStackT *stack, DirtyListT *dl, WindowT *win);
void wmRestore(WindowStackT *stack, DirtyListT *dl, const DisplayT *d, WindowT *win);
void wmRestoreMinimized(WindowStackT *stack, DirtyListT *dl, WindowT *win);
System Menu
The system menu (control menu) appears on single-click of the close gadget. Commands: Restore, Move, Size, Minimize, Maximize, Close, Screenshot, Window Screenshot. Matches Windows 3.x behavior.
Keyboard Window Management
| Key | Action |
|---|---|
| Alt+Tab | Cycle windows forward |
| Shift+Alt+Tab | Cycle windows backward |
| Alt+F4 | Close focused window |
| Alt+Space | Open system menu |
| F10 | Activate menu bar |
Widget System (dvxWidget.h)
A retained-mode widget toolkit layered on top of the window manager. Widgets form a tree rooted at a per-window VBox container. Layout is automatic via a flexbox-like algorithm with weighted space distribution.
Widget Catalog (32 types)
Containers
| Widget | Constructor | Description |
|---|---|---|
| VBox | wgtVBox(parent) |
Vertical stack layout |
| HBox | wgtHBox(parent) |
Horizontal stack layout |
| Frame | wgtFrame(parent, title) |
Titled groupbox with bevel border |
| TabControl | wgtTabControl(parent) |
Tabbed page container with scrollable headers |
| TabPage | wgtTabPage(tabs, title) |
Single page within a TabControl |
| ScrollPane | wgtScrollPane(parent) |
Scrollable container with automatic scrollbars |
| Splitter | wgtSplitter(parent, vertical) |
Draggable divider between two child regions |
| Toolbar | wgtToolbar(parent) |
Horizontal raised container for toolbar buttons |
| StatusBar | wgtStatusBar(parent) |
Horizontal sunken container for status text |
Basic Widgets
| Widget | Constructor | Description |
|---|---|---|
| Label | wgtLabel(parent, text) |
Static text display with optional alignment |
| Button | wgtButton(parent, text) |
Beveled push button with press animation |
| Checkbox | wgtCheckbox(parent, text) |
Toggle checkbox with checkmark glyph |
| RadioGroup | wgtRadioGroup(parent) |
Container for mutually exclusive radio buttons |
| Radio | wgtRadio(group, text) |
Individual radio button with diamond indicator |
Text Input Widgets
| Widget | Constructor | Description |
|---|---|---|
| TextInput | wgtTextInput(parent, maxLen) |
Single-line text field with selection, undo, clipboard |
| PasswordInput | wgtPasswordInput(parent, maxLen) |
Bullet-masked text field (no copy/cut) |
| MaskedInput | wgtMaskedInput(parent, mask) |
Formatted input (e.g. "(###) ###-####") |
| TextArea | wgtTextArea(parent, maxLen) |
Multi-line text editor with scrollbars |
Selection Widgets
| Widget | Constructor | Description |
|---|---|---|
| ListBox | wgtListBox(parent) |
Scrollable item list with optional multi-select and drag reorder |
| Dropdown | wgtDropdown(parent) |
Non-editable selection with popup list |
| ComboBox | wgtComboBox(parent, maxLen) |
Editable text field with dropdown suggestions |
| TreeView | wgtTreeView(parent) |
Hierarchical tree with expand/collapse, multi-select, drag reorder |
| TreeItem | wgtTreeItem(parent, text) |
Item node within a TreeView |
| ListView | wgtListView(parent) |
Multi-column list with sortable/resizable headers, multi-select |
Value Widgets
| Widget | Constructor | Description |
|---|---|---|
| Slider | wgtSlider(parent, min, max) |
Draggable track bar (horizontal or vertical) |
| Spinner | wgtSpinner(parent, min, max, step) |
Numeric up/down input with increment buttons |
| ProgressBar | wgtProgressBar(parent) |
Percentage display bar (horizontal or vertical) |
Visual Widgets
| Widget | Constructor | Description |
|---|---|---|
| Image | wgtImage(parent, data, w, h, pitch) |
Static image display (BMP/PNG/JPEG/GIF) |
| ImageButton | wgtImageButton(parent, data, w, h, pitch) |
Clickable image button with press animation |
| Canvas | wgtCanvas(parent, w, h) |
Drawable bitmap surface with programmatic drawing API |
| Spacer | wgtSpacer(parent) |
Invisible flexible space (weight=100) |
| Separator | wgtHSeparator(parent) / wgtVSeparator(parent) |
Beveled divider line |
Special Widgets
| Widget | Constructor | Description |
|---|---|---|
| AnsiTerm | wgtAnsiTerm(parent, cols, rows) |
VT100/ANSI terminal emulator with 16-color CGA palette, scrollback, blink |
| Timer | wgtTimer(parent, intervalMs, repeat) |
Invisible callback timer (one-shot or repeating) |
Widget Event Model
All widget types share a universal set of event callbacks set directly on the WidgetT struct:
| Callback | Signature | Description |
|---|---|---|
onClick |
void (WidgetT *w) |
Mouse click completed on the widget |
onDblClick |
void (WidgetT *w) |
Double-click on the widget |
onChange |
void (WidgetT *w) |
Value or state changed (checkbox toggle, text edit, slider move, timer fire) |
onFocus |
void (WidgetT *w) |
Widget received keyboard focus |
onBlur |
void (WidgetT *w) |
Widget lost keyboard focus |
Type-specific handlers (button press animation, listbox selection highlight) run first, then these universal callbacks fire.
Additional per-widget fields: userData (void pointer), tooltip
(hover text), contextMenu (right-click menu).
Initialization
WidgetT *wgtInitWindow(AppContextT *ctx, WindowT *win);
Attach the widget system to a window. Returns the root VBox container.
Installs onPaint, onMouse, onKey, and onResize handlers. Build
the UI by adding child widgets to the returned root.
Call wgtInvalidate(root) after the tree is fully built to trigger the
initial layout and paint.
Layout System
The layout engine runs in two passes:
- Measure (bottom-up): compute minimum sizes for every widget
- Arrange (top-down): distribute available space according to weights, respecting min/max constraints
Size Specifications
Size fields (minW, minH, maxW, maxH, prefW, prefH,
spacing, padding) accept tagged values:
wgtPixels(120) // 120 pixels
wgtChars(15) // 15 character widths (15 * 8 = 120 pixels)
wgtPercent(50) // 50% of parent dimension
A raw 0 means auto (use the widget's natural/computed size).
Weight
The weight field controls extra-space distribution among siblings:
weight = 0-- fixed size, does not stretch (default for most widgets)weight = 100-- normal stretch (default for spacers, text inputs)- Relative ratios work: weights of 100, 200, 100 give a 1:2:1 split
When all children have weight 0, the container's align property
(AlignStartE, AlignCenterE, AlignEndE) positions children within
the extra space.
Container Properties
| Field | Type | Default | Description |
|---|---|---|---|
align |
WidgetAlignE |
AlignStartE |
Main-axis alignment |
spacing |
int32_t |
0 (4px) | Tagged gap between children |
padding |
int32_t |
0 (4px) | Tagged internal padding |
Widget Operations
void wgtSetText(WidgetT *w, const char *text);
const char *wgtGetText(const WidgetT *w);
void wgtSetEnabled(WidgetT *w, bool enabled);
void wgtSetReadOnly(WidgetT *w, bool readOnly);
void wgtSetVisible(WidgetT *w, bool visible);
void wgtSetFocused(WidgetT *w);
WidgetT *wgtGetFocused(void);
void wgtSetName(WidgetT *w, const char *name);
WidgetT *wgtFind(WidgetT *root, const char *name);
void wgtDestroy(WidgetT *w);
void wgtInvalidate(WidgetT *w);
void wgtInvalidatePaint(WidgetT *w);
void wgtSetTooltip(WidgetT *w, const char *text);
void wgtSetDebugLayout(AppContextT *ctx, bool enabled);
AppContextT *wgtGetContext(const WidgetT *w);
wgtInvalidatetriggers full relayout + repaint (use after structural changes)wgtInvalidatePainttriggers repaint only (use for visual-only changes like checkbox toggle)wgtFindsearches by name using djb2 hash for fast rejectionwgtGetContextwalks up the tree to retrieve the AppContextT
Timer Widget
WidgetT *wgtTimer(WidgetT *parent, int32_t intervalMs, bool repeat);
void wgtTimerStart(WidgetT *w);
void wgtTimerStop(WidgetT *w);
void wgtTimerSetInterval(WidgetT *w, int32_t intervalMs);
bool wgtTimerIsRunning(const WidgetT *w);
Invisible widget that fires onChange at the specified interval. Does
not participate in layout. Set repeat = false for one-shot timers
that auto-stop after the first fire. wgtUpdateTimers() is called
automatically by dvxUpdate() each frame.
Layout and Paint Internals
Available for manual use when embedding in a custom event loop:
int32_t wgtResolveSize(int32_t taggedSize, int32_t parentSize, int32_t charWidth);
void wgtLayout(WidgetT *root, int32_t availW, int32_t availH, const BitmapFontT *font);
void wgtPaint(WidgetT *root, DisplayT *d, const BlitOpsT *ops,
const BitmapFontT *font, const ColorSchemeT *colors);
Font System
DVX uses a fixed-width 8x16 bitmap font covering the full IBM Code Page 437 character set (256 glyphs). The font data is compiled in as a static array -- no external font files.
| Property | Value |
|---|---|
| Width | 8 pixels (fixed) |
| Height | 16 pixels (8x14 also available) |
| Encoding | CP437 (full 256 glyphs) |
| Format | 1 bit per pixel, MSB = leftmost, 16 bytes per glyph |
| Box drawing | Characters 176--223 (scrollbar arrows, window gadgets) |
Character positions are pure multiplication (x = col * 8), and each
glyph scanline is exactly one byte, enabling simple per-scanline
rendering without bit shifting across byte boundaries.
Cursor System
Five software-rendered cursor shapes, stored as 16x16 AND/XOR bitmask pairs (the standard IBM VGA hardware cursor format):
| ID | Constant | Shape |
|---|---|---|
| 0 | CURSOR_ARROW |
Standard arrow pointer |
| 1 | CURSOR_RESIZE_H |
Horizontal resize (left-right) |
| 2 | CURSOR_RESIZE_V |
Vertical resize (up-down) |
| 3 | CURSOR_RESIZE_DIAG_NWSE |
NW-SE diagonal resize |
| 4 | CURSOR_RESIZE_DIAG_NESW |
NE-SW diagonal resize |
Cursors are painted in software into the backbuffer because VESA VBE does not provide a hardware sprite. The affected region is flushed to the LFB each frame.
Window Chrome
Windows use a Motif/GEOS-style frame:
- 4px beveled outer border with perpendicular groove breaks
- 20px title bar (dark background when focused)
- Close button on the left edge (single-click opens system menu, double-click closes)
- Minimize button on the right edge (always present)
- Maximize button to the left of minimize (resizable windows only)
- Optional menu bar below the title bar (20px)
- Optional scrollbars along the right and bottom edges (16px)
Minimized windows appear as 64x64 beveled icons along the bottom of the
screen. If a window icon is set via dvxSetWindowIcon(), that image is
shown; otherwise a scaled thumbnail of the window's content buffer is
used. Thumbnails refresh automatically one per frame (staggered).
Double-click an icon to restore.
Platform Abstraction (platform/dvxPlatform.h)
All OS-specific code is behind a single interface. To port DVX,
implement these functions in a new dvxPlatformXxx.c:
| Function | Purpose |
|---|---|
platformInit() |
One-time setup (signal handlers, etc.) |
platformYield() |
Cooperative multitasking yield |
platformVideoInit() |
Set up video mode, LFB, backbuffer |
platformVideoShutdown() |
Restore text mode, free resources |
platformVideoEnumModes() |
Enumerate available video modes |
platformVideoSetPalette() |
Set 8-bit palette entries |
platformVideoFreeBuffers() |
Free backbuffer without restoring text mode |
platformFlushRect() |
Copy rectangle from backbuffer to LFB |
platformSpanFill8/16/32() |
Optimized pixel fill (rep stosl on DOS) |
platformSpanCopy8/16/32() |
Optimized pixel copy (rep movsd on DOS) |
platformMouseInit() |
Initialize mouse driver |
platformMousePoll() |
Read mouse position and buttons |
platformMouseWheelInit() |
Detect and activate mouse wheel |
platformMouseWheelPoll() |
Read wheel delta |
platformMouseWarp() |
Move cursor to absolute position |
platformMouseSetAccel() |
Set double-speed threshold |
platformKeyboardGetModifiers() |
Read shift/ctrl/alt state |
platformKeyboardRead() |
Non-blocking key read |
platformAltScanToChar() |
Map Alt+scancode to ASCII |
platformValidateFilename() |
Check filename for OS constraints |
platformGetSystemInfo() |
Gather hardware info string |
platformGetMemoryInfo() |
Query total/free RAM |
platformMkdirRecursive() |
Create directory tree |
platformChdir() |
Change directory (with drive support on DOS) |
platformPathDirEnd() |
Find last path separator |
platformLineEnding() |
Native line ending string |
platformStripLineEndings() |
Remove CR from CR+LF pairs |
Key Constants (dvxTypes.h)
Extended Key Codes
Non-ASCII keys encoded as (scancode | 0x100):
KEY_F1 through KEY_F12
KEY_INSERT, KEY_DELETE
KEY_HOME, KEY_END
KEY_PGUP, KEY_PGDN
Chrome Constants
CHROME_BORDER_WIDTH 4 Border thickness
CHROME_TITLE_HEIGHT 20 Title bar height
CHROME_MENU_HEIGHT 20 Menu bar height
CHROME_CLOSE_BTN_SIZE 16 Close gadget size
SCROLLBAR_WIDTH 16 Scrollbar track width
MAX_WINDOWS 64 Maximum simultaneous windows
MAX_DIRTY_RECTS 128 Dirty rects per frame
Mouse Constants
MOUSE_LEFT 1 Left button bitmask
MOUSE_RIGHT 2 Right button bitmask
MOUSE_MIDDLE 4 Middle button bitmask
MOUSE_WHEEL_STEP 3 Lines per wheel notch
Hardware Requirements
- 486 or later CPU
- VESA VBE 2.0+ compatible video card with linear framebuffer
- PS/2 mouse (or compatible driver)
- DPMI host (CWSDPMI, Windows DOS box, DOSBox, 86Box)
Tested on 86Box with PCI video cards.