DVX_GUI/apps
2026-03-18 17:26:49 -05:00
..
clock More magic numbers replaced with named defines. 2026-03-18 01:50:51 -05:00
dvxdemo More magic numbers replaced with named defines. 2026-03-18 01:50:51 -05:00
notepad More magic numbers replaced with named defines. 2026-03-18 01:50:51 -05:00
progman Now reports system information for troubleshooting. 2026-03-18 17:26:49 -05:00
Makefile Now reports system information for troubleshooting. 2026-03-18 17:26:49 -05:00
README.md More doc fixes. 2026-03-18 02:08:26 -05:00

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.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.