extern pascal OSStatus GetDetachedIconSuite(IconSuiteRef *theIconSuite, SInt16 theResID, IconSelectorValue selector) // See comment in interface part. { long oldA4; OSStatus err; THz oldZone; oldA4 = SetUpA4(); assert(theIconSuite != NULL); oldZone = SetSystemZone(); // The algorithm here is perfectly simple. First get the icon suite, // then iterate over its contents detaching each handle. I looked // at the Icon Services code and this seems like a perfectly reasonable // strategy. It also disassembled SBGetDetachIconSuite and it works // in the same way. err = GetIconSuite(theIconSuite, theResID, selector); if (err == noErr) { (void) ForEachIconDo(*theIconSuite, kSelectorAllAvailableData, gDetachIconActionUPP, NULL); } SetZone(oldZone); (void) SetA4(oldA4); return err; }
/*-------------------------------------------------------------------- * DESCRIPTION * Do progress callback. - MAC version * * AUTHOR * mec * * DATE CREATED * May 4, 1995 *------------------------------------------------------------------*/ static SpStatus_t SpDoIter ( SpTagIter_t ProgressFunc, SpIterState_t State, SpProfile_t Profile, SpTagId_t TagId, void FAR *Data) { #if defined(KPMAC68K) volatile long hostA4, hostA5; volatile long thisA4, thisA5; #endif SpStatus_t status; if (NULL == ProgressFunc) return SpStatSuccess; #if defined(KPMAC68K) /* restore host's global world - we don't know if its an A4 or A5*/ SPretrieveCallbackA4A5(&hostA4, &hostA5); if (hostA5 != 0) thisA5 = SetA5(hostA5); if (hostA4 != 0) thisA4 = SetA4(hostA4); #endif status = CallSPIterCallBackFunc((spIterCallBackUPP)ProgressFunc, State, Profile, TagId, Data); #if defined (KPMAC68K) /* reset our global world */ if (hostA5 != 0) SetA5(thisA5); if (hostA4 != 0) SetA4(thisA4); #endif return status; }
static pascal void InsertMenuPatch(MenuHandle theMenu, SInt16 beforeID) // This is our patch on InsertMenu. The only goal of this // patch is to watch for the first person to insert a system // menu and then, when they do that, turn around and insert // our system menus along with it. This patch typically // executes at Process Manager startup time as the Help menu // is inserted. The nice thing about this is that we don't // have to monkey with the system state so that our menus // go into the system menu list; the system has already done // that, our menus just tag along for the ride. { long oldA4; oldA4 = SetUpA4(); // Our patch should only be installed if InitMoreSystemMenus was successful. assert(gRootSysMenus != NULL); CallInsertMenuProc(gInsertMenuOldUPP, theMenu, beforeID); if ( !gHaveInsertedRootSysMenus && IsSystemMenuID( (**theMenu).menuID ) ) { // Remember the system's MenuCInfo in gRootSysMenuCInfo // so that we can set it back later. We currently // don't use this information but I have a feeling // we'll need it in the future. gRootSysMenuCInfo = LMGetMenuCInfo(); // Insert our menus into the system menu list. InsertMySystemMenus((**theMenu).menuID); // We only try to do this once. If we fail, too bad, // there's no one to report an error to. gHaveInsertedRootSysMenus = true; } (void) SetA4(oldA4); }
extern pascal OSStatus InsertSystemMenu(MenuRef theMenu, SystemMenuCallbackProc callback, void *refcon) // See comment in interface part. { long oldA4; OSStatus err; RootSysMenuEntry newEntry; oldA4 = SetUpA4(); assert(ValidateSystemMenuRef(theMenu)); assert(callback != NULL); // If either of these fire, you're too late to call this routine, // either because system startup is complete or because someone // has already inserted a system menu. assert( IsSystemStartup() ); assert( ! gHaveInsertedRootSysMenus ); // Fill out the new entry. newEntry.theMenu = theMenu; newEntry.callback = callback; newEntry.refcon = refcon; // Add the entry on to the system menu list. Later on, in the // InsertMenuPatch, we'll add it to the menu bar. if (theMenu == NULL || callback == NULL) { err = paramErr; } else { err = PtrAndHand(&newEntry, (Handle) gRootSysMenus, sizeof(newEntry)); } (void) SetA4(oldA4); return err; }
~IASGlobalContext() { SetA4(saveA4); // Set A4 back. }
extern pascal OSStatus InsertSystemSubMenu(MenuRef rootMenu, MenuRef parentMenu, UInt16 itemInParent, MenuRef childMenu) // See comment in interface part. { long oldA4; OSStatus err; SubSysMenuEntry newEntry; SInt16 newIDForChildMenu; oldA4 = SetUpA4(); assert(ValidateSystemMenuRef(rootMenu )); assert(ValidateSystemMenuRef(parentMenu)); assert(ValidateSystemMenuRef(childMenu )); assert(gMenuSelectState = kMenuSelectStatePre); // Validate parameters err = noErr; if ((rootMenu == NULL) || (parentMenu == NULL) || (childMenu == NULL)) { err = paramErr; } if (err == noErr && ((itemInParent == 0) || (itemInParent > CountMenuItems(parentMenu)))) { err = paramErr; } // Make sure rootMenu references a current system menu. // If it does, record the index of the root menu for // later use by HandleMenuSelect. Also fill out the rest // of the fields of the sub-menu entry. if (err == noErr) { newEntry.rootMenuIndex = FindRootMenuByRef(rootMenu); newEntry.parentMenu = parentMenu; newEntry.itemInParent = itemInParent; newEntry.childMenu = childMenu; if (newEntry.rootMenuIndex == kRootMenuNotFound) { err = paramErr; } } // Add newEntry to the sub-menu list, creating the sub-menu list if necessary. if (err == noErr) { if (gSubSysMenus == NULL) { gSubSysMenus = (SubSysMenuHandle) NewHandleSys(0); err = MemError(); } } if (err == noErr) { err = PtrAndHand(&newEntry, (Handle) gSubSysMenus, sizeof(newEntry)); } // Finally, insert the menu with a unique ID into the menu bar, // and set the parent item to reference its ID. if (err == noErr) { newIDForChildMenu = FindUniqueSubMenuID(); (**childMenu).menuID = newIDForChildMenu; InsertMenu(childMenu, hierMenu); SetItemCmd(parentMenu, itemInParent, hMenuCmd); SetItemMark(parentMenu, itemInParent, newIDForChildMenu); // I added this after testing revealed that adding a sub-menu didn't // force the menu size to be recalculated, so the item text of the // hierarchical item in the sub-menu was being truncated. This // only appears to happen on Mac OS 8.5, but the fix is sufficiently // benign to be employed on all systems. CalcMenuSize(parentMenu); } (void) SetA4(oldA4); return err; }
static pascal SInt32 MenuSelectPatch(Point startPt) // This is our patch on MenuSelect. The basic idea is to // call our clients to let them adjust their menus (and install // sub-menus by calling InsertSystemMenu), call through to // the old trap, call our clients to un-adjust their menus, // and then call HandleMenuSelect to see whether the chosen // menu was one of our system menus. If it was, HandleMenuSelect // calls the client to tell them that their menu was chosen and // returns 0 so that we tell the host application that nothing // happened. // // Note that MenuSelect is called by MenuEvent, so this patch // covers that case as well. { long oldA4; SInt32 result; SubSysMenuHandle tempSubSysMenus; oldA4 = SetUpA4(); // Our patch should only be installed if InitMoreSystemMenus was successful. assert(gRootSysMenus != NULL); // Only do stuff if we're actually up and running. // If gHaveInsertedRootSysMenus is false, it means that // someone is calling MenuSelect before our InsertMenu patch // has run, ie before anyone has inserted any system menus, // ie before the Process Manager has launched. I don't know // whether this ever happens, I'm use being cautious. // Also, if gMenuSelectState is not NULL then we're getting recursion // where we're not expecting it (probably from the kSystemMenuPreSelectAdjust // or kSystemMenuPostSelectAdjust callbacks, but possibly from another // trap patch), so we just call through to the system in that case. // We want debug versions to tell the client that they're recursing // in an unsupport fashion. assert(gMenuSelectState == kMenuSelectStateNil); if ( gHaveInsertedRootSysMenus && gMenuSelectState == kMenuSelectStateNil) { // OK, so we're up and running, so let's do our stuff. // First tell all clients that we're about to do a MenuSelect // (they can adjust their menus and insert sub-menus)... assert(gSubSysMenus == NULL); gMenuSelectState = kMenuSelectStatePre; CallAllClients(kSystemMenuPreSelectAdjust, NULL); // ... then call through to the old trap address... result = CallMenuSelectProc(gMenuSelectOldUPP, startPt); // ... and then tell all clients that we're done... gMenuSelectState = kMenuSelectStatePost; CallAllClients(kSystemMenuPostSelectAdjust, NULL); // Things get tricky here. In order to allow the client // to post modal dialogs from its kSystemMenuActOnChosen callback, // we must be re-entrant at the time we call HandleMenuSelect // (because the ModalDialog routine will call MenuSelect). // But we want to avoid having sub-menus in the menu bar when // we're recursively called because we're going to call the // client's kSystemMenuPreSelectAdjust callback, which will // attempt to re-insert those menus. // // So, we remove our sub-menus now, before calling the // kSystemMenuActOnChosen callback, then we make the callback, // and then we dispose of the memory we used to track the // sub-menus. tempSubSysMenus = gSubSysMenus; gSubSysMenus = NULL; DeleteSubMenus(tempSubSysMenus); gMenuSelectState = kMenuSelectStateNil; // At this point we're prepared to accept recursion. // Call HandleMenuSelect to process the results // from the menu operation and call the appropriate // client if it was one of our menus. result = HandleMenuSelect(result, tempSubSysMenus); // Clean up. If we created any sub-menu info, // dispose of it. if (tempSubSysMenus != NULL) { DisposeHandle( (Handle) tempSubSysMenus); assert(MemError() == noErr); } } else { result = CallMenuSelectProc(gMenuSelectOldUPP, startPt); } assert(gMenuSelectState == kMenuSelectStateNil); (void) SetA4(oldA4); return result; }