summaryrefslogtreecommitdiffstats
path: root/unix/tkUnixMenu.c
diff options
context:
space:
mode:
authorrjohnson <rjohnson>1998-04-01 09:51:44 (GMT)
committerrjohnson <rjohnson>1998-04-01 09:51:44 (GMT)
commit066ea7fd88d49cb456f74da71dbe875e4fc0aabb (patch)
tree8fb30cb152c4dc191be47fa043d2e6f5ea38c7ba /unix/tkUnixMenu.c
parent13242623d2ff3ea02ab6a62bfb48a7dbb5c27e22 (diff)
downloadtk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.zip
tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.tar.gz
tk-066ea7fd88d49cb456f74da71dbe875e4fc0aabb.tar.bz2
Initial revision
Diffstat (limited to 'unix/tkUnixMenu.c')
-rw-r--r--unix/tkUnixMenu.c1603
1 files changed, 1603 insertions, 0 deletions
diff --git a/unix/tkUnixMenu.c b/unix/tkUnixMenu.c
new file mode 100644
index 0000000..3179a31
--- /dev/null
+++ b/unix/tkUnixMenu.c
@@ -0,0 +1,1603 @@
+/*
+ * tkUnixMenu.c --
+ *
+ * This module implements the UNIX platform-specific features of menus.
+ *
+ * Copyright (c) 1996-1997 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.
+ *
+ * SCCS: @(#) tkUnixMenu.c 1.76 97/11/05 09:08:22
+ */
+
+#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));
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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.
+ */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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.
+ */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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
+ * interp->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->name != NULL)) {
+ TkMenuReferences *menuRefPtr;
+
+ menuRefPtr = TkFindMenuReferences(mePtr->menuPtr->interp,
+ mePtr->name);
+ if ((menuRefPtr != NULL) && (menuRefPtr->menuPtr != NULL)) {
+ SetHelpMenu(menuRefPtr->menuPtr);
+ }
+ }
+ return TCL_OK;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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.
+ */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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->hideMargin && mePtr->indicatorOn &&
+ ((mePtr->type == CHECK_BUTTON_ENTRY)
+ || (mePtr->type == RADIO_BUTTON_ENTRY))) {
+ if ((mePtr->image != NULL) || (mePtr->bitmap != None)) {
+ *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 {
+ *heightPtr = 0;
+ *widthPtr = menuPtr->borderWidth;
+ }
+}
+
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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->accel != NULL)) {
+ *widthPtr = Tk_TextWidth(tkfont, mePtr->accel, mePtr->accelLength);
+ } else {
+ *widthPtr = 0;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 == tkActiveUid) {
+ int relief;
+ bgBorder = activeBorder;
+
+ if ((menuPtr->menuType == MENUBAR)
+ && ((menuPtr->postedCascade == NULL)
+ || (menuPtr->postedCascade != mePtr))) {
+ relief = TK_RELIEF_FLAT;
+ } else {
+ relief = TK_RELIEF_RAISED;
+ }
+
+ Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
+ menuPtr->activeBorderWidth, relief);
+ } else {
+ Tk_Fill3DRectangle(menuPtr->tkwin, d, bgBorder, x, y, width, height,
+ 0, TK_RELIEF_FLAT);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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];
+
+ /*
+ * Draw accelerator or cascade arrow.
+ */
+
+ if (menuPtr->menuType == MENUBAR) {
+ return;
+ }
+
+ if ((mePtr->type == CASCADE_ENTRY) && drawArrow) {
+ points[0].x = x + width - menuPtr->borderWidth
+ - menuPtr->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->accel != NULL) {
+ int left = x + mePtr->labelWidth + menuPtr->activeBorderWidth
+ + mePtr->indicatorSpace;
+ if (menuPtr->menuType == MENUBAR) {
+ left += 5;
+ }
+ Tk_DrawChars(menuPtr->display, d, gc, tkfont, mePtr->accel,
+ mePtr->accelLength, left,
+ (y + (height + fmPtr->ascent - fmPtr->descent) / 2));
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
+
+ dim = (int) mePtr->platformEntryData;
+ left = x + menuPtr->activeBorderWidth
+ + (mePtr->indicatorSpace - dim)/2;
+ if (menuPtr->menuType == MENUBAR) {
+ left += 5;
+ }
+ top = y + (height - dim)/2;
+ Tk_Fill3DRectangle(menuPtr->tkwin, d, menuPtr->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;
+
+ 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, menuPtr->border, points, 4,
+ DECORATION_BORDER_WIDTH, TK_RELIEF_FLAT);
+ }
+ Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 4,
+ DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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];
+ int margin;
+
+ if (menuPtr->menuType == MENUBAR) {
+ return;
+ }
+
+ margin = (fmPtr->ascent + fmPtr->descent)/2;
+ points[0].x = x;
+ points[0].y = y + height/2;
+ points[1].x = width - 1;
+ points[1].y = points[0].y;
+ Tk_Draw3DPolygon(menuPtr->tkwin, d, menuPtr->border, points, 2, 1,
+ TK_RELIEF_RAISED);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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, /* The menu we are drawing */
+ mePtr, /* The entry we are drawing */
+ d, /* What we are drawing into */
+ gc, /* The gc we are drawing into */
+ tkfont, /* The precalculated font */
+ fmPtr, /* The precalculated font metrics */
+ x, /* left edge */
+ y, /* right edge */
+ width, /* width of entry */
+ height) /* height of entry */
+ TkMenu *menuPtr;
+ TkMenuEntry *mePtr;
+ Drawable d;
+ GC gc;
+ Tk_Font tkfont;
+ CONST Tk_FontMetrics *fmPtr;
+ int x, y, width, height;
+{
+ int baseline;
+ int indicatorSpace = mePtr->indicatorSpace;
+ int leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth;
+ int imageHeight, imageWidth;
+
+ if (menuPtr->menuType == MENUBAR) {
+ leftEdge += 5;
+ }
+
+ /*
+ * Draw label or bitmap or image for entry.
+ */
+
+ baseline = y + (height + fmPtr->ascent - fmPtr->descent) / 2;
+ if (mePtr->image != NULL) {
+ Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
+ if ((mePtr->selectImage != NULL)
+ && (mePtr->entryFlags & ENTRY_SELECTED)) {
+ Tk_RedrawImage(mePtr->selectImage, 0, 0,
+ imageWidth, imageHeight, d, leftEdge,
+ (int) (y + (mePtr->height - imageHeight)/2));
+ } else {
+ Tk_RedrawImage(mePtr->image, 0, 0, imageWidth,
+ imageHeight, d, leftEdge,
+ (int) (y + (mePtr->height - imageHeight)/2));
+ }
+ } else if (mePtr->bitmap != None) {
+ int width, height;
+
+ Tk_SizeOfBitmap(menuPtr->display,
+ mePtr->bitmap, &width, &height);
+ XCopyPlane(menuPtr->display,
+ mePtr->bitmap, d,
+ gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge,
+ (int) (y + (mePtr->height - height)/2), 1);
+ } else {
+ if (mePtr->labelLength > 0) {
+ Tk_DrawChars(menuPtr->display, d, gc,
+ tkfont, mePtr->label, mePtr->labelLength,
+ leftEdge, baseline);
+ DrawMenuUnderline(menuPtr, mePtr, d, gc, tkfont, fmPtr, x, y,
+ width, height);
+ }
+ }
+
+ if (mePtr->state == tkDisabledUid) {
+ if (menuPtr->disabledFg == 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,
+ (int) (y + (mePtr->height - imageHeight)/2),
+ (unsigned) imageWidth, (unsigned) imageHeight);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 leftEdge = x + indicatorSpace + menuPtr->activeBorderWidth;
+ if (menuPtr->menuType == MENUBAR) {
+ leftEdge += 5;
+ }
+
+ Tk_UnderlineChars(menuPtr->display, d, gc, tkfont, mePtr->label,
+ leftEdge, y + (height + fmPtr->ascent - fmPtr->descent) / 2,
+ mePtr->underline, mePtr->underline + 1);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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);
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * 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, currentRowWidth, maxWidth;
+ int maxWindowWidth;
+ int lastRowBreak;
+ int helpMenuIndex = -1;
+ TkMenuEntry *mePtr;
+ int lastEntry;
+
+ if (menuPtr->tkwin == NULL) {
+ return;
+ }
+
+ maxWidth = 0;
+ if (menuPtr->numEntries == 0) {
+ height = 0;
+ } else {
+ maxWindowWidth = Tk_Width(menuPtr->tkwin);
+ if (maxWindowWidth == 1) {
+ maxWindowWidth = 0x7ffffff;
+ }
+ currentRowHeight = 0;
+ x = y = menuPtr->borderWidth;
+ lastRowBreak = 0;
+ currentRowWidth = 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.
+ */
+
+ Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
+
+ for (i = 0; i < menuPtr->numEntries; i++) {
+ mePtr = menuPtr->entries[i];
+ mePtr->entryFlags &= ~ENTRY_LAST_COLUMN;
+ tkfont = mePtr->tkfont;
+ if (tkfont == NULL) {
+ tkfont = menuPtr->tkfont;
+ fmPtr = &menuMetrics;
+ } else {
+ Tk_GetFontMetrics(tkfont, &entryMetrics);
+ fmPtr = &entryMetrics;
+ }
+
+ /*
+ * 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 * menuPtr->activeBorderWidth + 10;
+ mePtr->width = width;
+
+ GetMenuIndicatorGeometry(menuPtr, mePtr,
+ tkfont, fmPtr, &width, &height);
+ mePtr->indicatorSpace = width;
+ if (width > 0) {
+ mePtr->width += width;
+ }
+ mePtr->width += 2 * menuPtr->activeBorderWidth + 10;
+ }
+ if (mePtr->entryFlags & ENTRY_HELP_MENU) {
+ helpMenuIndex = i;
+ } else if (x + mePtr->width + menuPtr->borderWidth
+ > maxWindowWidth) {
+
+ if (i == lastRowBreak) {
+ mePtr->y = y;
+ mePtr->x = x;
+ lastRowBreak++;
+ y += mePtr->height;
+ currentRowHeight = 0;
+ } else {
+ x = menuPtr->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 = menuPtr->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
+ + menuPtr->borderWidth > maxWidth)) {
+ maxWidth = x + menuPtr->entries[lastEntry]->width
+ + menuPtr->borderWidth;
+ }
+ x = menuPtr->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 + menuPtr->borderWidth > maxWindowWidth) {
+ y += currentRowHeight;
+ currentRowHeight = mePtr->height;
+ x = menuPtr->borderWidth;
+ } else if (mePtr->height > currentRowHeight) {
+ currentRowHeight = mePtr->height;
+ }
+ mePtr->x = maxWindowWidth - menuPtr->borderWidth - mePtr->width;
+ mePtr->y = y + currentRowHeight - mePtr->height;
+ }
+ height = y + currentRowHeight + menuPtr->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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 margin, segmentWidth, maxX;
+
+ if (menuPtr->menuType != MASTER_MENU) {
+ return;
+ }
+
+ margin = (fmPtr->ascent + fmPtr->descent)/2;
+ points[0].x = x;
+ points[0].y = y + height/2;
+ points[1].y = points[0].y;
+ segmentWidth = 6;
+ maxX = width - 1;
+
+ 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, menuPtr->border, points, 2, 1,
+ TK_RELIEF_RAISED);
+ points[0].x += 2*segmentWidth;
+ }
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * 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.
+ */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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 == tkActiveUid)
+ && !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 (strcmp(cascadeEntryPtr->name,
+ Tk_PathName(menuPtr->tkwin)) == 0) {
+ if (cascadeEntryPtr->state == tkDisabledUid) {
+ parentDisabled = 1;
+ }
+ break;
+ }
+ }
+
+ if (((parentDisabled || (mePtr->state == tkDisabledUid)))
+ && (menuPtr->disabledFg != 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 = mePtr->border;
+ if (bgBorder == NULL) {
+ bgBorder = menuPtr->border;
+ }
+ if (strictMotif) {
+ activeBorder = bgBorder;
+ } else {
+ activeBorder = mePtr->activeBorder;
+ if (activeBorder == NULL) {
+ activeBorder = menuPtr->activeBorder;
+ }
+ }
+
+ if (mePtr->tkfont == NULL) {
+ fmPtr = menuMetricsPtr;
+ } else {
+ tkfont = mePtr->tkfont;
+ 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);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
+
+ if (mePtr->image != NULL) {
+ Tk_SizeOfImage(mePtr->image, widthPtr, heightPtr);
+ } else if (mePtr->bitmap != (Pixmap) NULL) {
+ Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, widthPtr, heightPtr);
+ } else {
+ *heightPtr = fmPtr->linespace;
+
+ if (mePtr->label != NULL) {
+ *widthPtr = Tk_TextWidth(tkfont, mePtr->label, mePtr->labelLength);
+ } else {
+ *widthPtr = 0;
+ }
+ }
+ *heightPtr += 1;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * 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;
+ Tk_FontMetrics menuMetrics, entryMetrics, *fmPtr;
+ int x, y, height, width, indicatorSpace, labelWidth, accelWidth;
+ int windowWidth, windowHeight, accelSpace;
+ int i, j, lastColumnBreak = 0;
+ TkMenuEntry *mePtr;
+
+ if (menuPtr->tkwin == NULL) {
+ return;
+ }
+
+ x = y = menuPtr->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.
+ */
+
+ Tk_GetFontMetrics(menuPtr->tkfont, &menuMetrics);
+ accelSpace = Tk_TextWidth(menuPtr->tkfont, "M", 1);
+
+ for (i = 0; i < menuPtr->numEntries; i++) {
+ mePtr = menuPtr->entries[i];
+ tkfont = mePtr->tkfont;
+ if (tkfont == NULL) {
+ tkfont = menuPtr->tkfont;
+ fmPtr = &menuMetrics;
+ } else {
+ 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 * menuPtr->activeBorderWidth;
+ menuPtr->entries[j]->x = x;
+ menuPtr->entries[j]->entryFlags &= ~ENTRY_LAST_COLUMN;
+ }
+ x += indicatorSpace + labelWidth + accelWidth
+ + 2 * menuPtr->activeBorderWidth;
+ windowWidth = x;
+ indicatorSpace = labelWidth = accelWidth = 0;
+ lastColumnBreak = i;
+ y = menuPtr->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 * menuPtr->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 * menuPtr->activeBorderWidth;
+ menuPtr->entries[j]->x = x;
+ menuPtr->entries[j]->entryFlags |= ENTRY_LAST_COLUMN;
+ }
+ windowWidth = x + indicatorSpace + labelWidth + accelWidth
+ + 2 * menuPtr->activeBorderWidth + 2 * menuPtr->borderWidth;
+
+
+ windowHeight += menuPtr->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;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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.
+ */
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpMenuInit --
+ *
+ * Does platform-specific initialization of menus.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+TkpMenuInit()
+{
+ /*
+ * Nothing to do.
+ */
+}