// The MIT License (MIT)
//
// Copyright (C) 2026 Scott Duensing
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.

// dvx_types.h  -- Shared type definitions for DVX GUI
//
// Central type definitions shared across all five layers of the DVX GUI
// stack (video, draw, comp, wm, app). Every header includes this file,
// so it must remain free of implementation details and function definitions.
// The design uses a single-include-tree rooted here to avoid circular
// dependencies between layers.
#ifndef DVX_TYPES_H
#define DVX_TYPES_H

#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>

// ============================================================
// ============================================================
// Pixel format descriptor
// ============================================================
//
// Describes the pixel encoding for the active VESA video mode.
// Populated once at startup from the VBE mode info block and then
// treated as read-only. Storing shift/mask/bits separately avoids
// repeated bit-scanning when packing colors  -- packColor() uses these
// fields directly for shift-and-mask arithmetic rather than computing
// them on the fly, which matters when called per-glyph during text
// rendering on a 486.

typedef struct {
    int32_t  bitsPerPixel;   // 8, 15, 16, or 32
    int32_t  bytesPerPixel;  // 1, 2, 2, or 4
    uint32_t redMask;        // e.g. 0xF800 for 565
    uint32_t greenMask;
    uint32_t blueMask;
    int32_t  redShift;       // bit position of red field
    int32_t  greenShift;
    int32_t  blueShift;
    int32_t  redBits;        // number of red bits (5, 6, 8...)
    int32_t  greenBits;
    int32_t  blueBits;
} PixelFormatT;

// ============================================================
// Display context
// ============================================================
//
// The single display context passed by pointer through every layer.
// Using one struct instead of globals makes the entire stack reentrant
// in principle and keeps the API clean.
//
// The double-buffer strategy (backBuf in system RAM, lfb is the real
// framebuffer) exists because writes to video memory over the PCI bus
// are dramatically slower than writes to main RAM on 486/Pentium hardware
//  -- often 10-50x slower for random-access patterns. All drawing goes to
// backBuf, and only dirty rectangles are flushed to lfb via fast aligned
// copies (rep movsd). This is the single most important performance
// decision in the entire compositor.
//
// The clip rectangle is mutable state set before each draw call so that
// the drawing layer doesn't need per-window context  -- it just clips to
// whatever rectangle is currently set on the display. This avoids an
// extra parameter on every draw function and mirrors how classic windowing
// systems (X11, GDI) handle clipping.

typedef struct {
    int32_t      width;
    int32_t      height;
    int32_t      pitch;       // bytes per scanline
    PixelFormatT format;
    uint8_t     *lfb;         // mapped linear framebuffer
    uint8_t     *backBuf;     // system RAM backbuffer
    uint8_t     *palette;     // 768 bytes for 8-bit mode, NULL otherwise
    int32_t      clipX;       // current clip rectangle
    int32_t      clipY;
    int32_t      clipW;
    int32_t      clipH;
} DisplayT;

// ============================================================
// Rectangle
// ============================================================
//
// x/y/w/h representation chosen over x1/y1/x2/y2 because most operations
// (clipping, blit sizing, layout) naturally work with origin + extent.
// The compositor, window manager, and widget layout engine all traffic
// in RectT, so keeping one canonical representation avoids conversion bugs.

typedef struct {
    int32_t x;
    int32_t y;
    int32_t w;
    int32_t h;
} RectT;

// ============================================================
// Span operation function pointers
// ============================================================
//
// BlitOpsT is a vtable for the two hot-path memory operations: filling
// a horizontal span with a solid color, and copying a span from one
// buffer to another. The function pointers are resolved once at init
// time based on the active pixel depth (8/16/32 bpp), and on DOS they
// dispatch to hand-written asm inner loops using rep stosl / rep movsd.
// Every rectangle fill, blit, and text draw ultimately bottlenecks
// through these two functions, so even a small speedup here multiplies
// across the entire frame.
//
// Storing bytesPerPixel alongside the function pointers keeps the hot data
// in one cache line and avoids re-dereferencing the DisplayT on every
// scanline of a fill or copy.

typedef void (*SpanFillFnT)(uint8_t *dst, uint32_t color, int32_t count);
typedef void (*SpanCopyFnT)(uint8_t *dst, const uint8_t *src, int32_t count);

typedef struct {
    SpanFillFnT spanFill;
    SpanCopyFnT spanCopy;
    int32_t     bytesPerPixel;
} BlitOpsT;

