tkMacOSXMenu.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:129k
源码类别:

通讯编程

开发平台:

Visual C++

  1.     } else {
  2. if (!geometryPtr->accelGlyph) {
  3.     width = Tk_TextWidth(tkfont, accel +
  4.     geometryPtr->accelTextStart, mePtr->accelLength -
  5.     geometryPtr->accelTextStart);
  6. }
  7. if (width < maxWidth) {
  8.     *textWidthPtr = maxWidth;
  9. } else {
  10.     *textWidthPtr = width;
  11. }
  12. if (geometryPtr->modifierNum) {
  13.     *modWidthPtr = geometryPtr->modifierWidth;
  14. }
  15.     }
  16. } else {
  17.     *textWidthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength);
  18. }
  19.     }
  20. }
  21. /*
  22.  *----------------------------------------------------------------------
  23.  *
  24.  * GetTearoffEntryGeometry --
  25.  *
  26.  * Gets the width and height of of a tearoff entry.
  27.  *
  28.  * Results:
  29.  * widthPtr and heightPtr are set.
  30.  *
  31.  * Side effects:
  32.  * None.
  33.  *
  34.  *----------------------------------------------------------------------
  35.  */
  36. void
  37. GetTearoffEntryGeometry (
  38.     TkMenu *menuPtr, /* The menu we are drawing */
  39.     TkMenuEntry *mePtr, /* The entry we are measuring */
  40.     Tk_Font tkfont, /* The precalculated font */
  41.     const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */
  42.     int *widthPtr, /* The resulting width */
  43.     int *heightPtr) /* The resulting height */
  44. {
  45. #ifdef USE_TK_MDEF
  46.     const int useMDEF = ((MacMenu *) menuPtr->platformData)->useMDEF;
  47. #endif
  48.     if (useMDEF && menuPtr->menuType != TEAROFF_MENU) {
  49. *heightPtr = fmPtr->linespace + menuItemExtraHeight;
  50. *widthPtr = menuPtr->totalWidth;
  51.     } else {
  52. *widthPtr = *heightPtr = 0;
  53.     }
  54. }
  55. /*
  56.  *----------------------------------------------------------------------
  57.  *
  58.  * GetMenuSeparatorGeometry --
  59.  *
  60.  * Gets the width and height of menu separator.
  61.  *
  62.  * Results:
  63.  * widthPtr and heightPtr are set.
  64.  *
  65.  * Side effects:
  66.  * None.
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70. void
  71. GetMenuSeparatorGeometry(
  72.     TkMenu *menuPtr, /* The menu we are drawing */
  73.     TkMenuEntry *mePtr, /* The entry we are measuring */
  74.     Tk_Font tkfont, /* The precalculated font */
  75.     const Tk_FontMetrics *fmPtr,/* The precalcualted font metrics */
  76.     int *widthPtr, /* The resulting width */
  77.     int *heightPtr) /* The resulting height */
  78. {
  79.     *widthPtr = 0;
  80.     *heightPtr = menuSeparatorHeight;
  81. }
  82. /*
  83.  *----------------------------------------------------------------------
  84.  *
  85.  * DrawMenuEntryIndicator --
  86.  *
  87.  * This procedure draws the indicator part of a menu.
  88.  *
  89.  * Results:
  90.  * None.
  91.  *
  92.  * Side effects:
  93.  * Commands are output to X to display the menu in its
  94.  * current mode.
  95.  *
  96.  *----------------------------------------------------------------------
  97.  */
  98. void
  99. DrawMenuEntryIndicator(
  100.     TkMenu *menuPtr, /* The menu we are drawing */
  101.     TkMenuEntry *mePtr, /* The entry we are drawing */
  102.     Drawable d, /* The drawable we are drawing */
  103.     GC gc, /* The GC we are drawing with */
  104.     GC indicatorGC, /* The GC to use for the indicator */
  105.     Tk_Font tkfont, /* The precalculated font */
  106.     const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */
  107.     int x, /* topleft hand corner of entry */
  108.     int y, /* topleft hand corner of entry */
  109.     int width, /* width of entry */
  110.     int height) /* height of entry */
  111. {
  112.     if ((mePtr->type == CHECK_BUTTON_ENTRY) ||
  113.     (mePtr->type == RADIO_BUTTON_ENTRY)) {
  114. if (mePtr->indicatorOn && (mePtr->entryFlags & ENTRY_SELECTED)) {
  115.     short mark;
  116.     int baseline = y + (height + fmPtr->ascent - fmPtr->descent)/2;
  117.     GetItemMark(((MacMenu *) menuPtr->platformData)->menuHdl,
  118.     mePtr->index + 1, &mark);
  119.     if (IS_THEME_MENU_FONT(tkfont)) {
  120. ThemeFontID font = kThemeMenuItemMarkFont;
  121. TextEncoding encoding = GetApplicationTextEncoding();
  122. CFStringRef cfStr;
  123. ThemeDrawState drawState;
  124. Rect bounds = {y, x + menuMarkIndent, y + height, x + width};
  125. if (mark < kSpaceCharCode) {
  126.     font = kThemeMenuItemCmdKeyFont;
  127.     encoding = kTextEncodingMacKeyboardGlyphs;
  128. }
  129. switch (mePtr->state) {
  130.     case ENTRY_ACTIVE:
  131. drawState = kThemeStatePressed;
  132. break;
  133.     case ENTRY_DISABLED:
  134. drawState = kThemeStateInactive;
  135. break;
  136.     default:
  137. drawState = kThemeStateActive;
  138. break;
  139. }
  140. cfStr = CFStringCreateWithBytes(NULL, (UInt8*)&mark, 1,
  141. encoding, false);
  142. if (cfStr) {
  143.     DrawThemeText(d, gc, cfStr, font, drawState, &bounds,
  144.     baseline, teFlushDefault);
  145.     CFRelease(cfStr);
  146. }
  147.     } else if (mark != 0) {
  148. const char *markUtf = NULL;
  149. int len;
  150. len = GetUtfMarkCharacter(mark, &markUtf);
  151. Tk_DrawChars(menuPtr->display, d, gc, tkfont, markUtf, len,
  152.     x + menuMarkIndent, baseline);
  153.     }
  154. }
  155.     }
  156. }
  157. #ifdef USE_TK_MDEF
  158. /*
  159.  *----------------------------------------------------------------------
  160.  *
  161.  * DrawMenuBackground --
  162.  *
  163.  * If Appearance is present, draws the Appearance background
  164.  *
  165.  * Results:
  166.  * Nothing
  167.  *
  168.  * Side effects:
  169.  * Commands are output to X to display the menu in its
  170.  * current mode.
  171.  *
  172.  *----------------------------------------------------------------------
  173.  */
  174. void
  175. DrawMenuBackground(
  176.     TkMenu *menuPtr,
  177.     Rect     *menuRectPtr, /* The menu rect */
  178.     Drawable d) /* What we are drawing into */
  179. {
  180.     Tk_3DBorder border;
  181.     EraseMenuBackground(((MacMenu *) menuPtr->platformData)->menuHdl,
  182.     menuRectPtr, ((MacDrawable*)d)->context);
  183.     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
  184.     Tk_Fill3DRectangle(menuPtr->tkwin, d, border,
  185.     menuRectPtr->left, menuRectPtr->top,
  186.     menuRectPtr->right - menuRectPtr->left,
  187.     menuRectPtr->bottom - menuRectPtr->top, 0, TK_RELIEF_FLAT);
  188. }
  189. #endif /* USE_TK_MDEF */
  190. /*
  191.  *----------------------------------------------------------------------
  192.  *
  193.  * DrawMenuEntryAccelerator --
  194.  *
  195.  * This procedure draws the accelerator part of a menu.
  196.  *
  197.  * Results:
  198.  * None.
  199.  *
  200.  * Side effects:
  201.  * Commands are output to X to display the menu in its
  202.  * current mode.
  203.  *
  204.  *----------------------------------------------------------------------
  205.  */
  206. void
  207. DrawMenuEntryAccelerator(
  208.     TkMenu *menuPtr, /* The menu we are drawing */
  209.     TkMenuEntry *mePtr, /* The entry we are drawing */
  210.     Drawable d, /* The drawable we are drawing in */
  211.     GC gc, /* The gc to draw into */
  212.     Tk_Font tkfont, /* The precalculated font */
  213.     const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */
  214.     Tk_3DBorder activeBorder, /* border for menu background */
  215.     int x, /* The left side of the entry */
  216.     int y, /* The top of the entry */
  217.     int width, /* The width of the entry */
  218.     int height, /* The height of the entry */
  219.     int drawArrow) /* Whether or not to draw cascade arrow */
  220. {
  221.     if (mePtr->type != CASCADE_ENTRY && mePtr->accelLength > 0) {
  222. const char *accel = (mePtr->accelPtr == NULL) ? ""
  223. : Tcl_GetString(mePtr->accelPtr);
  224. EntryGeometry *geometryPtr = (EntryGeometry*)mePtr->platformEntryData;
  225. int leftEdge = x + width - geometryPtr->accelTextWidth;
  226. int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  227. if (IS_THEME_MENU_FONT(tkfont)) {
  228.     CFStringRef cfStr;
  229.     ThemeDrawState drawState;
  230.     switch (mePtr->state) {
  231. case ENTRY_ACTIVE:
  232.     drawState = kThemeStatePressed;
  233.     break;
  234. case ENTRY_DISABLED:
  235.     drawState = kThemeStateInactive;
  236.     break;
  237. default:
  238.     drawState = kThemeStateActive;
  239.     break;
  240.     }
  241.     if ((mePtr->entryFlags & ENTRY_ACCEL_MASK) == 0) {
  242. leftEdge -= geometryPtr->modifierWidth;
  243.     }
  244.     if (geometryPtr->accelGlyph) {
  245. Rect bounds = {y, leftEdge, y + height, leftEdge +
  246. geometryPtr->accelTextWidth};
  247. cfStr = CFStringCreateWithBytes(NULL,
  248. (UInt8*)&geometryPtr->accelGlyph, 1,
  249. kTextEncodingMacKeyboardGlyphs, false);
  250. if (cfStr) {
  251.     DrawThemeText(d, gc, cfStr, kThemeMenuItemCmdKeyFont,
  252.     drawState, &bounds, baseline, teFlushDefault);
  253.     CFRelease(cfStr);
  254. }
  255.     } else {
  256. Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel + 
  257. geometryPtr->accelTextStart, mePtr->accelLength -
  258. geometryPtr->accelTextStart, leftEdge, baseline);
  259.     }
  260.     if (geometryPtr->modifierNum) {
  261. Rect bounds = {y, leftEdge - geometryPtr->modifierWidth,
  262. y + height, leftEdge};
  263. cfStr = CFStringCreateWithCharacters(NULL,
  264. geometryPtr->modifierUniChars,
  265. geometryPtr->modifierNum);
  266. if (cfStr) {
  267.     DrawThemeText(d, gc, cfStr, kThemeMenuItemCmdKeyFont,
  268.     drawState, &bounds, baseline, teFlushDefault);
  269.     CFRelease(cfStr);
  270. }
  271.     }
  272. } else {
  273.     Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel,
  274.     mePtr->accelLength, leftEdge, baseline);
  275. }
  276.     }
  277. }
  278. /*
  279.  *----------------------------------------------------------------------
  280.  *
  281.  * DrawMenuSeparator --
  282.  *
  283.  * The menu separator is drawn.
  284.  *
  285.  * Results:
  286.  * None.
  287.  *
  288.  * Side effects:
  289.  * Commands are output to X to display the menu in its
  290.  * current mode.
  291.  *
  292.  *----------------------------------------------------------------------
  293.  */
  294. void
  295. DrawMenuSeparator(
  296.     TkMenu *menuPtr, /* The menu we are drawing */
  297.     TkMenuEntry *mePtr, /* The entry we are drawing */
  298.     Drawable d, /* The drawable we are drawing into */
  299.     GC gc, /* The gc we are drawing with */
  300.     Tk_Font tkfont, /* The precalculated font */
  301.     const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */
  302.     int x, /* left coordinate of entry */
  303.     int y, /* top coordinate of entry */
  304.     int width, /* width of entry */
  305.     int height) /* height of entry */
  306. {
  307.     TkMacOSXDrawingContext dc;
  308.     Rect r;
  309.     r.top = y;
  310.     r.left = x;
  311.     r.bottom = y + height;
  312.     r.right = x + width;
  313.     if (TkMacOSXSetupDrawingContext(d, gc, 1, &dc)) {
  314. ChkErr(DrawThemeMenuSeparator, &r);
  315. TkMacOSXRestoreDrawingContext(&dc);
  316.     }
  317. }
  318. #ifdef USE_TK_MDEF
  319. /*
  320.  *----------------------------------------------------------------------
  321.  *
  322.  * AppearanceEntryDrawWrapper --
  323.  *
  324.  * It routes to the Appearance Managers DrawThemeEntry, which will
  325.  * then call us back after setting up the drawing context.
  326.  *
  327.  * Results:
  328.  * A menu entry is drawn
  329.  *
  330.  * Side effects:
  331.  * None
  332.  *
  333.  *----------------------------------------------------------------------
  334.  */
  335. void
  336. AppearanceEntryDrawWrapper(
  337.     TkMenuEntry *mePtr,
  338.     Rect *menuRectPtr,
  339.     MenuTrackingData *mtdPtr,
  340.     Drawable d,
  341.     Tk_FontMetrics *fmPtr,
  342.     Tk_Font tkfont,
  343.     int erase)
  344. {
  345.     MenuEntryUserData meData;
  346.     Rect itemRect;
  347.     ThemeMenuState theState;
  348.     ThemeMenuItemType theType;
  349.     Tk_FontMetrics entryMetrics;
  350.     meData.mePtr = mePtr;
  351.     meData.mdefDrawable = d;
  352.     if (mePtr->fontPtr == NULL) {
  353. meData.fmPtr = fmPtr;
  354. meData.tkfont = tkfont;
  355.     } else {
  356. meData.tkfont = Tk_GetFontFromObj(mePtr->menuPtr->tkwin,
  357. mePtr->fontPtr);
  358. Tk_GetFontMetrics(meData.tkfont, &entryMetrics);
  359. fmPtr = &entryMetrics;
  360.     }
  361.     itemRect.left = menuRectPtr->left + mePtr->x;
  362.     itemRect.top = mtdPtr->virtualMenuTop + mePtr->y;
  363.     itemRect.right = mePtr->entryFlags & ENTRY_LAST_COLUMN ?
  364.     menuRectPtr->right : itemRect.left + mePtr->width;
  365.     itemRect.bottom = itemRect.top + mePtr->height;
  366.     if (mePtr->state == ENTRY_ACTIVE) {
  367. theState = kThemeMenuSelected;
  368.     } else if (mePtr->state == ENTRY_DISABLED) {
  369. theState = kThemeMenuDisabled;
  370.     } else {
  371. theState = kThemeMenuActive;
  372.     }
  373.     if (mePtr->type == CASCADE_ENTRY) {
  374. theType = kThemeMenuItemHierarchical;
  375.     } else {
  376. theType = kThemeMenuItemPlain;
  377.     }
  378.     if (erase) {
  379. DisableScreenUpdates();
  380. DrawMenuBackground(mePtr->menuPtr, &itemRect, d);
  381.     }
  382.     DrawThemeMenuItem(menuRectPtr, &itemRect,
  383. mtdPtr->virtualMenuTop, mtdPtr->virtualMenuBottom, theState,
  384. theType | kThemeMenuItemNoBackground, tkThemeMenuItemDrawingUPP,
  385. (unsigned long) &meData);
  386.     if (erase) {
  387. EnableScreenUpdates();
  388.     }
  389. }
  390. /*
  391.  *----------------------------------------------------------------------
  392.  *
  393.  * ThemeMenuItemDrawingProc --
  394.  *
  395.  * This routine is called from the Appearance DrawThemeMenuEntry
  396.  *
  397.  * Results:
  398.  * A menu entry is drawn
  399.  *
  400.  * Side effects:
  401.  * None
  402.  *
  403.  *----------------------------------------------------------------------
  404.  */
  405. pascal void
  406. ThemeMenuItemDrawingProc(
  407.     const Rect *inBounds,
  408.     SInt16 inDepth,
  409.     Boolean inIsColorDevice,
  410.     SInt32 inUserData)
  411. {
  412.     MenuEntryUserData *meData = (MenuEntryUserData *) inUserData;
  413.     TkpDrawMenuEntry(meData->mePtr, meData->mdefDrawable, meData->tkfont,
  414.     meData->fmPtr, inBounds->left, inBounds->top, inBounds->right -
  415.     inBounds->left + menuItemExtraWidth, inBounds->bottom -
  416.     inBounds->top + menuItemExtraHeight, 0, 1);
  417. }
  418. #endif /* USE_TK_MDEF */
  419. /*
  420.  *----------------------------------------------------------------------
  421.  *
  422.  * TkMacOSXHandleTearoffMenu() --
  423.  *
  424.  * This routine sees if the MDEF has set a menu and a mouse position
  425.  * for tearing off and makes a tearoff menu if it has.
  426.  *
  427.  * Results:
  428.  * menuPtr->interp will have the result of the tearoff command.
  429.  *
  430.  * Side effects:
  431.  * A new tearoff menu is created if it is supposed to be.
  432.  *
  433.  *----------------------------------------------------------------------
  434.  */
  435. void
  436. TkMacOSXHandleTearoffMenu(void)
  437. {
  438.     /*
  439.      * Obsolete: Nothing to do.
  440.      */
  441. }
  442. /*
  443.  *--------------------------------------------------------------
  444.  *
  445.  * TkpInitializeMenuBindings --
  446.  *
  447.  * For every interp, initializes the bindings for Windows
  448.  * menus. Does nothing on Mac or XWindows.
  449.  *
  450.  * Results:
  451.  * None.
  452.  *
  453.  * Side effects:
  454.  * C-level bindings are setup for the interp which will
  455.  * handle Alt-key sequences for menus without beeping
  456.  * or interfering with user-defined Alt-key bindings.
  457.  *
  458.  *--------------------------------------------------------------
  459.  */
  460. void
  461. TkpInitializeMenuBindings(
  462.     Tcl_Interp *interp, /* The interpreter to set. */
  463.     Tk_BindingTable bindingTable)
  464. /* The table to add to. */
  465. {
  466.     /*
  467.      * Nothing to do.
  468.      */
  469. }
  470. /*
  471.  *--------------------------------------------------------------
  472.  *
  473.  * TkpComputeMenubarGeometry --
  474.  *
  475.  * This procedure is invoked to recompute the size and
  476.  * layout of a menu that is a menubar clone.
  477.  *
  478.  * Results:
  479.  * None.
  480.  *
  481.  * Side effects:
  482.  * Fields of menu entries are changed to reflect their
  483.  * current positions, and the size of the menu window
  484.  * itself may be changed.
  485.  *
  486.  *--------------------------------------------------------------
  487.  */
  488. void
  489. TkpComputeMenubarGeometry(
  490.     TkMenu *menuPtr) /* Structure describing menu. */
  491. {
  492.     TkpComputeStandardMenuGeometry(menuPtr);
  493. }
  494. /*
  495.  *----------------------------------------------------------------------
  496.  *
  497.  * DrawTearoffEntry --
  498.  *
  499.  * This procedure draws a tearoff entry.
  500.  *
  501.  * Results:
  502.  * None.
  503.  *
  504.  * Side effects:
  505.  * Commands are output to X to display the menu in its
  506.  * current mode.
  507.  *
  508.  *----------------------------------------------------------------------
  509.  */
  510. void
  511. DrawTearoffEntry(
  512.     TkMenu *menuPtr, /* The menu we are drawing */
  513.     TkMenuEntry *mePtr, /* The entry we are drawing */
  514.     Drawable d, /* The drawable we are drawing into */
  515.     GC gc, /* The gc we are drawing with */
  516.     Tk_Font tkfont, /* The font we are drawing with */
  517.     const Tk_FontMetrics *fmPtr,/* The metrics we are drawing with */
  518.     int x, /* Left edge of entry. */
  519.     int y, /* Top edge of entry. */
  520.     int width, /* Width of entry. */
  521.     int height) /* Height of entry. */
  522. {
  523.     XPoint points[2];
  524.     int margin, segmentWidth, maxX;
  525.     Tk_3DBorder border;
  526.     if (menuPtr->menuType != MASTER_MENU ) {
  527. return;
  528.     }
  529.     margin = fmPtr->linespace/2;
  530.     points[0].x = x;
  531.     points[0].y = y + height/2;
  532.     points[1].y = points[0].y;
  533.     segmentWidth = 6;
  534.     maxX  = x + menuPtr->totalWidth - 1;
  535.     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
  536.     while (points[0].x < maxX) {
  537. points[1].x = points[0].x + segmentWidth;
  538. if (points[1].x > maxX) {
  539.     points[1].x = maxX;
  540. }
  541. Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
  542. TK_RELIEF_RAISED);
  543. points[0].x += 2*segmentWidth;
  544.     }
  545. }
  546. /*
  547.  *----------------------------------------------------------------------
  548.  *
  549.  * TkMacOSXSetHelpMenuItemCount --
  550.  *
  551.  * Has to be called after the first call to InsertMenu. Sets
  552.  * up the global variable for the number of items in the
  553.  * unmodified help menu.
  554.  * NB. Nobody uses this any more, since you can get the number
  555.  * of system help items from HMGetHelpMenu trivially.
  556.  * But it is in the stubs table...
  557.  *
  558.  * Results:
  559.  * None.
  560.  *
  561.  * Side effects:
  562.  * Nothing.
  563.  *
  564.  *----------------------------------------------------------------------
  565.  */
  566. void
  567. TkMacOSXSetHelpMenuItemCount(void)
  568. {
  569.     /*
  570.      * Obsolete: Nothing to do.
  571.      */
  572. }
  573. /*
  574.  *----------------------------------------------------------------------
  575.  *
  576.  * TkMacOSXMenuClick --
  577.  *
  578.  * Prepares a menubar for MenuSelect or MenuKey.
  579.  *
  580.  * Results:
  581.  * None.
  582.  *
  583.  * Side effects:
  584.  * Any pending configurations of the menubar are completed.
  585.  *
  586.  *----------------------------------------------------------------------
  587.  */
  588. void
  589. TkMacOSXMenuClick(void)
  590. {
  591.     TkMenu *menuPtr;
  592.     TkMenuReferences *menuRefPtr;
  593.     if ((currentMenuBarInterp != NULL) && (currentMenuBarName != NULL)) {
  594. menuRefPtr = TkFindMenuReferences(currentMenuBarInterp,
  595. currentMenuBarName);
  596. for (menuPtr = menuRefPtr->menuPtr->masterMenuPtr;
  597. menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) {
  598.     if (menuPtr->menuType == MENUBAR) {
  599. CompleteIdlers(menuPtr);
  600. break;
  601.     }
  602. }
  603.     }
  604.     if (menuBarFlags & MENUBAR_REDRAW_PENDING) {
  605. Tcl_CancelIdleCall(DrawMenuBarWhenIdle, NULL);
  606. DrawMenuBarWhenIdle(NULL);
  607.     }
  608. }
  609. /*
  610.  *----------------------------------------------------------------------
  611.  *
  612.  * TkpDrawMenuEntry --
  613.  *
  614.  * Draws the given menu entry at the given coordinates with the
  615.  * given attributes.
  616.  *
  617.  * Results:
  618.  * None.
  619.  *
  620.  * Side effects:
  621.  * X Server commands are executed to display the menu entry.
  622.  *
  623.  *----------------------------------------------------------------------
  624.  */
  625. void
  626. TkpDrawMenuEntry(
  627.     TkMenuEntry *mePtr, /* The entry to draw */
  628.     Drawable d, /* What to draw into */
  629.     Tk_Font tkfont, /* Precalculated font for menu */
  630.     const Tk_FontMetrics *menuMetricsPtr,
  631. /* Precalculated metrics for menu */
  632.     int x, /* X-coordinate of topleft of entry */
  633.     int y, /* Y-coordinate of topleft of entry */
  634.     int width, /* Width of the entry rectangle */
  635.     int height, /* Height of the current rectangle */
  636.     int strictMotif, /* Boolean flag */
  637.     int drawArrow) /* Whether or not to draw the cascade
  638.  * arrow for cascade items. Only applies
  639.  * to Windows. */
  640. {
  641.     GC gc;
  642.     TkMenu *menuPtr = mePtr->menuPtr;
  643.     int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
  644.     GC indicatorGC;
  645.     Tk_3DBorder bgBorder, activeBorder;
  646.     const Tk_FontMetrics *fmPtr;
  647.     Tk_FontMetrics entryMetrics;
  648.     int adjustedY = y + padY;
  649.     int adjustedHeight = height - 2 * padY;
  650.     /*
  651.      * Choose the gc for drawing the foreground part of the entry.
  652.      * Under Appearance, we pass a null (appearanceGC) to tell
  653.      * ourselves not to change whatever color the appearance manager has set.
  654.      */
  655.     if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) {
  656. gc = mePtr->activeGC;
  657. if (gc == NULL) {
  658.     gc = menuPtr->activeGC;
  659. }
  660.     } else {
  661. TkMenuEntry *parentEntryPtr = GetParentMenuEntry(menuPtr);
  662. if (((parentEntryPtr && parentEntryPtr->state == ENTRY_DISABLED) ||
  663. (mePtr->state == ENTRY_DISABLED)) &&
  664. (menuPtr->disabledFgPtr != NULL)) {
  665.     gc = mePtr->disabledGC;
  666.     if (gc == NULL) {
  667. gc = menuPtr->disabledGC;
  668.     }
  669. } else {
  670.     gc = mePtr->textGC;
  671.     if (gc == NULL) {
  672. gc = menuPtr->textGC;
  673.     }
  674. }
  675.     }
  676.     indicatorGC = mePtr->indicatorGC;
  677.     if (indicatorGC == NULL) {
  678. indicatorGC = menuPtr->indicatorGC;
  679.     }
  680.     bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
  681.     (mePtr->borderPtr == NULL)
  682.     ? menuPtr->borderPtr : mePtr->borderPtr);
  683.     if (strictMotif) {
  684. activeBorder = bgBorder;
  685.     } else {
  686. activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
  687.     (mePtr->activeBorderPtr == NULL)
  688.     ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr);
  689.     }
  690.     if (mePtr->fontPtr == NULL) {
  691. fmPtr = menuMetricsPtr;
  692.     } else {
  693. tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
  694. Tk_GetFontMetrics(tkfont, &entryMetrics);
  695. fmPtr = &entryMetrics;
  696.     }
  697.     /*
  698.      * Need to draw the entire background, including padding. On Unix,
  699.      * for menubars, we have to draw the rest of the entry taking
  700.      * into account the padding.
  701.      */
  702.     DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y,
  703.     width, height);
  704.     if (mePtr->type == SEPARATOR_ENTRY) {
  705. DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont,
  706. fmPtr, x, adjustedY, width, adjustedHeight);
  707.     } else if (mePtr->type == TEAROFF_ENTRY) {
  708. DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  709. width, adjustedHeight);
  710.     } else {
  711. DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x,
  712. adjustedY, width, adjustedHeight);
  713. DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
  714. activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
  715. if (!mePtr->hideMargin) {
  716.     DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
  717.     fmPtr, x, adjustedY, width, adjustedHeight);
  718. }
  719.     }
  720. }
  721. /*
  722.  *--------------------------------------------------------------
  723.  *
  724.  * TkpComputeStandardMenuGeometry --
  725.  *
  726.  * This procedure is invoked to recompute the size and
  727.  * layout of a menu that is not a menubar clone.
  728.  *
  729.  * Results:
  730.  * None.
  731.  *
  732.  * Side effects:
  733.  * Fields of menu entries are changed to reflect their
  734.  * current positions, and the size of the menu window
  735.  * itself may be changed.
  736.  *
  737.  *--------------------------------------------------------------
  738.  */
  739. void
  740. TkpComputeStandardMenuGeometry(
  741.     TkMenu *menuPtr) /* Structure describing menu. */
  742. {
  743.     Tk_Font tkfont, menuFont;
  744.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  745.     int x, y, height, modifierWidth, labelWidth, indicatorSpace;
  746.     int windowWidth, windowHeight, accelWidth, maxAccelTextWidth;
  747.     int i, j, lastColumnBreak, maxModifierWidth, maxWidth, nonAccelMargin;
  748.     int maxNonAccelMargin, maxEntryWithAccelWidth, maxEntryWithoutAccelWidth;
  749.     int entryWidth, maxIndicatorSpace, borderWidth, activeBorderWidth;
  750.     TkMenuEntry *mePtr, *columnEntryPtr;
  751.     EntryGeometry *geometryPtr;
  752.     int haveAccel = 0;
  753.     if (menuPtr->tkwin == NULL) {
  754. return;
  755.     }
  756.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
  757.     &borderWidth);
  758.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
  759.     &activeBorderWidth);
  760.     x = y = borderWidth;
  761.     indicatorSpace = labelWidth = accelWidth = maxAccelTextWidth = 0;
  762.     windowHeight = windowWidth = maxWidth = lastColumnBreak = 0;
  763.     maxModifierWidth = nonAccelMargin = maxNonAccelMargin = 0;
  764.     maxEntryWithAccelWidth = maxEntryWithoutAccelWidth = 0;
  765.     maxIndicatorSpace = 0;
  766.     /*
  767.      * On the Mac especially, getting font metrics can be quite slow,
  768.      * so we want to do it intelligently. We are going to precalculate
  769.      * them and pass them down to all of the measuring and drawing
  770.      * routines. We will measure the font metrics of the menu once.
  771.      * If an entry does not have its own font set, then we give
  772.      * the geometry/drawing routines the menu's font and metrics.
  773.      * If an entry has its own font, we will measure that font and
  774.      * give all of the geometry/drawing the entry's font and metrics.
  775.      */
  776.     menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
  777.     Tk_GetFontMetrics(menuFont, &menuMetrics);
  778.     for (i = 0; i < menuPtr->numEntries; i++) {
  779. mePtr = menuPtr->entries[i];
  780. if (mePtr->type == CASCADE_ENTRY || mePtr->accelLength > 0) {
  781.     haveAccel = 1;
  782.     break;
  783. }
  784.     }
  785.     for (i = 0; i < menuPtr->numEntries; i++) {
  786. mePtr = menuPtr->entries[i];
  787. if (mePtr->fontPtr == NULL) {
  788.     tkfont = menuFont;
  789.     fmPtr = &menuMetrics;
  790. } else {
  791.     tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
  792.     Tk_GetFontMetrics(tkfont, &entryMetrics);
  793.     fmPtr = &entryMetrics;
  794. }
  795. if ((i > 0) && mePtr->columnBreak) {
  796.     if (maxIndicatorSpace != 0) {
  797. maxIndicatorSpace += 2;
  798.     }
  799.     for (j = lastColumnBreak; j < i; j++) {
  800. columnEntryPtr = menuPtr->entries[j];
  801. geometryPtr =
  802. (EntryGeometry *) columnEntryPtr->platformEntryData;
  803. columnEntryPtr->indicatorSpace = maxIndicatorSpace;
  804. columnEntryPtr->width = maxIndicatorSpace + maxWidth
  805. + 2 * activeBorderWidth;
  806. geometryPtr->accelTextWidth = maxAccelTextWidth;
  807. geometryPtr->modifierWidth = maxModifierWidth;
  808. columnEntryPtr->x = x;
  809. columnEntryPtr->entryFlags &= ~ENTRY_LAST_COLUMN;
  810. if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) {
  811.     geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth
  812.     - maxEntryWithAccelWidth;
  813.     if (geometryPtr->nonAccelMargin > maxNonAccelMargin) {
  814. geometryPtr->nonAccelMargin = maxNonAccelMargin;
  815.     }
  816. } else {
  817.     geometryPtr->nonAccelMargin = 0;
  818. }
  819.     }
  820.     x += maxIndicatorSpace + maxWidth + 2 * borderWidth;
  821.     windowWidth = x;
  822.     maxWidth = maxIndicatorSpace = maxAccelTextWidth = 0;
  823.     maxModifierWidth = maxNonAccelMargin = maxEntryWithAccelWidth = 0;
  824.     maxEntryWithoutAccelWidth = 0;
  825.     lastColumnBreak = i;
  826.     y = borderWidth;
  827. }
  828. geometryPtr = (EntryGeometry *) mePtr->platformEntryData;
  829. if (mePtr->type == SEPARATOR_ENTRY) {
  830.     GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
  831.     fmPtr, &entryWidth, &height);
  832.     mePtr->height = height;
  833. } else if (mePtr->type == TEAROFF_ENTRY) {
  834.     GetTearoffEntryGeometry(menuPtr, mePtr, tkfont,
  835.     fmPtr, &entryWidth, &height);
  836.     mePtr->height = height;
  837. } else {
  838.     /*
  839.      * For each entry, compute the height required by that
  840.      * particular entry, plus three widths:  the width of the
  841.      * label, the width to allow for an indicator to be displayed
  842.      * to the left of the label (if any), and the width of the
  843.      * accelerator to be displayed to the right of the label
  844.      * (if any). These sizes depend, of course, on the type
  845.      * of the entry.
  846.      */
  847.     GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &labelWidth, &height);
  848.     mePtr->height = height;
  849.     nonAccelMargin = 0;
  850.     if (mePtr->type == CASCADE_ENTRY) {
  851. GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr,
  852. &modifierWidth, &accelWidth, &height);
  853.     } else if (mePtr->accelLength == 0) {
  854. if (haveAccel && !mePtr->hideMargin) {
  855.     if (IS_THEME_MENU_FONT(tkfont)) {
  856. nonAccelMargin = menuSymbols[COMMAND_SYMBOL].width;
  857.     } else {
  858. nonAccelMargin = Tk_TextWidth(tkfont,
  859. menuSymbols[COMMAND_SYMBOL].utf,
  860. menuSymbols[COMMAND_SYMBOL].utfLen);
  861.     }
  862. }
  863. accelWidth = modifierWidth = 0;
  864.     } else {
  865. GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
  866. fmPtr, &modifierWidth, &accelWidth, &height);
  867. if (height > mePtr->height) {
  868.     mePtr->height = height;
  869. }
  870.     }
  871.     if (!(mePtr->hideMargin)) {
  872. GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont,
  873. fmPtr, &indicatorSpace, &height);
  874. if (height > mePtr->height) {
  875.     mePtr->height = height;
  876. }
  877.     } else {
  878. indicatorSpace = 0;
  879.     }
  880.     if (nonAccelMargin > maxNonAccelMargin) {
  881. maxNonAccelMargin = nonAccelMargin;
  882.     }
  883.     if (accelWidth > maxAccelTextWidth) {
  884. maxAccelTextWidth = accelWidth;
  885.     }
  886.     if (modifierWidth > maxModifierWidth) {
  887. maxModifierWidth = modifierWidth;
  888.     }
  889.     if (indicatorSpace > maxIndicatorSpace) {
  890. maxIndicatorSpace = indicatorSpace;
  891.     }
  892.     entryWidth = labelWidth + modifierWidth + accelWidth
  893.     + nonAccelMargin;
  894.     if (entryWidth > maxWidth) {
  895. maxWidth = entryWidth;
  896.     }
  897.     if (mePtr->accelLength > 0) {
  898. if (entryWidth > maxEntryWithAccelWidth) {
  899.     maxEntryWithAccelWidth = entryWidth;
  900. }
  901.     } else {
  902. if (entryWidth > maxEntryWithoutAccelWidth) {
  903.     maxEntryWithoutAccelWidth = entryWidth;
  904. }
  905.     }
  906.     mePtr->height += 2 * activeBorderWidth;
  907. }
  908. mePtr->y = y;
  909. y += menuPtr->entries[i]->height + borderWidth;
  910. if (y > windowHeight) {
  911.     windowHeight = y;
  912. }
  913.     }
  914.     for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
  915. columnEntryPtr = menuPtr->entries[j];
  916. geometryPtr = (EntryGeometry *) columnEntryPtr->platformEntryData;
  917. columnEntryPtr->indicatorSpace = maxIndicatorSpace;
  918. columnEntryPtr->width = maxIndicatorSpace + maxWidth
  919. + 2 * activeBorderWidth;
  920. geometryPtr->accelTextWidth = maxAccelTextWidth;
  921. columnEntryPtr->x = x;
  922. columnEntryPtr->entryFlags |= ENTRY_LAST_COLUMN;
  923. if (maxEntryWithoutAccelWidth > maxEntryWithAccelWidth) {
  924.     geometryPtr->nonAccelMargin = maxEntryWithoutAccelWidth
  925.     - maxEntryWithAccelWidth;
  926.     if (geometryPtr->nonAccelMargin > maxNonAccelMargin) {
  927. geometryPtr->nonAccelMargin = maxNonAccelMargin;
  928.     }
  929. } else {
  930.     geometryPtr->nonAccelMargin = 0;
  931. }
  932.     }
  933.     windowWidth = x + maxIndicatorSpace + maxWidth
  934.     + 2 * activeBorderWidth + borderWidth;
  935.     windowHeight += borderWidth;
  936.     /*
  937.      * The X server doesn't like zero dimensions, so round up to at least
  938.      * 1 (a zero-sized menu should never really occur, anyway).
  939.      */
  940.     if (windowWidth <= 0) {
  941. windowWidth = 1;
  942.     }
  943.     if (windowHeight <= 0) {
  944. windowHeight = 1;
  945.     }
  946.     menuPtr->totalWidth = windowWidth;
  947.     menuPtr->totalHeight = windowHeight;
  948. }
  949. /*
  950.  *----------------------------------------------------------------------
  951.  *
  952.  * DrawMenuEntryLabel --
  953.  *
  954.  * This procedure draws the label part of a menu.
  955.  *
  956.  * Results:
  957.  * None.
  958.  *
  959.  * Side effects:
  960.  * Commands are output to X to display the menu in its
  961.  * current mode.
  962.  *
  963.  *----------------------------------------------------------------------
  964.  */
  965. void
  966. DrawMenuEntryLabel(
  967.     TkMenu *menuPtr, /* The menu we are drawing */
  968.     TkMenuEntry *mePtr, /* The entry we are drawing */
  969.     Drawable d, /* What we are drawing into */
  970.     GC gc, /* The gc we are drawing into */
  971.     Tk_Font tkfont, /* The precalculated font */
  972.     const Tk_FontMetrics *fmPtr,/* The precalculated font metrics */
  973.     int x, /* left edge */
  974.     int y, /* right edge */
  975.     int width, /* width of entry */
  976.     int height) /* height of entry */
  977. {
  978.     int imageWidth, imageHeight, textWidth = 0, textHeight = 0;
  979.     int indicatorSpace =  mePtr->indicatorSpace;
  980.     int leftEdge = x + indicatorSpace;
  981.     int haveImage = 0, haveText = 0;
  982.     int imageXOffset = 0, imageYOffset = 0;
  983.     int textXOffset = 0, textYOffset = 0;
  984.     Pixmap bitmap = (Pixmap) NULL;
  985.     Tcl_DString itemTextDString;
  986.     /*
  987.      * Work out what we will need to draw first.
  988.      */
  989.     if (mePtr->image != NULL) {
  990. Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
  991. haveImage = 1;
  992.     } else if (mePtr->bitmapPtr != NULL) {
  993. bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
  994. Tk_SizeOfBitmap(menuPtr->display, bitmap, &imageWidth, &imageHeight);
  995. haveImage = 1;
  996.     }
  997.     if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
  998. if (mePtr->labelLength > 0) {
  999.     GetEntryText(mePtr, &itemTextDString);
  1000.     if (mePtr->compound != COMPOUND_NONE) {
  1001. textWidth = Tk_TextWidth(tkfont,
  1002. Tcl_DStringValue(&itemTextDString),
  1003. Tcl_DStringLength(&itemTextDString)) +
  1004. menuTextLeadingEdgeMargin + menuTextTrailingEdgeMargin;
  1005. textHeight = fmPtr->linespace;
  1006.     }
  1007.     haveText = 1;
  1008. }
  1009.     }
  1010.     /*
  1011.      * Now work out what the relative positions are.
  1012.      */
  1013.     if (haveImage && haveText && (mePtr->compound != COMPOUND_NONE)) {
  1014. int fullWidth = (imageWidth > textWidth ? imageWidth : textWidth);
  1015. switch ((enum compound) mePtr->compound) {
  1016.     case COMPOUND_TOP:
  1017. textXOffset = (fullWidth - textWidth)/2;
  1018. textYOffset = imageHeight/2 + 2;
  1019. imageXOffset = (fullWidth - imageWidth)/2;
  1020. imageYOffset = -textHeight/2;
  1021. break;
  1022.     case COMPOUND_BOTTOM:
  1023. textXOffset = (fullWidth - textWidth)/2;
  1024. textYOffset = -imageHeight/2;
  1025. imageXOffset = (fullWidth - imageWidth)/2;
  1026. imageYOffset = textHeight/2 + 2;
  1027. break;
  1028.     case COMPOUND_LEFT:
  1029. /*
  1030.  * Position image in the indicator space to the left of the
  1031.  * entries, unless this entry is a radio|check button because
  1032.  * then the indicator space will be used.
  1033.  */
  1034. textXOffset = imageWidth + 2 - menuTextLeadingEdgeMargin;
  1035. if ((mePtr->type != CHECK_BUTTON_ENTRY)
  1036. && (mePtr->type != RADIO_BUTTON_ENTRY)) {
  1037.     textXOffset -= indicatorSpace;
  1038.     imageXOffset = -indicatorSpace;
  1039. }
  1040. if (textXOffset < 0) {
  1041.     textXOffset = 0;
  1042. }
  1043. break;
  1044.     case COMPOUND_RIGHT:
  1045. imageXOffset = textWidth + 2 - menuTextTrailingEdgeMargin;
  1046. break;
  1047.     case COMPOUND_CENTER:
  1048. textXOffset = (fullWidth - textWidth)/2;
  1049. imageXOffset = (fullWidth - imageWidth)/2;
  1050. break;
  1051.     case COMPOUND_NONE:
  1052.      /*
  1053.       * Never reached.
  1054.       */
  1055. break;
  1056. }
  1057.     }
  1058.     /*
  1059.      * Draw label and/or bitmap or image for entry.
  1060.      */
  1061.     if (mePtr->image != NULL) {
  1062. if ((mePtr->selectImage != NULL)
  1063. && (mePtr->entryFlags & ENTRY_SELECTED)) {
  1064.     Tk_RedrawImage(mePtr->selectImage, 0, 0, imageWidth, imageHeight,
  1065.     d, leftEdge + imageXOffset,
  1066.     y + (mePtr->height - imageHeight)/2 + imageYOffset);
  1067. } else {
  1068.     Tk_RedrawImage(mePtr->image, 0, 0, imageWidth, imageHeight,
  1069.     d, leftEdge + imageXOffset,
  1070.     y + (mePtr->height - imageHeight)/2 + imageYOffset);
  1071. }
  1072.     } else if (mePtr->bitmapPtr != NULL) {
  1073. XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, imageWidth,
  1074. imageHeight, leftEdge + imageXOffset,
  1075. y + (mePtr->height - imageHeight)/2  + imageYOffset, 1);
  1076.     }
  1077.     if (haveText) {
  1078. int baseline = y + (height + fmPtr->ascent - fmPtr->descent)/2;
  1079. Tk_DrawChars(menuPtr->display, d, gc, tkfont,
  1080. Tcl_DStringValue(&itemTextDString),
  1081. Tcl_DStringLength(&itemTextDString),
  1082. leftEdge + menuTextLeadingEdgeMargin + textXOffset,
  1083. baseline + textYOffset);
  1084. Tcl_DStringFree(&itemTextDString);
  1085.     }
  1086.     if (mePtr->state == ENTRY_DISABLED) {
  1087. if (menuPtr->disabledFgPtr == NULL) {
  1088.     /* XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
  1089.     width, height); */
  1090. } else if ((mePtr->image != NULL)
  1091. && (menuPtr->disabledImageGC != None)) {
  1092.     XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  1093.     leftEdge + imageXOffset,
  1094.     y + (mePtr->height - imageHeight)/2 + imageYOffset,
  1095.     imageWidth, imageHeight);
  1096. }
  1097.     }
  1098. }
  1099. /*
  1100.  *----------------------------------------------------------------------
  1101.  *
  1102.  * DrawMenuEntryBackground --
  1103.  *
  1104.  * This procedure draws the background part of a menu entry.
  1105.  * Under Appearance, we only draw the background if the entry's
  1106.  * border is set, we DO NOT inherit it from the menu...
  1107.  *
  1108.  * Results:
  1109.  * None.
  1110.  *
  1111.  * Side effects:
  1112.  * Commands are output to X to display the menu in its
  1113.  * current mode.
  1114.  *
  1115.  *----------------------------------------------------------------------
  1116.  */
  1117. void
  1118. DrawMenuEntryBackground(
  1119.     TkMenu *menuPtr, /* The menu we are drawing. */
  1120.     TkMenuEntry *mePtr, /* The entry we are drawing. */
  1121.     Drawable d, /* What we are drawing into */
  1122.     Tk_3DBorder activeBorder, /* Border for active items */
  1123.     Tk_3DBorder bgBorder, /* Border for the background */
  1124.     int x, /* left edge */
  1125.     int y, /* top edge */
  1126.     int width, /* width of rectangle to draw */
  1127.     int height) /* height of rectangle to draw */
  1128. {
  1129.     if ((menuPtr->menuType == TEAROFF_MENU)
  1130.     || ((mePtr->state == ENTRY_ACTIVE)
  1131.     && (mePtr->activeBorderPtr != None))
  1132.     || ((mePtr->state != ENTRY_ACTIVE) && (mePtr->borderPtr != None))) {
  1133. if (mePtr->state == ENTRY_ACTIVE) {
  1134.     bgBorder = activeBorder;
  1135. }
  1136. Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder,
  1137. x, y, width, height, 0, TK_RELIEF_FLAT);
  1138.     }
  1139. }
  1140. /*
  1141.  *----------------------------------------------------------------------
  1142.  *
  1143.  * GetMenuLabelGeometry --
  1144.  *
  1145.  * Figures out the size of the label portion of a menu item.
  1146.  *
  1147.  * Results:
  1148.  * widthPtr and heightPtr are filled in with the correct geometry
  1149.  * information.
  1150.  *
  1151.  * Side effects:
  1152.  * None.
  1153.  *
  1154.  *----------------------------------------------------------------------
  1155.  */
  1156. void
  1157. GetMenuLabelGeometry(
  1158.     TkMenuEntry *mePtr, /* The entry we are computing */
  1159.     Tk_Font tkfont, /* The precalculated font */
  1160.     const Tk_FontMetrics *fmPtr,/* The precalculated metrics */
  1161.     int *widthPtr, /* The resulting width of the label portion */
  1162.     int *heightPtr) /* The resulting height of the label portion */
  1163. {
  1164.     TkMenu *menuPtr = mePtr->menuPtr;
  1165.     int haveImage = 0, tornOff = (menuPtr->menuType == TEAROFF_MENU);
  1166. #ifdef USE_TK_MDEF
  1167.     const int useMDEF = ((MacMenu *) menuPtr->platformData)->useMDEF;
  1168. #endif
  1169.     if (mePtr->image != NULL && (useMDEF || tornOff)) {
  1170. Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
  1171. haveImage = 1;
  1172.     } else if (mePtr->bitmapPtr != NULL && (useMDEF || tornOff)) {
  1173. Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
  1174. Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr);
  1175. haveImage = 1;
  1176.     }
  1177.     if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
  1178. int textWidth = 0, textHeight = fmPtr->linespace;
  1179. if (mePtr->labelPtr != NULL) {
  1180.     Tcl_DString itemTextDString;
  1181.     GetEntryText(mePtr, &itemTextDString);
  1182.     textWidth = Tk_TextWidth(tkfont,
  1183.     Tcl_DStringValue(&itemTextDString),
  1184.     Tcl_DStringLength(&itemTextDString)) +
  1185.     menuTextLeadingEdgeMargin + menuTextTrailingEdgeMargin;
  1186.     Tcl_DStringFree(&itemTextDString);
  1187.     if (haveImage && (mePtr->compound != COMPOUND_NONE)) {
  1188. switch ((enum compound) mePtr->compound) {
  1189.     int margin;
  1190.     case COMPOUND_TOP:
  1191.     case COMPOUND_BOTTOM:
  1192. if (textWidth > *widthPtr) {
  1193.     *widthPtr = textWidth;
  1194. }
  1195. *heightPtr += textHeight + 2;
  1196. break;
  1197.     case COMPOUND_LEFT:
  1198. margin = *widthPtr + 2;
  1199. if (margin > menuTextLeadingEdgeMargin) {
  1200.     margin = menuTextLeadingEdgeMargin;
  1201. }
  1202. *widthPtr += textWidth + 2 - margin;
  1203. if (textHeight > *heightPtr) {
  1204.     *heightPtr = textHeight;
  1205. }
  1206. break;
  1207.     case COMPOUND_RIGHT:
  1208. margin = menuTextTrailingEdgeMargin;
  1209. *widthPtr += textWidth + 2 - margin;
  1210. if (textHeight > *heightPtr) {
  1211.     *heightPtr = textHeight;
  1212. }
  1213. break;
  1214.     case COMPOUND_CENTER:
  1215. if (textWidth > *widthPtr) {
  1216.     *widthPtr = textWidth;
  1217. }
  1218. if (textHeight > *heightPtr) {
  1219.     *heightPtr = textHeight;
  1220. }
  1221. break;
  1222.     case COMPOUND_NONE:
  1223. /*
  1224.  * Never reached.
  1225.  */
  1226. break;
  1227. }
  1228. goto labelGeomDone;
  1229.     }
  1230. }
  1231. *widthPtr = textWidth;
  1232. *heightPtr = textHeight;
  1233.     }
  1234. labelGeomDone:
  1235.     *heightPtr += menuItemExtraHeight;
  1236.     *widthPtr += menuItemExtraWidth;
  1237. }
  1238. /*
  1239.  *----------------------------------------------------------------------
  1240.  *
  1241.  * TkMacOSXGenerateParentMenuSelectEvent --
  1242.  *
  1243.  * Respond to a hierarchical menu being opened.
  1244.  *
  1245.  * Results:
  1246.  * True if event(s) are generated - false otherwise.
  1247.  *
  1248.  * Side effects:
  1249.  * Places a virtual event on the event queue.
  1250.  *
  1251.  *----------------------------------------------------------------------
  1252.  */
  1253. int
  1254. TkMacOSXGenerateParentMenuSelectEvent(
  1255.     MenuRef menu)
  1256. {
  1257.     TkMenu *menuPtr = MenuPtrForMenuRef(menu);
  1258.     if (menuPtr) {
  1259. TkMenuEntry *parentEntryPtr = GetParentMenuEntry(menuPtr);
  1260. if (parentEntryPtr && (menuPtr = parentEntryPtr->menuPtr)) {
  1261.     TkActivateMenuEntry(menuPtr, parentEntryPtr->index);
  1262.     MenuSelectEvent(menuPtr);
  1263.     Tcl_ServiceAll();
  1264.     return true;
  1265. }
  1266.     }
  1267.     return false;
  1268. }
  1269. /*
  1270.  *----------------------------------------------------------------------
  1271.  *
  1272.  * TkMacOSXGenerateMenuSelectEvent --
  1273.  *
  1274.  * Respond to a menu item being selected.
  1275.  *
  1276.  * Results:
  1277.  * True if event(s) are generated - false otherwise.
  1278.  *
  1279.  * Side effects:
  1280.  * Places a virtual event on the event queue.
  1281.  *
  1282.  *----------------------------------------------------------------------
  1283.  */
  1284. int
  1285. TkMacOSXGenerateMenuSelectEvent(
  1286.     MenuRef menu,
  1287.     MenuItemIndex index)
  1288. {
  1289.     TkMenu *menuPtr = MenuPtrForMenuRef(menu);
  1290.     int item = index - 1;
  1291.     if (menuPtr) {
  1292. if (item < 0 || item >= menuPtr->numEntries ||
  1293. (menuPtr->entries[item])->state == ENTRY_DISABLED) {
  1294.     TkActivateMenuEntry(menuPtr, -1);
  1295. } else {
  1296.     TkActivateMenuEntry(menuPtr, item);
  1297.     MenuSelectEvent(menuPtr);
  1298.     Tcl_ServiceAll();
  1299.     return true;
  1300. }
  1301.     }
  1302.     return false;
  1303. }
  1304. /*
  1305.  *----------------------------------------------------------------------
  1306.  *
  1307.  * MenuSelectEvent --
  1308.  *
  1309.  * Generates a "MenuSelect" virtual event. This can be used to
  1310.  * do context-sensitive menu help.
  1311.  *
  1312.  * Results:
  1313.  * None.
  1314.  *
  1315.  * Side effects:
  1316.  * Places a virtual event on the event queue.
  1317.  *
  1318.  *----------------------------------------------------------------------
  1319.  */
  1320. void
  1321. MenuSelectEvent(
  1322.     TkMenu *menuPtr) /* the menu we have selected. */
  1323. {
  1324.     XVirtualEvent event;
  1325.     bzero(&event, sizeof(XVirtualEvent));
  1326.     event.type = VirtualEvent;
  1327.     event.serial = menuPtr->display->request;
  1328.     event.send_event = false;
  1329.     event.display = menuPtr->display;
  1330.     Tk_MakeWindowExist(menuPtr->tkwin);
  1331.     event.event = Tk_WindowId(menuPtr->tkwin);
  1332.     event.root = XRootWindow(menuPtr->display, 0);
  1333.     event.subwindow = None;
  1334.     event.time = TkpGetMS();
  1335.     XQueryPointer(NULL, None, NULL, NULL, &event.x_root, &event.y_root, NULL,
  1336.     NULL, &event.state);
  1337.     event.same_screen = true;
  1338.     event.name = Tk_GetUid("MenuSelect");
  1339.     Tk_QueueWindowEvent((XEvent *) &event, TCL_QUEUE_TAIL);
  1340. }
  1341. /*
  1342.  *----------------------------------------------------------------------
  1343.  *
  1344.  * TkMacOSXClearActiveMenu --
  1345.  *
  1346.  * Clears Tk's active entry for the given MenuRef.
  1347.  *
  1348.  * Results:
  1349.  * None.
  1350.  *
  1351.  * Side effects:
  1352.  * Generates <<MenuSelect>> virtual events.
  1353.  *
  1354.  *----------------------------------------------------------------------
  1355.  */
  1356. void
  1357. TkMacOSXClearActiveMenu(
  1358.     MenuRef menu)
  1359. {
  1360.     TkMenu *menuPtr = MenuPtrForMenuRef(menu);
  1361.     if (menuPtr) {
  1362. RecursivelyClearActiveMenu(menuPtr);
  1363.     }
  1364. }
  1365. /*
  1366.  *----------------------------------------------------------------------
  1367.  *
  1368.  * RecursivelyClearActiveMenu --
  1369.  *
  1370.  * Recursively clears the active entry in the menu's cascade hierarchy.
  1371.  *
  1372.  * Results:
  1373.  * None.
  1374.  *
  1375.  * Side effects:
  1376.  * Generates <<MenuSelect>> virtual events.
  1377.  *
  1378.  *----------------------------------------------------------------------
  1379.  */
  1380. void
  1381. RecursivelyClearActiveMenu(
  1382.     TkMenu *menuPtr) /* The menu to reset. */
  1383. {
  1384.     int i;
  1385.     TkMenuEntry *mePtr;
  1386.     TkActivateMenuEntry(menuPtr, -1);
  1387.     for (i = 0; i < menuPtr->numEntries; i++) {
  1388. mePtr = menuPtr->entries[i];
  1389. if (mePtr->type == CASCADE_ENTRY) {
  1390.     if ((mePtr->childMenuRefPtr != NULL)
  1391.     && (mePtr->childMenuRefPtr->menuPtr != NULL)) {
  1392. RecursivelyClearActiveMenu(mePtr->childMenuRefPtr->menuPtr);
  1393.     }
  1394. }
  1395.     }
  1396. }
  1397. /*
  1398.  *----------------------------------------------------------------------
  1399.  *
  1400.  * TkMacOSXClearMenubarActive --
  1401.  *
  1402.  * Recursively clears the active entry in the current menubar hierarchy.
  1403.  *
  1404.  * Results:
  1405.  * None.
  1406.  *
  1407.  * Side effects:
  1408.  * Generates <<MenuSelect>> virtual events.
  1409.  *
  1410.  *----------------------------------------------------------------------
  1411.  */
  1412. void
  1413. TkMacOSXClearMenubarActive(void)
  1414. {
  1415.     TkMenuReferences *menuBarRefPtr;
  1416.     if (currentMenuBarName != NULL) {
  1417. menuBarRefPtr = TkFindMenuReferences(currentMenuBarInterp,
  1418. currentMenuBarName);
  1419. if ((menuBarRefPtr != NULL) && (menuBarRefPtr->menuPtr != NULL)) {
  1420.     TkMenu *menuPtr;
  1421.     for (menuPtr = menuBarRefPtr->menuPtr->masterMenuPtr;
  1422.     menuPtr != NULL; menuPtr = menuPtr->nextInstancePtr) {
  1423. if (menuPtr->menuType == MENUBAR) {
  1424.     RecursivelyClearActiveMenu(menuPtr);
  1425. }
  1426.     }
  1427. }
  1428.     }
  1429. }
  1430. /*
  1431.  *----------------------------------------------------------------------
  1432.  *
  1433.  * TkpMenuNotifyToplevelCreate --
  1434.  *
  1435.  * This routine reconfigures the menu and the clones indicated by
  1436.  * menuName becuase a toplevel has been created and any system
  1437.  * menus need to be created. Only applicable to Windows.
  1438.  *
  1439.  * Results:
  1440.  * None.
  1441.  *
  1442.  * Side effects:
  1443.  * An idle handler is set up to do the reconfiguration.
  1444.  *
  1445.  *----------------------------------------------------------------------
  1446.  */
  1447. void
  1448. TkpMenuNotifyToplevelCreate(
  1449.     Tcl_Interp *interp, /* The interp the menu lives in. */
  1450.     char *menuName) /* The name of the menu to reconfigure. */
  1451. {
  1452.     /*
  1453.      * Nothing to do.
  1454.      */
  1455. }
  1456. /*
  1457.  *----------------------------------------------------------------------
  1458.  *
  1459.  * TkpMenuInit --
  1460.  *
  1461.  * Initializes Mac-specific menu data.
  1462.  *
  1463.  * Results:
  1464.  * None.
  1465.  *
  1466.  * Side effects:
  1467.  * Allocates a hash table.
  1468.  *
  1469.  *----------------------------------------------------------------------
  1470.  */
  1471. void
  1472. TkpMenuInit(void)
  1473. {
  1474.     MenuSymbol *ms = menuSymbols;
  1475.     CFStringRef cfStr;
  1476.     lastMenuID = 256;
  1477.     Tcl_InitHashTable(&commandTable, TCL_ONE_WORD_KEYS);
  1478.     currentMenuBarOwner = NULL;
  1479.     currentAppleMenuID = 0;
  1480.     currentHelpMenuID = 0;
  1481.     currentMenuBarInterp = NULL;
  1482.     currentMenuBarName = NULL;
  1483.     windowListPtr = NULL;
  1484. #ifdef USE_TK_MDEF
  1485.     tkThemeMenuItemDrawingUPP
  1486.     = NewMenuItemDrawingUPP(ThemeMenuItemDrawingProc);
  1487.     useMDEFVar = Tcl_NewStringObj("::tk::mac::useCustomMDEF", -1);
  1488.     macMDEFDrawable.winPtr = NULL;
  1489.     macMDEFDrawable.xOff = 0;
  1490.     macMDEFDrawable.yOff = 0;
  1491.     macMDEFDrawable.visRgn = NULL;
  1492.     macMDEFDrawable.aboveVisRgn = NULL;
  1493.     macMDEFDrawable.drawRect = CGRectNull;
  1494.     macMDEFDrawable.referenceCount = 0;
  1495.     macMDEFDrawable.toplevel = NULL;
  1496.     macMDEFDrawable.flags = 0;
  1497.     macMDEFDrawable.grafPtr = NULL;
  1498.     macMDEFDrawable.context = NULL;
  1499.     macMDEFDrawable.size = CGSizeZero;
  1500. #endif
  1501.     ChkErr(GetThemeMetric, kThemeMetricMenuMarkColumnWidth,
  1502.     &menuMarkColumnWidth);
  1503.     ChkErr(GetThemeMetric, kThemeMetricMenuMarkIndent, &menuMarkIndent);
  1504.     ChkErr(GetThemeMetric, kThemeMetricMenuTextLeadingEdgeMargin,
  1505.     &menuTextLeadingEdgeMargin);
  1506.     ChkErr(GetThemeMetric, kThemeMetricMenuTextTrailingEdgeMargin,
  1507.     &menuTextTrailingEdgeMargin);
  1508.     ChkErr(GetThemeMenuItemExtra, kThemeMenuItemPlain, &menuItemExtraHeight,
  1509.     &menuItemExtraWidth);
  1510.     ChkErr(GetThemeMenuSeparatorHeight, &menuSeparatorHeight);
  1511.     while (ms->unicode) {
  1512. ms->utfLen = Tcl_UniCharToUtf(ms->unicode, ms->utf);
  1513. ms->utf[ms->utfLen] = 0;
  1514. cfStr = CFStringCreateWithCharacters(NULL, &ms->unicode, 1);
  1515. if (cfStr) {
  1516.     ms->width = MeasureThemeText(cfStr, kThemeMenuItemCmdKeyFont);
  1517.     CFRelease(cfStr);
  1518. }
  1519. ms++;
  1520.     }
  1521. }
  1522. /*
  1523.  *----------------------------------------------------------------------
  1524.  *
  1525.  * TkpMenuThreadInit --
  1526.  *
  1527.  * Does platform-specific initialization of thread-specific
  1528.  * menu state.
  1529.  *
  1530.  * Results:
  1531.  * None.
  1532.  *
  1533.  * Side effects:
  1534.  * None.
  1535.  *
  1536.  *----------------------------------------------------------------------
  1537.  */
  1538. void
  1539. TkpMenuThreadInit(void)
  1540. {
  1541.     /*
  1542.      * Nothing to do.
  1543.      */
  1544. }
  1545. /*
  1546.  *----------------------------------------------------------------------
  1547.  *
  1548.  * TkpPreprocessMacMenu --
  1549.  *
  1550.  *    Handle preprocessing of menubar if it exists.
  1551.  *
  1552.  * Results:
  1553.  *    None.
  1554.  *
  1555.  * Side effects:
  1556.  *    All post commands for the current menubar get executed.
  1557.  *
  1558.  *----------------------------------------------------------------------
  1559.  */
  1560. void
  1561. TkMacOSXPreprocessMenu(void)
  1562. {
  1563.     if ((currentMenuBarName != NULL) && (currentMenuBarInterp != NULL)) {
  1564. TkMenuReferences *mbRefPtr =
  1565. TkFindMenuReferences(currentMenuBarInterp,currentMenuBarName);
  1566. if ((mbRefPtr != NULL) && (mbRefPtr->menuPtr != NULL)) {
  1567.     int code;
  1568.     Tcl_Preserve((ClientData) currentMenuBarInterp);
  1569.     code = TkPreprocessMenu(mbRefPtr->menuPtr->masterMenuPtr);
  1570.     if ((code != TCL_OK) && (code != TCL_CONTINUE)
  1571.     && (code != TCL_BREAK)) {
  1572. Tcl_AddErrorInfo(currentMenuBarInterp,
  1573. "n    (menu preprocess)");
  1574. Tcl_BackgroundError(currentMenuBarInterp);
  1575.     }
  1576.     Tcl_Release((ClientData) currentMenuBarInterp);
  1577. }
  1578.     }
  1579. }
  1580. #ifdef USE_TK_MDEF
  1581. #pragma mark MDEF
  1582. /*
  1583.  *----------------------------------------------------------------------
  1584.  *
  1585.  * MenuDefProc --
  1586.  *
  1587.  * This routine is the MDEF handler for Tk. It receives all messages
  1588.  * for the menu and dispatches them.
  1589.  *
  1590.  * Results:
  1591.  * None.
  1592.  *
  1593.  * Side effects:
  1594.  * This routine causes menus to be drawn and will certainly allocate
  1595.  * memory as a result. Also, the menu can scroll up and down, and
  1596.  * various other interface actions can take place.
  1597.  *
  1598.  *----------------------------------------------------------------------
  1599.  */
  1600. void
  1601. MenuDefProc(
  1602.     SInt16 message, /* What action are we taking? */
  1603.     MenuRef menu, /* The menu we are working with */
  1604.     Rect *menuRectPtr, /* A pointer to the rect for the
  1605.  * whole menu. */
  1606.     Point hitPt, /* Where the mouse was clicked for
  1607.  * the appropriate messages. */
  1608.     SInt16 *whichItem) /* Output result. Which item was
  1609.  * hit by the user? */
  1610. {
  1611.     TkMenu *menuPtr;
  1612.     Tcl_HashEntry *commandEntryPtr;
  1613.     MenuID menuID;
  1614.     menuID = GetMenuID(menu);
  1615.     commandEntryPtr = Tcl_FindHashEntry(&commandTable, (char*)(intptr_t)menuID);
  1616.     if (commandEntryPtr) {
  1617. menuPtr = (TkMenu *) Tcl_GetHashValue(commandEntryPtr);
  1618.     } else {
  1619. menuPtr = NULL;
  1620.     }
  1621.     switch (message) {
  1622. case kMenuInitMsg:
  1623.     *whichItem = noErr;
  1624.     break;
  1625. case kMenuDisposeMsg:
  1626.     break;
  1627. case kMenuHiliteItemMsg:
  1628.     HandleMenuHiliteMsg(menu, menuRectPtr, hitPt, whichItem, menuPtr);
  1629.     break;
  1630. case kMenuCalcItemMsg:
  1631.     HandleMenuCalcItemMsg(menu, menuRectPtr, hitPt, whichItem,
  1632.     menuPtr);
  1633.     break;
  1634. case kMenuDrawItemsMsg:
  1635. #ifdef TK_MAC_DEBUG_MENUS
  1636.     TkMacOSXDbgMsg("MDEF: DrawItemsMsg");
  1637. #endif
  1638.     /*
  1639.      * We do nothing  here, because we don't support the Menu Managers
  1640.      * dynamic item groups
  1641.      */
  1642.     break;
  1643. case kMenuThemeSavvyMsg:
  1644.     *whichItem = kThemeSavvyMenuResponse;
  1645.     break;
  1646. case kMenuSizeMsg:
  1647. #ifdef TK_MAC_DEBUG_MENUS
  1648.     TkMacOSXDbgMsg("MDEF: SizeMsg %d, %d", hitPt.h, hitPt.v);
  1649. #endif
  1650.     SetMenuWidth(menu, hitPt.h < menuPtr->totalWidth ? hitPt.h :
  1651.     menuPtr->totalWidth);
  1652.     SetMenuHeight(menu, hitPt.v < menuPtr->totalHeight ? hitPt.v :
  1653.     menuPtr->totalHeight);
  1654.     break;
  1655. case kMenuDrawMsg:
  1656.     HandleMenuDrawMsg(menu, menuRectPtr, hitPt, whichItem, menuPtr);
  1657.     break;
  1658. case kMenuFindItemMsg:
  1659.     HandleMenuFindItemMsg(menu, menuRectPtr, hitPt, whichItem,
  1660.     menuPtr);
  1661.     break;
  1662. case kMenuPopUpMsg:
  1663.     HandleMenuPopUpMsg(menu, menuRectPtr, hitPt, whichItem, menuPtr);
  1664.     break;
  1665.     }
  1666. }
  1667. /*
  1668.  *----------------------------------------------------------------------
  1669.  *
  1670.  * HandleMenuHiliteMsg --
  1671.  *
  1672.  * Handles the MenuDefProc's hilite message.
  1673.  *
  1674.  * Results:
  1675.  * A menu entry is drawn
  1676.  *
  1677.  * Side effects:
  1678.  * None
  1679.  *
  1680.  *----------------------------------------------------------------------
  1681.  */
  1682. void
  1683. HandleMenuHiliteMsg(
  1684.     MenuRef menu,
  1685.     Rect *menuRectPtr,
  1686.     Point hitPt,
  1687.     SInt16 *whichItem,
  1688.     TkMenu *menuPtr)
  1689. {
  1690.     OSStatus err;
  1691.     Tk_Font tkfont;
  1692.     Tk_FontMetrics fontMetrics;
  1693.     MDEFHiliteItemData *hidPtr = (MDEFHiliteItemData *)whichItem;
  1694.     int oldItem = hidPtr->previousItem - 1;
  1695.     int newItem = hidPtr->newItem - 1;
  1696.     MenuTrackingData mtd, *mtdPtr = &mtd;
  1697. #ifdef TK_MAC_DEBUG_MENUS
  1698.     TkMacOSXDbgMsg("MDEF: HiliteMsg %d -> %d", hidPtr->previousItem,
  1699.     hidPtr->newItem);
  1700. #endif
  1701.     GetPort(&macMDEFDrawable.grafPtr);
  1702.     macMDEFDrawable.context = (CGContextRef) hidPtr->context;
  1703.     err = ChkErr(GetMenuTrackingData, menu, mtdPtr);
  1704.     if (err != noErr) {
  1705. return;
  1706.     }
  1707.     tkfont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
  1708.     Tk_GetFontMetrics(tkfont, &fontMetrics);
  1709.     if (oldItem >= 0) {
  1710. AppearanceEntryDrawWrapper(menuPtr->entries[oldItem], menuRectPtr,
  1711. mtdPtr, (Drawable) &macMDEFDrawable, &fontMetrics, tkfont, 1);
  1712.     }
  1713.     if (newItem >= 0) {
  1714. AppearanceEntryDrawWrapper(menuPtr->entries[newItem], menuRectPtr,
  1715. mtdPtr, (Drawable) &macMDEFDrawable, &fontMetrics, tkfont, 0);
  1716.     }
  1717. }
  1718. /*
  1719.  *----------------------------------------------------------------------
  1720.  *
  1721.  * HandleMenuDrawMsg --
  1722.  *
  1723.  * Handles the MenuDefProc's draw message.
  1724.  *
  1725.  * Results:
  1726.  * A menu entry is drawn
  1727.  *
  1728.  * Side effects:
  1729.  * None
  1730.  *
  1731.  *----------------------------------------------------------------------
  1732.  */
  1733. void
  1734. HandleMenuDrawMsg(
  1735.     MenuRef menu,
  1736.     Rect *menuRectPtr,
  1737.     Point hitPt,
  1738.     SInt16 *whichItem,
  1739.     TkMenu *menuPtr)
  1740. {
  1741.     Tk_Font menuFont;
  1742.     Tk_FontMetrics fontMetrics;
  1743.     TkMenuEntry *mePtr;
  1744.     int i;
  1745.     Rect menuClipRect, bounds;
  1746.     MDEFDrawData *ddPtr = (MDEFDrawData*)whichItem;
  1747.     MenuTrackingData *mtdPtr = &(ddPtr->trackingData);
  1748.     TkWindow *winPtr = (TkWindow*)menuPtr->tkwin;
  1749.     GetPort(&macMDEFDrawable.grafPtr);
  1750.     GetPortBounds(macMDEFDrawable.grafPtr, &bounds);
  1751.     macMDEFDrawable.context = (CGContextRef) ddPtr->context;
  1752. #ifdef TK_MAC_DEBUG_MENUS
  1753.     TkMacOSXDbgMsg("MDEF: DrawMsg %d - %d; %d - %d", menuRectPtr->top,
  1754.     menuRectPtr->bottom, bounds.top, bounds.bottom);
  1755. #endif
  1756.     winPtr->changes.x = menuRectPtr->left;
  1757.     winPtr->changes.y = menuRectPtr->top;
  1758.     winPtr->changes.width = menuRectPtr->right - menuRectPtr->left;
  1759.     winPtr->changes.height = menuRectPtr->bottom - menuRectPtr->top;
  1760.     TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable,
  1761.     0, 0, -1, -1);
  1762. #if 0
  1763.     if (menuPtr->menuRefPtr->topLevelListPtr != NULL) {
  1764. menuType = kThemeMenuTypePullDown;
  1765.     } else if (menuPtr->menuRefPtr->parentEntryPtr != NULL) {
  1766. menuType = kThemeMenuTypeHierarchical;
  1767.     } else {
  1768. menuType = kThemeMenuTypePopUp;
  1769.     }
  1770. #endif
  1771.     DrawMenuBackground(menuPtr, menuRectPtr, (Drawable) &macMDEFDrawable);
  1772.     menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
  1773.     Tk_GetFontMetrics(menuFont, &fontMetrics);
  1774.     menuClipRect = *menuRectPtr;
  1775.     mtdPtr->virtualMenuBottom = mtdPtr->virtualMenuTop + menuPtr->totalHeight;
  1776.     /*
  1777.      * Next, figure out scrolling information.
  1778.      */
  1779.     if ((menuRectPtr->bottom - menuRectPtr->top) < menuPtr->totalHeight) {
  1780. short arrowHeight = fontMetrics.linespace + 1;
  1781. Rect arrowRect, eraseRect;
  1782. ThemeMenuState menuState = IsMenuItemEnabled(menu, 0) ?
  1783. kThemeMenuActive : kThemeMenuDisabled;
  1784. if (mtdPtr->virtualMenuTop < menuRectPtr->top) {
  1785.     arrowRect = bounds;
  1786.     /*arrowRect.top += 1;*/
  1787.     arrowRect.bottom = arrowRect.top + arrowHeight;
  1788.     eraseRect = arrowRect;
  1789.     eraseRect.top = menuRectPtr->top;
  1790.     menuClipRect.top = arrowRect.bottom;
  1791.     ChkErr(EraseMenuBackground, menu, &eraseRect,
  1792.     macMDEFDrawable.context);
  1793.     ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect,
  1794.     mtdPtr->virtualMenuTop, mtdPtr->virtualMenuBottom,
  1795.     menuState, kThemeMenuItemScrollUpArrow, NULL, 0);
  1796. #ifdef TK_MAC_DEBUG_MENUS
  1797.     TkMacOSXDbgMsg("upArrow:   %d - %d, %d - %d", arrowRect.top,
  1798.     arrowRect.bottom, arrowRect.left, arrowRect.right);
  1799. #endif
  1800. }
  1801. if (mtdPtr->virtualMenuBottom > menuRectPtr->bottom) {
  1802.     arrowRect = bounds;
  1803.     arrowRect.bottom -= 1;
  1804.     arrowRect.top = arrowRect.bottom - arrowHeight;
  1805.     eraseRect = arrowRect;
  1806.     eraseRect.bottom = menuRectPtr->bottom;
  1807.     menuClipRect.bottom = arrowRect.top;
  1808.     ChkErr(EraseMenuBackground, menu, &eraseRect,
  1809.     macMDEFDrawable.context);
  1810.     ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect,
  1811.     mtdPtr->virtualMenuTop, mtdPtr->virtualMenuBottom,
  1812.     menuState, kThemeMenuItemScrollDownArrow, NULL, 0);
  1813. #ifdef TK_MAC_DEBUG_MENUS
  1814.     TkMacOSXDbgMsg("downArrow: %d - %d, %d - %d", arrowRect.top,
  1815.     arrowRect.bottom, arrowRect.left, arrowRect.right);
  1816. #endif
  1817. }
  1818. TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable,
  1819. menuClipRect.left, menuClipRect.top, menuClipRect.right -
  1820. menuClipRect.left, menuClipRect.bottom - menuClipRect.top);
  1821.     }
  1822.     /*
  1823.      * Now, actually draw the menu. Don't draw entries that
  1824.      * are higher than the top arrow, and don't draw entries
  1825.      * that are lower than the bottom.
  1826.      */
  1827.     for (i = 0; i < menuPtr->numEntries; i++) {
  1828. mePtr = menuPtr->entries[i];
  1829. if (mtdPtr->virtualMenuTop + mePtr->y + mePtr->height <
  1830. menuClipRect.top || mtdPtr->virtualMenuTop + mePtr->y >
  1831. menuClipRect.bottom) {
  1832.     continue;
  1833. }
  1834. AppearanceEntryDrawWrapper(mePtr, menuRectPtr, mtdPtr,
  1835. (Drawable) &macMDEFDrawable, &fontMetrics, menuFont, 0);
  1836.     }
  1837.     MDEFScrollFlag = 1;
  1838. }
  1839. /*
  1840.  *----------------------------------------------------------------------
  1841.  *
  1842.  * HandleMenuFindItemMsg --
  1843.  *
  1844.  * Handles the MenuDefProc's FindItems message. We have to
  1845.  * respond by filling in the itemSelected, itemUnderMouse and
  1846.  * itemRect fields. This is also the time to scroll the menu if
  1847.  * it is too long to fit on the screen.
  1848.  *
  1849.  * Results:
  1850.  * The Menu system is informed of the selected item & the item
  1851.  * under the mouse.
  1852.  *
  1853.  * Side effects:
  1854.  * The menu might get scrolled.
  1855.  *
  1856.  *----------------------------------------------------------------------
  1857.  */
  1858. void
  1859. HandleMenuFindItemMsg(
  1860.     MenuRef menu,
  1861.     Rect *menuRectPtr,
  1862.     Point hitPt,
  1863.     SInt16 *whichItem,
  1864.     TkMenu *menuPtr)
  1865. {
  1866.     Tk_Font menuFont;
  1867.     Tk_FontMetrics fontMetrics;
  1868.     TkMenuEntry *mePtr;
  1869.     int i, newItem = -1, itemUnderMouse = -1;
  1870.     Rect itemRect = {0, 0, 0, 0}, menuClipRect, bounds;
  1871.     int hasTopScroll, hasBottomScroll;
  1872.     MDEFFindItemData *fiPtr = (MDEFFindItemData *)whichItem;
  1873.     MenuTrackingData *mtdPtr = &(fiPtr->trackingData), topMtd;
  1874.     enum {
  1875. DONT_SCROLL, DOWN_SCROLL, UP_SCROLL
  1876.     } scrollDirection;
  1877.     short arrowHeight;
  1878. #ifdef TK_MAC_DEBUG_MENUS
  1879.     static Point lastHitPt = {0, 0};
  1880.     if (hitPt.h != lastHitPt.h || hitPt.v != lastHitPt.v) {
  1881. lastHitPt = hitPt;
  1882. TkMacOSXDbgMsg("MDEF: FindItemMsg: %d, %d", hitPt.h, hitPt.v);
  1883.     }
  1884. #endif
  1885.     GetPort(&macMDEFDrawable.grafPtr);
  1886.     GetPortBounds(macMDEFDrawable.grafPtr, &bounds);
  1887.     macMDEFDrawable.context = (CGContextRef) fiPtr->context;
  1888.     /*
  1889.      * Now we need to take care of scrolling the menu.
  1890.      */
  1891.     menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
  1892.     Tk_GetFontMetrics(menuFont, &fontMetrics);
  1893.     arrowHeight = fontMetrics.linespace + 1;
  1894.     menuClipRect = *menuRectPtr;
  1895.     hasTopScroll = mtdPtr->virtualMenuTop < menuRectPtr->top;
  1896.     hasBottomScroll = mtdPtr->virtualMenuBottom > menuRectPtr->bottom;
  1897.     scrollDirection = DONT_SCROLL;
  1898.     if (hasTopScroll) {
  1899. menuClipRect.top = bounds.top + arrowHeight;
  1900. if (hitPt.v < menuClipRect.top) {
  1901.     newItem = -1;
  1902.     scrollDirection = DOWN_SCROLL;
  1903. }
  1904.     }
  1905.     if (hasBottomScroll) {
  1906. menuClipRect.bottom = bounds.bottom - 1 - arrowHeight;
  1907. if (hitPt.v > menuClipRect.bottom) {
  1908.     newItem = -1;
  1909.     scrollDirection = UP_SCROLL;
  1910. }
  1911.     }
  1912.     if (MDEFScrollFlag) {
  1913. scrollDirection = DONT_SCROLL;
  1914. MDEFScrollFlag = 0;
  1915.     }
  1916.     /*
  1917.      * Don't scroll if there are other menus open above us
  1918.      */
  1919.     ChkErr(GetMenuTrackingData, NULL, &topMtd);
  1920.     if (menu != topMtd.menu) {
  1921. scrollDirection = DONT_SCROLL;
  1922.     }
  1923.     if (scrollDirection == DONT_SCROLL) {
  1924. /*
  1925.  * Find out which item was hit. If it is the same as the old item,
  1926.  * we don't need to do anything.
  1927.  */
  1928. if (PtInRect(hitPt, menuRectPtr)) {
  1929.     for (i = 0; i < menuPtr->numEntries; i++) {
  1930. mePtr = menuPtr->entries[i];
  1931. itemRect.left = menuRectPtr->left + mePtr->x;
  1932. itemRect.top = mtdPtr->virtualMenuTop + mePtr->y;
  1933. itemRect.right = mePtr->entryFlags & ENTRY_LAST_COLUMN ?
  1934. menuRectPtr->right : itemRect.left + mePtr->width;
  1935. itemRect.bottom = itemRect.top + mePtr->height;
  1936. if (PtInRect(hitPt, &itemRect)) {
  1937.     if ((mePtr->type == SEPARATOR_ENTRY)
  1938.     || (mePtr->state == ENTRY_DISABLED)) {
  1939. newItem = -1;
  1940. itemUnderMouse = i;
  1941.     } else {
  1942. TkMenuEntry *parentEntryPtr =
  1943. GetParentMenuEntry(menuPtr);
  1944. if (parentEntryPtr &&
  1945. parentEntryPtr->state == ENTRY_DISABLED) {
  1946.     newItem = -1;
  1947.     itemUnderMouse = i;
  1948. } else {
  1949.     newItem = i;
  1950.     itemUnderMouse = i;
  1951. }
  1952.     }
  1953.     break;
  1954. }
  1955.     }
  1956. }
  1957.     } else {
  1958. short scrollAmt;
  1959. unsigned long scrollDelay;
  1960. Rect arrowRect, eraseRect, scrolledMenuClipRect;
  1961. ThemeMenuState menuState = IsMenuItemEnabled(menu, 0) ?
  1962. kThemeMenuActive : kThemeMenuDisabled;
  1963. int oldItem = mtdPtr->itemSelected - 1;
  1964. short d;
  1965. TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable,
  1966. 0, 0, -1, -1);
  1967. scrollAmt = fontMetrics.linespace + menuItemExtraHeight;
  1968. if (scrollDirection == UP_SCROLL) {
  1969.     scrollAmt = -scrollAmt;
  1970.     d = hitPt.v - bounds.bottom;
  1971. } else {
  1972.     d = bounds.top - hitPt.v;
  1973. }
  1974. scrollDelay = (d >= scrollAmt/2) ? 1 : 10;
  1975. menuClipRect = *menuRectPtr;
  1976. if (mtdPtr->virtualMenuTop + scrollAmt < menuRectPtr->top) {
  1977.     arrowRect = bounds;
  1978.     /*arrowRect.top += 1;*/
  1979.     arrowRect.bottom = arrowRect.top + arrowHeight;
  1980.     eraseRect = arrowRect;
  1981.     eraseRect.top = menuRectPtr->top;
  1982.     menuClipRect.top = arrowRect.bottom;
  1983.     if (!hasTopScroll) {
  1984. ChkErr(EraseMenuBackground, menu, &eraseRect,
  1985. macMDEFDrawable.context);
  1986. ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect,
  1987. mtdPtr->virtualMenuTop + scrollAmt,
  1988. mtdPtr->virtualMenuBottom + scrollAmt,
  1989. menuState, kThemeMenuItemScrollUpArrow, NULL, 0);
  1990. #ifdef TK_MAC_DEBUG_MENUS
  1991. TkMacOSXDbgMsg("upArrow:   %d - %d, %d - %d", arrowRect.top,
  1992. arrowRect.bottom, arrowRect.left, arrowRect.right);
  1993. #endif
  1994.     }
  1995. }
  1996. if (mtdPtr->virtualMenuBottom + scrollAmt > menuRectPtr->bottom) {
  1997.     arrowRect = bounds;
  1998.     arrowRect.bottom -= 1;
  1999.     arrowRect.top = arrowRect.bottom - arrowHeight;
  2000.     eraseRect = arrowRect;
  2001.     eraseRect.bottom = menuRectPtr->bottom;
  2002.     menuClipRect.bottom = arrowRect.top;
  2003.     if (!hasBottomScroll) {
  2004. ChkErr(EraseMenuBackground, menu, &eraseRect,
  2005. macMDEFDrawable.context);
  2006. ChkErr(DrawThemeMenuItem, menuRectPtr, &arrowRect,
  2007. mtdPtr->virtualMenuTop + scrollAmt,
  2008. mtdPtr->virtualMenuBottom + scrollAmt,
  2009. menuState, kThemeMenuItemScrollDownArrow, NULL, 0);
  2010. #ifdef TK_MAC_DEBUG_MENUS
  2011. TkMacOSXDbgMsg("downArrow: %d - %d, %d - %d", arrowRect.top,
  2012. arrowRect.bottom, arrowRect.left, arrowRect.right);
  2013. #endif
  2014.     }
  2015. }
  2016. TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable,
  2017. menuClipRect.left, menuClipRect.top, menuClipRect.right -
  2018. menuClipRect.left, menuClipRect.bottom - menuClipRect.top);
  2019. TkActivateMenuEntry(menuPtr, -1);
  2020. if (oldItem >= 0) {
  2021.     AppearanceEntryDrawWrapper(menuPtr->entries[oldItem], menuRectPtr,
  2022.     mtdPtr, (Drawable) &macMDEFDrawable, &fontMetrics,
  2023.     menuFont, 1);
  2024. }
  2025. ChkErr(ScrollMenuImage, menu, &menuClipRect, 0, scrollAmt,
  2026. macMDEFDrawable.context);
  2027. mtdPtr->virtualMenuTop += scrollAmt;
  2028. mtdPtr->virtualMenuBottom += scrollAmt;
  2029. scrolledMenuClipRect = menuClipRect;
  2030. OffsetRect(&scrolledMenuClipRect, 0, scrollAmt);
  2031. menuClipRect = bounds;
  2032. if (mtdPtr->virtualMenuTop < menuRectPtr->top) {
  2033.     menuClipRect.top += arrowHeight;
  2034. }
  2035. if (mtdPtr->virtualMenuBottom > menuRectPtr->bottom) {
  2036.     menuClipRect.bottom -= arrowHeight;
  2037. }
  2038. TkpClipDrawableToRect(menuPtr->display, (Drawable) &macMDEFDrawable,
  2039. menuClipRect.left, menuClipRect.top, menuClipRect.right -
  2040. menuClipRect.left, menuClipRect.bottom - menuClipRect.top);
  2041. if (scrolledMenuClipRect.bottom < menuClipRect.bottom) {
  2042.     menuClipRect.top = scrolledMenuClipRect.bottom;
  2043. } else if (scrolledMenuClipRect.top < menuClipRect.top) {
  2044.     menuClipRect.bottom = scrolledMenuClipRect.top;
  2045. }
  2046. for (i = 0; i < menuPtr->numEntries; i++) {
  2047.     mePtr = menuPtr->entries[i];
  2048.     if (mtdPtr->virtualMenuTop + mePtr->y + mePtr->height <
  2049.     menuClipRect.top || mtdPtr->virtualMenuTop + mePtr->y >
  2050.     menuClipRect.bottom) {
  2051. continue;
  2052.     }
  2053. #ifdef TK_MAC_DEBUG_MENUS
  2054.     TkMacOSXDbgMsg("Drawing item %i", i);
  2055. #endif
  2056.     AppearanceEntryDrawWrapper(mePtr, menuRectPtr, mtdPtr,
  2057.     (Drawable) &macMDEFDrawable, &fontMetrics, menuFont, 1);
  2058. }
  2059. Delay(scrollDelay, NULL);
  2060.     }
  2061.     mtdPtr->itemSelected = newItem + 1;
  2062.     mtdPtr->itemUnderMouse = itemUnderMouse + 1;
  2063.     mtdPtr->itemRect = itemRect;
  2064. }
  2065. /*
  2066.  *----------------------------------------------------------------------
  2067.  *
  2068.  * HandleMenuPopUpMsg --
  2069.  *
  2070.  * Handles the MenuDefProc's PopUp message. The menu is
  2071.  * posted with the selected item at the point given in hitPt.
  2072.  *
  2073.  * Results:
  2074.  * A menu is posted.
  2075.  *
  2076.  * Side effects:
  2077.  * None.
  2078.  *
  2079.  *----------------------------------------------------------------------
  2080.  */
  2081. void
  2082. HandleMenuPopUpMsg(
  2083.     MenuRef menu,
  2084.     Rect *menuRectPtr,
  2085.     Point hitPt,
  2086.     SInt16 *whichItem,
  2087.     TkMenu *menuPtr)
  2088. {
  2089.     int maxMenuHeight;
  2090.     int oldItem;
  2091.     Rect portRect;
  2092.     BitMap screenBits;
  2093.     static SInt16 menuBarHeight = 0;
  2094. #ifdef TK_MAC_DEBUG_MENUS
  2095.     TkMacOSXDbgMsg("MDEF: PopUpMsg");
  2096. #endif
  2097.     if (!menuBarHeight) {
  2098. ChkErr(GetThemeMenuBarHeight, &menuBarHeight);
  2099.     }
  2100.     GetQDGlobalsScreenBits(&screenBits);
  2101.     /*
  2102.      * Note that for some oddball reason, h and v are reversed in the
  2103.      * point given to us by the MDEF.
  2104.      */
  2105.     oldItem = *whichItem;
  2106.     if (oldItem >= menuPtr->numEntries) {
  2107. oldItem = -1;
  2108.     }
  2109.     portRect.top = 0;
  2110.     portRect.bottom = 1280;
  2111.     maxMenuHeight = screenBits.bounds.bottom - screenBits.bounds.top
  2112.     - menuBarHeight - SCREEN_MARGIN;
  2113.     if (menuPtr->totalHeight > maxMenuHeight) {
  2114. menuRectPtr->top = menuBarHeight;
  2115.     } else {
  2116. int delta;
  2117. menuRectPtr->top = hitPt.h;
  2118. if (oldItem >= 0) {
  2119.     menuRectPtr->top -= menuPtr->entries[oldItem]->y;
  2120. }
  2121. if (menuRectPtr->top < menuBarHeight) {
  2122.     /*
  2123.      * Displace downward if the menu would stick off the top of the
  2124.      * screen.
  2125.      */
  2126.     menuRectPtr->top = menuBarHeight + SCREEN_MARGIN;
  2127. } else {
  2128.     /*
  2129.      * Or upward if the menu sticks off the bottom end...
  2130.      */
  2131.     delta = menuRectPtr->top + menuPtr->totalHeight - maxMenuHeight;
  2132.     if (delta > 0) {
  2133. menuRectPtr->top -= delta;
  2134.     }
  2135. }
  2136.     }
  2137.     menuRectPtr->left = hitPt.v;
  2138.     menuRectPtr->right = menuRectPtr->left + menuPtr->totalWidth;
  2139.     menuRectPtr->bottom = menuRectPtr->top +
  2140.     ((maxMenuHeight < menuPtr->totalHeight)
  2141.     ? maxMenuHeight : menuPtr->totalHeight);
  2142.     if (menuRectPtr->top == menuBarHeight) {
  2143. *whichItem = hitPt.h;
  2144.     } else {
  2145. *whichItem = menuRectPtr->top;
  2146.     }
  2147. }
  2148. /*
  2149.  *----------------------------------------------------------------------
  2150.  *
  2151.  * HandleMenuCalcItemMsg --
  2152.  *
  2153.  * Handles the MenuDefProc's CalcItem message. It is supposed
  2154.  * to calculate the Rect of the menu entry in whichItem in the
  2155.  * menu, and put that in menuRectPtr. I assume this works, but I
  2156.  * have never seen the MenuManager send this message.
  2157.  *
  2158.  * Results:
  2159.  * The Menu Manager is informed of the bounding rect of a
  2160.  * menu rect.
  2161.  *
  2162.  * Side effects:
  2163.  * None.
  2164.  *
  2165.  *----------------------------------------------------------------------
  2166.  */
  2167. void
  2168. HandleMenuCalcItemMsg(
  2169.     MenuRef menu,
  2170.     Rect *menuRectPtr,
  2171.     Point hitPt,
  2172.     SInt16 *whichItem,
  2173.     TkMenu *menuPtr)
  2174. {
  2175.     TkMenuEntry *mePtr;
  2176.     MenuTrackingData mtd, *mtdPtr = &mtd;
  2177.     OSStatus err;
  2178.     int virtualTop, item = *whichItem-1;
  2179.     err = ChkErr(GetMenuTrackingData, menu, mtdPtr);
  2180.     if (err == noErr) {
  2181. virtualTop = mtdPtr->virtualMenuTop;
  2182.     } else {
  2183. virtualTop = 0;
  2184.     }
  2185.     if (item >= 0 && item < menuPtr->numEntries) {
  2186. mePtr = menuPtr->entries[item];
  2187. menuRectPtr->left = mePtr->x;
  2188. menuRectPtr->top = mePtr->y + virtualTop;
  2189. if (mePtr->entryFlags & ENTRY_LAST_COLUMN) {
  2190.     menuRectPtr->right = menuPtr->totalWidth;
  2191. } else {
  2192.     menuRectPtr->right = mePtr->x + mePtr->width;
  2193. }
  2194. menuRectPtr->bottom = menuRectPtr->top + mePtr->height;
  2195.     }
  2196. #ifdef TK_MAC_DEBUG_MENUS
  2197.     TkMacOSXDbgMsg("MDEF: CalcItemMsg %d: %d, %d", *whichItem,
  2198.     menuRectPtr->left, menuRectPtr->top);
  2199. #endif
  2200. }
  2201. #endif /* USE_TK_MDEF */