755 lines
37 KiB
HTML
755 lines
37 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>DVX Architecture Overview</title>
|
|
<style>
|
|
body { font-family: sans-serif; margin: 0; padding: 0; display: flex; }
|
|
nav { width: 250px; min-width: 250px; background: #f0f0f0; padding: 16px;
|
|
border-right: 1px solid #ccc; height: 100vh; overflow-y: auto;
|
|
position: sticky; top: 0; box-sizing: border-box; }
|
|
nav ul { list-style: none; padding-left: 16px; margin: 4px 0; }
|
|
nav > ul { padding-left: 0; }
|
|
nav a { text-decoration: none; color: #0066cc; }
|
|
nav a:hover { text-decoration: underline; }
|
|
main { flex: 1; padding: 24px 32px; max-width: 800px; }
|
|
h1 { border-bottom: 2px solid #333; padding-bottom: 4px; }
|
|
h2 { border-bottom: 1px solid #999; padding-bottom: 2px; margin-top: 32px; }
|
|
h3 { margin-top: 24px; }
|
|
pre { background: #f8f8f8; border: 1px solid #ddd; padding: 8px;
|
|
overflow-x: auto; font-size: 14px; }
|
|
blockquote { background: #fffde7; border-left: 4px solid #ffc107;
|
|
padding: 8px 12px; margin: 12px 0; }
|
|
hr { border: none; border-top: 1px solid #ccc; margin: 24px 0; }
|
|
img { max-width: 100%; }
|
|
.topic { margin-bottom: 48px; }
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<nav>
|
|
<h3>Contents</h3>
|
|
<ul>
|
|
<li><a href="#arch.overview">System Overview</a></li>
|
|
<li><a href="#arch.layers">Five-Layer Architecture</a></li>
|
|
<li><a href="#arch.pipeline">Display Pipeline</a></li>
|
|
<li><a href="#arch.windows">Window System</a></li>
|
|
<li><a href="#arch.widgets">Widget System</a></li>
|
|
<li><a href="#arch.dxe">DXE Module System</a></li>
|
|
<li><a href="#arch.events">Event Model</a></li>
|
|
<li><a href="#arch.fonts">Font System</a></li>
|
|
<li><a href="#arch.colors">Color System</a></li>
|
|
<li><a href="#arch.platform">Platform Layer</a></li>
|
|
<li><a href="#arch.build">Build System</a></li>
|
|
</ul>
|
|
<h3>Index</h3>
|
|
<ul>
|
|
<li><a href="#arch.overview">DVX</a></li>
|
|
<li><a href="#arch.overview">Architecture</a></li>
|
|
<li><a href="#arch.overview">DJGPP</a></li>
|
|
<li><a href="#arch.overview">DPMI</a></li>
|
|
<li><a href="#arch.layers">Layers</a></li>
|
|
<li><a href="#arch.layers">dvxVideo</a></li>
|
|
<li><a href="#arch.layers">dvxDraw</a></li>
|
|
<li><a href="#arch.layers">dvxComp</a></li>
|
|
<li><a href="#arch.layers">dvxWm</a></li>
|
|
<li><a href="#arch.layers">dvxApp</a></li>
|
|
<li><a href="#arch.pipeline">Display Pipeline</a></li>
|
|
<li><a href="#arch.pipeline">Backbuffer</a></li>
|
|
<li><a href="#arch.pipeline">Linear Framebuffer</a></li>
|
|
<li><a href="#arch.pipeline">LFB</a></li>
|
|
<li><a href="#arch.pipeline">Dirty Rects</a></li>
|
|
<li><a href="#arch.pipeline">Double Buffer</a></li>
|
|
<li><a href="#arch.pipeline">Compositing</a></li>
|
|
<li><a href="#arch.pipeline">DisplayT</a></li>
|
|
<li><a href="#arch.pipeline">BlitOpsT</a></li>
|
|
<li><a href="#arch.pipeline">DirtyListT</a></li>
|
|
<li><a href="#arch.windows">Window</a></li>
|
|
<li><a href="#arch.windows">WindowT</a></li>
|
|
<li><a href="#arch.windows">Z-Order</a></li>
|
|
<li><a href="#arch.windows">Chrome</a></li>
|
|
<li><a href="#arch.windows">Hit Testing</a></li>
|
|
<li><a href="#arch.windows">Menu System</a></li>
|
|
<li><a href="#arch.windows">Minimized Windows</a></li>
|
|
<li><a href="#arch.windows">Window Stack</a></li>
|
|
<li><a href="#arch.windows">Menus</a></li>
|
|
<li><a href="#arch.windows">Submenus</a></li>
|
|
<li><a href="#arch.widgets">Widgets</a></li>
|
|
<li><a href="#arch.widgets">WidgetT</a></li>
|
|
<li><a href="#arch.widgets">WidgetClassT</a></li>
|
|
<li><a href="#arch.widgets">Layout Engine</a></li>
|
|
<li><a href="#arch.widgets">Widget API</a></li>
|
|
<li><a href="#arch.widgets">Layout</a></li>
|
|
<li><a href="#arch.widgets">Flexbox</a></li>
|
|
<li><a href="#arch.widgets">WgtIfaceT</a></li>
|
|
<li><a href="#arch.dxe">DXE</a></li>
|
|
<li><a href="#arch.dxe">DXE3</a></li>
|
|
<li><a href="#arch.dxe">Modules</a></li>
|
|
<li><a href="#arch.dxe">Dynamic Loading</a></li>
|
|
<li><a href="#arch.dxe">Boot Sequence</a></li>
|
|
<li><a href="#arch.dxe">Crash Recovery</a></li>
|
|
<li><a href="#arch.dxe">Memory Tracking</a></li>
|
|
<li><a href="#arch.events">Events</a></li>
|
|
<li><a href="#arch.events">Input</a></li>
|
|
<li><a href="#arch.events">Mouse</a></li>
|
|
<li><a href="#arch.events">Keyboard</a></li>
|
|
<li><a href="#arch.events">Polling</a></li>
|
|
<li><a href="#arch.events">Cooperative</a></li>
|
|
<li><a href="#arch.events">Event Dispatch</a></li>
|
|
<li><a href="#arch.events">Accelerator Tables</a></li>
|
|
<li><a href="#arch.events">Cursor</a></li>
|
|
<li><a href="#arch.events">Double-Click</a></li>
|
|
<li><a href="#arch.fonts">Fonts</a></li>
|
|
<li><a href="#arch.fonts">Bitmap Font</a></li>
|
|
<li><a href="#arch.fonts">BitmapFontT</a></li>
|
|
<li><a href="#arch.fonts">Text Rendering</a></li>
|
|
<li><a href="#arch.fonts">CP437</a></li>
|
|
<li><a href="#arch.colors">Colors</a></li>
|
|
<li><a href="#arch.colors">Pixel Format</a></li>
|
|
<li><a href="#arch.colors">PixelFormatT</a></li>
|
|
<li><a href="#arch.colors">ColorSchemeT</a></li>
|
|
<li><a href="#arch.colors">Theming</a></li>
|
|
<li><a href="#arch.colors">Bevel</a></li>
|
|
<li><a href="#arch.platform">Platform Layer</a></li>
|
|
<li><a href="#arch.platform">dvxPlatform</a></li>
|
|
<li><a href="#arch.platform">VESA</a></li>
|
|
<li><a href="#arch.platform">VBE</a></li>
|
|
<li><a href="#arch.platform">INT 33h</a></li>
|
|
<li><a href="#arch.platform">INT 16h</a></li>
|
|
<li><a href="#arch.platform">Assembly</a></li>
|
|
<li><a href="#arch.platform">rep stosl</a></li>
|
|
<li><a href="#arch.platform">rep movsd</a></li>
|
|
<li><a href="#arch.build">Build</a></li>
|
|
<li><a href="#arch.build">Makefile</a></li>
|
|
<li><a href="#arch.build">Cross-Compilation</a></li>
|
|
<li><a href="#arch.build">dxe3gen</a></li>
|
|
<li><a href="#arch.build">mkcd.sh</a></li>
|
|
<li><a href="#arch.build">ISO</a></li>
|
|
</ul>
|
|
</nav>
|
|
<main>
|
|
<div class="topic" id="arch.overview">
|
|
<h1>DVX Architecture Overview</h1>
|
|
<h2>DVX Architecture Overview</h2>
|
|
<p>DOS Visual eXecutive -- A Windowing GUI for DJGPP/DPMI</p>
|
|
<p>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.</p>
|
|
<h3>Key Design Constraints</h3>
|
|
<ul>
|
|
<li>VESA VBE 2.0+ LFB only -- no bank switching. If the hardware cannot
|
|
provide a linear framebuffer, initialization fails.</li>
|
|
<li>486 baseline -- all hot paths are written to be fast on a 486, with
|
|
Pentium-specific paths where the gain is significant.</li>
|
|
<li>Single-tasking cooperative model -- applications yield the CPU via
|
|
tsYield(); there is no preemptive scheduler.</li>
|
|
<li>86Box is the trusted reference platform for testing. DOSBox-X is not used;
|
|
any bugs observed are treated as DVX bugs.</li>
|
|
</ul>
|
|
<p>No external font or cursor files -- all bitmaps are compiled in as static
|
|
const data.</p>
|
|
<p>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.</p>
|
|
<h3>Contents</h3>
|
|
<ul>
|
|
<li>.link arch.overview System Overview</li>
|
|
<li>.link arch.layers Five-Layer Architecture</li>
|
|
<li>.link arch.pipeline Display Pipeline</li>
|
|
<li>.link arch.windows Window System</li>
|
|
<li>.link arch.widgets Widget System</li>
|
|
<li>.link arch.dxe DXE Module System</li>
|
|
<li>.link arch.events Event Model</li>
|
|
<li>.link arch.fonts Font System</li>
|
|
<li>.link arch.colors Color System</li>
|
|
<li>.link arch.platform Platform Layer</li>
|
|
</ul>
|
|
<p>.link arch.build Build System</p>
|
|
</div>
|
|
<div class="topic" id="arch.layers">
|
|
<h1>Five-Layer Architecture</h1>
|
|
<h2>Five-Layer Architecture</h2>
|
|
<p>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.</p>
|
|
<pre><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 (dvxPlatform.h) | | dvxPlatformDos.c
|
|
| | OS-specific: video, input, asm spans | |
|
|
| +------------------------------------------+ |
|
|
| |
|
|
| +------------------------------------------+ |
|
|
| | Shared Types (dvxTypes.h) | |
|
|
| | DisplayT, WindowT, RectT, ColorSchemeT | |
|
|
| +------------------------------------------+ |
|
|
==================================================</code></pre>
|
|
<h3>Layer Summary</h3>
|
|
<pre> 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.</pre>
|
|
</div>
|
|
<div class="topic" id="arch.pipeline">
|
|
<h1>Display Pipeline</h1>
|
|
<h2>Display Pipeline</h2>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<h3>Per-Frame Compositing Pipeline</h3>
|
|
<pre><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)</code></pre>
|
|
<h3>Key Data Structures</h3>
|
|
<p>DisplayT -- Central display context: width, height, pitch, pixel format, LFB
|
|
pointer, backbuffer pointer, palette, clip rectangle. Passed by pointer
|
|
through every layer -- no globals.</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<h3>Why This Works on a 486</h3>
|
|
<ul>
|
|
<li>A full 640x480x32bpp frame is 1.2 MB -- far too much to flush every frame
|
|
over a slow PCI bus.</li>
|
|
<li>A typical dirty region during normal interaction (typing, menu open) is a
|
|
few KB.</li>
|
|
<li>Merging overlapping dirty rects into larger rects reduces per-rect
|
|
overhead and improves bus utilization.</li>
|
|
</ul>
|
|
<p>Per-window content buffers persist across frames, so windows don't repaint
|
|
on expose -- only when their own content changes.</p>
|
|
</div>
|
|
<div class="topic" id="arch.windows">
|
|
<h1>Window System</h1>
|
|
<h2>Window System</h2>
|
|
<h3>WindowT Structure</h3>
|
|
<p>Each WindowT is the central object of the window manager. Key fields:</p>
|
|
<pre> 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.</pre>
|
|
<h3>Window Stack (Z-Order)</h3>
|
|
<p>WindowStackT is an array of WindowT* ordered front-to-back: index count-1 is
|
|
the topmost window. This allows:</p>
|
|
<ul>
|
|
<li>Back-to-front iteration for painting (painter's algorithm).</li>
|
|
<li>Front-to-back iteration for hit testing (first hit wins).</li>
|
|
</ul>
|
|
<p>Reordering by pointer swap (no copying of large WindowT structs).</p>
|
|
<p>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.</p>
|
|
<h3>Chrome Layout</h3>
|
|
<pre><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 |
|
|
+-------------------------------------------+</code></pre>
|
|
<p>Chrome constants are compile-time defines:</p>
|
|
<pre><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</code></pre>
|
|
<h3>Hit Test Regions</h3>
|
|
<p>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).</p>
|
|
<h3>Menu System</h3>
|
|
<p>Menus use fixed-size arrays with inline char buffers (no heap strings). Up
|
|
to 8 menus per bar, items dynamically allocated. 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.</p>
|
|
<h3>Minimized Windows</h3>
|
|
<p>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.</p>
|
|
</div>
|
|
<div class="topic" id="arch.widgets">
|
|
<h1>Widget System</h1>
|
|
<h2>Widget System</h2>
|
|
<p>The widget system (dvxWidget.h) is a retained-mode toolkit layered on top of
|
|
the window manager. Widgets form a tree rooted at a per-window VBox
|
|
container.</p>
|
|
<h3>WidgetT Base Structure</h3>
|
|
<p>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*).</p>
|
|
<p>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.</p>
|
|
<h3>Layout Engine</h3>
|
|
<p>Two-pass flexbox-like algorithm:</p>
|
|
<ul>
|
|
<li>Bottom-up (calcMinSize) -- compute minimum sizes for every widget,
|
|
starting from leaves.</li>
|
|
</ul>
|
|
<p>Top-down (layout) -- allocate space within available bounds, distributing
|
|
extra space according to weight values (0 = fixed, 100 = normal stretch).</p>
|
|
<p>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).</p>
|
|
<h3>Widget Class Dispatch (WidgetClassT)</h3>
|
|
<p>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.</p>
|
|
<p>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).</p>
|
|
<h4>Class Flags</h4>
|
|
<pre> 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)</pre>
|
|
<h3>Available Widget Types</h3>
|
|
<p>Each widget is a separate .wgt DXE module. 29 widget types are included:</p>
|
|
<pre> 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)</pre>
|
|
<h3>Widget API Registry</h3>
|
|
<p>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.</p>
|
|
<h3>Widget Interface Descriptors (WgtIfaceT)</h3>
|
|
<p>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).</p>
|
|
</div>
|
|
<div class="topic" id="arch.dxe">
|
|
<h1>DXE Module System</h1>
|
|
<h2>DXE Module System</h2>
|
|
<p>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.</p>
|
|
<h3>Module Types</h3>
|
|
<pre> 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</pre>
|
|
<h3>Boot Sequence</h3>
|
|
<pre><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()</code></pre>
|
|
<h3>Application Lifecycle</h3>
|
|
<p>Two kinds of DXE apps:</p>
|
|
<h4>Callback-only (hasMainLoop = false)</h4>
|
|
<p>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.</p>
|
|
<h4>Main-loop (hasMainLoop = true)</h4>
|
|
<p>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.</p>
|
|
<h3>Crash Recovery</h3>
|
|
<p>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.</p>
|
|
<h3>Per-App Memory Tracking</h3>
|
|
<p>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.</p>
|
|
</div>
|
|
<div class="topic" id="arch.events">
|
|
<h1>Event Model</h1>
|
|
<h2>Event Model</h2>
|
|
<p>DVX uses a cooperative polling model. The main loop (dvxRun / dvxUpdate)
|
|
runs this cycle each frame:</p>
|
|
<ul>
|
|
<li>Poll mouse -- platformMousePoll() returns position and button bitmask.
|
|
Compare with previous frame for press/release edge detection.</li>
|
|
<li>Poll keyboard -- platformKeyboardRead() returns ASCII + scancode.
|
|
Non-blocking; returns false if buffer is empty.</li>
|
|
<li>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.</li>
|
|
<li>Compositor pass -- merge dirty rects, composite, flush to LFB.</li>
|
|
</ul>
|
|
<p>Yield -- platformYield() or idle callback.</p>
|
|
<h3>Event Dispatch Chain</h3>
|
|
<pre><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.)</code></pre>
|
|
<h3>Accelerator Tables</h3>
|
|
<p>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.</p>
|
|
<h3>Mouse Cursor</h3>
|
|
<p>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.</p>
|
|
<h3>Double-Click Detection</h3>
|
|
<p>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.</p>
|
|
</div>
|
|
<div class="topic" id="arch.fonts">
|
|
<h1>Font System</h1>
|
|
<h2>Font System</h2>
|
|
<p>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).</p>
|
|
<h3>BitmapFontT</h3>
|
|
<pre><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;</code></pre>
|
|
<p>Design rationale:</p>
|
|
<ul>
|
|
<li>Character positions are pure multiplication (x = col * 8).</li>
|
|
<li>Glyph lookup is a single array index.</li>
|
|
<li>Each scanline of a glyph is exactly one byte (1bpp at 8 pixels wide).</li>
|
|
<li>No glyph-width tables, kerning, or per-character positioning needed.</li>
|
|
</ul>
|
|
<p>8-pixel width aligns with byte boundaries -- no bit shifting in per-scanline
|
|
rendering.</p>
|
|
<h3>Text Rendering Functions</h3>
|
|
<p>drawChar() -- Renders a single character. Supports opaque (background fill)
|
|
and transparent modes.</p>
|
|
<p>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.</p>
|
|
<p>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.</p>
|
|
<p>drawTextAccel() -- Renders text with & accelerator markers. The character
|
|
after & is underlined to indicate the keyboard shortcut.</p>
|
|
<h3>Performance Optimization</h3>
|
|
<p>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.</p>
|
|
</div>
|
|
<div class="topic" id="arch.colors">
|
|
<h1>Color System</h1>
|
|
<h2>Color System</h2>
|
|
<h3>Pixel Format</h3>
|
|
<p>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.</p>
|
|
<p>Supported depths:</p>
|
|
<pre> 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).</pre>
|
|
<h3>ColorSchemeT -- Theming</h3>
|
|
<p>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.</p>
|
|
<p>Color roles mirror classic Motif/Windows 3.x conventions:</p>
|
|
<ul>
|
|
<li>desktop -- desktop background</li>
|
|
<li>windowFace, windowHighlight, windowShadow -- window chrome bevel triplet</li>
|
|
<li>activeTitleBg/Fg, inactiveTitleBg/Fg -- focused vs. unfocused title bar</li>
|
|
<li>contentBg/Fg -- window content area</li>
|
|
<li>menuBg/Fg, menuHighlightBg/Fg -- menus</li>
|
|
<li>buttonFace -- button background</li>
|
|
<li>scrollbarBg/Fg/Trough -- scrollbar components</li>
|
|
</ul>
|
|
<p>cursorFg/Bg -- mouse cursor colors</p>
|
|
<p>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().</p>
|
|
<h3>Bevel Styles</h3>
|
|
<p>Bevels are the defining visual element of the Motif aesthetic. Convenience
|
|
macros create bevel style descriptors by swapping highlight and shadow
|
|
colors:</p>
|
|
<pre><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</code></pre>
|
|
</div>
|
|
<div class="topic" id="arch.platform">
|
|
<h1>Platform Layer</h1>
|
|
<h2>Platform Layer</h2>
|
|
<p>All OS-specific and CPU-specific code is isolated behind dvxPlatform.h. To
|
|
port DVX, implement a new dvxPlatformXxx.c against this header.</p>
|
|
<h3>Implementations</h3>
|
|
<pre> 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.</pre>
|
|
<h3>Abstraction Areas</h3>
|
|
<h4>Video</h4>
|
|
<p>platformVideoInit() -- mode probe and framebuffer setup.
|
|
platformVideoShutdown() -- restore previous mode. platformVideoEnumModes()
|
|
-- enumerate available modes.</p>
|
|
<h4>Framebuffer Flush</h4>
|
|
<p>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.</p>
|
|
<h4>Optimized Memory Spans</h4>
|
|
<p>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.</p>
|
|
<h4>Mouse Input</h4>
|
|
<p>Polling model. platformMousePoll() returns position and button bitmask.
|
|
Wheel support via CuteMouse API.</p>
|
|
<h4>Keyboard Input</h4>
|
|
<p>platformKeyboardRead() -- non-blocking key read. platformKeyUpRead() -- key
|
|
release detection (requires INT 9 hook on DOS). platformAltScanToChar() --
|
|
scancode-to-ASCII lookup for Alt+key combinations.</p>
|
|
<h4>Crash Recovery</h4>
|
|
<p>platformInstallCrashHandler() -- signal handlers + longjmp for fault
|
|
tolerance.</p>
|
|
<h4>DXE Support</h4>
|
|
<p>platformRegisterDxeExports() -- register C runtime and platform symbols for
|
|
DXE resolution. platformRegisterSymOverrides() -- register function pointer
|
|
overrides for module loader.</p>
|
|
</div>
|
|
<div class="topic" id="arch.build">
|
|
<h1>Build System</h1>
|
|
<h2>Build System</h2>
|
|
<h3>Cross-Compilation</h3>
|
|
<p>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.</p>
|
|
<pre><code> make -- build everything
|
|
./mkcd.sh -- build + create ISO for 86Box</code></pre>
|
|
<h3>Build Targets</h3>
|
|
<pre><code> all: core tasks loader texthelp listhelp tools widgets shell taskmgr serial sql apps</code></pre>
|
|
<pre> 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</pre>
|
|
<h3>DXE3 Build Process</h3>
|
|
<p>Each DXE module is compiled to an object file with GCC, then linked with
|
|
dxe3gen:</p>
|
|
<pre><code> # Compile
|
|
i586-pc-msdosdjgpp-gcc -O2 -march=i486 -mtune=i586 -c -o widget.o widget.c
|
|
|
|
# Link as DXE with exported symbols
|
|
dxe3gen -o widget.wgt -E _wgtRegister -U widget.o
|
|
|
|
# Optionally append resources
|
|
dvxres build widget.wgt widget.res</code></pre>
|
|
<p>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).</p>
|
|
<h3>Deployment (mkcd.sh)</h3>
|
|
<ul>
|
|
<li>Runs make all.</li>
|
|
<li>Verifies critical outputs exist (dvx.exe, libtasks.lib, libdvx.lib,
|
|
dvxshell.lib).</li>
|
|
<li>Counts widget modules.</li>
|
|
<li>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).</li>
|
|
</ul>
|
|
<p>Places the ISO at ~/.var/app/net._86box._86Box/data/86Box/dvx.iso for 86Box
|
|
to mount as CD-ROM.</p>
|
|
<h3>Compiler Flags</h3>
|
|
<pre><code> -O2 Optimization level 2
|
|
-march=i486 486 instruction set baseline
|
|
-mtune=i586 Optimize scheduling for Pentium
|
|
-Wall -Wextra Full warnings</code></pre>
|
|
<h3>Directory Layout</h3>
|
|
<pre><code> dvxgui/
|
|
+-- core/ Core library sources (dvxVideo, dvxDraw, dvxComp, dvxWm, dvxApp, widget infra)
|
|
| +-- platform/ Platform abstraction (dvxPlatform.h, dvxPlatformDos.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 (86Box <-> secLink <-> telnet)
|
|
+-- sql/ SQLite integration
|
|
+-- bin/ Build output (dvx.exe, libs/, widgets/, apps/, config/)
|
|
+-- obj/ Intermediate object files
|
|
+-- docs/ Documentation</code></pre>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>
|