// ============================================================
// Bevel style
// ============================================================
//
// Bevels are the defining visual element of the Motif aesthetic.
// Swapping highlight and shadow colors flips between raised and sunken
// appearance  -- the BEVEL_RAISED and BEVEL_SUNKEN macros encode this
// convention so callers don't get the colors backwards.
//
// A width of 2 pixels is the standard Motif bevel size. Using 1 creates
// a thinner look for scrollbar troughs and other subtle borders.
// face = 0 means "don't fill the interior", which is used when drawing
// a bevel frame around content that's already been painted.

// Sentinel face value meaning "draw the border only, no interior fill".
// A plain 0 cannot be used because packed pure black (RGB 0,0,0) is also 0,
// which would wrongly suppress the fill of a black-faced widget.  0xFFFFFFFF
// is never produced by any DVX pixel format (XRGB, no 32-bit alpha).
#define BEVEL_NO_FILL  0xFFFFFFFFu

typedef struct {
    uint32_t highlight;   // lighter color (top/left edges)
    uint32_t shadow;      // darker color (bottom/right edges)
    uint32_t face;        // fill color for interior (BEVEL_NO_FILL = no fill)
    int32_t  width;       // border thickness in pixels (typically 2)
} BevelStyleT;

// Convenience initializers for common bevel styles (C99 compound literals)
#define BEVEL_RAISED(cs, bw)       (BevelStyleT){ (cs)->windowHighlight, (cs)->windowShadow, (cs)->windowFace, (bw) }
#define BEVEL_SUNKEN(cs, face, bw) (BevelStyleT){ (cs)->windowShadow, (cs)->windowHighlight, (face), (bw) }
#define BEVEL_TROUGH(cs)           (BevelStyleT){ (cs)->windowShadow, (cs)->windowHighlight, (cs)->scrollbarTrough, 1 }
#define BEVEL_SB_BUTTON(cs)        (BevelStyleT){ (cs)->windowHighlight, (cs)->windowShadow, (cs)->scrollbarBg, 1 }
#define BEVEL_POPUP(cs, bw)        (BevelStyleT){ (cs)->windowHighlight, (cs)->windowShadow, (cs)->menuBg, (bw) }

// ============================================================
// Bitmap font
// ============================================================
//
// Fixed-width 8-pixel-wide bitmap fonts only. This simplifies text
// rendering enormously: character positions are pure multiplication
// (x = col * 8), glyph lookup is a single array index, and the 1bpp
// format means each scanline of a glyph is exactly one byte.
//
// One font size is provided (8x16), matching the standard
// VGA ROM font and CP437 encoding. Proportional fonts would require
// glyph-width tables, kerning, and per-character positioning  -- none of
// which is worth the complexity for a DOS-era window manager targeting
// 640x480 screens. The 8-pixel width also aligns nicely with byte
// boundaries, enabling per-scanline glyph rendering without bit shifting.

#define FONT_CHAR_WIDTH  8    // fixed glyph width in pixels
#define FONT_CHAR_HEIGHT 16   // fixed glyph height in pixels

typedef struct {
    int32_t        charWidth;    // fixed width per glyph (e.g. 8)
    int32_t        charHeight;   // 16 (only 8x16 font provided)
    int32_t        firstChar;    // ASCII code of first glyph (typically 0)
    int32_t        numChars;     // number of glyphs (typically 256)
    const uint8_t *glyphData;    // packed 1bpp, charHeight bytes per glyph
} BitmapFontT;

// ============================================================
// Color scheme
// ============================================================
//
// All UI colors are pre-packed into display pixel format at init time.
// This means every color here is a uint32_t that can be written directly
// to the framebuffer without any per-pixel conversion. The tradeoff is
// that the scheme must be regenerated if the video mode changes, but
// since mode changes require re-init anyway, this is free in practice.
//
// The color set mirrors classic Motif/Windows 3.x conventions:
// windowHighlight/windowShadow form bevel pairs, activeTitleBg gives
// the focused window's title bar its distinctive color, and so on.
// Keeping all colors in one struct makes theme support trivial  -- just
// swap the struct.

typedef struct {
    uint32_t desktop;
    uint32_t windowFace;
    uint32_t windowHighlight;
    uint32_t windowShadow;
    uint32_t activeTitleBg;
    uint32_t activeTitleFg;
    uint32_t inactiveTitleBg;
    uint32_t inactiveTitleFg;
    uint32_t contentBg;
    uint32_t contentFg;
    uint32_t menuBg;
    uint32_t menuFg;
    uint32_t menuHighlightBg;
    uint32_t menuHighlightFg;
    uint32_t buttonFace;
    uint32_t scrollbarBg;
    uint32_t scrollbarFg;
    uint32_t scrollbarTrough;
    uint32_t cursorFg;
    uint32_t cursorBg;
} ColorSchemeT;

