// menuBuilderProbe.c - Phase 4.1 smoke test. // // Builds a minimal Apple+File menu bar via the uiBuilder surface, // installs it, runs the event loop, then sets $70=0x99 when the // File>Quit (or cmd-Q) handler fires. Verifies: // - uiBuilderMenuBytes emits a byte stream NewMenu accepts. // - uiBuilderInstallMenuBar drives DrawMenuBar without hanging. // - uiBuilderDispatch routes the menu pick to the right handler. // - Cmd-Q keystroke wakes the loop within the test.sh timeout. #include "iigs/toolbox.h" #include "iigs/desktop.h" #include "iigs/eventLoop.h" #include "iigs/uiBuilder.h" #include #define CMD_ABOUT 257 #define CMD_QUIT 256 static volatile uint16_t gIdleTicks; static void onIdle(void) { if (++gIdleTicks > 2000) { iigsEventLoopQuit(); } } static void onAbout(uint16_t cmdId) { (void)cmdId; // Mark "About picked" at $71. Test reads this if it wants to // confirm the dispatcher fired for a non-Quit item. *(volatile unsigned char *)0x71 = 0xAB; } static void onQuit(uint16_t cmdId) { (void)cmdId; // Mark "Quit picked" at $72, then ask the loop to exit. *(volatile unsigned char *)0x72 = 0xCD; iigsEventLoopQuit(); } static const UiCmdHandlerT gCmdTable[] = { { CMD_ABOUT, onAbout }, { CMD_QUIT, onQuit }, }; static const UiMenuItemT gAppleItems[] = { { CMD_ABOUT, "About Menu Probe", 0, 0 }, }; static const UiMenuItemT gFileItems[] = { { CMD_QUIT, "Quit", 'Q', 0 }, }; static const UiMenuT gMenus[] = { { 1, "Apple", MN_APPLE, 1, gAppleItems }, { 2, "File", 0, 1, gFileItems }, }; static void myOnMenu(uint16_t menuId, uint16_t itemId) { (void)menuId; uiBuilderDispatch(itemId, gCmdTable, (uint16_t)(sizeof gCmdTable / sizeof gCmdTable[0])); } int main(void) { unsigned short userId = startdesk(640); (void)userId; paintDesktopBackdrop(); uiBuilderInstallMenuBar(gMenus, (uint16_t)(sizeof gMenus / sizeof gMenus[0])); ShowCursor(); // Marker: init complete. Even if no menu pick comes in, this // proves the builder + DrawMenuBar got through. *(volatile unsigned char *)0x70 = 0x55; IigsEventCallbacksT cb; { unsigned char *p = (unsigned char *)&cb; for (uint16_t i = 0; i < sizeof cb; i++) { p[i] = 0; } } cb.onMenu = myOnMenu; // Watchdog so the headless test exits even if no key injection // reaches the menu pick: count idle ticks and quit after ~2000. cb.onIdle = onIdle; iigsEventLoop(&cb); // Final marker: loop exited cleanly. *(volatile unsigned char *)0x70 = 0x99; return 0; }