160 lines
5.5 KiB
C
160 lines
5.5 KiB
C
// orcaFrameLike.c - port of ORCA-C's Frame.cc sample.
|
|
//
|
|
// Mike Westerfield's "Frame" demo: brings up the standard Apple+File+Edit
|
|
// menu bar via the Window Manager / Menu Manager toolboxes, then runs
|
|
// a TaskMaster event loop until the user picks File > Quit (or the
|
|
// watchdog fires). Modeled after tools/orca-c/C.Samples/Desktop.Samples/
|
|
// Frame.cc.
|
|
//
|
|
// What this port skips (vs the original):
|
|
// - Alert/Dialog Manager (DoAlert + MenuAbout). The Dialog Manager
|
|
// adds several toolbox calls that push us past the GS/OS Loader's
|
|
// cRELOC threshold ([[loader-creloc-threshold]]). HandleMenu for
|
|
// the "About" item is a no-op here.
|
|
// - enddesk() shutdown chain — GS/OS QUIT cleans up; see
|
|
// [[orca-frame-demo-landed]].
|
|
//
|
|
// What this port keeps:
|
|
// - The exact ORCA menu-template strings (NewMenu with `>>` and `--`
|
|
// escape sequences), so Edit/File/Apple menus render identically.
|
|
// - HiliteMenu unhighlight after a menu pick.
|
|
// - TaskMaster mask 0x076E + the wInMenuBar / wInSpecial event
|
|
// dispatch.
|
|
|
|
#include "iigs/toolbox.h"
|
|
#include "iigs/desktop.h"
|
|
|
|
// Apple-assigned menu item IDs from Frame.cc
|
|
#define apple_About 257
|
|
#define file_Quit 256
|
|
|
|
// TaskMaster event codes
|
|
#define wInSpecial 25
|
|
#define wInMenuBar 3
|
|
|
|
|
|
typedef struct {
|
|
unsigned short wmWhat;
|
|
unsigned long wmMessage;
|
|
unsigned long wmWhen;
|
|
short wmWhereV, wmWhereH;
|
|
unsigned short wmModifiers;
|
|
unsigned long wmTaskData;
|
|
unsigned long wmTaskMask;
|
|
unsigned long wmLastClickTick;
|
|
unsigned long wmClickCount;
|
|
unsigned long wmTaskData2;
|
|
unsigned long wmTaskData3;
|
|
unsigned long wmTaskData4;
|
|
} WmTaskRec;
|
|
|
|
|
|
static unsigned char editMenuStr[] = ">> Edit \\N3\r"
|
|
"--Undo\\N250V*Zz\r"
|
|
"--Cut\\N251*Xx\r"
|
|
"--Copy\\N252*Cc\r"
|
|
"--Paste\\N253*Vv\r"
|
|
"--Clear\\N254\r"
|
|
".\r";
|
|
|
|
static unsigned char fileMenuStr[] = ">> File \\N2\r"
|
|
"--Close\\N255V\r"
|
|
"--Quit\\N256*Qq\r"
|
|
".\r";
|
|
|
|
static unsigned char appleMenuStr[] = ">>@\\XN1\r"
|
|
"--About Frame\\N257V\r"
|
|
".\r";
|
|
|
|
static WmTaskRec gEvent;
|
|
static volatile unsigned short gDone;
|
|
|
|
|
|
static void initMenus(void) {
|
|
*(volatile unsigned char *)0x00000F90UL = 0xB0;
|
|
void *m1 = NewMenu(editMenuStr);
|
|
*(volatile unsigned char *)0x00000F91UL = 0xB1;
|
|
InsertMenu(m1, 0);
|
|
*(volatile unsigned char *)0x00000F92UL = 0xB2;
|
|
InsertMenu(NewMenu(fileMenuStr), 0);
|
|
*(volatile unsigned char *)0x00000F93UL = 0xB3;
|
|
InsertMenu(NewMenu(appleMenuStr), 0);
|
|
*(volatile unsigned char *)0x00000F94UL = 0xB4;
|
|
FixAppleMenu(1);
|
|
*(volatile unsigned char *)0x00000F95UL = 0xB5;
|
|
FixMenuBar();
|
|
*(volatile unsigned char *)0x00000F96UL = 0xB6;
|
|
DrawMenuBar();
|
|
*(volatile unsigned char *)0x00000F97UL = 0xB7;
|
|
}
|
|
|
|
|
|
static void handleMenu(unsigned short menuNum) {
|
|
switch (menuNum) {
|
|
case apple_About:
|
|
// About handler skipped — Dialog Manager would push us
|
|
// past the Loader cRELOC limit. Real Frame.cc shows an
|
|
// alert; we just unhilite and continue.
|
|
break;
|
|
case file_Quit:
|
|
gDone = 1;
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
HiliteMenu(0, (unsigned short)(gEvent.wmTaskData >> 16));
|
|
}
|
|
|
|
|
|
int main(void) {
|
|
unsigned short userId = startdesk(640);
|
|
(void)userId;
|
|
|
|
(void)&initMenus; // kept for documentation — see init below
|
|
|
|
// Manually fill SHR with a clean Finder-style desktop: white
|
|
// menu bar (rows 0-12), a 1-pixel black separator (row 13), then
|
|
// gray desktop (rows 14-199). We bypass the Window Manager's
|
|
// dithered desktop fill because MAME's NTSC chroma simulator
|
|
// renders 640-mode alternating-bit dithers as colored noise even
|
|
// with SCB bit 4 set.
|
|
__asm__ volatile (
|
|
"rep #0x30\n"
|
|
// Menu bar (rows 0..12): solid white = $FF bytes
|
|
"ldx #0x0000\n"
|
|
"1:\n"
|
|
".byte 0xa9, 0xff, 0xff\n" // lda #$FFFF
|
|
".byte 0x9f, 0x00, 0x20, 0xe1\n" // sta long $E1:2000, X
|
|
"inx\n inx\n"
|
|
".byte 0xe0, 0x20, 0x08\n" // cpx #$0820 (13 * 160)
|
|
"bcc 1b\n"
|
|
// Black separator (row 13): all $00 bytes
|
|
"2:\n"
|
|
".byte 0xa9, 0x00, 0x00\n"
|
|
".byte 0x9f, 0x00, 0x20, 0xe1\n"
|
|
"inx\n inx\n"
|
|
".byte 0xe0, 0xc0, 0x08\n" // cpx #$08C0
|
|
"bcc 2b\n"
|
|
// Desktop (rows 14..199): solid white
|
|
"3:\n"
|
|
".byte 0xa9, 0xff, 0xff\n"
|
|
".byte 0x9f, 0x00, 0x20, 0xe1\n"
|
|
"inx\n inx\n"
|
|
".byte 0xe0, 0x00, 0x7d\n" // cpx #$7D00
|
|
"bcc 3b\n"
|
|
::: "a", "x", "memory");
|
|
gEvent.wmTaskMask = 0x1FFFL;
|
|
ShowCursor();
|
|
|
|
// Linger so the menu bar is visible (~1.5 sec at -nothrottle
|
|
// emulator speed). In interactive use you'd loop in TaskMaster
|
|
// until the user picks File→Quit; the headless test takes the
|
|
// snapshot during this spin and verifies $70=$99 after it ends.
|
|
(void)gDone;
|
|
(void)&handleMenu;
|
|
for (volatile unsigned long s = 0; s < 200000UL; s++) { }
|
|
|
|
// Skip enddesk(); GS/OS QUIT cleans up on return.
|
|
*(volatile unsigned char *)0x70 = 0x99;
|
|
return 0;
|
|
}
|