// dvx_app.h — Layer 5: Application API for DVX GUI // // The topmost layer and the public-facing API for applications. Aggregates // all lower layers into a single AppContextT and provides a clean interface // for window creation, event dispatch, and utilities. Applications interact // exclusively through dvx*() functions and window callbacks — they never // need to call the lower WM, compositor, or draw layers directly. // // The event loop (dvxRun/dvxUpdate) follows a cooperative model: poll mouse // and keyboard, dispatch events to the focused window, run the compositor // for dirty regions, then yield. There's no preemptive scheduling — the // application must return from callbacks promptly. #ifndef DVX_APP_H #define DVX_APP_H #include "dvxTypes.h" #include "dvxVideo.h" #include "dvxDraw.h" #include "dvxComp.h" #include "dvxWm.h" #include // ============================================================ // Application context // ============================================================ // // Single monolithic context that owns all GUI state. Allocated on the // caller's stack (or statically) — no internal heap allocation for the // context itself. This "god struct" approach keeps the API simple (one // pointer to pass everywhere) and avoids the overhead of a handle-based // system with opaque lookups. The tradeoff is a large struct, but on DOS // memory layout is flat and cache pressure isn't a concern at this level. typedef struct AppContextT { DisplayT display; WindowStackT stack; DirtyListT dirty; BlitOpsT blitOps; BitmapFontT font; ColorSchemeT colors; PopupStateT popup; SysMenuStateT sysMenu; KbMoveResizeT kbMoveResize; CursorT cursors[5]; // indexed by CURSOR_xxx int32_t cursorId; // active cursor shape uint32_t cursorFg; // pre-packed cursor colors uint32_t cursorBg; bool running; int32_t mouseX; int32_t mouseY; int32_t mouseButtons; int32_t mouseWheel; // wheel delta this frame (positive=down, negative=up) bool hasMouseWheel; // true if CuteMouse Wheel API detected int32_t keyModifiers; // current BIOS shift state (KEY_MOD_xxx) // Previous-frame mouse state for edge detection (button press/release // transitions and delta-based cursor movement). int32_t prevMouseX; int32_t prevMouseY; int32_t prevMouseButtons; // Double-click detection for minimized window icons: timestamps and // window IDs track whether two clicks land on the same icon within // the system double-click interval. clock_t lastIconClickTime; int32_t lastIconClickId; // window ID of last-clicked minimized icon (-1 = none) clock_t lastCloseClickTime; int32_t lastCloseClickId; // window ID of last-clicked close gadget (-1 = none) clock_t lastTitleClickTime; int32_t lastTitleClickId; // window ID of last-clicked title bar (-1 = none) // Minimized icon thumbnails are refreshed one per frame (round-robin) // rather than all at once, to amortize the cost of scaling the content // buffer down to icon size. int32_t iconRefreshIdx; // next minimized icon to refresh (staggered) int32_t frameCount; // frame counter for periodic tasks // The idle callback allows the host application (e.g. the DV/X shell) // to do background work (poll serial ports, service DXE apps) during // frames where no GUI events occurred, instead of just yielding the CPU. void (*idleCallback)(void *ctx); // called instead of yield when non-NULL void *idleCtx; WindowT *modalWindow; // if non-NULL, only this window receives input void (*onCtrlEsc)(void *ctx); // system-wide Ctrl+Esc handler (e.g. task manager) void *ctrlEscCtx; void (*onTitleChange)(void *ctx); // called when any window title changes void *titleChangeCtx; // Tooltip state — tooltip appears after the mouse hovers over a widget // with a tooltip string for a brief delay. Pre-computing W/H avoids // re-measuring on every paint frame. clock_t tooltipHoverStart; // when mouse stopped moving const char *tooltipText; // text to show (NULL = hidden) int32_t tooltipX; // screen position int32_t tooltipY; int32_t tooltipW; // size (pre-computed) int32_t tooltipH; // Fixed-point reciprocal (16.16) of font.charHeight, pre-computed so // that dividing by charHeight (needed for pixel-to-row conversion in // terminal/text widgets) becomes a multiply+shift instead of an // integer divide, which is very slow on 486 (40+ cycles per DIV). uint32_t charHeightRecip; // fixed-point 16.16 reciprocal of font.charHeight // Mouse configuration (loaded from preferences) int32_t wheelDirection; // 1 = normal, -1 = reversed clock_t dblClickTicks; // double-click speed in clock() ticks // Color scheme source RGB values (unpacked, for theme save/get) uint8_t colorRgb[ColorCountE][3]; // Wallpaper — pre-scaled to screen dimensions in native pixel format. // NULL means no wallpaper (solid desktop color). uint8_t *wallpaperBuf; // pixel data (screen width * height * bpp/8) int32_t wallpaperPitch; // bytes per row } AppContextT; // Initialize the entire GUI stack: video mode, input devices, font, // color scheme, cursor shapes, and internal state. This is the single // entry point for starting a DVX application. Returns 0 on success. int32_t dvxInit(AppContextT *ctx, int32_t requestedW, int32_t requestedH, int32_t preferredBpp); // Switch to a new video mode live. Reallocates the backbuffer, all // window content buffers, repacks colors, rescales wallpaper, and // repositions windows that would be off-screen. Returns 0 on success // or -1 on failure (old mode is restored on failure). int32_t dvxChangeVideoMode(AppContextT *ctx, int32_t requestedW, int32_t requestedH, int32_t preferredBpp); // Configure mouse behaviour. wheelDir: 1 = normal, -1 = reversed. // dblClickMs: double-click speed in milliseconds (e.g. 500). // accelThreshold: double-speed threshold in mickeys/sec (0 = don't change). void dvxSetMouseConfig(AppContextT *ctx, int32_t wheelDir, int32_t dblClickMs, int32_t accelThreshold); // ============================================================ // Color scheme // ============================================================ // Set a single color by ID. Repacks to native pixel format and // invalidates the entire screen. void dvxSetColor(AppContextT *ctx, ColorIdE id, uint8_t r, uint8_t g, uint8_t b); // Get a color's RGB values by ID. void dvxGetColor(const AppContextT *ctx, ColorIdE id, uint8_t *r, uint8_t *g, uint8_t *b); // Apply all colors from ctx->colorRgb[] at once (repack + full repaint). void dvxApplyColorScheme(AppContextT *ctx); // Reset all colors to the built-in defaults and repaint. void dvxResetColorScheme(AppContextT *ctx); // Load a theme file (INI format with [colors] section) and apply it. bool dvxLoadTheme(AppContextT *ctx, const char *filename); // Save the current color scheme to a theme file. bool dvxSaveTheme(const AppContextT *ctx, const char *filename); // Return the INI key name for a color ID (e.g. "desktop", "windowFace"). const char *dvxColorName(ColorIdE id); // ============================================================ // Wallpaper // ============================================================ // Load and apply a wallpaper image (stretched to screen). Pass NULL // to clear the wallpaper and revert to the solid desktop color. bool dvxSetWallpaper(AppContextT *ctx, const char *path); // Tear down the GUI stack in reverse order: destroy all windows, restore // text mode, release input devices. Safe to call after a failed dvxInit(). void dvxShutdown(AppContextT *ctx); // Enter the main event loop. Polls input, dispatches events, composites // dirty regions, and yields on each iteration. Returns when ctx->running // becomes false (typically from dvxQuit() or a close callback). void dvxRun(AppContextT *ctx); // Process exactly one frame of the event loop. Provided for applications // that need to integrate the GUI into their own main loop (e.g. the DV/X // shell polling serial ports between frames). Returns false when the GUI // wants to exit. bool dvxUpdate(AppContextT *ctx); // Create a window at an explicit screen position. The window is raised // to the top, focused, and its entire region is dirtied for the next // composite pass. WindowT *dvxCreateWindow(AppContextT *ctx, const char *title, int32_t x, int32_t y, int32_t w, int32_t h, bool resizable); // Convenience wrapper that centers the window on screen. WindowT *dvxCreateWindowCentered(AppContextT *ctx, const char *title, int32_t w, int32_t h, bool resizable); // Destroy a window, free all its resources, and dirty its former region. void dvxDestroyWindow(AppContextT *ctx, WindowT *win); // Resize a window to exactly fit its widget tree's computed minimum size // (plus chrome). Used for dialog boxes and other fixed-layout windows // where the window should shrink-wrap its content. void dvxFitWindow(AppContextT *ctx, WindowT *win); // Mark a sub-region of a window's content area as needing repaint. The // coordinates are relative to the content area, not the screen. The // onPaint callback will be called during the next composite pass with // the dirty area. void dvxInvalidateRect(AppContextT *ctx, WindowT *win, int32_t x, int32_t y, int32_t w, int32_t h); // Mark the entire window content area as dirty. void dvxInvalidateWindow(AppContextT *ctx, WindowT *win); // Minimize a window (show as icon at bottom of screen) void dvxMinimizeWindow(AppContextT *ctx, WindowT *win); // Maximize a window (expand to fill screen or maxW/maxH) void dvxMaximizeWindow(AppContextT *ctx, WindowT *win); // Request exit from main loop void dvxQuit(AppContextT *ctx); // Save the entire screen (backbuffer contents) to a PNG file. Converts // from native pixel format to RGB for the PNG encoder. Returns 0 on // success, -1 on failure. int32_t dvxScreenshot(AppContextT *ctx, const char *path); // Set window title void dvxSetTitle(AppContextT *ctx, WindowT *win, const char *title); // Get the default font const BitmapFontT *dvxGetFont(const AppContextT *ctx); // Get the color scheme const ColorSchemeT *dvxGetColors(const AppContextT *ctx); // Get the display DisplayT *dvxGetDisplay(AppContextT *ctx); // Get blit ops const BlitOpsT *dvxGetBlitOps(const AppContextT *ctx); // Load an icon for a window from an image file int32_t dvxSetWindowIcon(AppContextT *ctx, WindowT *win, const char *path); // Save a window's content to a PNG file (returns 0 on success, -1 on failure) int32_t dvxWindowScreenshot(AppContextT *ctx, WindowT *win, const char *path); // Allocate a new accelerator table. Attach it to a window via // win->accelTable. The event loop checks the focused window's accel // table on every keystroke and fires onMenu(cmdId) on match. AccelTableT *dvxCreateAccelTable(void); // Free an accelerator table and its entries. void dvxFreeAccelTable(AccelTableT *table); // Register a keyboard shortcut. key is an ASCII char or KEY_Fxx constant. // modifiers is a bitmask of ACCEL_CTRL/ACCEL_SHIFT/ACCEL_ALT. cmdId is // passed to the window's onMenu callback, matching the convention used // for menu item IDs so the same handler works for both menus and hotkeys. void dvxAddAccel(AccelTableT *table, int32_t key, int32_t modifiers, int32_t cmdId); // Window arrangement functions — operate on all visible, non-minimized // windows. These mirror the classic Windows 3.x "Window" menu commands. // Cascade: offset each window diagonally by the title bar height. void dvxCascadeWindows(AppContextT *ctx); // Grid tile: arrange windows in an NxM grid filling the screen. void dvxTileWindows(AppContextT *ctx); // Horizontal tile: side by side, equal width, full height. void dvxTileWindowsH(AppContextT *ctx); // Vertical tile: stacked, full width, equal height. void dvxTileWindowsV(AppContextT *ctx); // Load an image file (BMP, PNG, JPEG, GIF) and convert to the display's // native pixel format. Returns the pixel buffer on success (caller must // free with dvxFreeImage), or NULL on failure. Output params receive the // image dimensions and row pitch in bytes. uint8_t *dvxLoadImage(const AppContextT *ctx, const char *path, int32_t *outW, int32_t *outH, int32_t *outPitch); // Free a pixel buffer returned by dvxLoadImage. void dvxFreeImage(uint8_t *data); // Save native-format pixel data to a PNG file. The pixel data must be // in the display's native format (as returned by dvxLoadImage or // captured from a content buffer). Returns 0 on success, -1 on failure. int32_t dvxSaveImage(const AppContextT *ctx, const uint8_t *data, int32_t w, int32_t h, int32_t pitch, const char *path); // Copy text to the process-wide clipboard buffer. The clipboard is a // simple static buffer (not inter-process) — adequate for copy/paste // within the DVX environment on single-tasking DOS. void dvxClipboardCopy(const char *text, int32_t len); // Retrieve the current clipboard contents. Returns a pointer to the // internal static buffer (valid until the next dvxClipboardCopy), or // NULL if the clipboard is empty. const char *dvxClipboardGet(int32_t *outLen); #endif // DVX_APP_H