DVX_GUI/shell
2026-03-26 19:06:13 -05:00
..
Makefile Task Manager now it's own library. 2026-03-26 16:11:01 -05:00
README.md Docs. 2026-03-25 22:42:07 -05:00
shellApp.c Dynamic memory tracking improved. Callback app reaping fixed. 2026-03-26 19:06:13 -05:00
shellApp.h No more hard coded limits. All dynamic. 2026-03-26 18:33:32 -05:00
shellInfo.c Individual app memory tracking added. 2026-03-26 16:58:40 -05:00
shellInfo.h Start of major refactor for dynamic library and widget loading. 2026-03-22 20:50:25 -05:00
shellMain.c Individual app memory tracking added. 2026-03-26 16:58:40 -05:00

DVX Shell (dvxshell.lib)

The DVX Shell is a DXE3 module loaded by the DVX loader at startup. It initializes the GUI subsystem, loads DXE3 application modules on demand, runs the cooperative main loop, and provides crash recovery so a faulting app does not bring down the entire system.

Entry Point

The loader finds and calls shellMain() after all libs and widgets are loaded. shellMain():

  1. Loads preferences from CONFIG/DVX.INI
  2. Initializes the GUI via dvxInit() with configured video mode
  3. Applies saved mouse, color, and wallpaper settings from INI
  4. Initializes the cooperative task system (tsInit())
  5. Sets shell task (task 0) to TS_PRIORITY_HIGH
  6. Gathers system information via the platform layer
  7. Initializes the app slot table
  8. Registers idle callback, Ctrl+Esc handler, and title change handler
  9. Loads the desktop app (default: apps/progman/progman.app)
  10. Installs the crash handler (after init, so init crashes are fatal)
  11. Enters the main loop

Main Loop

Each iteration of the main loop does four things:

  1. dvxUpdate() -- process input events, dispatch callbacks, composite dirty rects, flush to LFB
  2. tsYield() -- give CPU time to app tasks (if any are active)
  3. shellReapApps() -- clean up any apps that terminated this frame
  4. shellDesktopUpdate() -- notify desktop app if apps were reaped

An idle callback (idleYield) is also registered so that dvxUpdate() yields to app tasks during quiet frames.

App Lifecycle

DXE App Contract

Every DXE app exports two symbols:

  • appDescriptor (AppDescriptorT) -- metadata:

    • name -- display name (max 64 chars)
    • hasMainLoop -- true for main-loop apps, false for callback-only
    • multiInstance -- true to allow multiple instances via temp copy
    • stackSize -- SHELL_STACK_DEFAULT (32KB) or explicit byte count
    • priority -- TS_PRIORITY_NORMAL or custom
  • appMain (int appMain(DxeAppContextT *)) -- entry point

Optional export: appShutdown (void appShutdown(void)) -- called during graceful shutdown.

Callback-Only Apps (hasMainLoop = false)

appMain() is called directly in the shell's task 0. It creates windows, registers callbacks, and returns immediately. The app lives entirely through GUI callbacks. Lifecycle ends when the last window closes.

Main-Loop Apps (hasMainLoop = true)

A dedicated cooperative task is created. appMain() runs in that task and can do its own polling/processing loop, calling tsYield() to share CPU. Lifecycle ends when appMain() returns or the task is killed.

App States

Free -> Loaded -> Running -> Terminating -> Free
State Description
AppStateFreeE Slot available for reuse
AppStateLoadedE DXE loaded, not yet started (transient)
AppStateRunningE Entry point called, active
AppStateTerminatingE Shutdown in progress, awaiting reap

App Slots

App slots are managed as a stb_ds dynamic array (no fixed max). Each slot tracks: app ID, name, path, DXE handle, state, task ID, entry/ shutdown function pointers, and the DxeAppContextT passed to the app.

The DxeAppContextT gives each app:

  • shellCtx -- pointer to the shell's AppContextT
  • appId -- this app's unique ID
  • appDir -- directory containing the .app file (for resources)
  • configDir -- writable config directory (CONFIG/<apppath>/)

App ID Tracking

ctx->currentAppId on AppContextT tracks which app is currently executing. The shell sets this before calling app code. dvxCreateWindow() stamps win->appId directly so the shell can associate windows with apps for cleanup.

Crash Recovery

The platform layer installs signal handlers for SIGSEGV, SIGFPE, and SIGILL via platformInstallCrashHandler(). If a crash occurs:

  1. Platform handler logs signal name and register dump (DJGPP)
  2. Handler longjmps to the setjmp point in shellMain()
  3. tsRecoverToMain() fixes the scheduler's bookkeeping
  4. Shell logs app-specific info (name, path, task ID)
  5. Crashed app is force-killed (shellForceKillApp())
  6. Error dialog is shown to the user
  7. Desktop is notified to refresh
  8. Main loop continues normally

This gives Windows 3.1-style fault tolerance -- one bad app does not take down the whole system.

Task Manager

The built-in Task Manager is always available via Ctrl+Esc. It shows all running apps with their names and provides an "End Task" button for force-killing hung apps. The Task Manager is a shell-level component, not tied to any app -- it persists even if the desktop app is terminated.

Desktop Update Notifications

Apps (especially the desktop app) register callbacks via shellRegisterDesktopUpdate() to be notified when app state changes (load, reap, crash, title change). Multiple callbacks are supported.

Files

File Description
shellMain.c Entry point, main loop, crash recovery, idle callback
shellApp.h App lifecycle types: AppDescriptorT, DxeAppContextT, ShellAppT, AppStateE
shellApp.c App loading, reaping, task creation, DXE management
shellInfo.h System information wrapper
shellInfo.c Gathers and caches hardware info via platform layer
shellTaskMgr.h Task Manager API
shellTaskMgr.c Task Manager window (list of running apps, End Task)
Makefile Builds bin/libs/dvxshell.lib + config/themes/wallpapers

Build

make            # builds dvxshell.lib + dvxshell.dep + config files
make clean      # removes objects, library, and config output

Depends on: libtasks.lib, libdvx.lib, texthelp.lib, listhelp.lib (via dvxshell.dep).