| .. | ||
| Makefile | ||
| README.md | ||
| shellApp.c | ||
| shellApp.h | ||
| shellExport.c | ||
| shellInfo.c | ||
| shellInfo.h | ||
| shellMain.c | ||
| shellTaskMgr.c | ||
| shellTaskMgr.h | ||
DVX Shell
Windows 3.x-style desktop shell for DOS. Loads applications as DXE3 shared libraries and includes crash recovery so one bad app doesn't take down the system.
Building
make # builds ../bin/dvx.exe
make clean # removes objects and binary
Requires lib/libdvx.a and lib/libtasks.a to be built first.
Files
| File | Purpose |
|---|---|
shellMain.c |
Entry point, main loop, crash recovery, logging |
shellApp.c |
App loading (dlopen), lifecycle, reaping, resource tracking |
shellApp.h |
ShellAppT, AppDescriptorT, AppStateE, DxeAppContextT, shell API |
shellExport.c |
DXE export table and wrapper functions |
Makefile |
Build rules, links -ldvx -ltasks -ldxe -lm |
Shell Main Loop
Each iteration of the main loop:
dvxUpdate()-- process input events, dispatch callbacks, composite dirty rectstsYield()-- give CPU time to main-loop app tasksshellReapApps()-- clean up apps that terminated this framedesktopUpdate()-- notify the desktop app if anything changed
An idle callback (idleYield) yields to app tasks during quiet periods when
there are no events or dirty rects to process.
DXE App Contract
Every .app file must export these symbols:
// Required: app metadata
AppDescriptorT appDescriptor = {
.name = "My App",
.hasMainLoop = false,
.multiInstance = false,
.stackSize = SHELL_STACK_DEFAULT,
.priority = TS_PRIORITY_NORMAL
};
// Required: entry point
int32_t appMain(DxeAppContextT *ctx);
// Optional: graceful shutdown hook
void appShutdown(void);
AppDescriptorT Fields
| Field | Type | Description |
|---|---|---|
name |
char[64] |
Display name shown in Task Manager |
hasMainLoop |
bool |
true = gets its own cooperative task; false = callback-only |
multiInstance |
bool |
true = allow multiple instances via temp file copy |
stackSize |
int32_t |
Task stack size (SHELL_STACK_DEFAULT for 8 KB default) |
priority |
int32_t |
Task priority (TS_PRIORITY_LOW/NORMAL/HIGH) |
DxeAppContextT
Passed to appMain():
| Field | Type | Description |
|---|---|---|
shellCtx |
AppContextT * |
The shell's GUI context for creating windows, drawing, etc. |
appId |
int32_t |
This app's unique ID (1-based slot index) |
appDir |
char[260] |
Directory containing the .app file for relative resource paths |
App Types
Callback-only (hasMainLoop = false):
appMaincalled in shell's task 0, creates windows, registers callbacks, returns 0- App lives through event callbacks dispatched by
dvxUpdate() - Lifecycle ends when the last window is closed
Main-loop (hasMainLoop = true):
- Shell creates a cooperative task via
tsCreate() appMainruns in that task with its own loop callingtsYield()- Lifecycle ends when
appMainreturns
Multi-Instance Support
DXE3's dlopen is reference-counted per path: loading the same .app twice
returns the same handle, sharing all global/static state. For apps that support
multiple instances (multiInstance = true), the shell copies the .app to a
temp file before loading, giving each instance independent code and data. The
temp file is cleaned up when the app terminates.
Apps that don't support multiple instances (multiInstance = false, the default)
are blocked from loading a second time with an error message.
Temp file paths use the TEMP or TMP environment variable if set, falling
back to the current directory.
Resource Tracking
The shell tracks which app owns which windows via sCurrentAppId, a global
set before calling any app code. The shell's dvxCreateWindow wrapper stamps
win->appId with the current app ID. On termination, the shell destroys all
windows belonging to the app.
Crash Recovery
Signal handlers for SIGSEGV, SIGFPE, and SIGILL longjmp back to the shell's
main loop. The scheduler is fixed via tsRecoverToMain(), the crashed app is
force-killed, and a diagnostic message is displayed. Register state and app
identity are logged to dvx.log.
DXE Export Table
The shell registers a symbol export table via dlregsym() before loading any
apps. Most symbols (all dvx*, wgt*, ts*, drawing functions, and required
libc functions) are exported directly. dvxCreateWindow and dvxDestroyWindow
are exported as wrappers that add resource tracking.
Shell API
| Function | Description |
|---|---|
shellAppInit() |
Initialize the app slot table |
shellLoadApp(ctx, path) |
Load and start an app from a .app file |
shellReapApps(ctx) |
Clean up terminated apps (call each frame) |
shellReapApp(ctx, app) |
Gracefully shut down a single app |
shellForceKillApp(ctx, app) |
Forcibly kill an app (skip shutdown hook) |
shellTerminateAllApps(ctx) |
Kill all running apps (shell shutdown) |
shellGetApp(appId) |
Get app slot by ID |
shellRunningAppCount() |
Count running apps |
shellLog(fmt, ...) |
Write to dvx.log |
shellRegisterDesktopUpdate(fn) |
Register callback for app state changes |
shellExportInit() |
Register DXE symbol export table |