// 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