// Color IDs for addressing individual colors in ColorSchemeT.
// Order matches the struct field order.
typedef enum {
    ColorDesktopE,
    ColorWindowFaceE,
    ColorWindowHighlightE,
    ColorWindowShadowE,
    ColorActiveTitleBgE,
    ColorActiveTitleFgE,
    ColorInactiveTitleBgE,
    ColorInactiveTitleFgE,
    ColorContentBgE,
    ColorContentFgE,
    ColorMenuBgE,
    ColorMenuFgE,
    ColorMenuHighlightBgE,
    ColorMenuHighlightFgE,
    ColorButtonFaceE,
    ColorScrollbarBgE,
    ColorScrollbarFgE,
    ColorScrollbarTroughE,
    ColorCursorFgE,
    ColorCursorBgE,
    ColorCountE
} ColorIdE;

_Static_assert(sizeof(ColorSchemeT) == (size_t)ColorCountE * sizeof(uint32_t), "ColorSchemeT field count must match ColorIdE with no padding");

typedef enum {
    WallpaperStretchE,
    WallpaperTileE,
    WallpaperCenterE
} WallpaperModeE;

// Video mode entry (enumerated at init, available to apps)
typedef struct {
    int32_t w;
    int32_t h;
    int32_t bpp;
} VideoModeInfoT;

// ============================================================
// Dirty rectangle list
// ============================================================
//
// Dynamic array of dirty rects (realloc'd on demand) rather than a linked
// list because: (a) the buffer is pre-allocated once to a soft cap so the
// per-frame add path never reallocs, (b) the rects sit contiguously, making
// the linear merge scan cache-friendly, and (c) reordering/merging works in
// place. When the count crosses the soft cap the array doubles; the
// compositor can also merge aggressively or fall back to a full-screen
// repaint.

typedef struct {
    RectT  *rects;  // dynamic array (realloc'd on demand)
    int32_t count;
    int32_t cap;
} DirtyListT;

// ============================================================
// Window chrome constants
// ============================================================
//
// These define the pixel geometry of the window frame (border, title bar,
// menu bar). They're compile-time constants because the DVX look demands
// a fixed, uniform chrome thickness across all windows  -- there's no
// per-window customization of frame geometry.
//
// CHROME_TOTAL_TOP/SIDE/BOTTOM are the total chrome insets from the
// outer frame rectangle to the content area. The content area position
// is computed from these constants, so they must be kept in sync with
// the drawing code in wmDrawChrome(). Menu bar height is added
// dynamically only for windows that have menus.

#define CHROME_BORDER_WIDTH   4
#define CHROME_TITLE_HEIGHT   20
#define CHROME_TITLE_PAD      4
#define CHROME_INNER_BORDER   2
// Menu bar height: matches the title bar so accent chrome and menu bar
// stack as a uniform vertical rhythm.  If the two ever need to differ,
// split these back into independent values.
#define CHROME_MENU_HEIGHT    CHROME_TITLE_HEIGHT
// Y offset from window top to the bottom of the title bar (= top of menu bar)
#define CHROME_TITLEBAR_BOTTOM (CHROME_BORDER_WIDTH + CHROME_TITLE_HEIGHT)
#define CHROME_TOTAL_TOP      (CHROME_BORDER_WIDTH + CHROME_TITLE_HEIGHT + CHROME_INNER_BORDER)
#define CHROME_TOTAL_SIDE     (CHROME_BORDER_WIDTH + CHROME_INNER_BORDER)
#define CHROME_TOTAL_BOTTOM   (CHROME_BORDER_WIDTH + CHROME_INNER_BORDER)

// ============================================================
// Menu types
// ============================================================
//
// Fixed-size arrays with inline char buffers rather than heap-allocated
// strings. This avoids malloc/free churn for menus that are typically
// built once at window creation and never change. The limits (16 items
// per menu, 8 menus per bar, 32-char labels) are generous for a DOS
// application; exceeding them is silently capped.
//
// Cascading submenus are supported by the subMenu pointer on MenuItemT.
// The forward declaration of MenuT is needed because MenuItemT contains
// a pointer to its parent type (circular reference between item and menu).

#define MAX_MENU_LABEL   32

