mirror of
https://github.com/elliotnunn/sys7.1-doc-wip.git
synced 2024-10-31 19:05:04 +00:00
677 lines
19 KiB
C
677 lines
19 KiB
C
/*
|
||
File: ModalDialogMenuExtensions.c
|
||
|
||
Contains: C language portions of Modal Dialog Menu Access Facillity
|
||
|
||
Written by: Darin Adler
|
||
|
||
Copyright: © 1990-1992 by Apple Computer, Inc., all rights reserved.
|
||
|
||
Change History (most recent first):
|
||
|
||
<23> 11/3/92 DTY Strip out unnecessary includes.
|
||
<22> 6/10/92 JSM Moved this file to ModalDialogMenuExtensions.c from
|
||
ModalDialogMenuPatches.c since it’s used by both the ROM and
|
||
System, keeping all the old revisions.
|
||
<21> 5/29/92 DCL Included TextUtils.p. EqualString was moved for the New Inside
|
||
Mac.
|
||
<20> 3/23/92 JSM OSEvents.h is obsolete, use Events.h.
|
||
<19> 2/20/91 KSM gbm,#KSM-3: Don't check spareflag of a NIL window.
|
||
<18> 2/10/91 KSM DBA,#80950: Fix to handle graying of Applications Menu properly.
|
||
<17> 1/5/91 fjs (KSM) do not allow non-printing function keys
|
||
<16> 12/18/90 KSM <rlc> Fix bug where DialogMgr incorrectly sets up the EditField
|
||
of the dialog record causing the Edit Menu to be incorrectly
|
||
enabled.
|
||
<15> 12/3/90 RLC <ksm> Change calls to IsWindowModal() to call the newer
|
||
GetWindowModalClass instead.
|
||
<14> 11/26/90 KSM (dba+dh)Remove extraneous ifdefs around includes. Also only
|
||
analyze in foregnd.
|
||
<13> 11/14/90 JL Changing InvalidMenuBar back to InvalMenuBar because Invalid is
|
||
misleading. All Inval… calls should be expanded to Invalidate if
|
||
they are expanded at all.
|
||
<12> 11/13/90 KSM <dba>Fix bug where we checked spareFlag directly instead of
|
||
calling IsWindowModal. IsWindowModal handles nil correctly, and
|
||
is smarter about variation 1 of WDEF 0. Change
|
||
SetSaveMenuEnableState to save the menu state, even if we are
|
||
only setting up the system menus and not disabling the
|
||
application menus. This fixes a bug where the system menus get
|
||
permanently disabled.
|
||
<11> 11/6/90 KSM <rlc>Revisit role of SetSaveMenuEnableState and ActiveWindowNeedsHelp
|
||
to handle the additional case of apps using modal window kinds, but
|
||
never calling _ModalDialog.
|
||
<10> 10/29/90 KSM <dba>Remove some dead code. Update to look for the modal dialog bit
|
||
before handling menus. Enable edit menu iff edit text is active.
|
||
<9> 10/15/90 JSM Really change InvalMenuBar to InvalidMenuBar.
|
||
<8> 10/15/90 JL Changing InvalMenuBar to InvalidMenuBar.
|
||
<7> 7/31/90 KSM Fix edit menu analysis state handling.
|
||
<6> 7/13/90 RLC Fix bug in testing menuselect result, hiword will be zero, but
|
||
entire longword might not be.
|
||
<5> 7/13/90 KSM Fix edit menu enabling check. Remove extra InvalMenuBar call in
|
||
EnableTheEditMenu.
|
||
<4> 7/10/90 dba get rid of C warnings
|
||
<3> 7/2/90 KSM Add edit menu handling.
|
||
<2> 6/8/90 KSM Update to use new IsFrontWindow modal calls.
|
||
<1> 6/1/90 KSM First checked in.
|
||
|
||
To Do:
|
||
add a MENU resource to indicate names of Edit menu items
|
||
find items from the Edit menu to enable them
|
||
use knowledge about Dialog Manager to know if Edit menu items should be enabled
|
||
note that we should *only* enable edit menus if the frontmost window is a
|
||
windowKind == dialogKind and there is an appropriate active editText field
|
||
(a visible TextEdit record that is currently active)
|
||
enable help menu
|
||
pass Cut, Copy, Paste, Clear, Select All through dialog filter as command keys
|
||
make a separate patch to Dialog Manager to make it handle command keys
|
||
use a global flag to prevent from saving the menu state twice
|
||
??? save menu state in a global instead of returning it as a function result
|
||
find all the *** and get rid of them
|
||
*/
|
||
|
||
/*
|
||
Modal Dialog Menu Access
|
||
Theory of Operation (Volume 1, Chapter 1, section 1)
|
||
|
||
The state of the world is “normal.”
|
||
STATE TRANSITION TABLE
|
||
|
||
State Event Event Event MenuSelect FlushEvents SysBeep
|
||
=MouseDn =NullEvt =Other (from App) (from anyone) (from App)
|
||
----- --------- --------- --------- ----------- ------------- -------------
|
||
0 1 0 0 0 0 0
|
||
1 0 3 0 0 0 2
|
||
2 0 3 0 0 0 2
|
||
3 0 0 0 0 0 0
|
||
|
||
What this means is:
|
||
State 0: This is the normal state of this code. If we see a mousedown in the menubar, we might
|
||
want to handle the menuselect call, but the app might already be doing this. So we save this
|
||
event and move to state 1.
|
||
|
||
State 1: We have seen a mousedown, but we are waiting to see if the application
|
||
is handling menus during modal dialogs. If we see the app call menuselect, we know it is
|
||
handling menus and return to state 0. If we see a flushevents call, we always go to state 0
|
||
and forget any event information we saved coming to this state. If we see a SysBeep, it might
|
||
be that that ModalDialog filter proc is complaining we clicked out of the dialog, or we may just
|
||
have gotten an extra beep. The SysBeep is "saved" and we go to state 2. A null event assumes
|
||
that the app had the change to handle the menus, but did not - so we assume it won't, go to
|
||
state 3.
|
||
|
||
State 2: We saw a sysbeep. If we see a null event, we have "eaten" the sysbeep and go to state
|
||
3. If we see another SysBeep, we Beep (for the one that got us to this state) and save off the
|
||
new SysBeep and stay in this state.
|
||
|
||
State 3: We've done our normal code and go back to state 0. This is implemented in the opposite
|
||
order, in that, we set the state to zero as we proceed on into the regular code.
|
||
|
||
------------------------------------------
|
||
In general, new patches do the following:
|
||
|
||
FlushEvents: go to state zero
|
||
MenuSelect: go to state zero (if the app called it)
|
||
SysBeep: if state 1, don't beep and go to state 2
|
||
if state 2, beep and stay in state 2
|
||
FilterEvent if state 0, mousedown goes to state 1
|
||
if state 1, null event goes to state 3, otherwise state 0
|
||
if state 2, null event goes to state 3, otherwise state 0
|
||
if state 3, we'll be on our way to state 0 anyway.
|
||
|
||
|
||
*/
|
||
|
||
#include <Dialogs.h>
|
||
#include <Events.h>
|
||
#include <Memory.h>
|
||
#include <Menus.h>
|
||
#include <Processes.h>
|
||
#include <TextUtils.h>
|
||
#include <Windows.h>
|
||
|
||
#include <DialogsPriv.h>
|
||
#include <MenuMgrPriv.h>
|
||
|
||
#define kFunctionKey 0x10
|
||
#define kCut 0x78
|
||
#define kCopy 0x63
|
||
#define kPaste 0x76
|
||
|
||
// Menu Mgr. data structures
|
||
|
||
typedef struct
|
||
{
|
||
short lastMenu;
|
||
short lastRight;
|
||
short reserved;
|
||
}
|
||
MenuListHeader;
|
||
|
||
typedef struct
|
||
{
|
||
MenuHandle handle;
|
||
short left;
|
||
}
|
||
MenuListEntry;
|
||
|
||
|
||
// menu bar iteration
|
||
|
||
MenuListHeader** GetMenuList(void);
|
||
MenuListEntry* GetNextMenu(short* offset);
|
||
|
||
|
||
// other menu operations
|
||
|
||
Boolean MenuBarEmpty(void);
|
||
Boolean PtInMenuBar(Point);
|
||
Boolean IsThisASystemMenu(short menuID);
|
||
Boolean IsModal(WindowPtr);
|
||
|
||
MenuHandle FindMenuByTitle(const unsigned char* title);
|
||
MenuHandle FindAppleMenu(void);
|
||
long GetMenuFlags(MenuHandle);
|
||
|
||
void DisableAppMenus(void);
|
||
void EnableTheEditMenu(void);
|
||
|
||
|
||
// routines to save enable state of all menus in the menu bar
|
||
|
||
Handle SaveMenusEnableState(void);
|
||
|
||
|
||
// globals (implemented in assembly) to keep our state
|
||
|
||
enum
|
||
{
|
||
kApplicationHandlesMenus,
|
||
kHandleSystemMenusDisabled,
|
||
kHandleMenusEditMenuDisabled,
|
||
kHandleMenusEditMenuEnabled,
|
||
};
|
||
typedef short TAnalyzedWindowState;
|
||
|
||
typedef struct
|
||
{
|
||
MenuHandle handle;
|
||
long savedEnableFlags;
|
||
}
|
||
MenuStateEntry;
|
||
|
||
pascal WindowPtr GetAnalyzedWindow(void);
|
||
pascal void SetAnalyzedWindow(WindowPtr);
|
||
|
||
pascal TAnalyzedWindowState GetAnalyzedWindowState(void);
|
||
pascal void SetAnalyzedWindowState(TAnalyzedWindowState);
|
||
|
||
pascal Handle GetSavedMenuState(void);
|
||
pascal void SetSavedMenuState(Handle);
|
||
|
||
|
||
// call to enable all menus for us
|
||
|
||
pascal void ModalDialogMenuSetup(Boolean nowModal)
|
||
= {0xAA67};
|
||
|
||
|
||
// heuristics used by the patches
|
||
|
||
pascal TAnalyzedWindowState ActiveWindowNeedsHelp(void);
|
||
|
||
|
||
// routines called by assembly language
|
||
|
||
pascal Handle SetSaveMenusEnableState(TAnalyzedWindowState state); // save state and enable selected menus
|
||
pascal void RestoreMenusEnableState(Handle state);
|
||
pascal void FilterEvent(EventRecord*);
|
||
|
||
|
||
// implementations
|
||
|
||
MenuListHeader** GetMenuList(void)
|
||
{
|
||
long result = (* (long*) 0xA1C);
|
||
if (result & 1)
|
||
return 0;
|
||
else
|
||
return (MenuListHeader**) result;
|
||
}
|
||
|
||
MenuListEntry* GetNextMenu(short* offset)
|
||
{
|
||
MenuListHeader** list = GetMenuList();
|
||
|
||
if (list == 0)
|
||
return 0;
|
||
*offset += sizeof(MenuListEntry);
|
||
if (*offset > (**list).lastMenu)
|
||
return 0;
|
||
else
|
||
return (MenuListEntry*) (((char*) *list) + *offset);
|
||
}
|
||
|
||
Boolean MenuBarEmpty(void)
|
||
{
|
||
short offset = 0;
|
||
return GetNextMenu(&offset) == 0; // no next menu means no menus in bar
|
||
}
|
||
|
||
|
||
Handle SaveMenusEnableState(void)
|
||
{
|
||
short offset;
|
||
MenuListEntry* mlEntry;
|
||
Handle handle;
|
||
offset = 0;
|
||
|
||
// First check to see if we already had saved the state (reentrant check)
|
||
if (GetSavedMenuState())
|
||
return 0;
|
||
|
||
// make a handle for saved enable states
|
||
|
||
handle = NewHandle(0);
|
||
if (handle == 0)
|
||
return 0;
|
||
|
||
// traverse the menus, saving state
|
||
|
||
while (mlEntry = GetNextMenu(&offset))
|
||
{
|
||
MenuStateEntry saved;
|
||
MenuHandle menu;
|
||
|
||
// make the saved state, and append it to the handle
|
||
|
||
menu = mlEntry->handle;
|
||
saved.handle = menu;
|
||
saved.savedEnableFlags = (**menu).enableFlags;
|
||
if (PtrAndHand((Ptr) &saved, handle, sizeof(MenuStateEntry)) != noErr)
|
||
{
|
||
DisposHandle(handle);
|
||
return 0;
|
||
}
|
||
}
|
||
|
||
// Be sure to save the state in our global
|
||
SetSavedMenuState(handle);
|
||
|
||
return handle;
|
||
}
|
||
|
||
pascal void RestoreMenusEnableState(Handle state)
|
||
{
|
||
short offset = 0;
|
||
MenuListEntry* mlEntry;
|
||
|
||
// traverse the menus, restoring all the enable flags
|
||
|
||
while (mlEntry = GetNextMenu(&offset))
|
||
{
|
||
MenuHandle handle = mlEntry->handle;
|
||
MenuStateEntry* stateEntry = (MenuStateEntry*) *state;
|
||
MenuStateEntry* afterLast = (MenuStateEntry*) (((char*) stateEntry) + GetHandleSize(state));
|
||
|
||
// search through the state handle for saved state for this menu
|
||
|
||
while (stateEntry < afterLast)
|
||
{
|
||
if (stateEntry->handle == handle)
|
||
{
|
||
// found it, jam it in enable flags and continue (unless system menu)
|
||
|
||
if (!IsThisASystemMenu((**handle).menuID))
|
||
(**handle).enableFlags = stateEntry->savedEnableFlags;
|
||
break;
|
||
}
|
||
stateEntry++;
|
||
}
|
||
}
|
||
|
||
DisposHandle(state);
|
||
|
||
// Be sure to clean up our global
|
||
SetSavedMenuState(0);
|
||
ModalDialogMenuSetup(false); // Tell system menus to return to normal state
|
||
}
|
||
|
||
|
||
void DisableAppMenus(void)
|
||
{
|
||
short offset = 0;
|
||
MenuListEntry* mlEntry;
|
||
|
||
// traverse the menus, setting all the enable flags to zero (unless system menu)
|
||
while (mlEntry = GetNextMenu(&offset))
|
||
{
|
||
if (!IsThisASystemMenu((**(mlEntry->handle)).menuID))
|
||
(**(mlEntry->handle)).enableFlags = 0;
|
||
}
|
||
}
|
||
|
||
|
||
Boolean ThereIsAnActiveEditTextFieldInThisWindow(WindowPtr active)
|
||
{
|
||
if (((WindowPeek)active)->windowKind == dialogKind)
|
||
{
|
||
// For some reason, NewDialog does not set up the editField in the DialogRecord.
|
||
// The next DialogMgr call does though, hence this peculiar call to GetDItem.
|
||
// Additionally, call SelIText on a stattext field points editField to that
|
||
// statText field, which belies the name editField.
|
||
short kind;
|
||
Handle h;
|
||
Rect r;
|
||
register short editField = ((DialogPeek)active)->editField; // Get the edit field locally
|
||
if (editField < 0) editField = 0; // Force into range
|
||
GetDItem(active, ++editField, &kind, &h, &r); // Inc. editField before use
|
||
// Check for editField erroneously pointing to a statText field (MPW 3.2 case)
|
||
if ((editField < 0) || ((kind & 0x7f) == editText))
|
||
if (((DialogPeek)active)->editField >= 0)
|
||
if ((**(((DialogPeek)active)->textH)).active != 0)
|
||
return true;
|
||
}
|
||
return false;
|
||
}
|
||
|
||
pascal Handle SetSaveMenusEnableState(TAnalyzedWindowState state)
|
||
{
|
||
/*
|
||
3 cases: regular window (do nothing)
|
||
modal window w/o _ModalDialog call (setup system menus)
|
||
_ModalDialog called (setup all menus)
|
||
*/
|
||
Handle result = nil;
|
||
|
||
if (state != kApplicationHandlesMenus)
|
||
{
|
||
// These 2 calls need to be in the opposite order in restore
|
||
ModalDialogMenuSetup(true); // System menus always need to be set up <18>
|
||
result = SaveMenusEnableState();
|
||
if (result)
|
||
{
|
||
// we have some kind of modal situation; check if we should setup all menus
|
||
if (state != kHandleSystemMenusDisabled)
|
||
{
|
||
// kHandleMenusEditMenuDisabled or kHandleMenusEditMenuEnabled: setup all the menus
|
||
DisableAppMenus();
|
||
if (state == kHandleMenusEditMenuEnabled)
|
||
EnableTheEditMenu();
|
||
}
|
||
}
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
void EnableTheEditMenu()
|
||
{
|
||
MenuListEntry* mlEntry;
|
||
short offset = 0;
|
||
|
||
while (mlEntry = GetNextMenu(&offset))
|
||
{
|
||
// Walk across the menus and look for Cut, Copy, and Paste (and maybe Undo) ...
|
||
MenuHandle menu = mlEntry->handle;
|
||
short items = CountMItems(menu);
|
||
short i = (short) ((items - 2) + 1); // Skip the last 2 items, since we are looking for a cluster of 3
|
||
if (i > (3 + 1)) i = (3 + 1); // Look at the first 3 items of each menu at most
|
||
while (--i > 0) // Start at the bottom of the menu, since cmd-X is usually item 3
|
||
{
|
||
short cmdChar;
|
||
GetItemCmd(menu, i, &cmdChar);
|
||
if (cmdChar == 'X')
|
||
{
|
||
long flagsToSet = (7 << i) + 1; // Compute flagsToSet now before incrementing i
|
||
GetItemCmd(menu, ++i, &cmdChar); // Check the next item (should be Copy)
|
||
if (cmdChar == 'C') // We found cmd-C, find Paste
|
||
{
|
||
GetItemCmd(menu, ++i, &cmdChar);
|
||
if (cmdChar == 'V') // We found cmd-V! This is Edit menu
|
||
(**menu).enableFlags |= flagsToSet; // So, set the flags
|
||
}
|
||
return; // Once we find cmd-X, don’t look any more
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
MenuHandle FindMenuByTitle(const unsigned char* title)
|
||
{
|
||
short offset = 0;
|
||
MenuListEntry* mlEntry;
|
||
|
||
// traverse the menus, searching for the proper menu item
|
||
|
||
while (mlEntry = GetNextMenu(&offset))
|
||
{
|
||
MenuHandle menu = mlEntry->handle;
|
||
if (EqualString((**menu).menuData, title, false, false))
|
||
return menu;
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
pascal TAnalyzedWindowState ActiveWindowNeedsHelp(void)
|
||
{
|
||
WindowPtr active;
|
||
TAnalyzedWindowState oldState;
|
||
TAnalyzedWindowState newState;
|
||
ProcessSerialNumber ourPSN;
|
||
ProcessSerialNumber currentPSN;
|
||
Boolean inFront;
|
||
|
||
if (MenuBarEmpty()) // short-circuit when there are no menus
|
||
return false;
|
||
|
||
// short circuit when current application is not frontmost since its menubar is not visible
|
||
inFront = false;
|
||
(void) GetFrontProcess(&ourPSN);
|
||
currentPSN.highLongOfPSN = 0;
|
||
currentPSN.lowLongOfPSN = kCurrentProcess;
|
||
(void) SameProcess(¤tPSN, &ourPSN, &inFront);
|
||
if (inFront == false)
|
||
return false;
|
||
|
||
active = FrontWindow();
|
||
oldState = GetAnalyzedWindowState();
|
||
|
||
if (active != GetAnalyzedWindow())
|
||
{
|
||
Boolean calledModalDialog;
|
||
|
||
// latch onto the active window
|
||
|
||
SetAnalyzedWindow(active);
|
||
SetAnalyzedWindowState(kApplicationHandlesMenus);
|
||
if (active)
|
||
{
|
||
|
||
// <18> <KSM The rest of the code in this block is change>
|
||
// Any window that is a modal dialog (WDEF 0 and variant=dBoxProc) window,
|
||
// or was the the active window at the time _ModalDialog was called
|
||
// requires us to disallow switching out (i.e., we must disable the Process menu).
|
||
// IsModal() OR _ModalDialog implies set up System Menus for a modal dialog
|
||
// But ONLY if _ModalDialog was called for this window should we check to see
|
||
// if we should handle the menus on the application's behalf.
|
||
|
||
// Find out if we called ModalDialog on this window
|
||
calledModalDialog = ((((WindowPeek)active)->spareFlag & systemHandlesMenusMask) != 0);
|
||
|
||
// Should we disable System Menus (either case)?
|
||
if (IsModal(active) || calledModalDialog)
|
||
SetAnalyzedWindowState(kHandleSystemMenusDisabled); // disable System Menus
|
||
|
||
// Should we handle menus for the application (only if ModalDialog was called)?
|
||
if (calledModalDialog)
|
||
{
|
||
// if application handles menus, Apple menu
|
||
// (or at least About item) will be disabled
|
||
|
||
MenuHandle appleMenu = FindAppleMenu();
|
||
long appleMenuFlags = GetMenuFlags(appleMenu);
|
||
if (appleMenu && (appleMenuFlags & 1) && (appleMenuFlags & 2))
|
||
{
|
||
// the application doesn’t handle menus, we will
|
||
if (ThereIsAnActiveEditTextFieldInThisWindow(active))
|
||
SetAnalyzedWindowState(kHandleMenusEditMenuEnabled);
|
||
else
|
||
SetAnalyzedWindowState(kHandleMenusEditMenuDisabled);
|
||
// since we allow choices from the menu bar, unhilite the menu to make that obvious
|
||
HiliteMenu(0);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
newState = GetAnalyzedWindowState();
|
||
|
||
// if the state has changed, menu titles may have dimmed/undimmed so redraw them
|
||
|
||
if (oldState != newState)
|
||
InvalMenuBar();
|
||
|
||
// return true if we are handling menus
|
||
|
||
return newState;
|
||
}
|
||
|
||
pascal void FilterEvent(EventRecord* event)
|
||
{
|
||
if ((event->what == nullEvent) || (event->what == updateEvt))
|
||
(void) ActiveWindowNeedsHelp();
|
||
else if (event->what == mouseDown)
|
||
{
|
||
if (PtInMenuBar(event->where))
|
||
{
|
||
TAnalyzedWindowState state = ActiveWindowNeedsHelp();
|
||
if ((state == kHandleMenusEditMenuEnabled) || (state == kHandleMenusEditMenuDisabled))
|
||
{
|
||
long result;
|
||
register short menuID;
|
||
event->what = nullEvent;
|
||
|
||
// track the menus
|
||
|
||
result = MenuSelect(event->where);
|
||
if (menuID = (short) (result >> 16))
|
||
{
|
||
short cmdChar;
|
||
GetItemCmd(GetMHandle(menuID), (short) result, &cmdChar);
|
||
// following is a compatibility hack for Word which does not respect enableFlags
|
||
if (cmdChar != 0)
|
||
{
|
||
EvQElPtr postedEvent;
|
||
if (PPostEvent(keyDown, cmdChar, &postedEvent) != noErr)
|
||
// if the event was not posted, unhilite the menu now
|
||
HiliteMenu(0);
|
||
else
|
||
// otherwise, wait for MenuKey to unhilite it
|
||
postedEvent->evtQModifiers = cmdKey;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
else if (event->what == keyDown)
|
||
{
|
||
if ((event->modifiers & cmdKey) || ((char) event->message == kFunctionKey))
|
||
{
|
||
TAnalyzedWindowState state = ActiveWindowNeedsHelp();
|
||
if ((state == kHandleMenusEditMenuEnabled) || (state == kHandleMenusEditMenuDisabled))
|
||
{
|
||
long result;
|
||
unsigned char key = (char) event->message;
|
||
|
||
if (key == kFunctionKey)
|
||
{
|
||
unsigned char virtualKey = (event->message & keyCodeMask) >> 8;
|
||
|
||
switch (virtualKey)
|
||
{
|
||
case kCut:
|
||
key = 'X';
|
||
break;
|
||
|
||
case kCopy:
|
||
key = 'C';
|
||
break;
|
||
|
||
case kPaste:
|
||
key = 'V';
|
||
break;
|
||
|
||
default:
|
||
key = 0;
|
||
break;
|
||
}
|
||
}
|
||
|
||
// just hilite the menus when the relevant key is pressed
|
||
|
||
if (key && (result = MenuKey(key)))
|
||
{
|
||
long dummy;
|
||
Delay(8, &dummy);
|
||
}
|
||
HiliteMenu(0);
|
||
}
|
||
}
|
||
}
|
||
|
||
if (event->what != nullEvent)
|
||
SetAnalyzedWindow((WindowPtr) 1); // set to something that is never a window
|
||
}
|
||
|
||
long GetMenuFlags(MenuHandle menu)
|
||
{
|
||
if (menu)
|
||
{
|
||
Handle savedFlags = GetSavedMenuState();
|
||
if (savedFlags)
|
||
{
|
||
MenuStateEntry* stateEntry = (MenuStateEntry*) *savedFlags;
|
||
MenuStateEntry* afterLast = (MenuStateEntry*) (((char*) stateEntry) + GetHandleSize(savedFlags));
|
||
|
||
// search through the state handle for saved state for this menu
|
||
|
||
while (stateEntry < afterLast)
|
||
{
|
||
if (stateEntry->handle == menu)
|
||
// found it, return saved enable flags
|
||
return stateEntry->savedEnableFlags;
|
||
++stateEntry;
|
||
}
|
||
}
|
||
return (**menu).enableFlags; // didn’t find a saved state, so return the flags from the menu
|
||
}
|
||
return 0; // didn’t find a menu, so return nothing enabled
|
||
}
|
||
|
||
MenuHandle FindAppleMenu(void)
|
||
{
|
||
// *** use MENU resource
|
||
return FindMenuByTitle("\p\024");
|
||
}
|
||
|
||
Boolean PtInMenuBar(Point pt)
|
||
{
|
||
Rect mbRect;
|
||
(void) GetMBARRect(&mbRect);
|
||
return PtInRect(pt, &mbRect);
|
||
}
|
||
|
||
Boolean IsThisASystemMenu(short menuID)
|
||
{
|
||
Boolean isSys;
|
||
if (IsSystemMenu(menuID, &isSys) != noErr)
|
||
return 0;
|
||
return isSys;
|
||
}
|
||
|
||
Boolean IsModal(WindowPtr active)
|
||
{
|
||
short class;
|
||
if (GetWindowModalClass(active,&class) != noErr)
|
||
return false;
|
||
return (class == dBoxProc);
|
||
}
|