diff options
Diffstat (limited to 'macosx/tkMacOSXMenu.c')
-rw-r--r-- | macosx/tkMacOSXMenu.c | 4886 |
1 files changed, 944 insertions, 3942 deletions
diff --git a/macosx/tkMacOSXMenu.c b/macosx/tkMacOSXMenu.c index 386fe50..6877819 100644 --- a/macosx/tkMacOSXMenu.c +++ b/macosx/tkMacOSXMenu.c @@ -4,8 +4,8 @@ * 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> + * Copyright 2001-2009, Apple Inc. + * Copyright (c) 2005-2009 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. @@ -16,6 +16,7 @@ #include "tkMenu.h" #include "tkColor.h" #include "tkFont.h" +#include "tkMacOSXWm.h" #include "tkMacOSXDebug.h" /* @@ -24,1564 +25,488 @@ #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. */ +#define ENTRY_HELP_MENU ENTRY_PLATFORM_FLAG1 +#define ENTRY_APPLE_MENU ENTRY_PLATFORM_FLAG2 +#define ENTRY_WINDOWS_MENU ENTRY_PLATFORM_FLAG3 + +#define sl(s) ((int) (sizeof(s "") - 1)) + +#define SPECIALMENU(n, f) {.name = "." #n, .len = sl(#n) + 1, \ + .flag = ENTRY_##f##_MENU } +static const struct { + const char *name; const size_t len; const int flag; +} specialMenus[] = { + SPECIALMENU(help, HELP), + SPECIALMENU(apple, APPLE), + SPECIALMENU(window, WINDOWS), + {NULL} }; - -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}, +#undef SPECIALMENU + +#define MODIFIER(n, f) {.name = #n, .len = sl(#n), .mask = f } +static const struct { + const char *name; const size_t len; const NSUInteger mask; +} modifiers[] = { + MODIFIER(Control, NSControlKeyMask), + MODIFIER(Ctrl, NSControlKeyMask), + MODIFIER(Option, NSAlternateKeyMask), + MODIFIER(Opt, NSAlternateKeyMask), + MODIFIER(Alt, NSAlternateKeyMask), + MODIFIER(Shift, NSShiftKeyMask), + MODIFIER(Command, NSCommandKeyMask), + MODIFIER(Cmd, NSCommandKeyMask), + MODIFIER(Meta, NSCommandKeyMask), + {NULL} }; - -enum MenuSymbolIdx { - COMMAND_SYMBOL, - OPTION_SYMBOL, - CONTROL_SYMBOL, - SHIFT_SYMBOL, - CHECK_SYMBOL, - DIAMDOND_SYMBOL, - BULLET_SYMBOL, - ELLIPSIS_SYMBOL, +#undef MODIFIER + +#define ACCEL(n, c) {.name = #n, .len = sl(#n), .ch = c } +static const struct { + const char *name; const size_t len; const UniChar ch; +} specialAccelerators[] = { + ACCEL(PageUp, NSPageUpFunctionKey), + ACCEL(PageDown, NSPageDownFunctionKey), + ACCEL(Left, NSLeftArrowFunctionKey), + ACCEL(Right, NSRightArrowFunctionKey), + ACCEL(Up, NSUpArrowFunctionKey), + ACCEL(Down, NSDownArrowFunctionKey), + ACCEL(Escape, 0x001b), + ACCEL(Clear, NSClearDisplayFunctionKey), + ACCEL(Enter, NSEnterCharacter), + ACCEL(Backspace, NSBackspaceCharacter), + ACCEL(Space, ' '), + ACCEL(Tab, NSTabCharacter), + ACCEL(BackTab, NSBackTabCharacter), + ACCEL(Delete, NSDeleteCharacter), + ACCEL(Home, NSHomeFunctionKey), + ACCEL(End, NSEndFunctionKey), + ACCEL(Return, NSCarriageReturnCharacter), + ACCEL(Help, NSHelpFunctionKey), + ACCEL(Power, 0x233d), + ACCEL(Eject, 0xf804), + {NULL} }; +#undef ACCEL +#undef sl -MenuRef tkCurrentAppleMenu = NULL; - -static SInt32 menuMarkColumnWidth = 0, menuMarkIndent = 0; +static int gNoTkMenus = 0; /* This is used by Tk_MacOSXTurnOffMenus as + * the flag that Tk is not to draw any + * menus. */ +static int inPostMenu = 0; +static unsigned long defaultBg = 0, defaultFg = 0; +static SInt32 menuMarkColumnWidth = 0, menuIconTrailingEdgeMargin = 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 CheckForSpecialMenu(TkMenu *menuPtr); +static NSString *ParseAccelerator(const char *accel, NSUInteger *maskPtr); +static int GenerateMenuSelectEvent(TKMenu *menu, NSMenuItem *menuItem); +static void MenuSelectEvent(TkMenu *menuPtr); +static void RecursivelyClearActiveMenu(TkMenu *menuPtr); +static int ModifierCharWidth(Tk_Font tkfont); + +#pragma mark TKMenu + +@interface TKMenu(TKMenuPrivate) +- (id) initWithTkMenu: (TkMenu *) tkMenu; +- (TkMenu *) tkMenu; +- (int) tkIndexOfItem: (NSMenuItem *) menuItem; +- (void) insertItem: (NSMenuItem *) newItem atTkIndex: (NSInteger) index; +@end + +#if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 +#define TKMenu_NSMenuDelegate <NSMenuDelegate> +#else +#define TKMenu_NSMenuDelegate +#endif +@interface TKMenu(TKMenuDelegate) TKMenu_NSMenuDelegate +@end -static void -DrawThemeText( - Drawable d, - GC gc, - CFStringRef string, - ThemeFontID font, - ThemeDrawState drawState, - const Rect* bounds, - int baseline, - int just) +@implementation TKMenu +- (void) setSpecial: (NSUInteger) special { - 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); - } + NSAssert(!_tkSpecial, @"Cannot change specialness of a special menu"); + _tkSpecial = special; } - -/* - *---------------------------------------------------------------------- - * - * MeasureThemeText -- - * - * Wrapper for GetThemeTextDimensions API. - * - * Results: - * None. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -static int -MeasureThemeText( - CFStringRef string, - ThemeFontID font) +- (BOOL) isSpecial: (NSUInteger) special { - Point pt; - - ChkErr(GetThemeTextDimensions, string, font, kThemeStateActive, false, &pt, - NULL); - return pt.h; + return (_tkSpecial == special); } - -/* - *---------------------------------------------------------------------- - * - * 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. - * - *---------------------------------------------------------------------- - */ +@end -int -TkMacOSXUseMenuID( - short macID) /* The id to take out of the table */ +@implementation TKMenu(TKMenuPrivate) + +- (id) initWithTitle: (NSString *) aTitle { - 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; + self = [super initWithTitle:aTitle]; + if (self) { + _tkMenu = NULL; + _tkOffset = 0; + _tkItemCount = 0; + _tkSpecial = 0; + [self setDelegate:self]; } - Tcl_SetHashValue(commandEntryPtr, NULL); - return TCL_OK; + return self; } - -/* - *---------------------------------------------------------------------- - * - * 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 */ +- (id) initWithTkMenu: (TkMenu *) tkMenu { - 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; + NSString *title = [[NSString alloc] initWithUTF8String: + Tk_PathName(tkMenu->tkwin)]; - 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; + self = [self initWithTitle:title]; + [title release]; + if (self) { + _tkMenu = tkMenu; } - Tcl_SetHashValue(commandEntryPtr, (char *) menuPtr); - *menuIDPtr = returnID; - return TCL_OK; + return self; } - -/* - *---------------------------------------------------------------------- - * - * 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 */ +- (id) copyWithZone: (NSZone *) zone { - Tcl_HashEntry *entryPtr = Tcl_FindHashEntry(&commandTable, - (char*)(intptr_t)menuID); + TKMenu *copy = [super copyWithZone:zone]; - if (entryPtr != NULL) { - Tcl_DeleteHashEntry(entryPtr); - } - if (menuID == currentAppleMenuID) { - currentAppleMenuID = 0; - } - if (menuID == currentHelpMenuID) { - currentHelpMenuID = 0; - } + NSAssert(_tkMenu == nil, @"Cannot copy tkMenu"); + copy->_tkMenu = _tkMenu; + copy->_tkOffset = _tkOffset; + copy->_tkItemCount = _tkItemCount; + copy->_tkSpecial = _tkSpecial; + return copy; } - -/* - *---------------------------------------------------------------------- - * - * 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 *) tkMenu { - 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; + return _tkMenu; } - -/* - *---------------------------------------------------------------------- - * - * 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) +- (int) tkIndexOfItem: (NSMenuItem *) menuItem { - TkMenuEntry *cascadeEntryPtr; + return [self indexOfItem:menuItem] - _tkOffset; +} - for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; - cascadeEntryPtr != NULL; - cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { - const char *name = (cascadeEntryPtr->namePtr == NULL) ? "" - : Tcl_GetString(cascadeEntryPtr->namePtr); +- (void) insertItem: (NSMenuItem *) newItem atTkIndex: (NSInteger) index +{ + [super insertItem:newItem atIndex:index + _tkOffset]; + _tkItemCount++; +} - if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) { - break; +- (void) insertItem: (NSMenuItem *) newItem atIndex: (NSInteger) index +{ + if (_tkMenu && index >= 0) { + if ((NSUInteger)index <= _tkOffset) { + _tkOffset++; + } else { + NSAssert((NSUInteger)index >= _tkItemCount + _tkOffset, + @"Cannot insert in the middle of Tk menu"); } } - return cascadeEntryPtr; + [super insertItem:newItem atIndex:index]; } - -/* - *---------------------------------------------------------------------- - * - * 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. */ +- (void) removeItemAtIndex: (NSInteger) index { - 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; + if (_tkMenu && index >= 0) { + if ((NSUInteger)index < _tkOffset) { + _tkOffset--; + } else if ((NSUInteger)index < _tkItemCount + _tkOffset) { + _tkItemCount--; + } } + [super removeItemAtIndex:index]; +} - menuPtr->platformData = (TkMenuPlatformData) ckalloc(sizeof(MacMenu)); - ((MacMenu *) menuPtr->platformData)->menuHdl = macMenuHdl; +- (NSMenuItem *) newTkMenuItem: (TkMenuEntry *) mePtr +{ + NSMenuItem *menuItem = [[NSMenuItem alloc] initWithTitle:@"" + action:@selector(tkMenuItemInvoke:) keyEquivalent:@""]; -#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. - */ + [menuItem setTarget:self]; + [menuItem setTag:(NSInteger)mePtr]; + return menuItem; +} +@end - 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; - } - } - } - } +@implementation TKMenu(TKMenuActions) +// target methods - menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; - Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); - return TCL_OK; +- (BOOL) validateMenuItem: (NSMenuItem *) menuItem +{ + return [menuItem isEnabled]; } - -/* - *---------------------------------------------------------------------- - * - * 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 */ +- (void) tkMenuItemInvoke: (id) sender { - MenuRef macMenuHdl = ((MacMenu *) menuPtr->platformData)->menuHdl; + /* + * With the delegate matching key equivalents, when a menu action is sent + * in response to a key equivalent, sender is the whole menu and not the + * the specific menu item, use this to ignore key equivalents for our + * menus (as Tk handles them directly via bindings). + */ - 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 ([sender isKindOfClass:[NSMenuItem class]]) { + NSMenuItem *menuItem = (NSMenuItem *)sender; + TkMenu *menuPtr = (TkMenu *)_tkMenu; + TkMenuEntry *mePtr = (TkMenuEntry *)[menuItem tag]; + + if (menuPtr && mePtr) { + Tcl_Interp *interp = menuPtr->interp; + + Tcl_Preserve(interp); + Tcl_Preserve(menuPtr); - if ((HMGetHelpMenu(&helpMenuHdl,&helpIndex) == noErr) - && (helpMenuHdl != NULL)) { - int i, count = CountMenuItems(helpMenuHdl); + int result = TkInvokeMenu(interp, menuPtr, mePtr->index); - for (i = helpIndex; i <= count; i++) { - DeleteMenuItem(helpMenuHdl, helpIndex); + if (result != TCL_OK && result != TCL_CONTINUE && + result != TCL_BREAK) { + Tcl_AddErrorInfo(interp, "\n (menu invoke)"); + Tcl_BackgroundException(interp, result); } + Tcl_Release(menuPtr); + Tcl_Release(interp); } - 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. - * - *---------------------------------------------------------------------- - */ +@end -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. - * - *---------------------------------------------------------------------- - */ +@implementation TKMenu(TKMenuDelegate) +#define keyEquivModifiersMatch(km, m) (( \ + ((km) & NSCommandKeyMask) != ((m) & NSCommandKeyMask) || \ + ((km) & NSAlternateKeyMask) != ((m) & NSAlternateKeyMask) || \ + ((km) & NSControlKeyMask) != ((m) & NSControlKeyMask) || \ + (((km) & NSShiftKeyMask) != ((m) & NSShiftKeyMask) && \ + ((m) & NSFunctionKeyMask))) ? NO : YES) -void -TkpDestroyMenuEntry( - TkMenuEntry *mePtr) /* The common structure for the menu entry. */ +- (BOOL) menuHasKeyEquivalent: (NSMenu *) menu forEvent: (NSEvent *) event + target: (id *) target action: (SEL *) action { - TkMenu *menuPtr = mePtr->menuPtr; + NSString *key = [event charactersIgnoringModifiers]; + NSUInteger modifiers = [event modifierFlags] & + NSDeviceIndependentModifierFlagsMask; - ckfree((char *) mePtr->platformEntryData); - if ((menuPtr->platformData != NULL) - && !(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { - menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; - Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); + if (modifiers == (NSCommandKeyMask | NSShiftKeyMask) && + [key compare:@"?"] == NSOrderedSame) { + return NO; } -} - -/* - *---------------------------------------------------------------------- - * - * 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; + NSArray *itemArray = [self itemArray]; + + for (NSMenuItem *item in itemArray) { + if ([item isEnabled] && [[item keyEquivalent] compare:key] == + NSOrderedSame) { + NSUInteger keyEquivModifiers = [item keyEquivalentModifierMask]; + + if (keyEquivModifiersMatch(keyEquivModifiers, modifiers)) { + *target = [item target]; + *action = [item action]; + return YES; } } } + return NO; } - -/* - *---------------------------------------------------------------------- - * - * 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. */ +- (void) menuWillOpen: (NSMenu *) menu { - 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++; + if (_tkMenu) { + //RecursivelyClearActiveMenu(_tkMenu); + GenerateMenuSelectEvent((TKMenu *)[self supermenu], + [self itemInSupermenu]); } - 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) +- (void) menuDidClose: (NSMenu *) menu { - 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 (_tkMenu) { + RecursivelyClearActiveMenu(_tkMenu); } - 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) +- (void) menu: (NSMenu *) menu willHighlightItem: (NSMenuItem *) item { - 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++; + if (_tkMenu) { + GenerateMenuSelectEvent(self, item); } - *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. */ +- (void) menuNeedsUpdate: (NSMenu *) menu { - 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; + TkMenu *menuPtr = (TkMenu *) _tkMenu; - if (childMenuHdl != NULL) { - int error = SetMenuCascade(mePtr->childMenuRefPtr->menuPtr); + if (menuPtr) { + Tcl_Interp *interp = menuPtr->interp; - if (error != TCL_OK) { - return error; - } + Tcl_Preserve(interp); + Tcl_Preserve(menuPtr); - if (menuPtr->menuType == MENUBAR) { - CFStringRef cfStr = CFStringCreateWithCString(NULL, - (!(mePtr->labelPtr) ? "" : - Tcl_GetString(mePtr->labelPtr)), - kCFStringEncodingUTF8); + int result = TkPostCommand(_tkMenu); - if (cfStr) { - SetMenuTitleWithCFString(childMenuHdl, cfStr); - CFRelease(cfStr); - } - } - } + if (result!=TCL_OK && result!=TCL_CONTINUE && result!=TCL_BREAK) { + Tcl_AddErrorInfo(interp, "\n (menu preprocess)"); + Tcl_BackgroundException(interp, result); } + Tcl_Release(menuPtr); + Tcl_Release(interp); } +} +@end - /* - * 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. - */ +#pragma mark TKApplication(TKMenu) - 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); - } +@interface NSApplication(TKMenu) +- (void) setAppleMenu: (NSMenu *) menu; +@end - if (!(menuPtr->menuFlags & MENU_RECONFIGURE_PENDING)) { - menuPtr->menuFlags |= MENU_RECONFIGURE_PENDING; - Tcl_DoWhenIdle(ReconfigureMacintoshMenu, (ClientData) menuPtr); - } +@implementation TKApplication(TKMenu) - return TCL_OK; +- (void) menuBeginTracking: (NSNotification *) notification +{ +#ifdef TK_MAC_DEBUG_NOTIFICATIONS + TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); +#endif + //TkMacOSXClearMenubarActive(); + //TkMacOSXPreprocessMenu(); } - -/* - *---------------------------------------------------------------------- - * - * 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. */ +- (void) menuEndTracking: (NSNotification *) notification { - 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); - } +#ifdef TK_MAC_DEBUG_NOTIFICATIONS + TKLog(@"-[%@(%p) %s] %@", [self class], self, _cmd, notification); #endif - - mePtr = GetParentMenuEntry(menuPtr); - if (mePtr && mePtr->state == ENTRY_DISABLED) { - parentDisabled = 1; + if (!inPostMenu) { + TkMacOSXClearMenubarActive(); } +} - /* - * First, we get rid of all of the old items. - */ - - count = CountMenuItems(macMenuHdl); - for (index = base; index < count; index++) { - DeleteMenuItem(macMenuHdl, base + 1); +- (void) tkSetMainMenu: (TKMenu *) menu +{ + if (gNoTkMenus) { + return; } - count = menuPtr->numEntries; + TKMenu *applicationMenu = nil; - for (index = 1; index <= count; index++) { - mePtr = menuPtr->entries[index - 1]; + if (menu) { + NSMenuItem *applicationMenuItem = [menu numberOfItems] ? + [menu itemAtIndex:0] : nil; - /* - * We have to do separators separately because SetMenuItemText - * does not parse meta-characters. - */ + if (![menu isSpecial:tkMainMenu]) { + TkMenuEntry *mePtr = (TkMenuEntry *)[applicationMenuItem tag]; - 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); + if (!mePtr || !(mePtr->entryFlags & ENTRY_APPLE_MENU)) { + applicationMenuItem = [NSMenuItem itemWithSubmenu: + [[_defaultApplicationMenu copy] autorelease]]; + [menu insertItem:applicationMenuItem atIndex:0]; } - Tcl_DStringFree(&itemTextDString); - - /* - * Set enabling and disabling correctly. - */ - - if (parentDisabled || (mePtr->state == ENTRY_DISABLED)) { - DisableMenuItem(macMenuHdl, base + index); - } else { - EnableMenuItem(macMenuHdl, base + index); + [menu setSpecial:tkMainMenu]; + } + applicationMenu = (TKMenu *)[applicationMenuItem submenu]; + if (![applicationMenu isSpecial:tkApplicationMenu]) { + for (NSMenuItem *item in _defaultApplicationMenuItems) { + [applicationMenu addItem:[[item copy] autorelease]]; } + [applicationMenu setSpecial:tkApplicationMenu]; + } - /* - * Set the check mark for check entries and radio entries. - */ + NSArray *itemArray = [menu itemArray]; - 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)); - } - } + for (NSMenuItem *item in itemArray) { + TkMenuEntry *mePtr = (TkMenuEntry *)[item tag]; + TKMenu *submenu = (TKMenu *)[item submenu]; - 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 && submenu) { + if ((mePtr->entryFlags & ENTRY_WINDOWS_MENU) && + ![submenu isSpecial:tkWindowsMenu]) { + NSInteger index = 0; - 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; - } + for (NSMenuItem *i in _defaultWindowsMenuItems) { + [submenu insertItem:[[i copy] autorelease] atIndex: + index++]; } - } 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; + [self setWindowsMenu:submenu]; + [submenu setSpecial:tkWindowsMenu]; + } else if ((mePtr->entryFlags & ENTRY_HELP_MENU) && + ![submenu isSpecial:tkHelpMenu]) { + NSInteger index = 0; + + for (NSMenuItem *i in _defaultHelpMenuItems) { + [submenu insertItem:[[i copy] autorelease] atIndex: + index++]; } + [submenu setSpecial:tkHelpMenu]; } - ChkErr(SetMenuItemModifiers, macMenuHdl, base + index, - modifiers); } } + } else { + menu = _defaultMainMenu; + applicationMenu = _defaultApplicationMenu; } -} - -/* - *---------------------------------------------------------------------- - * - * 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); - } - } + NSMenuItem *servicesMenuItem = + [applicationMenu itemWithTitle:@"Services"]; - if (menuPtr->menuType == MENUBAR) { - if (!(menuBarFlags & MENUBAR_REDRAW_PENDING)) { - Tcl_DoWhenIdle(DrawMenuBarWhenIdle, NULL); - menuBarFlags |= MENUBAR_REDRAW_PENDING; - } + if (servicesMenuItem && [servicesMenuItem submenu] != _servicesMenu) { + [[_servicesMenu itemInSupermenu] setSubmenu:nil]; + [servicesMenuItem setSubmenu:_servicesMenu]; } + [self setAppleMenu:applicationMenu]; + [self setMainMenu:menu]; } +@end + +#pragma mark - /* *---------------------------------------------------------------------- * - * CompleteIdlers -- + * TkpNewMenu -- * - * Completes all idle handling so that the menus are in sync when - * the user invokes them with the mouse. + * Gets a new blank menu. Only the platform specific options are filled + * in. * * Results: - * None. + * Returns a standard Tcl error. * * Side effects: - * The Macintosh menu handles are flushed out. + * Allocates a NSMenu and puts it into the platformData field of the + * menuPtr. * *---------------------------------------------------------------------- */ -void -CompleteIdlers( - TkMenu *menuPtr) /* The menu we are completing. */ +int +TkpNewMenu( + TkMenu *menuPtr) /* The common structure we are making the + * platform structure for. */ { - 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); - } - } + TKMenu *menu = [[TKMenu alloc] initWithTkMenu:menuPtr]; + menuPtr->platformData = (TkMenuPlatformData) + TkMacOSXMakeUncollectable(menu); + CheckForSpecialMenu(menuPtr); + return TCL_OK; } /* *---------------------------------------------------------------------- * - * TkpPostMenu -- + * TkpDestroyMenu -- * - * Posts a menu on the screen + * Destroys platform-specific menu structures. * * Results: * None. * * Side effects: - * The menu is posted and handled. + * All platform-specific allocations are freed up. * *---------------------------------------------------------------------- */ -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 */ +void +TkpDestroyMenu( + TkMenu *menuPtr) /* The common menu structure */ { - 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; + TkMacOSXMakeCollectableAndRelease(menuPtr->platformData); } /* @@ -1590,9 +515,8 @@ endPostMenu: * 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. + * specific fields filled in. The Macintosh uses the platformEntryData + * field of the TkMenuEntry record. * * Results: * Standard TCL error. @@ -1608,490 +532,233 @@ 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); + TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData; + NSMenuItem *menuItem; + if (mePtr->type == SEPARATOR_ENTRY || mePtr->type == TEAROFF_ENTRY) { + menuItem = [[NSMenuItem separatorItem] retain]; + } else { + menuItem = [menu newTkMenuItem:mePtr]; } + mePtr->platformEntryData = (TkMenuPlatformEntryData) + TkMacOSXMakeUncollectable(menuItem); /* - * 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. + * Caller TkMenuEntry() already did this same insertion into the generic + * TkMenu so we just match it for the platform menu. */ - 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\024"); - 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; + [menu insertItem:menuItem atTkIndex:mePtr->index]; + return TCL_OK; } /* *---------------------------------------------------------------------- * - * RecursivelyInsertMenu -- + * TkpConfigureMenuEntry -- * - * Puts all of the cascades of this menu in the Mac hierarchical list. + * Processes configurations for menu entries. * * Results: - * None. + * Returns standard TCL result. If TCL_ERROR is returned, then the + * interp's result contains an error message. * * Side effects: - * The menubar is changed. + * Configuration information get set for mePtr; old resources get freed, + * if any need it. * *---------------------------------------------------------------------- */ -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; +int +TkpConfigureMenuEntry( + TkMenuEntry *mePtr) /* Information about menu entry; may or may + * not already have values for some fields. */ +{ + NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; + NSString *title = @""; + NSAttributedString *attributedTitle = nil; + NSImage *image = nil; + NSString *keyEquivalent = @""; + NSUInteger modifierMask = NSCommandKeyMask; + NSMenu *submenu = nil; + NSDictionary *attributes; + int imageWidth, imageHeight; + GC gc = (mePtr->textGC ? mePtr->textGC : mePtr->menuPtr->textGC); + Tcl_Obj *fontPtr = (mePtr->fontPtr ? mePtr->fontPtr : + mePtr->menuPtr->fontPtr); + + if (mePtr->image) { + Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight); + image = TkMacOSXGetNSImageWithTkImage(mePtr->menuPtr->display, + mePtr->image, imageWidth, imageHeight); + } else if (mePtr->bitmapPtr != None) { + Pixmap bitmap = Tk_GetBitmapFromObj(mePtr->menuPtr->tkwin, + mePtr->bitmapPtr); + + Tk_SizeOfBitmap(mePtr->menuPtr->display, bitmap, &imageWidth, + &imageHeight); + image = TkMacOSXGetNSImageWithBitmap(mePtr->menuPtr->display, bitmap, + gc, imageWidth, imageHeight); + } + [menuItem setImage:image]; + if ((!image || mePtr->compound != COMPOUND_NONE) && mePtr->labelPtr && + mePtr->labelLength) { + title = [[[NSString alloc] initWithBytes:Tcl_GetString(mePtr->labelPtr) + length:mePtr->labelLength encoding:NSUTF8StringEncoding] + autorelease]; + if ([title hasSuffix:@"..."]) { + title = [NSString stringWithFormat:@"%@%C", + [title substringToIndex:[title length] - 3], 0x2026]; + } + } + [menuItem setTitle:title]; + if (strcmp(Tcl_GetString(fontPtr), "menu") || gc->foreground != defaultFg + || gc->background != defaultBg) { + attributes = TkMacOSXNSFontAttributesForFont(Tk_GetFontFromObj( + mePtr->menuPtr->tkwin, fontPtr)); + if (gc->foreground != defaultFg || gc->background != defaultBg) { + NSColor *color = TkMacOSXGetNSColor(gc, + gc->foreground!=defaultFg? gc->foreground:gc->background); + + attributes = [[attributes mutableCopy] autorelease]; + [(NSMutableDictionary *)attributes setObject:color + forKey:NSForegroundColorAttributeName]; + } + if (attributes) { + attributedTitle = [[[NSAttributedString alloc] + initWithString:title attributes:attributes] autorelease]; + } + } + [menuItem setAttributedTitle:attributedTitle]; + [menuItem setEnabled:!(mePtr->state == ENTRY_DISABLED)]; + [menuItem setState:((mePtr->type == CHECK_BUTTON_ENTRY || + mePtr->type == RADIO_BUTTON_ENTRY) && mePtr->indicatorOn && + (mePtr->entryFlags & ENTRY_SELECTED) ? NSOnState : NSOffState)]; + if (mePtr->type != CASCADE_ENTRY && mePtr->accelPtr && mePtr->accelLength) { + keyEquivalent = ParseAccelerator(Tcl_GetString(mePtr->accelPtr), + &modifierMask); + } + [menuItem setKeyEquivalent:keyEquivalent]; + [menuItem setKeyEquivalentModifierMask:modifierMask]; + if (mePtr->type == CASCADE_ENTRY && mePtr->namePtr) { + TkMenuReferences *menuRefPtr; + + menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp, + mePtr->namePtr); + if (menuRefPtr && menuRefPtr->menuPtr) { + CheckForSpecialMenu(menuRefPtr->menuPtr); + submenu = (TKMenu *) menuRefPtr->menuPtr->platformData; + if ([submenu supermenu] && [menuItem submenu] != submenu) { + /* + * This happens during a clone, where the parent menu is + * cloned before its children, so just ignore this temprary + * setting, it will be changed shortly (c.f. tkMenu.c + * CloneMenu()) + */ - 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); + submenu = nil; + } else { + [submenu setTitle:title]; } } } -} - -/* - *---------------------------------------------------------------------- - * - * RecursivelyDeleteMenu -- - * - * Takes all of the cascades of this menu out of the Mac hierarchical - * list. - * - * Results: - * None. - * - * Side effects: - * The menubar is changed. - * - *---------------------------------------------------------------------- - */ + [menuItem setSubmenu:submenu]; -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); + /*Disabling parent menu disables entries; we must re-enable the entries here.*/ + NSArray *itemArray = [submenu itemArray]; + + if ([menuItem isEnabled]) { + for (NSMenuItem *item in itemArray) { + [item setEnabled:YES]; } } - } + + return TCL_OK; } /* *---------------------------------------------------------------------- * - * SetDefaultMenubar -- + * TkpDestroyMenuEntry -- * - * Puts the Apple, File and Edit menus into the Macintosh menubar. + * Cleans up platform-specific menu entry items. * * Results: - * None. + * None * * Side effects: - * The menubar is changed. + * All platform-specific allocations are freed up. * *---------------------------------------------------------------------- */ void -SetDefaultMenubar(void) +TkpDestroyMenuEntry( + TkMenuEntry *mePtr) { - 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; + if (mePtr->platformEntryData && mePtr->menuPtr->platformData) { + TKMenu *menu = (TKMenu *) mePtr->menuPtr->platformData; + NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; + NSInteger index = [menu indexOfItem:menuItem]; + + if (index > -1) { + [menu removeItemAtIndex:index]; + } } + TkMacOSXMakeCollectableAndRelease(mePtr->platformEntryData); } /* *---------------------------------------------------------------------- * - * TkpSetMainMenubar -- + * TkpPostMenu -- * - * Puts the menu associated with a window into the menubar. Should - * only be called when the window is in front. + * Posts a menu on the screen * * Results: * None. * * Side effects: - * The menubar is changed. + * The menu is posted and handled. * *---------------------------------------------------------------------- */ -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. - */ +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 */ { - TkWindow *winPtr = (TkWindow *) tkwin; - WindowRef macWindowPtr; - WindowRef frontNonFloating; - - macWindowPtr = TkMacOSXDrawableWindow(winPtr->window); - - frontNonFloating = ActiveNonFloatingWindow(); - if ((macWindowPtr == NULL) || (macWindowPtr != frontNonFloating)) { - return; + NSWindow *win = [NSApp keyWindow]; + if (!win) { + return TCL_ERROR; } - if ((currentMenuBarInterp != interp) || (currentMenuBarOwner != tkwin) - || (currentMenuBarName == NULL) || (menuName == NULL) - || (strcmp(menuName, currentMenuBarName) != 0)) { - Tk_Window searchWindow; - TopLevelMenubarList *listPtr; + inPostMenu = 1; - if (currentMenuBarName != NULL) { - ckfree(currentMenuBarName); - } + int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE); + NSView *view = [win contentView]; + NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1); - if (menuName == NULL) { - searchWindow = tkwin; - if (strcmp(Tk_Class(searchWindow), "Menu") == 0) { - TkMenuReferences *menuRefPtr; + frame.origin = [view convertPoint: + [win convertScreenToBase:frame.origin] fromView:nil]; - menuRefPtr = TkFindMenuReferences(interp, Tk_PathName(tkwin)); - if (menuRefPtr != NULL) { - TkMenu *menuPtr = menuRefPtr->menuPtr; + NSMenu *menu = (NSMenu *) menuPtr->platformData; + NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc] + initTextCell:@"" pullsDown:NO]; - 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; - } + [popUpButtonCell setAltersStateOfSelectedItem:NO]; + [popUpButtonCell setMenu:menu]; + [popUpButtonCell selectItem:nil]; + [popUpButtonCell performClickWithFrame:frame inView:view]; + [popUpButtonCell release]; + Tcl_SetServiceMode(oldMode); + inPostMenu = 0; + return TCL_OK; } /* @@ -2105,8 +772,8 @@ TkpSetMainMenubar( * None. * * Side effects: - * On Windows and UNIX, associates the platform menu with the - * platform window. + * On Windows and UNIX, associates the platform menu with the platform + * window. * *---------------------------------------------------------------------- */ @@ -2116,276 +783,115 @@ 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); - } + TkWindow *winPtr = (TkWindow *) tkwin; - if (menuPtr != NULL) { - listPtr = (TopLevelMenubarList *) ckalloc(sizeof(TopLevelMenubarList)); - listPtr->nextPtr = windowListPtr; - windowListPtr = listPtr; - listPtr->tkwin = tkwin; - listPtr->menuPtr = menuPtr; + if (winPtr->wmInfoPtr) { + winPtr->wmInfoPtr->menuPtr = menuPtr; } } /* *---------------------------------------------------------------------- * - * EventuallyInvokeMenu -- + * TkpSetMainMenubar -- * - * This IdleTime callback actually invokes the menu command - * scheduled in TkMacOSXDispatchMenuEvent. + * Puts the menu associated with a window into the menubar. Should only + * be called when the window is in front. * * Results: * None. * * Side effects: - * Commands get executed. + * The menubar is changed. * *---------------------------------------------------------------------- */ void -EventuallyInvokeMenu ( - ClientData data) +TkpSetMainMenubar( + Tcl_Interp *interp, /* The interpreter of the application */ + Tk_Window tkwin, /* The frame we are setting up */ + const char *menuName) /* The name of the menu to put in front. If + * NULL, use the default menu bar. */ { - struct MenuCommandHandlerData *realData = - (struct MenuCommandHandlerData *) data; - int code; - - code = TkInvokeMenu(realData->menuPtr->interp, realData->menuPtr, - realData->index); + static Tcl_Interp *currentInterp = NULL; + TKMenu *menu = nil; - if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { - Tcl_AddErrorInfo(realData->menuPtr->interp, "\n (menu invoke)"); - Tcl_BackgroundError(realData->menuPtr->interp); - } + if (menuName) { + TkWindow *winPtr = (TkWindow *) tkwin; - 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); - } - } + if (winPtr->wmInfoPtr && winPtr->wmInfoPtr->menuPtr && + winPtr->wmInfoPtr->menuPtr->masterMenuPtr && + winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin && + !strcmp(menuName, Tk_PathName( + winPtr->wmInfoPtr->menuPtr->masterMenuPtr->tkwin))) { + menu = (TKMenu *) winPtr->wmInfoPtr->menuPtr->platformData; } 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; + TkMenuReferences *menuRefPtr = TkFindMenuReferences(interp, + menuName); + + if (menuRefPtr && menuRefPtr->menuPtr && + menuRefPtr->menuPtr->platformData) { + menu = (TKMenu *) menuRefPtr->menuPtr->platformData; } } } - 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; + if (menu || interp != currentInterp) { + [NSApp tkSetMainMenu:menu]; } + currentInterp = interp; } /* *---------------------------------------------------------------------- * - * GetMenuAccelGeometry -- + * CheckForSpecialMenu -- * - * Gets the width and height of the accelerator area of a menu. + * Given a menu, check to see whether or not it is a cascade in a menubar + * with one of the special names .apple, .help or .window If it is, the + * entry that points to this menu will be marked. * * Results: - * widthPtr and heightPtr are set. + * None. * * Side effects: - * None. + * Will set entryFlags appropriately. * *---------------------------------------------------------------------- */ -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 */ +static void +CheckForSpecialMenu( + TkMenu *menuPtr) /* The menu we are checking */ { - *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; - } - } else { - if (!geometryPtr->accelGlyph) { - width = Tk_TextWidth(tkfont, accel + - geometryPtr->accelTextStart, mePtr->accelLength - - geometryPtr->accelTextStart); - } - if (width < maxWidth) { - *textWidthPtr = maxWidth; + if (!menuPtr->masterMenuPtr->tkwin) { + return; + } + for (TkMenuEntry *cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr; + cascadeEntryPtr; + cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) { + if (cascadeEntryPtr->menuPtr->menuType == MENUBAR + && cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin) { + TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr; + int i = 0; + Tcl_DString ds; + + Tcl_DStringInit(&ds); + Tcl_DStringAppend(&ds, Tk_PathName(masterMenuPtr->tkwin), -1); + while (specialMenus[i].name) { + Tcl_DStringAppend(&ds, specialMenus[i].name, + specialMenus[i].len); + if (strcmp(Tcl_DStringValue(&ds), + Tk_PathName(menuPtr->masterMenuPtr->tkwin)) == 0) { + cascadeEntryPtr->entryFlags |= specialMenus[i].flag; } else { - *textWidthPtr = width; - } - if (geometryPtr->modifierNum) { - *modWidthPtr = geometryPtr->modifierWidth; + cascadeEntryPtr->entryFlags &= ~specialMenus[i].flag; } + Tcl_DStringSetLength(&ds, Tcl_DStringLength(&ds) - + specialMenus[i].len); + i++; } - } else { - *textWidthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength); + Tcl_DStringFree(&ds); } } } @@ -2393,48 +899,12 @@ GetMenuAccelGeometry ( /* *---------------------------------------------------------------------- * - * GetTearoffEntryGeometry -- - * - * Gets the width and height of of a tearoff entry. - * - * Results: - * widthPtr and heightPtr are set. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -GetTearoffEntryGeometry ( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are measuring */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ - int *widthPtr, /* The resulting width */ - int *heightPtr) /* The resulting height */ -{ -#ifdef USE_TK_MDEF - const int useMDEF = ((MacMenu *) menuPtr->platformData)->useMDEF; -#endif - if (useMDEF && menuPtr->menuType != TEAROFF_MENU) { - *heightPtr = fmPtr->linespace + menuItemExtraHeight; - *widthPtr = menuPtr->totalWidth; - } else { - *widthPtr = *heightPtr = 0; - } -} - -/* - *---------------------------------------------------------------------- - * - * GetMenuSeparatorGeometry -- + * ParseAccelerator -- * - * Gets the width and height of menu separator. + * Parse accelerator string. * * Results: - * widthPtr and heightPtr are set. + * Accelerator string & flags. * * Side effects: * None. @@ -2442,705 +912,96 @@ GetTearoffEntryGeometry ( *---------------------------------------------------------------------- */ -void -GetMenuSeparatorGeometry( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are measuring */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalcualted font metrics */ - int *widthPtr, /* The resulting width */ - int *heightPtr) /* The resulting height */ +static NSString * +ParseAccelerator( + const char *accel, + NSUInteger *maskPtr) { - *widthPtr = 0; - *heightPtr = menuSeparatorHeight; -} - -/* - *---------------------------------------------------------------------- - * - * DrawMenuEntryIndicator -- - * - * This procedure draws the indicator part of a menu. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -void -DrawMenuEntryIndicator( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* The drawable we are drawing */ - GC gc, /* The GC we are drawing with */ - GC indicatorGC, /* The GC to use for the indicator */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ - int x, /* topleft hand corner of entry */ - int y, /* topleft hand corner of entry */ - int width, /* width of entry */ - int height) /* height of entry */ -{ - if ((mePtr->type == CHECK_BUTTON_ENTRY) || - (mePtr->type == RADIO_BUTTON_ENTRY)) { - if (mePtr->indicatorOn && (mePtr->entryFlags & ENTRY_SELECTED)) { - short mark; - int baseline = y + (height + fmPtr->ascent - fmPtr->descent)/2; - - GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl, - mePtr->index + 1, &mark); - if (IS_THEME_MENU_FONT(tkfont)) { - ThemeFontID font = kThemeMenuItemMarkFont; - TextEncoding encoding = GetApplicationTextEncoding(); - CFStringRef cfStr; - ThemeDrawState drawState; - Rect bounds = {y, x + menuMarkIndent, y + height, x + width}; - - if (mark < kSpaceCharCode) { - font = kThemeMenuItemCmdKeyFont; - encoding = kTextEncodingMacKeyboardGlyphs; - } - switch (mePtr->state) { - case ENTRY_ACTIVE: - drawState = kThemeStatePressed; - break; - case ENTRY_DISABLED: - drawState = kThemeStateInactive; - break; - default: - drawState = kThemeStateActive; - break; - } - cfStr = CFStringCreateWithBytes(NULL, (UInt8*)&mark, 1, - encoding, false); - if (cfStr) { - DrawThemeText(d, gc, cfStr, font, drawState, &bounds, - baseline, teFlushDefault); - CFRelease(cfStr); - } - } else if (mark != 0) { - const char *markUtf = NULL; - int len; + unichar ch = 0; + size_t len; + int i; - len = GetUtfMarkCharacter(mark, &markUtf); - Tk_DrawChars(menuPtr->display, d, gc, tkfont, markUtf, len, - x + menuMarkIndent, baseline); + *maskPtr = 0; + while (1) { + i = 0; + while (modifiers[i].name) { + int l = modifiers[i].len; + + if (!strncasecmp(accel, modifiers[i].name, l) && + (accel[l] == '-' || accel[l] == '+')) { + *maskPtr |= modifiers[i].mask; + accel += l+1; + break; } + i++; + } + if (!modifiers[i].name || !*accel) { + break; } } -} - -#ifdef USE_TK_MDEF -/* - *---------------------------------------------------------------------- - * - * DrawMenuBackground -- - * - * If Appearance is present, draws the Appearance background - * - * Results: - * Nothing - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ -void -DrawMenuBackground( - TkMenu *menuPtr, - Rect *menuRectPtr, /* The menu rect */ - Drawable d) /* What we are drawing into */ -{ - Tk_3DBorder border; - - EraseMenuBackground(((MacMenu *) menuPtr->platformData)->menuHdl, - menuRectPtr, ((MacDrawable*)d)->context); - border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); - Tk_Fill3DRectangle(menuPtr->tkwin, d, border, - menuRectPtr->left, menuRectPtr->top, - menuRectPtr->right - menuRectPtr->left, - menuRectPtr->bottom - menuRectPtr->top, 0, TK_RELIEF_FLAT); -} -#endif /* USE_TK_MDEF */ - -/* - *---------------------------------------------------------------------- - * - * DrawMenuEntryAccelerator -- - * - * This procedure draws the accelerator part of a menu. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ + len = strlen(accel); + if (len > 1) { + i = 0; + if (accel[0] == 'F' && len < 4 && accel[1] > '0' && accel[1] <= '9') { + int fkey = accel[1] - '0'; -void -DrawMenuEntryAccelerator( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* The drawable we are drawing in */ - GC gc, /* The gc to draw into */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ - Tk_3DBorder activeBorder, /* border for menu background */ - int x, /* The left side of the entry */ - int y, /* The top of the entry */ - int width, /* The width of the entry */ - int height, /* The height of the entry */ - int drawArrow) /* Whether or not to draw cascade arrow */ -{ - if (mePtr->type != CASCADE_ENTRY && mePtr->accelLength > 0) { - const char *accel = (mePtr->accelPtr == NULL) ? "" - : Tcl_GetString(mePtr->accelPtr); - EntryGeometry *geometryPtr = (EntryGeometry*)mePtr->platformEntryData; - int leftEdge = x + width - geometryPtr->accelTextWidth; - int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2; - - if (IS_THEME_MENU_FONT(tkfont)) { - CFStringRef cfStr; - ThemeDrawState drawState; - - switch (mePtr->state) { - case ENTRY_ACTIVE: - drawState = kThemeStatePressed; - break; - case ENTRY_DISABLED: - drawState = kThemeStateInactive; - break; - default: - drawState = kThemeStateActive; - break; - } - if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) { - leftEdge -= geometryPtr->modifierWidth; - } - if (geometryPtr->accelGlyph) { - Rect bounds = {y, leftEdge, y + height, leftEdge + - geometryPtr->accelTextWidth}; - - cfStr = CFStringCreateWithBytes(NULL, - (UInt8*)&geometryPtr->accelGlyph, 1, - kTextEncodingMacKeyboardGlyphs, false); - if (cfStr) { - DrawThemeText(d, gc, cfStr, kThemeMenuItemCmdKeyFont, - drawState, &bounds, baseline, teFlushDefault); - CFRelease(cfStr); + if (len == 3) { + if (accel[2] >= '0' && accel[2] <= '9') { + fkey = 10 * fkey + (accel[2] - '0'); + } else { + fkey = 0; } - } else { - Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel + - geometryPtr->accelTextStart, mePtr->accelLength - - geometryPtr->accelTextStart, leftEdge, baseline); } - if (geometryPtr->modifierNum) { - Rect bounds = {y, leftEdge - geometryPtr->modifierWidth, - y + height, leftEdge}; - - cfStr = CFStringCreateWithCharacters(NULL, - geometryPtr->modifierUniChars, - geometryPtr->modifierNum); - if (cfStr) { - DrawThemeText(d, gc, cfStr, kThemeMenuItemCmdKeyFont, - drawState, &bounds, baseline, teFlushDefault); - CFRelease(cfStr); - } + if (fkey >= 1 && fkey <= 15) { + ch = NSF1FunctionKey + fkey - 1; } - } else { - Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel, - mePtr->accelLength, leftEdge, baseline); + } else while (specialAccelerators[i].name) { + if (accel[0] == specialAccelerators[i].name[0] && + len == specialAccelerators[i].len && !strncasecmp(accel, + specialAccelerators[i].name, specialAccelerators[i].len)) { + ch = specialAccelerators[i].ch; + break; + } + i++; } } -} - -/* - *---------------------------------------------------------------------- - * - * DrawMenuSeparator -- - * - * The menu separator is drawn. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -void -DrawMenuSeparator( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* The drawable we are drawing into */ - GC gc, /* The gc we are drawing with */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ - int x, /* left coordinate of entry */ - int y, /* top coordinate of entry */ - int width, /* width of entry */ - int height) /* height of entry */ -{ - TkMacOSXDrawingContext dc; - Rect r; - - r.top = y; - r.left = x; - r.bottom = y + height; - r.right = x + width; - if (TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) { - ChkErr(DrawThemeMenuSeparator, &r); - TkMacOSXRestoreDrawingContext(&dc); - } -} - -#ifdef USE_TK_MDEF -/* - *---------------------------------------------------------------------- - * - * AppearanceEntryDrawWrapper -- - * - * It routes to the Appearance Managers DrawThemeEntry, which will - * then call us back after setting up the drawing context. - * - * Results: - * A menu entry is drawn - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ -void -AppearanceEntryDrawWrapper( - TkMenuEntry *mePtr, - Rect *menuRectPtr, - MenuTrackingData *mtdPtr, - Drawable d, - Tk_FontMetrics *fmPtr, - Tk_Font tkfont, - int erase) -{ - MenuEntryUserData meData; - Rect itemRect; - ThemeMenuState theState; - ThemeMenuItemType theType; - Tk_FontMetrics entryMetrics; - - meData.mePtr = mePtr; - meData.mdefDrawable = d; - if (mePtr->fontPtr == NULL) { - meData.fmPtr = fmPtr; - meData.tkfont = tkfont; - } else { - meData.tkfont = Tk_GetFontFromObj(mePtr->menuPtr->tkwin, - mePtr->fontPtr); - Tk_GetFontMetrics(meData.tkfont, &entryMetrics); - fmPtr = &entryMetrics; - } - itemRect.left = menuRectPtr->left + mePtr->x; - itemRect.top = mtdPtr->virtualMenuTop + mePtr->y; - itemRect.right = mePtr->entryFlags & ENTRY_LAST_COLUMN ? - menuRectPtr->right : itemRect.left + mePtr->width; - itemRect.bottom = itemRect.top + mePtr->height; - - if (mePtr->state == ENTRY_ACTIVE) { - theState = kThemeMenuSelected; - } else if (mePtr->state == ENTRY_DISABLED) { - theState = kThemeMenuDisabled; + if (ch) { + return [[[NSString alloc] initWithCharacters:&ch length:1] autorelease]; } else { - theState = kThemeMenuActive; - } - if (mePtr->type == CASCADE_ENTRY) { - theType = kThemeMenuItemHierarchical; - } else { - theType = kThemeMenuItemPlain; - } - if (erase) { - DisableScreenUpdates(); - DrawMenuBackground(mePtr->menuPtr, &itemRect, d); + return [[[[NSString alloc] initWithUTF8String:accel] autorelease] + lowercaseString]; } - DrawThemeMenuItem(menuRectPtr, &itemRect, - mtdPtr->virtualMenuTop, mtdPtr->virtualMenuBottom, theState, - theType | kThemeMenuItemNoBackground, tkThemeMenuItemDrawingUPP, - (unsigned long) &meData); - if (erase) { - EnableScreenUpdates(); - } -} - -/* - *---------------------------------------------------------------------- - * - * ThemeMenuItemDrawingProc -- - * - * This routine is called from the Appearance DrawThemeMenuEntry - * - * Results: - * A menu entry is drawn - * - * Side effects: - * None - * - *---------------------------------------------------------------------- - */ -pascal void -ThemeMenuItemDrawingProc( - const Rect *inBounds, - SInt16 inDepth, - Boolean inIsColorDevice, - SInt32 inUserData) -{ - MenuEntryUserData *meData = (MenuEntryUserData *) inUserData; - - TkpDrawMenuEntry(meData->mePtr, meData->mdefDrawable, meData->tkfont, - meData->fmPtr, inBounds->left, inBounds->top, inBounds->right - - inBounds->left + menuItemExtraWidth, inBounds->bottom - - inBounds->top + menuItemExtraHeight, 0, 1); -} -#endif /* USE_TK_MDEF */ - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXHandleTearoffMenu() -- - * - * This routine sees if the MDEF has set a menu and a mouse position - * for tearing off and makes a tearoff menu if it has. - * - * Results: - * menuPtr->interp will have the result of the tearoff command. - * - * Side effects: - * A new tearoff menu is created if it is supposed to be. - * - *---------------------------------------------------------------------- - */ - -void -TkMacOSXHandleTearoffMenu(void) -{ - /* - * Obsolete: Nothing to do. - */ } /* *-------------------------------------------------------------- * - * TkpInitializeMenuBindings -- + * ModifierCharWidth -- * - * For every interp, initializes the bindings for Windows - * menus. Does nothing on Mac or XWindows. + * Helper mesuring width of command char in given font. * * Results: - * None. + * Width of command char. * * Side effects: - * C-level bindings are setup for the interp which will - * handle Alt-key sequences for menus without beeping - * or interfering with user-defined Alt-key bindings. - * - *-------------------------------------------------------------- - */ - -void -TkpInitializeMenuBindings( - Tcl_Interp *interp, /* The interpreter to set. */ - Tk_BindingTable bindingTable) - /* The table to add to. */ -{ - /* - * Nothing to do. - */ -} - -/* - *-------------------------------------------------------------- - * - * TkpComputeMenubarGeometry -- - * - * This procedure is invoked to recompute the size and - * layout of a menu that is a menubar clone. - * - * Results: * None. * - * Side effects: - * Fields of menu entries are changed to reflect their - * current positions, and the size of the menu window - * itself may be changed. - * *-------------------------------------------------------------- */ -void -TkpComputeMenubarGeometry( - TkMenu *menuPtr) /* Structure describing menu. */ -{ - TkpComputeStandardMenuGeometry(menuPtr); -} - -/* - *---------------------------------------------------------------------- - * - * DrawTearoffEntry -- - * - * This procedure draws a tearoff entry. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -void -DrawTearoffEntry( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* The drawable we are drawing into */ - GC gc, /* The gc we are drawing with */ - Tk_Font tkfont, /* The font we are drawing with */ - const Tk_FontMetrics *fmPtr,/* The metrics we are drawing with */ - int x, /* Left edge of entry. */ - int y, /* Top edge of entry. */ - int width, /* Width of entry. */ - int height) /* Height of entry. */ -{ - XPoint points[2]; - int margin, segmentWidth, maxX; - Tk_3DBorder border; - - if (menuPtr->menuType != MASTER_MENU ) { - return; - } - - margin = fmPtr->linespace/2; - points[0].x = x; - points[0].y = y + height/2; - points[1].y = points[0].y; - segmentWidth = 6; - maxX = x + menuPtr->totalWidth - 1; - border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr); - - while (points[0].x < maxX) { - points[1].x = points[0].x + segmentWidth; - if (points[1].x > maxX) { - points[1].x = maxX; - } - Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1, - TK_RELIEF_RAISED); - points[0].x += 2*segmentWidth; - } -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXSetHelpMenuItemCount -- - * - * Has to be called after the first call to InsertMenu. Sets - * up the global variable for the number of items in the - * unmodified help menu. - * NB. Nobody uses this any more, since you can get the number - * of system help items from HMGetHelpMenu trivially. - * But it is in the stubs table... - * - * Results: - * None. - * - * Side effects: - * Nothing. - * - *---------------------------------------------------------------------- - */ - -void -TkMacOSXSetHelpMenuItemCount(void) +static int +ModifierCharWidth( + Tk_Font tkfont) { - /* - * Obsolete: Nothing to do. - */ -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXMenuClick -- - * - * Prepares a menubar for MenuSelect or MenuKey. - * - * Results: - * None. - * - * Side effects: - * Any pending configurations of the menubar are completed. - * - *---------------------------------------------------------------------- - */ + static NSString *cmdChar = nil; -void -TkMacOSXMenuClick(void) -{ - TkMenu *menuPtr; - TkMenuReferences *menuRefPtr; - - if ((currentMenuBarInterp != NULL) && (currentMenuBarName != NULL)) { - menuRefPtr = TkFindMenuReferences(currentMenuBarInterp, - currentMenuBarName); - for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr; - menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) { - if (menuPtr->menuType == MENUBAR) { - CompleteIdlers(menuPtr); - break; - } - } - } + if (!cmdChar) { + unichar cmd = kCommandUnicode; - if (menuBarFlags & MENUBAR_REDRAW_PENDING) { - Tcl_CancelIdleCall(DrawMenuBarWhenIdle, NULL); - DrawMenuBarWhenIdle(NULL); - } -} - -/* - *---------------------------------------------------------------------- - * - * TkpDrawMenuEntry -- - * - * Draws the given menu entry at the given coordinates with the - * given attributes. - * - * Results: - * None. - * - * Side effects: - * X Server commands are executed to display the menu entry. - * - *---------------------------------------------------------------------- - */ - -void -TkpDrawMenuEntry( - TkMenuEntry *mePtr, /* The entry to draw */ - Drawable d, /* What to draw into */ - Tk_Font tkfont, /* Precalculated font for menu */ - const Tk_FontMetrics *menuMetricsPtr, - /* Precalculated metrics for menu */ - int x, /* X-coordinate of topleft of entry */ - int y, /* Y-coordinate of topleft of entry */ - int width, /* Width of the entry rectangle */ - int height, /* Height of the current rectangle */ - int strictMotif, /* Boolean flag */ - int drawArrow) /* Whether or not to draw the cascade - * arrow for cascade items. Only applies - * to Windows. */ -{ - GC gc; - TkMenu *menuPtr = mePtr->menuPtr; - int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0; - GC indicatorGC; - Tk_3DBorder bgBorder, activeBorder; - const Tk_FontMetrics *fmPtr; - Tk_FontMetrics entryMetrics; - int adjustedY = y + padY; - int adjustedHeight = height - 2 * padY; - - /* - * Choose the gc for drawing the foreground part of the entry. - * Under Appearance, we pass a null (appearanceGC) to tell - * ourselves not to change whatever color the appearance manager has set. - */ - - if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) { - gc = mePtr->activeGC; - if (gc == NULL) { - gc = menuPtr->activeGC; - } - } else { - TkMenuEntry *parentEntryPtr = GetParentMenuEntry(menuPtr); - - if (((parentEntryPtr && parentEntryPtr->state == ENTRY_DISABLED) || - (mePtr->state == ENTRY_DISABLED)) && - (menuPtr->disabledFgPtr != NULL)) { - gc = mePtr->disabledGC; - if (gc == NULL) { - gc = menuPtr->disabledGC; - } - } else { - gc = mePtr->textGC; - if (gc == NULL) { - gc = menuPtr->textGC; - } - } - } - - indicatorGC = mePtr->indicatorGC; - if (indicatorGC == NULL) { - indicatorGC = menuPtr->indicatorGC; - } - - bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, - (mePtr->borderPtr == NULL) - ? menuPtr->borderPtr : mePtr->borderPtr); - if (strictMotif) { - activeBorder = bgBorder; - } else { - activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin, - (mePtr->activeBorderPtr == NULL) - ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr); - } - - if (mePtr->fontPtr == NULL) { - fmPtr = menuMetricsPtr; - } else { - tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); - Tk_GetFontMetrics(tkfont, &entryMetrics); - fmPtr = &entryMetrics; - } - - /* - * Need to draw the entire background, including padding. On Unix, - * for menubars, we have to draw the rest of the entry taking - * into account the padding. - */ - - DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y, - width, height); - - if (mePtr->type == SEPARATOR_ENTRY) { - DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, - fmPtr, x, adjustedY, width, adjustedHeight); - } else if (mePtr->type == TEAROFF_ENTRY) { - DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY, - width, adjustedHeight); - } else { - DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, - adjustedY, width, adjustedHeight); - DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, - activeBorder, x, adjustedY, width, adjustedHeight, drawArrow); - if (!mePtr->hideMargin) { - DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, - fmPtr, x, adjustedY, width, adjustedHeight); - } + cmdChar = [[NSString alloc] initWithCharacters:&cmd length:1]; } + return [cmdChar sizeWithAttributes: + TkMacOSXNSFontAttributesForFont(tkfont)].width; } /* @@ -3148,16 +1009,15 @@ TkpDrawMenuEntry( * * TkpComputeStandardMenuGeometry -- * - * This procedure is invoked to recompute the size and - * layout of a menu that is not a menubar clone. + * This procedure is invoked to recompute the size and layout of a menu + * that is not a menubar clone. * * Results: * None. * * Side effects: - * Fields of menu entries are changed to reflect their - * current positions, and the size of the menu window - * itself may be changed. + * Fields of menu entries are changed to reflect their current positions, + * and the size of the menu window itself may be changed. * *-------------------------------------------------------------- */ @@ -3168,13 +1028,12 @@ TkpComputeStandardMenuGeometry( { Tk_Font tkfont, menuFont; Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr; - int x, y, height, modifierWidth, labelWidth, indicatorSpace; - int windowWidth, windowHeight, accelWidth, maxAccelTextWidth; - int i, j, lastColumnBreak, maxModifierWidth, maxWidth, nonAccelMargin; - int maxNonAccelMargin, maxEntryWithAccelWidth, maxEntryWithoutAccelWidth; + int modifierCharWidth, menuModifierCharWidth; + int x, y, modifierWidth, labelWidth, indicatorSpace; + int windowWidth, windowHeight, accelWidth; + int i, j, lastColumnBreak, maxWidth; int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth; TkMenuEntry *mePtr, *columnEntryPtr; - EntryGeometry *geometryPtr; int haveAccel = 0; if (menuPtr->tkwin == NULL) { @@ -3186,25 +1045,22 @@ TkpComputeStandardMenuGeometry( Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr, &activeBorderWidth); x = y = borderWidth; - indicatorSpace = labelWidth = accelWidth = maxAccelTextWidth = 0; - windowHeight = windowWidth = maxWidth = lastColumnBreak = 0; - maxModifierWidth = nonAccelMargin = maxNonAccelMargin = 0; - maxEntryWithAccelWidth = maxEntryWithoutAccelWidth = 0; + windowHeight = maxWidth = lastColumnBreak = 0; maxIndicatorSpace = 0; /* - * On the Mac especially, getting font metrics can be quite slow, - * so we want to do it intelligently. We are going to precalculate - * them and pass them down to all of the measuring and drawing - * routines. We will measure the font metrics of the menu once. - * If an entry does not have its own font set, then we give - * the geometry/drawing routines the menu's font and metrics. - * If an entry has its own font, we will measure that font and - * give all of the geometry/drawing the entry's font and metrics. + * On the Mac especially, getting font metrics can be quite slow, so we + * want to do it intelligently. We are going to precalculate them and pass + * them down to all of the measuring and drawing routines. We will measure + * the font metrics of the menu once. If an entry does not have its own + * font set, then we give the geometry/drawing routines the menu's font + * and metrics. If an entry has its own font, we will measure that font + * and give all of the geometry/drawing the entry's font and metrics. */ menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); Tk_GetFontMetrics(menuFont, &menuMetrics); + menuModifierCharWidth = ModifierCharWidth(menuFont); for (i = 0; i < menuPtr->numEntries; i++) { mePtr = menuPtr->entries[i]; @@ -3219,10 +1075,12 @@ TkpComputeStandardMenuGeometry( if (mePtr->fontPtr == NULL) { tkfont = menuFont; fmPtr = &menuMetrics; + modifierCharWidth = menuModifierCharWidth; } else { tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr); Tk_GetFontMetrics(tkfont, &entryMetrics); fmPtr = &entryMetrics; + modifierCharWidth = ModifierCharWidth(tkfont); } if ((i > 0) && mePtr->columnBreak) { @@ -3231,120 +1089,106 @@ TkpComputeStandardMenuGeometry( } for (j = lastColumnBreak; j < i; j++) { columnEntryPtr = menuPtr->entries[j]; - geometryPtr = - (EntryGeometry *) columnEntryPtr->platformEntryData; - columnEntryPtr->indicatorSpace = maxIndicatorSpace; columnEntryPtr->width = maxIndicatorSpace + maxWidth + 2 * activeBorderWidth; - geometryPtr->accelTextWidth = maxAccelTextWidth; - geometryPtr->modifierWidth = maxModifierWidth; columnEntryPtr->x = x; columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN; - if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) { - geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth - - maxEntryWithAccelWidth; - if (geometryPtr->nonAccelMargin > maxNonAccelMargin) { - geometryPtr->nonAccelMargin = maxNonAccelMargin; - } - } else { - geometryPtr->nonAccelMargin = 0; - } } x += maxIndicatorSpace + maxWidth + 2 * borderWidth; - windowWidth = x; - maxWidth = maxIndicatorSpace = maxAccelTextWidth = 0; - maxModifierWidth = maxNonAccelMargin = maxEntryWithAccelWidth = 0; - maxEntryWithoutAccelWidth = 0; + maxWidth = maxIndicatorSpace = 0; lastColumnBreak = i; y = borderWidth; } - geometryPtr = (EntryGeometry *) mePtr->platformEntryData; - - if (mePtr->type == SEPARATOR_ENTRY) { - GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont, - fmPtr, &entryWidth, &height); - mePtr->height = height; - } else if (mePtr->type == TEAROFF_ENTRY) { - GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, - fmPtr, &entryWidth, &height); - mePtr->height = height; + accelWidth = modifierWidth = indicatorSpace = 0; + if (mePtr->type == SEPARATOR_ENTRY || mePtr->type == TEAROFF_ENTRY) { + mePtr->height = menuSeparatorHeight; } else { /* - * For each entry, compute the height required by that - * particular entry, plus three widths: the width of the - * label, the width to allow for an indicator to be displayed - * to the left of the label (if any), and the width of the - * accelerator to be displayed to the right of the label - * (if any). These sizes depend, of course, on the type - * of the entry. + * For each entry, compute the height required by that particular + * entry, plus three widths: the width of the label, the width to + * allow for an indicator to be displayed to the left of the label + * (if any), and the width of the accelerator to be displayed to + * the right of the label (if any). These sizes depend, of course, + * on the type of the entry. */ - GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &labelWidth, &height); - mePtr->height = height; + NSMenuItem *menuItem = (NSMenuItem *) mePtr->platformEntryData; + int haveImage = 0, width = 0, height = 0; - nonAccelMargin = 0; - if (mePtr->type == CASCADE_ENTRY) { - GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, - &modifierWidth, &accelWidth, &height); - } else if (mePtr->accelLength == 0) { - if (haveAccel && !mePtr->hideMargin) { - if (IS_THEME_MENU_FONT(tkfont)) { - nonAccelMargin = menuSymbols[COMMAND_SYMBOL].width; - } else { - nonAccelMargin = Tk_TextWidth(tkfont, - menuSymbols[COMMAND_SYMBOL].utf, - menuSymbols[COMMAND_SYMBOL].utfLen); - } + if (mePtr->image) { + Tk_SizeOfImage(mePtr->image, &width, &height); + haveImage = 1; + } else if (mePtr->bitmapPtr) { + Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, + mePtr->bitmapPtr); + + Tk_SizeOfBitmap(menuPtr->display, bitmap, &width, &height); + haveImage = 1; + } + if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { + NSAttributedString *attrTitle = [menuItem attributedTitle]; + NSSize size; + + if (attrTitle) { + size = [attrTitle size]; + } else { + size = [[menuItem title] sizeWithAttributes: + TkMacOSXNSFontAttributesForFont(tkfont)]; } - accelWidth = modifierWidth = 0; - } else { - GetMenuAccelGeometry(menuPtr, mePtr, tkfont, - fmPtr, &modifierWidth, &accelWidth, &height); - if (height > mePtr->height) { - mePtr->height = height; + size.width += menuTextLeadingEdgeMargin + + menuTextTrailingEdgeMargin; + if (size.height < fmPtr->linespace) { + size.height = fmPtr->linespace; + } + if (haveImage && (mePtr->compound != COMPOUND_NONE)) { + int margin = width + menuIconTrailingEdgeMargin; + + if (margin > menuTextLeadingEdgeMargin) { + margin = menuTextLeadingEdgeMargin; + } + width += size.width + menuIconTrailingEdgeMargin - margin; + if (size.height > height) { + height = size.height; + } + } else { + width = size.width; + height = size.height; } } + labelWidth = width + menuItemExtraWidth; + mePtr->height = height + menuItemExtraHeight; - if (!(mePtr->hideMargin)) { - GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, - fmPtr, &indicatorSpace, &height); - if (height > mePtr->height) { - mePtr->height = height; + if (mePtr->type == CASCADE_ENTRY) { + modifierWidth = modifierCharWidth; + } else if (mePtr->accelLength == 0) { + if (haveAccel && !mePtr->hideMargin) { + modifierWidth = modifierCharWidth; } } else { - indicatorSpace = 0; - } + NSUInteger modifMask = [menuItem keyEquivalentModifierMask]; + int i = 0; - if (nonAccelMargin > maxNonAccelMargin) { - maxNonAccelMargin = nonAccelMargin; - } - if (accelWidth > maxAccelTextWidth) { - maxAccelTextWidth = accelWidth; + while (modifiers[i].name) { + if (modifMask & modifiers[i].mask) { + modifMask &= ~modifiers[i].mask; + modifierWidth += modifierCharWidth; + } + i++; + } + accelWidth = [[menuItem keyEquivalent] sizeWithAttributes: + TkMacOSXNSFontAttributesForFont(tkfont)].width; } - if (modifierWidth > maxModifierWidth) { - maxModifierWidth = modifierWidth; + if (!mePtr->hideMargin) { + indicatorSpace = menuMarkColumnWidth; } if (indicatorSpace > maxIndicatorSpace) { maxIndicatorSpace = indicatorSpace; } - - entryWidth = labelWidth + modifierWidth + accelWidth - + nonAccelMargin; - + entryWidth = labelWidth + modifierWidth + accelWidth; if (entryWidth > maxWidth) { maxWidth = entryWidth; } - - if (mePtr->accelLength > 0) { - if (entryWidth > maxEntryWithAccelWidth) { - maxEntryWithAccelWidth = entryWidth; - } - } else { - if (entryWidth > maxEntryWithoutAccelWidth) { - maxEntryWithoutAccelWidth = entryWidth; - } - } mePtr->height += 2 * activeBorderWidth; } mePtr->y = y; @@ -3356,33 +1200,16 @@ TkpComputeStandardMenuGeometry( for (j = lastColumnBreak; j < menuPtr->numEntries; j++) { columnEntryPtr = menuPtr->entries[j]; - geometryPtr = (EntryGeometry *) columnEntryPtr->platformEntryData; - columnEntryPtr->indicatorSpace = maxIndicatorSpace; columnEntryPtr->width = maxIndicatorSpace + maxWidth + 2 * activeBorderWidth; - geometryPtr->accelTextWidth = maxAccelTextWidth; columnEntryPtr->x = x; columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN; - if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) { - geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth - - maxEntryWithAccelWidth; - if (geometryPtr->nonAccelMargin > maxNonAccelMargin) { - geometryPtr->nonAccelMargin = maxNonAccelMargin; - } - } else { - geometryPtr->nonAccelMargin = 0; - } } windowWidth = x + maxIndicatorSpace + maxWidth + 2 * activeBorderWidth + borderWidth; windowHeight += borderWidth; - /* - * The X server doesn't like zero dimensions, so round up to at least - * 1 (a zero-sized menu should never really occur, anyway). - */ - if (windowWidth <= 0) { windowWidth = 1; } @@ -3396,353 +1223,7 @@ TkpComputeStandardMenuGeometry( /* *---------------------------------------------------------------------- * - * DrawMenuEntryLabel -- - * - * This procedure draws the label part of a menu. - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -void -DrawMenuEntryLabel( - TkMenu *menuPtr, /* The menu we are drawing */ - TkMenuEntry *mePtr, /* The entry we are drawing */ - Drawable d, /* What we are drawing into */ - GC gc, /* The gc we are drawing into */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */ - int x, /* left edge */ - int y, /* right edge */ - int width, /* width of entry */ - int height) /* height of entry */ -{ - int imageWidth, imageHeight, textWidth = 0, textHeight = 0; - int indicatorSpace = mePtr->indicatorSpace; - int leftEdge = x + indicatorSpace; - int haveImage = 0, haveText = 0; - int imageXOffset = 0, imageYOffset = 0; - int textXOffset = 0, textYOffset = 0; - Pixmap bitmap = (Pixmap) NULL; - Tcl_DString itemTextDString; - - /* - * Work out what we will need to draw first. - */ - - if (mePtr->image != NULL) { - Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight); - haveImage = 1; - } else if (mePtr->bitmapPtr != NULL) { - bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); - Tk_SizeOfBitmap(menuPtr->display, bitmap, &imageWidth, &imageHeight); - haveImage = 1; - } - if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { - if (mePtr->labelLength > 0) { - GetEntryText(mePtr, &itemTextDString); - if (mePtr->compound != COMPOUND_NONE) { - textWidth = Tk_TextWidth(tkfont, - Tcl_DStringValue(&itemTextDString), - Tcl_DStringLength(&itemTextDString)) + - menuTextLeadingEdgeMargin + menuTextTrailingEdgeMargin; - textHeight = fmPtr->linespace; - } - haveText = 1; - } - } - - /* - * Now work out what the relative positions are. - */ - - if (haveImage && haveText && (mePtr->compound != COMPOUND_NONE)) { - int fullWidth = (imageWidth > textWidth ? imageWidth : textWidth); - - switch ((enum compound) mePtr->compound) { - case COMPOUND_TOP: - textXOffset = (fullWidth - textWidth)/2; - textYOffset = imageHeight/2 + 2; - imageXOffset = (fullWidth - imageWidth)/2; - imageYOffset = -textHeight/2; - break; - case COMPOUND_BOTTOM: - textXOffset = (fullWidth - textWidth)/2; - textYOffset = -imageHeight/2; - imageXOffset = (fullWidth - imageWidth)/2; - imageYOffset = textHeight/2 + 2; - break; - case COMPOUND_LEFT: - /* - * Position image in the indicator space to the left of the - * entries, unless this entry is a radio|check button because - * then the indicator space will be used. - */ - - textXOffset = imageWidth + 2 - menuTextLeadingEdgeMargin; - if ((mePtr->type != CHECK_BUTTON_ENTRY) - && (mePtr->type != RADIO_BUTTON_ENTRY)) { - textXOffset -= indicatorSpace; - imageXOffset = -indicatorSpace; - } - if (textXOffset < 0) { - textXOffset = 0; - } - break; - case COMPOUND_RIGHT: - imageXOffset = textWidth + 2 - menuTextTrailingEdgeMargin; - break; - case COMPOUND_CENTER: - textXOffset = (fullWidth - textWidth)/2; - imageXOffset = (fullWidth - imageWidth)/2; - break; - case COMPOUND_NONE: - /* - * Never reached. - */ - break; - } - } - - /* - * Draw label and/or bitmap or image for entry. - */ - - if (mePtr->image != NULL) { - if ((mePtr->selectImage != NULL) - && (mePtr->entryFlags & ENTRY_SELECTED)) { - Tk_RedrawImage(mePtr->selectImage, 0, 0, imageWidth, imageHeight, - d, leftEdge + imageXOffset, - y + (mePtr->height - imageHeight)/2 + imageYOffset); - } else { - Tk_RedrawImage(mePtr->image, 0, 0, imageWidth, imageHeight, - d, leftEdge + imageXOffset, - y + (mePtr->height - imageHeight)/2 + imageYOffset); - } - } else if (mePtr->bitmapPtr != NULL) { - XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, imageWidth, - imageHeight, leftEdge + imageXOffset, - y + (mePtr->height - imageHeight)/2 + imageYOffset, 1); - } - if (haveText) { - int baseline = y + (height + fmPtr->ascent - fmPtr->descent)/2; - - Tk_DrawChars(menuPtr->display, d, gc, tkfont, - Tcl_DStringValue(&itemTextDString), - Tcl_DStringLength(&itemTextDString), - leftEdge + menuTextLeadingEdgeMargin + textXOffset, - baseline + textYOffset); - Tcl_DStringFree(&itemTextDString); - } - - if (mePtr->state == ENTRY_DISABLED) { - if (menuPtr->disabledFgPtr == NULL) { - /* XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y, - width, height); */ - } else if ((mePtr->image != NULL) - && (menuPtr->disabledImageGC != None)) { - XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC, - leftEdge + imageXOffset, - y + (mePtr->height - imageHeight)/2 + imageYOffset, - imageWidth, imageHeight); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * DrawMenuEntryBackground -- - * - * This procedure draws the background part of a menu entry. - * Under Appearance, we only draw the background if the entry's - * border is set, we DO NOT inherit it from the menu... - * - * Results: - * None. - * - * Side effects: - * Commands are output to X to display the menu in its - * current mode. - * - *---------------------------------------------------------------------- - */ - -void -DrawMenuEntryBackground( - TkMenu *menuPtr, /* The menu we are drawing. */ - TkMenuEntry *mePtr, /* The entry we are drawing. */ - Drawable d, /* What we are drawing into */ - Tk_3DBorder activeBorder, /* Border for active items */ - Tk_3DBorder bgBorder, /* Border for the background */ - int x, /* left edge */ - int y, /* top edge */ - int width, /* width of rectangle to draw */ - int height) /* height of rectangle to draw */ -{ - if ((menuPtr->menuType == TEAROFF_MENU) - || ((mePtr->state == ENTRY_ACTIVE) - && (mePtr->activeBorderPtr != None)) - || ((mePtr->state != ENTRY_ACTIVE) && (mePtr->borderPtr != None))) { - if (mePtr->state == ENTRY_ACTIVE) { - bgBorder = activeBorder; - } - Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, - x, y, width, height, 0, TK_RELIEF_FLAT); - } -} - -/* - *---------------------------------------------------------------------- - * - * GetMenuLabelGeometry -- - * - * Figures out the size of the label portion of a menu item. - * - * Results: - * widthPtr and heightPtr are filled in with the correct geometry - * information. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -void -GetMenuLabelGeometry( - TkMenuEntry *mePtr, /* The entry we are computing */ - Tk_Font tkfont, /* The precalculated font */ - const Tk_FontMetrics *fmPtr,/* The precalculated metrics */ - int *widthPtr, /* The resulting width of the label portion */ - int *heightPtr) /* The resulting height of the label portion */ -{ - TkMenu *menuPtr = mePtr->menuPtr; - int haveImage = 0, tornOff = (menuPtr->menuType == TEAROFF_MENU); -#ifdef USE_TK_MDEF - const int useMDEF = ((MacMenu *) menuPtr->platformData)->useMDEF; -#endif - - if (mePtr->image != NULL && (useMDEF || tornOff)) { - Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr); - haveImage = 1; - } else if (mePtr->bitmapPtr != NULL && (useMDEF || tornOff)) { - Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr); - Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr); - haveImage = 1; - } - if (!haveImage || (mePtr->compound != COMPOUND_NONE)) { - int textWidth = 0, textHeight = fmPtr->linespace; - - if (mePtr->labelPtr != NULL) { - Tcl_DString itemTextDString; - - GetEntryText(mePtr, &itemTextDString); - textWidth = Tk_TextWidth(tkfont, - Tcl_DStringValue(&itemTextDString), - Tcl_DStringLength(&itemTextDString)) + - menuTextLeadingEdgeMargin + menuTextTrailingEdgeMargin; - Tcl_DStringFree(&itemTextDString); - - if (haveImage && (mePtr->compound != COMPOUND_NONE)) { - switch ((enum compound) mePtr->compound) { - int margin; - - case COMPOUND_TOP: - case COMPOUND_BOTTOM: - if (textWidth > *widthPtr) { - *widthPtr = textWidth; - } - *heightPtr += textHeight + 2; - break; - case COMPOUND_LEFT: - margin = *widthPtr + 2; - if (margin > menuTextLeadingEdgeMargin) { - margin = menuTextLeadingEdgeMargin; - } - *widthPtr += textWidth + 2 - margin; - if (textHeight > *heightPtr) { - *heightPtr = textHeight; - } - break; - case COMPOUND_RIGHT: - margin = menuTextTrailingEdgeMargin; - *widthPtr += textWidth + 2 - margin; - if (textHeight > *heightPtr) { - *heightPtr = textHeight; - } - break; - case COMPOUND_CENTER: - if (textWidth > *widthPtr) { - *widthPtr = textWidth; - } - if (textHeight > *heightPtr) { - *heightPtr = textHeight; - } - break; - case COMPOUND_NONE: - /* - * Never reached. - */ - break; - } - goto labelGeomDone; - } - } - *widthPtr = textWidth; - *heightPtr = textHeight; - } - -labelGeomDone: - *heightPtr += menuItemExtraHeight; - *widthPtr += menuItemExtraWidth; -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXGenerateParentMenuSelectEvent -- - * - * Respond to a hierarchical menu being opened. - * - * Results: - * True if event(s) are generated - false otherwise. - * - * Side effects: - * Places a virtual event on the event queue. - * - *---------------------------------------------------------------------- - */ - -int -TkMacOSXGenerateParentMenuSelectEvent( - MenuRef menu) -{ - TkMenu *menuPtr = MenuPtrForMenuRef(menu); - - if (menuPtr) { - TkMenuEntry *parentEntryPtr = GetParentMenuEntry(menuPtr); - - if (parentEntryPtr && (menuPtr = parentEntryPtr->menuPtr)) { - TkActivateMenuEntry(menuPtr, parentEntryPtr->index); - MenuSelectEvent(menuPtr); - Tcl_ServiceAll(); - return true; - } - } - return false; -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXGenerateMenuSelectEvent -- + * GenerateMenuSelectEvent -- * * Respond to a menu item being selected. * @@ -3756,34 +1237,34 @@ TkMacOSXGenerateParentMenuSelectEvent( */ int -TkMacOSXGenerateMenuSelectEvent( - MenuRef menu, - MenuItemIndex index) +GenerateMenuSelectEvent( + TKMenu *menu, + NSMenuItem *menuItem) { - TkMenu *menuPtr = MenuPtrForMenuRef(menu); - int item = index - 1; + TkMenu *menuPtr = [menu tkMenu]; if (menuPtr) { - if (item < 0 || item >= menuPtr->numEntries || - (menuPtr->entries[item])->state == ENTRY_DISABLED) { + int index = [menu tkIndexOfItem:menuItem]; + + if (index < 0 || index >= menuPtr->numEntries || + (menuPtr->entries[index])->state == ENTRY_DISABLED) { TkActivateMenuEntry(menuPtr, -1); } else { - TkActivateMenuEntry(menuPtr, item); + TkActivateMenuEntry(menuPtr, index); MenuSelectEvent(menuPtr); - Tcl_ServiceAll(); return true; } } return false; } - + /* *---------------------------------------------------------------------- * * MenuSelectEvent -- * - * Generates a "MenuSelect" virtual event. This can be used to - * do context-sensitive menu help. + * Generates a "MenuSelect" virtual event. This can be used to do + * context-sensitive menu help. * * Results: * None. @@ -3802,46 +1283,22 @@ MenuSelectEvent( bzero(&event, sizeof(XVirtualEvent)); event.type = VirtualEvent; - event.serial = menuPtr->display->request; + event.serial = LastKnownRequestProcessed(menuPtr->display); event.send_event = false; event.display = menuPtr->display; - Tk_MakeWindowExist(menuPtr->tkwin); event.event = Tk_WindowId(menuPtr->tkwin); event.root = XRootWindow(menuPtr->display, 0); event.subwindow = None; event.time = TkpGetMS(); - XQueryPointer(NULL, None, NULL, NULL, &event.x_root, &event.y_root, NULL, NULL, &event.state); event.same_screen = true; event.name = Tk_GetUid("MenuSelect"); - Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); -} - -/* - *---------------------------------------------------------------------- - * - * TkMacOSXClearActiveMenu -- - * - * Clears Tk's active entry for the given MenuRef. - * - * Results: - * None. - * - * Side effects: - * Generates <<MenuSelect>> virtual events. - * - *---------------------------------------------------------------------- - */ - -void -TkMacOSXClearActiveMenu( - MenuRef menu) -{ - TkMenu *menuPtr = MenuPtrForMenuRef(menu); - - if (menuPtr) { - RecursivelyClearActiveMenu(menuPtr); + Tk_MakeWindowExist(menuPtr->tkwin); + if (Tcl_GetServiceMode() != TCL_SERVICE_NONE) { + Tk_HandleEvent((XEvent *) &event); + } else { + Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL); } } @@ -3866,16 +1323,15 @@ RecursivelyClearActiveMenu( TkMenu *menuPtr) /* The menu to reset. */ { int i; - TkMenuEntry *mePtr; TkActivateMenuEntry(menuPtr, -1); for (i = 0; i < menuPtr->numEntries; i++) { - mePtr = menuPtr->entries[i]; - if (mePtr->type == CASCADE_ENTRY) { - if ((mePtr->childMenuRefPtr != NULL) - && (mePtr->childMenuRefPtr->menuPtr != NULL)) { - RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr); - } + TkMenuEntry *mePtr = menuPtr->entries[i]; + + if (mePtr->type == CASCADE_ENTRY + && (mePtr->childMenuRefPtr != NULL) + && (mePtr->childMenuRefPtr->menuPtr != NULL)) { + RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr); } } } @@ -3899,20 +1355,13 @@ RecursivelyClearActiveMenu( void TkMacOSXClearMenubarActive(void) { - TkMenuReferences *menuBarRefPtr; - - if (currentMenuBarName != NULL) { - menuBarRefPtr = TkFindMenuReferences(currentMenuBarInterp, - currentMenuBarName); - if ((menuBarRefPtr != NULL) && (menuBarRefPtr->menuPtr != NULL)) { - TkMenu *menuPtr; - - for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr; - menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) { - if (menuPtr->menuType == MENUBAR) { - RecursivelyClearActiveMenu(menuPtr); - } - } + NSMenu *mainMenu = [NSApp mainMenu]; + + if (mainMenu && [mainMenu isKindOfClass:[TKMenu class]]) { + TkMenu *menuPtr = [(TKMenu *) mainMenu tkMenu]; + + if (menuPtr && menuPtr->numEntries && menuPtr->entries) { + RecursivelyClearActiveMenu(menuPtr); } } } @@ -3920,29 +1369,25 @@ TkMacOSXClearMenubarActive(void) /* *---------------------------------------------------------------------- * - * TkpMenuNotifyToplevelCreate -- + * Tk_MacOSXTurnOffMenus -- * - * This routine reconfigures the menu and the clones indicated by - * menuName becuase a toplevel has been created and any system - * menus need to be created. Only applicable to Windows. + * 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: - * An idle handler is set up to do the reconfiguration. + * A flag is set which will disable all menu drawing. * *---------------------------------------------------------------------- */ void -TkpMenuNotifyToplevelCreate( - Tcl_Interp *interp, /* The interp the menu lives in. */ - char *menuName) /* The name of the menu to reconfigure. */ +Tk_MacOSXTurnOffMenus(void) { - /* - * Nothing to do. - */ + gNoTkMenus = 1; } /* @@ -3964,66 +1409,46 @@ TkpMenuNotifyToplevelCreate( void TkpMenuInit(void) { - MenuSymbol *ms = menuSymbols; - CFStringRef cfStr; - - lastMenuID = 256; - Tcl_InitHashTable(&commandTable, TCL_ONE_WORD_KEYS); - currentMenuBarOwner = NULL; - currentAppleMenuID = 0; - currentHelpMenuID = 0; - currentMenuBarInterp = NULL; - currentMenuBarName = NULL; - windowListPtr = NULL; - -#ifdef USE_TK_MDEF - tkThemeMenuItemDrawingUPP - = NewMenuItemDrawingUPP(ThemeMenuItemDrawingProc); - useMDEFVar = Tcl_NewStringObj("::tk::mac::useCustomMDEF", -1); - macMDEFDrawable.winPtr = NULL; - macMDEFDrawable.xOff = 0; - macMDEFDrawable.yOff = 0; - macMDEFDrawable.visRgn = NULL; - macMDEFDrawable.aboveVisRgn = NULL; - macMDEFDrawable.drawRect = CGRectNull; - macMDEFDrawable.referenceCount = 0; - macMDEFDrawable.toplevel = NULL; - macMDEFDrawable.flags = 0; - macMDEFDrawable.grafPtr = NULL; - macMDEFDrawable.context = NULL; - macMDEFDrawable.size = CGSizeZero; -#endif + TkColor *tkColPtr; + + NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; + +#define observe(n, s) \ + [nc addObserver:NSApp selector:@selector(s) name:(n) object:nil] + observe(NSMenuDidBeginTrackingNotification, menuBeginTracking:); + observe(NSMenuDidEndTrackingNotification, menuEndTracking:); +#undef observe + + [NSMenuItem setUsesUserKeyEquivalents:NO]; + tkColPtr = TkpGetColor(None, DEF_MENU_BG_COLOR); + defaultBg = tkColPtr->color.pixel; + ckfree(tkColPtr); + tkColPtr = TkpGetColor(None, DEF_MENU_FG); + defaultFg = tkColPtr->color.pixel; + ckfree(tkColPtr); ChkErr(GetThemeMetric, kThemeMetricMenuMarkColumnWidth, &menuMarkColumnWidth); - ChkErr(GetThemeMetric, kThemeMetricMenuMarkIndent, &menuMarkIndent); ChkErr(GetThemeMetric, kThemeMetricMenuTextLeadingEdgeMargin, &menuTextLeadingEdgeMargin); ChkErr(GetThemeMetric, kThemeMetricMenuTextTrailingEdgeMargin, &menuTextTrailingEdgeMargin); + ChkErr(GetThemeMetric, kThemeMetricMenuIconTrailingEdgeMargin, + &menuIconTrailingEdgeMargin); ChkErr(GetThemeMenuItemExtra, kThemeMenuItemPlain, &menuItemExtraHeight, &menuItemExtraWidth); ChkErr(GetThemeMenuSeparatorHeight, &menuSeparatorHeight); - - while (ms->unicode) { - ms->utfLen = Tcl_UniCharToUtf(ms->unicode, ms->utf); - ms->utf[ms->utfLen] = 0; - cfStr = CFStringCreateWithCharacters(NULL, &ms->unicode, 1); - if (cfStr) { - ms->width = MeasureThemeText(cfStr, kThemeMenuItemCmdKeyFont); - CFRelease(cfStr); - } - ms++; - } } + +#pragma mark - +#pragma mark NOPs /* *---------------------------------------------------------------------- * * TkpMenuThreadInit -- * - * Does platform-specific initialization of thread-specific - * menu state. + * Does platform-specific initialization of thread-specific menu state. * * Results: * None. @@ -4045,696 +1470,273 @@ TkpMenuThreadInit(void) /* *---------------------------------------------------------------------- * - * TkpPreprocessMacMenu -- + * TkpMenuNotifyToplevelCreate -- * - * Handle preprocessing of menubar if it exists. + * This routine reconfigures the menu and the clones indicated by + * menuName because a toplevel has been created and any system menus need + * to be created. Only applicable to Windows. * * Results: - * None. + * None. * * Side effects: - * All post commands for the current menubar get executed. + * An idle handler is set up to do the reconfiguration. * *---------------------------------------------------------------------- */ void -TkMacOSXPreprocessMenu(void) +TkpMenuNotifyToplevelCreate( + Tcl_Interp *interp, /* The interp the menu lives in. */ + const char *menuName) /* The name of the menu to reconfigure. */ { - if ((currentMenuBarName != NULL) && (currentMenuBarInterp != NULL)) { - TkMenuReferences *mbRefPtr = - TkFindMenuReferences(currentMenuBarInterp,currentMenuBarName); - - if ((mbRefPtr != NULL) && (mbRefPtr->menuPtr != NULL)) { - int code; - - Tcl_Preserve((ClientData) currentMenuBarInterp); - code = TkPreprocessMenu(mbRefPtr->menuPtr->masterMenuPtr); - if ((code != TCL_OK) && (code != TCL_CONTINUE) - && (code != TCL_BREAK)) { - Tcl_AddErrorInfo(currentMenuBarInterp, - "\n (menu preprocess)"); - Tcl_BackgroundError(currentMenuBarInterp); - } - Tcl_Release((ClientData) currentMenuBarInterp); - } - } + /* + * Nothing to do. + */ } -#ifdef USE_TK_MDEF -#pragma mark MDEF /* - *---------------------------------------------------------------------- + *-------------------------------------------------------------- * - * MenuDefProc -- + * TkpInitializeMenuBindings -- * - * This routine is the MDEF handler for Tk. It receives all messages - * for the menu and dispatches them. + * For every interp, initializes the bindings for Windows menus. Does + * nothing on Mac or XWindows. * * Results: * None. * * Side effects: - * This routine causes menus to be drawn and will certainly allocate - * memory as a result. Also, the menu can scroll up and down, and - * various other interface actions can take place. + * C-level bindings are setup for the interp which will handle Alt-key + * sequences for menus without beeping or interfering with user-defined + * Alt-key bindings. * - *---------------------------------------------------------------------- + *-------------------------------------------------------------- */ void -MenuDefProc( - SInt16 message, /* What action are we taking? */ - MenuRef menu, /* The menu we are working with */ - Rect *menuRectPtr, /* A pointer to the rect for the - * whole menu. */ - Point hitPt, /* Where the mouse was clicked for - * the appropriate messages. */ - SInt16 *whichItem) /* Output result. Which item was - * hit by the user? */ +TkpInitializeMenuBindings( + Tcl_Interp *interp, /* The interpreter to set. */ + Tk_BindingTable bindingTable) + /* The table to add to. */ { - TkMenu *menuPtr; - Tcl_HashEntry *commandEntryPtr; - MenuID menuID; - - menuID = GetMenuID(menu); - commandEntryPtr = Tcl_FindHashEntry(&commandTable, (char*)(intptr_t)menuID); - - if (!commandEntryPtr) return; - menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr); + /* + * Nothing to do. + */ +} + +/* + *-------------------------------------------------------------- + * + * TkpComputeMenubarGeometry -- + * + * This procedure is invoked to recompute the size and layout of a menu + * that is a menubar clone. + * + * Results: + * None. + * + * Side effects: + * Fields of menu entries are changed to reflect their current positions, + * and the size of the menu window itself may be changed. + * + *-------------------------------------------------------------- + */ - switch (message) { - case kMenuInitMsg: - *whichItem = noErr; - break; - case kMenuDisposeMsg: - break; - case kMenuHiliteItemMsg: - HandleMenuHiliteMsg(menu, menuRectPtr, hitPt, whichItem, menuPtr); - break; - case kMenuCalcItemMsg: - HandleMenuCalcItemMsg(menu, menuRectPtr, hitPt, whichItem, - menuPtr); - break; - case kMenuDrawItemsMsg: -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("MDEF: DrawItemsMsg"); -#endif - /* - * We do nothing here, because we don't support the Menu Managers - * dynamic item groups - */ - break; - case kMenuThemeSavvyMsg: - *whichItem = kThemeSavvyMenuResponse; - break; - case kMenuSizeMsg: -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("MDEF: SizeMsg %d, %d", hitPt.h, hitPt.v); -#endif - SetMenuWidth(menu, hitPt.h < menuPtr->totalWidth ? hitPt.h : - menuPtr->totalWidth); - SetMenuHeight(menu, hitPt.v < menuPtr->totalHeight ? hitPt.v : - menuPtr->totalHeight); - break; - case kMenuDrawMsg: - HandleMenuDrawMsg(menu, menuRectPtr, hitPt, whichItem, menuPtr); - break; - case kMenuFindItemMsg: - HandleMenuFindItemMsg(menu, menuRectPtr, hitPt, whichItem, - menuPtr); - break; - case kMenuPopUpMsg: - HandleMenuPopUpMsg(menu, menuRectPtr, hitPt, whichItem, menuPtr); - break; - } +void +TkpComputeMenubarGeometry( + TkMenu *menuPtr) /* Structure describing menu. */ +{ + TkpComputeStandardMenuGeometry(menuPtr); } + /* *---------------------------------------------------------------------- * - * HandleMenuHiliteMsg -- + * TkpDrawMenuEntry -- * - * Handles the MenuDefProc's hilite message. + * Draws the given menu entry at the given coordinates with the given + * attributes. * * Results: - * A menu entry is drawn + * None. * * Side effects: - * None + * X Server commands are executed to display the menu entry. * *---------------------------------------------------------------------- */ void -HandleMenuHiliteMsg( - MenuRef menu, - Rect *menuRectPtr, - Point hitPt, - SInt16 *whichItem, - TkMenu *menuPtr) +TkpDrawMenuEntry( + TkMenuEntry *mePtr, /* The entry to draw */ + Drawable d, /* What to draw into */ + Tk_Font tkfont, /* Precalculated font for menu */ + const Tk_FontMetrics *menuMetricsPtr, + /* Precalculated metrics for menu */ + int x, /* X-coordinate of topleft of entry */ + int y, /* Y-coordinate of topleft of entry */ + int width, /* Width of the entry rectangle */ + int height, /* Height of the current rectangle */ + int strictMotif, /* Boolean flag */ + int drawArrow) /* Whether or not to draw the cascade arrow + * for cascade items. Only applies to + * Windows. */ { - OSStatus err; - Tk_Font tkfont; - Tk_FontMetrics fontMetrics; - MDEFHiliteItemData *hidPtr = (MDEFHiliteItemData *)whichItem; - int oldItem = hidPtr->previousItem - 1; - int newItem = hidPtr->newItem - 1; - MenuTrackingData mtd, *mtdPtr = &mtd; - -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("MDEF: HiliteMsg %d -> %d", hidPtr->previousItem, - hidPtr->newItem); -#endif - GetPort(&macMDEFDrawable.grafPtr); - macMDEFDrawable.context = (CGContextRef) hidPtr->context; - - err = ChkErr(GetMenuTrackingData, menu, mtdPtr); - if (err != noErr) { - return; - } - - tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); - Tk_GetFontMetrics(tkfont, &fontMetrics); - if (oldItem >= 0) { - AppearanceEntryDrawWrapper(menuPtr->entries[oldItem], menuRectPtr, - mtdPtr, (Drawable) &macMDEFDrawable, &fontMetrics, tkfont, 1); - } - if (newItem >= 0) { - AppearanceEntryDrawWrapper(menuPtr->entries[newItem], menuRectPtr, - mtdPtr, (Drawable) &macMDEFDrawable, &fontMetrics, tkfont, 0); - } } + +#pragma mark Obsolete /* *---------------------------------------------------------------------- * - * HandleMenuDrawMsg -- + * TkMacOSXPreprocessMenu -- * - * Handles the MenuDefProc's draw message. + * Handle preprocessing of menubar if it exists. * * Results: - * A menu entry is drawn + * None. * * Side effects: - * None + * All post commands for the current menubar get executed. * *---------------------------------------------------------------------- */ void -HandleMenuDrawMsg( - MenuRef menu, - Rect *menuRectPtr, - Point hitPt, - SInt16 *whichItem, - TkMenu *menuPtr) +TkMacOSXPreprocessMenu(void) { - Tk_Font menuFont; - Tk_FontMetrics fontMetrics; - TkMenuEntry *mePtr; - int i; - Rect menuClipRect, bounds; - MDEFDrawData *ddPtr = (MDEFDrawData*)whichItem; - MenuTrackingData *mtdPtr = &(ddPtr->trackingData); - TkWindow *winPtr = (TkWindow*)menuPtr->tkwin; - - GetPort(&macMDEFDrawable.grafPtr); - GetPortBounds(macMDEFDrawable.grafPtr, &bounds); - macMDEFDrawable.context = (CGContextRef) ddPtr->context; -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("MDEF: DrawMsg %d - %d; %d - %d", menuRectPtr->top, - menuRectPtr->bottom, bounds.top, bounds.bottom); -#endif - winPtr->changes.x = menuRectPtr->left; - winPtr->changes.y = menuRectPtr->top; - winPtr->changes.width = menuRectPtr->right - menuRectPtr->left; - winPtr->changes.height = menuRectPtr->bottom - menuRectPtr->top; - TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable, - 0, 0, -1, -1); -#if 0 - if (menuPtr->menuRefPtr->topLevelListPtr != NULL) { - menuType = kThemeMenuTypePullDown; - } else if (menuPtr->menuRefPtr->parentEntryPtr != NULL) { - menuType = kThemeMenuTypeHierarchical; - } else { - menuType = kThemeMenuTypePopUp; - } -#endif - DrawMenuBackground(menuPtr, menuRectPtr, (Drawable) &macMDEFDrawable); - menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); - Tk_GetFontMetrics(menuFont, &fontMetrics); - menuClipRect = *menuRectPtr; - mtdPtr->virtualMenuBottom = mtdPtr->virtualMenuTop + menuPtr->totalHeight; - - /* - * Next, figure out scrolling information. - */ - - if ((menuRectPtr->bottom - menuRectPtr->top) < menuPtr->totalHeight) { - short arrowHeight = fontMetrics.linespace + 1; - Rect arrowRect, eraseRect; - ThemeMenuState menuState = IsMenuItemEnabled(menu, 0) ? - kThemeMenuActive : kThemeMenuDisabled; - - if (mtdPtr->virtualMenuTop < menuRectPtr->top) { - arrowRect = bounds; - /*arrowRect.top += 1;*/ - arrowRect.bottom = arrowRect.top + arrowHeight; - eraseRect = arrowRect; - eraseRect.top = menuRectPtr->top; - menuClipRect.top = arrowRect.bottom; - ChkErr(EraseMenuBackground, menu, &eraseRect, - macMDEFDrawable.context); - ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect, - mtdPtr->virtualMenuTop, mtdPtr->virtualMenuBottom, - menuState, kThemeMenuItemScrollUpArrow, NULL, 0); -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("upArrow: %d - %d, %d - %d", arrowRect.top, - arrowRect.bottom, arrowRect.left, arrowRect.right); -#endif - } - if (mtdPtr->virtualMenuBottom > menuRectPtr->bottom) { - arrowRect = bounds; - arrowRect.bottom -= 1; - arrowRect.top = arrowRect.bottom - arrowHeight; - eraseRect = arrowRect; - eraseRect.bottom = menuRectPtr->bottom; - menuClipRect.bottom = arrowRect.top; - ChkErr(EraseMenuBackground, menu, &eraseRect, - macMDEFDrawable.context); - ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect, - mtdPtr->virtualMenuTop, mtdPtr->virtualMenuBottom, - menuState, kThemeMenuItemScrollDownArrow, NULL, 0); -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("downArrow: %d - %d, %d - %d", arrowRect.top, - arrowRect.bottom, arrowRect.left, arrowRect.right); -#endif - } - TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable, - menuClipRect.left, menuClipRect.top, menuClipRect.right - - menuClipRect.left, menuClipRect.bottom - menuClipRect.top); - } +} + +/* + *---------------------------------------------------------------------- + * + * 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. + * + *---------------------------------------------------------------------- + */ - /* - * Now, actually draw the menu. Don't draw entries that - * are higher than the top arrow, and don't draw entries - * that are lower than the bottom. - */ +int +TkMacOSXUseMenuID( + short macID) /* The id to take out of the table */ +{ + return TCL_OK; +} + +/* + *---------------------------------------------------------------------- + * + * 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. + * + *---------------------------------------------------------------------- + */ - for (i = 0; i < menuPtr->numEntries; i++) { - mePtr = menuPtr->entries[i]; - if (mtdPtr->virtualMenuTop + mePtr->y + mePtr->height < - menuClipRect.top || mtdPtr->virtualMenuTop + mePtr->y > - menuClipRect.bottom) { - continue; - } - AppearanceEntryDrawWrapper(mePtr, menuRectPtr, mtdPtr, - (Drawable) &macMDEFDrawable, &fontMetrics, menuFont, 0); - } - MDEFScrollFlag = 1; +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. */ +{ + return TCL_ERROR; } /* *---------------------------------------------------------------------- * - * HandleMenuFindItemMsg -- + * TkMacOSXHandleTearoffMenu() -- * - * Handles the MenuDefProc's FindItems message. We have to - * respond by filling in the itemSelected, itemUnderMouse and - * itemRect fields. This is also the time to scroll the menu if - * it is too long to fit on the screen. + * This routine sees if the MDEF has set a menu and a mouse position for + * tearing off and makes a tearoff menu if it has. * * Results: - * The Menu system is informed of the selected item & the item - * under the mouse. + * menuPtr->interp will have the result of the tearoff command. * * Side effects: - * The menu might get scrolled. + * A new tearoff menu is created if it is supposed to be. * *---------------------------------------------------------------------- */ + void -HandleMenuFindItemMsg( - MenuRef menu, - Rect *menuRectPtr, - Point hitPt, - SInt16 *whichItem, - TkMenu *menuPtr) +TkMacOSXHandleTearoffMenu(void) { - Tk_Font menuFont; - Tk_FontMetrics fontMetrics; - TkMenuEntry *mePtr; - int i, newItem = -1, itemUnderMouse = -1; - Rect itemRect = {0, 0, 0, 0}, menuClipRect, bounds; - int hasTopScroll, hasBottomScroll; - MDEFFindItemData *fiPtr = (MDEFFindItemData *)whichItem; - MenuTrackingData *mtdPtr = &(fiPtr->trackingData), topMtd; - enum { - DONT_SCROLL, DOWN_SCROLL, UP_SCROLL - } scrollDirection; - short arrowHeight; - -#ifdef TK_MAC_DEBUG_MENUS - static Point lastHitPt = {0, 0}; - if (hitPt.h != lastHitPt.h || hitPt.v != lastHitPt.v) { - lastHitPt = hitPt; - TkMacOSXDbgMsg("MDEF: FindItemMsg: %d, %d", hitPt.h, hitPt.v); - } -#endif - - GetPort(&macMDEFDrawable.grafPtr); - GetPortBounds(macMDEFDrawable.grafPtr, &bounds); - macMDEFDrawable.context = (CGContextRef) fiPtr->context; - /* - * Now we need to take care of scrolling the menu. - */ - - menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr); - Tk_GetFontMetrics(menuFont, &fontMetrics); - arrowHeight = fontMetrics.linespace + 1; - menuClipRect = *menuRectPtr; - hasTopScroll = mtdPtr->virtualMenuTop < menuRectPtr->top; - hasBottomScroll = mtdPtr->virtualMenuBottom > menuRectPtr->bottom; - scrollDirection = DONT_SCROLL; - if (hasTopScroll) { - menuClipRect.top = bounds.top + arrowHeight; - if (hitPt.v < menuClipRect.top) { - newItem = -1; - scrollDirection = DOWN_SCROLL; - } - } - if (hasBottomScroll) { - menuClipRect.bottom = bounds.bottom - 1 - arrowHeight; - if (hitPt.v > menuClipRect.bottom) { - newItem = -1; - scrollDirection = UP_SCROLL; - } - } - if (MDEFScrollFlag) { - scrollDirection = DONT_SCROLL; - MDEFScrollFlag = 0; - } - /* - * Don't scroll if there are other menus open above us + * Obsolete: Nothing to do. */ - ChkErr(GetMenuTrackingData, NULL, &topMtd); - if (menu != topMtd.menu) { - scrollDirection = DONT_SCROLL; - } - if (scrollDirection == DONT_SCROLL) { - /* - * Find out which item was hit. If it is the same as the old item, - * we don't need to do anything. - */ - - if (PtInRect(hitPt, menuRectPtr)) { - for (i = 0; i < menuPtr->numEntries; i++) { - mePtr = menuPtr->entries[i]; - itemRect.left = menuRectPtr->left + mePtr->x; - itemRect.top = mtdPtr->virtualMenuTop + mePtr->y; - itemRect.right = mePtr->entryFlags & ENTRY_LAST_COLUMN ? - menuRectPtr->right : itemRect.left + mePtr->width; - itemRect.bottom = itemRect.top + mePtr->height; - if (PtInRect(hitPt, &itemRect)) { - if ((mePtr->type == SEPARATOR_ENTRY) - || (mePtr->state == ENTRY_DISABLED)) { - newItem = -1; - itemUnderMouse = i; - } else { - TkMenuEntry *parentEntryPtr = - GetParentMenuEntry(menuPtr); - - if (parentEntryPtr && - parentEntryPtr->state == ENTRY_DISABLED) { - newItem = -1; - itemUnderMouse = i; - } else { - newItem = i; - itemUnderMouse = i; - } - } - break; - } - } - } - } else { - short scrollAmt; - unsigned long scrollDelay; - Rect arrowRect, eraseRect, scrolledMenuClipRect; - ThemeMenuState menuState = IsMenuItemEnabled(menu, 0) ? - kThemeMenuActive : kThemeMenuDisabled; - int oldItem = mtdPtr->itemSelected - 1; - short d; - - TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable, - 0, 0, -1, -1); - scrollAmt = fontMetrics.linespace + menuItemExtraHeight; - if (scrollDirection == UP_SCROLL) { - scrollAmt = -scrollAmt; - d = hitPt.v - bounds.bottom; - } else { - d = bounds.top - hitPt.v; - } - scrollDelay = (d >= scrollAmt/2) ? 1 : 10; - menuClipRect = *menuRectPtr; - if (mtdPtr->virtualMenuTop + scrollAmt < menuRectPtr->top) { - arrowRect = bounds; - /*arrowRect.top += 1;*/ - arrowRect.bottom = arrowRect.top + arrowHeight; - eraseRect = arrowRect; - eraseRect.top = menuRectPtr->top; - menuClipRect.top = arrowRect.bottom; - if (!hasTopScroll) { - ChkErr(EraseMenuBackground, menu, &eraseRect, - macMDEFDrawable.context); - ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect, - mtdPtr->virtualMenuTop + scrollAmt, - mtdPtr->virtualMenuBottom + scrollAmt, - menuState, kThemeMenuItemScrollUpArrow, NULL, 0); -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("upArrow: %d - %d, %d - %d", arrowRect.top, - arrowRect.bottom, arrowRect.left, arrowRect.right); -#endif - } - } - if (mtdPtr->virtualMenuBottom + scrollAmt > menuRectPtr->bottom) { - arrowRect = bounds; - arrowRect.bottom -= 1; - arrowRect.top = arrowRect.bottom - arrowHeight; - eraseRect = arrowRect; - eraseRect.bottom = menuRectPtr->bottom; - menuClipRect.bottom = arrowRect.top; - if (!hasBottomScroll) { - ChkErr(EraseMenuBackground, menu, &eraseRect, - macMDEFDrawable.context); - ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect, - mtdPtr->virtualMenuTop + scrollAmt, - mtdPtr->virtualMenuBottom + scrollAmt, - menuState, kThemeMenuItemScrollDownArrow, NULL, 0); -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("downArrow: %d - %d, %d - %d", arrowRect.top, - arrowRect.bottom, arrowRect.left, arrowRect.right); -#endif - } - } - TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable, - menuClipRect.left, menuClipRect.top, menuClipRect.right - - menuClipRect.left, menuClipRect.bottom - menuClipRect.top); - TkActivateMenuEntry(menuPtr, -1); - if (oldItem >= 0) { - AppearanceEntryDrawWrapper(menuPtr->entries[oldItem], menuRectPtr, - mtdPtr, (Drawable) &macMDEFDrawable, &fontMetrics, - menuFont, 1); - } - ChkErr(ScrollMenuImage, menu, &menuClipRect, 0, scrollAmt, - macMDEFDrawable.context); - mtdPtr->virtualMenuTop += scrollAmt; - mtdPtr->virtualMenuBottom += scrollAmt; - scrolledMenuClipRect = menuClipRect; - OffsetRect(&scrolledMenuClipRect, 0, scrollAmt); - menuClipRect = bounds; - if (mtdPtr->virtualMenuTop < menuRectPtr->top) { - menuClipRect.top += arrowHeight; - } - if (mtdPtr->virtualMenuBottom > menuRectPtr->bottom) { - menuClipRect.bottom -= arrowHeight; - } - TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable, - menuClipRect.left, menuClipRect.top, menuClipRect.right - - menuClipRect.left, menuClipRect.bottom - menuClipRect.top); - if (scrolledMenuClipRect.bottom < menuClipRect.bottom) { - menuClipRect.top = scrolledMenuClipRect.bottom; - } else if (scrolledMenuClipRect.top < menuClipRect.top) { - menuClipRect.bottom = scrolledMenuClipRect.top; - } - for (i = 0; i < menuPtr->numEntries; i++) { - mePtr = menuPtr->entries[i]; - if (mtdPtr->virtualMenuTop + mePtr->y + mePtr->height < - menuClipRect.top || mtdPtr->virtualMenuTop + mePtr->y > - menuClipRect.bottom) { - continue; - } -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("Drawing item %i", i); -#endif - AppearanceEntryDrawWrapper(mePtr, menuRectPtr, mtdPtr, - (Drawable) &macMDEFDrawable, &fontMetrics, menuFont, 1); - } - Delay(scrollDelay, NULL); - } - mtdPtr->itemSelected = newItem + 1; - mtdPtr->itemUnderMouse = itemUnderMouse + 1; - mtdPtr->itemRect = itemRect; } /* *---------------------------------------------------------------------- * - * HandleMenuPopUpMsg -- + * TkMacOSXSetHelpMenuItemCount -- * - * Handles the MenuDefProc's PopUp message. The menu is - * posted with the selected item at the point given in hitPt. + * Has to be called after the first call to InsertMenu. Sets up the + * global variable for the number of items in the unmodified help menu. + * NB. Nobody uses this any more, since you can get the number of system + * help items from HMGetHelpMenu trivially. But it is in the stubs + * table... * * Results: - * A menu is posted. + * None. * * Side effects: - * None. + * Nothing. * *---------------------------------------------------------------------- */ + void -HandleMenuPopUpMsg( - MenuRef menu, - Rect *menuRectPtr, - Point hitPt, - SInt16 *whichItem, - TkMenu *menuPtr) +TkMacOSXSetHelpMenuItemCount(void) { - int maxMenuHeight; - int oldItem; - Rect portRect; - BitMap screenBits; - static SInt16 menuBarHeight = 0; - -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("MDEF: PopUpMsg"); -#endif - - if (!menuBarHeight) { - ChkErr(GetThemeMenuBarHeight, &menuBarHeight); - } - GetQDGlobalsScreenBits(&screenBits); - - /* - * Note that for some oddball reason, h and v are reversed in the - * point given to us by the MDEF. - */ - - oldItem = *whichItem; - if (oldItem >= menuPtr->numEntries) { - oldItem = -1; - } - portRect.top = 0; - portRect.bottom = 1280; - maxMenuHeight = screenBits.bounds.bottom - screenBits.bounds.top - - menuBarHeight - SCREEN_MARGIN; - if (menuPtr->totalHeight > maxMenuHeight) { - menuRectPtr->top = menuBarHeight; - } else { - int delta; - - menuRectPtr->top = hitPt.h; - if (oldItem >= 0) { - menuRectPtr->top -= menuPtr->entries[oldItem]->y; - } - - if (menuRectPtr->top < menuBarHeight) { - /* - * Displace downward if the menu would stick off the top of the - * screen. - */ - - menuRectPtr->top = menuBarHeight + SCREEN_MARGIN; - } else { - /* - * Or upward if the menu sticks off the bottom end... - */ - - delta = menuRectPtr->top + menuPtr->totalHeight - maxMenuHeight; - if (delta > 0) { - menuRectPtr->top -= delta; - } - } - } - menuRectPtr->left = hitPt.v; - menuRectPtr->right = menuRectPtr->left + menuPtr->totalWidth; - menuRectPtr->bottom = menuRectPtr->top + - ((maxMenuHeight < menuPtr->totalHeight) - ? maxMenuHeight : menuPtr->totalHeight); - if (menuRectPtr->top == menuBarHeight) { - *whichItem = hitPt.h; - } else { - *whichItem = menuRectPtr->top; - } } /* *---------------------------------------------------------------------- * - * HandleMenuCalcItemMsg -- + * TkMacOSXMenuClick -- * - * Handles the MenuDefProc's CalcItem message. It is supposed - * to calculate the Rect of the menu entry in whichItem in the - * menu, and put that in menuRectPtr. I assume this works, but I - * have never seen the MenuManager send this message. + * Prepares a menubar for MenuSelect or MenuKey. * * Results: - * The Menu Manager is informed of the bounding rect of a - * menu rect. + * None. * * Side effects: - * None. + * Any pending configurations of the menubar are completed. * *---------------------------------------------------------------------- */ void -HandleMenuCalcItemMsg( - MenuRef menu, - Rect *menuRectPtr, - Point hitPt, - SInt16 *whichItem, - TkMenu *menuPtr) +TkMacOSXMenuClick(void) { - TkMenuEntry *mePtr; - MenuTrackingData mtd, *mtdPtr = &mtd; - OSStatus err; - int virtualTop, item = *whichItem-1; - - err = ChkErr(GetMenuTrackingData, menu, mtdPtr); - if (err == noErr) { - virtualTop = mtdPtr->virtualMenuTop; - } else { - virtualTop = 0; - } - - if (item >= 0 && item < menuPtr->numEntries) { - mePtr = menuPtr->entries[item]; - menuRectPtr->left = mePtr->x; - menuRectPtr->top = mePtr->y + virtualTop; - if (mePtr->entryFlags & ENTRY_LAST_COLUMN) { - menuRectPtr->right = menuPtr->totalWidth; - } else { - menuRectPtr->right = mePtr->x + mePtr->width; - } - menuRectPtr->bottom = menuRectPtr->top + mePtr->height; - } -#ifdef TK_MAC_DEBUG_MENUS - TkMacOSXDbgMsg("MDEF: CalcItemMsg %d: %d, %d", *whichItem, - menuRectPtr->left, menuRectPtr->top); -#endif } -#endif /* USE_TK_MDEF */ + +/* + * Local Variables: + * mode: objc + * c-basic-offset: 4 + * fill-column: 79 + * coding: utf-8 + * End: + */ |