4 * This module implements button-like widgets that are used
5 * to invoke pull-down menus.
7 * Copyright (c) 1990-1994 The Regents of the University of California.
8 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
9 * Copyright (c) 1995 Christian Werner
11 * See the file "license.terms" for information on usage and redistribution
12 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
20 * A data structure of the following type is kept for each
21 * widget managed by this file:
25 CkWindow *winPtr; /* Window that embodies the widget. NULL
26 * means that the window has been destroyed
27 * but the data structures haven't yet been
29 Tcl_Interp *interp; /* Interpreter associated with menubutton. */
30 Tcl_Command widgetCmd; /* Token for menubutton's widget command. */
31 char *menuName; /* Name of menu associated with widget.
35 * Information about what's displayed in the menu button:
38 char *text; /* Text to display in button (malloc'ed)
40 int numChars; /* # of characters in text. */
41 char *textVarName; /* Name of variable (malloc'ed) or NULL.
42 * If non-NULL, button displays the contents
43 * of this variable. */
46 * Information used when displaying widget:
49 Ck_Uid state; /* State of button for display purposes:
50 * normal, active, or disabled. */
51 int normalFg; /* Foreground color in normal mode. */
52 int normalBg; /* Background color in normal mode. */
53 int normalAttr; /* Attributes in normal mode. */
54 int activeFg; /* Foreground color in active mode. */
55 int activeBg; /* Ditto, background color. */
56 int activeAttr; /* Attributes in active mode. */
57 int disabledBg; /* Background color when disabled. */
58 int disabledFg; /* Foreground color when disabled. */
59 int disabledAttr; /* Attributes when disabled. */
60 int underlineFg; /* Foreground color for underlined char. */
61 int underlineAttr; /* Attribute for underlined character. */
62 int indicatorFg; /* Foreground color for indicator. */
63 int underline; /* Index of underlined character, < 0 if
65 int width, height; /* If > 0, these specify dimensions to request
66 * for window, in characters for text and in
67 * pixels for bitmaps. In this case the actual
68 * size of the text string or bitmap is
69 * ignored in computing desired window size. */
70 Ck_Anchor anchor; /* Where text/bitmap should be displayed
71 * inside window region. */
72 int indicatorOn; /* Non-zero means display indicator; 0 means
76 * Miscellaneous information:
79 char *takeFocus; /* Value of -takefocus option; not used in
80 * the C code, but used by keyboard traversal
81 * scripts. Malloc'ed, but may be NULL. */
82 int flags; /* Various flags; see below for
87 * Flag bits for buttons:
89 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler
90 * has already been queued to redraw
92 * POSTED: Non-zero means that the menu associated
93 * with this button has been posted (typically
94 * because of an active button press).
95 * GOT_FOCUS: Non-zero means this button currently
96 * has the input focus.
99 #define REDRAW_PENDING 1
104 * Information used for parsing configuration specs:
107 static Ck_ConfigSpec configSpecs[] = {
108 {CK_CONFIG_ATTR, "-activeattributes", "activeAttributes",
109 "ActiveAttributes", DEF_MENUBUTTON_ACTIVE_ATTR_COLOR,
110 Ck_Offset(MenuButton, activeAttr), CK_CONFIG_COLOR_ONLY},
111 {CK_CONFIG_ATTR, "-activeattributes", "activeAttributes",
112 "ActiveAttributes", DEF_MENUBUTTON_ACTIVE_ATTR_MONO,
113 Ck_Offset(MenuButton, activeAttr), CK_CONFIG_MONO_ONLY},
114 {CK_CONFIG_ATTR, "-attributes", "attributes", "Attributes",
115 DEF_MENUBUTTON_ATTR, Ck_Offset(MenuButton, normalAttr), 0},
116 {CK_CONFIG_COLOR, "-activebackground", "activeBackground", "Foreground",
117 DEF_MENUBUTTON_ACTIVE_BG_COLOR, Ck_Offset(MenuButton, activeBg),
118 CK_CONFIG_COLOR_ONLY},
119 {CK_CONFIG_COLOR, "-activebackground", "activeBackground", "Foreground",
120 DEF_MENUBUTTON_ACTIVE_BG_MONO, Ck_Offset(MenuButton, activeBg),
121 CK_CONFIG_MONO_ONLY},
122 {CK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
123 DEF_MENUBUTTON_ACTIVE_FG_COLOR, Ck_Offset(MenuButton, activeFg),
124 CK_CONFIG_COLOR_ONLY},
125 {CK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
126 DEF_MENUBUTTON_ACTIVE_FG_MONO, Ck_Offset(MenuButton, activeFg),
127 CK_CONFIG_MONO_ONLY},
128 {CK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
129 DEF_MENUBUTTON_ANCHOR, Ck_Offset(MenuButton, anchor), 0},
130 {CK_CONFIG_COLOR, "-background", "background", "Background",
131 DEF_MENUBUTTON_BG_COLOR, Ck_Offset(MenuButton, normalBg),
132 CK_CONFIG_COLOR_ONLY},
133 {CK_CONFIG_COLOR, "-background", "background", "Background",
134 DEF_MENUBUTTON_BG_MONO, Ck_Offset(MenuButton, normalBg),
135 CK_CONFIG_MONO_ONLY},
136 {CK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
137 (char *) NULL, 0, 0},
138 {CK_CONFIG_ATTR, "-disabledattributes", "disabledAttributes",
139 "DisabledAttributes", DEF_MENUBUTTON_DISABLED_ATTR,
140 Ck_Offset(MenuButton, disabledAttr), 0},
141 {CK_CONFIG_COLOR, "-disabledbackground", "disabledBackground",
142 "DisabledBackground", DEF_MENUBUTTON_DISABLED_FG_COLOR,
143 Ck_Offset(MenuButton, disabledBg),
144 CK_CONFIG_COLOR_ONLY},
145 {CK_CONFIG_COLOR, "-disabledbackground", "disabledBackground",
146 "DisabledBackground", DEF_MENUBUTTON_DISABLED_BG_MONO,
147 Ck_Offset(MenuButton, disabledBg),
148 CK_CONFIG_MONO_ONLY},
149 {CK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
150 "DisabledForeground", DEF_MENUBUTTON_DISABLED_BG_COLOR,
151 Ck_Offset(MenuButton, disabledFg),
152 CK_CONFIG_COLOR_ONLY},
153 {CK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
154 "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_MONO,
155 Ck_Offset(MenuButton, disabledFg),
156 CK_CONFIG_MONO_ONLY},
157 {CK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
158 (char *) NULL, 0, 0},
159 {CK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
160 DEF_MENUBUTTON_FG, Ck_Offset(MenuButton, normalFg), 0},
161 {CK_CONFIG_COORD, "-height", "height", "Height",
162 DEF_MENUBUTTON_HEIGHT, Ck_Offset(MenuButton, height), 0},
163 {CK_CONFIG_COLOR, "-indicatorforeground", "indicatorForeground",
164 "Foreground", DEF_MENUBUTTON_INDICATOR_FG_COLOR,
165 Ck_Offset(MenuButton, indicatorFg), CK_CONFIG_COLOR_ONLY},
166 {CK_CONFIG_COLOR, "-indicatorforeground", "indicatorForeground",
167 "Foreground", DEF_MENUBUTTON_INDICATOR_FG_MONO,
168 Ck_Offset(MenuButton, indicatorFg), CK_CONFIG_MONO_ONLY},
169 {CK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn",
170 DEF_MENUBUTTON_INDICATOR, Ck_Offset(MenuButton, indicatorOn), 0},
171 {CK_CONFIG_STRING, "-menu", "menu", "Menu",
172 DEF_MENUBUTTON_MENU, Ck_Offset(MenuButton, menuName),
174 {CK_CONFIG_UID, "-state", "state", "State",
175 DEF_MENUBUTTON_STATE, Ck_Offset(MenuButton, state), 0},
176 {CK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
177 DEF_MENUBUTTON_TAKE_FOCUS, Ck_Offset(MenuButton, takeFocus),
179 {CK_CONFIG_STRING, "-text", "text", "Text",
180 DEF_MENUBUTTON_TEXT, Ck_Offset(MenuButton, text), 0},
181 {CK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
182 DEF_MENUBUTTON_TEXT_VARIABLE, Ck_Offset(MenuButton, textVarName),
184 {CK_CONFIG_INT, "-underline", "underline", "Underline",
185 DEF_MENUBUTTON_UNDERLINE, Ck_Offset(MenuButton, underline), 0},
186 {CK_CONFIG_ATTR, "-underlineattributes", "underlineAttributes",
187 "UnderlineAttributes", DEF_MENUBUTTON_UNDERLINE_ATTR,
188 Ck_Offset(MenuButton, underlineAttr), 0},
189 {CK_CONFIG_COLOR, "-underlineforeground", "underlineForeground",
190 "UnderlineForeground", DEF_MENUBUTTON_UNDERLINE_FG_COLOR,
191 Ck_Offset(MenuButton, underlineFg), CK_CONFIG_COLOR_ONLY},
192 {CK_CONFIG_COLOR, "-underlineforeground", "underlineForeground",
193 "UnderlineForeground", DEF_MENUBUTTON_UNDERLINE_FG_MONO,
194 Ck_Offset(MenuButton, underlineFg), CK_CONFIG_MONO_ONLY},
195 {CK_CONFIG_COORD, "-width", "width", "Width",
196 DEF_MENUBUTTON_WIDTH, Ck_Offset(MenuButton, width), 0},
197 {CK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
202 * Forward declarations for procedures defined later in this file:
205 static void ComputeMenuButtonGeometry _ANSI_ARGS_((
207 static void MenuButtonCmdDeletedProc _ANSI_ARGS_((
208 ClientData clientData));
209 static void MenuButtonEventProc _ANSI_ARGS_((ClientData clientData,
211 static char * MenuButtonTextVarProc _ANSI_ARGS_((
212 ClientData clientData, Tcl_Interp *interp,
213 char *name1, char *name2, int flags));
214 static int MenuButtonWidgetCmd _ANSI_ARGS_((ClientData clientData,
215 Tcl_Interp *interp, int argc, char **argv));
216 static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp,
217 MenuButton *mbPtr, int argc, char **argv,
219 static void DestroyMenuButton _ANSI_ARGS_((ClientData clientData));
220 static void DisplayMenuButton _ANSI_ARGS_((ClientData clientData));
223 *--------------------------------------------------------------
225 * Ck_MenubuttonCmd --
227 * This procedure is invoked to process the "menubutton"
228 * Tcl commands. See the user documentation for details
232 * A standard Tcl result.
235 * See the user documentation.
237 *--------------------------------------------------------------
241 Ck_MenubuttonCmd(clientData, interp, argc, argv)
242 ClientData clientData; /* Main window associated with
244 Tcl_Interp *interp; /* Current interpreter. */
245 int argc; /* Number of arguments. */
246 char **argv; /* Argument strings. */
248 register MenuButton *mbPtr;
249 CkWindow *mainPtr = (CkWindow *) clientData;
253 Tcl_AppendResult(interp, "wrong # args: should be \"",
254 argv[0], " pathName ?options?\"", (char *) NULL);
259 * Create the new window.
262 new = Ck_CreateWindowFromPath(interp, mainPtr, argv[1], 0);
268 * Initialize the data structure for the button.
271 mbPtr = (MenuButton *) ckalloc(sizeof(MenuButton));
273 mbPtr->interp = interp;
274 mbPtr->widgetCmd = Tcl_CreateCommand(interp, mbPtr->winPtr->pathName,
275 MenuButtonWidgetCmd, (ClientData) mbPtr, MenuButtonCmdDeletedProc);
276 mbPtr->menuName = NULL;
280 mbPtr->textVarName = NULL;
281 mbPtr->state = ckNormalUid;
284 mbPtr->normalAttr = 0;
287 mbPtr->activeAttr = 0;
288 mbPtr->disabledBg = 0;
289 mbPtr->disabledFg = 0;
290 mbPtr->disabledAttr = 0;
291 mbPtr->underlineFg = 0;
292 mbPtr->underlineAttr = 0;
293 mbPtr->indicatorFg = 0;
294 mbPtr->underline = -1;
297 mbPtr->anchor = CK_ANCHOR_CENTER;
298 mbPtr->indicatorOn = 0;
299 mbPtr->takeFocus = NULL;
302 Ck_SetClass(mbPtr->winPtr, "Menubutton");
303 Ck_CreateEventHandler(mbPtr->winPtr,
304 CK_EV_EXPOSE | CK_EV_MAP | CK_EV_DESTROY,
305 MenuButtonEventProc, (ClientData) mbPtr);
306 if (ConfigureMenuButton(interp, mbPtr, argc-2, argv+2, 0) != TCL_OK) {
307 Ck_DestroyWindow(mbPtr->winPtr);
311 interp->result = mbPtr->winPtr->pathName;
316 *--------------------------------------------------------------
318 * MenuButtonWidgetCmd --
320 * This procedure is invoked to process the Tcl command
321 * that corresponds to a widget managed by this module.
322 * See the user documentation for details on what it does.
325 * A standard Tcl result.
328 * See the user documentation.
330 *--------------------------------------------------------------
334 MenuButtonWidgetCmd(clientData, interp, argc, argv)
335 ClientData clientData; /* Information about button widget. */
336 Tcl_Interp *interp; /* Current interpreter. */
337 int argc; /* Number of arguments. */
338 char **argv; /* Argument strings. */
340 register MenuButton *mbPtr = (MenuButton *) clientData;
346 Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
347 " option ?arg arg ...?\"", (char *) NULL);
350 Ck_Preserve((ClientData) mbPtr);
352 length = strlen(argv[1]);
353 if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
356 Tcl_AppendResult(interp, "wrong # args: should be \"",
357 argv[0], " cget option\"",
361 result = Ck_ConfigureValue(interp, mbPtr->winPtr, configSpecs,
362 (char *) mbPtr, argv[2], 0);
363 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
366 result = Ck_ConfigureInfo(interp, mbPtr->winPtr, configSpecs,
367 (char *) mbPtr, (char *) NULL, 0);
368 } else if (argc == 3) {
369 result = Ck_ConfigureInfo(interp, mbPtr->winPtr, configSpecs,
370 (char *) mbPtr, argv[2], 0);
372 result = ConfigureMenuButton(interp, mbPtr, argc-2, argv+2,
373 CK_CONFIG_ARGV_ONLY);
376 Tcl_AppendResult(interp, "bad option \"", argv[1],
377 "\": must be cget or configure",
381 Ck_Release((ClientData) mbPtr);
385 Ck_Release((ClientData) mbPtr);
390 *----------------------------------------------------------------------
392 * DestroyMenuButton --
394 * This procedure is invoked to recycle all of the resources
395 * associated with a button widget. It is invoked as a
396 * when-idle handler in order to make sure that there is no
397 * other use of the button pending at the time of the deletion.
403 * Everything associated with the widget is freed up.
405 *----------------------------------------------------------------------
409 DestroyMenuButton(clientData)
410 ClientData clientData; /* Info about button widget. */
412 register MenuButton *mbPtr = (MenuButton *) clientData;
415 * Free up all the stuff that requires special handling, then
416 * let Ck_FreeOptions handle all the standard option-related
420 if (mbPtr->textVarName != NULL) {
421 Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName,
422 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
423 MenuButtonTextVarProc, (ClientData) mbPtr);
425 Ck_FreeOptions(configSpecs, (char *) mbPtr, 0);
426 ckfree((char *) mbPtr);
430 *----------------------------------------------------------------------
432 * ConfigureMenuButton --
434 * This procedure is called to process an argv/argc list, plus
435 * the Tk option database, in order to configure (or
436 * reconfigure) a menubutton widget.
439 * The return value is a standard Tcl result. If TCL_ERROR is
440 * returned, then interp->result contains an error message.
443 * Configuration information, such as text string, colors, font,
444 * etc. get set for mbPtr; old resources get freed, if there
445 * were any. The menubutton is redisplayed.
447 *----------------------------------------------------------------------
451 ConfigureMenuButton(interp, mbPtr, argc, argv, flags)
452 Tcl_Interp *interp; /* Used for error reporting. */
453 register MenuButton *mbPtr; /* Information about widget; may or may
454 * not already have values for some fields. */
455 int argc; /* Number of valid entries in argv. */
456 char **argv; /* Arguments. */
457 int flags; /* Flags to pass to Tk_ConfigureWidget. */
462 * Eliminate any existing trace on variables monitored by the menubutton.
465 if (mbPtr->textVarName != NULL) {
466 Tcl_UntraceVar(interp, mbPtr->textVarName,
467 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
468 MenuButtonTextVarProc, (ClientData) mbPtr);
471 result = Ck_ConfigureWidget(interp, mbPtr->winPtr, configSpecs,
472 argc, argv, (char *) mbPtr, flags);
473 if (result != TCL_OK) {
478 * A few options need special processing, such as setting the
479 * background from a 3-D border, or filling in complicated
480 * defaults that couldn't be specified to Tk_ConfigureWidget.
483 if ((mbPtr->state != ckNormalUid) && (mbPtr->state != ckActiveUid)
484 && (mbPtr->state != ckDisabledUid)) {
485 Tcl_AppendResult(interp, "bad state value \"", mbPtr->state,
486 "\": must be normal, active, or disabled", (char *) NULL);
487 mbPtr->state = ckNormalUid;
491 if (mbPtr->textVarName != NULL) {
493 * The menubutton displays a variable. Set up a trace to watch
494 * for any changes in it.
499 value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY);
501 Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text,
504 if (mbPtr->text != NULL) {
507 mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
508 strcpy(mbPtr->text, value);
510 Tcl_TraceVar(interp, mbPtr->textVarName,
511 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
512 MenuButtonTextVarProc, (ClientData) mbPtr);
515 ComputeMenuButtonGeometry(mbPtr);
518 * Lastly, arrange for the button to be redisplayed.
521 if ((mbPtr->winPtr->flags & CK_MAPPED)
522 && !(mbPtr->flags & REDRAW_PENDING)) {
523 Tk_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
524 mbPtr->flags |= REDRAW_PENDING;
531 *----------------------------------------------------------------------
533 * DisplayMenuButton --
535 * This procedure is invoked to display a menubutton widget.
541 * Commands are output to X to display the menubutton in its
544 *----------------------------------------------------------------------
548 DisplayMenuButton(clientData)
549 ClientData clientData; /* Information about widget. */
551 MenuButton *mbPtr = (MenuButton *) clientData;
552 int x, y, fg, bg, attr, textWidth, charWidth;
553 CkWindow *winPtr = mbPtr->winPtr;
555 mbPtr->flags &= ~REDRAW_PENDING;
556 if ((mbPtr->winPtr == NULL) || !(winPtr->flags & CK_MAPPED)) {
560 if (mbPtr->state == ckDisabledUid) {
561 fg = mbPtr->disabledFg;
562 bg = mbPtr->disabledBg;
563 attr = mbPtr->disabledAttr;
564 } else if (mbPtr->state == ckActiveUid) {
565 fg = mbPtr->activeFg;
566 bg = mbPtr->activeBg;
567 attr = mbPtr->activeAttr;
569 fg = mbPtr->normalFg;
570 bg = mbPtr->normalBg;
571 attr = mbPtr->normalAttr;
575 * Display text for button.
578 if (mbPtr->text != NULL)
579 CkMeasureChars(winPtr->mainPtr, mbPtr->text, mbPtr->numChars, 0,
580 winPtr->width, 0, CK_NEWLINES_NOT_SPECIAL | CK_IGNORE_TABS,
581 &textWidth, &charWidth);
585 switch (mbPtr->anchor) {
586 case CK_ANCHOR_NW: case CK_ANCHOR_W: case CK_ANCHOR_SW:
589 case CK_ANCHOR_N: case CK_ANCHOR_CENTER: case CK_ANCHOR_S:
590 x = (winPtr->width - textWidth) / 2;
591 if (mbPtr->indicatorOn)
595 x = winPtr->width - textWidth;
596 if (mbPtr->indicatorOn)
600 if (x + textWidth > winPtr->width)
601 textWidth = winPtr->width - x;
603 switch (mbPtr->anchor) {
604 case CK_ANCHOR_NW: case CK_ANCHOR_N: case CK_ANCHOR_NE:
607 case CK_ANCHOR_W: case CK_ANCHOR_CENTER: case CK_ANCHOR_E:
608 y = (winPtr->height - 1) / 2;
611 y = winPtr->height - 1;
617 Ck_SetWindowAttr(winPtr, fg, bg, attr);
618 Ck_ClearToBot(winPtr, 0, 0);
619 if (mbPtr->text != NULL) {
620 CkDisplayChars(winPtr->mainPtr, winPtr->window, mbPtr->text,
622 0, CK_NEWLINES_NOT_SPECIAL | CK_IGNORE_TABS);
623 if (mbPtr->underline >= 0 && mbPtr->state == ckNormalUid) {
624 Ck_SetWindowAttr(winPtr, mbPtr->underlineFg, bg,
625 mbPtr->underlineAttr);
626 CkUnderlineChars(winPtr->mainPtr, winPtr->window,
627 mbPtr->text, charWidth, x, y,
628 0, CK_NEWLINES_NOT_SPECIAL | CK_IGNORE_TABS,
629 mbPtr->underline, mbPtr->underline);
630 Ck_SetWindowAttr(winPtr, fg, bg, attr);
633 if (mbPtr->indicatorOn) {
637 if (x >= winPtr->width)
638 x = winPtr->width - 1;
639 Ck_GetGChar(mbPtr->interp, "diamond", &gchar);
640 Ck_SetWindowAttr(winPtr, mbPtr->indicatorFg, bg, attr);
641 mvwaddch(winPtr->window, y, x, gchar);
643 Ck_SetWindowAttr(winPtr, fg, bg, attr);
644 wmove(winPtr->window, y, x);
645 Ck_EventuallyRefresh(winPtr);
649 *--------------------------------------------------------------
651 * MenuButtonEventProc --
653 * This procedure is invoked by the Tk dispatcher for various
660 * When the window gets deleted, internal structures get
661 * cleaned up. When it gets exposed, it is redisplayed.
663 *--------------------------------------------------------------
667 MenuButtonEventProc(clientData, eventPtr)
668 ClientData clientData; /* Information about window. */
669 CkEvent *eventPtr; /* Information about event. */
671 MenuButton *mbPtr = (MenuButton *) clientData;
673 if (eventPtr->type == CK_EV_EXPOSE) {
674 if (mbPtr->winPtr != NULL && !(mbPtr->flags & REDRAW_PENDING)) {
675 Tk_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
676 mbPtr->flags |= REDRAW_PENDING;
678 } else if (eventPtr->type == CK_EV_DESTROY) {
679 if (mbPtr->winPtr != NULL) {
680 mbPtr->winPtr = NULL;
681 Tcl_DeleteCommand(mbPtr->interp,
682 Tcl_GetCommandName(mbPtr->interp, mbPtr->widgetCmd));
684 if (mbPtr->flags & REDRAW_PENDING) {
685 Tk_CancelIdleCall(DisplayMenuButton, (ClientData) mbPtr);
687 Ck_EventuallyFree((ClientData) mbPtr,
688 (Ck_FreeProc *) DestroyMenuButton);
693 *----------------------------------------------------------------------
695 * MenuButtonCmdDeletedProc --
697 * This procedure is invoked when a widget command is deleted. If
698 * the widget isn't already in the process of being destroyed,
699 * this command destroys it.
705 * The widget is destroyed.
707 *----------------------------------------------------------------------
711 MenuButtonCmdDeletedProc(clientData)
712 ClientData clientData; /* Pointer to widget record for widget. */
714 MenuButton *mbPtr = (MenuButton *) clientData;
715 CkWindow *winPtr = mbPtr->winPtr;
718 * This procedure could be invoked either because the window was
719 * destroyed and the command was then deleted (in which case winPtr
720 * is NULL) or because the command was deleted, and then this procedure
721 * destroys the widget.
724 if (winPtr != NULL) {
725 mbPtr->winPtr = NULL;
726 Ck_DestroyWindow(winPtr);
731 *----------------------------------------------------------------------
733 * ComputeMenuButtonGeometry --
735 * After changes in a menu button's text or bitmap, this procedure
736 * recomputes the menu button's geometry and passes this information
737 * along to the geometry manager for the window.
743 * The menu button's window may change size.
745 *----------------------------------------------------------------------
749 ComputeMenuButtonGeometry(mbPtr)
750 register MenuButton *mbPtr; /* Widget record for menu button. */
752 int width, height, dummy;
753 CkWindow *winPtr = mbPtr->winPtr;
755 mbPtr->numChars = mbPtr->text == NULL ? 0 : strlen(mbPtr->text);
756 if (mbPtr->height > 0)
757 height = mbPtr->height;
760 if (mbPtr->width > 0)
761 width = mbPtr->width;
763 CkMeasureChars(winPtr->mainPtr, mbPtr->text == NULL ? "" : mbPtr->text,
764 mbPtr->numChars, 0, 100000, 0,
765 CK_NEWLINES_NOT_SPECIAL | CK_IGNORE_TABS,
769 * When issuing the geometry request, add extra space for the indicator
773 if (mbPtr->indicatorOn)
776 Ck_GeometryRequest(mbPtr->winPtr, width, height);
780 *--------------------------------------------------------------
782 * MenuButtonTextVarProc --
784 * This procedure is invoked when someone changes the variable
785 * whose contents are to be displayed in a menu button.
788 * NULL is always returned.
791 * The text displayed in the menu button will change to match the
794 *--------------------------------------------------------------
798 MenuButtonTextVarProc(clientData, interp, name1, name2, flags)
799 ClientData clientData; /* Information about button. */
800 Tcl_Interp *interp; /* Interpreter containing variable. */
801 char *name1; /* Name of variable. */
802 char *name2; /* Second part of variable name. */
803 int flags; /* Information about what happened. */
805 register MenuButton *mbPtr = (MenuButton *) clientData;
809 * If the variable is unset, then immediately recreate it unless
810 * the whole interpreter is going away.
813 if (flags & TCL_TRACE_UNSETS) {
814 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
815 Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text,
817 Tcl_TraceVar(interp, mbPtr->textVarName,
818 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
819 MenuButtonTextVarProc, clientData);
821 return (char *) NULL;
824 value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY);
828 if (mbPtr->text != NULL) {
831 mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
832 strcpy(mbPtr->text, value);
833 ComputeMenuButtonGeometry(mbPtr);
835 if ((mbPtr->winPtr != NULL) && (mbPtr->winPtr->flags & CK_MAPPED)
836 && !(mbPtr->flags & REDRAW_PENDING)) {
837 Tk_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
838 mbPtr->flags |= REDRAW_PENDING;
840 return (char *) NULL;