397 lines
14 KiB
Markdown
397 lines
14 KiB
Markdown
# DVX -- DOS Visual eXecutive
|
|
|
|
A windowed GUI compositor and desktop shell for DOS, built with
|
|
DJGPP/DPMI. DVX combines a Motif-style window manager, dirty-rectangle
|
|
compositor, cooperative task switcher, and a modular DXE3 architecture
|
|
into a multitasking desktop environment. The bootstrap loader
|
|
dynamically discovers and loads core libraries, widget plugins, and
|
|
applications at runtime.
|
|
|
|
Targets real and emulated 486+ hardware with VESA VBE 2.0+ linear
|
|
framebuffer. No bank switching -- LFB or fail.
|
|
|
|
|
|
## Features
|
|
|
|
- Motif/GEOS-style beveled window chrome with drag, resize, minimize,
|
|
maximize, and restore
|
|
- Dirty-rectangle compositor -- only changed regions are flushed to video
|
|
memory, critical for acceptable frame rates on 486/Pentium hardware
|
|
- 32 widget types across 26 DXE modules: buttons, text inputs, list
|
|
boxes, tree views, list views, tab controls, sliders, spinners,
|
|
progress bars, dropdowns, combo boxes, splitters, scroll panes, ANSI
|
|
terminal emulator, and more
|
|
- Flexbox-style automatic layout engine (VBox/HBox containers with
|
|
weighted space distribution)
|
|
- Dropdown menus with cascading submenus, checkbox and radio items,
|
|
keyboard accelerators, and context menus
|
|
- Modal dialogs: message box (OK/Cancel/Yes/No/Retry) and file
|
|
open/save with directory navigation and filter dropdown
|
|
- 20-color theme system with live preview and INI-based theme files
|
|
- Wallpaper support: stretch, tile, or center with bilinear scaling and
|
|
16bpp ordered dithering
|
|
- Live video mode switching without restart
|
|
- Mouse wheel support (CuteMouse Wheel API)
|
|
- Screenshots (full screen or per-window) saved as PNG
|
|
- Clipboard (copy/cut/paste within DVX)
|
|
- Timer widget for periodic callbacks
|
|
- Cooperative task switcher for apps that need their own main loop
|
|
- DXE3 dynamic application loading with crash recovery (SIGSEGV,
|
|
SIGFPE, SIGILL caught and isolated per-app)
|
|
- INI-based preferences system with typed read/write accessors
|
|
- Encrypted serial networking stack (DH key exchange, XTEA-CTR cipher)
|
|
- Platform abstraction layer -- DOS/DJGPP production target, Linux/SDL2
|
|
development target
|
|
- Modular DXE architecture with dependency resolution -- core libraries,
|
|
widget plugins, and applications are all separate loadable modules
|
|
|
|
|
|
## Target Hardware
|
|
|
|
- **CPU**: 486 baseline, Pentium-optimized paths where significant
|
|
- **Video**: VESA VBE 2.0+ with linear framebuffer
|
|
- **OS**: DOS with DPMI (CWSDPMI or equivalent)
|
|
- **Supported depths**: 8, 15, 16, 24, 32 bpp
|
|
- **Test platform**: 86Box with PCI video cards
|
|
|
|
|
|
## Architecture
|
|
|
|
DVX uses a modular DXE3 architecture. The bootstrap loader (`dvx.exe`)
|
|
is a small executable that discovers, dependency-sorts, and loads all
|
|
modules at startup. Core libraries, widget plugins, and applications
|
|
are separate `.lib`, `.wgt`, and `.app` DXE shared libraries.
|
|
|
|
```
|
|
dvx.exe (bootstrap loader)
|
|
|
|
|
+-- platformRegisterDxeExports() -- platform + libc/libm symbols
|
|
|
|
|
+-- libs/ (scanned, dependency-ordered)
|
|
| libtasks.lib -- cooperative task switching, stb_ds
|
|
| libdvx.lib -- draw, comp, wm, app, widget infrastructure
|
|
| dvxshell.lib -- shell, app lifecycle, crash recovery
|
|
|
|
|
+-- widgets/ (scanned, each calls wgtRegister)
|
|
| box.wgt, button.wgt, label.wgt, ... (26 modules)
|
|
|
|
|
+-- shellMain() -- found via dlsym, enters main loop
|
|
|
|
|
+-- apps/ (loaded on demand by shell)
|
|
progman.app, notepad.app, clock.app, ...
|
|
```
|
|
|
|
### Boot Sequence
|
|
|
|
1. `dvx.exe` starts, calls `platformRegisterDxeExports()` to register
|
|
platform and libc/libm symbols for DXE modules
|
|
2. Scans `libs/` recursively for `*.lib` files, reads `.dep` files,
|
|
topologically sorts, and loads in dependency order
|
|
3. Scans `widgets/` recursively for `*.wgt` files, loads each, and
|
|
calls `wgtRegister()` on any module that exports it
|
|
4. Finds `shellMain()` across loaded modules via `dlsym`
|
|
5. Calls `shellMain()`, which initializes the GUI, loads the desktop
|
|
app, and enters the main event loop
|
|
|
|
### Dependency Resolution
|
|
|
|
Each DXE module may have a `.dep` file (same base name, `.dep`
|
|
extension) listing the base names of modules that must be loaded before
|
|
it. The loader reads all `.dep` files, builds a dependency graph, and
|
|
loads modules in topological order. For example, `libdvx.dep` contains
|
|
`libtasks`, and `dvxshell.dep` lists `libtasks`, `libdvx`, and all
|
|
widget modules it requires.
|
|
|
|
### Widget DXE Modules
|
|
|
|
The 32 widget types in the `WidgetTypeE` enum are implemented across 26
|
|
`.wgt` DXE modules. Some modules register multiple widget types:
|
|
|
|
| Module | Widget Types |
|
|
|--------|-------------|
|
|
| `box.wgt` | VBox, HBox, Frame |
|
|
| `radio.wgt` | RadioGroup, Radio |
|
|
| `textinpt.wgt` | TextInput, TextArea |
|
|
| `tabctrl.wgt` | TabControl, TabPage |
|
|
| `treeview.wgt` | TreeView, TreeItem |
|
|
|
|
Each widget DXE exports a standard `wgtRegister()` function that
|
|
registers its widget class(es) with the core widget infrastructure.
|
|
Widget DXEs are discovered by directory scanning, not hardcoded.
|
|
|
|
### App Types
|
|
|
|
**Callback-only** (`hasMainLoop = false`): `appMain` creates windows,
|
|
registers callbacks, and returns. The app lives through event callbacks
|
|
in the shell's main loop. No dedicated task or stack needed.
|
|
|
|
**Main-loop** (`hasMainLoop = true`): A cooperative task is created for
|
|
the app. `appMain` runs its own loop calling `tsYield()` to share CPU.
|
|
Used for apps that need continuous processing (clocks, terminal
|
|
emulators, games).
|
|
|
|
### Crash Recovery
|
|
|
|
The shell installs signal handlers for SIGSEGV, SIGFPE, and SIGILL. If
|
|
an app crashes, the handler `longjmp`s back to the shell's main loop,
|
|
the crashed app is force-killed, and the shell continues running.
|
|
Diagnostic information (registers, faulting EIP) is logged to `dvx.log`.
|
|
|
|
|
|
## Directory Structure
|
|
|
|
### Source Tree
|
|
|
|
```
|
|
dvxgui/
|
|
core/ Core GUI infrastructure (-> libs/libdvx.lib)
|
|
platform/ Platform abstraction (dvxPlatform.h, dvxPlatformDos.c)
|
|
thirdparty/ stb_image.h, stb_image_write.h
|
|
tasks/ Cooperative task switcher (-> libs/libtasks.lib)
|
|
thirdparty/ stb_ds.h
|
|
shell/ Desktop shell (-> libs/dvxshell.lib)
|
|
widgets/ Widget modules (-> widgets/*.wgt, 26 files)
|
|
loader/ Bootstrap loader (-> dvx.exe)
|
|
apps/ Application modules (-> apps/*.app)
|
|
progman/ Program Manager -- app launcher grid
|
|
notepad/ Text editor with file I/O
|
|
clock/ Digital clock (multi-instance, main-loop)
|
|
dvxdemo/ Widget system showcase / demo app
|
|
cpanel/ Control Panel -- themes, wallpaper, video, mouse
|
|
imgview/ Image Viewer -- BMP/PNG/JPEG/GIF display
|
|
config/ Themes, wallpapers, dvx.ini, dependency files
|
|
rs232/ ISR-driven UART serial driver (librs232.a)
|
|
packet/ HDLC framing, CRC-16, Go-Back-N (libpacket.a)
|
|
security/ DH key exchange, XTEA-CTR cipher (libsecurity.a)
|
|
seclink/ Secure serial link wrapper (libseclink.a)
|
|
proxy/ Linux serial-to-telnet proxy (secproxy)
|
|
termdemo/ Encrypted ANSI terminal demo (termdemo.exe)
|
|
bin/ Build output
|
|
lib/ Build output (static libraries)
|
|
releases/ Release archives
|
|
```
|
|
|
|
### Build Output (`bin/`)
|
|
|
|
```
|
|
bin/
|
|
dvx.exe Bootstrap loader
|
|
dvx.map Linker map
|
|
libs/
|
|
libtasks.lib Task switching DXE
|
|
libdvx.lib Core GUI DXE
|
|
libdvx.dep Dependencies: libtasks
|
|
dvxshell.lib Shell DXE
|
|
dvxshell.dep Dependencies: libtasks, libdvx, box, button, etc.
|
|
widgets/
|
|
box.wgt VBox/HBox/Frame
|
|
button.wgt Button
|
|
canvas.wgt Canvas
|
|
checkbox.wgt Checkbox
|
|
combobox.wgt ComboBox
|
|
dropdown.wgt Dropdown
|
|
image.wgt Image
|
|
imgbtn.wgt ImageButton
|
|
label.wgt Label
|
|
listbox.wgt ListBox
|
|
listview.wgt ListView
|
|
progress.wgt ProgressBar
|
|
radio.wgt RadioGroup/Radio
|
|
scrlpane.wgt ScrollPane
|
|
separatr.wgt Separator
|
|
slider.wgt Slider
|
|
spacer.wgt Spacer
|
|
spinner.wgt Spinner
|
|
splitter.wgt Splitter
|
|
statbar.wgt StatusBar
|
|
tabctrl.wgt TabControl/TabPage
|
|
terminal.wgt AnsiTerm
|
|
textinpt.wgt TextInput/TextArea
|
|
timer.wgt Timer
|
|
toolbar.wgt Toolbar
|
|
treeview.wgt TreeView/TreeItem
|
|
apps/
|
|
progman/progman.app
|
|
notepad/notepad.app
|
|
clock/clock.app
|
|
dvxdemo/dvxdemo.app
|
|
cpanel/cpanel.app
|
|
imgview/imgview.app
|
|
config/
|
|
dvx.ini
|
|
themes/
|
|
cde.thm
|
|
geos.thm
|
|
win31.thm
|
|
wpaper/
|
|
blueglow.jpg
|
|
swoop.jpg
|
|
triangle.jpg
|
|
```
|
|
|
|
|
|
## Building
|
|
|
|
Requires the DJGPP cross-compiler (`i586-pc-msdosdjgpp-gcc`).
|
|
|
|
```bash
|
|
# Build everything (loader, core, tasks, shell, widgets, all apps)
|
|
make
|
|
|
|
# Build individual components
|
|
make -C loader # builds dvx.exe
|
|
make -C core # builds libs/libdvx.lib + widgets/*.wgt
|
|
make -C tasks # builds libs/libtasks.lib
|
|
make -C shell # builds libs/dvxshell.lib + config
|
|
make -C widgets # builds widgets/*.wgt
|
|
make -C apps # builds apps/*/*.app
|
|
|
|
# Clean all build artifacts
|
|
make clean
|
|
```
|
|
|
|
Set `DJGPP_PREFIX` in the component Makefiles if your toolchain is
|
|
installed somewhere other than `~/djgpp/djgpp`.
|
|
|
|
|
|
## Deployment
|
|
|
|
### CD-ROM ISO (86Box)
|
|
|
|
The primary deployment method is an ISO image mounted as a CD-ROM in
|
|
86Box:
|
|
|
|
```bash
|
|
./mkcd.sh
|
|
```
|
|
|
|
This builds everything, then creates an ISO 9660 image with 8.3
|
|
filenames at `~/.var/app/net._86box._86Box/data/86Box/dvx.iso`. Mount
|
|
it in 86Box as a CD-ROM drive and run `D:\DVX.EXE` (or whatever drive
|
|
letter is assigned).
|
|
|
|
## Configuration
|
|
|
|
DVX reads its configuration from `CONFIG\DVX.INI` on the target
|
|
filesystem. The INI file uses a standard `[section]` / `key = value`
|
|
format. Settings are applied at startup and can be changed live from the
|
|
Control Panel app.
|
|
|
|
```ini
|
|
[video]
|
|
width = 640
|
|
height = 480
|
|
bpp = 16
|
|
|
|
[mouse]
|
|
wheel = normal
|
|
doubleclick = 500
|
|
acceleration = medium
|
|
|
|
[colors]
|
|
desktop = 0,128,128
|
|
windowFace = 192,192,192
|
|
windowHighlight = 255,255,255
|
|
windowShadow = 128,128,128
|
|
activeTitleBg = 48,48,48
|
|
activeTitleFg = 255,255,255
|
|
inactiveTitleBg = 160,160,160
|
|
inactiveTitleFg = 64,64,64
|
|
contentBg = 192,192,192
|
|
contentFg = 0,0,0
|
|
menuBg = 192,192,192
|
|
menuFg = 0,0,0
|
|
menuHighlightBg = 48,48,48
|
|
menuHighlightFg = 255,255,255
|
|
buttonFace = 192,192,192
|
|
scrollbarBg = 192,192,192
|
|
scrollbarFg = 128,128,128
|
|
scrollbarTrough = 160,160,160
|
|
cursorColor = 255,255,255
|
|
cursorOutline = 0,0,0
|
|
|
|
[desktop]
|
|
wallpaper = C:\DVX\WPAPER\SWOOP.JPG
|
|
mode = stretch
|
|
```
|
|
|
|
### Video Section
|
|
|
|
- `width`, `height` -- requested resolution (closest VESA mode is used)
|
|
- `bpp` -- preferred color depth (8, 15, 16, 24, or 32)
|
|
|
|
### Mouse Section
|
|
|
|
- `wheel` -- `normal` or `reversed`
|
|
- `doubleclick` -- double-click speed in milliseconds (200--900)
|
|
- `acceleration` -- `off`, `low`, `medium`, or `high`
|
|
|
|
### Colors Section
|
|
|
|
All 20 system colors as `R,G,B` triplets (0--255). Key names match the
|
|
`ColorIdE` enum: `desktop`, `windowFace`, `windowHighlight`, `windowShadow`,
|
|
`activeTitleBg`, `activeTitleFg`, `inactiveTitleBg`, `inactiveTitleFg`,
|
|
`contentBg`, `contentFg`, `menuBg`, `menuFg`, `menuHighlightBg`,
|
|
`menuHighlightFg`, `buttonFace`, `scrollbarBg`, `scrollbarFg`,
|
|
`scrollbarTrough`, `cursorColor`, `cursorOutline`. Missing keys fall back to
|
|
compiled-in defaults (GEOS Ensemble palette). Colors can also be loaded from
|
|
standalone `.thm` theme files via the Control Panel.
|
|
|
|
### Desktop Section
|
|
|
|
- `wallpaper` -- path to wallpaper image (BMP, PNG, JPEG, GIF)
|
|
- `mode` -- `stretch`, `tile`, or `center`
|
|
|
|
|
|
## Bundled Applications
|
|
|
|
| App | File | Type | Description |
|
|
|-----|------|------|-------------|
|
|
| Program Manager | `progman.app` | Callback | App launcher grid with icons; Help menu opens the shell's Task Manager (Ctrl+Esc) |
|
|
| Notepad | `notepad.app` | Callback | Text editor with File/Edit menus, open/save dialogs, clipboard, and undo |
|
|
| Clock | `clock.app` | Main-loop | Digital clock display; multi-instance capable |
|
|
| DVX Demo | `dvxdemo.app` | Callback | Widget system showcase demonstrating all 32 widget types |
|
|
| Control Panel | `cpanel.app` | Callback | System settings: color themes with live preview, wallpaper selection, video mode switching, mouse configuration |
|
|
| Image Viewer | `imgview.app` | Callback | Displays BMP, PNG, JPEG, and GIF images with file dialog |
|
|
|
|
|
|
## Serial / Networking Stack
|
|
|
|
A layered encrypted serial communications stack for connecting DVX to
|
|
remote systems (BBS, etc.) through 86Box's emulated UART:
|
|
|
|
| Layer | Library | Description |
|
|
|-------|---------|-------------|
|
|
| rs232 | `librs232.a` | ISR-driven UART driver with FIFO support, automatic UART type detection (8250 through 16750), configurable baud rate |
|
|
| packet | `libpacket.a` | HDLC framing with byte stuffing, CRC-16 integrity checks, Go-Back-N sliding window for reliable delivery, 255-byte max payload |
|
|
| security | `libsecurity.a` | 1024-bit Diffie-Hellman key exchange (RFC 2409 Group 2), XTEA-CTR stream cipher, XTEA-CTR DRBG random number generator |
|
|
| seclink | `libseclink.a` | Convenience wrapper: multiplexed channels (0--127), per-packet encryption flag, bulk send helper |
|
|
| proxy | `secproxy` | Linux-side bridge: 86Box emulated serial port <-> secLink <-> telnet BBS; socket shim replaces rs232 API |
|
|
|
|
|
|
## Third-Party Dependencies
|
|
|
|
All third-party code is vendored as single-header libraries with no
|
|
external dependencies:
|
|
|
|
| Library | Location | Purpose |
|
|
|---------|----------|---------|
|
|
| stb_image.h | `core/thirdparty/` | Image loading (BMP, PNG, JPEG, GIF) |
|
|
| stb_image_write.h | `core/thirdparty/` | Image writing (PNG export for screenshots) |
|
|
| stb_ds.h | `tasks/thirdparty/` | Dynamic array and hash map (used by task manager) |
|
|
|
|
|
|
## Component Documentation
|
|
|
|
Each component directory has its own README with detailed API reference:
|
|
|
|
- [`core/README.md`](core/README.md) -- Core GUI library architecture and API
|
|
- [`tasks/README.md`](tasks/README.md) -- Task switcher API
|
|
- [`shell/README.md`](shell/README.md) -- Shell internals and DXE app contract
|
|
- [`apps/README.md`](apps/README.md) -- Writing DXE applications
|
|
- [`rs232/README.md`](rs232/README.md) -- Serial port driver
|
|
- [`packet/README.md`](packet/README.md) -- Packet transport protocol
|
|
- [`security/README.md`](security/README.md) -- Cryptographic primitives
|
|
- [`seclink/README.md`](seclink/README.md) -- Secure serial link
|
|
- [`proxy/README.md`](proxy/README.md) -- Linux SecLink proxy
|
|
- [`termdemo/README.md`](termdemo/README.md) -- Encrypted terminal demo
|