#include "tkInt.h"
#include "tkDefault.h"
#ifdef MAC_TCL
# include "tkMacInt.h"
#endif
typedef struct MenuEntry {
int type;
struct Menu *menuPtr;
char *label;
int labelLength;
int underline;
Pixmap bitmap;
char *imageString;
Tk_Image image;
char *selectImageString;
Tk_Image selectImage;
char *accel;
int accelLength;
Tk_Uid state;
int height;
int y;
int indicatorOn;
int indicatorDiameter;
Tk_3DBorder border;
XColor *fg;
Tk_3DBorder activeBorder;
XColor *activeFg;
XFontStruct *fontPtr;
GC textGC;
GC activeGC;
GC disabledGC;
XColor *indicatorFg;
GC indicatorGC;
char *command;
char *name;
char *onValue;
char *offValue;
int flags;
} MenuEntry;
#define ENTRY_SELECTED 1
#define ENTRY_NEEDS_REDISPLAY 4
#define COMMAND_ENTRY 0
#define SEPARATOR_ENTRY 1
#define CHECK_BUTTON_ENTRY 2
#define RADIO_BUTTON_ENTRY 3
#define CASCADE_ENTRY 4
#define TEAROFF_ENTRY 5
#define COMMAND_MASK TK_CONFIG_USER_BIT
#define SEPARATOR_MASK (TK_CONFIG_USER_BIT << 1)
#define CHECK_BUTTON_MASK (TK_CONFIG_USER_BIT << 2)
#define RADIO_BUTTON_MASK (TK_CONFIG_USER_BIT << 3)
#define CASCADE_MASK (TK_CONFIG_USER_BIT << 4)
#define TEAROFF_MASK (TK_CONFIG_USER_BIT << 5)
#define ALL_MASK (COMMAND_MASK | SEPARATOR_MASK \
| CHECK_BUTTON_MASK | RADIO_BUTTON_MASK | CASCADE_MASK | TEAROFF_MASK)
static Tk_ConfigSpec entryConfigSpecs[] = {
{TK_CONFIG_BORDER, "-activebackground", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_ACTIVE_BG, Tk_Offset(MenuEntry, activeBorder),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_COLOR, "-activeforeground", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_ACTIVE_FG, Tk_Offset(MenuEntry, activeFg),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-accelerator", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_ACCELERATOR, Tk_Offset(MenuEntry, accel),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_BORDER, "-background", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_BG, Tk_Offset(MenuEntry, border),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|SEPARATOR_MASK|TEAROFF_MASK|TK_CONFIG_NULL_OK},
{TK_CONFIG_BITMAP, "-bitmap", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_BITMAP, Tk_Offset(MenuEntry, bitmap),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-command", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_COMMAND, Tk_Offset(MenuEntry, command),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_FONT, "-font", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_FONT, Tk_Offset(MenuEntry, fontPtr),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_COLOR, "-foreground", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_FG, Tk_Offset(MenuEntry, fg),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-image", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_IMAGE, Tk_Offset(MenuEntry, imageString),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_NULL_OK},
{TK_CONFIG_BOOLEAN, "-indicatoron", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_INDICATOR, Tk_Offset(MenuEntry, indicatorOn),
CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_DONT_SET_DEFAULT},
{TK_CONFIG_STRING, "-label", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_LABEL, Tk_Offset(MenuEntry, label),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK},
{TK_CONFIG_STRING, "-menu", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_MENU, Tk_Offset(MenuEntry, name),
CASCADE_MASK|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-offvalue", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_OFF_VALUE, Tk_Offset(MenuEntry, offValue),
CHECK_BUTTON_MASK},
{TK_CONFIG_STRING, "-onvalue", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_ON_VALUE, Tk_Offset(MenuEntry, onValue),
CHECK_BUTTON_MASK},
{TK_CONFIG_COLOR, "-selectcolor", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_SELECT, Tk_Offset(MenuEntry, indicatorFg),
CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-selectimage", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_SELECT_IMAGE, Tk_Offset(MenuEntry, selectImageString),
CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK},
{TK_CONFIG_UID, "-state", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_STATE, Tk_Offset(MenuEntry, state),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TEAROFF_MASK|TK_CONFIG_DONT_SET_DEFAULT},
{TK_CONFIG_STRING, "-value", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_VALUE, Tk_Offset(MenuEntry, onValue),
RADIO_BUTTON_MASK|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_CHECK_VARIABLE, Tk_Offset(MenuEntry, name),
CHECK_BUTTON_MASK|TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-variable", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_RADIO_VARIABLE, Tk_Offset(MenuEntry, name),
RADIO_BUTTON_MASK},
{TK_CONFIG_INT, "-underline", (char *) NULL, (char *) NULL,
DEF_MENU_ENTRY_UNDERLINE, Tk_Offset(MenuEntry, underline),
COMMAND_MASK|CHECK_BUTTON_MASK|RADIO_BUTTON_MASK|CASCADE_MASK
|TK_CONFIG_DONT_SET_DEFAULT},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
typedef struct Menu {
Tk_Window tkwin;
Display *display;
Tcl_Interp *interp;
Tcl_Command widgetCmd;
MenuEntry **entries;
int numEntries;
int active;
Tk_3DBorder border;
int borderWidth;
Tk_3DBorder activeBorder;
int activeBorderWidth;
int relief;
XFontStruct *fontPtr;
XColor *fg;
GC textGC;
XColor *disabledFg;
Pixmap gray;
GC disabledGC;
XColor *activeFg;
GC activeGC;
XColor *indicatorFg;
GC indicatorGC;
int indicatorSpace;
int labelWidth;
int tearOff;
char *tearOffCommand;
int transient;
Tk_Cursor cursor;
char *takeFocus;
char *postCommand;
MenuEntry *postedCascade;
int flags;
} Menu;
#define REDRAW_PENDING 1
#define RESIZE_PENDING 2
static Tk_ConfigSpec configSpecs[] = {
{TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
DEF_MENU_ACTIVE_BG_COLOR, Tk_Offset(Menu, activeBorder),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
DEF_MENU_ACTIVE_BG_MONO, Tk_Offset(Menu, activeBorder),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_PIXELS, "-activeborderwidth", "activeBorderWidth", "BorderWidth",
DEF_MENU_ACTIVE_BORDER_WIDTH, Tk_Offset(Menu, activeBorderWidth), 0},
{TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
DEF_MENU_ACTIVE_FG_COLOR, Tk_Offset(Menu, activeFg),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
DEF_MENU_ACTIVE_FG_MONO, Tk_Offset(Menu, activeFg),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_BORDER, "-background", "background", "Background",
DEF_MENU_BG_COLOR, Tk_Offset(Menu, border), TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-background", "background", "Background",
DEF_MENU_BG_MONO, Tk_Offset(Menu, border), TK_CONFIG_MONO_ONLY},
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
DEF_MENU_BORDER_WIDTH, Tk_Offset(Menu, borderWidth), 0},
{TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
DEF_MENU_CURSOR, Tk_Offset(Menu, cursor), TK_CONFIG_NULL_OK},
{TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
"DisabledForeground", DEF_MENU_DISABLED_FG_COLOR,
Tk_Offset(Menu, disabledFg), TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
{TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
"DisabledForeground", DEF_MENU_DISABLED_FG_MONO,
Tk_Offset(Menu, disabledFg), TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
{TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_FONT, "-font", "font", "Font",
DEF_MENU_FONT, Tk_Offset(Menu, fontPtr), 0},
{TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
DEF_MENU_FG, Tk_Offset(Menu, fg), 0},
{TK_CONFIG_STRING, "-postcommand", "postCommand", "Command",
DEF_MENU_POST_COMMAND, Tk_Offset(Menu, postCommand), TK_CONFIG_NULL_OK},
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
DEF_MENU_RELIEF, Tk_Offset(Menu, relief), 0},
{TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background",
DEF_MENU_SELECT_COLOR, Tk_Offset(Menu, indicatorFg),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-selectcolor", "selectColor", "Background",
DEF_MENU_SELECT_MONO, Tk_Offset(Menu, indicatorFg),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
DEF_MENU_TAKE_FOCUS, Tk_Offset(Menu, takeFocus), TK_CONFIG_NULL_OK},
{TK_CONFIG_BOOLEAN, "-tearoff", "tearOff", "TearOff",
DEF_MENU_TEAROFF, Tk_Offset(Menu, tearOff), 0},
{TK_CONFIG_STRING, "-tearoffcommand", "tearOffCommand", "TearOffCommand",
DEF_MENU_TEAROFF_CMD, Tk_Offset(Menu, tearOffCommand),
TK_CONFIG_NULL_OK},
{TK_CONFIG_BOOLEAN, "-transient", "transient", "Transient",
DEF_MENU_TRANSIENT, Tk_Offset(Menu, transient), 0},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
#define CASCADE_ARROW_HEIGHT 10
#define CASCADE_ARROW_WIDTH 8
#define DECORATION_BORDER_WIDTH 2
#define MARGIN_WIDTH 2
static int ActivateMenuEntry _ANSI_ARGS_((Menu *menuPtr,
int index));
static void ComputeMenuGeometry _ANSI_ARGS_((
ClientData clientData));
static int ConfigureMenu _ANSI_ARGS_((Tcl_Interp *interp,
Menu *menuPtr, int argc, char **argv,
int flags));
static int ConfigureMenuEntry _ANSI_ARGS_((Tcl_Interp *interp,
Menu *menuPtr, MenuEntry *mePtr, int index,
int argc, char **argv, int flags));
static void DestroyMenu _ANSI_ARGS_((char *memPtr));
static void DestroyMenuEntry _ANSI_ARGS_((char *memPtr));
static void DisplayMenu _ANSI_ARGS_((ClientData clientData));
static void EventuallyRedrawMenu _ANSI_ARGS_((Menu *menuPtr,
MenuEntry *mePtr));
static int GetMenuIndex _ANSI_ARGS_((Tcl_Interp *interp,
Menu *menuPtr, char *string, int lastOK,
int *indexPtr));
static int MenuAddOrInsert _ANSI_ARGS_((Tcl_Interp *interp,
Menu *menuPtr, char *indexString, int argc,
char **argv));
static void MenuCmdDeletedProc _ANSI_ARGS_((
ClientData clientData));
static void MenuEventProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
static void MenuImageProc _ANSI_ARGS_((ClientData clientData,
int x, int y, int width, int height, int imgWidth,
int imgHeight));
static MenuEntry * MenuNewEntry _ANSI_ARGS_((Menu *menuPtr, int index,
int type));
static void MenuSelectImageProc _ANSI_ARGS_((ClientData clientData,
int x, int y, int width, int height, int imgWidth,
int imgHeight));
static char * MenuVarProc _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, char *name1, char *name2,
int flags));
static int MenuWidgetCmd _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int argc, char **argv));
static int PostSubmenu _ANSI_ARGS_((Tcl_Interp *interp,
Menu *menuPtr, MenuEntry *mePtr));
int
Tk_MenuCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
Tk_Window tkwin = (Tk_Window) clientData;
Tk_Window new;
register Menu *menuPtr;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " pathName ?options?\"", (char *) NULL);
return TCL_ERROR;
}
new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], "");
if (new == NULL) {
return TCL_ERROR;
}
menuPtr = (Menu *) ckalloc(sizeof(Menu));
menuPtr->tkwin = new;
menuPtr->display = Tk_Display(new);
menuPtr->interp = interp;
menuPtr->widgetCmd = Tcl_CreateCommand(interp,
Tk_PathName(menuPtr->tkwin), MenuWidgetCmd,
(ClientData) menuPtr, MenuCmdDeletedProc);
menuPtr->entries = NULL;
menuPtr->numEntries = 0;
menuPtr->active = -1;
menuPtr->border = NULL;
menuPtr->borderWidth = 0;
menuPtr->relief = TK_RELIEF_FLAT;
menuPtr->activeBorder = NULL;
menuPtr->activeBorderWidth = 0;
menuPtr->fontPtr = NULL;
menuPtr->fg = NULL;
menuPtr->textGC = None;
menuPtr->disabledFg = NULL;
menuPtr->gray = None;
menuPtr->disabledGC = None;
menuPtr->activeFg = NULL;
menuPtr->activeGC = None;
menuPtr->indicatorFg = NULL;
menuPtr->indicatorGC = None;
menuPtr->indicatorSpace = 0;
menuPtr->labelWidth = 0;
menuPtr->tearOff = 1;
menuPtr->tearOffCommand = NULL;
menuPtr->cursor = None;
menuPtr->takeFocus = NULL;
menuPtr->postCommand = NULL;
menuPtr->postedCascade = NULL;
menuPtr->flags = 0;
Tk_SetClass(new, "Menu");
Tk_CreateEventHandler(menuPtr->tkwin, ExposureMask|StructureNotifyMask,
MenuEventProc, (ClientData) menuPtr);
if (ConfigureMenu(interp, menuPtr, argc-2, argv+2, 0) != TCL_OK) {
goto error;
}
interp->result = Tk_PathName(menuPtr->tkwin);
return TCL_OK;
error:
Tk_DestroyWindow(menuPtr->tkwin);
return TCL_ERROR;
}
static int
MenuWidgetCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
register Menu *menuPtr = (Menu *) clientData;
register MenuEntry *mePtr;
int result = TCL_OK;
size_t length;
int c;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " option ?arg arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
Tcl_Preserve((ClientData) menuPtr);
c = argv[1][0];
length = strlen(argv[1]);
if ((c == 'a') && (strncmp(argv[1], "activate", length) == 0)
&& (length >= 2)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " activate index\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (menuPtr->active == index) {
goto done;
}
if (index >= 0) {
if ((menuPtr->entries[index]->type == SEPARATOR_ENTRY)
|| (menuPtr->entries[index]->state == tkDisabledUid)) {
index = -1;
}
}
result = ActivateMenuEntry(menuPtr, index);
} else if ((c == 'a') && (strncmp(argv[1], "add", length) == 0)
&& (length >= 2)) {
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " add type ?options?\"", (char *) NULL);
goto error;
}
if (MenuAddOrInsert(interp, menuPtr, (char *) NULL,
argc-2, argv+2) != TCL_OK) {
goto error;
}
} else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
&& (length >= 2)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " cget option\"",
(char *) NULL);
goto error;
}
result = Tk_ConfigureValue(interp, menuPtr->tkwin, configSpecs,
(char *) menuPtr, argv[2], 0);
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
&& (length >= 2)) {
if (argc == 2) {
result = Tk_ConfigureInfo(interp, menuPtr->tkwin, configSpecs,
(char *) menuPtr, (char *) NULL, 0);
} else if (argc == 3) {
result = Tk_ConfigureInfo(interp, menuPtr->tkwin, configSpecs,
(char *) menuPtr, argv[2], 0);
} else {
result = ConfigureMenu(interp, menuPtr, argc-2, argv+2,
TK_CONFIG_ARGV_ONLY);
}
} else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
int first, last, i, numDeleted;
if ((argc != 3) && (argc != 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " delete first ?last?\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &first) != TCL_OK) {
goto error;
}
if (argc == 3) {
last = first;
} else {
if (GetMenuIndex(interp, menuPtr, argv[3], 0, &last) != TCL_OK) {
goto error;
}
}
if (menuPtr->tearOff && (first == 0)) {
first = 1;
}
if ((first < 0) || (last < first)) {
goto done;
}
numDeleted = last + 1 - first;
for (i = first; i <= last; i++) {
Tcl_EventuallyFree((ClientData) menuPtr->entries[i],
DestroyMenuEntry);
}
for (i = last+1; i < menuPtr->numEntries; i++) {
menuPtr->entries[i-numDeleted] = menuPtr->entries[i];
}
menuPtr->numEntries -= numDeleted;
if ((menuPtr->active >= first) && (menuPtr->active <= last)) {
menuPtr->active = -1;
} else if (menuPtr->active > last) {
menuPtr->active -= numDeleted;
}
if (!(menuPtr->flags & RESIZE_PENDING)) {
menuPtr->flags |= RESIZE_PENDING;
Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
}
} else if ((c == 'e') && (length >= 7)
&& (strncmp(argv[1], "entrycget", length) == 0)) {
int index;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " entrycget index option\"",
(char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (index < 0) {
goto done;
}
mePtr = menuPtr->entries[index];
Tcl_Preserve((ClientData) mePtr);
result = Tk_ConfigureValue(interp, menuPtr->tkwin, entryConfigSpecs,
(char *) mePtr, argv[3], COMMAND_MASK << mePtr->type);
Tcl_Release((ClientData) mePtr);
} else if ((c == 'e') && (length >= 7)
&& (strncmp(argv[1], "entryconfigure", length) == 0)) {
int index;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " entryconfigure index ?option value ...?\"",
(char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (index < 0) {
goto done;
}
mePtr = menuPtr->entries[index];
Tcl_Preserve((ClientData) mePtr);
if (argc == 3) {
result = Tk_ConfigureInfo(interp, menuPtr->tkwin, entryConfigSpecs,
(char *) mePtr, (char *) NULL,
COMMAND_MASK << mePtr->type);
} else if (argc == 4) {
result = Tk_ConfigureInfo(interp, menuPtr->tkwin, entryConfigSpecs,
(char *) mePtr, argv[3], COMMAND_MASK << mePtr->type);
} else {
result = ConfigureMenuEntry(interp, menuPtr, mePtr, index, argc-3,
argv+3, TK_CONFIG_ARGV_ONLY | COMMAND_MASK << mePtr->type);
}
Tcl_Release((ClientData) mePtr);
} else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
&& (length >= 3)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " index string\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (index < 0) {
interp->result = "none";
} else {
sprintf(interp->result, "%d", index);
}
} else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
&& (length >= 3)) {
if (argc < 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " insert index type ?options?\"", (char *) NULL);
goto error;
}
if (MenuAddOrInsert(interp, menuPtr, argv[2],
argc-3, argv+3) != TCL_OK) {
goto error;
}
} else if ((c == 'i') && (strncmp(argv[1], "invoke", length) == 0)
&& (length >= 3)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " invoke index\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (index < 0) {
goto done;
}
mePtr = menuPtr->entries[index];
if (mePtr->state == tkDisabledUid) {
goto done;
}
Tcl_Preserve((ClientData) mePtr);
if (mePtr->type == CHECK_BUTTON_ENTRY) {
if (mePtr->flags & ENTRY_SELECTED) {
if (Tcl_SetVar(interp, mePtr->name, mePtr->offValue,
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
result = TCL_ERROR;
}
} else {
if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue,
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
result = TCL_ERROR;
}
}
} else if (mePtr->type == RADIO_BUTTON_ENTRY) {
if (Tcl_SetVar(interp, mePtr->name, mePtr->onValue,
TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG) == NULL) {
result = TCL_ERROR;
}
}
if ((result == TCL_OK) && (mePtr->command != NULL)) {
result = TkCopyAndGlobalEval(interp, mePtr->command);
}
if ((result == TCL_OK) && (mePtr->type == CASCADE_ENTRY)) {
result = PostSubmenu(menuPtr->interp, menuPtr, mePtr);
}
Tcl_Release((ClientData) mePtr);
} else if ((c == 'p') && (strncmp(argv[1], "post", length) == 0)
&& (length == 4)) {
int x, y, tmp, vRootX, vRootY;
int vRootWidth, vRootHeight;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " post x y\"", (char *) NULL);
goto error;
}
if ((Tcl_GetInt(interp, argv[2], &x) != TCL_OK)
|| (Tcl_GetInt(interp, argv[3], &y) != TCL_OK)) {
goto error;
}
ActivateMenuEntry(menuPtr, -1);
if (menuPtr->postCommand != NULL) {
result = TkCopyAndGlobalEval(menuPtr->interp,
menuPtr->postCommand);
if (result != TCL_OK) {
return result;
}
if (menuPtr->flags & RESIZE_PENDING) {
Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr);
ComputeMenuGeometry((ClientData) menuPtr);
}
}
Tk_GetVRootGeometry(Tk_Parent(menuPtr->tkwin), &vRootX, &vRootY,
&vRootWidth, &vRootHeight);
x += vRootX;
y += vRootY;
tmp = WidthOfScreen(Tk_Screen(menuPtr->tkwin))
- Tk_ReqWidth(menuPtr->tkwin);
if (x > tmp) {
x = tmp;
}
if (x < 0) {
x = 0;
}
tmp = HeightOfScreen(Tk_Screen(menuPtr->tkwin))
- Tk_ReqHeight(menuPtr->tkwin);
if (y > tmp) {
y = tmp;
}
if (y < 0) {
y = 0;
}
if ((x != Tk_X(menuPtr->tkwin)) || (y != Tk_Y(menuPtr->tkwin))) {
Tk_MoveToplevelWindow(menuPtr->tkwin, x, y);
}
if (!Tk_IsMapped(menuPtr->tkwin)) {
Tk_MapWindow(menuPtr->tkwin);
}
XRaiseWindow(menuPtr->display, Tk_WindowId(menuPtr->tkwin));
} else if ((c == 'p') && (strncmp(argv[1], "postcascade", length) == 0)
&& (length > 4)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " postcascade index\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if ((index < 0) || (menuPtr->entries[index]->type != CASCADE_ENTRY)) {
result = PostSubmenu(interp, menuPtr, (MenuEntry *) NULL);
} else {
result = PostSubmenu(interp, menuPtr, menuPtr->entries[index]);
}
} else if ((c == 't') && (strncmp(argv[1], "type", length) == 0)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " type index\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (index < 0) {
goto done;
}
mePtr = menuPtr->entries[index];
switch (mePtr->type) {
case COMMAND_ENTRY:
interp->result = "command";
break;
case SEPARATOR_ENTRY:
interp->result = "separator";
break;
case CHECK_BUTTON_ENTRY:
interp->result = "checkbutton";
break;
case RADIO_BUTTON_ENTRY:
interp->result = "radiobutton";
break;
case CASCADE_ENTRY:
interp->result = "cascade";
break;
case TEAROFF_ENTRY:
interp->result = "tearoff";
break;
}
} else if ((c == 'u') && (strncmp(argv[1], "unpost", length) == 0)) {
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " unpost\"", (char *) NULL);
goto error;
}
Tk_UnmapWindow(menuPtr->tkwin);
if (result == TCL_OK) {
result = PostSubmenu(interp, menuPtr, (MenuEntry *) NULL);
}
} else if ((c == 'y') && (strncmp(argv[1], "yposition", length) == 0)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " yposition index\"", (char *) NULL);
goto error;
}
if (GetMenuIndex(interp, menuPtr, argv[2], 0, &index) != TCL_OK) {
goto error;
}
if (index < 0) {
interp->result = "0";
} else {
sprintf(interp->result, "%d", menuPtr->entries[index]->y);
}
} else {
Tcl_AppendResult(interp, "bad option \"", argv[1],
"\": must be activate, add, cget, configure, delete, ",
"entrycget, entryconfigure, index, insert, invoke, ",
"post, postcascade, type, unpost, or yposition",
(char *) NULL);
goto error;
}
done:
Tcl_Release((ClientData) menuPtr);
return result;
error:
Tcl_Release((ClientData) menuPtr);
return TCL_ERROR;
}
static void
DestroyMenu(memPtr)
char *memPtr;
{
register Menu *menuPtr = (Menu *) memPtr;
int i;
for (i = 0; i < menuPtr->numEntries; i++) {
DestroyMenuEntry((char *) menuPtr->entries[i]);
}
if (menuPtr->entries != NULL) {
ckfree((char *) menuPtr->entries);
}
if (menuPtr->textGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->textGC);
}
if (menuPtr->gray != None) {
Tk_FreeBitmap(menuPtr->display, menuPtr->gray);
}
if (menuPtr->disabledGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->disabledGC);
}
if (menuPtr->activeGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->activeGC);
}
if (menuPtr->indicatorGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC);
}
Tk_FreeOptions(configSpecs, (char *) menuPtr, menuPtr->display, 0);
ckfree((char *) menuPtr);
}
static void
DestroyMenuEntry(memPtr)
char *memPtr;
{
register MenuEntry *mePtr = (MenuEntry *) memPtr;
Menu *menuPtr = mePtr->menuPtr;
if (menuPtr->postedCascade == mePtr) {
PostSubmenu(menuPtr->interp, menuPtr, (MenuEntry *) NULL);
}
if (mePtr->image != NULL) {
Tk_FreeImage(mePtr->image);
}
if (mePtr->selectImage != NULL) {
Tk_FreeImage(mePtr->image);
}
if (mePtr->textGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->textGC);
}
if (mePtr->activeGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->activeGC);
}
if (mePtr->disabledGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->disabledGC);
}
if (mePtr->indicatorGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->indicatorGC);
}
if (mePtr->name != NULL) {
Tcl_UntraceVar(menuPtr->interp, mePtr->name,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
MenuVarProc, (ClientData) mePtr);
}
Tk_FreeOptions(entryConfigSpecs, (char *) mePtr, menuPtr->display,
(COMMAND_MASK << mePtr->type));
ckfree((char *) mePtr);
}
static int
ConfigureMenu(interp, menuPtr, argc, argv, flags)
Tcl_Interp *interp;
register Menu *menuPtr;
int argc;
char **argv;
int flags;
{
XSetWindowAttributes atts;
XGCValues gcValues;
GC newGC;
unsigned long mask;
int i;
if (Tk_ConfigureWidget(interp, menuPtr->tkwin, configSpecs,
argc, argv, (char *) menuPtr, flags) != TCL_OK) {
return TCL_ERROR;
}
Tk_SetBackgroundFromBorder(menuPtr->tkwin, menuPtr->border);
gcValues.font = menuPtr->fontPtr->fid;
gcValues.foreground = menuPtr->fg->pixel;
gcValues.background = Tk_3DBorderColor(menuPtr->border)->pixel;
newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
&gcValues);
if (menuPtr->textGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->textGC);
}
menuPtr->textGC = newGC;
if (menuPtr->disabledFg != NULL) {
gcValues.foreground = menuPtr->disabledFg->pixel;
mask = GCForeground|GCBackground|GCFont;
} else {
gcValues.foreground = gcValues.background;
if (menuPtr->gray == None) {
menuPtr->gray = Tk_GetBitmap(interp, menuPtr->tkwin,
Tk_GetUid("gray50"));
if (menuPtr->gray == None) {
return TCL_ERROR;
}
}
gcValues.fill_style = FillStippled;
gcValues.stipple = menuPtr->gray;
mask = GCForeground|GCFillStyle|GCStipple;
}
newGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues);
if (menuPtr->disabledGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->disabledGC);
}
menuPtr->disabledGC = newGC;
gcValues.font = menuPtr->fontPtr->fid;
gcValues.foreground = menuPtr->activeFg->pixel;
gcValues.background = Tk_3DBorderColor(menuPtr->activeBorder)->pixel;
newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCBackground|GCFont,
&gcValues);
if (menuPtr->activeGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->activeGC);
}
menuPtr->activeGC = newGC;
gcValues.foreground = menuPtr->indicatorFg->pixel;
newGC = Tk_GetGC(menuPtr->tkwin, GCForeground|GCFont, &gcValues);
if (menuPtr->indicatorGC != None) {
Tk_FreeGC(menuPtr->display, menuPtr->indicatorGC);
}
menuPtr->indicatorGC = newGC;
if (menuPtr->transient) {
atts.override_redirect = True;
atts.save_under = True;
} else {
atts.override_redirect = False;
atts.save_under = False;
}
if ((atts.override_redirect
!= Tk_Attributes(menuPtr->tkwin)->override_redirect)
|| (atts.save_under
!= Tk_Attributes(menuPtr->tkwin)->save_under)) {
Tk_ChangeWindowAttributes(menuPtr->tkwin,
CWOverrideRedirect|CWSaveUnder, &atts);
}
#ifdef MAC_TCL
TkMacMakeMenuWindow(menuPtr->tkwin, menuPtr->transient);
#endif
for (i = 0; i < menuPtr->numEntries; i++) {
MenuEntry *mePtr;
mePtr = menuPtr->entries[i];
ConfigureMenuEntry(interp, menuPtr, mePtr, i, 0, (char **) NULL,
TK_CONFIG_ARGV_ONLY | COMMAND_MASK << mePtr->type);
}
if (menuPtr->tearOff) {
if ((menuPtr->numEntries == 0)
|| (menuPtr->entries[0]->type != TEAROFF_ENTRY)) {
MenuNewEntry(menuPtr, 0, TEAROFF_ENTRY);
}
} else if ((menuPtr->numEntries > 0)
&& (menuPtr->entries[0]->type == TEAROFF_ENTRY)) {
Tcl_EventuallyFree((ClientData) menuPtr->entries[0],
DestroyMenuEntry);
for (i = 1; i < menuPtr->numEntries; i++) {
menuPtr->entries[i-1] = menuPtr->entries[i];
}
menuPtr->numEntries--;
}
if (!(menuPtr->flags & RESIZE_PENDING)) {
menuPtr->flags |= RESIZE_PENDING;
Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
}
return TCL_OK;
}
static int
ConfigureMenuEntry(interp, menuPtr, mePtr, index, argc, argv, flags)
Tcl_Interp *interp;
Menu *menuPtr;
register MenuEntry *mePtr;
int index;
int argc;
char **argv;
int flags;
{
XGCValues gcValues;
GC newGC, newActiveGC, newDisabledGC;
unsigned long mask;
Tk_Image image;
if (menuPtr->postedCascade == mePtr) {
if (PostSubmenu(menuPtr->interp, menuPtr, (MenuEntry *) NULL)
!= TCL_OK) {
Tcl_BackgroundError(menuPtr->interp);
}
}
if ((mePtr->name != NULL) &&
((mePtr->type == CHECK_BUTTON_ENTRY)
|| (mePtr->type == RADIO_BUTTON_ENTRY))) {
Tcl_UntraceVar(menuPtr->interp, mePtr->name,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
MenuVarProc, (ClientData) mePtr);
}
if (Tk_ConfigureWidget(interp, menuPtr->tkwin, entryConfigSpecs,
argc, argv, (char *) mePtr,
flags | (COMMAND_MASK << mePtr->type)) != TCL_OK) {
return TCL_ERROR;
}
if (mePtr->label == NULL) {
mePtr->labelLength = 0;
} else {
mePtr->labelLength = strlen(mePtr->label);
}
if (mePtr->accel == NULL) {
mePtr->accelLength = 0;
} else {
mePtr->accelLength = strlen(mePtr->accel);
}
if (mePtr->state == tkActiveUid) {
if (index != menuPtr->active) {
ActivateMenuEntry(menuPtr, index);
}
} else {
if (index == menuPtr->active) {
ActivateMenuEntry(menuPtr, -1);
}
if ((mePtr->state != tkNormalUid) && (mePtr->state != tkDisabledUid)) {
Tcl_AppendResult(interp, "bad state value \"", mePtr->state,
"\": must be normal, active, or disabled", (char *) NULL);
mePtr->state = tkNormalUid;
return TCL_ERROR;
}
}
if ((mePtr->fontPtr != NULL) || (mePtr->border != NULL)
|| (mePtr->fg != NULL) || (mePtr->activeBorder != NULL)
|| (mePtr->activeFg != NULL)) {
gcValues.foreground = (mePtr->fg != NULL) ? mePtr->fg->pixel
: menuPtr->fg->pixel;
gcValues.background = Tk_3DBorderColor(
(mePtr->border != NULL) ? mePtr->border : menuPtr->border)
->pixel;
gcValues.font = (mePtr->fontPtr != NULL) ? mePtr->fontPtr->fid
: menuPtr->fontPtr->fid;
gcValues.graphics_exposures = False;
newGC = Tk_GetGC(menuPtr->tkwin,
GCForeground|GCBackground|GCFont|GCGraphicsExposures,
&gcValues);
if (menuPtr->disabledFg != NULL) {
gcValues.foreground = menuPtr->disabledFg->pixel;
mask = GCForeground|GCBackground|GCFont|GCGraphicsExposures;
} else {
gcValues.foreground = gcValues.background;
gcValues.fill_style = FillStippled;
gcValues.stipple = menuPtr->gray;
mask = GCForeground|GCFillStyle|GCStipple;
}
newDisabledGC = Tk_GetGC(menuPtr->tkwin, mask, &gcValues);
gcValues.foreground = (mePtr->activeFg != NULL)
? mePtr->activeFg->pixel : menuPtr->activeFg->pixel;
gcValues.background = Tk_3DBorderColor(
(mePtr->activeBorder != NULL) ? mePtr->activeBorder
: menuPtr->activeBorder)->pixel;
newActiveGC = Tk_GetGC(menuPtr->tkwin,
GCForeground|GCBackground|GCFont|GCGraphicsExposures,
&gcValues);
} else {
newGC = None;
newActiveGC = None;
newDisabledGC = None;
}
if (mePtr->textGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->textGC);
}
mePtr->textGC = newGC;
if (mePtr->activeGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->activeGC);
}
mePtr->activeGC = newActiveGC;
if (mePtr->disabledGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->disabledGC);
}
mePtr->disabledGC = newDisabledGC;
if (mePtr->indicatorFg != NULL) {
gcValues.foreground = mePtr->indicatorFg->pixel;
newGC = Tk_GetGC(menuPtr->tkwin, GCForeground, &gcValues);
} else {
newGC = None;
}
if (mePtr->indicatorGC != None) {
Tk_FreeGC(menuPtr->display, mePtr->indicatorGC);
}
mePtr->indicatorGC = newGC;
if ((mePtr->type == CHECK_BUTTON_ENTRY)
|| (mePtr->type == RADIO_BUTTON_ENTRY)) {
char *value;
if (mePtr->name == NULL) {
mePtr->name = (char *) ckalloc((unsigned) (mePtr->labelLength + 1));
strcpy(mePtr->name, (mePtr->label == NULL) ? "" : mePtr->label);
}
if (mePtr->onValue == NULL) {
mePtr->onValue = (char *) ckalloc((unsigned)
(mePtr->labelLength + 1));
strcpy(mePtr->onValue, (mePtr->label == NULL) ? "" : mePtr->label);
}
value = Tcl_GetVar(interp, mePtr->name, TCL_GLOBAL_ONLY);
mePtr->flags &= ~ENTRY_SELECTED;
if (value != NULL) {
if (strcmp(value, mePtr->onValue) == 0) {
mePtr->flags |= ENTRY_SELECTED;
}
} else {
Tcl_SetVar(interp, mePtr->name,
(mePtr->type == CHECK_BUTTON_ENTRY) ? mePtr->offValue : "",
TCL_GLOBAL_ONLY);
}
Tcl_TraceVar(interp, mePtr->name,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
MenuVarProc, (ClientData) mePtr);
}
if (mePtr->imageString != NULL) {
image = Tk_GetImage(interp, menuPtr->tkwin, mePtr->imageString,
MenuImageProc, (ClientData) mePtr);
if (image == NULL) {
return TCL_ERROR;
}
} else {
image = NULL;
}
if (mePtr->image != NULL) {
Tk_FreeImage(mePtr->image);
}
mePtr->image = image;
if (mePtr->selectImageString != NULL) {
image = Tk_GetImage(interp, menuPtr->tkwin, mePtr->selectImageString,
MenuSelectImageProc, (ClientData) mePtr);
if (image == NULL) {
return TCL_ERROR;
}
} else {
image = NULL;
}
if (mePtr->selectImage != NULL) {
Tk_FreeImage(mePtr->selectImage);
}
mePtr->selectImage = image;
if (!(menuPtr->flags & RESIZE_PENDING)) {
menuPtr->flags |= RESIZE_PENDING;
Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
}
return TCL_OK;
}
static void
ComputeMenuGeometry(clientData)
ClientData clientData;
{
Menu *menuPtr = (Menu *) clientData;
register MenuEntry *mePtr;
XFontStruct *fontPtr;
int maxLabelWidth, maxIndicatorWidth, maxAccelWidth;
int width, height, indicatorSpace;
int i, y;
int imageWidth, imageHeight;
if (menuPtr->tkwin == NULL) {
return;
}
maxLabelWidth = maxIndicatorWidth = maxAccelWidth = 0;
y = menuPtr->borderWidth;
for (i = 0; i < menuPtr->numEntries; i++) {
mePtr = menuPtr->entries[i];
indicatorSpace = 0;
fontPtr = mePtr->fontPtr;
if (fontPtr == NULL) {
fontPtr = menuPtr->fontPtr;
}
if (mePtr->image != NULL) {
Tk_SizeOfImage(mePtr->image, &imageWidth, &imageHeight);
imageOrBitmap:
mePtr->height = imageHeight;
width = imageWidth;
if (mePtr->indicatorOn) {
if (mePtr->type == CHECK_BUTTON_ENTRY) {
indicatorSpace = (14*mePtr->height)/10;
mePtr->indicatorDiameter = (65*mePtr->height)/100;
} else if (mePtr->type == RADIO_BUTTON_ENTRY) {
indicatorSpace = (14*mePtr->height)/10;
mePtr->indicatorDiameter = (75*mePtr->height)/100;
}
}
} else if (mePtr->bitmap != None) {
Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap,
&imageWidth, &imageHeight);
goto imageOrBitmap;
} else {
mePtr->height = fontPtr->ascent + fontPtr->descent;
if (mePtr->label != NULL) {
(void) TkMeasureChars(fontPtr, mePtr->label,
mePtr->labelLength, 0, (int) 100000, 0,
TK_NEWLINES_NOT_SPECIAL, &width);
} else {
width = 0;
}
if (mePtr->indicatorOn) {
if (mePtr->type == CHECK_BUTTON_ENTRY) {
indicatorSpace = mePtr->height;
mePtr->indicatorDiameter = (80*mePtr->height)/100;
} else if (mePtr->type == RADIO_BUTTON_ENTRY) {
indicatorSpace = mePtr->height;
mePtr->indicatorDiameter = mePtr->height;
}
}
}
mePtr->height += 2*menuPtr->activeBorderWidth + 2;
if (width > maxLabelWidth) {
maxLabelWidth = width;
}
if (mePtr->type == CASCADE_ENTRY) {
width = 2*CASCADE_ARROW_WIDTH;
} else if (mePtr->accel != NULL) {
(void) TkMeasureChars(fontPtr, mePtr->accel, mePtr->accelLength,
0, (int) 100000, 0, TK_NEWLINES_NOT_SPECIAL, &width);
} else {
width = 0;
}
if (width > maxAccelWidth) {
maxAccelWidth = width;
}
if (mePtr->type == SEPARATOR_ENTRY) {
mePtr->height = 8;
}
if (mePtr->type == TEAROFF_ENTRY) {
mePtr->height = 12;
}
if (indicatorSpace > maxIndicatorWidth) {
maxIndicatorWidth = indicatorSpace;
}
mePtr->y = y;
y += mePtr->height;
}
menuPtr->indicatorSpace = maxIndicatorWidth + MARGIN_WIDTH;
if (maxIndicatorWidth != 0) {
menuPtr->indicatorSpace += MARGIN_WIDTH;
}
menuPtr->labelWidth = maxLabelWidth + MARGIN_WIDTH;
width = menuPtr->indicatorSpace + menuPtr->labelWidth + maxAccelWidth
+ 2*menuPtr->borderWidth + 2*menuPtr->activeBorderWidth;
if (maxAccelWidth != 0) {
width += MARGIN_WIDTH;
}
height = y + menuPtr->borderWidth;
if (width <= 0) {
width = 1;
}
if (height <= 0) {
height = 1;
}
if ((width != Tk_ReqWidth(menuPtr->tkwin)) ||
(height != Tk_ReqHeight(menuPtr->tkwin))) {
Tk_GeometryRequest(menuPtr->tkwin, width, height);
} else {
EventuallyRedrawMenu(menuPtr, (MenuEntry *) NULL);
}
menuPtr->flags &= ~RESIZE_PENDING;
}
static void
DisplayMenu(clientData)
ClientData clientData;
{
register Menu *menuPtr = (Menu *) clientData;
register MenuEntry *mePtr;
register Tk_Window tkwin = menuPtr->tkwin;
Tk_3DBorder bgBorder, activeBorder;
XFontStruct *fontPtr;
int index, baseline, strictMotif, leftEdge, y, height;
GC gc;
XPoint points[3];
menuPtr->flags &= ~REDRAW_PENDING;
if ((menuPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
return;
}
strictMotif = Tk_StrictMotif(menuPtr->tkwin);
leftEdge = menuPtr->borderWidth + menuPtr->indicatorSpace
+ menuPtr->activeBorderWidth;
for (index = 0; index < menuPtr->numEntries; index++) {
mePtr = menuPtr->entries[index];
if (!(mePtr->flags & ENTRY_NEEDS_REDISPLAY)) {
continue;
}
mePtr->flags &= ~ENTRY_NEEDS_REDISPLAY;
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->state == tkActiveUid) {
bgBorder = activeBorder;
Tk_Fill3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin),
bgBorder, menuPtr->borderWidth, mePtr->y,
Tk_Width(tkwin) - 2*menuPtr->borderWidth, mePtr->height,
menuPtr->activeBorderWidth, TK_RELIEF_RAISED);
} else {
Tk_Fill3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin),
bgBorder, menuPtr->borderWidth, mePtr->y,
Tk_Width(tkwin) - 2*menuPtr->borderWidth, mePtr->height,
0, TK_RELIEF_FLAT);
}
if ((mePtr->state == tkActiveUid) && !strictMotif) {
gc = mePtr->activeGC;
if (gc == NULL) {
gc = menuPtr->activeGC;
}
} else {
if ((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;
}
}
}
fontPtr = mePtr->fontPtr;
if (fontPtr == NULL) {
fontPtr = menuPtr->fontPtr;
}
baseline = mePtr->y + (mePtr->height + fontPtr->ascent
- fontPtr->descent)/2;
if (mePtr->image != NULL) {
int width, height;
Tk_SizeOfImage(mePtr->image, &width, &height);
if ((mePtr->selectImage != NULL)
&& (mePtr->flags & ENTRY_SELECTED)) {
Tk_RedrawImage(mePtr->selectImage, 0, 0, width, height,
Tk_WindowId(tkwin), leftEdge,
(int) (mePtr->y + (mePtr->height - height)/2));
} else {
Tk_RedrawImage(mePtr->image, 0, 0, width, height,
Tk_WindowId(tkwin), leftEdge,
(int) (mePtr->y + (mePtr->height - height)/2));
}
} else if (mePtr->bitmap != None) {
int width, height;
Tk_SizeOfBitmap(menuPtr->display, mePtr->bitmap, &width, &height);
XCopyPlane(menuPtr->display, mePtr->bitmap, Tk_WindowId(tkwin),
gc, 0, 0, (unsigned) width, (unsigned) height, leftEdge,
(int) (mePtr->y + (mePtr->height - height)/2), 1);
} else {
baseline = mePtr->y + (mePtr->height + fontPtr->ascent
- fontPtr->descent)/2;
if (mePtr->label != NULL) {
TkDisplayChars(menuPtr->display, Tk_WindowId(tkwin), gc,
fontPtr, mePtr->label, mePtr->labelLength,
leftEdge, baseline, leftEdge,
TK_NEWLINES_NOT_SPECIAL);
if (mePtr->underline >= 0) {
TkUnderlineChars(menuPtr->display, Tk_WindowId(tkwin), gc,
fontPtr, mePtr->label, leftEdge, baseline,
leftEdge, TK_NEWLINES_NOT_SPECIAL,
mePtr->underline, mePtr->underline);
}
}
}
if (mePtr->type == CASCADE_ENTRY) {
points[0].x = Tk_Width(tkwin) - menuPtr->borderWidth
- menuPtr->activeBorderWidth - MARGIN_WIDTH
- CASCADE_ARROW_WIDTH;
points[0].y = mePtr->y + (mePtr->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, Tk_WindowId(tkwin), activeBorder,
points, 3, DECORATION_BORDER_WIDTH,
(menuPtr->postedCascade == mePtr) ? TK_RELIEF_SUNKEN
: TK_RELIEF_RAISED);
} else if (mePtr->accel != NULL) {
TkDisplayChars(menuPtr->display, Tk_WindowId(tkwin), gc,
fontPtr, mePtr->accel, mePtr->accelLength,
leftEdge + menuPtr->labelWidth, baseline,
leftEdge + menuPtr->labelWidth, TK_NEWLINES_NOT_SPECIAL);
}
gc = mePtr->indicatorGC;
if (gc == None) {
gc = menuPtr->indicatorGC;
}
if ((mePtr->type == CHECK_BUTTON_ENTRY) && mePtr->indicatorOn) {
int dim, x, y;
dim = mePtr->indicatorDiameter;
x = menuPtr->borderWidth + menuPtr->activeBorderWidth
+ (menuPtr->indicatorSpace - dim)/2;
y = mePtr->y + (mePtr->height - dim)/2;
Tk_Fill3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin),
menuPtr->border, x, y, dim, dim,
DECORATION_BORDER_WIDTH, TK_RELIEF_SUNKEN);
x += DECORATION_BORDER_WIDTH;
y += DECORATION_BORDER_WIDTH;
dim -= 2*DECORATION_BORDER_WIDTH;
if ((dim > 0) && (mePtr->flags & ENTRY_SELECTED)) {
XFillRectangle(menuPtr->display, Tk_WindowId(tkwin), gc,
x, y, (unsigned int) dim, (unsigned int) dim);
}
}
if ((mePtr->type == RADIO_BUTTON_ENTRY) && mePtr->indicatorOn) {
XPoint points[4];
int radius;
radius = mePtr->indicatorDiameter/2;
points[0].x = menuPtr->borderWidth + menuPtr->activeBorderWidth
+ (menuPtr->indicatorSpace - mePtr->indicatorDiameter)/2;
points[0].y = mePtr->y + (mePtr->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->flags & ENTRY_SELECTED) {
XFillPolygon(menuPtr->display, Tk_WindowId(tkwin), gc,
points, 4, Convex, CoordModeOrigin);
} else {
Tk_Fill3DPolygon(menuPtr->tkwin, Tk_WindowId(tkwin),
menuPtr->border, points, 4, DECORATION_BORDER_WIDTH,
TK_RELIEF_FLAT);
}
Tk_Draw3DPolygon(menuPtr->tkwin, Tk_WindowId(tkwin),
menuPtr->border, points, 4, DECORATION_BORDER_WIDTH,
TK_RELIEF_SUNKEN);
}
if (mePtr->type == SEPARATOR_ENTRY) {
XPoint points[2];
points[0].x = 0;
points[0].y = mePtr->y + mePtr->height/2;
points[1].x = Tk_Width(tkwin) - 1;
points[1].y = points[0].y;
Tk_Draw3DPolygon(menuPtr->tkwin, Tk_WindowId(tkwin),
menuPtr->border, points, 2, 1, TK_RELIEF_RAISED);
}
if (mePtr->type == TEAROFF_ENTRY) {
XPoint points[2];
int width, maxX;
points[0].x = 0;
points[0].y = mePtr->y + mePtr->height/2;
points[1].y = points[0].y;
width = 6;
maxX = Tk_Width(tkwin) - 1;
while (points[0].x < maxX) {
points[1].x = points[0].x + width;
if (points[1].x > maxX) {
points[1].x = maxX;
}
Tk_Draw3DPolygon(menuPtr->tkwin, Tk_WindowId(tkwin),
menuPtr->border, points, 2, 1, TK_RELIEF_RAISED);
points[0].x += 2*width;
}
}
if ((mePtr->state == tkDisabledUid) && (menuPtr->disabledFg == NULL)) {
XFillRectangle(menuPtr->display, Tk_WindowId(tkwin),
menuPtr->disabledGC, menuPtr->borderWidth,
mePtr->y,
(unsigned) (Tk_Width(tkwin) - 2*menuPtr->borderWidth),
(unsigned) mePtr->height);
}
}
if (menuPtr->numEntries >= 1) {
mePtr = menuPtr->entries[menuPtr->numEntries-1];
y = mePtr->y + mePtr->height;
} else {
y = menuPtr->borderWidth;
}
height = Tk_Height(tkwin) - menuPtr->borderWidth - y;
if (height > 0) {
Tk_Fill3DRectangle(tkwin, Tk_WindowId(tkwin),
menuPtr->border, menuPtr->borderWidth, y,
Tk_Width(tkwin) - 2*menuPtr->borderWidth,
height, 0, TK_RELIEF_FLAT);
}
Tk_Draw3DRectangle(menuPtr->tkwin, Tk_WindowId(tkwin),
menuPtr->border, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin),
menuPtr->borderWidth, menuPtr->relief);
}
static int
GetMenuIndex(interp, menuPtr, string, lastOK, indexPtr)
Tcl_Interp *interp;
Menu *menuPtr;
char *string;
int lastOK;
int *indexPtr;
{
int i, y;
if ((string[0] == 'a') && (strcmp(string, "active") == 0)) {
*indexPtr = menuPtr->active;
return TCL_OK;
}
if (((string[0] == 'l') && (strcmp(string, "last") == 0))
|| ((string[0] == 'e') && (strcmp(string, "end") == 0))) {
*indexPtr = menuPtr->numEntries - ((lastOK) ? 0 : 1);
return TCL_OK;
}
if ((string[0] == 'n') && (strcmp(string, "none") == 0)) {
*indexPtr = -1;
return TCL_OK;
}
if (string[0] == '@') {
if (Tcl_GetInt(interp, string+1, &y) == TCL_OK) {
for (i = 0; i < menuPtr->numEntries; i++) {
MenuEntry *mePtr = menuPtr->entries[i];
if (y < (mePtr->y + mePtr->height)) {
break;
}
}
if (i >= menuPtr->numEntries) {
i = menuPtr->numEntries-1;
}
*indexPtr = i;
return TCL_OK;
} else {
Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
}
}
if (isdigit(UCHAR(string[0]))) {
if (Tcl_GetInt(interp, string, &i) == TCL_OK) {
if (i >= menuPtr->numEntries) {
if (lastOK) {
i = menuPtr->numEntries;
} else {
i = menuPtr->numEntries-1;
}
} else if (i < 0) {
i = -1;
}
*indexPtr = i;
return TCL_OK;
}
Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
}
for (i = 0; i < menuPtr->numEntries; i++) {
char *label;
label = menuPtr->entries[i]->label;
if ((label != NULL)
&& (Tcl_StringMatch(menuPtr->entries[i]->label, string))) {
*indexPtr = i;
return TCL_OK;
}
}
Tcl_AppendResult(interp, "bad menu entry index \"",
string, "\"", (char *) NULL);
return TCL_ERROR;
}
static void
MenuEventProc(clientData, eventPtr)
ClientData clientData;
XEvent *eventPtr;
{
Menu *menuPtr = (Menu *) clientData;
if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
EventuallyRedrawMenu(menuPtr, (MenuEntry *) NULL);
} else if (eventPtr->type == ConfigureNotify) {
EventuallyRedrawMenu(menuPtr, (MenuEntry *) NULL);
} else if (eventPtr->type == DestroyNotify) {
if (menuPtr->tkwin != NULL) {
menuPtr->tkwin = NULL;
Tcl_DeleteCommand(menuPtr->interp,
Tcl_GetCommandName(menuPtr->interp, menuPtr->widgetCmd));
}
if (menuPtr->flags & REDRAW_PENDING) {
Tcl_CancelIdleCall(DisplayMenu, (ClientData) menuPtr);
}
if (menuPtr->flags & RESIZE_PENDING) {
Tcl_CancelIdleCall(ComputeMenuGeometry, (ClientData) menuPtr);
}
Tcl_EventuallyFree((ClientData) menuPtr, DestroyMenu);
}
}
static void
MenuCmdDeletedProc(clientData)
ClientData clientData;
{
Menu *menuPtr = (Menu *) clientData;
Tk_Window tkwin = menuPtr->tkwin;
if (tkwin != NULL) {
menuPtr->tkwin = NULL;
Tk_DestroyWindow(tkwin);
}
}
static MenuEntry *
MenuNewEntry(menuPtr, index, type)
Menu *menuPtr;
int index;
int type;
{
MenuEntry *mePtr;
MenuEntry **newEntries;
int i;
newEntries = (MenuEntry **) ckalloc((unsigned)
((menuPtr->numEntries+1)*sizeof(MenuEntry *)));
for (i = 0; i < index; i++) {
newEntries[i] = menuPtr->entries[i];
}
for ( ; i < menuPtr->numEntries; i++) {
newEntries[i+1] = menuPtr->entries[i];
}
if (menuPtr->numEntries != 0) {
ckfree((char *) menuPtr->entries);
}
menuPtr->entries = newEntries;
menuPtr->numEntries++;
menuPtr->entries[index] = mePtr = (MenuEntry *) ckalloc(sizeof(MenuEntry));
mePtr->type = type;
mePtr->menuPtr = menuPtr;
mePtr->label = NULL;
mePtr->labelLength = 0;
mePtr->underline = -1;
mePtr->bitmap = None;
mePtr->imageString = NULL;
mePtr->image = NULL;
mePtr->selectImageString = NULL;
mePtr->selectImage = NULL;
mePtr->accel = NULL;
mePtr->accelLength = 0;
mePtr->state = tkNormalUid;
mePtr->height = 0;
mePtr->y = 0;
mePtr->indicatorDiameter = 0;
mePtr->border = NULL;
mePtr->fg = NULL;
mePtr->activeBorder = NULL;
mePtr->activeFg = NULL;
mePtr->fontPtr = NULL;
mePtr->textGC = None;
mePtr->activeGC = None;
mePtr->disabledGC = None;
mePtr->indicatorOn = 1;
mePtr->indicatorFg = NULL;
mePtr->indicatorGC = None;
mePtr->command = NULL;
mePtr->name = NULL;
mePtr->onValue = NULL;
mePtr->offValue = NULL;
mePtr->flags = 0;
return mePtr;
}
static int
MenuAddOrInsert(interp, menuPtr, indexString, argc, argv)
Tcl_Interp *interp;
Menu *menuPtr;
char *indexString;
int argc;
char **argv;
{
int c, type, i, index;
size_t length;
MenuEntry *mePtr;
if (indexString != NULL) {
if (GetMenuIndex(interp, menuPtr, indexString, 1, &index) != TCL_OK) {
return TCL_ERROR;
}
} else {
index = menuPtr->numEntries;
}
if (index < 0) {
Tcl_AppendResult(interp, "bad index \"", indexString, "\"",
(char *) NULL);
return TCL_ERROR;
}
if (menuPtr->tearOff && (index == 0)) {
index = 1;
}
c = argv[0][0];
length = strlen(argv[0]);
if ((c == 'c') && (strncmp(argv[0], "cascade", length) == 0)
&& (length >= 2)) {
type = CASCADE_ENTRY;
} else if ((c == 'c') && (strncmp(argv[0], "checkbutton", length) == 0)
&& (length >= 2)) {
type = CHECK_BUTTON_ENTRY;
} else if ((c == 'c') && (strncmp(argv[0], "command", length) == 0)
&& (length >= 2)) {
type = COMMAND_ENTRY;
} else if ((c == 'r')
&& (strncmp(argv[0], "radiobutton", length) == 0)) {
type = RADIO_BUTTON_ENTRY;
} else if ((c == 's')
&& (strncmp(argv[0], "separator", length) == 0)) {
type = SEPARATOR_ENTRY;
} else {
Tcl_AppendResult(interp, "bad menu entry type \"",
argv[0], "\": must be cascade, checkbutton, ",
"command, radiobutton, or separator", (char *) NULL);
return TCL_ERROR;
}
mePtr = MenuNewEntry(menuPtr, index, type);
if (ConfigureMenuEntry(interp, menuPtr, mePtr, index,
argc-1, argv+1, 0) != TCL_OK) {
DestroyMenuEntry((ClientData) mePtr);
for (i = index+1; i < menuPtr->numEntries; i++) {
menuPtr->entries[i-1] = menuPtr->entries[i];
}
menuPtr->numEntries--;
return TCL_ERROR;
}
return TCL_OK;
}
static char *
MenuVarProc(clientData, interp, name1, name2, flags)
ClientData clientData;
Tcl_Interp *interp;
char *name1;
char *name2;
int flags;
{
MenuEntry *mePtr = (MenuEntry *) clientData;
Menu *menuPtr;
char *value;
menuPtr = mePtr->menuPtr;
if (flags & TCL_TRACE_UNSETS) {
mePtr->flags &= ~ENTRY_SELECTED;
if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
Tcl_TraceVar(interp, mePtr->name,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
MenuVarProc, clientData);
}
EventuallyRedrawMenu(menuPtr, (MenuEntry *) NULL);
return (char *) NULL;
}
value = Tcl_GetVar(interp, mePtr->name, TCL_GLOBAL_ONLY);
if (value == NULL) {
value = "";
}
if (strcmp(value, mePtr->onValue) == 0) {
if (mePtr->flags & ENTRY_SELECTED) {
return (char *) NULL;
}
mePtr->flags |= ENTRY_SELECTED;
} else if (mePtr->flags & ENTRY_SELECTED) {
mePtr->flags &= ~ENTRY_SELECTED;
} else {
return (char *) NULL;
}
EventuallyRedrawMenu(menuPtr, (MenuEntry *) NULL);
return (char *) NULL;
}
static void
EventuallyRedrawMenu(menuPtr, mePtr)
register Menu *menuPtr;
register MenuEntry *mePtr;
{
int i;
if (menuPtr->tkwin == NULL) {
return;
}
if (mePtr != NULL) {
mePtr->flags |= ENTRY_NEEDS_REDISPLAY;
} else {
for (i = 0; i < menuPtr->numEntries; i++) {
menuPtr->entries[i]->flags |= ENTRY_NEEDS_REDISPLAY;
}
}
if ((menuPtr->tkwin == NULL) || !Tk_IsMapped(menuPtr->tkwin)
|| (menuPtr->flags & REDRAW_PENDING)) {
return;
}
Tcl_DoWhenIdle(DisplayMenu, (ClientData) menuPtr);
menuPtr->flags |= REDRAW_PENDING;
}
static int
PostSubmenu(interp, menuPtr, mePtr)
Tcl_Interp *interp;
register Menu *menuPtr;
register MenuEntry *mePtr;
{
char string[30];
int result, x, y;
Tk_Window tkwin;
if (mePtr == menuPtr->postedCascade) {
return TCL_OK;
}
if (menuPtr->postedCascade != NULL) {
EventuallyRedrawMenu(menuPtr, (MenuEntry *) NULL);
result = Tcl_VarEval(interp, menuPtr->postedCascade->name,
" unpost", (char *) NULL);
menuPtr->postedCascade = NULL;
if (result != TCL_OK) {
return result;
}
}
if ((mePtr != NULL) && (mePtr->name != NULL)
&& Tk_IsMapped(menuPtr->tkwin)) {
tkwin = Tk_NameToWindow(interp, mePtr->name, menuPtr->tkwin);
if (tkwin == NULL) {
return TCL_ERROR;
}
if (Tk_Parent(tkwin) != menuPtr->tkwin) {
Tcl_AppendResult(interp, "cascaded sub-menu ",
Tk_PathName(tkwin), " must be a child of ",
Tk_PathName(menuPtr->tkwin), (char *) NULL);
return TCL_ERROR;
}
Tk_GetRootCoords(menuPtr->tkwin, &x, &y);
x += Tk_Width(menuPtr->tkwin) - menuPtr->borderWidth
- menuPtr->activeBorderWidth - 2;
y += mePtr->y + menuPtr->activeBorderWidth + 2;
sprintf(string, "%d %d", x, y);
result = Tcl_VarEval(interp, mePtr->name, " post ", string,
(char *) NULL);
if (result != TCL_OK) {
return result;
}
menuPtr->postedCascade = mePtr;
}
return TCL_OK;
}
static int
ActivateMenuEntry(menuPtr, index)
register Menu *menuPtr;
int index;
{
register MenuEntry *mePtr;
int result = TCL_OK;
if (menuPtr->active >= 0) {
mePtr = menuPtr->entries[menuPtr->active];
if (mePtr->state == tkActiveUid) {
mePtr->state = tkNormalUid;
}
EventuallyRedrawMenu(menuPtr, menuPtr->entries[menuPtr->active]);
}
menuPtr->active = index;
if (index >= 0) {
mePtr = menuPtr->entries[index];
mePtr->state = tkActiveUid;
EventuallyRedrawMenu(menuPtr, mePtr);
}
return result;
}
static void
MenuImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
ClientData clientData;
int x, y;
int width, height;
int imgWidth, imgHeight;
{
register Menu *menuPtr = ((MenuEntry *) clientData)->menuPtr;
if ((menuPtr->tkwin != NULL) && !(menuPtr->flags & RESIZE_PENDING)) {
menuPtr->flags |= RESIZE_PENDING;
Tcl_DoWhenIdle(ComputeMenuGeometry, (ClientData) menuPtr);
}
}
static void
MenuSelectImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
ClientData clientData;
int x, y;
int width, height;
int imgWidth, imgHeight;
{
register MenuEntry *mePtr = (MenuEntry *) clientData;
if ((mePtr->flags & ENTRY_SELECTED)
&& !(mePtr->menuPtr->flags & REDRAW_PENDING)) {
mePtr->menuPtr->flags |= REDRAW_PENDING;
Tcl_DoWhenIdle(DisplayMenu, (ClientData) mePtr->menuPtr);
}
}