25 KiB
DVX Shell Applications
Every DVX application is a DXE3 module packaged as a .app file,
installed under bin/apps/kpunch/<name>/<name>.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. Seeprogman/,dvxdemo/,cpanel/,dvxhelp/. - BASIC apps --
.dbpprojects compiled to.appfiles by the host-sidebascomp. The compiler links the BASIC bytecode into a copy ofbasstub.app, which acts as the runtime host. Seeiconed/,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:
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.").
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):
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 <app>.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
<app>.dhsnext to<app>.cor<app>.dbp, where<app>is the name of the.appfile. - The top-level
compile-helptarget runssrc/tools/helpFiles.sh, which finds every such file by name, compiles it to<app>.hlpnext to<app>.app, deploys the source as<APP>.DHS, and writes an<APP>.HCFso the loader's boot-time help rebuild produces it too. No list needs editing when an app is added. - F1 needs no code: before
appMainthe shell setsctx->helpFileto<app>.hlpbeside<app>.appwhen that file exists. - C apps open it from Help > Contents with
shellOpenHelp(ctx->shellCtx, ctx->helpFile). - BASIC apps call
HelpView "<app>.hlp"(fromsrc/include/basic/help.bas) from Help > Contents. F1 opens the focused control's or form'sHelpTopic. - 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 <name>.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 <appname> # 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
<app>/that holds<app>/<app>.cis one. All.cfiles in the directory are compiled and linked withdxe3gen -Uinto<app>.app, then resources are attached withdvxres buildif<app>/<app>.resexists. No list needs editing. - BASIC apps run
bascomp <app>.dbp -o <app>.app -release, which handles project-file parsing, compilation, resource attachment, and linking intobasstub.app.
Build output goes to bin/apps/kpunch/<app>/<app>.app.
Writing a New C App
Minimal skeleton:
#include "dvxApp.h"
#include "dvxWgt.h"
#include "shellApp.h"
#include <stdint.h>
#include <stdbool.h>
// 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/<app>/<app>.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 <app> then produces bin/apps/kpunch/<app>/<app>.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_<app> (relative to the program's source directory, <app>
being the last part of that directory), as APP_DATA_dvxdemo does.
make <app> 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 <app>.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
...