// Forward declaration for submenu pointers
typedef struct MenuT MenuT;

typedef enum {
    MenuItemNormalE,
    MenuItemCheckE,
    MenuItemRadioE,
} MenuItemTypeE;

typedef struct {
    char           label[MAX_MENU_LABEL];
    int32_t        id;           // application-defined command ID
    MenuItemTypeE  type;         // normal, checkbox, or radio
    bool           separator;    // true = this is a separator line, not a clickable item
    bool           enabled;
    bool           checked;
    char           accelKey;     // lowercase accelerator character, 0 if none
    MenuT         *subMenu;      // child menu for cascading submenus (NULL if leaf item)
} MenuItemT;

// MenuT is a named struct (not anonymous typedef) because MenuItemT
// needs a forward pointer to it for cascading submenus.
struct MenuT {
    char      label[MAX_MENU_LABEL];   // menu bar label (e.g. "File")
    MenuItemT *items;      // dynamic array (realloc'd on demand)
    int32_t    itemCount;
    int32_t    itemCap;
    int32_t   barX;        // computed position on menu bar
    int32_t   barW;        // computed width on menu bar
    char      accelKey;    // lowercase accelerator character, 0 if none
};

// positionsDirty defers the O(n) barX/barW recomputation until the
// menu bar is actually drawn, avoiding redundant work when multiple
// menus are added in sequence during window setup.
typedef struct {
    MenuT **menus;         // dynamic array of owned MenuT pointers (realloc'd on demand)
    int32_t menuCount;
    int32_t menuCap;
    int32_t activeIdx;        // menu bar item with open popup (-1 = none)
    bool    positionsDirty;   // true = barX/barW need recomputation
} MenuBarT;

// ============================================================
// Scrollbar types
// ============================================================
//
// Window-level scrollbars (separate from the widget-internal scrollbar
// drawing code). These are attached to WindowT and managed by the WM
// layer. The thumb size is computed proportionally from pageSize relative
// to the total range (max - min), matching the Windows/Motif convention.
//
// x/y/length are computed by wmUpdateContentRect() and cached here so
// hit-testing and drawing don't need to recompute them each frame.

typedef enum {
    ScrollbarVerticalE,
    ScrollbarHorizontalE
} ScrollbarOrientE;

// Arrow glyph direction for the scrollbar painter.  Values 0..3 must
// preserve the ordering the draw-layer arrow helper switches on (up,
// down, left, right).
typedef enum {
    ScrollArrowUpE,
    ScrollArrowDownE,
    ScrollArrowLeftE,
    ScrollArrowRightE
} ScrollArrowDirE;

#define SCROLLBAR_WIDTH 16
#define SB_ARROW_ROWS   4     // number of rows in scrollbar arrow glyph
#define SB_ARROW_HALF   2     // half-width of scrollbar arrow tip

typedef struct {
    ScrollbarOrientE orient;
    int32_t          min;         // scroll range min
    int32_t          max;         // scroll range max
    int32_t          value;       // current scroll position
    int32_t          pageSize;    // visible portion (for thumb sizing)
    int32_t          x;           // computed position relative to window
    int32_t          y;
    int32_t          length;      // total length of scrollbar track
} ScrollbarT;

// ============================================================
// Accelerator table (global hotkeys)
// ============================================================
//
// Per-window accelerator tables for keyboard shortcuts (e.g. Ctrl+S for
// save). The modifier flags intentionally match the BIOS INT 16h shift
// state bits so that the raw keyboard data can be compared directly
// without translation.
//
// normKey and normMods are precomputed at registration time: the key is
// uppercased and shift is stripped from modifiers. This lets the runtime
// match in O(n) with just two integer comparisons per entry, avoiding
// case-folding and modifier normalization on every keystroke.


// Modifier flags for accelerators (match BIOS shift state bits)
#define ACCEL_SHIFT  0x03
#define ACCEL_CTRL   0x04
#define ACCEL_ALT    0x08

// Non-ASCII keys are encoded as (scancode | KEY_EXT_FLAG) to distinguish
// them from regular ASCII values in a single int32_t keycode space.
#define KEY_EXT_FLAG 0x100

