// 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) // 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 // 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 } 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); // 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