| .. | ||
| clock | ||
| dvxdemo | ||
| notepad | ||
| progman | ||
| Makefile | ||
| README.md | ||
DVX Shell Applications
DXE3 shared library applications loaded at runtime by the DVX Shell. Each app
is a .app file (DXE3 format) placed under the apps/ directory tree. The
Program Manager scans this directory recursively and displays all discovered
apps.
Building
make # builds all .app files into ../bin/apps/<name>/
make clean # removes objects and binaries
Requires lib/libdvx.a, lib/libtasks.a, and the DXE3 tools (dxe3gen)
from the DJGPP toolchain.
Applications
| App | File | Type | Description |
|---|---|---|---|
| Program Manager | progman/progman.c |
Callback | Desktop app: app launcher grid, Task Manager (Ctrl+Esc), window management |
| Notepad | notepad/notepad.c |
Callback | Text editor with file I/O, dirty tracking via hash |
| Clock | clock/clock.c |
Main-loop | Digital clock, multi-instance capable |
| DVX Demo | dvxdemo/dvxdemo.c |
Callback | Widget system showcase with all widget types |
Writing a New App
Minimal callback-only app
#include "dvxApp.h"
#include "dvxWidget.h"
#include "shellApp.h"
AppDescriptorT appDescriptor = {
.name = "My App",
.hasMainLoop = false,
.stackSize = SHELL_STACK_DEFAULT,
.priority = TS_PRIORITY_NORMAL
};
static DxeAppContextT *sCtx = NULL;
static WindowT *sWin = NULL;
static void onClose(WindowT *win) {
dvxDestroyWindow(sCtx->shellCtx, win);
sWin = NULL;
}
int32_t appMain(DxeAppContextT *ctx) {
sCtx = ctx;
AppContextT *ac = ctx->shellCtx;
sWin = dvxCreateWindow(ac, "My App", 100, 100, 300, 200, true);
if (!sWin) {
return -1;
}
sWin->onClose = onClose;
WidgetT *root = wgtInitWindow(ac, sWin);
wgtLabel(root, "Hello, DVX!");
wgtInvalidate(root);
return 0;
}
Minimal main-loop app
#include "dvxApp.h"
#include "dvxWidget.h"
#include "dvxWm.h"
#include "shellApp.h"
#include "taskswitch.h"
AppDescriptorT appDescriptor = {
.name = "My Task App",
.hasMainLoop = true,
.stackSize = SHELL_STACK_DEFAULT,
.priority = TS_PRIORITY_NORMAL
};
static bool sQuit = false;
static void onClose(WindowT *win) {
sQuit = true;
}
int32_t appMain(DxeAppContextT *ctx) {
AppContextT *ac = ctx->shellCtx;
WindowT *win = dvxCreateWindow(ac, "My Task App", 100, 100, 200, 100, false);
if (!win) {
return -1;
}
win->onClose = onClose;
while (!sQuit) {
// Do work, update window content
tsYield();
}
dvxDestroyWindow(ac, win);
return 0;
}
Adding to the build
Add your app directory and source to apps/Makefile. Each app is compiled to
an object file, then linked into a .app via dxe3gen:
$(BIN_DIR)/myapp.app: $(OBJ_DIR)/myapp/myapp.o
$(DXE3GEN) -o $@ -E _appDescriptor -E _appMain -U $<
The -E flags export the required symbols. -U marks unresolved symbols as
imports to be resolved from the shell's export table at load time.
App Guidelines
- Include
shellApp.hforAppDescriptorT,DxeAppContextT, andSHELL_STACK_DEFAULT. - Use
ctx->shellCtx(theAppContextT *) for all DVX API calls. - Callback-only apps must destroy their own windows in
onCloseviadvxDestroyWindow(). The shell detects the last window closing and reaps the app. - Main-loop apps must call
tsYield()regularly. A task that never yields blocks the entire system. - Use file-scoped
staticvariables for app state. Each DXE has its own data segment, so there is no collision between apps. - Set
multiInstance = truein the descriptor if the app can safely run multiple copies simultaneously. - Avoid
static inlinefunctions in shared headers. Code inlined into the DXE binary cannot be updated without recompiling the app. Use macros for trivial expressions or regular functions exported through the shell's DXE table.