65816-llvm-mos/demos/helloWindow.c
2026-05-18 14:43:35 -05:00

128 lines
4.1 KiB
C

// helloWindow.c - GS/OS app that opens a Window Manager window and
// draws a greeting in it. Runs under real GS/OS 6.0.2 in MAME.
//
// What this exercises:
// - The full Window Manager StartUp chain (Memory + QD + Event +
// Scheduler + Window).
// - NewWindow ParamList with paramLength = sizeof (ORCA Clock.cc /
// Reversi.cc convention).
// - SetPort / ShowWindow / MoveTo / DrawString round-trip.
// - Event-driven keypress wait via GetNextEvent.
// - The W65816 backend's bank-byte relocation:
// `gWp.wTitle = gTitle` stores a 32-bit pointer where the bank
// byte is materialized via the new LDAi16imm_bank pseudo
// (lowered to `lda $BE` reading PBR from a crt0-set DP slot).
// Toolbox calls now receive correct `bank:offset` pointers for
// any `&global` argument — no wrapper-side workarounds needed.
//
// Why fTitle is NOT set in wFrameBits despite wTitle being valid:
// The Window Manager hangs trying to render a titled window without
// Font Manager initialization. A "real" titled-window demo would
// need to drive QDStartUp's font allocation and possibly start the
// Font Manager (FMStartUp) — that's the next milestone.
#include "iigs/toolbox.h"
#define fVis 0x0020
#define fMove 0x0080
#define fZoom 0x0100
#define fGrow 0x0400
#define fClose 0x4000
#define fTitle 0x8000
typedef struct { short v1, h1, v2, h2; } Rect;
typedef struct {
unsigned short paramLength;
unsigned short wFrameBits;
void *wTitle;
unsigned long wRefCon;
Rect wZoom;
void *wColor;
short wYOrigin, wXOrigin;
short wDataH, wDataV;
short wMaxHeight, wMaxWidth;
short wScrollVer, wScrollHor;
short wPageVer, wPageHor;
unsigned long wInfoRefCon;
short wInfoHeight;
void *wFrameDefProc;
void *wInfoDefProc;
void *wContDefProc;
Rect wPosition;
void *wPlane;
void *wStorage;
} NewWindowParm;
// Pascal strings: leading length byte, then characters.
static unsigned char gTitle[] = "\x09llvm816!!";
static unsigned char gMsg[] = "\x14Hello from llvm816!";
// ParamList in BSS so the bank byte of &gWp resolves to PBR via the
// new LDAi16imm_bank reloc path.
static NewWindowParm gWp;
static unsigned short blockAddr(void *handle) {
return (unsigned short)(unsigned long)*(void **)handle;
}
int main(void) {
unsigned short userId = MMStartUp();
void *dpH = NewHandle(0x900UL, userId, 0xC005, (void *)0);
unsigned short dpBase = blockAddr(dpH);
QDStartUp(dpBase, 0, 0xA0, userId);
EMStartUp((unsigned short)(dpBase + 0x100), 0x14, 0, 0,
0x14F, 0xC7, userId);
SchStartUp();
WindStartUp(userId);
// Zero the parm block, then set only the fields we want non-zero.
{
unsigned char *p = (unsigned char *)&gWp;
for (unsigned short i = 0; i < sizeof gWp; i++) {
p[i] = 0;
}
}
gWp.paramLength = (unsigned short)sizeof gWp;
// fVis+fMove only — fTitle requires Font Manager startup (FMStartUp
// with proper DP allocation) which is a TODO for the full ORCA-
// style desktop init. wTitle is still set to prove the new
// R_W65816_BANK16 reloc produces the correct bank byte at runtime
// (even though WM doesn't dereference it without fTitle).
gWp.wFrameBits = fVis | fMove;
gWp.wTitle = gTitle;
gWp.wMaxHeight = 200;
gWp.wMaxWidth = 320;
gWp.wPosition.v1 = 40; gWp.wPosition.h1 = 30;
gWp.wPosition.v2 = 140; gWp.wPosition.h2 = 290;
gWp.wPlane = (void *)-1L;
void *win = NewWindow(&gWp);
if (win) {
SetPort(win);
ShowWindow(win);
MoveTo(20, 30);
DrawString(gMsg);
}
// Brief visible linger before checking events (so snapshot demos can
// capture the window). Then wait for a real keypress.
for (volatile unsigned long s = 0; s < 400000UL; s++) { }
short evt[8];
while (1) {
if (GetNextEvent(0xFFFF, evt)) {
break;
}
}
SysBeep();
*(volatile unsigned char *)0x70 = 0x99;
return 0;
}