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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUnixMenu.c --
  3.  *
  4.  * This module implements the UNIX platform-specific features of menus.
  5.  *
  6.  * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
  7.  *
  8.  * See the file "license.terms" for information on usage and redistribution
  9.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  10.  *
  11.  * RCS: @(#) $Id: tkUnixMenu.c,v 1.7.2.2 2006/11/24 18:11:54 hobbs Exp $
  12.  */
  13. #include "tkPort.h"
  14. #include "default.h"
  15. #include "tkInt.h"
  16. #include "tkUnixInt.h"
  17. #include "tkMenu.h"
  18. /*
  19.  * Constants used for menu drawing.
  20.  */
  21. #define MENU_MARGIN_WIDTH 2
  22. #define MENU_DIVIDER_HEIGHT 2
  23. /*
  24.  * Platform specific flags for Unix.
  25.  */
  26. #define ENTRY_HELP_MENU ENTRY_PLATFORM_FLAG1
  27. /*
  28.  * Procedures used internally.
  29.  */
  30. static void SetHelpMenu _ANSI_ARGS_((TkMenu *menuPtr));
  31. static void DrawMenuEntryAccelerator _ANSI_ARGS_((
  32.     TkMenu *menuPtr, TkMenuEntry *mePtr, 
  33.     Drawable d, GC gc, Tk_Font tkfont,
  34.     CONST Tk_FontMetrics *fmPtr,
  35.     Tk_3DBorder activeBorder, int x, int y,
  36.     int width, int height, int drawArrow));
  37. static void DrawMenuEntryBackground _ANSI_ARGS_((
  38.     TkMenu *menuPtr, TkMenuEntry *mePtr,
  39.     Drawable d, Tk_3DBorder activeBorder,
  40.     Tk_3DBorder bgBorder, int x, int y,
  41.     int width, int heigth));
  42. static void DrawMenuEntryIndicator _ANSI_ARGS_((
  43.     TkMenu *menuPtr, TkMenuEntry *mePtr,
  44.     Drawable d, GC gc, GC indicatorGC, 
  45.     Tk_Font tkfont,
  46.     CONST Tk_FontMetrics *fmPtr, int x, int y,
  47.     int width, int height));
  48. static void DrawMenuEntryLabel _ANSI_ARGS_((
  49.     TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
  50.     GC gc, Tk_Font tkfont,
  51.     CONST Tk_FontMetrics *fmPtr, int x, int y,
  52.     int width, int height));
  53. static void DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
  54.     TkMenuEntry *mePtr, Drawable d, GC gc, 
  55.     Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  56.     int x, int y, int width, int height));
  57. static void DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
  58.     TkMenuEntry *mePtr, Drawable d, GC gc, 
  59.     Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  60.     int x, int y, int width, int height));
  61. static void DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr,
  62.     TkMenuEntry *mePtr, Drawable d, GC gc,
  63.     Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x,
  64.     int y, int width, int height));
  65. static void GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  66.     TkMenuEntry *mePtr, Tk_Font tkfont,
  67.     CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  68.     int *heightPtr));
  69. static void GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
  70.     Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  71.     int *widthPtr, int *heightPtr));
  72. static void GetMenuIndicatorGeometry _ANSI_ARGS_((
  73.     TkMenu *menuPtr, TkMenuEntry *mePtr, 
  74.     Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
  75.     int *widthPtr, int *heightPtr));
  76. static void GetMenuSeparatorGeometry _ANSI_ARGS_((
  77.     TkMenu *menuPtr, TkMenuEntry *mePtr,
  78.     Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
  79.     int *widthPtr, int *heightPtr));
  80. static void GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
  81.     TkMenuEntry *mePtr, Tk_Font tkfont,
  82.     CONST Tk_FontMetrics *fmPtr, int *widthPtr,
  83.     int *heightPtr));
  84. /*
  85.  *----------------------------------------------------------------------
  86.  *
  87.  * TkpNewMenu --
  88.  *
  89.  * Gets the platform-specific piece of the menu. Invoked during idle
  90.  * after the generic part of the menu has been created.
  91.  *
  92.  * Results:
  93.  * Standard TCL error.
  94.  *
  95.  * Side effects:
  96.  * Allocates any platform specific allocations and places them
  97.  * in the platformData field of the menuPtr.
  98.  *
  99.  *----------------------------------------------------------------------
  100.  */
  101. int
  102. TkpNewMenu(menuPtr)
  103.     TkMenu *menuPtr;
  104. {
  105.     SetHelpMenu(menuPtr);
  106.     return TCL_OK;
  107. }
  108. /*
  109.  *----------------------------------------------------------------------
  110.  *
  111.  * TkpDestroyMenu --
  112.  *
  113.  * Destroys platform-specific menu structures. Called when the
  114.  * generic menu structure is destroyed for the menu.
  115.  *
  116.  * Results:
  117.  * None.
  118.  *
  119.  * Side effects:
  120.  * All platform-specific allocations are freed up.
  121.  *
  122.  *----------------------------------------------------------------------
  123.  */
  124. void
  125. TkpDestroyMenu(menuPtr)
  126.     TkMenu *menuPtr;
  127. {
  128.     /*
  129.      * Nothing to do.
  130.      */
  131. }
  132. /*
  133.  *----------------------------------------------------------------------
  134.  *
  135.  * TkpDestroyMenuEntry --
  136.  *
  137.  * Cleans up platform-specific menu entry items. Called when entry
  138.  * is destroyed in the generic code.
  139.  *
  140.  * Results:
  141.  * None.
  142.  *
  143.  * Side effects:
  144.  * All platform specific allocations are freed up.
  145.  *
  146.  *----------------------------------------------------------------------
  147.  */
  148. void
  149. TkpDestroyMenuEntry(mEntryPtr)
  150.     TkMenuEntry *mEntryPtr;
  151. {
  152.     /*
  153.      * Nothing to do.
  154.      */
  155. }
  156. /*
  157.  *----------------------------------------------------------------------
  158.  *
  159.  * TkpConfigureMenuEntry --
  160.  *
  161.  * Processes configuration options for menu entries. Called when
  162.  * the generic options are processed for the menu.
  163.  *
  164.  * Results:
  165.  * Returns standard TCL result. If TCL_ERROR is returned, then
  166.  * the interp's result contains an error message.
  167.  *
  168.  * Side effects:
  169.  * Configuration information get set for mePtr; old resources
  170.  * get freed, if any need it.
  171.  *
  172.  *----------------------------------------------------------------------
  173.  */
  174. int
  175. TkpConfigureMenuEntry(mePtr)
  176.     register TkMenuEntry *mePtr; /* Information about menu entry;  may
  177.  * or may not already have values for
  178.  * some fields. */
  179. {
  180.     /*
  181.      * If this is a cascade menu, and the child menu exists, check to
  182.      * see if the child menu is a help menu.
  183.      */
  184.     if ((mePtr->type == CASCADE_ENTRY) && (mePtr->namePtr != NULL)) {
  185. TkMenuReferences *menuRefPtr;
  186. menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp,
  187. mePtr->namePtr);
  188. if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) {
  189.     SetHelpMenu(menuRefPtr->menuPtr);
  190. }
  191.     }
  192.     return TCL_OK;
  193. }
  194. /*
  195.  *----------------------------------------------------------------------
  196.  *
  197.  * TkpMenuNewEntry --
  198.  *
  199.  * Called when a new entry is created in a menu. Fills in platform
  200.  * specific data for the entry. The platformEntryData field
  201.  * is used to store the indicator diameter for radio button
  202.  * and check box entries.
  203.  *
  204.  * Results:
  205.  *  Standard TCL error.
  206.  *
  207.  * Side effects:
  208.  * None on Unix.
  209.  *
  210.  *----------------------------------------------------------------------
  211.  */
  212. int
  213. TkpMenuNewEntry(mePtr)
  214.     TkMenuEntry *mePtr;
  215. {
  216.     return TCL_OK;
  217. }
  218. /*
  219.  *----------------------------------------------------------------------
  220.  *
  221.  * TkpSetWindowMenuBar --
  222.  *
  223.  * Sets up the menu as a menubar in the given window.
  224.  *
  225.  * Results:
  226.  * None.
  227.  *
  228.  * Side effects:
  229.  * Recomputes geometry of given window.
  230.  *
  231.  *----------------------------------------------------------------------
  232.  */
  233. void
  234. TkpSetWindowMenuBar(tkwin, menuPtr)
  235.     Tk_Window tkwin; /* The window we are setting */
  236.     TkMenu *menuPtr; /* The menu we are setting */
  237. {
  238.     if (menuPtr == NULL) {
  239. TkUnixSetMenubar(tkwin, NULL);
  240.     } else {
  241. TkUnixSetMenubar(tkwin, menuPtr->tkwin);
  242.     }
  243. }
  244. /*
  245.  *----------------------------------------------------------------------
  246.  *
  247.  * TkpSetMainMenuBar --
  248.  *
  249.  * Called when a toplevel widget is brought to front. On the
  250.  * Macintosh, sets up the menubar that goes accross the top
  251.  * of the main monitor. On other platforms, nothing is necessary.
  252.  *
  253.  * Results:
  254.  * None.
  255.  *
  256.  * Side effects:
  257.  * Recompute geometry of given window.
  258.  *
  259.  *----------------------------------------------------------------------
  260.  */
  261. void
  262. TkpSetMainMenubar(interp, tkwin, menuName)
  263.     Tcl_Interp *interp;
  264.     Tk_Window tkwin;
  265.     char *menuName;
  266. {
  267.     /*
  268.      * Nothing to do.
  269.      */
  270. }
  271. /*
  272.  *----------------------------------------------------------------------
  273.  *
  274.  * GetMenuIndicatorGeometry --
  275.  *
  276.  * Fills out the geometry of the indicator in a menu item. Note
  277.  * that the mePtr->height field must have already been filled in
  278.  * by GetMenuLabelGeometry since this height depends on the label
  279.  * height.
  280.  *
  281.  * Results:
  282.  * widthPtr and heightPtr point to the new geometry values.
  283.  *
  284.  * Side effects:
  285.  * None.
  286.  *
  287.  *----------------------------------------------------------------------
  288.  */
  289. static void
  290. GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  291.     TkMenu *menuPtr; /* The menu we are drawing. */
  292.     TkMenuEntry *mePtr; /* The entry we are interested in. */
  293.     Tk_Font tkfont; /* The precalculated font */
  294.     CONST Tk_FontMetrics *fmPtr; /* The precalculated metrics */
  295.     int *widthPtr; /* The resulting width */
  296.     int *heightPtr; /* The resulting height */
  297. {
  298.     if ((mePtr->type == CHECK_BUTTON_ENTRY)
  299.     || (mePtr->type == RADIO_BUTTON_ENTRY)) {
  300. if (!mePtr->hideMargin && mePtr->indicatorOn) {
  301.     if ((mePtr->image != NULL) || (mePtr->bitmapPtr != NULL)) {
  302. *widthPtr = (14 * mePtr->height) / 10;
  303. *heightPtr = mePtr->height;
  304. if (mePtr->type == CHECK_BUTTON_ENTRY) {
  305.     mePtr->platformEntryData = 
  306.     (TkMenuPlatformEntryData) ((65 * mePtr->height)
  307.     / 100);
  308. } else {
  309.     mePtr->platformEntryData = 
  310.     (TkMenuPlatformEntryData) ((75 * mePtr->height)
  311.     / 100);
  312. }             
  313.     } else {
  314. *widthPtr = *heightPtr = mePtr->height;
  315. if (mePtr->type == CHECK_BUTTON_ENTRY) {
  316.     mePtr->platformEntryData = (TkMenuPlatformEntryData)
  317. ((80 * mePtr->height) / 100);
  318. } else {
  319.     mePtr->platformEntryData = (TkMenuPlatformEntryData)
  320. mePtr->height;
  321. }
  322.     }
  323. } else {
  324.     int borderWidth;
  325.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
  326.     menuPtr->borderWidthPtr, &borderWidth);
  327.     *heightPtr = 0;
  328.     *widthPtr = borderWidth;
  329. }
  330.     } else {
  331. int borderWidth;
  332. Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
  333. &borderWidth);
  334.         *heightPtr = 0;
  335.         *widthPtr = borderWidth;
  336.     }
  337. }
  338. /*
  339.  *----------------------------------------------------------------------
  340.  *
  341.  * GetMenuAccelGeometry --
  342.  *
  343.  * Get the geometry of the accelerator area of a menu item.
  344.  *
  345.  * Results:
  346.  * heightPtr and widthPtr are set.
  347.  *
  348.  * Side effects:
  349.  * None.
  350.  *
  351.  *----------------------------------------------------------------------
  352.  */
  353. static void
  354. GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  355.     TkMenu *menuPtr; /* The menu was are drawing */
  356.     TkMenuEntry *mePtr; /* The entry we are getting the geometry for */
  357.     Tk_Font tkfont; /* The precalculated font */
  358.     CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */
  359.     int *widthPtr; /* The width of the acclerator area */
  360.     int *heightPtr; /* The height of the accelerator area */
  361. {
  362.     *heightPtr = fmPtr->linespace;
  363.     if (mePtr->type == CASCADE_ENTRY) {
  364.      *widthPtr = 2 * CASCADE_ARROW_WIDTH;
  365.     } else if ((menuPtr->menuType != MENUBAR)
  366.     && (mePtr->accelPtr != NULL)) {
  367. char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL);
  368.      *widthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength);
  369.     } else {
  370.      *widthPtr = 0;
  371.     }
  372. }
  373. /*
  374.  *----------------------------------------------------------------------
  375.  *
  376.  * DrawMenuEntryBackground --
  377.  *
  378.  * This procedure draws the background part of a menu.
  379.  *
  380.  * Results:
  381.  * None.
  382.  *
  383.  * Side effects:
  384.  * Commands are output to X to display the menu in its
  385.  * current mode.
  386.  *
  387.  *----------------------------------------------------------------------
  388.  */
  389. static void
  390. DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y,
  391. width, height)
  392.     TkMenu *menuPtr; /* The menu we are drawing */
  393.     TkMenuEntry *mePtr; /* The entry we are drawing. */
  394.     Drawable d; /* The drawable we are drawing into */
  395.     Tk_3DBorder activeBorder; /* The border for an active item */
  396.     Tk_3DBorder bgBorder; /* The background border */
  397.     int x; /* Left coordinate of entry rect */
  398.     int y; /* Right coordinate of entry rect */
  399.     int width; /* Width of entry rect */
  400.     int height; /* Height of entry rect */
  401. {
  402.     if (mePtr->state == ENTRY_ACTIVE) {
  403. int relief;
  404. int activeBorderWidth;
  405.      bgBorder = activeBorder;
  406. if ((menuPtr->menuType == MENUBAR)
  407. && ((menuPtr->postedCascade == NULL)
  408. || (menuPtr->postedCascade != mePtr))) {
  409.     relief = TK_RELIEF_FLAT;
  410. } else {
  411.     relief = TK_RELIEF_RAISED;
  412. }
  413. Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
  414. menuPtr->activeBorderWidthPtr, &activeBorderWidth);
  415. Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
  416. activeBorderWidth, relief);
  417.     } else {
  418. Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
  419. 0, TK_RELIEF_FLAT);
  420.     }
  421. }
  422. /*
  423.  *----------------------------------------------------------------------
  424.  *
  425.  * DrawMenuEntryAccelerator --
  426.  *
  427.  * This procedure draws the background part of a menu.
  428.  *
  429.  * Results:
  430.  * None.
  431.  *
  432.  * Side effects:
  433.  * Commands are output to X to display the menu in its
  434.  * current mode.
  435.  *
  436.  *----------------------------------------------------------------------
  437.  */
  438. static void
  439. DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder,
  440. x, y, width, height, drawArrow)
  441.     TkMenu *menuPtr; /* The menu we are drawing */
  442.     TkMenuEntry *mePtr; /* The entry we are drawing */
  443.     Drawable d; /* The drawable we are drawing into */
  444.     GC gc; /* The precalculated gc to draw with */
  445.     Tk_Font tkfont; /* The precalculated font */
  446.     CONST Tk_FontMetrics *fmPtr; /* The precalculated metrics */
  447.     Tk_3DBorder activeBorder; /* The border for an active item */
  448.     int x; /* Left coordinate of entry rect */
  449.     int y; /* Top coordinate of entry rect */
  450.     int width; /* Width of entry */
  451.     int height; /* Height of entry */
  452.     int drawArrow; /* Whether or not to draw arrow. */
  453. {
  454.     XPoint points[3];
  455.     int borderWidth, activeBorderWidth;
  456.     
  457.     /*
  458.      * Draw accelerator or cascade arrow.
  459.      */
  460.     if (menuPtr->menuType == MENUBAR) {
  461. return;
  462.     }
  463.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
  464.     &borderWidth);
  465.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
  466.     &activeBorderWidth);
  467.     if ((mePtr->type == CASCADE_ENTRY) && drawArrow) {
  468.      points[0].x = x + width - borderWidth - activeBorderWidth
  469.         - CASCADE_ARROW_WIDTH;
  470.      points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2;
  471.      points[1].x = points[0].x;
  472.      points[1].y = points[0].y + CASCADE_ARROW_HEIGHT;
  473.      points[2].x = points[0].x + CASCADE_ARROW_WIDTH;
  474.      points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2;
  475.      Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points, 3,
  476. DECORATION_BORDER_WIDTH,
  477.      (menuPtr->postedCascade == mePtr)
  478.      ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
  479.     } else if (mePtr->accelPtr != NULL) {
  480. char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL);
  481. int left = x + mePtr->labelWidth + activeBorderWidth
  482.         + mePtr->indicatorSpace;
  483. if (menuPtr->menuType == MENUBAR) {
  484.     left += 5;
  485. }
  486.      Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel,
  487. mePtr->accelLength, left,
  488. (y + (height + fmPtr->ascent - fmPtr->descent) / 2));
  489.     }
  490. }
  491. /*
  492.  *----------------------------------------------------------------------
  493.  *
  494.  * DrawMenuEntryIndicator --
  495.  *
  496.  * This procedure draws the background part of a menu.
  497.  *
  498.  * Results:
  499.  * None.
  500.  *
  501.  * Side effects:
  502.  * Commands are output to X to display the menu in its
  503.  * current mode.
  504.  *
  505.  *----------------------------------------------------------------------
  506.  */
  507. static void
  508. DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr,
  509. x, y, width, height)
  510.     TkMenu *menuPtr; /* The menu we are drawing */
  511.     TkMenuEntry *mePtr; /* The entry we are drawing */
  512.     Drawable d; /* The drawable to draw into */
  513.     GC gc; /* The gc to draw with */
  514.     GC indicatorGC; /* The gc that indicators draw with */
  515.     Tk_Font tkfont; /* The font to draw with */
  516.     CONST Tk_FontMetrics *fmPtr; /* The font metrics of the font */
  517.     int x; /* The left of the entry rect */
  518.     int y; /* The top of the entry rect */
  519.     int width; /* Width of menu entry */
  520.     int height; /* Height of menu entry */
  521. {
  522.     /*
  523.      * Draw check-button indicator.
  524.      */
  525.     if ((mePtr->type == CHECK_BUTTON_ENTRY) && mePtr->indicatorOn) {
  526. int dim, top, left;
  527. int activeBorderWidth;
  528. Tk_3DBorder border;
  529. dim = (int) mePtr->platformEntryData;
  530. Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
  531. menuPtr->activeBorderWidthPtr, &activeBorderWidth);
  532. left = x + activeBorderWidth + (mePtr->indicatorSpace - dim)/2;
  533. if (menuPtr->menuType == MENUBAR) {
  534.     left += 5;
  535. }
  536. top = y + (height - dim)/2;
  537. border = Tk_Get3DBorderFromObj(menuPtr->tkwin,
  538. menuPtr->borderPtr);
  539. Tk_Fill3DRectangle(menuPtr->tkwin, d, border, left, top, dim,
  540. dim, DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
  541. left += DECORATION_BORDER_WIDTH;
  542. top += DECORATION_BORDER_WIDTH;
  543. dim -= 2*DECORATION_BORDER_WIDTH;
  544. if ((dim > 0) && (mePtr->entryFlags
  545. & ENTRY_SELECTED)) {
  546.     XFillRectangle(menuPtr->display, d, indicatorGC, left, top,
  547.     (unsigned int) dim, (unsigned int) dim);
  548. }
  549.     }
  550.     /*
  551.      * Draw radio-button indicator.
  552.      */
  553.     if ((mePtr->type == RADIO_BUTTON_ENTRY) && mePtr->indicatorOn) {
  554. XPoint points[4];
  555. int radius;
  556. Tk_3DBorder border;
  557. border = Tk_Get3DBorderFromObj(menuPtr->tkwin, 
  558. menuPtr->borderPtr);
  559. radius = ((int) mePtr->platformEntryData)/2;
  560. points[0].x = x + (mePtr->indicatorSpace
  561. - (int) mePtr->platformEntryData)/2;
  562. points[0].y = y + (height)/2;
  563. points[1].x = points[0].x + radius;
  564. points[1].y = points[0].y + radius;
  565. points[2].x = points[1].x + radius;
  566. points[2].y = points[0].y;
  567. points[3].x = points[1].x;
  568. points[3].y = points[0].y - radius;
  569. if (mePtr->entryFlags & ENTRY_SELECTED) {
  570.     XFillPolygon(menuPtr->display, d, indicatorGC, points, 4,
  571.     Convex, CoordModeOrigin);
  572. } else {
  573.     Tk_Fill3DPolygon(menuPtr->tkwin, d, border, points, 4,
  574.     DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
  575. }
  576. Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 4,
  577. DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
  578.     }
  579. }
  580. /*
  581.  *----------------------------------------------------------------------
  582.  *
  583.  * DrawMenuSeparator --
  584.  *
  585.  * This procedure draws a separator menu item.
  586.  *
  587.  * Results:
  588.  * None.
  589.  *
  590.  * Side effects:
  591.  * Commands are output to X to display the menu in its
  592.  * current mode.
  593.  *
  594.  *----------------------------------------------------------------------
  595.  */
  596. static void
  597. DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  598.     TkMenu *menuPtr; /* The menu we are drawing */
  599.     TkMenuEntry *mePtr; /* The entry we are drawing */
  600.     Drawable d; /* The drawable we are using */
  601.     GC gc; /* The gc to draw into */
  602.     Tk_Font tkfont; /* The font to draw with */
  603.     CONST Tk_FontMetrics *fmPtr; /* The font metrics from the font */
  604.     int x;
  605.     int y;
  606.     int width;
  607.     int height;
  608. {
  609.     XPoint points[2];
  610.     Tk_3DBorder border;
  611.     if (menuPtr->menuType == MENUBAR) {
  612. return;
  613.     }
  614.     
  615.     points[0].x = x;
  616.     points[0].y = y + height/2;
  617.     points[1].x = width - 1;
  618.     points[1].y = points[0].y;
  619.     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
  620.     Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
  621.     TK_RELIEF_RAISED);
  622. }
  623. /*
  624.  *----------------------------------------------------------------------
  625.  *
  626.  * DrawMenuEntryLabel --
  627.  *
  628.  * This procedure draws the label part of a menu.
  629.  *
  630.  * Results:
  631.  * None.
  632.  *
  633.  * Side effects:
  634.  * Commands are output to X to display the menu in its
  635.  * current mode.
  636.  *
  637.  *----------------------------------------------------------------------
  638.  */
  639. static void
  640. DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  641.     TkMenu *menuPtr; /* The menu we are drawing. */
  642.     TkMenuEntry *mePtr; /* The entry we are drawing. */
  643.     Drawable d; /* What we are drawing into. */
  644.     GC gc; /* The gc we are drawing into.*/
  645.     Tk_Font tkfont; /* The precalculated font. */
  646.     CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics. */
  647.     int x; /* Left edge. */
  648.     int y; /* Top edge. */
  649.     int width; /* width of entry. */
  650.     int height; /* height of entry. */
  651. {
  652.     int indicatorSpace =  mePtr->indicatorSpace;
  653.     int activeBorderWidth;
  654.     int leftEdge;
  655.     int imageHeight, imageWidth;
  656.     int textHeight = 0, textWidth = 0; /* stop GCC warning */
  657.     int haveImage = 0, haveText = 0;
  658.     int imageXOffset = 0, imageYOffset = 0;
  659.     int textXOffset = 0, textYOffset = 0;
  660.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
  661.     &activeBorderWidth);
  662.     leftEdge = x + indicatorSpace + activeBorderWidth;
  663.     if (menuPtr->menuType == MENUBAR) {
  664. leftEdge += 5;
  665.     }
  666.     
  667.     /*
  668.      * Work out what we will need to draw first.
  669.      */
  670.     if (mePtr->image != NULL) {
  671.      Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
  672. haveImage = 1;
  673.     } else if (mePtr->bitmapPtr != NULL) {
  674. Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
  675. Tk_SizeOfBitmap(menuPtr->display, bitmap, &imageWidth, &imageHeight);
  676. haveImage = 1;
  677.     }
  678.     if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
  679. if (mePtr->labelLength > 0) {
  680.     char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
  681.     textWidth = Tk_TextWidth(tkfont, label, mePtr->labelLength);
  682.     textHeight = fmPtr->linespace;
  683.     haveText = 1;
  684. }
  685.     }
  686.     
  687.     /*
  688.      * Now work out what the relative positions are.
  689.      */
  690.     if (haveImage && haveText) {
  691. int fullWidth = (imageWidth > textWidth ? imageWidth : textWidth);
  692. switch ((enum compound) mePtr->compound) {
  693.     case COMPOUND_TOP: {
  694. textXOffset = (fullWidth - textWidth)/2;
  695. textYOffset = imageHeight/2 + 2;
  696. imageXOffset = (fullWidth - imageWidth)/2;
  697. imageYOffset = -textHeight/2;
  698. break;
  699.     }
  700.     case COMPOUND_BOTTOM: {
  701. textXOffset = (fullWidth - textWidth)/2;
  702. textYOffset = -imageHeight/2;
  703. imageXOffset = (fullWidth - imageWidth)/2;
  704. imageYOffset = textHeight/2 + 2;
  705. break;
  706.     }
  707.     case COMPOUND_LEFT: {
  708. /*
  709.  * Position image in the indicator space to the left of the
  710.  * entries, unless this entry is a radio|check button because
  711.  * then the indicator space will be used.
  712.  */
  713. textXOffset = imageWidth + 2;
  714. textYOffset = 0;
  715. imageXOffset = 0;
  716. imageYOffset = 0;
  717. if ((mePtr->type != CHECK_BUTTON_ENTRY) 
  718. && (mePtr->type != RADIO_BUTTON_ENTRY)) {
  719.     textXOffset -= indicatorSpace;
  720.     if (textXOffset < 0) {
  721. textXOffset = 0;
  722.     }
  723.     imageXOffset = -indicatorSpace;
  724. }
  725. break;
  726.     }
  727.     case COMPOUND_RIGHT: {
  728. textXOffset = 0;
  729. textYOffset = 0;
  730. imageXOffset = textWidth + 2;
  731. imageYOffset = 0;
  732. break;
  733.     }
  734.     case COMPOUND_CENTER: {
  735. textXOffset = (fullWidth - textWidth)/2;
  736. textYOffset = 0;
  737. imageXOffset = (fullWidth - imageWidth)/2;
  738. imageYOffset = 0;
  739. break;
  740.     }
  741.     case COMPOUND_NONE: {break;}
  742. }
  743.     } else {
  744. textXOffset = 0;
  745. textYOffset = 0;
  746. imageXOffset = 0;
  747. imageYOffset = 0;
  748.     }
  749.     
  750.     /*
  751.      * Draw label and/or bitmap or image for entry.
  752.      */
  753.     if (mePtr->image != NULL) {
  754.      if ((mePtr->selectImage != NULL)
  755.      && (mePtr->entryFlags & ENTRY_SELECTED)) {
  756.     Tk_RedrawImage(mePtr->selectImage, 0, 0,
  757.     imageWidth, imageHeight, d, leftEdge + imageXOffset,
  758.     (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset));
  759.      } else {
  760.     Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
  761.     imageHeight, d, leftEdge + imageXOffset,
  762.     (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset));
  763.      }
  764.     } else if (mePtr->bitmapPtr != None) {
  765. Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
  766. XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, 
  767. (unsigned) imageWidth, (unsigned) imageHeight, 
  768. leftEdge + imageXOffset,
  769. (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset), 1);
  770.     }
  771.     if ((mePtr->compound != COMPOUND_NONE) || !haveImage) {
  772. int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
  773.      if (mePtr->labelLength > 0) {
  774.     char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
  775.     Tk_DrawChars(menuPtr->display, d, gc, tkfont, label,
  776.     mePtr->labelLength, leftEdge + textXOffset, 
  777.     baseline + textYOffset);
  778.     DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, 
  779.     x + textXOffset, y + textYOffset,
  780.     width, height);
  781.      }
  782.     }
  783.     if (mePtr->state == ENTRY_DISABLED) {
  784. if (menuPtr->disabledFgPtr == NULL) {
  785.     XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
  786.     (unsigned) width, (unsigned) height);
  787. } else if ((mePtr->image != NULL) 
  788. && (menuPtr->disabledImageGC != None)) {
  789.     XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
  790.     leftEdge + imageXOffset,
  791.     (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset),
  792.     (unsigned) imageWidth, (unsigned) imageHeight);
  793. }
  794.     }
  795. }
  796. /*
  797.  *----------------------------------------------------------------------
  798.  *
  799.  * DrawMenuUnderline --
  800.  *
  801.  * On appropriate platforms, draw the underline character for the
  802.  * menu.
  803.  *
  804.  * Results:
  805.  * None.
  806.  *
  807.  * Side effects:
  808.  * Commands are output to X to display the menu in its
  809.  * current mode.
  810.  *
  811.  *----------------------------------------------------------------------
  812.  */
  813. static void
  814. DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  815.     TkMenu *menuPtr; /* The menu to draw into */
  816.     TkMenuEntry *mePtr; /* The entry we are drawing */
  817.     Drawable d; /* What we are drawing into */
  818.     GC gc; /* The gc to draw into */
  819.     Tk_Font tkfont; /* The precalculated font */
  820.     CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */
  821.     int x;
  822.     int y;
  823.     int width;
  824.     int height;
  825. {
  826.     if ((mePtr->underline >= 0) && (mePtr->labelPtr != NULL)) {
  827. int len;
  828. /* do the unicode call just to prevent overruns */
  829. Tcl_GetUnicodeFromObj(mePtr->labelPtr, &len);
  830. if (mePtr->underline < len) {
  831.     int activeBorderWidth;
  832.     int leftEdge;
  833.     CONST char *label, *start, *end;
  834.     label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
  835.     start = Tcl_UtfAtIndex(label, mePtr->underline);
  836.     end = Tcl_UtfNext(start);
  837.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
  838.     menuPtr->activeBorderWidthPtr, &activeBorderWidth);
  839.     leftEdge = x + mePtr->indicatorSpace + activeBorderWidth;
  840.     if (menuPtr->menuType == MENUBAR) {
  841. leftEdge += 5;
  842.     }
  843.     Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, label, leftEdge,
  844.     y + (height + fmPtr->ascent - fmPtr->descent) / 2,
  845.     start - label, end - label);
  846. }
  847.     }
  848. }
  849. /*
  850.  *----------------------------------------------------------------------
  851.  *
  852.  * TkpPostMenu --
  853.  *
  854.  * Posts a menu on the screen
  855.  *
  856.  * Results:
  857.  * None.
  858.  *
  859.  * Side effects:
  860.  * The menu is posted and handled.
  861.  *
  862.  *----------------------------------------------------------------------
  863.  */
  864. int
  865. TkpPostMenu(interp, menuPtr, x, y)
  866.     Tcl_Interp *interp;
  867.     TkMenu *menuPtr;
  868.     int x;
  869.     int y;
  870. {
  871.     return TkPostTearoffMenu(interp, menuPtr, x, y);
  872. }
  873. /*
  874.  *----------------------------------------------------------------------
  875.  *
  876.  * GetMenuSeparatorGeometry --
  877.  *
  878.  * Gets the width and height of the indicator area of a menu.
  879.  *
  880.  * Results:
  881.  * widthPtr and heightPtr are set.
  882.  *
  883.  * Side effects:
  884.  * None.
  885.  *
  886.  *----------------------------------------------------------------------
  887.  */
  888. static void
  889. GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr,
  890. heightPtr) 
  891.     TkMenu *menuPtr; /* The menu we are measuring */
  892.     TkMenuEntry *mePtr; /* The entry we are measuring */
  893.     Tk_Font tkfont; /* The precalculated font */
  894.     CONST Tk_FontMetrics *fmPtr; /* The precalcualted font metrics */
  895.     int *widthPtr; /* The resulting width */
  896.     int *heightPtr; /* The resulting height */
  897. {
  898.     *widthPtr = 0;
  899.     *heightPtr = fmPtr->linespace;
  900. }
  901. /*
  902.  *----------------------------------------------------------------------
  903.  *
  904.  * GetTearoffEntryGeometry --
  905.  *
  906.  * Gets the width and height of the indicator area of a menu.
  907.  *
  908.  * Results:
  909.  * widthPtr and heightPtr are set.
  910.  *
  911.  * Side effects:
  912.  * None.
  913.  *
  914.  *----------------------------------------------------------------------
  915.  */
  916. static void
  917. GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  918.     TkMenu *menuPtr; /* The menu we are drawing */
  919.     TkMenuEntry *mePtr; /* The entry we are measuring */
  920.     Tk_Font tkfont; /* The precalculated font */
  921.     CONST Tk_FontMetrics *fmPtr; /* The precalculated font metrics */
  922.     int *widthPtr; /* The resulting width */
  923.     int *heightPtr; /* The resulting height */
  924. {
  925.     if (menuPtr->menuType != MASTER_MENU) {
  926. *heightPtr = 0;
  927. *widthPtr = 0;
  928.     } else {
  929. *heightPtr = fmPtr->linespace;
  930. *widthPtr = Tk_TextWidth(tkfont, "W", 1);
  931.     }
  932. }
  933. /*
  934.  *--------------------------------------------------------------
  935.  *
  936.  * TkpComputeMenubarGeometry --
  937.  *
  938.  * This procedure is invoked to recompute the size and
  939.  * layout of a menu that is a menubar clone.
  940.  *
  941.  * Results:
  942.  * None.
  943.  *
  944.  * Side effects:
  945.  * Fields of menu entries are changed to reflect their
  946.  * current positions, and the size of the menu window
  947.  * itself may be changed.
  948.  *
  949.  *--------------------------------------------------------------
  950.  */
  951. void
  952. TkpComputeMenubarGeometry(menuPtr)
  953.     TkMenu *menuPtr; /* Structure describing menu. */
  954. {
  955.     Tk_Font tkfont;
  956.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  957.     int width, height;
  958.     int i, j;
  959.     int x, y, currentRowHeight, maxWidth;
  960.     int maxWindowWidth;
  961.     int lastRowBreak;
  962.     int helpMenuIndex = -1;
  963.     TkMenuEntry *mePtr;
  964.     int lastEntry;
  965.     Tk_Font menuFont;
  966.     int borderWidth;
  967.     int activeBorderWidth;
  968.     
  969.     if (menuPtr->tkwin == NULL) {
  970. return;
  971.     }
  972.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
  973.     &borderWidth);
  974.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
  975.     &activeBorderWidth);
  976.     maxWidth = 0;
  977.     if (menuPtr->numEntries == 0) {
  978. height = 0;
  979.     } else {
  980. int borderWidth;
  981. maxWindowWidth = Tk_Width(menuPtr->tkwin);
  982. if (maxWindowWidth == 1) {
  983.     maxWindowWidth = 0x7ffffff;
  984. }
  985. currentRowHeight = 0;
  986. Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
  987. &borderWidth);
  988. x = y = borderWidth;
  989. lastRowBreak = 0;
  990. /*
  991.  * On the Mac especially, getting font metrics can be quite slow,
  992.  * so we want to do it intelligently. We are going to precalculate
  993.  * them and pass them down to all of the measureing and drawing
  994.  * routines. We will measure the font metrics of the menu once,
  995.  * and if an entry has a font set, we will measure it as we come
  996.  * to it, and then we decide which set to give the geometry routines.
  997.  */
  998. menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
  999. Tk_GetFontMetrics(menuFont, &menuMetrics);
  1000. for (i = 0; i < menuPtr->numEntries; i++) {
  1001.     mePtr = menuPtr->entries[i];
  1002.     mePtr->entryFlags &= ~ENTRY_LAST_COLUMN;
  1003.     if (mePtr->fontPtr != NULL) {
  1004. tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
  1005. Tk_GetFontMetrics(tkfont, &entryMetrics);
  1006. fmPtr = &entryMetrics;
  1007.     } else {
  1008. tkfont = menuFont;
  1009. fmPtr = &menuMetrics;
  1010.     }
  1011.     /*
  1012.      * For every entry, we need to check to see whether or not we
  1013.      * wrap. If we do wrap, then we have to adjust all of the previous
  1014.      * entries' height and y position, because when we see them
  1015.      * the first time, we don't know how big its neighbor might
  1016.      * be.
  1017.      */
  1018.     
  1019.     if ((mePtr->type == SEPARATOR_ENTRY)
  1020.     || (mePtr->type == TEAROFF_ENTRY)) {
  1021. mePtr->height = mePtr->width = 0;
  1022.     } else {
  1023. GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width, &height);
  1024. mePtr->height = height + 2 * activeBorderWidth + 10;
  1025. mePtr->width = width;
  1026. GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr,
  1027. &width, &height);
  1028. mePtr->indicatorSpace = width;
  1029. if (width > 0) {
  1030.     mePtr->width += width;
  1031. }
  1032. mePtr->width += 2 * activeBorderWidth + 10;
  1033.     }
  1034.     if (mePtr->entryFlags & ENTRY_HELP_MENU) {
  1035. helpMenuIndex = i;
  1036.     } else if (x + mePtr->width + borderWidth > maxWindowWidth) {
  1037. if (i == lastRowBreak) {
  1038.     mePtr->y = y;
  1039.     mePtr->x = x;
  1040.     lastRowBreak++;
  1041.     y += mePtr->height;
  1042.     currentRowHeight = 0;
  1043. } else {
  1044.     x = borderWidth;
  1045.     for (j = lastRowBreak; j < i; j++) {
  1046. menuPtr->entries[j]->y = y + currentRowHeight
  1047.         - menuPtr->entries[j]->height;
  1048. menuPtr->entries[j]->x = x;
  1049. x += menuPtr->entries[j]->width;
  1050.     }
  1051.     lastRowBreak = i;
  1052.     y += currentRowHeight;
  1053.     currentRowHeight = mePtr->height;
  1054. }
  1055. if (x > maxWidth) {
  1056.     maxWidth = x;
  1057. }
  1058. x = borderWidth;
  1059.     } else {
  1060. x += mePtr->width;
  1061. if (mePtr->height > currentRowHeight) {
  1062.     currentRowHeight = mePtr->height;
  1063. }
  1064.     } 
  1065. }
  1066. lastEntry = menuPtr->numEntries - 1;
  1067. if (helpMenuIndex == lastEntry) {
  1068.     lastEntry--;
  1069. }
  1070. if ((lastEntry >= 0) && (x + menuPtr->entries[lastEntry]->width
  1071. + borderWidth > maxWidth)) {
  1072.     maxWidth = x + menuPtr->entries[lastEntry]->width + borderWidth;
  1073. }
  1074. x = borderWidth;
  1075. for (j = lastRowBreak; j < menuPtr->numEntries; j++) {
  1076.     if (j == helpMenuIndex) {
  1077. continue;
  1078.     }
  1079.     menuPtr->entries[j]->y = y + currentRowHeight
  1080.     - menuPtr->entries[j]->height;
  1081.     menuPtr->entries[j]->x = x;
  1082.     x += menuPtr->entries[j]->width;
  1083. }
  1084. if (helpMenuIndex != -1) {
  1085.     mePtr = menuPtr->entries[helpMenuIndex];
  1086.     if (x + mePtr->width + borderWidth > maxWindowWidth) {
  1087. y += currentRowHeight;
  1088. currentRowHeight = mePtr->height;
  1089. x = borderWidth;
  1090.     } else if (mePtr->height > currentRowHeight) {
  1091. currentRowHeight = mePtr->height;
  1092.     }
  1093.     mePtr->x = maxWindowWidth - borderWidth - mePtr->width;
  1094.     mePtr->y = y + currentRowHeight - mePtr->height;
  1095. }
  1096. height = y + currentRowHeight + borderWidth;
  1097.     }
  1098.     width = Tk_Width(menuPtr->tkwin);    
  1099.     /*
  1100.      * The X server doesn't like zero dimensions, so round up to at least
  1101.      * 1 (a zero-sized menu should never really occur, anyway).
  1102.      */
  1103.     if (width <= 0) {
  1104. width = 1;
  1105.     }
  1106.     if (height <= 0) {
  1107. height = 1;
  1108.     }
  1109.     menuPtr->totalWidth = maxWidth;
  1110.     menuPtr->totalHeight = height;
  1111. }
  1112. /*
  1113.  *----------------------------------------------------------------------
  1114.  *
  1115.  * DrawTearoffEntry --
  1116.  *
  1117.  * This procedure draws the background part of a menu.
  1118.  *
  1119.  * Results:
  1120.  * None.
  1121.  *
  1122.  * Side effects:
  1123.  * Commands are output to X to display the menu in its
  1124.  * current mode.
  1125.  *
  1126.  *----------------------------------------------------------------------
  1127.  */
  1128. static void
  1129. DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
  1130.     TkMenu *menuPtr; /* The menu we are drawing */
  1131.     TkMenuEntry *mePtr; /* The entry we are drawing */
  1132.     Drawable d; /* The drawable we are drawing into */
  1133.     GC gc; /* The gc we are drawing with */
  1134.     Tk_Font tkfont; /* The font we are drawing with */
  1135.     CONST Tk_FontMetrics *fmPtr; /* The metrics we are drawing with */
  1136.     int x;
  1137.     int y;
  1138.     int width;
  1139.     int height;
  1140. {
  1141.     XPoint points[2];
  1142.     int segmentWidth, maxX;
  1143.     Tk_3DBorder border;
  1144.     if (menuPtr->menuType != MASTER_MENU) {
  1145. return;
  1146.     }
  1147.     
  1148.     points[0].x = x;
  1149.     points[0].y = y + height/2;
  1150.     points[1].y = points[0].y;
  1151.     segmentWidth = 6;
  1152.     maxX  = width - 1;
  1153.     border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
  1154.     while (points[0].x < maxX) {
  1155. points[1].x = points[0].x + segmentWidth;
  1156. if (points[1].x > maxX) {
  1157.     points[1].x = maxX;
  1158. }
  1159. Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
  1160. TK_RELIEF_RAISED);
  1161. points[0].x += 2 * segmentWidth;
  1162.     }
  1163. }
  1164. /*
  1165.  *--------------------------------------------------------------
  1166.  *
  1167.  * TkpInitializeMenuBindings --
  1168.  *
  1169.  * For every interp, initializes the bindings for Windows
  1170.  * menus. Does nothing on Mac or XWindows.
  1171.  *
  1172.  * Results:
  1173.  * None.
  1174.  *
  1175.  * Side effects:
  1176.  * C-level bindings are setup for the interp which will
  1177.  * handle Alt-key sequences for menus without beeping
  1178.  * or interfering with user-defined Alt-key bindings.
  1179.  *
  1180.  *--------------------------------------------------------------
  1181.  */
  1182. void
  1183. TkpInitializeMenuBindings(interp, bindingTable)
  1184.     Tcl_Interp *interp;     /* The interpreter to set. */
  1185.     Tk_BindingTable bindingTable;   /* The table to add to. */
  1186. {
  1187.     /*
  1188.      * Nothing to do.
  1189.      */
  1190. }
  1191. /*
  1192.  *----------------------------------------------------------------------
  1193.  *
  1194.  * SetHelpMenu --
  1195.  *
  1196.  * Given a menu, check to see whether or not it is a help menu
  1197.  * cascade in a menubar. If it is, the entry that points to
  1198.  * this menu will be marked.
  1199.  *
  1200.  * RESULTS:
  1201.  * None.
  1202.  *
  1203.  * Side effects:
  1204.  * Will set the ENTRY_HELP_MENU flag appropriately.
  1205.  *
  1206.  *----------------------------------------------------------------------
  1207.  */
  1208. static void
  1209. SetHelpMenu(menuPtr)
  1210.      TkMenu *menuPtr; /* The menu we are checking */
  1211. {
  1212.     TkMenuEntry *cascadeEntryPtr;
  1213.     for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  1214.     cascadeEntryPtr != NULL;
  1215.     cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
  1216. if ((cascadeEntryPtr->menuPtr->menuType == MENUBAR)
  1217. && (cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin != NULL)
  1218. && (menuPtr->masterMenuPtr->tkwin != NULL)) {
  1219.     TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr;
  1220.     char *helpMenuName = ckalloc(strlen(Tk_PathName(
  1221.     masterMenuPtr->tkwin)) + strlen(".help") + 1);
  1222.     strcpy(helpMenuName, Tk_PathName(masterMenuPtr->tkwin));
  1223.     strcat(helpMenuName, ".help");
  1224.     if (strcmp(helpMenuName,
  1225.     Tk_PathName(menuPtr->masterMenuPtr->tkwin)) == 0) {
  1226. cascadeEntryPtr->entryFlags |= ENTRY_HELP_MENU;
  1227.     } else {
  1228. cascadeEntryPtr->entryFlags &= ~ENTRY_HELP_MENU;
  1229.     }
  1230.     ckfree(helpMenuName);
  1231. }
  1232.     }
  1233. }
  1234. /*
  1235.  *----------------------------------------------------------------------
  1236.  *
  1237.  * TkpDrawMenuEntry --
  1238.  *
  1239.  * Draws the given menu entry at the given coordinates with the
  1240.  * given attributes.
  1241.  *
  1242.  * Results:
  1243.  * None.
  1244.  *
  1245.  * Side effects:
  1246.  * X Server commands are executed to display the menu entry.
  1247.  *
  1248.  *----------------------------------------------------------------------
  1249.  */
  1250. void
  1251. TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, 
  1252. strictMotif, drawArrow)
  1253.     TkMenuEntry *mePtr;     /* The entry to draw */
  1254.     Drawable d;     /* What to draw into */
  1255.     Tk_Font tkfont;     /* Precalculated font for menu */
  1256.     CONST Tk_FontMetrics *menuMetricsPtr;
  1257.     /* Precalculated metrics for menu */
  1258.     int x;     /* X-coordinate of topleft of entry */
  1259.     int y;     /* Y-coordinate of topleft of entry */
  1260.     int width;     /* Width of the entry rectangle */
  1261.     int height;     /* Height of the current rectangle */
  1262.     int strictMotif;     /* Boolean flag */
  1263.     int drawArrow;     /* Whether or not to draw the cascade
  1264.      * arrow for cascade items. Only applies
  1265.      * to Windows. */
  1266. {
  1267.     GC gc, indicatorGC;
  1268.     TkMenu *menuPtr = mePtr->menuPtr;
  1269.     Tk_3DBorder bgBorder, activeBorder;
  1270.     CONST Tk_FontMetrics *fmPtr;
  1271.     Tk_FontMetrics entryMetrics;
  1272.     int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
  1273.     int adjustedY = y + padY;
  1274.     int adjustedHeight = height - 2 * padY;
  1275.     /*
  1276.      * Choose the gc for drawing the foreground part of the entry.
  1277.      */
  1278.     if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) {
  1279. gc = mePtr->activeGC;
  1280. if (gc == NULL) {
  1281.     gc = menuPtr->activeGC;
  1282. }
  1283.     } else {
  1284.      TkMenuEntry *cascadeEntryPtr;
  1285.      int parentDisabled = 0;
  1286.     
  1287.      for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
  1288.      cascadeEntryPtr != NULL;
  1289.      cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
  1290.     if (cascadeEntryPtr->namePtr != NULL) {
  1291. char *name = Tcl_GetStringFromObj(cascadeEntryPtr->namePtr,
  1292. NULL);
  1293. if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) {
  1294.     if (cascadeEntryPtr->state == ENTRY_DISABLED) {
  1295. parentDisabled = 1;
  1296.     }
  1297.     break;
  1298.           }
  1299.          }
  1300.      }
  1301. if (((parentDisabled || (mePtr->state == ENTRY_DISABLED)))
  1302. && (menuPtr->disabledFgPtr != NULL)) {
  1303.     gc = mePtr->disabledGC;
  1304.     if (gc == NULL) {
  1305. gc = menuPtr->disabledGC;
  1306.     }
  1307. } else {
  1308.     gc = mePtr->textGC;
  1309.     if (gc == NULL) {
  1310. gc = menuPtr->textGC;
  1311.     }
  1312. }
  1313.     }
  1314.     indicatorGC = mePtr->indicatorGC;
  1315.     if (indicatorGC == NULL) {
  1316. indicatorGC = menuPtr->indicatorGC;
  1317.     }
  1318.     bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
  1319.     (mePtr->borderPtr == NULL)
  1320.     ? menuPtr->borderPtr : mePtr->borderPtr);
  1321.     if (strictMotif) {
  1322. activeBorder = bgBorder;
  1323.     } else {
  1324. activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
  1325.     (mePtr->activeBorderPtr == NULL)
  1326.     ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr);
  1327.     }
  1328.     if (mePtr->fontPtr == NULL) {
  1329. fmPtr = menuMetricsPtr;
  1330.     } else {
  1331. tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
  1332. Tk_GetFontMetrics(tkfont, &entryMetrics);
  1333. fmPtr = &entryMetrics;
  1334.     }
  1335.     /*
  1336.      * Need to draw the entire background, including padding. On Unix,
  1337.      * for menubars, we have to draw the rest of the entry taking
  1338.      * into account the padding.
  1339.      */
  1340.     
  1341.     DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, 
  1342.     bgBorder, x, y, width, height);
  1343.     
  1344.     if (mePtr->type == SEPARATOR_ENTRY) {
  1345. DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, 
  1346. fmPtr, x, adjustedY, width, adjustedHeight);
  1347.     } else if (mePtr->type == TEAROFF_ENTRY) {
  1348. DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  1349. width, adjustedHeight);
  1350.     } else {
  1351. DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
  1352. width, adjustedHeight);
  1353. DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
  1354. activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
  1355. if (!mePtr->hideMargin) {
  1356.     DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
  1357.     fmPtr, x, adjustedY, width, adjustedHeight);
  1358. }
  1359.     }
  1360. }
  1361. /*
  1362.  *----------------------------------------------------------------------
  1363.  *
  1364.  * GetMenuLabelGeometry --
  1365.  *
  1366.  * Figures out the size of the label portion of a menu item.
  1367.  *
  1368.  * Results:
  1369.  * widthPtr and heightPtr are filled in with the correct geometry
  1370.  * information.
  1371.  *
  1372.  * Side effects:
  1373.  * None.
  1374.  *
  1375.  *----------------------------------------------------------------------
  1376.  */
  1377. static void
  1378. GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr)
  1379.     TkMenuEntry *mePtr; /* The entry we are computing */
  1380.     Tk_Font tkfont; /* The precalculated font */
  1381.     CONST Tk_FontMetrics *fmPtr; /* The precalculated metrics */
  1382.     int *widthPtr; /* The resulting width of the label
  1383.  * portion */
  1384.     int *heightPtr; /* The resulting height of the label
  1385.  * portion */
  1386. {
  1387.     TkMenu *menuPtr = mePtr->menuPtr;
  1388.     int haveImage = 0;
  1389.  
  1390.     if (mePtr->image != NULL) {
  1391.      Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
  1392. haveImage = 1;
  1393.     } else if (mePtr->bitmapPtr !=  NULL) {
  1394. Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
  1395.      Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr);
  1396. haveImage = 1;
  1397.     } else {
  1398. *heightPtr = 0;
  1399. *widthPtr = 0;
  1400.     }
  1401.     
  1402.     if (haveImage && (mePtr->compound == COMPOUND_NONE)) {
  1403. /* We don't care about the text in this case */
  1404.     } else {
  1405. /* Either it is compound or we don't have an image */
  1406.      if (mePtr->labelPtr != NULL) {
  1407.     int textWidth;
  1408.     char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
  1409.     textWidth = Tk_TextWidth(tkfont, label, mePtr->labelLength);
  1410.     
  1411.     if ((mePtr->compound != COMPOUND_NONE) && haveImage) {
  1412. switch ((enum compound) mePtr->compound) {
  1413.     case COMPOUND_TOP:
  1414.     case COMPOUND_BOTTOM: {
  1415. if (textWidth > *widthPtr) {
  1416.     *widthPtr = textWidth;
  1417. }
  1418. /* Add text and padding */
  1419. *heightPtr += fmPtr->linespace + 2;
  1420. break;
  1421.     }
  1422.     case COMPOUND_LEFT:
  1423.     case COMPOUND_RIGHT: {
  1424. if (fmPtr->linespace > *heightPtr) {
  1425.     *heightPtr = fmPtr->linespace;
  1426. }
  1427. /* Add text and padding */
  1428. *widthPtr += textWidth + 2;
  1429. break;
  1430.     }
  1431.     case COMPOUND_CENTER: {
  1432. if (fmPtr->linespace > *heightPtr) {
  1433.     *heightPtr = fmPtr->linespace;
  1434. }
  1435. if (textWidth > *widthPtr) {
  1436.     *widthPtr = textWidth;
  1437. }
  1438. break;
  1439.     }
  1440.     case COMPOUND_NONE: {break;}
  1441. }
  1442.      } else {
  1443. /* We don't have an image or we're not compound */
  1444. *heightPtr = fmPtr->linespace;
  1445. *widthPtr = textWidth;
  1446.     }
  1447. } else {
  1448.     /* An empty entry still has this height */
  1449.     *heightPtr = fmPtr->linespace;
  1450.      }
  1451.     }
  1452.     *heightPtr += 1;
  1453. }
  1454. /*
  1455.  *--------------------------------------------------------------
  1456.  *
  1457.  * TkpComputeStandardMenuGeometry --
  1458.  *
  1459.  * This procedure is invoked to recompute the size and
  1460.  * layout of a menu that is not a menubar clone.
  1461.  *
  1462.  * Results:
  1463.  * None.
  1464.  *
  1465.  * Side effects:
  1466.  * Fields of menu entries are changed to reflect their
  1467.  * current positions, and the size of the menu window
  1468.  * itself may be changed.
  1469.  *
  1470.  *--------------------------------------------------------------
  1471.  */
  1472. void
  1473. TkpComputeStandardMenuGeometry(
  1474.     menuPtr) /* Structure describing menu. */
  1475.     TkMenu *menuPtr;
  1476. {
  1477.     Tk_Font tkfont, menuFont;
  1478.     Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
  1479.     int x, y, height, width, indicatorSpace, labelWidth, accelWidth;
  1480.     int windowWidth, windowHeight, accelSpace;
  1481.     int i, j, lastColumnBreak = 0;
  1482.     TkMenuEntry *mePtr;
  1483.     int borderWidth, activeBorderWidth;
  1484.     
  1485.     if (menuPtr->tkwin == NULL) {
  1486. return;
  1487.     }
  1488.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
  1489.     &borderWidth);
  1490.     Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
  1491.     &activeBorderWidth);
  1492.     x = y = borderWidth;
  1493.     indicatorSpace = labelWidth = accelWidth = 0;
  1494.     windowHeight = windowWidth = 0;
  1495.     /*
  1496.      * On the Mac especially, getting font metrics can be quite slow,
  1497.      * so we want to do it intelligently. We are going to precalculate
  1498.      * them and pass them down to all of the measuring and drawing
  1499.      * routines. We will measure the font metrics of the menu once.
  1500.      * If an entry does not have its own font set, then we give
  1501.      * the geometry/drawing routines the menu's font and metrics.
  1502.      * If an entry has its own font, we will measure that font and
  1503.      * give all of the geometry/drawing the entry's font and metrics.
  1504.      */
  1505.     menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
  1506.     Tk_GetFontMetrics(menuFont, &menuMetrics);
  1507.     accelSpace = Tk_TextWidth(menuFont, "M", 1);
  1508.     for (i = 0; i < menuPtr->numEntries; i++) {
  1509. mePtr = menuPtr->entries[i];
  1510. if (mePtr->fontPtr == NULL) {
  1511.     tkfont = menuFont;
  1512.     fmPtr = &menuMetrics;
  1513. } else {
  1514.     tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
  1515.     Tk_GetFontMetrics(tkfont, &entryMetrics);
  1516.     fmPtr = &entryMetrics;
  1517. }
  1518. if ((i > 0) && mePtr->columnBreak) {
  1519.     if (accelWidth != 0) {
  1520. labelWidth += accelSpace;
  1521.     }
  1522.     for (j = lastColumnBreak; j < i; j++) {
  1523. menuPtr->entries[j]->indicatorSpace = indicatorSpace;
  1524. menuPtr->entries[j]->labelWidth = labelWidth;
  1525. menuPtr->entries[j]->width = indicatorSpace + labelWidth
  1526. + accelWidth + 2 * activeBorderWidth;
  1527. menuPtr->entries[j]->x = x;
  1528. menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN;
  1529.     }
  1530.     x += indicatorSpace + labelWidth + accelWidth
  1531.     + 2 * activeBorderWidth;
  1532.     windowWidth = x;
  1533.     indicatorSpace = labelWidth = accelWidth = 0;
  1534.     lastColumnBreak = i;
  1535.     y = borderWidth;
  1536. }
  1537. if (mePtr->type == SEPARATOR_ENTRY) {
  1538.     GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
  1539.          fmPtr, &width, &height);
  1540.     mePtr->height = height;
  1541. } else if (mePtr->type == TEAROFF_ENTRY) {
  1542.     GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, 
  1543.          fmPtr, &width, &height);
  1544.     mePtr->height = height;
  1545.     labelWidth = width;
  1546. } else {
  1547.     
  1548.     /*
  1549.      * For each entry, compute the height required by that
  1550.      * particular entry, plus three widths:  the width of the
  1551.      * label, the width to allow for an indicator to be displayed
  1552.      * to the left of the label (if any), and the width of the
  1553.      * accelerator to be displayed to the right of the label
  1554.      * (if any).  These sizes depend, of course, on the type
  1555.      * of the entry.
  1556.      */
  1557.     
  1558.     GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width,
  1559.          &height);
  1560.     mePtr->height = height;
  1561.     if (!mePtr->hideMargin) {
  1562. width += MENU_MARGIN_WIDTH;
  1563.     }
  1564.     if (width > labelWidth) {
  1565.      labelWidth = width;
  1566.     }
  1567.     GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
  1568.     fmPtr, &width, &height);
  1569.     if (height > mePtr->height) {
  1570.      mePtr->height = height;
  1571.     }
  1572.     if (!mePtr->hideMargin) {
  1573. width += MENU_MARGIN_WIDTH;
  1574.     }
  1575.     if (width > accelWidth) {
  1576.      accelWidth = width;
  1577.     }
  1578.     GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, 
  1579.          fmPtr, &width, &height);
  1580.     if (height > mePtr->height) {
  1581.      mePtr->height = height;
  1582.     }
  1583.     if (!mePtr->hideMargin) {
  1584. width += MENU_MARGIN_WIDTH;
  1585.     }
  1586.     if (width > indicatorSpace) {
  1587.      indicatorSpace = width;
  1588.     }
  1589.     mePtr->height += 2 * activeBorderWidth + MENU_DIVIDER_HEIGHT;
  1590.      }
  1591.         mePtr->y = y;
  1592. y += mePtr->height;
  1593. if (y > windowHeight) {
  1594.     windowHeight = y;
  1595. }
  1596.     }
  1597.     if (accelWidth != 0) {
  1598. labelWidth += accelSpace;
  1599.     }
  1600.     for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
  1601. menuPtr->entries[j]->indicatorSpace = indicatorSpace;
  1602. menuPtr->entries[j]->labelWidth = labelWidth;
  1603. menuPtr->entries[j]->width = indicatorSpace + labelWidth
  1604. + accelWidth + 2 * activeBorderWidth;
  1605. menuPtr->entries[j]->x = x;
  1606. menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN;
  1607.     }
  1608.     windowWidth = x + indicatorSpace + labelWidth + accelWidth
  1609.     + 2 * activeBorderWidth + 2 * borderWidth;
  1610.     windowHeight += borderWidth;
  1611.     
  1612.     /*
  1613.      * The X server doesn't like zero dimensions, so round up to at least
  1614.      * 1 (a zero-sized menu should never really occur, anyway).
  1615.      */
  1616.     if (windowWidth <= 0) {
  1617. windowWidth = 1;
  1618.     }
  1619.     if (windowHeight <= 0) {
  1620. windowHeight = 1;
  1621.     }
  1622.     menuPtr->totalWidth = windowWidth;
  1623.     menuPtr->totalHeight = windowHeight;
  1624. }
  1625. /*
  1626.  *----------------------------------------------------------------------
  1627.  *
  1628.  * TkpMenuNotifyToplevelCreate --
  1629.  *
  1630.  * This routine reconfigures the menu and the clones indicated by
  1631.  * menuName becuase a toplevel has been created and any system
  1632.  * menus need to be created. Not applicable to UNIX.
  1633.  *
  1634.  * Results:
  1635.  * None.
  1636.  *
  1637.  * Side effects:
  1638.  * An idle handler is set up to do the reconfiguration.
  1639.  *
  1640.  *----------------------------------------------------------------------
  1641.  */
  1642. void
  1643. TkpMenuNotifyToplevelCreate(interp, menuName)
  1644.     Tcl_Interp *interp; /* The interp the menu lives in. */
  1645.     char *menuName; /* The name of the menu to 
  1646.  * reconfigure. */
  1647. {
  1648.     /*
  1649.      * Nothing to do.
  1650.      */
  1651. }
  1652. /*
  1653.  *----------------------------------------------------------------------
  1654.  *
  1655.  * TkpMenuInit --
  1656.  *
  1657.  * Does platform-specific initialization of menus.
  1658.  *
  1659.  * Results:
  1660.  * None.
  1661.  *
  1662.  * Side effects:
  1663.  * None.
  1664.  *
  1665.  *----------------------------------------------------------------------
  1666.  */
  1667. void
  1668. TkpMenuInit()
  1669. {
  1670.     /*
  1671.      * Nothing to do.
  1672.      */
  1673. }
  1674. /*
  1675.  *----------------------------------------------------------------------
  1676.  *
  1677.  * TkpMenuThreadInit --
  1678.  *
  1679.  * Does platform-specific initialization of thread-specific
  1680.  *      menu state.
  1681.  *
  1682.  * Results:
  1683.  * None.
  1684.  *
  1685.  * Side effects:
  1686.  * None.
  1687.  *
  1688.  *----------------------------------------------------------------------
  1689.  */
  1690. void
  1691. TkpMenuThreadInit()
  1692. {
  1693.     /*
  1694.      * Nothing to do.
  1695.      */
  1696. }