OSDN Git Service

Enable to track git://github.com/monaka/binutils.git
[pf3gnuchains/pf3gnuchains3x.git] / tk / unix / tkUnixMenu.c
diff --git a/tk/unix/tkUnixMenu.c b/tk/unix/tkUnixMenu.c
new file mode 100644 (file)
index 0000000..dcfb533
--- /dev/null
@@ -0,0 +1,1807 @@
+/* 
+ * tkUnixMenu.c --
+ *
+ *     This module implements the UNIX platform-specific features of menus.
+ *
+ * Copyright (c) 1996-1998 by Sun Microsystems, Inc.
+ *
+ * See the file "license.terms" for information on usage and redistribution
+ * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
+ *
+ * RCS: @(#) $Id$
+ */
+
+#include "tkPort.h"
+#include "default.h"
+#include "tkInt.h"
+#include "tkUnixInt.h"
+#include "tkMenu.h"
+
+/*
+ * Constants used for menu drawing.
+ */
+
+#define MENU_MARGIN_WIDTH      2
+#define MENU_DIVIDER_HEIGHT    2
+
+/*
+ * Platform specific flags for Unix.
+ */
+
+#define ENTRY_HELP_MENU                ENTRY_PLATFORM_FLAG1
+
+/*
+ * Procedures used internally.
+ */
+
+static void            SetHelpMenu _ANSI_ARGS_((TkMenu *menuPtr));
+static void            DrawMenuEntryAccelerator _ANSI_ARGS_((
+                           TkMenu *menuPtr, TkMenuEntry *mePtr, 
+                           Drawable d, GC gc, Tk_Font tkfont,
+                           CONST Tk_FontMetrics *fmPtr,
+                           Tk_3DBorder activeBorder, int x, int y,
+                           int width, int height, int drawArrow));
+static void            DrawMenuEntryBackground _ANSI_ARGS_((
+                           TkMenu *menuPtr, TkMenuEntry *mePtr,
+                           Drawable d, Tk_3DBorder activeBorder,
+                           Tk_3DBorder bgBorder, int x, int y,
+                           int width, int heigth));
+static void            DrawMenuEntryIndicator _ANSI_ARGS_((
+                           TkMenu *menuPtr, TkMenuEntry *mePtr,
+                           Drawable d, GC gc, GC indicatorGC, 
+                           Tk_Font tkfont,
+                           CONST Tk_FontMetrics *fmPtr, int x, int y,
+                           int width, int height));
+static void            DrawMenuEntryLabel _ANSI_ARGS_((
+                           TkMenu * menuPtr, TkMenuEntry *mePtr, Drawable d,
+                           GC gc, Tk_Font tkfont,
+                           CONST Tk_FontMetrics *fmPtr, int x, int y,
+                           int width, int height));
+static void            DrawMenuSeparator _ANSI_ARGS_((TkMenu *menuPtr,
+                           TkMenuEntry *mePtr, Drawable d, GC gc, 
+                           Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
+                           int x, int y, int width, int height));
+static void            DrawTearoffEntry _ANSI_ARGS_((TkMenu *menuPtr,
+                           TkMenuEntry *mePtr, Drawable d, GC gc, 
+                           Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
+                           int x, int y, int width, int height));
+static void            DrawMenuUnderline _ANSI_ARGS_((TkMenu *menuPtr,
+                           TkMenuEntry *mePtr, Drawable d, GC gc,
+                           Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, int x,
+                           int y, int width, int height));
+static void            GetMenuAccelGeometry _ANSI_ARGS_((TkMenu *menuPtr,
+                           TkMenuEntry *mePtr, Tk_Font tkfont,
+                           CONST Tk_FontMetrics *fmPtr, int *widthPtr,
+                           int *heightPtr));
+static void            GetMenuLabelGeometry _ANSI_ARGS_((TkMenuEntry *mePtr,
+                           Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
+                           int *widthPtr, int *heightPtr));
+static void            GetMenuIndicatorGeometry _ANSI_ARGS_((
+                           TkMenu *menuPtr, TkMenuEntry *mePtr, 
+                           Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr, 
+                           int *widthPtr, int *heightPtr));
+static void            GetMenuSeparatorGeometry _ANSI_ARGS_((
+                           TkMenu *menuPtr, TkMenuEntry *mePtr,
+                           Tk_Font tkfont, CONST Tk_FontMetrics *fmPtr,
+                           int *widthPtr, int *heightPtr));
+static void            GetTearoffEntryGeometry _ANSI_ARGS_((TkMenu *menuPtr,
+                           TkMenuEntry *mePtr, Tk_Font tkfont,
+                           CONST Tk_FontMetrics *fmPtr, int *widthPtr,
+                           int *heightPtr));
+
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpNewMenu --
+ *
+ *     Gets the platform-specific piece of the menu. Invoked during idle
+ *     after the generic part of the menu has been created.
+ *
+ * Results:
+ *     Standard TCL error.
+ *
+ * Side effects:
+ *     Allocates any platform specific allocations and places them
+ *     in the platformData field of the menuPtr.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpNewMenu(menuPtr)
+    TkMenu *menuPtr;
+{
+    SetHelpMenu(menuPtr);
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDestroyMenu --
+ *
+ *     Destroys platform-specific menu structures. Called when the
+ *     generic menu structure is destroyed for the menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     All platform-specific allocations are freed up.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyMenu(menuPtr)
+    TkMenu *menuPtr;
+{
+    /*
+     * Nothing to do.
+     */
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDestroyMenuEntry --
+ *
+ *     Cleans up platform-specific menu entry items. Called when entry
+ *     is destroyed in the generic code.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     All platform specific allocations are freed up.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDestroyMenuEntry(mEntryPtr)
+    TkMenuEntry *mEntryPtr;
+{
+    /*
+     * Nothing to do.
+     */
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpConfigureMenuEntry --
+ *
+ *     Processes configuration options for menu entries. Called when
+ *     the generic options are processed for the menu.
+ *
+ * Results:
+ *     Returns standard TCL result. If TCL_ERROR is returned, then
+ *     the interp's result contains an error message.
+ *
+ * Side effects:
+ *     Configuration information get set for mePtr; old resources
+ *     get freed, if any need it.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpConfigureMenuEntry(mePtr)
+    register TkMenuEntry *mePtr;       /* Information about menu entry;  may
+                                        * or may not already have values for
+                                        * some fields. */
+{
+    /*
+     * If this is a cascade menu, and the child menu exists, check to
+     * see if the child menu is a help menu.
+     */
+
+    if ((mePtr->type == CASCADE_ENTRY) && (mePtr->namePtr != NULL)) {
+       TkMenuReferences *menuRefPtr;
+
+       menuRefPtr = TkFindMenuReferencesObj(mePtr->menuPtr->interp,
+               mePtr->namePtr);
+       if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) {
+           SetHelpMenu(menuRefPtr->menuPtr);
+       }
+    }
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpMenuNewEntry --
+ *
+ *     Called when a new entry is created in a menu. Fills in platform
+ *     specific data for the entry. The platformEntryData field
+ *     is used to store the indicator diameter for radio button
+ *     and check box entries.
+ *
+ * Results:
+ *     Standard TCL error.
+ *
+ * Side effects:
+ *     None on Unix.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpMenuNewEntry(mePtr)
+    TkMenuEntry *mePtr;
+{
+    return TCL_OK;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpSetWindowMenuBar --
+ *
+ *     Sets up the menu as a menubar in the given window.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Recomputes geometry of given window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpSetWindowMenuBar(tkwin, menuPtr)
+    Tk_Window tkwin;                   /* The window we are setting */
+    TkMenu *menuPtr;                   /* The menu we are setting */
+{
+    if (menuPtr == NULL) {
+       TkUnixSetMenubar(tkwin, NULL);
+    } else {
+       TkUnixSetMenubar(tkwin, menuPtr->tkwin);
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpSetMainMenuBar --
+ *
+ *     Called when a toplevel widget is brought to front. On the
+ *     Macintosh, sets up the menubar that goes accross the top
+ *     of the main monitor. On other platforms, nothing is necessary.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Recompute geometry of given window.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpSetMainMenubar(interp, tkwin, menuName)
+    Tcl_Interp *interp;
+    Tk_Window tkwin;
+    char *menuName;
+{
+    /*
+     * Nothing to do.
+     */
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetMenuIndicatorGeometry --
+ *
+ *     Fills out the geometry of the indicator in a menu item. Note
+ *     that the mePtr->height field must have already been filled in
+ *     by GetMenuLabelGeometry since this height depends on the label
+ *     height.
+ *
+ * Results:
+ *     widthPtr and heightPtr point to the new geometry values.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
+    TkMenu *menuPtr;                   /* The menu we are drawing. */
+    TkMenuEntry *mePtr;                        /* The entry we are interested in. */
+    Tk_Font tkfont;                    /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;       /* The precalculated metrics */
+    int *widthPtr;                     /* The resulting width */
+    int *heightPtr;                    /* The resulting height */
+{
+    if ((mePtr->type == CHECK_BUTTON_ENTRY)
+           || (mePtr->type == RADIO_BUTTON_ENTRY)) {
+       if (!mePtr->hideMargin && mePtr->indicatorOn) {
+           if ((mePtr->image != NULL) || (mePtr->bitmapPtr != NULL)) {
+               *widthPtr = (14 * mePtr->height) / 10;
+               *heightPtr = mePtr->height;
+               if (mePtr->type == CHECK_BUTTON_ENTRY) {
+                   mePtr->platformEntryData = 
+                           (TkMenuPlatformEntryData) ((65 * mePtr->height)
+                           / 100);
+               } else {
+                   mePtr->platformEntryData = 
+                           (TkMenuPlatformEntryData) ((75 * mePtr->height)
+                           / 100);
+               }                   
+           } else {
+               *widthPtr = *heightPtr = mePtr->height;
+               if (mePtr->type == CHECK_BUTTON_ENTRY) {
+                   mePtr->platformEntryData = (TkMenuPlatformEntryData)
+                       ((80 * mePtr->height) / 100);
+               } else {
+                   mePtr->platformEntryData = (TkMenuPlatformEntryData)
+                       mePtr->height;
+               }
+           }
+       } else {
+           int borderWidth;
+
+           Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
+                   menuPtr->borderWidthPtr, &borderWidth);
+           *heightPtr = 0;
+           *widthPtr = borderWidth;
+       }
+    } else {
+       int borderWidth;
+
+       Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
+               &borderWidth);
+        *heightPtr = 0;
+        *widthPtr = borderWidth;
+    }
+}
+
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetMenuAccelGeometry --
+ *
+ *     Get the geometry of the accelerator area of a menu item.
+ *
+ * Results:
+ *     heightPtr and widthPtr are set.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetMenuAccelGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
+    TkMenu *menuPtr;           /* The menu was are drawing */
+    TkMenuEntry *mePtr;                /* The entry we are getting the geometry for */
+    Tk_Font tkfont;            /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics */
+    int *widthPtr;             /* The width of the acclerator area */
+    int *heightPtr;            /* The height of the accelerator area */
+{
+    *heightPtr = fmPtr->linespace;
+    if (mePtr->type == CASCADE_ENTRY) {
+       *widthPtr = 2 * CASCADE_ARROW_WIDTH;
+    } else if ((menuPtr->menuType != MENUBAR)
+           && (mePtr->accelPtr != NULL)) {
+       char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL);
+       
+       *widthPtr = Tk_TextWidth(tkfont, accel, mePtr->accelLength);
+    } else {
+       *widthPtr = 0;
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuEntryBackground --
+ *
+ *     This procedure draws the background part of a menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, bgBorder, x, y,
+       width, height)
+    TkMenu *menuPtr;           /* The menu we are drawing */
+    TkMenuEntry *mePtr;                /* The entry we are drawing. */
+    Drawable d;                        /* The drawable we are drawing into */
+    Tk_3DBorder activeBorder;  /* The border for an active item */
+    Tk_3DBorder bgBorder;      /* The background border */
+    int x;                     /* Left coordinate of entry rect */
+    int y;                     /* Right coordinate of entry rect */
+    int width;                 /* Width of entry rect */
+    int height;                        /* Height of entry rect */
+{
+    if (mePtr->state == ENTRY_ACTIVE) {
+       int relief;
+       int activeBorderWidth;
+
+       bgBorder = activeBorder;
+
+       if ((menuPtr->menuType == MENUBAR)
+               && ((menuPtr->postedCascade == NULL)
+               || (menuPtr->postedCascade != mePtr))) {
+           relief = TK_RELIEF_FLAT;
+       } else {
+           relief = TK_RELIEF_RAISED;
+       }
+
+       Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
+               menuPtr->activeBorderWidthPtr, &activeBorderWidth);
+       Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
+               activeBorderWidth, relief);
+    } else {
+       Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
+               0, TK_RELIEF_FLAT);
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuEntryAccelerator --
+ *
+ *     This procedure draws the background part of a menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr, activeBorder,
+       x, y, width, height, drawArrow)
+    TkMenu *menuPtr;                   /* The menu we are drawing */
+    TkMenuEntry *mePtr;                        /* The entry we are drawing */
+    Drawable d;                                /* The drawable we are drawing into */
+    GC gc;                             /* The precalculated gc to draw with */
+    Tk_Font tkfont;                    /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;       /* The precalculated metrics */
+    Tk_3DBorder activeBorder;          /* The border for an active item */
+    int x;                             /* Left coordinate of entry rect */
+    int y;                             /* Top coordinate of entry rect */
+    int width;                         /* Width of entry */
+    int height;                                /* Height of entry */
+    int drawArrow;                     /* Whether or not to draw arrow. */
+{
+    XPoint points[3];
+    int borderWidth, activeBorderWidth;
+    
+    /*
+     * Draw accelerator or cascade arrow.
+     */
+
+    if (menuPtr->menuType == MENUBAR) {
+       return;
+    }
+
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
+           &borderWidth);
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
+           &activeBorderWidth);
+    if ((mePtr->type == CASCADE_ENTRY) && drawArrow) {
+       points[0].x = x + width - borderWidth - activeBorderWidth
+               - CASCADE_ARROW_WIDTH;
+       points[0].y = y + (height - CASCADE_ARROW_HEIGHT)/2;
+       points[1].x = points[0].x;
+       points[1].y = points[0].y + CASCADE_ARROW_HEIGHT;
+       points[2].x = points[0].x + CASCADE_ARROW_WIDTH;
+       points[2].y = points[0].y + CASCADE_ARROW_HEIGHT/2;
+       Tk_Fill3DPolygon(menuPtr->tkwin, d, activeBorder, points, 3,
+               DECORATION_BORDER_WIDTH,
+               (menuPtr->postedCascade == mePtr)
+               ? TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
+    } else if (mePtr->accelPtr != NULL) {
+       char *accel = Tcl_GetStringFromObj(mePtr->accelPtr, NULL);
+       int left = x + mePtr->labelWidth + activeBorderWidth
+               + mePtr->indicatorSpace;
+       
+       if (menuPtr->menuType == MENUBAR) {
+           left += 5;
+       }
+       Tk_DrawChars(menuPtr->display, d, gc, tkfont, accel,
+               mePtr->accelLength, left,
+               (y + (height + fmPtr->ascent - fmPtr->descent) / 2));
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuEntryIndicator --
+ *
+ *     This procedure draws the background part of a menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont, fmPtr,
+       x, y, width, height)
+    TkMenu *menuPtr;                   /* The menu we are drawing */
+    TkMenuEntry *mePtr;                        /* The entry we are drawing */
+    Drawable d;                                /* The drawable to draw into */
+    GC gc;                             /* The gc to draw with */
+    GC indicatorGC;                    /* The gc that indicators draw with */
+    Tk_Font tkfont;                    /* The font to draw with */
+    CONST Tk_FontMetrics *fmPtr;       /* The font metrics of the font */
+    int x;                             /* The left of the entry rect */
+    int y;                             /* The top of the entry rect */
+    int width;                         /* Width of menu entry */
+    int height;                                /* Height of menu entry */
+{
+    /*
+     * Draw check-button indicator.
+     */
+
+    if ((mePtr->type == CHECK_BUTTON_ENTRY) && mePtr->indicatorOn) {
+       int dim, top, left;
+       int activeBorderWidth;
+       Tk_3DBorder border;
+       
+       dim = (int) mePtr->platformEntryData;
+       Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
+               menuPtr->activeBorderWidthPtr, &activeBorderWidth);
+       left = x + activeBorderWidth + (mePtr->indicatorSpace - dim)/2;
+       if (menuPtr->menuType == MENUBAR) {
+           left += 5;
+       }
+       top = y + (height - dim)/2;
+       border = Tk_Get3DBorderFromObj(menuPtr->tkwin,
+               menuPtr->borderPtr);
+       Tk_Fill3DRectangle(menuPtr->tkwin, d, border, left, top, dim,
+               dim, DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
+       left += DECORATION_BORDER_WIDTH;
+       top += DECORATION_BORDER_WIDTH;
+       dim -= 2*DECORATION_BORDER_WIDTH;
+       if ((dim > 0) && (mePtr->entryFlags
+               & ENTRY_SELECTED)) {
+           XFillRectangle(menuPtr->display, d, indicatorGC, left, top,
+                   (unsigned int) dim, (unsigned int) dim);
+       }
+    }
+
+    /*
+     * Draw radio-button indicator.
+     */
+
+    if ((mePtr->type == RADIO_BUTTON_ENTRY) && mePtr->indicatorOn) {
+       XPoint points[4];
+       int radius;
+       Tk_3DBorder border;
+
+       border = Tk_Get3DBorderFromObj(menuPtr->tkwin, 
+               menuPtr->borderPtr);
+       radius = ((int) mePtr->platformEntryData)/2;
+       points[0].x = x + (mePtr->indicatorSpace
+               - (int) mePtr->platformEntryData)/2;
+       points[0].y = y + (height)/2;
+       points[1].x = points[0].x + radius;
+       points[1].y = points[0].y + radius;
+       points[2].x = points[1].x + radius;
+       points[2].y = points[0].y;
+       points[3].x = points[1].x;
+       points[3].y = points[0].y - radius;
+       if (mePtr->entryFlags & ENTRY_SELECTED) {
+           XFillPolygon(menuPtr->display, d, indicatorGC, points, 4,
+                   Convex, CoordModeOrigin);
+       } else {
+           Tk_Fill3DPolygon(menuPtr->tkwin, d, border, points, 4,
+                   DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
+       }
+       Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 4,
+               DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuSeparator --
+ *
+ *     This procedure draws a separator menu item.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
+    TkMenu *menuPtr;                   /* The menu we are drawing */
+    TkMenuEntry *mePtr;                        /* The entry we are drawing */
+    Drawable d;                                /* The drawable we are using */
+    GC gc;                             /* The gc to draw into */
+    Tk_Font tkfont;                    /* The font to draw with */
+    CONST Tk_FontMetrics *fmPtr;       /* The font metrics from the font */
+    int x;
+    int y;
+    int width;
+    int height;
+{
+    XPoint points[2];
+    Tk_3DBorder border;
+
+    if (menuPtr->menuType == MENUBAR) {
+       return;
+    }
+    
+    points[0].x = x;
+    points[0].y = y + height/2;
+    points[1].x = width - 1;
+    points[1].y = points[0].y;
+    border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
+    Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
+           TK_RELIEF_RAISED);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuEntryLabel --
+ *
+ *     This procedure draws the label part of a menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
+    TkMenu *menuPtr;           /* The menu we are drawing. */
+    TkMenuEntry *mePtr;                /* The entry we are drawing. */
+    Drawable d;                        /* What we are drawing into. */
+    GC gc;                     /* The gc we are drawing into.*/
+    Tk_Font tkfont;            /* The precalculated font. */
+    CONST Tk_FontMetrics *fmPtr;/* The precalculated font metrics. */
+    int x;                     /* Left edge. */
+    int y;                     /* Top edge. */
+    int width;                 /* width of entry. */
+    int height;                        /* height of entry. */
+{
+    int indicatorSpace =  mePtr->indicatorSpace;
+    int activeBorderWidth;
+    int leftEdge;
+    int imageHeight, imageWidth;
+    int textHeight = 0, textWidth = 0; /* stop GCC warning */
+    int haveImage = 0, haveText = 0;
+    int imageXOffset = 0, imageYOffset = 0;
+    int textXOffset = 0, textYOffset = 0;
+
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
+           &activeBorderWidth);
+    leftEdge = x + indicatorSpace + activeBorderWidth;
+    if (menuPtr->menuType == MENUBAR) {
+       leftEdge += 5;
+    }
+    
+    /*
+     * Work out what we will need to draw first.
+     */
+
+    if (mePtr->image != NULL) {
+       Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
+       haveImage = 1;
+    } else if (mePtr->bitmapPtr != NULL) {
+       Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
+       Tk_SizeOfBitmap(menuPtr->display, bitmap, &imageWidth, &imageHeight);
+       haveImage = 1;
+    }
+    if (!haveImage || (mePtr->compound != COMPOUND_NONE)) {
+       if (mePtr->labelLength > 0) {
+           char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
+           textWidth = Tk_TextWidth(tkfont, label, mePtr->labelLength);
+           textHeight = fmPtr->linespace;
+           haveText = 1;
+       }
+    }
+    
+    /*
+     * Now work out what the relative positions are.
+     */
+
+    if (haveImage && haveText) {
+       int fullWidth = (imageWidth > textWidth ? imageWidth : textWidth);
+       switch ((enum compound) mePtr->compound) {
+           case COMPOUND_TOP: {
+               textXOffset = (fullWidth - textWidth)/2;
+               textYOffset = imageHeight/2 + 2;
+               imageXOffset = (fullWidth - imageWidth)/2;
+               imageYOffset = -textHeight/2;
+               break;
+           }
+           case COMPOUND_BOTTOM: {
+               textXOffset = (fullWidth - textWidth)/2;
+               textYOffset = -imageHeight/2;
+               imageXOffset = (fullWidth - imageWidth)/2;
+               imageYOffset = textHeight/2 + 2;
+               break;
+           }
+           case COMPOUND_LEFT: {
+               textXOffset = imageWidth + 2;
+               textYOffset = 0;
+               imageXOffset = 0;
+               imageYOffset = 0;
+               break;
+           }
+           case COMPOUND_RIGHT: {
+               textXOffset = 0;
+               textYOffset = 0;
+               imageXOffset = textWidth + 2;
+               imageYOffset = 0;
+               break;
+           }
+           case COMPOUND_CENTER: {
+               textXOffset = (fullWidth - textWidth)/2;
+               textYOffset = 0;
+               imageXOffset = (fullWidth - imageWidth)/2;
+               imageYOffset = 0;
+               break;
+           }
+           case COMPOUND_NONE: {break;}
+       }
+    } else {
+       textXOffset = 0;
+       textYOffset = 0;
+       imageXOffset = 0;
+       imageYOffset = 0;
+    }
+    
+    /*
+     * Draw label and/or bitmap or image for entry.
+     */
+
+    if (mePtr->image != NULL) {
+       if ((mePtr->selectImage != NULL)
+               && (mePtr->entryFlags & ENTRY_SELECTED)) {
+           Tk_RedrawImage(mePtr->selectImage, 0, 0,
+                   imageWidth, imageHeight, d, leftEdge + imageXOffset,
+                   (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset));
+       } else {
+           Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
+                   imageHeight, d, leftEdge + imageXOffset,
+                   (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset));
+       }
+    } else if (mePtr->bitmapPtr != None) {
+       Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
+       XCopyPlane(menuPtr->display, bitmap, d, gc, 0, 0, 
+               (unsigned) imageWidth, (unsigned) imageHeight, 
+               leftEdge + imageXOffset,
+               (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset), 1);
+    }
+    if ((mePtr->compound != COMPOUND_NONE) || !haveImage) {
+       int baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
+       if (mePtr->labelLength > 0) {
+           char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
+           Tk_DrawChars(menuPtr->display, d, gc, tkfont, label,
+                   mePtr->labelLength, leftEdge + textXOffset, 
+                   baseline + textYOffset);
+           DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, 
+                   x + textXOffset, y + textYOffset,
+                   width, height);
+       }
+    }
+
+    if (mePtr->state == ENTRY_DISABLED) {
+       if (menuPtr->disabledFgPtr == NULL) {
+           XFillRectangle(menuPtr->display, d, menuPtr->disabledGC, x, y,
+                   (unsigned) width, (unsigned) height);
+       } else if ((mePtr->image != NULL) 
+               && (menuPtr->disabledImageGC != None)) {
+           XFillRectangle(menuPtr->display, d, menuPtr->disabledImageGC,
+                   leftEdge + imageXOffset,
+                   (int) (y + (mePtr->height - imageHeight)/2 + imageYOffset),
+                   (unsigned) imageWidth, (unsigned) imageHeight);
+       }
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawMenuUnderline --
+ *
+ *     On appropriate platforms, draw the underline character for the
+ *     menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
+    TkMenu *menuPtr;                   /* The menu to draw into */
+    TkMenuEntry *mePtr;                        /* The entry we are drawing */
+    Drawable d;                                /* What we are drawing into */
+    GC gc;                             /* The gc to draw into */
+    Tk_Font tkfont;                    /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;       /* The precalculated font metrics */
+    int x;
+    int y;
+    int width;
+    int height;
+{
+    int indicatorSpace = mePtr->indicatorSpace;
+
+    if (mePtr->underline >= 0) {
+       int activeBorderWidth;
+       int leftEdge;
+       char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
+       CONST char *start = Tcl_UtfAtIndex(label, mePtr->underline);
+       CONST char *end = Tcl_UtfNext(start);
+
+       Tk_GetPixelsFromObj(NULL, menuPtr->tkwin,
+               menuPtr->activeBorderWidthPtr, &activeBorderWidth);
+       leftEdge = x + indicatorSpace + activeBorderWidth;
+       if (menuPtr->menuType == MENUBAR) {
+           leftEdge += 5;
+       }
+
+       Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, label,
+               leftEdge, y + (height + fmPtr->ascent - fmPtr->descent) / 2,
+               start - label, end - label);
+    }          
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpPostMenu --
+ *
+ *     Posts a menu on the screen
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     The menu is posted and handled.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkpPostMenu(interp, menuPtr, x, y)
+    Tcl_Interp *interp;
+    TkMenu *menuPtr;
+    int x;
+    int y;
+{
+    return TkPostTearoffMenu(interp, menuPtr, x, y);
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetMenuSeparatorGeometry --
+ *
+ *     Gets the width and height of the indicator area of a menu.
+ *
+ * Results:
+ *     widthPtr and heightPtr are set.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr,
+       heightPtr) 
+    TkMenu *menuPtr;                   /* The menu we are measuring */
+    TkMenuEntry *mePtr;                        /* The entry we are measuring */
+    Tk_Font tkfont;                    /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;       /* The precalcualted font metrics */
+    int *widthPtr;                     /* The resulting width */
+    int *heightPtr;                    /* The resulting height */
+{
+    *widthPtr = 0;
+    *heightPtr = fmPtr->linespace;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetTearoffEntryGeometry --
+ *
+ *     Gets the width and height of the indicator area of a menu.
+ *
+ * Results:
+ *     widthPtr and heightPtr are set.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, fmPtr, widthPtr, heightPtr)
+    TkMenu *menuPtr;                   /* The menu we are drawing */
+    TkMenuEntry *mePtr;                        /* The entry we are measuring */
+    Tk_Font tkfont;                    /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;       /* The precalculated font metrics */
+    int *widthPtr;                     /* The resulting width */
+    int *heightPtr;                    /* The resulting height */
+{
+    if (menuPtr->menuType != MASTER_MENU) {
+       *heightPtr = 0;
+       *widthPtr = 0;
+    } else {
+       *heightPtr = fmPtr->linespace;
+       *widthPtr = Tk_TextWidth(tkfont, "W", 1);
+    }
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkpComputeMenubarGeometry --
+ *
+ *     This procedure is invoked to recompute the size and
+ *     layout of a menu that is a menubar clone.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Fields of menu entries are changed to reflect their
+ *     current positions, and the size of the menu window
+ *     itself may be changed.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkpComputeMenubarGeometry(menuPtr)
+    TkMenu *menuPtr;           /* Structure describing menu. */
+{
+    Tk_Font tkfont;
+    Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
+    int width, height;
+    int i, j;
+    int x, y, currentRowHeight, maxWidth;
+    int maxWindowWidth;
+    int lastRowBreak;
+    int helpMenuIndex = -1;
+    TkMenuEntry *mePtr;
+    int lastEntry;
+    Tk_Font menuFont;
+    int borderWidth;
+    int activeBorderWidth;
+    
+    if (menuPtr->tkwin == NULL) {
+       return;
+    }
+
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
+           &borderWidth);
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
+           &activeBorderWidth);
+    maxWidth = 0;
+    if (menuPtr->numEntries == 0) {
+       height = 0;
+    } else {
+       int borderWidth;
+       
+       maxWindowWidth = Tk_Width(menuPtr->tkwin);
+       if (maxWindowWidth == 1) {
+           maxWindowWidth = 0x7ffffff;
+       }
+       currentRowHeight = 0;
+       Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
+               &borderWidth);
+       x = y = borderWidth;
+       lastRowBreak = 0;
+       
+       /*
+        * On the Mac especially, getting font metrics can be quite slow,
+        * so we want to do it intelligently. We are going to precalculate
+        * them and pass them down to all of the measureing and drawing
+        * routines. We will measure the font metrics of the menu once,
+        * and if an entry has a font set, we will measure it as we come
+        * to it, and then we decide which set to give the geometry routines.
+        */
+
+       menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
+       Tk_GetFontMetrics(menuFont, &menuMetrics);
+       
+       for (i = 0; i < menuPtr->numEntries; i++) {
+           mePtr = menuPtr->entries[i];
+           mePtr->entryFlags &= ~ENTRY_LAST_COLUMN;
+           if (mePtr->fontPtr != NULL) {
+               tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
+               Tk_GetFontMetrics(tkfont, &entryMetrics);
+               fmPtr = &entryMetrics;
+           } else {
+               tkfont = menuFont;
+               fmPtr = &menuMetrics;
+           }
+
+           /*
+            * For every entry, we need to check to see whether or not we
+            * wrap. If we do wrap, then we have to adjust all of the previous
+            * entries' height and y position, because when we see them
+            * the first time, we don't know how big its neighbor might
+            * be.
+            */
+           
+           if ((mePtr->type == SEPARATOR_ENTRY)
+                   || (mePtr->type == TEAROFF_ENTRY)) {
+               mePtr->height = mePtr->width = 0;
+           } else {
+               GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width, &height);
+               mePtr->height = height + 2 * activeBorderWidth + 10;
+               mePtr->width = width;
+
+               GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, fmPtr,
+                       &width, &height);
+               mePtr->indicatorSpace = width;
+               if (width > 0) {
+                   mePtr->width += width;
+               }
+               mePtr->width += 2 * activeBorderWidth + 10;
+           }
+           if (mePtr->entryFlags & ENTRY_HELP_MENU) {
+               helpMenuIndex = i;
+           } else if (x + mePtr->width + borderWidth > maxWindowWidth) {
+
+               if (i == lastRowBreak) {
+                   mePtr->y = y;
+                   mePtr->x = x;
+                   lastRowBreak++;
+                   y += mePtr->height;
+                   currentRowHeight = 0;
+               } else {
+                   x = borderWidth;
+                   for (j = lastRowBreak; j < i; j++) {
+                       menuPtr->entries[j]->y = y + currentRowHeight
+                               - menuPtr->entries[j]->height;
+                       menuPtr->entries[j]->x = x;
+                       x += menuPtr->entries[j]->width;
+                   }
+                   lastRowBreak = i;
+                   y += currentRowHeight;
+                   currentRowHeight = mePtr->height;
+               }
+               if (x > maxWidth) {
+                   maxWidth = x;
+               }
+               x = borderWidth;
+           } else {
+               x += mePtr->width;
+               if (mePtr->height > currentRowHeight) {
+                   currentRowHeight = mePtr->height;
+               }
+           } 
+       }
+
+       lastEntry = menuPtr->numEntries - 1;
+       if (helpMenuIndex == lastEntry) {
+           lastEntry--;
+       }
+       if ((lastEntry >= 0) && (x + menuPtr->entries[lastEntry]->width
+               + borderWidth > maxWidth)) {
+           maxWidth = x + menuPtr->entries[lastEntry]->width + borderWidth;
+       }
+       x = borderWidth;
+       for (j = lastRowBreak; j < menuPtr->numEntries; j++) {
+           if (j == helpMenuIndex) {
+               continue;
+           }
+           menuPtr->entries[j]->y = y + currentRowHeight
+                   - menuPtr->entries[j]->height;
+           menuPtr->entries[j]->x = x;
+           x += menuPtr->entries[j]->width;
+       }
+       
+
+       if (helpMenuIndex != -1) {
+           mePtr = menuPtr->entries[helpMenuIndex];
+           if (x + mePtr->width + borderWidth > maxWindowWidth) {
+               y += currentRowHeight;
+               currentRowHeight = mePtr->height;
+               x = borderWidth;
+           } else if (mePtr->height > currentRowHeight) {
+               currentRowHeight = mePtr->height;
+           }
+           mePtr->x = maxWindowWidth - borderWidth - mePtr->width;
+           mePtr->y = y + currentRowHeight - mePtr->height;
+       }
+       height = y + currentRowHeight + borderWidth;
+    }
+    width = Tk_Width(menuPtr->tkwin);    
+
+    /*
+     * The X server doesn't like zero dimensions, so round up to at least
+     * 1 (a zero-sized menu should never really occur, anyway).
+     */
+
+    if (width <= 0) {
+       width = 1;
+    }
+    if (height <= 0) {
+       height = 1;
+    }
+    menuPtr->totalWidth = maxWidth;
+    menuPtr->totalHeight = height;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * DrawTearoffEntry --
+ *
+ *     This procedure draws the background part of a menu.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Commands are output to X to display the menu in its
+ *     current mode.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y, width, height)
+    TkMenu *menuPtr;                   /* The menu we are drawing */
+    TkMenuEntry *mePtr;                        /* The entry we are drawing */
+    Drawable d;                                /* The drawable we are drawing into */
+    GC gc;                             /* The gc we are drawing with */
+    Tk_Font tkfont;                    /* The font we are drawing with */
+    CONST Tk_FontMetrics *fmPtr;       /* The metrics we are drawing with */
+    int x;
+    int y;
+    int width;
+    int height;
+{
+    XPoint points[2];
+    int segmentWidth, maxX;
+    Tk_3DBorder border;
+
+    if (menuPtr->menuType != MASTER_MENU) {
+       return;
+    }
+    
+    points[0].x = x;
+    points[0].y = y + height/2;
+    points[1].y = points[0].y;
+    segmentWidth = 6;
+    maxX  = width - 1;
+    border = Tk_Get3DBorderFromObj(menuPtr->tkwin, menuPtr->borderPtr);
+
+    while (points[0].x < maxX) {
+       points[1].x = points[0].x + segmentWidth;
+       if (points[1].x > maxX) {
+           points[1].x = maxX;
+       }
+       Tk_Draw3DPolygon(menuPtr->tkwin, d, border, points, 2, 1,
+               TK_RELIEF_RAISED);
+       points[0].x += 2 * segmentWidth;
+    }
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkpInitializeMenuBindings --
+ *
+ *     For every interp, initializes the bindings for Windows
+ *     menus. Does nothing on Mac or XWindows.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     C-level bindings are setup for the interp which will
+ *     handle Alt-key sequences for menus without beeping
+ *     or interfering with user-defined Alt-key bindings.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkpInitializeMenuBindings(interp, bindingTable)
+    Tcl_Interp *interp;                    /* The interpreter to set. */
+    Tk_BindingTable bindingTable;   /* The table to add to. */
+{
+    /*
+     * Nothing to do.
+     */
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * SetHelpMenu --
+ *
+ *     Given a menu, check to see whether or not it is a help menu
+ *     cascade in a menubar. If it is, the entry that points to
+ *     this menu will be marked.
+ *
+ * RESULTS:
+ *     None.
+ *
+ * Side effects:
+ *     Will set the ENTRY_HELP_MENU flag appropriately.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+SetHelpMenu(menuPtr)
+     TkMenu *menuPtr;          /* The menu we are checking */
+{
+    TkMenuEntry *cascadeEntryPtr;
+
+    for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
+           cascadeEntryPtr != NULL;
+           cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
+       if ((cascadeEntryPtr->menuPtr->menuType == MENUBAR)
+               && (cascadeEntryPtr->menuPtr->masterMenuPtr->tkwin != NULL)
+               && (menuPtr->masterMenuPtr->tkwin != NULL)) {
+           TkMenu *masterMenuPtr = cascadeEntryPtr->menuPtr->masterMenuPtr;
+           char *helpMenuName = ckalloc(strlen(Tk_PathName(
+                   masterMenuPtr->tkwin)) + strlen(".help") + 1);
+
+           strcpy(helpMenuName, Tk_PathName(masterMenuPtr->tkwin));
+           strcat(helpMenuName, ".help");
+           if (strcmp(helpMenuName,
+                   Tk_PathName(menuPtr->masterMenuPtr->tkwin)) == 0) {
+               cascadeEntryPtr->entryFlags |= ENTRY_HELP_MENU;
+           } else {
+               cascadeEntryPtr->entryFlags &= ~ENTRY_HELP_MENU;
+           }
+           ckfree(helpMenuName);
+       }
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpDrawMenuEntry --
+ *
+ *     Draws the given menu entry at the given coordinates with the
+ *     given attributes.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     X Server commands are executed to display the menu entry.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpDrawMenuEntry(mePtr, d, tkfont, menuMetricsPtr, x, y, width, height, 
+       strictMotif, drawArrow)
+    TkMenuEntry *mePtr;                    /* The entry to draw */
+    Drawable d;                            /* What to draw into */
+    Tk_Font tkfont;                /* Precalculated font for menu */
+    CONST Tk_FontMetrics *menuMetricsPtr;
+                                   /* Precalculated metrics for menu */
+    int x;                         /* X-coordinate of topleft of entry */
+    int y;                         /* Y-coordinate of topleft of entry */
+    int width;                     /* Width of the entry rectangle */
+    int height;                            /* Height of the current rectangle */
+    int strictMotif;               /* Boolean flag */
+    int drawArrow;                 /* Whether or not to draw the cascade
+                                    * arrow for cascade items. Only applies
+                                    * to Windows. */
+{
+    GC gc, indicatorGC;
+    TkMenu *menuPtr = mePtr->menuPtr;
+    Tk_3DBorder bgBorder, activeBorder;
+    CONST Tk_FontMetrics *fmPtr;
+    Tk_FontMetrics entryMetrics;
+    int padY = (menuPtr->menuType == MENUBAR) ? 3 : 0;
+    int adjustedY = y + padY;
+    int adjustedHeight = height - 2 * padY;
+
+    /*
+     * Choose the gc for drawing the foreground part of the entry.
+     */
+
+    if ((mePtr->state == ENTRY_ACTIVE) && !strictMotif) {
+       gc = mePtr->activeGC;
+       if (gc == NULL) {
+           gc = menuPtr->activeGC;
+       }
+    } else {
+       TkMenuEntry *cascadeEntryPtr;
+       int parentDisabled = 0;
+       
+       for (cascadeEntryPtr = menuPtr->menuRefPtr->parentEntryPtr;
+               cascadeEntryPtr != NULL;
+               cascadeEntryPtr = cascadeEntryPtr->nextCascadePtr) {
+           if (cascadeEntryPtr->namePtr != NULL) {
+               char *name = Tcl_GetStringFromObj(cascadeEntryPtr->namePtr,
+                       NULL);
+
+               if (strcmp(name, Tk_PathName(menuPtr->tkwin)) == 0) {
+                   if (cascadeEntryPtr->state == ENTRY_DISABLED) {
+                       parentDisabled = 1;
+                   }
+                   break;
+               }
+           }
+       }
+
+       if (((parentDisabled || (mePtr->state == ENTRY_DISABLED)))
+               && (menuPtr->disabledFgPtr != NULL)) {
+           gc = mePtr->disabledGC;
+           if (gc == NULL) {
+               gc = menuPtr->disabledGC;
+           }
+       } else {
+           gc = mePtr->textGC;
+           if (gc == NULL) {
+               gc = menuPtr->textGC;
+           }
+       }
+    }
+    indicatorGC = mePtr->indicatorGC;
+    if (indicatorGC == NULL) {
+       indicatorGC = menuPtr->indicatorGC;
+    }
+
+    bgBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
+           (mePtr->borderPtr == NULL)
+           ? menuPtr->borderPtr : mePtr->borderPtr);
+    if (strictMotif) {
+       activeBorder = bgBorder;
+    } else {
+       activeBorder = Tk_Get3DBorderFromObj(menuPtr->tkwin,
+           (mePtr->activeBorderPtr == NULL)
+           ? menuPtr->activeBorderPtr : mePtr->activeBorderPtr);
+    }
+
+    if (mePtr->fontPtr == NULL) {
+       fmPtr = menuMetricsPtr;
+    } else {
+       tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
+       Tk_GetFontMetrics(tkfont, &entryMetrics);
+       fmPtr = &entryMetrics;
+    }
+
+    /*
+     * Need to draw the entire background, including padding. On Unix,
+     * for menubars, we have to draw the rest of the entry taking
+     * into account the padding.
+     */
+    
+    DrawMenuEntryBackground(menuPtr, mePtr, d, activeBorder, 
+           bgBorder, x, y, width, height);
+    
+    if (mePtr->type == SEPARATOR_ENTRY) {
+       DrawMenuSeparator(menuPtr, mePtr, d, gc, tkfont, 
+               fmPtr, x, adjustedY, width, adjustedHeight);
+    } else if (mePtr->type == TEAROFF_ENTRY) {
+       DrawTearoffEntry(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
+               width, adjustedHeight);
+    } else {
+       DrawMenuEntryLabel(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, adjustedY,
+               width, adjustedHeight);
+       DrawMenuEntryAccelerator(menuPtr, mePtr, d, gc, tkfont, fmPtr,
+               activeBorder, x, adjustedY, width, adjustedHeight, drawArrow);
+       if (!mePtr->hideMargin) {
+           DrawMenuEntryIndicator(menuPtr, mePtr, d, gc, indicatorGC, tkfont,
+                   fmPtr, x, adjustedY, width, adjustedHeight);
+       }
+    }
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * GetMenuLabelGeometry --
+ *
+ *     Figures out the size of the label portion of a menu item.
+ *
+ * Results:
+ *     widthPtr and heightPtr are filled in with the correct geometry
+ *     information.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetMenuLabelGeometry(mePtr, tkfont, fmPtr, widthPtr, heightPtr)
+    TkMenuEntry *mePtr;                        /* The entry we are computing */
+    Tk_Font tkfont;                    /* The precalculated font */
+    CONST Tk_FontMetrics *fmPtr;       /* The precalculated metrics */
+    int *widthPtr;                     /* The resulting width of the label
+                                        * portion */
+    int *heightPtr;                    /* The resulting height of the label
+                                        * portion */
+{
+    TkMenu *menuPtr = mePtr->menuPtr;
+    int haveImage = 0;
+    if (mePtr->image != NULL) {
+       Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
+       haveImage = 1;
+    } else if (mePtr->bitmapPtr !=  NULL) {
+       Pixmap bitmap = Tk_GetBitmapFromObj(menuPtr->tkwin, mePtr->bitmapPtr);
+       Tk_SizeOfBitmap(menuPtr->display, bitmap, widthPtr, heightPtr);
+       haveImage = 1;
+    } else {
+       *heightPtr = 0;
+       *widthPtr = 0;
+    }
+       
+    if (haveImage && (mePtr->compound == COMPOUND_NONE)) {
+       /* We don't care about the text in this case */
+    } else {
+       /* Either it is compound or we don't have an image */
+       if (mePtr->labelPtr != NULL) {
+           int textWidth;
+           char *label = Tcl_GetStringFromObj(mePtr->labelPtr, NULL);
+           textWidth = Tk_TextWidth(tkfont, label, mePtr->labelLength);
+           
+           if ((mePtr->compound != COMPOUND_NONE) && haveImage) {
+               switch ((enum compound) mePtr->compound) {
+                   case COMPOUND_TOP:
+                   case COMPOUND_BOTTOM: {
+                       if (textWidth > *widthPtr) {
+                           *widthPtr = textWidth;
+                       }
+                       /* Add text and padding */
+                       *heightPtr += fmPtr->linespace + 2;
+                       break;
+                   }
+                   case COMPOUND_LEFT:
+                   case COMPOUND_RIGHT: {
+                       if (fmPtr->linespace > *heightPtr) {
+                           *heightPtr = fmPtr->linespace;
+                       }
+                       /* Add text and padding */
+                       *widthPtr += textWidth + 2;
+                       break;
+                   }
+                   case COMPOUND_CENTER: {
+                       if (fmPtr->linespace > *heightPtr) {
+                           *heightPtr = fmPtr->linespace;
+                       }
+                       if (textWidth > *widthPtr) {
+                           *widthPtr = textWidth;
+                       }
+                       break;
+                   }
+                   case COMPOUND_NONE: {break;}
+               }
+       } else {
+               /* We don't have an image or we're not compound */
+               *heightPtr = fmPtr->linespace;
+               *widthPtr = textWidth;
+           }
+       } else {
+           /* An empty entry still has this height */
+           *heightPtr = fmPtr->linespace;
+       }
+    }
+    *heightPtr += 1;
+}
+\f
+/*
+ *--------------------------------------------------------------
+ *
+ * TkpComputeStandardMenuGeometry --
+ *
+ *     This procedure is invoked to recompute the size and
+ *     layout of a menu that is not a menubar clone.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     Fields of menu entries are changed to reflect their
+ *     current positions, and the size of the menu window
+ *     itself may be changed.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkpComputeStandardMenuGeometry(
+    menuPtr)           /* Structure describing menu. */
+    TkMenu *menuPtr;
+{
+    Tk_Font tkfont, menuFont;
+    Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
+    int x, y, height, width, indicatorSpace, labelWidth, accelWidth;
+    int windowWidth, windowHeight, accelSpace;
+    int i, j, lastColumnBreak = 0;
+    TkMenuEntry *mePtr;
+    int borderWidth, activeBorderWidth;
+    
+    if (menuPtr->tkwin == NULL) {
+       return;
+    }
+
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->borderWidthPtr,
+           &borderWidth);
+    Tk_GetPixelsFromObj(NULL, menuPtr->tkwin, menuPtr->activeBorderWidthPtr,
+           &activeBorderWidth);
+    x = y = borderWidth;
+    indicatorSpace = labelWidth = accelWidth = 0;
+    windowHeight = windowWidth = 0;
+
+    /*
+     * On the Mac especially, getting font metrics can be quite slow,
+     * so we want to do it intelligently. We are going to precalculate
+     * them and pass them down to all of the measuring and drawing
+     * routines. We will measure the font metrics of the menu once.
+     * If an entry does not have its own font set, then we give
+     * the geometry/drawing routines the menu's font and metrics.
+     * If an entry has its own font, we will measure that font and
+     * give all of the geometry/drawing the entry's font and metrics.
+     */
+
+    menuFont = Tk_GetFontFromObj(menuPtr->tkwin, menuPtr->fontPtr);
+    Tk_GetFontMetrics(menuFont, &menuMetrics);
+    accelSpace = Tk_TextWidth(menuFont, "M", 1);
+
+    for (i = 0; i < menuPtr->numEntries; i++) {
+       mePtr = menuPtr->entries[i];
+       if (mePtr->fontPtr == NULL) {
+           tkfont = menuFont;
+           fmPtr = &menuMetrics;
+       } else {
+           tkfont = Tk_GetFontFromObj(menuPtr->tkwin, mePtr->fontPtr);
+           Tk_GetFontMetrics(tkfont, &entryMetrics);
+           fmPtr = &entryMetrics;
+       }
+
+       if ((i > 0) && mePtr->columnBreak) {
+           if (accelWidth != 0) {
+               labelWidth += accelSpace;
+           }
+           for (j = lastColumnBreak; j < i; j++) {
+               menuPtr->entries[j]->indicatorSpace = indicatorSpace;
+               menuPtr->entries[j]->labelWidth = labelWidth;
+               menuPtr->entries[j]->width = indicatorSpace + labelWidth
+                       + accelWidth + 2 * activeBorderWidth;
+               menuPtr->entries[j]->x = x;
+               menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN;
+           }
+           x += indicatorSpace + labelWidth + accelWidth
+                   + 2 * activeBorderWidth;
+           windowWidth = x;
+           indicatorSpace = labelWidth = accelWidth = 0;
+           lastColumnBreak = i;
+           y = borderWidth;
+       }
+
+       if (mePtr->type == SEPARATOR_ENTRY) {
+           GetMenuSeparatorGeometry(menuPtr, mePtr, tkfont,
+                   fmPtr, &width, &height);
+           mePtr->height = height;
+       } else if (mePtr->type == TEAROFF_ENTRY) {
+           GetTearoffEntryGeometry(menuPtr, mePtr, tkfont, 
+                   fmPtr, &width, &height);
+           mePtr->height = height;
+           labelWidth = width;
+       } else {
+           
+           /*
+            * For each entry, compute the height required by that
+            * particular entry, plus three widths:  the width of the
+            * label, the width to allow for an indicator to be displayed
+            * to the left of the label (if any), and the width of the
+            * accelerator to be displayed to the right of the label
+            * (if any).  These sizes depend, of course, on the type
+            * of the entry.
+            */
+           
+           GetMenuLabelGeometry(mePtr, tkfont, fmPtr, &width,
+                   &height);
+           mePtr->height = height;
+           if (!mePtr->hideMargin) {
+               width += MENU_MARGIN_WIDTH;
+           }
+           if (width > labelWidth) {
+               labelWidth = width;
+           }
+       
+           GetMenuAccelGeometry(menuPtr, mePtr, tkfont,
+                   fmPtr, &width, &height);
+           if (height > mePtr->height) {
+               mePtr->height = height;
+           }
+           if (!mePtr->hideMargin) {
+               width += MENU_MARGIN_WIDTH;
+           }
+           if (width > accelWidth) {
+               accelWidth = width;
+           }
+
+           GetMenuIndicatorGeometry(menuPtr, mePtr, tkfont, 
+                   fmPtr, &width, &height);
+           if (height > mePtr->height) {
+               mePtr->height = height;
+           }
+           if (!mePtr->hideMargin) {
+               width += MENU_MARGIN_WIDTH;
+           }
+           if (width > indicatorSpace) {
+               indicatorSpace = width;
+           }
+
+           mePtr->height += 2 * activeBorderWidth + MENU_DIVIDER_HEIGHT;
+       }
+        mePtr->y = y;
+       y += mePtr->height;
+       if (y > windowHeight) {
+           windowHeight = y;
+       }
+    }
+
+    if (accelWidth != 0) {
+       labelWidth += accelSpace;
+    }
+    for (j = lastColumnBreak; j < menuPtr->numEntries; j++) {
+       menuPtr->entries[j]->indicatorSpace = indicatorSpace;
+       menuPtr->entries[j]->labelWidth = labelWidth;
+       menuPtr->entries[j]->width = indicatorSpace + labelWidth
+               + accelWidth + 2 * activeBorderWidth;
+       menuPtr->entries[j]->x = x;
+       menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN;
+    }
+    windowWidth = x + indicatorSpace + labelWidth + accelWidth
+           + 2 * activeBorderWidth + 2 * borderWidth;
+
+
+    windowHeight += borderWidth;
+    
+    /*
+     * The X server doesn't like zero dimensions, so round up to at least
+     * 1 (a zero-sized menu should never really occur, anyway).
+     */
+
+    if (windowWidth <= 0) {
+       windowWidth = 1;
+    }
+    if (windowHeight <= 0) {
+       windowHeight = 1;
+    }
+    menuPtr->totalWidth = windowWidth;
+    menuPtr->totalHeight = windowHeight;
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpMenuNotifyToplevelCreate --
+ *
+ *     This routine reconfigures the menu and the clones indicated by
+ *     menuName becuase a toplevel has been created and any system
+ *     menus need to be created. Not applicable to UNIX.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     An idle handler is set up to do the reconfiguration.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpMenuNotifyToplevelCreate(interp, menuName)
+    Tcl_Interp *interp;                        /* The interp the menu lives in. */
+    char *menuName;                    /* The name of the menu to 
+                                        * reconfigure. */
+{
+    /*
+     * Nothing to do.
+     */
+}
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpMenuInit --
+ *
+ *     Does platform-specific initialization of menus.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpMenuInit()
+{
+    /*
+     * Nothing to do.
+     */
+}
+
+\f
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpMenuThreadInit --
+ *
+ *     Does platform-specific initialization of thread-specific
+ *      menu state.
+ *
+ * Results:
+ *     None.
+ *
+ * Side effects:
+ *     None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpMenuThreadInit()
+{
+    /*
+     * Nothing to do.
+     */
+}
+