#define KEY_F1       (0x3B | KEY_EXT_FLAG)
#define KEY_F2       (0x3C | KEY_EXT_FLAG)
#define KEY_F3       (0x3D | KEY_EXT_FLAG)
#define KEY_F4       (0x3E | KEY_EXT_FLAG)
#define KEY_F5       (0x3F | KEY_EXT_FLAG)
#define KEY_F6       (0x40 | KEY_EXT_FLAG)
#define KEY_F7       (0x41 | KEY_EXT_FLAG)
#define KEY_F8       (0x42 | KEY_EXT_FLAG)
#define KEY_F9       (0x43 | KEY_EXT_FLAG)
#define KEY_F10      (0x44 | KEY_EXT_FLAG)
#define KEY_F11      (0x57 | KEY_EXT_FLAG)
#define KEY_F12      (0x58 | KEY_EXT_FLAG)
#define KEY_INSERT   (0x52 | KEY_EXT_FLAG)
#define KEY_DELETE   (0x53 | KEY_EXT_FLAG)
#define KEY_HOME     (0x47 | KEY_EXT_FLAG)
#define KEY_END      (0x4F | KEY_EXT_FLAG)
#define KEY_PGUP     (0x49 | KEY_EXT_FLAG)
#define KEY_PGDN     (0x51 | KEY_EXT_FLAG)
#define KEY_UP       (0x48 | KEY_EXT_FLAG)
#define KEY_DOWN     (0x50 | KEY_EXT_FLAG)
#define KEY_LEFT     (0x4B | KEY_EXT_FLAG)
#define KEY_RIGHT    (0x4D | KEY_EXT_FLAG)

// Raw BIOS scancodes (enhanced INT 16h) and ASCII codes checked directly
// by the keyboard poller. Extended keys arrive with ascii == 0.
#define KEY_SCAN_ESC           0x01
#define KEY_SCAN_TAB           0x0F
#define KEY_SCAN_SPACE         0x39
#define KEY_SCAN_F1            0x3B
#define KEY_SCAN_F10           0x44
#define KEY_SCAN_UP            0x48
#define KEY_SCAN_LEFT          0x4B
#define KEY_SCAN_RIGHT         0x4D
#define KEY_SCAN_DOWN          0x50
#define KEY_SCAN_ALT_F4        0x6B
#define KEY_SCAN_CTRL_F12      0x8A
#define KEY_SCAN_ALT_TAB       0xA5
#define KEY_ASCII_CTRL_A       0x01  // BIOS Ctrl+A..Ctrl+Z arrive as 0x01..0x1A
#define KEY_ASCII_CTRL_Z       0x1A

// ASCII control / printable ranges (non-extended codes).
#define KEY_ESCAPE            0x1B
#define KEY_ENTER             0x0D  // Enter/Return (carriage return)
#define KEY_TAB               0x09
#define KEY_SPACE             0x20
#define KEY_ASCII_DEL         0x7F  // not the same as KEY_DELETE (scancode 0x53)
#define KEY_BACKSPACE         0x08  // ASCII backspace (not KEY_DELETE scancode)
#define KEY_ASCII_PRINT_FIRST 0x20  // space
#define KEY_ASCII_PRINT_LAST  0x7E  // tilde

// Ctrl-letter codes (A=1, B=2, ..., Z=26) used for clipboard shortcuts.
#define KEY_CTRL_A   0x01
#define KEY_CTRL_C   0x03
#define KEY_CTRL_V   0x16
#define KEY_CTRL_X   0x18
#define KEY_CTRL_Z   0x1A

typedef struct {
    int32_t key;         // key code: ASCII char or KEY_Fxx for extended
    int32_t modifiers;   // ACCEL_CTRL, ACCEL_SHIFT, ACCEL_ALT (OR'd together)
    int32_t cmdId;       // command ID passed to onMenu
    int32_t normKey;     // pre-normalized key (uppercased) for fast matching
    int32_t normMods;    // pre-masked modifiers (CTRL|ALT only) for fast matching
} AccelEntryT;

typedef struct {
    AccelEntryT *entries;   // dynamic array (realloc'd on demand)
    int32_t      count;
    int32_t      cap;
} AccelTableT;

// ============================================================
// Window
// ============================================================
//
// WindowT is the central object of the window manager. Each window owns
// its own content backbuffer, which persists across frames so that
// applications don't need to repaint on every expose event  -- only when
// their actual content changes. This is crucial for performance on slow
// hardware: dragging a window across others doesn't force every obscured
// window to repaint.
//
// The content area (contentX/Y/W/H) is computed from the frame dimensions
// minus chrome. This separation lets the compositor blit chrome and content
// independently during dirty-rect repainting.
//
// RESIZE_xxx flags are bitfields so that corner resizes can combine two
// edges (e.g. RESIZE_LEFT | RESIZE_TOP for the top-left corner).

