EXPORT(sqInt) primitiveGetItemCmd(void) { CharParameter aCharacter; MenuHandle menuHandle; sqInt menuHandleOop; sqInt anInteger; sqInt _return_value; menuHandleOop = interpreterProxy->stackValue(1); anInteger = interpreterProxy->stackIntegerValue(0); if (interpreterProxy->failed()) { return null; } menuHandle = ((MenuHandle) (interpreterProxy->positive64BitValueOf(menuHandleOop))); if (!(ioCheckMenuHandle(menuHandle))) { _return_value = interpreterProxy->success(0); if (interpreterProxy->failed()) { return null; } interpreterProxy->popthenPush(3, _return_value); return null; } aCharacter = 0; GetItemCmd(menuHandle,anInteger,&aCharacter); _return_value = interpreterProxy->integerObjectOf(aCharacter); if (interpreterProxy->failed()) { return null; } interpreterProxy->popthenPush(3, _return_value); return null; }
static SInt32 HandleMenuSelect(SInt32 menuAndItem, SubSysMenuHandle subSysMenus) // This routine is called from the tail patch on MenuSelect // to handle an actual menu command being returned. // menuAndItem was the result from the original MenuSelect, and // the result of this routine will be returned from our MenuSelect // patch. // // The basic idea is that, if the menu command was on // a system menu belong to us, we call the appropriate client // callback routine and return 0 so that the client sees // a null selection. If the menu command doesn't belong to us, // we just return the value passed in. { SInt32 result; SInt16 hitMenuID; UInt16 hitItem; ItemCount foundIndex; MenuRef foundMenuRef; // The system implementation of MenuSelect will return 0 if the hit item // is in a system menu. Fortunately, the real hit item is still around // in the low memory global MenuDisable. So we use if menuAndItem is zero. // // One weird edge case is cancelling sticky menus. If the user brings // down a sticky menu and never chooses anything, the sticky menu // will eventually time out. But LMGetMenuDisable is still set to // the menu and item of the item over which the mouse was last moved. // So, we conditionalise our access to LMGetMenuDisable with a // call to LMGetTheMenu. If LMGetTheMenu is 0, the operation was // cancelled and we should bail out without choosing the item // in LMGetMenuDisable. // // Also note that we assign result before doing this, so we only use // MenuDisable if it relates to a system menu and never return it from // this routine, and hence from our patch on MenuSelect. result = menuAndItem; if (menuAndItem == 0) { if ( LMGetTheMenu() != 0 ) { menuAndItem = LMGetMenuDisable(); } } hitMenuID = menuAndItem >> 16; hitItem = menuAndItem & 0x0FFFF; // Search our list of system menus looking for a matching menu ID. // Start by looking for a root menu and, if that fails, look for // one of the sub-menus we attached to the root menus. // // If we find a matching menu, call the corresponding client with a // kSystemMenuActOnChosen message, and also set menuAndItem to 0 so // that the application never sees the menu choice. foundMenuRef = NULL; foundIndex = FindRootMenuByID(hitMenuID); if (foundIndex != kRootMenuNotFound) { foundMenuRef = (*gRootSysMenus)[foundIndex].theMenu; } else { ItemCount entryCount; ItemCount entryIndex; entryCount = CountSubSysMenus(subSysMenus); for (entryIndex = 0; entryIndex < entryCount; entryIndex++) { if (hitMenuID == (**(*subSysMenus)[entryIndex].childMenu).menuID) { foundIndex = (*subSysMenus)[entryIndex].rootMenuIndex; foundMenuRef = (*subSysMenus)[entryIndex].childMenu; assert(foundIndex < CountRootSysMenus()); break; } } } if (foundIndex != kRootMenuNotFound) { Boolean enabled; CharParameter cmdOfHitItem; assert(ValidateSystemMenuRef(foundMenuRef)); // Because we're using MenuDisable to get the actual item hit, // we'll often get false positives, hits on the menu title or // when the menu item is disabled. Make sure we don't call the // client in these cases. // Item 0 is the title and is never enabled. Items from 1 to 31 // are controlled by the enableFlags field of the menu. Items // above 31 are always assumed to be enabled. // // Note that I don't use IsMenuItemEnabled (introduced in Mac OS 8.5) // to access this information because it's a CFM-only routine. It's // only relevant for items beyond 31, which is a corner case IMHO. // Also, items that are the root of sub-menus (ie their cmd is // hMenuCmd) can not be chosen. if (hitItem == 0) { enabled = false; } else if (hitItem <= 31) { enabled = (((**foundMenuRef).enableFlags & (1L << hitItem)) != 0); } else { enabled = true; } if (enabled) { GetItemCmd(foundMenuRef, hitItem, &cmdOfHitItem); enabled = (cmdOfHitItem != hMenuCmd); } if (enabled) { CallSingleClient(foundIndex, kSystemMenuActOnChosen, foundMenuRef, (void *) hitItem); } result = 0; } return result; }