tkMacOSXMenu.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:129k
- /*
- * tkMacOSXMenu.c --
- *
- * This module implements the Mac-platform specific features of menus.
- *
- * Copyright (c) 1996-1997 by Sun Microsystems, Inc.
- * Copyright 2001, Apple Computer, Inc.
- * Copyright (c) 2005-2007 Daniel A. Steffen <das@users.sourceforge.net>
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkMacOSXMenu.c,v 1.6.2.30 2007/11/09 06:26:56 das Exp $
- */
- #include "tkMacOSXPrivate.h"
- #include "tkMenubutton.h"
- #include "tkMenu.h"
- #include "tkColor.h"
- #include "tkFont.h"
- #include "tkMacOSXDebug.h"
- /*
- #ifdef TK_MAC_DEBUG
- #define TK_MAC_DEBUG_MENUS
- #endif
- */
- #define USE_TK_MDEF
- typedef struct MacMenu {
- MenuRef menuHdl; /* The Menu Manager data structure. */
- #ifdef USE_TK_MDEF
- int useMDEF; /* true if this menu uses the MDEF */
- #endif
- } MacMenu;
- typedef struct MenuEntryUserData {
- Drawable mdefDrawable;
- TkMenuEntry *mePtr;
- Tk_Font tkfont;
- Tk_FontMetrics *fmPtr;
- } MenuEntryUserData;
- /*
- * Platform specific flags for menu entries
- *
- * ENTRY_COMMAND_ACCEL Indicates the entry has the command key
- * in its accelerator string.
- * ENTRY_OPTION_ACCEL Indicates the entry has the option key
- * in its accelerator string.
- * ENTRY_SHIFT_ACCEL Indicates the entry has the shift key
- * in its accelerator string.
- * ENTRY_CONTROL_ACCEL Indicates the entry has the control key
- * in its accelerator string.
- */
- #define ENTRY_COMMAND_ACCEL ENTRY_PLATFORM_FLAG1
- #define ENTRY_OPTION_ACCEL ENTRY_PLATFORM_FLAG2
- #define ENTRY_SHIFT_ACCEL ENTRY_PLATFORM_FLAG3
- #define ENTRY_CONTROL_ACCEL ENTRY_PLATFORM_FLAG4
- #define ENTRY_ACCEL_MASK (ENTRY_COMMAND_ACCEL | ENTRY_OPTION_ACCEL
- | ENTRY_SHIFT_ACCEL | ENTRY_CONTROL_ACCEL)
- #define MODIFIER_NUM 4
- /*
- * This structure is used to keep track of subfields within Macintosh menu
- * items.
- */
- typedef struct EntryGeometry {
- int accelTextStart; /* Offset into the accel string where
- * the text starts. Everything before
- * this is modifier key descriptions.
- */
- int modifierWidth; /* Width of modifier symbols. */
- int accelTextWidth; /* Width of the text after the modifier
- * keys. */
- int nonAccelMargin; /* The width of the margin for entries
- * without accelerators. */
- int modifierNum; /* Number of modifiers */
- Tcl_UniChar modifierUniChars[MODIFIER_NUM];
- /* Modifiers in unicode */
- char accelGlyph; /* Accelerator glyph, if any */
- } EntryGeometry;
- /*
- * Structure to keep track of toplevel windows and their menubars.
- */
- typedef struct TopLevelMenubarList {
- struct TopLevelMenubarList *nextPtr;
- /* The next window in the list. */
- Tk_Window tkwin; /* The toplevel window. */
- TkMenu *menuPtr; /* The menu associated with this
- * toplevel. */
- } TopLevelMenubarList;
- /*
- * Platform-specific flags for menus.
- *
- * MENU_APPLE_MENU 0 indicates a custom Apple menu has
- * not been installed; 1 a custom Apple
- * menu has been installed.
- * MENU_HELP_MENU 0 indicates a custom Help menu has
- * not been installed; 1 a custom Help
- * menu has been installed.
- * MENU_RECONFIGURE_PENDING 1 indicates that an idle handler has
- * been scheduled to reconfigure the
- * Macintosh MenuHandle.
- */
- #define MENU_APPLE_MENU MENU_PLATFORM_FLAG1
- #define MENU_HELP_MENU MENU_PLATFORM_FLAG2
- #define MENU_RECONFIGURE_PENDING MENU_PLATFORM_FLAG3
- #define CASCADE_CMD (0x1b) /* The special command char for cascade
- * menus. */
- #define MENUBAR_REDRAW_PENDING 1
- static int gNoTkMenus = 0; /* This is used by Tk_MacOSXTurnOffMenus as the
- * flag that Tk is not to draw any menus. */
- static Tcl_HashTable commandTable;
- /* The list of menuInstancePtrs associated with
- * menu ids */
- static short currentAppleMenuID;
- /* The id of the current Apple menu. 0 for
- * none. */
- static short currentHelpMenuID; /* The id of the current Help menu. 0 for
- * none. */
- static Tcl_Interp *currentMenuBarInterp;
- /* The interpreter of the window that owns
- * the current menubar. */
- static char *currentMenuBarName;
- /* Malloced. Name of current menu in menu bar.
- * NULL if no menu set. TO DO: make this a
- * DString. */
- static Tk_Window currentMenuBarOwner;
- /* Which window owns the current menu bar. */
- static int inPostMenu; /* We cannot be re-entrant like X
- * windows. */
- static short lastMenuID; /* To pass to NewMenu; need to figure out
- * a good way to do this. */
- static short lastCascadeID;
- /* Cascades have to have ids that are
- * less than 256. */
- static int menuBarFlags; /* Used for whether the menu bar needs
- * redrawing or not. */
- struct MenuCommandHandlerData { /* This is the ClientData we pass to */
- TkMenu *menuPtr; /* Tcl_DoWhenIdle to move handling */
- int index; /* menu commands to the event loop. */
- };
- static TopLevelMenubarList *windowListPtr;
- /* A list of windows that have menubars set. */
- /*
- * Array of unicode, charcode and utf representations of the most common
- * special menu symbols.
- */
- typedef struct MenuSymbol {
- const Tcl_UniChar unicode;
- const char charCode;
- /* char padding; */
- int utfLen, width;
- char utf[TCL_UTF_MAX + 1];
- } MenuSymbol;
- static MenuSymbol menuSymbols[] = {
- {kCommandUnicode, kCommandCharCode},
- {kOptionUnicode, kMenuOptionGlyph},
- {kControlUnicode, kMenuControlGlyph},
- {kShiftUnicode, kMenuShiftGlyph},
- {kCheckUnicode, kCheckCharCode},
- {kDiamondUnicode, kDiamondCharCode},
- {kBulletUnicode, kBulletCharCode},
- {0x2026, kNullCharCode},
- {0, 0},
- };
- enum MenuSymbolIdx {
- COMMAND_SYMBOL,
- OPTION_SYMBOL,
- CONTROL_SYMBOL,
- SHIFT_SYMBOL,
- CHECK_SYMBOL,
- DIAMDOND_SYMBOL,
- BULLET_SYMBOL,
- ELLIPSIS_SYMBOL,
- };
- MenuRef tkCurrentAppleMenu = NULL;
- static SInt32 menuMarkColumnWidth = 0, menuMarkIndent = 0;
- static SInt32 menuTextLeadingEdgeMargin = 0, menuTextTrailingEdgeMargin = 0;
- static SInt16 menuItemExtraHeight = 0, menuItemExtraWidth = 0;
- static SInt16 menuSeparatorHeight = 0;
- /*
- * Forward declarations for procedures defined later in this file:
- */
- MODULE_SCOPE int TkMacOSXGetNewMenuID(Tcl_Interp *interp, TkMenu *menuInstPtr,
- int cascade, short *menuIDPtr);
- MODULE_SCOPE void TkMacOSXFreeMenuID(short menuID);
- static void CompleteIdlers(TkMenu *menuPtr);
- static void DrawMenuBarWhenIdle(ClientData clientData);
- static void DrawMenuEntryAccelerator(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Drawable d, GC gc, Tk_Font tkfont, const Tk_FontMetrics *fmPtr,
- Tk_3DBorder activeBorder, int x, int y, int width, int height,
- int drawArrow);
- static void DrawMenuEntryBackground(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Drawable d, Tk_3DBorder activeBorder, Tk_3DBorder bgBorder, int x,
- int y, int width, int heigth);
- static void DrawMenuEntryIndicator(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Drawable d, GC gc, GC indicatorGC, Tk_Font tkfont,
- const Tk_FontMetrics *fmPtr, int x, int y, int width, int height);
- static void DrawMenuEntryLabel(TkMenu * menuPtr, TkMenuEntry *mePtr,
- Drawable d, GC gc, Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int x,
- int y, int width, int height);
- static void DrawMenuSeparator(TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d,
- GC gc, Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int x, int y,
- int width, int height);
- static void DrawTearoffEntry(TkMenu *menuPtr, TkMenuEntry *mePtr, Drawable d,
- GC gc, Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int x, int y,
- int width, int height);
- static void EventuallyInvokeMenu(ClientData data);
- static void GetEntryText(TkMenuEntry *mePtr, Tcl_DString *dStringPtr);
- static void GetMenuAccelGeometry(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int *modWidthPtr,
- int *textWidthPtr, int *heightPtr);
- static void GetMenuLabelGeometry(TkMenuEntry *mePtr, Tk_Font tkfont,
- const Tk_FontMetrics *fmPtr, int *widthPtr, int *heightPtr);
- static void GetMenuIndicatorGeometry(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int *widthPtr,
- int *heightPtr);
- static void GetMenuSeparatorGeometry(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int *widthPtr,
- int *heightPtr);
- static TkMenuEntry* GetParentMenuEntry(TkMenu *menuPtr);
- static void GetTearoffEntryGeometry(TkMenu *menuPtr, TkMenuEntry *mePtr,
- Tk_Font tkfont, const Tk_FontMetrics *fmPtr, int *widthPtr,
- int *heightPtr);
- static char FindMarkCharacter(TkMenuEntry *mePtr);
- static int GetUtfMarkCharacter(char markChar, const char **markUtfPtr);
- static TkMenu* MenuPtrForMenuRef(MenuRef menu);
- static int ParseAccelerators(const char **accelStringPtr, int *modifierNumPtr,
- Tcl_UniChar *modifierUniChars, int *modifierWidth);
- static void MenuSelectEvent(TkMenu *menuPtr);
- static void ReconfigureIndividualMenu(TkMenu *menuPtr, MenuHandle macMenuHdl,
- int base);
- static void ReconfigureMacintoshMenu(ClientData clientData);
- static void RecursivelyClearActiveMenu(TkMenu *menuPtr);
- static void RecursivelyDeleteMenu(TkMenu *menuPtr);
- static void RecursivelyInsertMenu(TkMenu *menuPtr);
- static void SetDefaultMenubar(void);
- static int SetMenuCascade(TkMenu *menuPtr);
- #ifdef USE_TK_MDEF
- #define SCREEN_MARGIN 5
- static MacDrawable macMDEFDrawable;
- /* Drawable for use by MDEF code */
- static int MDEFScrollFlag = 0; /* Used so that popups don't scroll too soon.*/
- static MenuItemDrawingUPP tkThemeMenuItemDrawingUPP;
- /* Points to the UPP for theme Item drawing. */
- static Tcl_Obj *useMDEFVar;
- static void DrawMenuBackground(TkMenu *menuPtr, Rect *menuRectPtr,
- Drawable d);
- static void MenuDefProc(short message, MenuHandle menu, Rect *menuRectPtr,
- Point hitPt, short *whichItem );
- static void HandleMenuHiliteMsg(MenuRef menu, Rect *menuRectPtr, Point hitPt,
- SInt16 *whichItem, TkMenu *menuPtr);
- static void HandleMenuDrawMsg(MenuRef menu, Rect *menuRectPtr, Point hitPt,
- SInt16 *whichItem, TkMenu *menuPtr);
- static void HandleMenuFindItemMsg(MenuRef menu, Rect *menuRectPtr,
- Point hitPt, SInt16 *whichItem, TkMenu *menuPtr);
- static void HandleMenuPopUpMsg(MenuRef menu, Rect *menuRectPtr, Point hitPt,
- SInt16 *whichItem, TkMenu *menuPtr);
- static void HandleMenuCalcItemMsg(MenuRef menu, Rect *menuRectPtr, Point hitPt,
- SInt16 *whichItem, TkMenu *menuPtr);
- static void AppearanceEntryDrawWrapper(TkMenuEntry *mePtr, Rect * menuRectPtr,
- MenuTrackingData *mtdPtr, Drawable d, Tk_FontMetrics *fmPtr,
- Tk_Font tkfont, int erase);
- static pascal void ThemeMenuItemDrawingProc(const Rect *inBounds,
- SInt16 inDepth, Boolean inIsColorDevice, SInt32 inUserData);
- #else /* USE_TK_MDEF */
- # define useMDEF 0
- #endif /* USE_TK_MDEF */
- #define IS_THEME_MENU_FONT(tkfont) (strcmp(Tk_NameOfFont(tkfont), "menu") == 0)
- /*
- *----------------------------------------------------------------------
- *
- * DrawThemeText --
- *
- * Wrapper for DrawThemeTextBox API.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static void
- DrawThemeText(
- Drawable d,
- GC gc,
- CFStringRef string,
- ThemeFontID font,
- ThemeDrawState drawState,
- const Rect* bounds,
- int baseline,
- int just)
- {
- TkMacOSXDrawingContext dc;
- Rect adjustedBounds;
- /*
- * Menu item text drawn with the .Keyboard font (used for
- * kThemeMenuItemCmdKeyFont) won't always have the same ascent and
- * baseline as text drawn with the regular menu item font, since the
- * glyphs in the .Keyboard font may have a different height. Therefore, we
- * first determine the baseline of the text and then adjust the bounds
- * rect so the baseline aligns with the overall baseline of the menu item.
- */
- if (font == kThemeMenuItemCmdKeyFont) {
- Point size;
- SInt16 cmdKeyBaseline;
- GetThemeTextDimensions(string, font, drawState, false, &size,
- &cmdKeyBaseline);
- adjustedBounds = *bounds;
- OffsetRect(&adjustedBounds, 0, baseline - bounds->top - size.v -
- cmdKeyBaseline);
- bounds = &adjustedBounds;
- }
- if (TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
- ChkErr(DrawThemeTextBox, string, font, drawState, false, bounds, just,
- dc.context);
- TkMacOSXRestoreDrawingContext(&dc);
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * MeasureThemeText --
- *
- * Wrapper for GetThemeTextDimensions API.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- static int
- MeasureThemeText(
- CFStringRef string,
- ThemeFontID font)
- {
- Point pt;
- ChkErr(GetThemeTextDimensions, string, font, kThemeStateActive, false, &pt,
- NULL);
- return pt.h;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkMacOSXUseID --
- *
- * Take the ID out of the available list for new menus. Used by the
- * default menu bar's menus so that they do not get created at the tk
- * level. See TkMacOSXGetNewMenuID for more information.
- *
- * Results:
- * Returns TCL_OK if the id was not in use. Returns TCL_ERROR if the
- * id was in use.
- *
- * Side effects:
- * A hash table entry in the command table is created with a NULL
- * value.
- *
- *----------------------------------------------------------------------
- */
- int
- TkMacOSXUseMenuID(
- short macID) /* The id to take out of the table */
- {
- Tcl_HashEntry *commandEntryPtr;
- int newEntry;
- int iMacID = macID; /* Do this to remove compiler warning */
- TkMenuInit();
- commandEntryPtr = Tcl_CreateHashEntry(&commandTable, (char *) iMacID,
- &newEntry);
- if (!newEntry) {
- return TCL_ERROR;
- }
- Tcl_SetHashValue(commandEntryPtr, NULL);
- return TCL_OK;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkMacOSXGetNewMenuID --
- *
- * Allocates a new menu id and marks it in use. Each menu on the
- * mac must be designated by a unique id, which is a short. In
- * addition, some ids are reserved by the system. Since Tk uses
- * mostly dynamic menus, we must allocate and free these ids on
- * the fly. We use the id as a key into a hash table; if there
- * is no hash entry, we know that we can use the id.
- *
- * Carbon allows a much larger number of menus than the old APIs.
- * I believe this is 32768, but am not sure. This code just uses
- * 2000 as the upper limit. Unfortunately tk leaks menus when
- * cloning, under some circumstances (see bug on sourceforge).
- *
- * Results:
- * Returns TCL_OK if succesful; TCL_ERROR if there are no more
- * ids of the appropriate type to allocate. menuIDPtr contains
- * the new id if succesful.
- *
- * Side effects:
- * An entry is created for the menu in the command hash table,
- * and the hash entry is stored in the appropriate field in the
- * menu data structure.
- *
- *----------------------------------------------------------------------
- */
- int
- TkMacOSXGetNewMenuID(
- Tcl_Interp *interp, /* Used for error reporting */
- TkMenu *menuPtr, /* The menu we are working with */
- int cascade, /* 0 if we are working with a normal menu;
- * 1 if we are working with a cascade */
- short *menuIDPtr) /* The resulting id */
- {
- int found = 0;
- int newEntry;
- Tcl_HashEntry *commandEntryPtr = NULL;
- short returnID = *menuIDPtr;
- /*
- * The following code relies on shorts and unsigned chars wrapping
- * when the highest value is incremented. Also, the values between
- * 236 and 255 inclusive are reserved for DA's by the Mac OS.
- */
- if (!cascade) {
- short curID = lastMenuID + 1;
- if (curID == 236) {
- curID = 256;
- }
- while (curID != lastMenuID) {
- int iCurID = curID;
- commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
- (char *) iCurID, &newEntry);
- if (newEntry == 1) {
- found = 1;
- lastMenuID = returnID = curID;
- break;
- }
- curID++;
- if (curID == 236) {
- curID = 256;
- }
- }
- } else {
- /*
- * Cascade ids must be between 0 and 235 only, so they must be
- * dealt with separately.
- */
- short curID = lastCascadeID + 1;
- if (curID == 2000) {
- curID = 0;
- }
- while (curID != lastCascadeID) {
- int iCurID = curID;
- commandEntryPtr = Tcl_CreateHashEntry(&commandTable,
- (char *) iCurID, &newEntry);
- if (newEntry == 1) {
- found = 1;
- lastCascadeID = returnID = curID;
- break;
- }
- curID++;
- if (curID == 2000) {
- curID = 0;
- }
- }
- }
- if (!found) {
- Tcl_ResetResult(interp);
- Tcl_AppendResult(interp, "No more menus can be allocated.", NULL);
- return TCL_ERROR;
- }
- Tcl_SetHashValue(commandEntryPtr, (char *) menuPtr);
- *menuIDPtr = returnID;
- return TCL_OK;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkMacOSXFreeMenuID --
- *
- * Marks the id as free.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The hash table entry for the ID is cleared.
- *
- *----------------------------------------------------------------------
- */
- void
- TkMacOSXFreeMenuID(
- short menuID) /* The id to free */
- {
- Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable,
- (char*)(intptr_t)menuID);
- if (entryPtr != NULL) {
- Tcl_DeleteHashEntry(entryPtr);
- }
- if (menuID == currentAppleMenuID) {
- currentAppleMenuID = 0;
- }
- if (menuID == currentHelpMenuID) {
- currentHelpMenuID = 0;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * MenuPtrForMenuRef --
- *
- * Returns a pointer to the TkMenu corresponding to a given
- * Carbon MenuRef.
- *
- * Results:
- * Returns a pointer to a TkMenu or NULL.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- TkMenu*
- MenuPtrForMenuRef(
- MenuRef menu)
- {
- TkMenu *menuPtr = NULL;
- MenuID menuID = GetMenuID(menu);
- Tcl_HashEntry *commandEntryPtr = Tcl_FindHashEntry(&commandTable,
- (char*)(intptr_t)menuID);
- if (commandEntryPtr) {
- menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
- }
- return menuPtr;
- }
- /*
- *----------------------------------------------------------------------
- *
- * GetParentMenuEntry --
- *
- * Returns a pointer to the parent's TkMenuEntry of a given TkMenu.
- *
- * Results:
- * Returns a pointer to a TkMenuEntry or NULL.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- TkMenuEntry*
- GetParentMenuEntry(
- TkMenu *menuPtr)
- {
- TkMenuEntry *cascadeEntryPtr;
- for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
- cascadeEntryPtr != NULL;
- cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
- const char *name = (cascadeEntryPtr->namePtr == NULL) ? ""
- : Tcl_GetString(cascadeEntryPtr->namePtr);
- if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) {
- break;
- }
- }
- return cascadeEntryPtr;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpNewMenu --
- *
- * Gets a new blank menu. Only the platform specific options are filled
- * in.
- *
- * Results:
- * Returns a standard TCL error.
- *
- * Side effects:
- * Allocates a Macintosh menu handle and puts in the platformData
- * field of the menuPtr.
- *
- *----------------------------------------------------------------------
- */
- int
- TkpNewMenu(
- TkMenu *menuPtr) /* The common structure we are making the
- * platform structure for. */
- {
- short menuID;
- MenuRef macMenuHdl;
- #ifdef USE_TK_MDEF
- MenuDefSpec menuDefSpec;
- Tcl_Obj *useMDEFObjPtr;
- int useMDEF = 1;
- #endif
- int error = TCL_OK;
- OSStatus err;
- CFStringRef cfStr;
- error = TkMacOSXGetNewMenuID(menuPtr->interp, menuPtr, 0, &menuID);
- if (error != TCL_OK) {
- return error;
- }
- err = ChkErr(CreateNewMenu, menuID, kMenuAttrDoNotUseUserCommandKeys,
- &macMenuHdl);
- if (err != noErr) {
- Tcl_AppendResult(menuPtr->interp, "CreateNewMenu failed.", NULL);
- return TCL_ERROR;
- }
- cfStr = CFStringCreateWithCString(NULL, Tk_PathName(menuPtr->tkwin),
- kCFStringEncodingUTF8);
- if (!cfStr) {
- Tcl_AppendResult(menuPtr->interp, "CFStringCreateWithCString failed.",
- NULL);
- return TCL_ERROR;
- }
- err = ChkErr(SetMenuTitleWithCFString, macMenuHdl, cfStr);
- CFRelease(cfStr);
- if (err != noErr) {
- Tcl_AppendResult(menuPtr->interp, "SetMenuTitleWithCFString failed.",
- NULL);
- return TCL_ERROR;
- }
- menuPtr->platformData = (TkMenuPlatformData) ckalloc(sizeof(MacMenu));
- ((MacMenu *) menuPtr->platformData)->menuHdl = macMenuHdl;
- #ifdef USE_TK_MDEF
- /*
- * Check whether we want to use the custom mdef or not. For now
- * the default is to use it unless the variable is explicitly
- * set to no.
- */
- useMDEFObjPtr = Tcl_ObjGetVar2(menuPtr->interp, useMDEFVar, NULL,
- TCL_GLOBAL_ONLY);
- if (useMDEFObjPtr == NULL || Tcl_GetBooleanFromObj(NULL, useMDEFObjPtr,
- &useMDEF) == TCL_ERROR || useMDEF) {
- menuDefSpec.defType = kMenuDefProcPtr;
- menuDefSpec.u.defProc = MenuDefProc;
- ChkErr(SetMenuDefinition, macMenuHdl, &menuDefSpec);
- }
- ((MacMenu *) menuPtr->platformData)->useMDEF = useMDEF;
- #endif /* USE_TK_MDEF */
- if ((currentMenuBarInterp == menuPtr->interp)
- && (currentMenuBarName != NULL)) {
- Tk_Window parentWin = Tk_Parent(menuPtr->tkwin);
- if (strcmp(currentMenuBarName, Tk_PathName(parentWin)) == 0) {
- if ((strcmp(Tk_PathName(menuPtr->tkwin)
- + strlen(Tk_PathName(parentWin)), ".apple") == 0)
- || (strcmp(Tk_PathName(menuPtr->tkwin)
- + strlen(Tk_PathName(parentWin)), ".help") == 0)) {
- if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DrawMenuBarWhenIdle, NULL);
- menuBarFlags |= MENUBAR_REDRAW_PENDING;
- }
- }
- }
- }
- menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
- return TCL_OK;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpDestroyMenu --
- *
- * Destroys platform-specific menu structures.
- *
- * Results:
- * None.
- *
- * Side effects:
- * All platform-specific allocations are freed up.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpDestroyMenu(
- TkMenu *menuPtr) /* The common menu structure */
- {
- MenuRef macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
- if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
- Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr);
- menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING;
- }
- if (GetMenuID(macMenuHdl) == currentHelpMenuID) {
- MenuRef helpMenuHdl;
- MenuItemIndex helpIndex;
- if ((HMGetHelpMenu(&helpMenuHdl,&helpIndex) == noErr)
- && (helpMenuHdl != NULL)) {
- int i, count = CountMenuItems(helpMenuHdl);
- for (i = helpIndex; i <= count; i++) {
- DeleteMenuItem(helpMenuHdl, helpIndex);
- }
- }
- currentHelpMenuID = 0;
- }
- if (menuPtr->platformData != NULL) {
- MenuID menuID = GetMenuID(macMenuHdl);
- DeleteMenu(menuID);
- TkMacOSXFreeMenuID(menuID);
- DisposeMenu(macMenuHdl);
- ckfree((char *) menuPtr->platformData);
- menuPtr->platformData = NULL;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * SetMenuCascade --
- *
- * Does any cleanup to change a menu from a normal to a cascade.
- *
- * Results:
- * Standard Tcl error.
- *
- * Side effects:
- * The mac menu id is reset.
- *
- *----------------------------------------------------------------------
- */
- int
- SetMenuCascade(
- TkMenu* menuPtr) /* The menu we are setting up to be a
- * cascade. */
- {
- MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
- MenuID newMenuID, menuID = GetMenuID(macMenuHdl);
- int error = TCL_OK;
- if (menuID >= 256) {
- error = TkMacOSXGetNewMenuID(menuPtr->interp, menuPtr, 1, &newMenuID);
- if (error == TCL_OK) {
- TkMacOSXFreeMenuID(menuID);
- SetMenuID(macMenuHdl,newMenuID);
- }
- }
- return error;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpDestroyMenuEntry --
- *
- * Cleans up platform-specific menu entry items.
- *
- * Results:
- * None
- *
- * Side effects:
- * All platform-specific allocations are freed up.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpDestroyMenuEntry(
- TkMenuEntry *mePtr) /* The common structure for the menu entry. */
- {
- TkMenu *menuPtr = mePtr->menuPtr;
- ckfree((char *) mePtr->platformEntryData);
- if ((menuPtr->platformData != NULL)
- && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
- menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * GetEntryText --
- *
- * Given a menu entry, gives back the text that should go in it.
- * Separators should be done by the caller, as they have to be
- * handled specially. This is primarily used to do a substitution
- * between "..." and the ellipsis character which looks nicer.
- *
- * Results:
- * itemText points to the new text for the item.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- void
- GetEntryText(
- TkMenuEntry *mePtr, /* A pointer to the menu entry. */
- Tcl_DString *dStringPtr) /* The DString to put the text into. This
- * will be initialized by this routine. */
- {
- #ifdef USE_TK_MDEF
- const int useMDEF = ((MacMenu *) mePtr->menuPtr->platformData)->useMDEF;
- #endif
- int noLabel = (mePtr->labelPtr == NULL || mePtr->labelLength == 0);
- Tcl_DStringInit(dStringPtr);
- if (mePtr->type == TEAROFF_ENTRY && (useMDEF || noLabel)) {
- Tcl_DStringAppend(dStringPtr, "(Tear-off)", -1);
- } else if (mePtr->imagePtr != NULL && (useMDEF || noLabel) &&
- mePtr->compound == COMPOUND_NONE) {
- Tcl_DStringAppend(dStringPtr, "(Image)", -1);
- } else if (mePtr->bitmapPtr != NULL && (useMDEF || noLabel) &&
- mePtr->compound == COMPOUND_NONE) {
- Tcl_DStringAppend(dStringPtr, "(Pixmap)", -1);
- } else if (noLabel) {
- /*
- * The Mac menu manager does not like null strings.
- */
- Tcl_DStringAppend(dStringPtr, " ", -1);
- } else {
- int length;
- char *text = Tcl_GetStringFromObj(mePtr->labelPtr, &length);
- char *dStringText;
- int i;
- for (i = 0; *text; text++, i++) {
- if ((*text == '.') && (*(text+1) == '.') && (*(text+2) == '.')) {
- Tcl_DStringAppend(dStringPtr, menuSymbols[ELLIPSIS_SYMBOL].utf,
- menuSymbols[ELLIPSIS_SYMBOL].utfLen);
- i += menuSymbols[ELLIPSIS_SYMBOL].utfLen - 1;
- text += 2;
- } else {
- Tcl_DStringSetLength(dStringPtr,
- Tcl_DStringLength(dStringPtr) + 1);
- dStringText = Tcl_DStringValue(dStringPtr);
- dStringText[i] = *text;
- }
- }
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * FindMarkCharacter --
- *
- * Finds the Macintosh mark character based on the font of the
- * item. We calculate a good mark character based on the font
- * that this item is rendered in.
- *
- * Results:
- * Mark char.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- char
- FindMarkCharacter(
- TkMenuEntry *mePtr) /* The entry we are finding the character
- * for. */
- {
- static const char markChars[] = {kCheckCharCode, kDiamondCharCode,
- kBulletCharCode, '-', kCheckCharCode};
- const char *markChar = markChars;
- int i = sizeof(markChars);
- Tk_Font tkfont;
- tkfont = Tk_GetFontFromObj(mePtr->menuPtr->tkwin,
- (mePtr->fontPtr == NULL) ? mePtr->menuPtr->fontPtr
- : mePtr->fontPtr);
- while (--i) {
- if (!TkMacOSXIsCharacterMissing(tkfont, *markChar)) {
- break;
- }
- markChar++;
- }
- return *markChar;
- }
- /*
- *----------------------------------------------------------------------
- *
- * GetUtfMarkCharacter --
- *
- * Get the utf8 string for the given mark character, taking into
- * account the special menu font char codes.
- *
- * Results:
- * Length of returned utf8 string.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- GetUtfMarkCharacter(
- char markChar,
- const char **markUtfPtr)
- {
- const MenuSymbol *ms = menuSymbols;
- int len = 0;
- while (ms->unicode) {
- if (ms->charCode && ms->charCode == markChar) {
- *markUtfPtr = ms->utf;
- len = ms->utfLen;
- break;
- }
- ms++;
- }
- if (!len) {
- static char markUtf[TCL_UTF_MAX + 1];
- Tcl_ExternalToUtf(NULL, TkMacOSXCarbonEncoding, &markChar, 1, 0, NULL,
- markUtf, TCL_UTF_MAX + 1, NULL, &len, NULL);
- *markUtfPtr = markUtf;
- }
- return len;
- }
- /*
- *----------------------------------------------------------------------
- *
- * ParseAccelerators --
- *
- * Parse menu accelerator string.
- *
- * Results:
- * Accelerator flags.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- int
- ParseAccelerators(
- const char **accelStringPtr,
- int *modifierNumPtr,
- Tcl_UniChar *modifierUniChars,
- int *modifierWidth)
- {
- struct Modif {
- const char *name;
- const size_t len;
- const int flag, symbol;
- };
- #define MODIF(n, f) { #n, sizeof(#n)-1, ENTRY_##f##_ACCEL, f##_SYMBOL }
- static const struct Modif modifs[] = {
- MODIF(Control, CONTROL),
- MODIF(Ctrl, CONTROL),
- MODIF(Option, OPTION),
- MODIF(Opt, OPTION),
- MODIF(Alt, OPTION),
- MODIF(Shift, SHIFT),
- MODIF(Command, COMMAND),
- MODIF(Cmd, COMMAND),
- MODIF(Meta, COMMAND),
- { NULL, 0, 0, 0}
- };
- #undef MODIF
- const char *accelString = *accelStringPtr;
- int flags = 0, num = 0, seen = 0, width = 0;
- const struct Modif *m;
- while (1) {
- m = modifs;
- while (m->name) {
- int l = m->len;
- if (!strncasecmp(accelString, m->name, l) &&
- (accelString[l] == '-' || accelString[l] == '+')) {
- flags |= m->flag;
- accelString += l+1;
- break;
- }
- m++;
- }
- if (!m->name || !*accelString) {
- break;
- }
- }
- m = modifs;
- while (m->name && num < MODIFIER_NUM) {
- if (flags & m->flag && !(seen & m->flag)) {
- modifierUniChars[num++] = menuSymbols[m->symbol].unicode;
- width += menuSymbols[m->symbol].width;
- seen |= m->flag;
- }
- m++;
- }
- *accelStringPtr = accelString;
- *modifierNumPtr = num;
- *modifierWidth = width;
- return flags;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpConfigureMenuEntry --
- *
- * Processes configurations for menu entries.
- *
- * Results:
- * Returns standard TCL result. If TCL_ERROR is returned, then
- * the interp's result contains an error message.
- *
- * Side effects:
- * Configuration information get set for mePtr; old resources
- * get freed, if any need it.
- *
- *----------------------------------------------------------------------
- */
- int
- TkpConfigureMenuEntry(
- TkMenuEntry *mePtr) /* Information about menu entry; may
- * or may not already have values for
- * some fields. */
- {
- TkMenu *menuPtr = mePtr->menuPtr;
- EntryGeometry *geometryPtr = (EntryGeometry *) mePtr->platformEntryData;
- /*
- * Cascade menus have to have menu IDs of less than 256. So
- * we need to change the child menu if this has been configured
- * for a cascade item.
- */
- if (mePtr->type == CASCADE_ENTRY) {
- if ((mePtr->childMenuRefPtr != NULL)
- && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
- MenuHandle childMenuHdl = ((MacMenu *) mePtr
- ->childMenuRefPtr->menuPtr->platformData)->menuHdl;
- if (childMenuHdl != NULL) {
- int error = SetMenuCascade(mePtr->childMenuRefPtr->menuPtr);
- if (error != TCL_OK) {
- return error;
- }
- if (menuPtr->menuType == MENUBAR) {
- CFStringRef cfStr = CFStringCreateWithCString(NULL,
- (!(mePtr->labelPtr) ? "" :
- Tcl_GetString(mePtr->labelPtr)),
- kCFStringEncodingUTF8);
- if (cfStr) {
- SetMenuTitleWithCFString(childMenuHdl, cfStr);
- CFRelease(cfStr);
- }
- }
- }
- }
- }
- /*
- * We need to parse the accelerator string. If it has the strings
- * for Command, Control, Shift or Option, we need to flag it
- * so we can draw the symbols for it. We also need to precalcuate
- * the position of the first real character we are drawing.
- */
- if (0 == mePtr->accelLength) {
- geometryPtr->accelTextStart = -1;
- } else {
- const char *accelString = (mePtr->accelPtr == NULL) ? ""
- : Tcl_GetString(mePtr->accelPtr);
- const char *accelStart = accelString;
- mePtr->entryFlags &= ~ENTRY_ACCEL_MASK;
- mePtr->entryFlags |= ParseAccelerators(&accelString,
- &geometryPtr->modifierNum, geometryPtr->modifierUniChars,
- &geometryPtr->modifierWidth);
- geometryPtr->accelTextStart = (ptrdiff_t)(accelString - accelStart);
- }
- if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
- menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
- }
- return TCL_OK;
- }
- /*
- *----------------------------------------------------------------------
- *
- * ReconfigureIndividualMenu --
- *
- * This routine redoes the guts of the menu. It works from
- * a base item and offset, so that a regular menu will
- * just have all of its items added, but the help menu will
- * have all of its items appended after the apple-defined
- * items.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The Macintosh menu handle is updated
- *
- *----------------------------------------------------------------------
- */
- void
- ReconfigureIndividualMenu(
- TkMenu *menuPtr, /* The menu we are affecting. */
- MenuHandle macMenuHdl, /* The macintosh menu we are affecting.
- * Will not necessarily be
- * menuPtr->platformData because this could
- * be the help menu. */
- int base) /* The last index that we do not want
- * touched. 0 for normal menus;
- * # of system help menu items
- * for help menus. */
- {
- int count;
- int index;
- TkMenuEntry *mePtr;
- int parentDisabled = 0;
- #ifdef TK_MAC_DEBUG_MENUS
- /*
- * Carbon-internal menu debugging (c.f. Technote 2124)
- */
- TkMacOSXInitNamedDebugSymbol(HIToolbox, void, DebugPrintMenu,
- MenuRef menu);
- if (DebugPrintMenu) {
- DebugPrintMenu(macMenuHdl);
- }
- #endif
- mePtr = GetParentMenuEntry(menuPtr);
- if (mePtr && mePtr->state == ENTRY_DISABLED) {
- parentDisabled = 1;
- }
- /*
- * First, we get rid of all of the old items.
- */
- count = CountMenuItems(macMenuHdl);
- for (index = base; index < count; index++) {
- DeleteMenuItem(macMenuHdl, base + 1);
- }
- count = menuPtr->numEntries;
- for (index = 1; index <= count; index++) {
- mePtr = menuPtr->entries[index - 1];
- /*
- * We have to do separators separately because SetMenuItemText
- * does not parse meta-characters.
- */
- if (mePtr->type == SEPARATOR_ENTRY) {
- AppendMenuItemTextWithCFString(macMenuHdl, NULL,
- kMenuItemAttrSeparator | kMenuItemAttrDisabled, 0, NULL);
- } else {
- Tcl_DString itemTextDString;
- CFStringRef cfStr;
- GetEntryText(mePtr, &itemTextDString);
- cfStr = CFStringCreateWithCString(NULL,
- Tcl_DStringValue(&itemTextDString), kCFStringEncodingUTF8);
- if (cfStr) {
- AppendMenuItemTextWithCFString(macMenuHdl, cfStr, 0, 0, NULL);
- CFRelease(cfStr);
- } else {
- AppendMenuItemTextWithCFString(macMenuHdl, CFSTR ("<Error>"),
- 0, 0, NULL);
- }
- Tcl_DStringFree(&itemTextDString);
- /*
- * Set enabling and disabling correctly.
- */
- if (parentDisabled || (mePtr->state == ENTRY_DISABLED)) {
- DisableMenuItem(macMenuHdl, base + index);
- } else {
- EnableMenuItem(macMenuHdl, base + index);
- }
- /*
- * Set the check mark for check entries and radio entries.
- */
- SetItemMark(macMenuHdl, base + index, 0);
- if ((mePtr->type == CHECK_BUTTON_ENTRY)
- || (mePtr->type == RADIO_BUTTON_ENTRY)) {
- CheckMenuItem(macMenuHdl, base + index, (mePtr->entryFlags
- & ENTRY_SELECTED) && mePtr->indicatorOn);
- if (mePtr->indicatorOn
- && (mePtr->entryFlags & ENTRY_SELECTED)) {
- SetItemMark(macMenuHdl, base + index,
- FindMarkCharacter(mePtr));
- }
- }
- if (mePtr->type == CASCADE_ENTRY) {
- if ((mePtr->childMenuRefPtr != NULL)
- && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
- MenuHandle childMenuHdl =
- ((MacMenu *) mePtr->childMenuRefPtr
- ->menuPtr->platformData)->menuHdl;
- if (childMenuHdl != NULL) {
- ChkErr(SetMenuItemHierarchicalID, macMenuHdl,
- base + index, GetMenuID(childMenuHdl));
- }
- /*
- * If we changed the highligthing of this menu, its
- * children all have to be reconfigured so that
- * their state will be reflected in the menubar.
- */
- if (!(mePtr->childMenuRefPtr->menuPtr->menuFlags
- & MENU_RECONFIGURE_PENDING)) {
- mePtr->childMenuRefPtr->menuPtr->menuFlags
- |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
- (ClientData) mePtr->childMenuRefPtr->menuPtr);
- }
- }
- }
- if ((mePtr->type != CASCADE_ENTRY) && (mePtr->accelPtr != NULL)) {
- int accelLen, modifiers = 0, hasCmd = 0;
- EntryGeometry *geometryPtr =
- (EntryGeometry*)mePtr->platformEntryData;
- int offset = geometryPtr->accelTextStart;
- char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, &accelLen);
- accelLen -= offset;
- accel += offset;
- if (mePtr->entryFlags & ENTRY_OPTION_ACCEL) {
- modifiers |= kMenuOptionModifier;
- }
- if (mePtr->entryFlags & ENTRY_SHIFT_ACCEL) {
- modifiers |= kMenuShiftModifier;
- }
- if (mePtr->entryFlags & ENTRY_CONTROL_ACCEL) {
- modifiers |= kMenuControlModifier;
- }
- if (mePtr->entryFlags & ENTRY_COMMAND_ACCEL) {
- hasCmd = 1;
- }
- if (accelLen == 1) {
- if (hasCmd || (modifiers != 0 && modifiers !=
- kMenuShiftModifier)) {
- SetItemCmd(macMenuHdl, base + index, accel[0]);
- if (!hasCmd) {
- modifiers |= kMenuNoCommandModifier;
- }
- }
- } else {
- /*
- * Convert from accelerator names to Carbon menu glyphs.
- */
- struct Glyph {
- const char *name;
- const size_t len;
- const char glyph;
- };
- #define GLYPH(n, g) { #n, sizeof(#n)-1, kMenu##g##Glyph }
- static const struct Glyph glyphs[] = {
- GLYPH(PageUp, PageUp),
- GLYPH(PageDown, PageDown),
- GLYPH(Left, LeftArrow),
- GLYPH(Right, RightArrow),
- GLYPH(Up, UpArrow),
- GLYPH(Down, DownArrow),
- GLYPH(Escape, Escape),
- GLYPH(Clear, Clear),
- GLYPH(Enter, Enter),
- GLYPH(Backspace,DeleteLeft),
- GLYPH(Space, Space),
- GLYPH(Tab, TabRight),
- GLYPH(Delete, DeleteRight),
- GLYPH(Home, NorthwestArrow),
- GLYPH(End, SoutheastArrow),
- GLYPH(Return, Return),
- GLYPH(Help, Help),
- GLYPH(Power, Power),
- { NULL, 0, 0}
- };
- #undef GLYPH
- const struct Glyph *g = glyphs;
- char glyph = 0;
- if (accel[0] == 'F' && accelLen < 4 &&
- (accel[1] > '0' && accel[1] <= '9')) {
- int fkey = accel[1] - '0';
- if (accelLen == 3) {
- if (accel[2] >= '0' && accel[2] <= '9') {
- fkey = 10 * fkey + (accel[2] - '0');
- } else {
- fkey = 0;
- }
- }
- if (fkey >= 1 && fkey <= 12) {
- glyph = kMenuF1Glyph + fkey - 1;
- } else if (fkey >= 13 && fkey <= 15) {
- glyph = kMenuF13Glyph + fkey - 13;
- }
- } else while (g->name) {
- if (accel[0] == g->name[0] &&
- (size_t)accelLen == g->len &&
- !strncasecmp(accel, g->name, g->len)) {
- glyph = g->glyph;
- break;
- }
- g++;
- }
- if (glyph) {
- ChkErr(SetMenuItemKeyGlyph, macMenuHdl, base + index,
- glyph);
- if (!hasCmd) {
- modifiers |= kMenuNoCommandModifier;
- }
- geometryPtr->accelGlyph = glyph;
- }
- }
- ChkErr(SetMenuItemModifiers, macMenuHdl, base + index,
- modifiers);
- }
- }
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * ReconfigureMacintoshMenu --
- *
- * Rebuilds the Macintosh MenuHandle items from the menu. Called
- * usually as an idle handler, but can be called synchronously
- * if the menu is about to be posted.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Configuration information get set for mePtr; old resources
- * get freed, if any need it.
- *
- *----------------------------------------------------------------------
- */
- void
- ReconfigureMacintoshMenu(
- ClientData clientData) /* Information about menu entry; may
- * or may not already have values for
- * some fields. */
- {
- TkMenu *menuPtr = (TkMenu *) clientData;
- MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
- MenuHandle helpMenuHdl = NULL;
- menuPtr->menuFlags &= ~MENU_RECONFIGURE_PENDING;
- if (NULL == macMenuHdl) {
- return;
- }
- ReconfigureIndividualMenu(menuPtr, macMenuHdl, 0);
- if (GetMenuID(macMenuHdl) == currentHelpMenuID) {
- MenuItemIndex helpIndex;
- HMGetHelpMenu(&helpMenuHdl,&helpIndex);
- if (helpMenuHdl != NULL) {
- ReconfigureIndividualMenu(menuPtr, helpMenuHdl, helpIndex - 1);
- }
- }
- if (menuPtr->menuType == MENUBAR) {
- if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DrawMenuBarWhenIdle, NULL);
- menuBarFlags |= MENUBAR_REDRAW_PENDING;
- }
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * CompleteIdlers --
- *
- * Completes all idle handling so that the menus are in sync when
- * the user invokes them with the mouse.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The Macintosh menu handles are flushed out.
- *
- *----------------------------------------------------------------------
- */
- void
- CompleteIdlers(
- TkMenu *menuPtr) /* The menu we are completing. */
- {
- int i;
- if (menuPtr->menuFlags & MENU_RECONFIGURE_PENDING) {
- Tcl_CancelIdleCall(ReconfigureMacintoshMenu, (ClientData) menuPtr);
- ReconfigureMacintoshMenu((ClientData) menuPtr);
- }
- for (i = 0; i < menuPtr->numEntries; i++) {
- if ((menuPtr->entries[i]->type == CASCADE_ENTRY) &&
- (menuPtr->entries[i]->childMenuRefPtr != NULL) &&
- (menuPtr->entries[i]->childMenuRefPtr->menuPtr != NULL)) {
- CompleteIdlers(menuPtr->entries[i]->childMenuRefPtr->menuPtr);
- }
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpPostMenu --
- *
- * Posts a menu on the screen
- *
- * Results:
- * None.
- *
- * Side effects:
- * The menu is posted and handled.
- *
- *----------------------------------------------------------------------
- */
- int
- TkpPostMenu(
- Tcl_Interp *interp, /* The interpreter this menu lives in */
- TkMenu *menuPtr, /* The menu we are posting */
- int x, /* The global x-coordinate of the top, left-
- * hand corner of where the menu is supposed
- * to be posted. */
- int y) /* The global y-coordinate */
- {
- MenuHandle macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl;
- long popUpResult;
- int result;
- if (inPostMenu > 0) {
- Tcl_AppendResult(interp,
- "Cannot call post menu while already posting menu", NULL);
- result = TCL_ERROR;
- } else {
- short menuID;
- Window window;
- int oldWidth = menuPtr->totalWidth;
- inPostMenu++;
- result = TkPreprocessMenu(menuPtr);
- /*
- * The post commands could have deleted the menu, which means
- * we are dead and should go away.
- */
- if (result != TCL_OK || !menuPtr->tkwin) {
- goto endPostMenu;
- }
- CompleteIdlers(menuPtr);
- if (menuBarFlags & MENUBAR_REDRAW_PENDING) {
- Tcl_CancelIdleCall(DrawMenuBarWhenIdle, NULL);
- DrawMenuBarWhenIdle(NULL);
- }
- RecursivelyInsertMenu(menuPtr);
- TkMacOSXTrackingLoop(1);
- popUpResult = PopUpMenuSelect(macMenuHdl, y, x, menuPtr->active);
- TkMacOSXTrackingLoop(0);
- menuPtr->totalWidth = oldWidth;
- /*
- * Simulate the mouse up.
- */
- window = Tk_WindowId(menuPtr->tkwin);
- TkGenerateButtonEventForXPointer(window);
- /*
- * Dispatch the command.
- */
- menuID = HiWord(popUpResult);
- if (menuID != 0) {
- result = TkMacOSXDispatchMenuEvent(menuID, LoWord(popUpResult));
- }
- endPostMenu:
- inPostMenu--;
- }
- return result;
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpMenuNewEntry --
- *
- * Adds a pointer to a new menu entry structure with the platform-
- * specific fields filled in. The Macintosh uses the
- * platformEntryData field of the TkMenuEntry record to store
- * geometry information.
- *
- * Results:
- * Standard TCL error.
- *
- * Side effects:
- * Storage gets allocated. New menu entry data is put into the
- * platformEntryData field of the mePtr.
- *
- *----------------------------------------------------------------------
- */
- int
- TkpMenuNewEntry(
- TkMenuEntry *mePtr) /* The menu we are adding an entry to */
- {
- EntryGeometry *geometryPtr =
- (EntryGeometry *) ckalloc(sizeof(EntryGeometry));
- TkMenu *menuPtr = mePtr->menuPtr;
- geometryPtr->accelTextStart = 0;
- geometryPtr->accelTextWidth = 0;
- geometryPtr->nonAccelMargin = 0;
- geometryPtr->modifierWidth = 0;
- geometryPtr->modifierNum = 0;
- geometryPtr->accelGlyph = 0;
- mePtr->platformEntryData = (TkMenuPlatformEntryData) geometryPtr;
- if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) {
- menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr);
- }
- return TCL_OK;
- }
- /*
- *----------------------------------------------------------------------
- *
- * Tk_MacOSXTurnOffMenus --
- *
- * Turns off all the menu drawing code. This is more than just disabling
- * the "menu" command, this means that Tk will NEVER touch the menubar.
- * It is needed in the Plugin, where Tk does not own the menubar.
- *
- * Results:
- * None.
- *
- * Side effects:
- * A flag is set which will disable all menu drawing.
- *
- *----------------------------------------------------------------------
- */
- void
- Tk_MacOSXTurnOffMenus(void)
- {
- gNoTkMenus = 1;
- }
- /*
- *----------------------------------------------------------------------
- *
- * DrawMenuBarWhenIdle --
- *
- * Update the menu bar next time there is an idle event.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Menu bar is redrawn.
- *
- *----------------------------------------------------------------------
- */
- void
- DrawMenuBarWhenIdle(
- ClientData clientData) /* ignored here */
- {
- TkMenuReferences *menuRefPtr;
- TkMenu *appleMenuPtr, *helpMenuPtr, *menuBarPtr = NULL;
- MenuHandle macMenuHdl;
- Tcl_HashEntry *hashEntryPtr;
- /*
- * If we have been turned off, exit.
- */
- if (gNoTkMenus) {
- return;
- }
- /*
- * We need to clear the apple and help menus of any extra items.
- */
- if (currentAppleMenuID != 0) {
- hashEntryPtr = Tcl_FindHashEntry(&commandTable,
- (char*)(intptr_t)currentAppleMenuID);
- appleMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
- TkpDestroyMenu(appleMenuPtr);
- TkpNewMenu(appleMenuPtr);
- appleMenuPtr->menuFlags &= ~MENU_APPLE_MENU;
- appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) appleMenuPtr);
- }
- if (currentHelpMenuID != 0) {
- hashEntryPtr = Tcl_FindHashEntry(&commandTable,
- (char*)(intptr_t)currentHelpMenuID);
- helpMenuPtr = (TkMenu *) Tcl_GetHashValue(hashEntryPtr);
- TkpDestroyMenu(helpMenuPtr);
- TkpNewMenu(helpMenuPtr);
- helpMenuPtr->menuFlags &= ~MENU_HELP_MENU;
- helpMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
- (ClientData) helpMenuPtr);
- }
- /*
- * We need to find the clone of this menu that is the menubar.
- * Once we do that, for every cascade in the menu, we need to
- * insert the Mac menu in the Mac menubar. Finally, we need
- * to redraw the menubar.
- */
- menuRefPtr = NULL;
- if (currentMenuBarName != NULL) {
- menuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
- currentMenuBarName);
- }
- if (menuRefPtr) {
- TkMenu *menuPtr;
- TkMenu *cascadeMenuPtr;
- char *appleMenuName, *helpMenuName;
- int appleIndex = -1, helpIndex = -1, i;
- menuPtr = menuRefPtr->menuPtr;
- if (menuPtr != NULL) {
- TkMenuReferences *specialMenuRefPtr;
- TkMenuEntry *specialEntryPtr;
- appleMenuName = ckalloc(strlen(currentMenuBarName) + 1 +
- strlen(".apple") + 1);
- sprintf(appleMenuName, "%s.apple", Tk_PathName(menuPtr->tkwin));
- specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
- appleMenuName);
- if ((specialMenuRefPtr != NULL)
- && (specialMenuRefPtr->menuPtr != NULL)) {
- for (specialEntryPtr = specialMenuRefPtr->parentEntryPtr;
- specialEntryPtr != NULL;
- specialEntryPtr = specialEntryPtr->nextCascadePtr) {
- if (specialEntryPtr->menuPtr == menuPtr) {
- appleIndex = specialEntryPtr->index;
- break;
- }
- }
- }
- ckfree(appleMenuName);
- helpMenuName = ckalloc(strlen(currentMenuBarName) + 1 +
- strlen(".help") + 1);
- sprintf(helpMenuName, "%s.help", Tk_PathName(menuPtr->tkwin));
- specialMenuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
- helpMenuName);
- if ((specialMenuRefPtr != NULL)
- && (specialMenuRefPtr->menuPtr != NULL)) {
- for (specialEntryPtr = specialMenuRefPtr->parentEntryPtr;
- specialEntryPtr != NULL;
- specialEntryPtr = specialEntryPtr->nextCascadePtr) {
- if (specialEntryPtr->menuPtr == menuPtr) {
- helpIndex = specialEntryPtr->index;
- break;
- }
- }
- }
- ckfree(helpMenuName);
- }
- for (menuBarPtr = menuPtr;
- (menuBarPtr != NULL) && (menuBarPtr->menuType != MENUBAR);
- menuBarPtr = menuBarPtr->nextInstancePtr) {
- /*
- * Null loop body.
- */
- }
- if (menuBarPtr) {
- if (menuBarPtr->tearoff != menuPtr->tearoff) {
- if (menuBarPtr->tearoff) {
- appleIndex = (-1 == appleIndex) ? appleIndex
- : appleIndex + 1;
- helpIndex = (-1 == helpIndex) ? helpIndex
- : helpIndex + 1;
- } else {
- appleIndex = (-1 == appleIndex) ? appleIndex
- : appleIndex - 1;
- helpIndex = (-1 == helpIndex) ? helpIndex
- : helpIndex - 1;
- }
- }
- ClearMenuBar();
- if (appleIndex == -1) {
- InsertMenu(tkAppleMenu, 0);
- currentAppleMenuID = 0;
- tkCurrentAppleMenu = tkAppleMenu;
- } else {
- short appleID;
- appleMenuPtr = menuBarPtr->entries[appleIndex]
- ->childMenuRefPtr->menuPtr;
- TkpDestroyMenu(appleMenuPtr);
- TkMacOSXGetNewMenuID(appleMenuPtr->interp, appleMenuPtr, 0,
- &appleID);
- macMenuHdl = NewMenu(appleID, "p 24");
- appleMenuPtr->platformData =
- (TkMenuPlatformData) ckalloc(sizeof(MacMenu));
- ((MacMenu *)appleMenuPtr->platformData)->menuHdl
- = macMenuHdl;
- appleMenuPtr->menuFlags |= MENU_APPLE_MENU;
- if (!(appleMenuPtr->menuFlags
- & MENU_RECONFIGURE_PENDING)) {
- appleMenuPtr->menuFlags |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
- (ClientData) appleMenuPtr);
- }
- InsertMenu(macMenuHdl, 0);
- RecursivelyInsertMenu(appleMenuPtr);
- currentAppleMenuID = appleID;
- tkCurrentAppleMenu = macMenuHdl;
- }
- if (helpIndex == -1) {
- currentHelpMenuID = 0;
- }
- for (i = 0; i < menuBarPtr->numEntries; i++) {
- if (i == appleIndex) {
- if (menuBarPtr->entries[i]->state == ENTRY_DISABLED) {
- DisableMenuItem(((MacMenu *) menuBarPtr->entries[i]
- ->childMenuRefPtr->menuPtr
- ->platformData)->menuHdl, 0);
- } else {
- EnableMenuItem(((MacMenu *) menuBarPtr->entries[i]
- ->childMenuRefPtr->menuPtr
- ->platformData)->menuHdl, 0);
- }
- continue;
- } else if (i == helpIndex) {
- TkMenu *helpMenuPtr = menuBarPtr->entries[i]
- ->childMenuRefPtr->menuPtr;
- if (helpMenuPtr == NULL) {
- continue;
- }
- helpMenuPtr->menuFlags |= MENU_HELP_MENU;
- if (!(helpMenuPtr->menuFlags
- & MENU_RECONFIGURE_PENDING)) {
- helpMenuPtr->menuFlags
- |= MENU_RECONFIGURE_PENDING;
- Tcl_DoWhenIdle(ReconfigureMacintoshMenu,
- (ClientData) helpMenuPtr);
- }
- macMenuHdl =
- ((MacMenu *) helpMenuPtr->platformData)->menuHdl;
- currentHelpMenuID = GetMenuID(macMenuHdl);
- } else if (menuBarPtr->entries[i]->type
- == CASCADE_ENTRY) {
- if ((menuBarPtr->entries[i]->childMenuRefPtr != NULL)
- && menuBarPtr->entries[i]->childMenuRefPtr
- ->menuPtr != NULL) {
- cascadeMenuPtr = menuBarPtr->entries[i]
- ->childMenuRefPtr->menuPtr;
- macMenuHdl = ((MacMenu *) cascadeMenuPtr
- ->platformData)->menuHdl;
- DeleteMenu(GetMenuID(macMenuHdl));
- InsertMenu(macMenuHdl, 0);
- RecursivelyInsertMenu(cascadeMenuPtr);
- if (menuBarPtr->entries[i]->state == ENTRY_DISABLED) {
- DisableMenuItem(((MacMenu *) menuBarPtr->entries[i]
- ->childMenuRefPtr->menuPtr
- ->platformData)->menuHdl, 0);
- } else {
- EnableMenuItem(((MacMenu *) menuBarPtr->entries[i]
- ->childMenuRefPtr->menuPtr
- ->platformData)->menuHdl, 0);
- }
- }
- }
- }
- }
- }
- if (!menuRefPtr || !menuBarPtr) {
- SetDefaultMenubar();
- }
- DrawMenuBar();
- menuBarFlags &= ~MENUBAR_REDRAW_PENDING;
- }
- /*
- *----------------------------------------------------------------------
- *
- * RecursivelyInsertMenu --
- *
- * Puts all of the cascades of this menu in the Mac hierarchical list.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The menubar is changed.
- *
- *----------------------------------------------------------------------
- */
- void
- RecursivelyInsertMenu(
- TkMenu *menuPtr) /* All of the cascade items in this menu
- * will be inserted into the mac menubar. */
- {
- int i;
- TkMenu *cascadeMenuPtr;
- MenuHandle macMenuHdl;
- for (i = 0; i < menuPtr->numEntries; i++) {
- if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
- if ((menuPtr->entries[i]->childMenuRefPtr != NULL) &&
- (menuPtr->entries[i]->childMenuRefPtr->menuPtr != NULL)) {
- cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr;
- macMenuHdl =
- ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl;
- InsertMenu(macMenuHdl, -1);
- RecursivelyInsertMenu(cascadeMenuPtr);
- }
- }
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * RecursivelyDeleteMenu --
- *
- * Takes all of the cascades of this menu out of the Mac hierarchical
- * list.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The menubar is changed.
- *
- *----------------------------------------------------------------------
- */
- void
- RecursivelyDeleteMenu(
- TkMenu *menuPtr) /* All of the cascade items in this menu
- * will be deleted from the mac menubar. */
- {
- int i;
- TkMenu *cascadeMenuPtr;
- MenuHandle macMenuHdl;
- for (i = 0; i < menuPtr->numEntries; i++) {
- if (menuPtr->entries[i]->type == CASCADE_ENTRY) {
- if ((menuPtr->entries[i]->childMenuRefPtr != NULL) &&
- (menuPtr->entries[i]->childMenuRefPtr->menuPtr != NULL)) {
- cascadeMenuPtr = menuPtr->entries[i]->childMenuRefPtr->menuPtr;
- macMenuHdl =
- ((MacMenu *) cascadeMenuPtr->platformData)->menuHdl;
- DeleteMenu(GetMenuID(macMenuHdl));
- RecursivelyDeleteMenu(cascadeMenuPtr);
- }
- }
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * SetDefaultMenubar --
- *
- * Puts the Apple, File and Edit menus into the Macintosh menubar.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The menubar is changed.
- *
- *----------------------------------------------------------------------
- */
- void
- SetDefaultMenubar(void)
- {
- if (currentMenuBarName != NULL) {
- ckfree(currentMenuBarName);
- currentMenuBarName = NULL;
- }
- currentMenuBarOwner = NULL;
- ClearMenuBar();
- InsertMenu(tkAppleMenu, 0);
- InsertMenu(tkFileMenu, 0);
- InsertMenu(tkEditMenu, 0);
- if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DrawMenuBarWhenIdle, NULL);
- menuBarFlags |= MENUBAR_REDRAW_PENDING;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpSetMainMenubar --
- *
- * Puts the menu associated with a window into the menubar. Should
- * only be called when the window is in front.
- *
- * Results:
- * None.
- *
- * Side effects:
- * The menubar is changed.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpSetMainMenubar(
- Tcl_Interp *interp, /* The interpreter of the application */
- Tk_Window tkwin, /* The frame we are setting up */
- char *menuName) /* The name of the menu to put in front.
- * If NULL, use the default menu bar.
- */
- {
- TkWindow *winPtr = (TkWindow *) tkwin;
- WindowRef macWindowPtr;
- WindowRef frontNonFloating;
- macWindowPtr = TkMacOSXDrawableWindow(winPtr->window);
- frontNonFloating = ActiveNonFloatingWindow();
- if ((macWindowPtr == NULL) || (macWindowPtr != frontNonFloating)) {
- return;
- }
- if ((currentMenuBarInterp != interp) || (currentMenuBarOwner != tkwin)
- || (currentMenuBarName == NULL) || (menuName == NULL)
- || (strcmp(menuName, currentMenuBarName) != 0)) {
- Tk_Window searchWindow;
- TopLevelMenubarList *listPtr;
- if (currentMenuBarName != NULL) {
- ckfree(currentMenuBarName);
- }
- if (menuName == NULL) {
- searchWindow = tkwin;
- if (strcmp(Tk_Class(searchWindow), "Menu") == 0) {
- TkMenuReferences *menuRefPtr;
- menuRefPtr = TkFindMenuReferences(interp, Tk_PathName(tkwin));
- if (menuRefPtr != NULL) {
- TkMenu *menuPtr = menuRefPtr->menuPtr;
- if (menuPtr != NULL) {
- searchWindow = menuPtr->masterMenuPtr->tkwin;
- }
- }
- }
- for (; searchWindow != NULL;
- searchWindow = Tk_Parent(searchWindow)) {
- for (listPtr = windowListPtr; listPtr != NULL;
- listPtr = listPtr->nextPtr) {
- if (listPtr->tkwin == searchWindow) {
- break;
- }
- }
- if (listPtr != NULL) {
- menuName = Tk_PathName(
- listPtr->menuPtr->masterMenuPtr->tkwin);
- break;
- }
- }
- }
- if (menuName == NULL) {
- currentMenuBarName = NULL;
- } else {
- currentMenuBarName = ckalloc(strlen(menuName) + 1);
- strcpy(currentMenuBarName, menuName);
- }
- currentMenuBarOwner = tkwin;
- currentMenuBarInterp = interp;
- }
- if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) {
- Tcl_DoWhenIdle(DrawMenuBarWhenIdle, NULL);
- menuBarFlags |= MENUBAR_REDRAW_PENDING;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkpSetWindowMenuBar --
- *
- * Associates a given menu with a window.
- *
- * Results:
- * None.
- *
- * Side effects:
- * On Windows and UNIX, associates the platform menu with the
- * platform window.
- *
- *----------------------------------------------------------------------
- */
- void
- TkpSetWindowMenuBar(
- Tk_Window tkwin, /* The window we are setting the menu in */
- TkMenu *menuPtr) /* The menu we are setting */
- {
- TopLevelMenubarList *listPtr, *prevPtr;
- /*
- * Remove any existing reference to this window.
- */
- for (prevPtr = NULL, listPtr = windowListPtr;
- listPtr != NULL;
- prevPtr = listPtr, listPtr = listPtr->nextPtr) {
- if (listPtr->tkwin == tkwin) {
- break;
- }
- }
- if (listPtr != NULL) {
- if (prevPtr != NULL) {
- prevPtr->nextPtr = listPtr->nextPtr;
- } else {
- windowListPtr = listPtr->nextPtr;
- }
- ckfree((char *) listPtr);
- }
- if (menuPtr != NULL) {
- listPtr = (TopLevelMenubarList *) ckalloc(sizeof(TopLevelMenubarList));
- listPtr->nextPtr = windowListPtr;
- windowListPtr = listPtr;
- listPtr->tkwin = tkwin;
- listPtr->menuPtr = menuPtr;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * EventuallyInvokeMenu --
- *
- * This IdleTime callback actually invokes the menu command
- * scheduled in TkMacOSXDispatchMenuEvent.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Commands get executed.
- *
- *----------------------------------------------------------------------
- */
- void
- EventuallyInvokeMenu (
- ClientData data)
- {
- struct MenuCommandHandlerData *realData =
- (struct MenuCommandHandlerData *) data;
- int code;
- code = TkInvokeMenu(realData->menuPtr->interp, realData->menuPtr,
- realData->index);
- if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) {
- Tcl_AddErrorInfo(realData->menuPtr->interp, "n (menu invoke)");
- Tcl_BackgroundError(realData->menuPtr->interp);
- }
- if (realData->menuPtr->tkwin) {
- RecursivelyClearActiveMenu(realData->menuPtr);
- }
- TkMacOSXClearMenubarActive();
- Tcl_Release(realData->menuPtr->interp);
- Tcl_Release(realData->menuPtr);
- }
- /*
- *----------------------------------------------------------------------
- *
- * TkMacOSXDispatchMenuEvent --
- *
- * Given a menu id and an item, dispatches the command associated
- * with it.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Commands for the event are scheduled for execution at idle time.
- *
- *----------------------------------------------------------------------
- */
- int
- TkMacOSXDispatchMenuEvent(
- int menuID, /* The menu id of the menu we are invoking */
- int index) /* The one-based index of the item that was
- * selected. */
- {
- int result = TCL_OK;
- if (menuID != 0) {
- if (menuID == kHMHelpMenuID) {
- if (currentMenuBarOwner != NULL) {
- TkMenuReferences *helpMenuRef;
- char *helpMenuName = ckalloc(strlen(currentMenuBarName)
- + strlen(".help") + 1);
- sprintf(helpMenuName, "%s.help", currentMenuBarName);
- helpMenuRef = TkFindMenuReferences(currentMenuBarInterp,
- helpMenuName);
- ckfree(helpMenuName);
- if ((helpMenuRef != NULL) && (helpMenuRef->menuPtr != NULL)) {
- MenuRef outHelpMenu;
- MenuItemIndex itemIndex;
- int newIndex;
- HMGetHelpMenu(&outHelpMenu, &itemIndex);
- newIndex = index - itemIndex;
- result = TkInvokeMenu(currentMenuBarInterp,
- helpMenuRef->menuPtr, newIndex);
- }
- }
- } else {
- Tcl_HashEntry *commandEntryPtr =
- Tcl_FindHashEntry(&commandTable, (char*)(intptr_t)menuID);
- if (commandEntryPtr != NULL) {
- TkMenu *menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
- if ((currentAppleMenuID == menuID)
- && (index > menuPtr->numEntries + 1)) {
- /*
- * We don't need to do anything here, the standard
- * Application event handler will open the built-in
- * Apple menu item for us.
- */
- result = TCL_OK;
- } else {
- struct MenuCommandHandlerData *data
- = (struct MenuCommandHandlerData *)
- ckalloc(sizeof(struct MenuCommandHandlerData));
- Tcl_Preserve(menuPtr->interp);
- Tcl_Preserve(menuPtr);
- data->menuPtr = menuPtr;
- data->index = index - 1;
- Tcl_DoWhenIdle(EventuallyInvokeMenu,
- (ClientData) data);
- /* result = TkInvokeMenu(menuPtr->interp, menuPtr, index - 1); */
- }
- } else {
- return TCL_ERROR;
- }
- }
- }
- return result;
- }
- /*
- *----------------------------------------------------------------------
- *
- * GetMenuIndicatorGeometry --
- *
- * Gets the width and height of the indicator area of a menu.
- *
- * Results:
- * widthPtr and heightPtr are set.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- void
- GetMenuIndicatorGeometry (
- TkMenu *menuPtr, /* The menu we are drawing */
- TkMenuEntry *mePtr, /* The entry we are measuring */
- Tk_Font tkfont, /* Precalculated font */
- const Tk_FontMetrics *fmPtr,/* Precalculated font metrics */
- int *widthPtr, /* The resulting width */
- int *heightPtr) /* The resulting height */
- {
- *heightPtr = fmPtr->linespace + menuItemExtraHeight;
- if (IS_THEME_MENU_FONT(tkfont)) {
- *widthPtr = menuMarkColumnWidth;
- } else {
- const char markChar = FindMarkCharacter(mePtr);
- const char *markUtf = NULL;
- int len;
- len = GetUtfMarkCharacter(markChar, &markUtf);
- *widthPtr = Tk_TextWidth(tkfont, markUtf, len) + 2*menuMarkIndent;
- }
- }
- /*
- *----------------------------------------------------------------------
- *
- * GetMenuAccelGeometry --
- *
- * Gets the width and height of the accelerator area of a menu.
- *
- * Results:
- * widthPtr and heightPtr are set.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
- void
- GetMenuAccelGeometry (
- TkMenu *menuPtr, /* The menu we are measuring */
- TkMenuEntry *mePtr, /* The entry we are measuring */
- Tk_Font tkfont, /* The precalculated font */
- const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */
- int *modWidthPtr, /* The width of all of the key
- * modifier symbols. */
- int *textWidthPtr, /* The resulting width */
- int *heightPtr) /* The resulting height */
- {
- *heightPtr = fmPtr->linespace + menuItemExtraHeight;
- *modWidthPtr = menuSymbols[COMMAND_SYMBOL].width;
- *textWidthPtr = 0;
- if (mePtr->type != CASCADE_ENTRY && mePtr->accelLength > 0) {
- const char *accel = (mePtr->accelPtr == NULL) ? ""
- : Tcl_GetString(mePtr->accelPtr);
- EntryGeometry *geometryPtr = (EntryGeometry*)mePtr->platformEntryData;
- if (IS_THEME_MENU_FONT(tkfont)) {
- CFStringRef cfStr;
- int width = 0;
- int maxWidth = ((TkFont *)tkfont)->fm.maxWidth;
- if (geometryPtr->accelGlyph) {
- cfStr = CFStringCreateWithBytes(NULL,
- (UInt8*)&geometryPtr->accelGlyph, 1,
- kTextEncodingMacKeyboardGlyphs, false);
- if (cfStr) {
- width = MeasureThemeText(cfStr, kThemeMenuItemCmdKeyFont);
- CFRelease(cfStr);
- }
- }
- if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) {
- if (!geometryPtr->accelGlyph) {
- width = Tk_TextWidth(tkfont, accel, mePtr->accelLength);
- }
- *textWidthPtr = maxWidth;
- if (width < maxWidth) {
- *modWidthPtr = 0;
- } else {
- *modWidthPtr = width - maxWidth;
- }