#define MAX_TITLE_LEN  128

#define RESIZE_NONE    0
#define RESIZE_LEFT    1
#define RESIZE_RIGHT   2
#define RESIZE_TOP     4
#define RESIZE_BOTTOM  8

// Window size limits
#define MIN_WINDOW_W         80
#define MIN_WINDOW_H         60
#define WM_MAX_FROM_SCREEN   (-1)  // use screen dimension as max (for maxW/maxH)
#define DRAG_MIN_VISIBLE     50    // min pixels of window kept on-screen by move/resize

// Default / minimum VESA video mode.  Used as the lower bound when
// enumerating available modes and as the fallback mode when the
// preferences file doesn't specify otherwise.
#define DVX_DEFAULT_VIDEO_W   640
#define DVX_DEFAULT_VIDEO_H   480
#define DVX_DEFAULT_VIDEO_BPP 16

// Window paint states (for WindowT.paintNeeded)
#define PAINT_NONE     0  // no paint needed
#define PAINT_PARTIAL  1  // only dirty widgets (deferred wgtInvalidatePaint)
#define PAINT_FULL     2  // clear + relayout + repaint all (wgtInvalidate)

// Hit test region identifiers (returned via hitPart from wmHitTest)
#define HIT_CONTENT    0
#define HIT_TITLE      1
#define HIT_CLOSE      2
#define HIT_RESIZE     3
#define HIT_MENU       4
#define HIT_VSCROLL    5
#define HIT_HSCROLL    6
#define HIT_MINIMIZE   7
#define HIT_MAXIMIZE   8
#define HIT_NONE       (-1)

// Minimized windows display as icons at the bottom of the screen,
// similar to a classic desktop icon bar.
#define ICON_SIZE         64
#define ICON_BORDER       2
#define ICON_TOTAL_SIZE   (ICON_SIZE + ICON_BORDER * 2)
#define ICON_SPACING      2

typedef struct WindowT {
    int32_t      id;
    int32_t      appId;        // shell app ID (0 = shell itself)
    int32_t      x;
    int32_t      y;
    int32_t      w;
    int32_t      h;
    int32_t      contentX;      // offset from frame to content area
    int32_t      contentY;
    int32_t      contentW;
    int32_t      contentH;
    char         title[MAX_TITLE_LEN];
    bool         visible;
    bool         focused;
    bool         minimized;
    bool         maximized;
    bool         resizable;
    bool         modal;
    bool         destroyPending;  // hidden and queued for deferred destruction
    bool         iconNeedsRefresh;  // true when contentBuf has changed since last icon refresh
    // Paint state: PAINT_NONE = idle, PAINT_PARTIAL = only dirty widgets,
    // PAINT_FULL = clear background + relayout + repaint all.
    // wgtInvalidatePaint sets PARTIAL, wgtInvalidate sets FULL.
    // Higher values take priority (FULL > PARTIAL > NONE).
    uint8_t      paintNeeded;      // 0=none, 1=partial, 2=full
    int32_t      maxW;          // maximum width (WM_MAX_FROM_SCREEN = use screen width)
    int32_t      maxH;          // maximum height (WM_MAX_FROM_SCREEN = use screen height)
    // Pre-maximize geometry is saved so wmRestore() can put the window
    // back exactly where it was. This matches Windows 3.x behavior.
    int32_t      preMaxX;       // saved position before maximize
    int32_t      preMaxY;
    int32_t      preMaxW;
    int32_t      preMaxH;

    // Per-window content backbuffer
    uint8_t     *contentBuf;
    int32_t      contentPitch;

    // Icon image (display pixel format, NULL if none)
    uint8_t     *iconData;
    int32_t      iconW;
    int32_t      iconH;
    int32_t      iconPitch;

    // Menu bar (NULL if no menus)
    MenuBarT    *menuBar;

    // Scrollbars (NULL if not present)
    ScrollbarT  *vScroll;
    ScrollbarT  *hScroll;

    // Widget tree root (NULL if no widgets)
    struct WidgetT *widgetRoot;

    // Widget that held keyboard focus when this window last lost WM focus.
    // Restored by the widget paint handler when the window regains focus;
    // cleared by widgetClearReferences when that widget is destroyed.
    struct WidgetT *lastFocusWidget;

    // Context menu (NULL if none, caller owns the MenuT allocation)
    MenuT       *contextMenu;

    // Accelerator table (NULL if none, caller owns allocation)
    AccelTableT *accelTable;

    // Callbacks  -- the application's interface to the window manager.
    // Using function pointers rather than a message queue keeps latency
    // low (no queuing/dispatching overhead) and matches the callback-driven
    // model that DOS programs expect. The widget system installs its own
    // handlers here via wgtInitWindow() and dispatches to individual widgets.
    void        *userData;
    void       (*onPaint)(struct WindowT *win, RectT *dirtyArea);
    void       (*onKey)(struct WindowT *win, int32_t key, int32_t mod);
    void       (*onKeyUp)(struct WindowT *win, int32_t scancode, int32_t mod);
    void       (*onMouse)(struct WindowT *win, int32_t x, int32_t y, int32_t buttons);
    void       (*onResize)(struct WindowT *win, int32_t newW, int32_t newH);
    void       (*onClose)(struct WindowT *win);
    void       (*onMenu)(struct WindowT *win, int32_t menuId);
    void       (*onScroll)(struct WindowT *win, ScrollbarOrientE orient, int32_t value);
    int32_t    (*onCursorQuery)(struct WindowT *win, int32_t x, int32_t y); // return CURSOR_* or 0 for default
    void       (*onFocus)(struct WindowT *win);  // window gained focus
    void       (*onBlur)(struct WindowT *win);   // window lost focus
} WindowT;

