141 lines
3.8 KiB
Markdown
141 lines
3.8 KiB
Markdown
# 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
|
|
|
|
```c
|
|
#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
|
|
|
|
```c
|
|
#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`:
|
|
|
|
```makefile
|
|
$(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.h` for `AppDescriptorT`, `DxeAppContextT`, and
|
|
`SHELL_STACK_DEFAULT`.
|
|
- Use `ctx->shellCtx` (the `AppContextT *`) for all DVX API calls.
|
|
- Callback-only apps must destroy their own windows in `onClose` via
|
|
`dvxDestroyWindow()`. 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 `static` variables for app state. Each DXE has its own data
|
|
segment, so there is no collision between apps.
|
|
- Set `multiInstance = true` in the descriptor if the app can safely run
|
|
multiple copies simultaneously.
|
|
- Avoid `static inline` functions 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.
|