# DVX Shell Applications Every DVX application is a DXE3 module packaged as a `.app` file, installed under `bin/apps/kpunch//.app`. The Program Manager scans this directory at startup and displays each discovered app as a launchable icon on the desktop. This directory holds the source for the bundled applications plus the BASIC-based sample apps. Two flavours of app live side by side: * **C apps** -- written directly against the DVX SDK headers, compiled to a DXE3 by `dxe3gen`. See `progman/`, `dvxdemo/`, `cpanel/`, `dvxhelp/`. * **BASIC apps** -- `.dbp` projects compiled to `.app` files by the host-side `bascomp`. The compiler links the BASIC bytecode into a copy of `basstub.app`, which acts as the runtime host. See `iconed/`, `notepad/`, `imgview/`, `basdemo/`, `resedit/`, `widshow/`, `helpedit/`, `clock/`, `welcome/`, `fileMgr/`, `terminal/`, `player/`, `recorder/`. The rest of this document covers writing a C app against the SDK. For BASIC apps, see `dvxbasic/README.md`. A new app outside this tree starts from the SDK templates (`bin/sdk/newProject.sh app|basic NAME`, sources in `src/sdk/`). ## DXE App Contract Every `.app` binary exports two required symbols and one optional symbol: ```c AppDescriptorT appDescriptor; // required (SHELL_APP_DESCRIPTOR) int32_t appMain(DxeAppContextT *ctx); // required void appShutdown(void); // optional ``` ### `appDescriptor` A statically-initialised struct read by the shell at load time to decide how to launch the app. Declare it with `SHELL_APP_DESCRIPTOR`, which names the global and records the `DVX_ABI_VERSION` the app was built with; the shell refuses an app whose `abiVersion` differs ("This program was built for a different version of DVX and cannot run."). ```c typedef struct { uint32_t abiVersion; // set by SHELL_APP_DESCRIPTOR; first char name[SHELL_APP_NAME_MAX]; // display name (<= 64 chars) bool hasMainLoop; // see below bool multiInstance; // may have multiple copies open int32_t stackSize; // SHELL_STACK_DEFAULT or byte count int32_t priority; // TS_PRIORITY_* for main-loop apps } AppDescriptorT; ``` Example (from the SDK's game template, `src/sdk/templates/game/tplName.c`): ```c SHELL_APP_DESCRIPTOR( .name = TPLNAME_TITLE, .hasMainLoop = true, .multiInstance = false, .stackSize = SHELL_STACK_DEFAULT, .priority = TS_PRIORITY_NORMAL ); ``` ### `appMain` Entry point. The shell calls it with a `DxeAppContextT` that exposes the shell's GUI context, the app's ID, its install directory, its writable folder in the user folder (`userDir`: `shellEnsureUserDir`, `shellUserPath`; shipped files are in `DATA/` beside the .app: `shellDataPath`), launch arguments, and a help-topic query callback for F1. Returning from `appMain` signals that the app has finished; the shell unloads the DXE, frees per-app memory, and reclaims the app slot. ### `appShutdown` Called by the shell when the app is force-killed (by the Task Manager) or when the shell is shutting down with this app still running. Main-loop apps use it to set a flag that their main loop observes, so the loop exits cleanly and `appMain` can return. ## App Types ### Callback-only apps (`hasMainLoop = false`) `appMain` creates windows, registers callbacks, and returns 0. The shell drives all further work by invoking those callbacks in response to user input and timers. No dedicated task is allocated; no per-app stack is consumed. The app's lifetime ends when the last window closes (or when every callback has released all references). Use this pattern for event-driven UI: Notepad, Program Manager, DVX Demo, Control Panel, Image Viewer. ### Main-loop apps (`hasMainLoop = true`) The shell creates a cooperative task for the app and calls `appMain` from inside it. `appMain` runs a loop that calls `tsYield()` periodically to share the CPU. Exit by breaking out of the loop and returning. Use this pattern when the app needs continuous background work that does not map cleanly onto event callbacks: terminal emulators, games, and every compiled BASIC program (the BASIC stub runs the program and its event loop in the app's task). ## Resource Conventions Apps attach resources to their `.app` binary using `dvxres build` (see `src/tools/README.md`). The standard resource names are: | Name | Type | Meaning | |---------------|--------|---------| | `icon32` | icon | 32x32 BMP shown in Program Manager and the Task Manager. | | `name` | text | Human-readable display name (overrides `appDescriptor.name` for UI where available). | | `author` | text | Author / maintainer name. | | `publisher` | text | Publisher or studio. | | `copyright` | text | Copyright notice. | | `version` | text | Version string, free-form. | | `description` | text | One-sentence description, shown in Program Manager's status bar and List view. | | `helpfile` | text | BASIC apps: name of the app's `.hlp` file, relative to the app's directory (the project's Help File); the BASIC stub sets F1 help from it. Not needed when the file is `.hlp`, which the shell uses by default. | Additional application-specific resources may be attached with any unique name. The runtime reads them via `dvxResOpen(appPath)` / `dvxResRead(handle, name, &size)` / `dvxResClose(handle)`. Typical `.res` manifest: ``` # dvxdemo.res icon32 icon icon32.bmp name text "DVX Demo" author text "Scott Duensing" copyright text "Copyright 2026 Scott Duensing" publisher text "Kangaroo Punch Studios" description text "Widget toolkit demonstration" ``` ## Help Every app has its own help file; the system help (the user guide plus the developer reference, opened from Program Manager) holds only material that applies to every app, and never lists or describes individual apps. * Write the help source as `.dhs` next to `.c` or `.dbp`, where `` is the name of the `.app` file. * The top-level `compile-help` target runs `src/tools/helpFiles.sh`, which finds every such file by name, compiles it to `.hlp` next to `.app`, deploys the source as `.DHS`, and writes an `.HCF` so the loader's boot-time help rebuild produces it too. No list needs editing when an app is added. * F1 needs no code: before `appMain` the shell sets `ctx->helpFile` to `.hlp` beside `.app` when that file exists. * C apps open it from Help > Contents with `shellOpenHelp(ctx->shellCtx, ctx->helpFile)`. * BASIC apps call `HelpView ".hlp"` (from `src/include/basic/help.bas`) from Help > Contents. F1 opens the focused control's or form's `HelpTopic`. * Every app's Help menu has Contents and About. See `claudeDocs/perAppHelp.md` for the full rules. ## Bundled Applications ### Program Manager (progman) | | | |---|---| | File | `apps/kpunch/progman/progman.app` | | Type | Callback-only | | Multi-instance | No | The desktop: program groups in a list on the left, the selected group's items as large icons, small icons, or a list on the right, a search box that filters every group, and a status bar. The automatic "Installed Programs" group is rebuilt from `shellProgramScan()` at start, on View > Refresh, and when the window comes to the front with programs added or removed; items in the "Startup" group run once DVX is up. Groups, items (name, program, arguments, working folder, icon, shortcut key, run minimized, grid cell), view, options, and Run history are saved in `USER/APPS/KPUNCH/PROGMAN/PROGMAN.INI` after every change (crash-safe rewrite). Running, the Run dialog, program discovery, and file associations are shell library services (`shellRun.h`, `shellProg.h`, `shellAssoc.h`) shared with other programs. Closing it exits DVX through `shellRequestExit()`; `shellRegisterDesktopUpdate()` keeps the running count current. Design notes: `claudeDocs/programManager.md`. Sources: `progman.c` (window, menus, commands), `pmModel.c` (groups, items, PROGMAN.INI; no widgets, host-tested), `pmView.c` (the icon view, a private widget class), `pmProps.c` (item Properties dialog). Its own help is `progman.dhs` (progman.hlp). The directory also owns the system help: `dvxhelp.hcf` (on-target rebuild recipe) and `userHelp.dhs`, the end-user guide that is compiled first so its `user.welcome` page is the help file's default topic. ### Notepad (notepad, BASIC) | | | |---|---| | File | `apps/kpunch/notepad/notepad.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | Plain-text editor with File menu (New, Open, Save, Save As) and Edit menu (Cut, Copy, Paste, Select All). Built from a BASIC project (`notepad.dbp` + `notepad.frm`); demonstrates the form designer, TextInput widget, and common dialog integration. ### Clock (clock, BASIC) | | | |---|---| | File | `apps/kpunch/clock/clock.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | Yes | Digital clock showing the time and date, updated by a Timer. Each new copy opens a little lower and to the right of the previous one (`ShellInstanceCount`, shell.bas). Built from `clock.dbp` + `clock.frm`; its help is `clock.dhs`. ### Welcome (welcome, BASIC) | | | |---|---| | File | `apps/kpunch/welcome/welcome.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | The window DVX shows after the desktop when it starts for the first time (DVX.INI `[shell] welcome`, written by Setup). "Don't show this again" removes the key when the window closes; unticked, it writes the program's path back (`ShellSetWelcome`, shell.bas). "Open the User Guide" opens the system help. Built from `welcome.dbp` + `welcome.frm`; its help is `welcome.dhs`. ### File Manager (fileMgr, BASIC) | | | |---|---| | File | `apps/kpunch/fileMgr/fileMgr.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | Yes | Drive buttons, a path box, a folder tree, and a sortable file list with open / run, copy, move, cut / copy / paste between windows, rename, delete, new folder, properties (attributes), selection, and filter commands. Copy, move, and delete run as jobs with their own progress windows, driven by a Timer, so the program stays usable. Built from `fileMgr.dbp`: `fileMgr.frm` (the window), `fmProps.frm` (Properties), `fileMgr.bas` (the job engine), `fmJob.cls`, with the fileops.bas, shell.bas, commdlg.bas, and help.bas libraries; its help is `fileMgr.dhs`. ### Terminal (terminal, BASIC) | | | |---|---| | File | `apps/kpunch/terminal/terminal.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | Yes (one per COM port, for example) | A BBS / serial terminal: serial port, modem (dialing, redial, carrier loss), the secure link to the DVX host proxy (with or without a passphrase), and Telnet; a phone book of sessions (TERMINAL.INI in its settings folder); the ANSI terminal with scrollback, colors, local echo, answerback, capture to file, and break; XMODEM, XMODEM-1K, YMODEM, and ZMODEM uploads and downloads (ZMODEM downloads start by themselves) with a progress window that asks about existing files. The connection, the terminal feed, and the transfers run in the conn and xfer libraries (conn.bas, xfer.bas); a 10 ms Timer moves them along. Started with `telnet://host[:port]` it connects to that host. Built from `terminal.dbp`: `terminal.frm` (the window), `termBook.frm` (Phone Book), `termSess.frm` (Session Settings), `termXfer.frm` (Transfer Options), `termPass.frm` (passphrase), `termProg.frm` (File Transfer), `terminal.bas` (the phone book and shared state), `termMain.bas` (the start), with the conn.bas, xfer.bas, prefs.bas, fileops.bas, shell.bas, commdlg.bas, and help.bas libraries; its help is `terminal.dhs`. ### Media Player (player, BASIC) | | | |---|---| | File | `apps/kpunch/player/player.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No (a second start hands its files over: NewArgs) | Plays music modules (MOD, S3M, XM, IT), MIDI files (MID, RMI), and WAV and VOC sounds from a list, through music.lib (music.bas): play, pause, stop, previous, next, a position slider that seeks once it stands still, a volume slider, Repeat Off / List / Track, and Shuffle (a shuffled play order with the track playing first). A 250 ms Timer shows the position and notices a track's end. Files named on its command line are added to the list and the first plays; ASSOC.INI opens those file types in it. The list and the settings are kept in PLAYER.INI in its settings folder. Built from `player.dbp` + `player.frm`, with the music.bas, prefs.bas, fileops.bas, commdlg.bas, and help.bas libraries; its help is `player.dhs`. Tested on the host by `src/test/music/playerTest.c` and on DOS by `player.scr`. ### Sound Recorder (recorder, BASIC) | | | |---|---| | File | `apps/kpunch/recorder/recorder.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | Records sound from the card's microphone, line, or CD input into WAV files through audio.lib's recording (sound.bas RecordStart, RecordStop, RecordLength, RecordLevel): Record, Stop, Play (PlayWave), a level meter (a ProgressBar) and the length shown by a 100 ms Timer, the format the card chose. A recording goes into RECORDING.WAV in its settings folder until File > Save As copies it out (FILECOPY); New, Open, and closing ask about a recording not saved. Options picks the quality (telephone 8 kHz 8-bit mono, radio 22 kHz 8-bit mono, CD 44.1 kHz 16-bit stereo) and the input (inputs the card lacks are greyed). The MIDI Keyboard input (when DVX.INI [audio] midiIn names the MIDI port) records MIDI instead: MidiInOpen, each message played as it comes on a live music (MusicMidiSend) and kept in a MIDI recording (MidiRecordAdd with MidiInTime), the Timer at 20 ms meanwhile, the level the last note's velocity; Stop writes RECORDING.MID (MidiRecordSave) and Play plays it with music.lib. Open takes WAV and MIDI files (MusicLoad tells which). Settings are kept in RECORDER.INI. Built from `recorder.dbp` + `recorder.frm`, with the sound.bas, music.bas, prefs.bas, fileops.bas, commdlg.bas, and help.bas libraries; its help is `recorder.dhs`. Tested on the host by `src/test/music/recorderTest.c` and on DOS by `record.scr`. ### DVX Demo (dvxdemo) | | | |---|---| | File | `apps/kpunch/dvxdemo/dvxdemo.app` | | Type | Callback-only | | Multi-instance | No | Widget toolkit showcase. Opens multiple windows demonstrating virtually every widget type: * Main window -- raw paint callbacks (gradients, patterns, text) * Widget demo -- form widgets (TextInput, Checkbox, Radio, ListBox) * Controls window -- tabbed advanced widgets (Dropdown, ProgressBar, Slider, Spinner, TreeView, ListView, ScrollPane, Toolbar, Canvas, Splitter, Image) * Terminal window -- AnsiTerm widget Resources include `logo.bmp`, `new.bmp`, `open.bmp`, `sample.bmp`, `save.bmp`. Reference implementation for widget-based UIs. ### Control Panel (cpanel) | | | |---|---| | File | `apps/kpunch/cpanel/cpanel.app` | | Type | Callback-only | | Multi-instance | No | System configuration with five tabs: * **Mouse** -- scroll direction, wheel speed, double-click speed, acceleration, cursor speed * **Colors** -- every system colour with live preview; theme load and save * **Desktop** -- wallpaper image and display mode * **Video** -- resolution and colour depth switching * **File Types** -- file associations (`cpTypes.c`): add, change, and remove which program opens each extension Changes preview live. OK writes to `USER/DVX.INI` and the file types to `USER/ASSOC.INI` (the user's changes to `SYSTEM/ASSOC.INI`, through `shellAssocSet`/`shellAssocRemove`); themes it saves go to `USER/THEMES`, and its lists show `SHARED`'s and the user's together; Cancel reverts to the snapshot taken when the panel opened. ### Image Viewer (imgview, BASIC) | | | |---|---| | File | `apps/kpunch/imgview/imgview.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | Displays BMP, PNG, JPEG, and GIF images scaled to fit the window with aspect ratio preserved. Resize to zoom. Open via the File menu or via launch arguments. Built from a BASIC project using the Canvas widget. ### DVX BASIC (dvxbasic) | | | |---|---| | File | `apps/kpunch/dvxbasic/dvxbasic.app` | | Type | Callback-only | | Multi-instance | No | Visual Basic 3 compatible IDE: form designer, per-procedure code editor, project manager, compiler, and runtime VM. See `dvxbasic/README.md` for a detailed architecture description. `dvxbasic/` also builds: * `bin/libs/kpunch/basrt/basrt.lib` -- the BASIC runtime (VM + values) as a separately loadable library, so compiled BASIC apps do not carry their own copy of the runtime. * `bin/apps/kpunch/dvxbasic/basstub.app` -- the stub used as the template for every compiled BASIC app. ### DVX Help Viewer (dvxhelp) | | | |---|---| | File | `apps/kpunch/dvxhelp/dvxhelp.app` | | Type | Callback-only | | Multi-instance | Yes | Renders compiled `.hlp` files produced by `dvxhlpc`. Supports table of contents, keyword index, full-text search (trigram), hyperlinks, and inline images. The file is read with the `hlpfile` library (`src/libs/kpunch/hlpfile`) and topics are drawn by the HelpView widget (`src/widgets/kpunch/helpView`, BASIC type HelpPane), the same code a BASIC program uses through `hlpfile.bas` and HelpPane. ### Icon Editor (iconed, BASIC) | | | |---|---| | File | `apps/kpunch/iconed/iconed.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | Dot-by-dot editor for 16x16, 24x24, and 32x32 icons. Pencil / eraser / colour picker tools, 32-colour palette, BMP or PNG open, PNG (or BMP by extension) save. ### Help Editor (helpedit, BASIC) | | | |---|---| | File | `apps/kpunch/helpedit/helpedit.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | Editor for `.dhs` help source files with syntax highlighting. Build > Compile writes `.hlp` next to the source; Build > Preview compiles and opens the result in the help viewer. Its own help is `helpedit.hlp`; Help > Help File Format opens the format reference in the viewer's `dvxhelp.hlp` (by its path under the programs folder: the editor has a folder of its own, a package of Developer Tools with `SYSTEM\DVXHLPC.EXE`). ### Resource Editor (resedit, BASIC) | | | |---|---| | File | `apps/kpunch/resedit/resedit.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | GUI wrapper around `dvxres`: open a `.app` / `.wgt` / `.lib`, browse its resources, add, replace, extract, or remove them. ### BASIC Demo (basdemo, BASIC) | | | |---|---| | File | `apps/kpunch/basdemo/basdemo.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | Gallery of short BASIC programs demonstrating the language and the form designer. Intended as sample source for reading. ### Widget Showcase (widshow, BASIC) | | | |---|---| | File | `apps/kpunch/widshow/widshow.app` | | Type | BASIC (main-loop via basstub) | | Multi-instance | No | One tabbed window exercising the standard BASIC controls, with tooltips and a status bar reporting each event. Shipped in the SDK as a sample project, with basdemo. ## Build ``` make # build every app (C apps + BASIC apps) make # build a single app make clean # remove all app build artifacts ``` The `apps/kpunch/Makefile` orchestrates both C and BASIC builds: * **C apps** are discovered: every directory `/` that holds `/.c` is one. All `.c` files in the directory are compiled and linked with `dxe3gen -U` into `.app`, then resources are attached with `dvxres build` if `/.res` exists. No list needs editing. * **BASIC apps** run `bascomp .dbp -o .app -release`, which handles project-file parsing, compilation, resource attachment, and linking into `basstub.app`. Build output goes to `bin/apps/kpunch//.app`. ## Writing a New C App Minimal skeleton: ```c #include "dvxApp.h" #include "dvxWgt.h" #include "shellApp.h" #include #include // Prototypes static int32_t appMainImpl(DxeAppContextT *ctx); static void onClose(WindowT *win); // Required descriptor SHELL_APP_DESCRIPTOR( .name = "My App", .hasMainLoop = false, .multiInstance = false, .stackSize = SHELL_STACK_DEFAULT, .priority = 0 ); static void onClose(WindowT *win) { (void)win; // Callback-only apps: nothing to do; the shell reaps us when // the last window closes. } int32_t appMain(DxeAppContextT *ctx) { return appMainImpl(ctx); } static int32_t appMainImpl(DxeAppContextT *ctx) { AppContextT *ac = ctx->shellCtx; WindowT *win = dvxCreateWindow(ac, appDescriptor.name, 100, 100, 320, 240, true); if (!win) { return -1; } win->onClose = onClose; return 0; } ``` Put the source in `apps/kpunch//.c` (more `.c` files in the same directory are linked in too), drop a `.res` manifest next to the source, and provide a 32x32 `icon32.bmp`. The Makefile finds the app by itself; `make ` then produces `bin/apps/kpunch//.app`. Files a program reads at run time (pictures, data) are installed beside it by one Makefile rule, for C and BASIC programs alike: list them in `APP_DATA_` (relative to the program's source directory, `` being the last part of that directory), as `APP_DATA_dvxdemo` does. `make ` copies them into the program's folder and `make clean` removes them; the program finds them through its own folder (`App.Path` in BASIC, the app context's `appDir` in C). ## Testing Locally After `make`, the app is deployed in-tree under `bin/apps/kpunch/`. Launch the full system (`bin/dvx.exe`) and the Program Manager picks up the new app automatically on the next boot. To iterate quickly: rebuild the single app, restart DVX, and launch it. The log at `bin/USER/DVX.LOG` records load errors, missing dependencies, and per-app crash diagnostics. ## Files Each app's own help source `.dhs` sits beside its `.c` or `.dbp` (see Help above). `progman/`, `dvxbasic/`, and `dvxhelp/` also hold help configured by hand in the top-level Makefile and their `.hcf` files: the system help (`progman/userHelp.dhs`), the BASIC help, and the viewer's help. ``` apps/kpunch/ Makefile top-level app build README.md this file # C apps progman/ progman.c Program Manager window, menus, commands pmModel.c/.h groups, items, PROGMAN.INI pmView.c/.h icon view widget class pmProps.c/.h item Properties dialog progman.dhs Program Manager's own help dvxhelp.hcf help-compiler config (system reference) userHelp.dhs end-user guide (first part of the system help) dvxdemo/ dvxdemo.c widget showcase dvxdemo.res icon32.bmp logo.bmp / new.bmp / open.bmp / sample.bmp / save.bmp cpanel/ cpanel.c Control Panel cpTypes.c/.h File Types page cpanel.res icon32.bmp dvxhelp/ dvxhelp.c help viewer (reads .hlp files with the hlpfile library, shows topics in the HelpView widget) dvxhelp.res help.dhs source for the dvxhelp app's own help sample.dhs small sample source icon32.bmp # BASIC apps iconed/ iconed.dbp iconed.frm ICON32.BMP helpedit/ help editor (Developer Tools) helpedit.dbp helpedit.frm helpedit.dhs ICON32.BMP notepad/ notepad.dbp notepad.frm ICON32.BMP imgview/ imgview.dbp imgview.frm ICON32.BMP basdemo/ basdemo.dbp basdemo.frm ICON32.BMP resedit/ resedit.dbp resedit.frm ICON32.BMP widshow/ widshow.dbp widshow.frm ICON32.BMP clock/ clock.dbp clock.frm clock.dhs ICON32.BMP welcome/ welcome.dbp welcome.frm welcome.dhs ICON32.BMP fileMgr/ fileMgr.dbp fileMgr.frm the window fmProps.frm Properties dialog fileMgr.bas job engine (copy / move / delete windows) fmJob.cls one job fileMgr.dhs ICON32.BMP terminal/ terminal.dbp terminal.frm the window termBook.frm Phone Book termSess.frm Session Settings termXfer.frm Transfer Options termPass.frm secure link passphrase termProg.frm File Transfer (progress) terminal.bas phone book (TERMINAL.INI), shared state termMain.bas start terminal.dhs ICON32.BMP player/ player.dbp player.frm player.dhs ICON32.BMP recorder/ recorder.dbp recorder.frm recorder.dhs ICON32.BMP dvxbasic/ see dvxbasic/README.md compiler/ lexer, parser, codegen, strip, obfuscate runtime/ VM + value system formrt/ form runtime (BASIC <-> DVX widgets) ide/ IDE front end stub/ bascomp + basstub ... ```