// ============================================================
// Window stack
// ============================================================
//
// The window stack is an array of pointers ordered front-to-back: index
// count-1 is the topmost (frontmost) window. This ordering means the
// compositor can iterate back-to-front for painting (painter's algorithm)
// and front-to-back for hit testing (first hit wins).
//
// Using an array of pointers (not embedded structs) lets us reorder
// windows by swapping pointers instead of copying entire WindowT structs,
// which matters because WindowT is large.
//
// Drag/resize/scroll state lives here rather than on individual windows
// because only one interaction can be active at a time system-wide  --
// you can't drag two windows simultaneously with a single mouse.

typedef struct {
    WindowT **windows; // dynamic array (realloc'd on demand)
    int32_t   count;
    int32_t   cap;
    int32_t  focusedIdx;
    int32_t  dragWindow;
    int32_t  dragOffX;
    int32_t  dragOffY;
    int32_t  dragStartX;   // mouse position at drag begin (for deadzone)
    int32_t  dragStartY;
    bool     dragActive;   // true once mouse moved past deadzone
    int32_t  resizeWindow;
    int32_t  resizeEdge;
    int32_t  scrollWindow;       // window being scroll-dragged (HIT_NONE = none)
    ScrollbarOrientE scrollOrient; // orientation of the scrollbar being dragged
    int32_t  scrollDragOff;      // mouse offset from thumb start
} WindowStackT;

// Mouse button bitmask flags (used in onMouse callbacks, dvxUpdate, etc.)
#define MOUSE_LEFT     1
#define MOUSE_RIGHT    2
#define MOUSE_MIDDLE   4

// Default scrollbar lines to scroll per mouse wheel notch
#define MOUSE_WHEEL_STEP_DEFAULT 3
#define MOUSE_WHEEL_STEP_MIN     1
#define MOUSE_WHEEL_STEP_MAX     10

// Default mouse INI values (single source of truth for cpanel writer and shell reader).
#define MOUSE_DBLCLICK_DEFAULT_MS    500
#define MOUSE_SPEED_DEFAULT          8
#define MOUSE_ACCEL_DEFAULT          "medium"
#define MOUSE_WHEEL_DIR_DEFAULT      "normal"

// Mouse acceleration threshold levels.  Higher values = less acceleration
// (threshold above which doubling kicks in).  MOUSE_ACCEL_OFF effectively
// disables acceleration by setting the threshold above any realistic speed.
#define MOUSE_ACCEL_OFF              10000
#define MOUSE_ACCEL_LOW              100
#define MOUSE_ACCEL_MEDIUM           64
#define MOUSE_ACCEL_HIGH             32

// ============================================================
// Mouse cursor
// ============================================================
//
// Software-rendered cursor using the classic AND/XOR mask approach from
// the original IBM VGA hardware cursor spec. This two-mask scheme enables
// four pixel states: transparent (AND=1, XOR=0), inverted (AND=1, XOR=1),
// black (AND=0, XOR=0), and white (AND=0, XOR=1). The cursor is drawn
// in software on top of the composited frame because VESA VBE doesn't
// provide a hardware sprite  -- the cursor is painted into the backbuffer
// and the affected region is flushed to the LFB each frame.
//
// 16 pixels wide using uint16_t rows, one word per scanline. This keeps
// cursor data compact and aligned, and 16x16 is the standard DOS cursor size.

