65816-llvm-mos/runtime/include/iigs/cursor.h
Scott Duensing da095402ec Updated
2026-06-02 23:17:57 -05:00

91 lines
3.4 KiB
C

// iigs/cursor.h - convenience wrappers for the QuickDraw Cursor Mgr.
//
// What's here today: a small push/pop stack of CursorRecord COPIES so
// transient cursor state (e.g. "show busy while loading", "show I-beam
// in text fields") can be installed and restored without the caller
// owning a heap-resident cursor pointer. Toolset-owned cursor records
// can move under us when Memory Mgr compacts; the push routines copy
// 256 bytes from the toolset's live cursor into our save stack so the
// pop path always restores a valid record.
//
// Pair with InitCursor() (called by startdesk()). The push/pop calls
// hard-error before InitCursor has run - the Cursor Mgr's save buffer
// is NULL until then and any SetCursor would walk through 0.
//
// Phase 2.5 (2026-06-01) scope: thin wrappers + Wait / IBeam ROM
// shapes via GetCursorAdr(). Embedded cursor blobs are NOT in scope -
// callers who want a custom cursor should construct their own Cursor
// record (per ORCA quickdraw.h:112) and pass its pointer to SetCursor()
// directly.
#ifndef IIGS_CURSOR_H
#define IIGS_CURSOR_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "iigs/toolbox.h" // brings in IigsCursorT (opaque)
// Maximum nesting depth of iigsCursorPushArrow / iigsCursorPushBusy.
// 8 is generous for the desktop demos we ship; exceeding it triggers
// the assert-no-op behavior documented on the push routines.
#ifndef IIGS_CURSOR_STACK_DEPTH
#define IIGS_CURSOR_STACK_DEPTH 8
#endif
// Save a COPY of the currently-installed cursor on the internal stack
// and install the ROM arrow cursor. The "arrow" here is whatever
// shape InitCursor() set up - on IIgs that's the standard mouse arrow.
// We re-arm it by calling InitCursor again; the Cursor Mgr re-points
// its working cursor to the ROM arrow shape without re-allocating the
// save buffer (idempotent post-init).
//
// Precondition: InitCursor() must have been called (startdesk() does
// this). If not, the call is a no-op and returns nonzero.
// Stack overflow: if the push stack is already at IIGS_CURSOR_STACK_DEPTH,
// returns nonzero and does NOT change the active cursor.
//
// Returns 0 on success.
uint16_t iigsCursorPushArrow(void);
// Save a COPY of the currently-installed cursor on the internal stack
// and install the ROM "busy" (wristwatch) cursor via WaitCursor().
// Same preconditions and error path as iigsCursorPushArrow().
//
// Returns 0 on success.
uint16_t iigsCursorPushBusy(void);
// Pop the topmost saved CursorRecord and re-install it via SetCursor().
// The save stack stores full RECORD COPIES (not pointers), so this is
// safe even if Memory Mgr moved the toolset's live cursor since the
// matching push.
//
// Returns 0 on success. Returns nonzero if the stack is empty (under-
// flow) or if iigsCursorRegister has not yet been called.
uint16_t iigsCursorPop(void);
// Install `cursor` as the active cursor; the IigsCursorT layout MUST
// match QD's CursorRecord (cursorHeight, cursorWidth, cursorData[],
// cursorMask[], cursorHotSpot). Pass NULL to no-op. This is a thin
// wrapper around SetCursor() that also captures the new cursor as the
// "registered" cursor (used by iigsCursorPop() when the save stack is
// empty - that's how we get back to the application's default cursor
// after a Push/Pop mismatch).
//
// Returns 0 on success.
uint16_t iigsCursorRegister(const IigsCursorT *cursor);
#ifdef __cplusplus
}
#endif
#endif // IIGS_CURSOR_H