305 lines
14 KiB
C
305 lines
14 KiB
C
// 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 <time.h>
|
|
|
|
// ============================================================
|
|
// 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];
|
|
// Available video modes (enumerated once at init)
|
|
VideoModeInfoT *videoModes; // stb_ds dynamic array
|
|
int32_t videoModeCount;
|
|
// Wallpaper -- pre-rendered to screen dimensions in native pixel format.
|
|
// NULL means no wallpaper (solid desktop color). wallpaperPath is
|
|
// kept so the image can be reloaded after a video mode or mode change.
|
|
uint8_t *wallpaperBuf; // pixel data (screen width * height * bpp/8)
|
|
int32_t wallpaperPitch; // bytes per row
|
|
char wallpaperPath[260]; // source image path (empty = none)
|
|
WallpaperModeE wallpaperMode; // stretch, tile, or center
|
|
} 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);
|
|
|
|
// Return a human-readable display label (e.g. "Desktop", "Cursor Color").
|
|
const char *dvxColorLabel(ColorIdE id);
|
|
|
|
// ============================================================
|
|
// Wallpaper
|
|
// ============================================================
|
|
|
|
// Load and apply a wallpaper image. Uses the current wallpaperMode
|
|
// (stretch/tile/center). Pass NULL to clear the wallpaper.
|
|
bool dvxSetWallpaper(AppContextT *ctx, const char *path);
|
|
|
|
// Change the wallpaper display mode and re-render the buffer.
|
|
// Has no effect if no wallpaper is loaded.
|
|
void dvxSetWallpaperMode(AppContextT *ctx, WallpaperModeE mode);
|
|
|
|
// Return the list of available video modes (enumerated at init).
|
|
// count receives the number of entries.
|
|
const VideoModeInfoT *dvxGetVideoModes(const AppContextT *ctx, int32_t *count);
|
|
|
|
// 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
|