typedef struct {
    int32_t        width;
    int32_t        height;
    int32_t        hotX;
    int32_t        hotY;
    const uint16_t *andMask;   // 0 = draw cursor pixel, 1 = transparent
    const uint16_t *xorData;   // 0 = black, 1 = white (where andMask = 0)
} CursorT;

// ============================================================
// Popup state for dropdown menus (with cascading submenu support)
// ============================================================
//
// Only one popup chain can be active at a time (menus are modal).
// Cascading submenus are tracked as a stack of PopupLevelT frames,
// where each level saves the parent menu's state so it can be restored
// when the submenu closes. The stack grows dynamically to support
// arbitrary nesting depth.
//
// The popup's screen coordinates are stored directly rather than computed
// relative to the window, because the popup is painted on top of
// everything during the compositor's overlay pass and needs absolute
// screen positioning.


// Saved parent popup state when a submenu is open
typedef struct {
    MenuT   *menu;
    int32_t  menuIdx;
    int32_t  popupX;
    int32_t  popupY;
    int32_t  popupW;
    int32_t  popupH;
    int32_t  hoverItem;
} PopupLevelT;

typedef struct {
    bool         active;
    bool         isContextMenu; // true = context menu (no menu bar association)
    int32_t      windowId;      // which window owns this popup chain
    int32_t      menuIdx;       // which menu bar menu is open (top level)
    int32_t      popupX;        // screen position of current (deepest) popup
    int32_t      popupY;
    int32_t      popupW;
    int32_t      popupH;
    int32_t      hoverItem;     // highlighted item in current popup (-1 = none)
    MenuT       *menu;          // direct pointer to current menu (avoids lookup for submenus)
    int32_t      depth;         // 0 = top-level only, 1+ = submenu depth
    PopupLevelT *parentStack; // dynamic array (realloc'd on demand)
    int32_t      parentCap;
} PopupStateT;

// ============================================================
// System menu (control menu / close box menu)
// ============================================================
//
// The system menu appears when clicking the close gadget once (double-click
// closes). This matches classic Windows 3.x/Motif behavior where the control
// menu provides Move, Size, Minimize, Maximize, Restore, and Close. The
// menu items are dynamically enabled/disabled based on window state (e.g.
// Restore is disabled if the window isn't maximized).

typedef enum {
    SysMenuRestoreE       = 1,
    SysMenuMoveE          = 2,
    SysMenuSizeE          = 3,
    SysMenuMinimizeE      = 4,
    SysMenuMaximizeE      = 5,
    SysMenuCloseE         = 6,
    SysMenuScreenshotE    = 7,
    SysMenuWinScreenshotE = 8
} SysMenuCmdE;

#define SYS_MENU_MAX_ITEMS 10

typedef struct {
    char    label[MAX_MENU_LABEL];
    int32_t cmd;
    bool    separator;
    bool    enabled;
    char    accelKey;
} SysMenuItemT;

typedef struct {
    bool          active;
    int32_t       windowId;
    int32_t       popupX;
    int32_t       popupY;
    int32_t       popupW;
    int32_t       popupH;
    int32_t       hoverItem;
    SysMenuItemT  items[SYS_MENU_MAX_ITEMS];
    int32_t       itemCount;
} SysMenuStateT;

// ============================================================
// Keyboard move/resize mode
// ============================================================
//
// Supports moving and resizing windows via arrow keys (triggered from
// the system menu's Move/Size commands). The original geometry is saved
// so that Escape can cancel the operation and restore the window to its
// prior position/size. This is the standard Windows 3.x keyboard
// accessibility mechanism for window management.

typedef enum {
    KbModeNoneE   = 0,
    KbModeMoveE   = 1,
    KbModeResizeE = 2
} KbModeE;

typedef struct {
    KbModeE mode;
    int32_t windowId;
    int32_t origX;
    int32_t origY;
    int32_t origW;
    int32_t origH;
} KbMoveResizeT;

// ============================================================
// Utility macros
// ============================================================

#define DVX_MIN(a, b) ((a) < (b) ? (a) : (b))
#define DVX_ARRAY_LEN(a) ((int32_t)(sizeof(a) / sizeof((a)[0])))
#define DVX_MAX(a, b) ((a) > (b) ? (a) : (b))

#endif // DVX_TYPES_H
