Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libtk/generic/tkMenubutton.c
1810 views
1
/*
2
* tkMenubutton.c --
3
*
4
* This module implements button-like widgets that are used
5
* to invoke pull-down menus.
6
*
7
* Copyright (c) 1990-1994 The Regents of the University of California.
8
* Copyright (c) 1994-1995 Sun Microsystems, Inc.
9
*
10
* See the file "license.terms" for information on usage and redistribution
11
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
12
*
13
* SCCS: @(#) tkMenubutton.c 1.77 96/02/15 18:52:22
14
*/
15
16
#include "tkInt.h"
17
#include "tkDefault.h"
18
19
/*
20
* A data structure of the following type is kept for each
21
* widget managed by this file:
22
*/
23
24
typedef struct {
25
Tk_Window tkwin; /* Window that embodies the widget. NULL
26
* means that the window has been destroyed
27
* but the data structures haven't yet been
28
* cleaned up.*/
29
Display *display; /* Display containing widget. Needed, among
30
* other things, so that resources can bee
31
* freed up even after tkwin has gone away. */
32
Tcl_Interp *interp; /* Interpreter associated with menubutton. */
33
Tcl_Command widgetCmd; /* Token for menubutton's widget command. */
34
char *menuName; /* Name of menu associated with widget.
35
* Malloc-ed. */
36
37
/*
38
* Information about what's displayed in the menu button:
39
*/
40
41
char *text; /* Text to display in button (malloc'ed)
42
* or NULL. */
43
int numChars; /* # of characters in text. */
44
int underline; /* Index of character to underline. */
45
char *textVarName; /* Name of variable (malloc'ed) or NULL.
46
* If non-NULL, button displays the contents
47
* of this variable. */
48
Pixmap bitmap; /* Bitmap to display or None. If not None
49
* then text and textVar and underline
50
* are ignored. */
51
char *imageString; /* Name of image to display (malloc'ed), or
52
* NULL. If non-NULL, bitmap, text, and
53
* textVarName are ignored. */
54
Tk_Image image; /* Image to display in window, or NULL if
55
* none. */
56
57
/*
58
* Information used when displaying widget:
59
*/
60
61
Tk_Uid state; /* State of button for display purposes:
62
* normal, active, or disabled. */
63
Tk_3DBorder normalBorder; /* Structure used to draw 3-D
64
* border and background when window
65
* isn't active. NULL means no such
66
* border exists. */
67
Tk_3DBorder activeBorder; /* Structure used to draw 3-D
68
* border and background when window
69
* is active. NULL means no such
70
* border exists. */
71
int borderWidth; /* Width of border. */
72
int relief; /* 3-d effect: TK_RELIEF_RAISED, etc. */
73
int highlightWidth; /* Width in pixels of highlight to draw
74
* around widget when it has the focus.
75
* <= 0 means don't draw a highlight. */
76
XColor *highlightBgColorPtr;
77
/* Color for drawing traversal highlight
78
* area when highlight is off. */
79
XColor *highlightColorPtr; /* Color for drawing traversal highlight. */
80
int inset; /* Total width of all borders, including
81
* traversal highlight and 3-D border.
82
* Indicates how much interior stuff must
83
* be offset from outside edges to leave
84
* room for borders. */
85
XFontStruct *fontPtr; /* Information about text font, or NULL. */
86
XColor *normalFg; /* Foreground color in normal mode. */
87
XColor *activeFg; /* Foreground color in active mode. NULL
88
* means use normalFg instead. */
89
XColor *disabledFg; /* Foreground color when disabled. NULL
90
* means use normalFg with a 50% stipple
91
* instead. */
92
GC normalTextGC; /* GC for drawing text in normal mode. */
93
GC activeTextGC; /* GC for drawing text in active mode (NULL
94
* means use normalTextGC). */
95
Pixmap gray; /* Pixmap for displaying disabled text/icon if
96
* disabledFg is NULL. */
97
GC disabledGC; /* Used to produce disabled effect. If
98
* disabledFg isn't NULL, this GC is used to
99
* draw button text or icon. Otherwise
100
* text or icon is drawn with normalGC and
101
* this GC is used to stipple background
102
* across it. */
103
int leftBearing; /* Distance from text origin to leftmost drawn
104
* pixel (positive means to right). */
105
int rightBearing; /* Amount text sticks right from its origin. */
106
char *widthString; /* Value of -width option. Malloc'ed. */
107
char *heightString; /* Value of -height option. Malloc'ed. */
108
int width, height; /* If > 0, these specify dimensions to request
109
* for window, in characters for text and in
110
* pixels for bitmaps. In this case the actual
111
* size of the text string or bitmap is
112
* ignored in computing desired window size. */
113
int wrapLength; /* Line length (in pixels) at which to wrap
114
* onto next line. <= 0 means don't wrap
115
* except at newlines. */
116
int padX, padY; /* Extra space around text or bitmap (pixels
117
* on each side). */
118
Tk_Anchor anchor; /* Where text/bitmap should be displayed
119
* inside window region. */
120
Tk_Justify justify; /* Justification to use for multi-line text. */
121
int textWidth; /* Width needed to display text as requested,
122
* in pixels. */
123
int textHeight; /* Height needed to display text as requested,
124
* in pixels. */
125
int indicatorOn; /* Non-zero means display indicator; 0 means
126
* don't display. */
127
int indicatorHeight; /* Height of indicator in pixels. This same
128
* amount of extra space is also left on each
129
* side of the indicator. 0 if no indicator. */
130
int indicatorWidth; /* Width of indicator in pixels, including
131
* indicatorHeight in padding on each side.
132
* 0 if no indicator. */
133
134
/*
135
* Miscellaneous information:
136
*/
137
138
Tk_Cursor cursor; /* Current cursor for window, or None. */
139
char *takeFocus; /* Value of -takefocus option; not used in
140
* the C code, but used by keyboard traversal
141
* scripts. Malloc'ed, but may be NULL. */
142
int flags; /* Various flags; see below for
143
* definitions. */
144
} MenuButton;
145
146
/*
147
* Flag bits for buttons:
148
*
149
* REDRAW_PENDING: Non-zero means a DoWhenIdle handler
150
* has already been queued to redraw
151
* this window.
152
* POSTED: Non-zero means that the menu associated
153
* with this button has been posted (typically
154
* because of an active button press).
155
* GOT_FOCUS: Non-zero means this button currently
156
* has the input focus.
157
*/
158
159
#define REDRAW_PENDING 1
160
#define POSTED 2
161
#define GOT_FOCUS 4
162
163
/*
164
* The following constants define the dimensions of the cascade indicator,
165
* which is displayed if the "-indicatoron" option is true. The units for
166
* these options are 1/10 millimeters.
167
*/
168
169
#define INDICATOR_WIDTH 40
170
#define INDICATOR_HEIGHT 17
171
172
/*
173
* Information used for parsing configuration specs:
174
*/
175
176
static Tk_ConfigSpec configSpecs[] = {
177
{TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
178
DEF_MENUBUTTON_ACTIVE_BG_COLOR, Tk_Offset(MenuButton, activeBorder),
179
TK_CONFIG_COLOR_ONLY},
180
{TK_CONFIG_BORDER, "-activebackground", "activeBackground", "Foreground",
181
DEF_MENUBUTTON_ACTIVE_BG_MONO, Tk_Offset(MenuButton, activeBorder),
182
TK_CONFIG_MONO_ONLY},
183
{TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
184
DEF_MENUBUTTON_ACTIVE_FG_COLOR, Tk_Offset(MenuButton, activeFg),
185
TK_CONFIG_COLOR_ONLY},
186
{TK_CONFIG_COLOR, "-activeforeground", "activeForeground", "Background",
187
DEF_MENUBUTTON_ACTIVE_FG_MONO, Tk_Offset(MenuButton, activeFg),
188
TK_CONFIG_MONO_ONLY},
189
{TK_CONFIG_ANCHOR, "-anchor", "anchor", "Anchor",
190
DEF_MENUBUTTON_ANCHOR, Tk_Offset(MenuButton, anchor), 0},
191
{TK_CONFIG_BORDER, "-background", "background", "Background",
192
DEF_MENUBUTTON_BG_COLOR, Tk_Offset(MenuButton, normalBorder),
193
TK_CONFIG_COLOR_ONLY},
194
{TK_CONFIG_BORDER, "-background", "background", "Background",
195
DEF_MENUBUTTON_BG_MONO, Tk_Offset(MenuButton, normalBorder),
196
TK_CONFIG_MONO_ONLY},
197
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
198
(char *) NULL, 0, 0},
199
{TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
200
(char *) NULL, 0, 0},
201
{TK_CONFIG_BITMAP, "-bitmap", "bitmap", "Bitmap",
202
DEF_MENUBUTTON_BITMAP, Tk_Offset(MenuButton, bitmap),
203
TK_CONFIG_NULL_OK},
204
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
205
DEF_MENUBUTTON_BORDER_WIDTH, Tk_Offset(MenuButton, borderWidth), 0},
206
{TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
207
DEF_MENUBUTTON_CURSOR, Tk_Offset(MenuButton, cursor),
208
TK_CONFIG_NULL_OK},
209
{TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
210
"DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_COLOR,
211
Tk_Offset(MenuButton, disabledFg),
212
TK_CONFIG_COLOR_ONLY|TK_CONFIG_NULL_OK},
213
{TK_CONFIG_COLOR, "-disabledforeground", "disabledForeground",
214
"DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_MONO,
215
Tk_Offset(MenuButton, disabledFg),
216
TK_CONFIG_MONO_ONLY|TK_CONFIG_NULL_OK},
217
{TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
218
(char *) NULL, 0, 0},
219
{TK_CONFIG_FONT, "-font", "font", "Font",
220
DEF_MENUBUTTON_FONT, Tk_Offset(MenuButton, fontPtr), 0},
221
{TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
222
DEF_MENUBUTTON_FG, Tk_Offset(MenuButton, normalFg), 0},
223
{TK_CONFIG_STRING, "-height", "height", "Height",
224
DEF_MENUBUTTON_HEIGHT, Tk_Offset(MenuButton, heightString), 0},
225
{TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
226
"HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG,
227
Tk_Offset(MenuButton, highlightBgColorPtr), 0},
228
{TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
229
DEF_MENUBUTTON_HIGHLIGHT, Tk_Offset(MenuButton, highlightColorPtr), 0},
230
{TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
231
"HighlightThickness", DEF_MENUBUTTON_HIGHLIGHT_WIDTH,
232
Tk_Offset(MenuButton, highlightWidth), 0},
233
{TK_CONFIG_STRING, "-image", "image", "Image",
234
DEF_MENUBUTTON_IMAGE, Tk_Offset(MenuButton, imageString),
235
TK_CONFIG_NULL_OK},
236
{TK_CONFIG_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn",
237
DEF_MENUBUTTON_INDICATOR, Tk_Offset(MenuButton, indicatorOn), 0},
238
{TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
239
DEF_MENUBUTTON_JUSTIFY, Tk_Offset(MenuButton, justify), 0},
240
{TK_CONFIG_STRING, "-menu", "menu", "Menu",
241
DEF_MENUBUTTON_MENU, Tk_Offset(MenuButton, menuName),
242
TK_CONFIG_NULL_OK},
243
{TK_CONFIG_PIXELS, "-padx", "padX", "Pad",
244
DEF_MENUBUTTON_PADX, Tk_Offset(MenuButton, padX), 0},
245
{TK_CONFIG_PIXELS, "-pady", "padY", "Pad",
246
DEF_MENUBUTTON_PADY, Tk_Offset(MenuButton, padY), 0},
247
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
248
DEF_MENUBUTTON_RELIEF, Tk_Offset(MenuButton, relief), 0},
249
{TK_CONFIG_UID, "-state", "state", "State",
250
DEF_MENUBUTTON_STATE, Tk_Offset(MenuButton, state), 0},
251
{TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
252
DEF_MENUBUTTON_TAKE_FOCUS, Tk_Offset(MenuButton, takeFocus),
253
TK_CONFIG_NULL_OK},
254
{TK_CONFIG_STRING, "-text", "text", "Text",
255
DEF_MENUBUTTON_TEXT, Tk_Offset(MenuButton, text), 0},
256
{TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
257
DEF_MENUBUTTON_TEXT_VARIABLE, Tk_Offset(MenuButton, textVarName),
258
TK_CONFIG_NULL_OK},
259
{TK_CONFIG_INT, "-underline", "underline", "Underline",
260
DEF_MENUBUTTON_UNDERLINE, Tk_Offset(MenuButton, underline), 0},
261
{TK_CONFIG_STRING, "-width", "width", "Width",
262
DEF_MENUBUTTON_WIDTH, Tk_Offset(MenuButton, widthString), 0},
263
{TK_CONFIG_PIXELS, "-wraplength", "wrapLength", "WrapLength",
264
DEF_MENUBUTTON_WRAP_LENGTH, Tk_Offset(MenuButton, wrapLength), 0},
265
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
266
(char *) NULL, 0, 0}
267
};
268
269
/*
270
* Forward declarations for procedures defined later in this file:
271
*/
272
273
static void ComputeMenuButtonGeometry _ANSI_ARGS_((
274
MenuButton *mbPtr));
275
static void MenuButtonCmdDeletedProc _ANSI_ARGS_((
276
ClientData clientData));
277
static void MenuButtonEventProc _ANSI_ARGS_((ClientData clientData,
278
XEvent *eventPtr));
279
static void MenuButtonImageProc _ANSI_ARGS_((ClientData clientData,
280
int x, int y, int width, int height, int imgWidth,
281
int imgHeight));
282
static char * MenuButtonTextVarProc _ANSI_ARGS_((
283
ClientData clientData, Tcl_Interp *interp,
284
char *name1, char *name2, int flags));
285
static int MenuButtonWidgetCmd _ANSI_ARGS_((ClientData clientData,
286
Tcl_Interp *interp, int argc, char **argv));
287
static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp,
288
MenuButton *mbPtr, int argc, char **argv,
289
int flags));
290
static void DestroyMenuButton _ANSI_ARGS_((char *memPtr));
291
static void DisplayMenuButton _ANSI_ARGS_((ClientData clientData));
292
293
/*
294
*--------------------------------------------------------------
295
*
296
* Tk_MenubuttonCmd --
297
*
298
* This procedure is invoked to process the "button", "label",
299
* "radiobutton", and "checkbutton" Tcl commands. See the
300
* user documentation for details on what it does.
301
*
302
* Results:
303
* A standard Tcl result.
304
*
305
* Side effects:
306
* See the user documentation.
307
*
308
*--------------------------------------------------------------
309
*/
310
311
int
312
Tk_MenubuttonCmd(clientData, interp, argc, argv)
313
ClientData clientData; /* Main window associated with
314
* interpreter. */
315
Tcl_Interp *interp; /* Current interpreter. */
316
int argc; /* Number of arguments. */
317
char **argv; /* Argument strings. */
318
{
319
register MenuButton *mbPtr;
320
Tk_Window tkwin = (Tk_Window) clientData;
321
Tk_Window new;
322
323
if (argc < 2) {
324
Tcl_AppendResult(interp, "wrong # args: should be \"",
325
argv[0], " pathName ?options?\"", (char *) NULL);
326
return TCL_ERROR;
327
}
328
329
/*
330
* Create the new window.
331
*/
332
333
new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
334
if (new == NULL) {
335
return TCL_ERROR;
336
}
337
338
/*
339
* Initialize the data structure for the button.
340
*/
341
342
mbPtr = (MenuButton *) ckalloc(sizeof(MenuButton));
343
mbPtr->tkwin = new;
344
mbPtr->display = Tk_Display (new);
345
mbPtr->interp = interp;
346
mbPtr->widgetCmd = Tcl_CreateCommand(interp, Tk_PathName(mbPtr->tkwin),
347
MenuButtonWidgetCmd, (ClientData) mbPtr, MenuButtonCmdDeletedProc);
348
mbPtr->menuName = NULL;
349
mbPtr->text = NULL;
350
mbPtr->numChars = 0;
351
mbPtr->underline = -1;
352
mbPtr->textVarName = NULL;
353
mbPtr->bitmap = None;
354
mbPtr->imageString = NULL;
355
mbPtr->image = NULL;
356
mbPtr->state = tkNormalUid;
357
mbPtr->normalBorder = NULL;
358
mbPtr->activeBorder = NULL;
359
mbPtr->borderWidth = 0;
360
mbPtr->relief = TK_RELIEF_FLAT;
361
mbPtr->highlightWidth = 0;
362
mbPtr->highlightBgColorPtr = NULL;
363
mbPtr->highlightColorPtr = NULL;
364
mbPtr->inset = 0;
365
mbPtr->fontPtr = NULL;
366
mbPtr->normalFg = NULL;
367
mbPtr->activeFg = NULL;
368
mbPtr->disabledFg = NULL;
369
mbPtr->normalTextGC = None;
370
mbPtr->activeTextGC = None;
371
mbPtr->gray = None;
372
mbPtr->disabledGC = None;
373
mbPtr->leftBearing = 0;
374
mbPtr->rightBearing = 0;
375
mbPtr->widthString = NULL;
376
mbPtr->heightString = NULL;
377
mbPtr->width = 0;
378
mbPtr->width = 0;
379
mbPtr->wrapLength = 0;
380
mbPtr->padX = 0;
381
mbPtr->padY = 0;
382
mbPtr->anchor = TK_ANCHOR_CENTER;
383
mbPtr->justify = TK_JUSTIFY_CENTER;
384
mbPtr->indicatorOn = 0;
385
mbPtr->indicatorWidth = 0;
386
mbPtr->indicatorHeight = 0;
387
mbPtr->cursor = None;
388
mbPtr->takeFocus = NULL;
389
mbPtr->flags = 0;
390
391
Tk_SetClass(mbPtr->tkwin, "Menubutton");
392
Tk_CreateEventHandler(mbPtr->tkwin,
393
ExposureMask|StructureNotifyMask|FocusChangeMask,
394
MenuButtonEventProc, (ClientData) mbPtr);
395
if (ConfigureMenuButton(interp, mbPtr, argc-2, argv+2, 0) != TCL_OK) {
396
Tk_DestroyWindow(mbPtr->tkwin);
397
return TCL_ERROR;
398
}
399
400
interp->result = Tk_PathName(mbPtr->tkwin);
401
return TCL_OK;
402
}
403
404
/*
405
*--------------------------------------------------------------
406
*
407
* MenuButtonWidgetCmd --
408
*
409
* This procedure is invoked to process the Tcl command
410
* that corresponds to a widget managed by this module.
411
* See the user documentation for details on what it does.
412
*
413
* Results:
414
* A standard Tcl result.
415
*
416
* Side effects:
417
* See the user documentation.
418
*
419
*--------------------------------------------------------------
420
*/
421
422
static int
423
MenuButtonWidgetCmd(clientData, interp, argc, argv)
424
ClientData clientData; /* Information about button widget. */
425
Tcl_Interp *interp; /* Current interpreter. */
426
int argc; /* Number of arguments. */
427
char **argv; /* Argument strings. */
428
{
429
register MenuButton *mbPtr = (MenuButton *) clientData;
430
int result = TCL_OK;
431
size_t length;
432
int c;
433
434
if (argc < 2) {
435
Tcl_AppendResult(interp, "wrong # args: should be \"", argv[0],
436
" option ?arg arg ...?\"", (char *) NULL);
437
return TCL_ERROR;
438
}
439
Tcl_Preserve((ClientData) mbPtr);
440
c = argv[1][0];
441
length = strlen(argv[1]);
442
if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
443
&& (length >= 2)) {
444
if (argc != 3) {
445
Tcl_AppendResult(interp, "wrong # args: should be \"",
446
argv[0], " cget option\"",
447
(char *) NULL);
448
goto error;
449
}
450
result = Tk_ConfigureValue(interp, mbPtr->tkwin, configSpecs,
451
(char *) mbPtr, argv[2], 0);
452
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
453
&& (length >= 2)) {
454
if (argc == 2) {
455
result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs,
456
(char *) mbPtr, (char *) NULL, 0);
457
} else if (argc == 3) {
458
result = Tk_ConfigureInfo(interp, mbPtr->tkwin, configSpecs,
459
(char *) mbPtr, argv[2], 0);
460
} else {
461
result = ConfigureMenuButton(interp, mbPtr, argc-2, argv+2,
462
TK_CONFIG_ARGV_ONLY);
463
}
464
} else {
465
Tcl_AppendResult(interp, "bad option \"", argv[1],
466
"\": must be cget or configure",
467
(char *) NULL);
468
goto error;
469
}
470
Tcl_Release((ClientData) mbPtr);
471
return result;
472
473
error:
474
Tcl_Release((ClientData) mbPtr);
475
return TCL_ERROR;
476
}
477
478
/*
479
*----------------------------------------------------------------------
480
*
481
* DestroyMenuButton --
482
*
483
* This procedure is invoked to recycle all of the resources
484
* associated with a button widget. It is invoked as a
485
* when-idle handler in order to make sure that there is no
486
* other use of the button pending at the time of the deletion.
487
*
488
* Results:
489
* None.
490
*
491
* Side effects:
492
* Everything associated with the widget is freed up.
493
*
494
*----------------------------------------------------------------------
495
*/
496
497
static void
498
DestroyMenuButton(memPtr)
499
char *memPtr; /* Info about button widget. */
500
{
501
register MenuButton *mbPtr = (MenuButton *) memPtr;
502
503
/*
504
* Free up all the stuff that requires special handling, then
505
* let Tk_FreeOptions handle all the standard option-related
506
* stuff.
507
*/
508
509
if (mbPtr->textVarName != NULL) {
510
Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName,
511
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
512
MenuButtonTextVarProc, (ClientData) mbPtr);
513
}
514
if (mbPtr->image != NULL) {
515
Tk_FreeImage(mbPtr->image);
516
}
517
if (mbPtr->normalTextGC != None) {
518
Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC);
519
}
520
if (mbPtr->activeTextGC != None) {
521
Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC);
522
}
523
if (mbPtr->gray != None) {
524
Tk_FreeBitmap(mbPtr->display, mbPtr->gray);
525
}
526
if (mbPtr->disabledGC != None) {
527
Tk_FreeGC(mbPtr->display, mbPtr->disabledGC);
528
}
529
Tk_FreeOptions(configSpecs, (char *) mbPtr, mbPtr->display, 0);
530
ckfree((char *) mbPtr);
531
}
532
533
/*
534
*----------------------------------------------------------------------
535
*
536
* ConfigureMenuButton --
537
*
538
* This procedure is called to process an argv/argc list, plus
539
* the Tk option database, in order to configure (or
540
* reconfigure) a menubutton widget.
541
*
542
* Results:
543
* The return value is a standard Tcl result. If TCL_ERROR is
544
* returned, then interp->result contains an error message.
545
*
546
* Side effects:
547
* Configuration information, such as text string, colors, font,
548
* etc. get set for mbPtr; old resources get freed, if there
549
* were any. The menubutton is redisplayed.
550
*
551
*----------------------------------------------------------------------
552
*/
553
554
static int
555
ConfigureMenuButton(interp, mbPtr, argc, argv, flags)
556
Tcl_Interp *interp; /* Used for error reporting. */
557
register MenuButton *mbPtr; /* Information about widget; may or may
558
* not already have values for some fields. */
559
int argc; /* Number of valid entries in argv. */
560
char **argv; /* Arguments. */
561
int flags; /* Flags to pass to Tk_ConfigureWidget. */
562
{
563
XGCValues gcValues;
564
GC newGC;
565
unsigned long mask;
566
int result;
567
Tk_Image image;
568
569
/*
570
* Eliminate any existing trace on variables monitored by the menubutton.
571
*/
572
573
if (mbPtr->textVarName != NULL) {
574
Tcl_UntraceVar(interp, mbPtr->textVarName,
575
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
576
MenuButtonTextVarProc, (ClientData) mbPtr);
577
}
578
579
result = Tk_ConfigureWidget(interp, mbPtr->tkwin, configSpecs,
580
argc, argv, (char *) mbPtr, flags);
581
if (result != TCL_OK) {
582
return TCL_ERROR;
583
}
584
585
/*
586
* A few options need special processing, such as setting the
587
* background from a 3-D border, or filling in complicated
588
* defaults that couldn't be specified to Tk_ConfigureWidget.
589
*/
590
591
if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) {
592
Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder);
593
} else {
594
Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder);
595
if ((mbPtr->state != tkNormalUid) && (mbPtr->state != tkActiveUid)
596
&& (mbPtr->state != tkDisabledUid)) {
597
Tcl_AppendResult(interp, "bad state value \"", mbPtr->state,
598
"\": must be normal, active, or disabled", (char *) NULL);
599
mbPtr->state = tkNormalUid;
600
return TCL_ERROR;
601
}
602
}
603
604
if (mbPtr->highlightWidth < 0) {
605
mbPtr->highlightWidth = 0;
606
}
607
608
gcValues.font = mbPtr->fontPtr->fid;
609
gcValues.foreground = mbPtr->normalFg->pixel;
610
gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel;
611
612
/*
613
* Note: GraphicsExpose events are disabled in GC's because they're
614
* used to copy stuff from an off-screen pixmap onto the screen (we know
615
* that there's no problem with obscured areas).
616
*/
617
618
gcValues.graphics_exposures = False;
619
newGC = Tk_GetGC(mbPtr->tkwin,
620
GCForeground|GCBackground|GCFont|GCGraphicsExposures, &gcValues);
621
if (mbPtr->normalTextGC != None) {
622
Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC);
623
}
624
mbPtr->normalTextGC = newGC;
625
626
gcValues.font = mbPtr->fontPtr->fid;
627
gcValues.foreground = mbPtr->activeFg->pixel;
628
gcValues.background = Tk_3DBorderColor(mbPtr->activeBorder)->pixel;
629
newGC = Tk_GetGC(mbPtr->tkwin, GCForeground|GCBackground|GCFont,
630
&gcValues);
631
if (mbPtr->activeTextGC != None) {
632
Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC);
633
}
634
mbPtr->activeTextGC = newGC;
635
636
gcValues.font = mbPtr->fontPtr->fid;
637
gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel;
638
if ((mbPtr->disabledFg != NULL) && (mbPtr->imageString == NULL)) {
639
gcValues.foreground = mbPtr->disabledFg->pixel;
640
mask = GCForeground|GCBackground|GCFont;
641
} else {
642
gcValues.foreground = gcValues.background;
643
if (mbPtr->gray == None) {
644
mbPtr->gray = Tk_GetBitmap(interp, mbPtr->tkwin,
645
Tk_GetUid("gray50"));
646
if (mbPtr->gray == None) {
647
return TCL_ERROR;
648
}
649
}
650
gcValues.fill_style = FillStippled;
651
gcValues.stipple = mbPtr->gray;
652
mask = GCForeground|GCFillStyle|GCStipple;
653
}
654
newGC = Tk_GetGC(mbPtr->tkwin, mask, &gcValues);
655
if (mbPtr->disabledGC != None) {
656
Tk_FreeGC(mbPtr->display, mbPtr->disabledGC);
657
}
658
mbPtr->disabledGC = newGC;
659
660
if (mbPtr->padX < 0) {
661
mbPtr->padX = 0;
662
}
663
if (mbPtr->padY < 0) {
664
mbPtr->padY = 0;
665
}
666
667
/*
668
* Get the image for the widget, if there is one. Allocate the
669
* new image before freeing the old one, so that the reference
670
* count doesn't go to zero and cause image data to be discarded.
671
*/
672
673
if (mbPtr->imageString != NULL) {
674
image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin,
675
mbPtr->imageString, MenuButtonImageProc, (ClientData) mbPtr);
676
if (image == NULL) {
677
return TCL_ERROR;
678
}
679
} else {
680
image = NULL;
681
}
682
if (mbPtr->image != NULL) {
683
Tk_FreeImage(mbPtr->image);
684
}
685
mbPtr->image = image;
686
687
if ((mbPtr->image == NULL) && (mbPtr->bitmap == None)
688
&& (mbPtr->textVarName != NULL)) {
689
/*
690
* The menubutton displays a variable. Set up a trace to watch
691
* for any changes in it.
692
*/
693
694
char *value;
695
696
value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY);
697
if (value == NULL) {
698
Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text,
699
TCL_GLOBAL_ONLY);
700
} else {
701
if (mbPtr->text != NULL) {
702
ckfree(mbPtr->text);
703
}
704
mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
705
strcpy(mbPtr->text, value);
706
}
707
Tcl_TraceVar(interp, mbPtr->textVarName,
708
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
709
MenuButtonTextVarProc, (ClientData) mbPtr);
710
}
711
712
/*
713
* Recompute the geometry for the button.
714
*/
715
716
if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) {
717
if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString,
718
&mbPtr->width) != TCL_OK) {
719
widthError:
720
Tcl_AddErrorInfo(interp, "\n (processing -width option)");
721
return TCL_ERROR;
722
}
723
if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString,
724
&mbPtr->height) != TCL_OK) {
725
heightError:
726
Tcl_AddErrorInfo(interp, "\n (processing -height option)");
727
return TCL_ERROR;
728
}
729
} else {
730
if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width)
731
!= TCL_OK) {
732
goto widthError;
733
}
734
if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height)
735
!= TCL_OK) {
736
goto heightError;
737
}
738
}
739
ComputeMenuButtonGeometry(mbPtr);
740
741
/*
742
* Lastly, arrange for the button to be redisplayed.
743
*/
744
745
if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) {
746
Tcl_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
747
mbPtr->flags |= REDRAW_PENDING;
748
}
749
750
return TCL_OK;
751
}
752
753
/*
754
*----------------------------------------------------------------------
755
*
756
* DisplayMenuButton --
757
*
758
* This procedure is invoked to display a menubutton widget.
759
*
760
* Results:
761
* None.
762
*
763
* Side effects:
764
* Commands are output to X to display the menubutton in its
765
* current mode.
766
*
767
*----------------------------------------------------------------------
768
*/
769
770
static void
771
DisplayMenuButton(clientData)
772
ClientData clientData; /* Information about widget. */
773
{
774
register MenuButton *mbPtr = (MenuButton *) clientData;
775
GC gc;
776
Tk_3DBorder border;
777
Pixmap pixmap;
778
int x = 0; /* Initialization needed only to stop
779
* compiler warning. */
780
int y;
781
register Tk_Window tkwin = mbPtr->tkwin;
782
int width, height;
783
784
mbPtr->flags &= ~REDRAW_PENDING;
785
if ((mbPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
786
return;
787
}
788
789
if ((mbPtr->state == tkDisabledUid) && (mbPtr->disabledFg != NULL)) {
790
gc = mbPtr->disabledGC;
791
border = mbPtr->normalBorder;
792
} else if ((mbPtr->state == tkActiveUid) && !Tk_StrictMotif(mbPtr->tkwin)) {
793
gc = mbPtr->activeTextGC;
794
border = mbPtr->activeBorder;
795
} else {
796
gc = mbPtr->normalTextGC;
797
border = mbPtr->normalBorder;
798
}
799
800
/*
801
* In order to avoid screen flashes, this procedure redraws
802
* the menu button in a pixmap, then copies the pixmap to the
803
* screen in a single operation. This means that there's no
804
* point in time where the on-sreen image has been cleared.
805
*/
806
807
pixmap = Tk_GetPixmap(mbPtr->display, Tk_WindowId(tkwin),
808
Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
809
Tk_Fill3DRectangle(tkwin, pixmap, border, 0, 0, Tk_Width(tkwin),
810
Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
811
812
/*
813
* Display image or bitmap or text for button.
814
*/
815
816
if (mbPtr->image != None) {
817
Tk_SizeOfImage(mbPtr->image, &width, &height);
818
819
imageOrBitmap:
820
switch (mbPtr->anchor) {
821
case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW:
822
x += mbPtr->inset;
823
break;
824
case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S:
825
x += ((int) (Tk_Width(tkwin) - width
826
- mbPtr->indicatorWidth))/2;
827
break;
828
default:
829
x += Tk_Width(tkwin) - mbPtr->inset - width
830
- mbPtr->indicatorWidth;
831
break;
832
}
833
switch (mbPtr->anchor) {
834
case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
835
y = mbPtr->inset;
836
break;
837
case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
838
y = ((int) (Tk_Height(tkwin) - height))/2;
839
break;
840
default:
841
y = Tk_Height(tkwin) - mbPtr->inset - height;
842
break;
843
}
844
if (mbPtr->image != NULL) {
845
Tk_RedrawImage(mbPtr->image, 0, 0, width, height, pixmap,
846
x, y);
847
} else {
848
XCopyPlane(mbPtr->display, mbPtr->bitmap, pixmap,
849
gc, 0, 0, (unsigned) width, (unsigned) height, x, y, 1);
850
}
851
} else if (mbPtr->bitmap != None) {
852
Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
853
goto imageOrBitmap;
854
} else {
855
width = mbPtr->textWidth;
856
height = mbPtr->textHeight;
857
switch (mbPtr->anchor) {
858
case TK_ANCHOR_NW: case TK_ANCHOR_W: case TK_ANCHOR_SW:
859
x = mbPtr->inset + mbPtr->padX;
860
break;
861
case TK_ANCHOR_N: case TK_ANCHOR_CENTER: case TK_ANCHOR_S:
862
x = ((int) (Tk_Width(tkwin) - width
863
- mbPtr->indicatorWidth))/2;
864
break;
865
default:
866
x = Tk_Width(tkwin) - width - mbPtr->padX - mbPtr->inset
867
- mbPtr->indicatorWidth;
868
break;
869
}
870
switch (mbPtr->anchor) {
871
case TK_ANCHOR_NW: case TK_ANCHOR_N: case TK_ANCHOR_NE:
872
y = mbPtr->inset + mbPtr->padY;
873
break;
874
case TK_ANCHOR_W: case TK_ANCHOR_CENTER: case TK_ANCHOR_E:
875
y = ((int) (Tk_Height(tkwin) - height))/2;
876
break;
877
default:
878
y = Tk_Height(tkwin) - mbPtr->inset - mbPtr->padY - height;
879
break;
880
}
881
TkDisplayText(mbPtr->display, pixmap, mbPtr->fontPtr,
882
mbPtr->text, mbPtr->numChars, x, y, mbPtr->textWidth,
883
mbPtr->justify, mbPtr->underline, gc);
884
}
885
886
/*
887
* If the menu button is disabled with a stipple rather than a special
888
* foreground color, generate the stippled effect.
889
*/
890
891
if ((mbPtr->state == tkDisabledUid)
892
&& ((mbPtr->disabledFg == NULL) || (mbPtr->image != NULL))) {
893
XFillRectangle(mbPtr->display, pixmap, mbPtr->disabledGC,
894
mbPtr->inset, mbPtr->inset,
895
(unsigned) (Tk_Width(tkwin) - 2*mbPtr->inset),
896
(unsigned) (Tk_Height(tkwin) - 2*mbPtr->inset));
897
}
898
899
/*
900
* Draw the cascade indicator for the menu button on the
901
* right side of the window, if desired.
902
*/
903
904
if (mbPtr->indicatorOn) {
905
int borderWidth;
906
907
borderWidth = (mbPtr->indicatorHeight+1)/3;
908
if (borderWidth < 1) {
909
borderWidth = 1;
910
}
911
Tk_Fill3DRectangle(tkwin, pixmap, border,
912
Tk_Width(tkwin) - mbPtr->inset - mbPtr->indicatorWidth
913
+ mbPtr->indicatorHeight,
914
y + ((int) (height - mbPtr->indicatorHeight))/2,
915
mbPtr->indicatorWidth - 2*mbPtr->indicatorHeight,
916
mbPtr->indicatorHeight, borderWidth, TK_RELIEF_RAISED);
917
}
918
919
/*
920
* Draw the border and traversal highlight last. This way, if the
921
* menu button's contents overflow onto the border they'll be covered
922
* up by the border.
923
*/
924
925
if (mbPtr->relief != TK_RELIEF_FLAT) {
926
Tk_Draw3DRectangle(tkwin, pixmap, border,
927
mbPtr->highlightWidth, mbPtr->highlightWidth,
928
Tk_Width(tkwin) - 2*mbPtr->highlightWidth,
929
Tk_Height(tkwin) - 2*mbPtr->highlightWidth,
930
mbPtr->borderWidth, mbPtr->relief);
931
}
932
if (mbPtr->highlightWidth != 0) {
933
GC gc;
934
935
if (mbPtr->flags & GOT_FOCUS) {
936
gc = Tk_GCForColor(mbPtr->highlightColorPtr, pixmap);
937
} else {
938
gc = Tk_GCForColor(mbPtr->highlightBgColorPtr, pixmap);
939
}
940
Tk_DrawFocusHighlight(tkwin, gc, mbPtr->highlightWidth, pixmap);
941
}
942
943
/*
944
* Copy the information from the off-screen pixmap onto the screen,
945
* then delete the pixmap.
946
*/
947
948
XCopyArea(mbPtr->display, pixmap, Tk_WindowId(tkwin),
949
mbPtr->normalTextGC, 0, 0, (unsigned) Tk_Width(tkwin),
950
(unsigned) Tk_Height(tkwin), 0, 0);
951
Tk_FreePixmap(mbPtr->display, pixmap);
952
}
953
954
/*
955
*--------------------------------------------------------------
956
*
957
* MenuButtonEventProc --
958
*
959
* This procedure is invoked by the Tk dispatcher for various
960
* events on buttons.
961
*
962
* Results:
963
* None.
964
*
965
* Side effects:
966
* When the window gets deleted, internal structures get
967
* cleaned up. When it gets exposed, it is redisplayed.
968
*
969
*--------------------------------------------------------------
970
*/
971
972
static void
973
MenuButtonEventProc(clientData, eventPtr)
974
ClientData clientData; /* Information about window. */
975
XEvent *eventPtr; /* Information about event. */
976
{
977
MenuButton *mbPtr = (MenuButton *) clientData;
978
if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
979
goto redraw;
980
} else if (eventPtr->type == ConfigureNotify) {
981
/*
982
* Must redraw after size changes, since layout could have changed
983
* and borders will need to be redrawn.
984
*/
985
986
goto redraw;
987
} else if (eventPtr->type == DestroyNotify) {
988
if (mbPtr->tkwin != NULL) {
989
mbPtr->tkwin = NULL;
990
Tcl_DeleteCommand(mbPtr->interp,
991
Tcl_GetCommandName(mbPtr->interp, mbPtr->widgetCmd));
992
}
993
if (mbPtr->flags & REDRAW_PENDING) {
994
Tcl_CancelIdleCall(DisplayMenuButton, (ClientData) mbPtr);
995
}
996
Tcl_EventuallyFree((ClientData) mbPtr, DestroyMenuButton);
997
} else if (eventPtr->type == FocusIn) {
998
if (eventPtr->xfocus.detail != NotifyInferior) {
999
mbPtr->flags |= GOT_FOCUS;
1000
if (mbPtr->highlightWidth > 0) {
1001
goto redraw;
1002
}
1003
}
1004
} else if (eventPtr->type == FocusOut) {
1005
if (eventPtr->xfocus.detail != NotifyInferior) {
1006
mbPtr->flags &= ~GOT_FOCUS;
1007
if (mbPtr->highlightWidth > 0) {
1008
goto redraw;
1009
}
1010
}
1011
}
1012
return;
1013
1014
redraw:
1015
if ((mbPtr->tkwin != NULL) && !(mbPtr->flags & REDRAW_PENDING)) {
1016
Tcl_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
1017
mbPtr->flags |= REDRAW_PENDING;
1018
}
1019
}
1020
1021
/*
1022
*----------------------------------------------------------------------
1023
*
1024
* MenuButtonCmdDeletedProc --
1025
*
1026
* This procedure is invoked when a widget command is deleted. If
1027
* the widget isn't already in the process of being destroyed,
1028
* this command destroys it.
1029
*
1030
* Results:
1031
* None.
1032
*
1033
* Side effects:
1034
* The widget is destroyed.
1035
*
1036
*----------------------------------------------------------------------
1037
*/
1038
1039
static void
1040
MenuButtonCmdDeletedProc(clientData)
1041
ClientData clientData; /* Pointer to widget record for widget. */
1042
{
1043
MenuButton *mbPtr = (MenuButton *) clientData;
1044
Tk_Window tkwin = mbPtr->tkwin;
1045
1046
/*
1047
* This procedure could be invoked either because the window was
1048
* destroyed and the command was then deleted (in which case tkwin
1049
* is NULL) or because the command was deleted, and then this procedure
1050
* destroys the widget.
1051
*/
1052
1053
if (tkwin != NULL) {
1054
mbPtr->tkwin = NULL;
1055
Tk_DestroyWindow(tkwin);
1056
}
1057
}
1058
1059
/*
1060
*----------------------------------------------------------------------
1061
*
1062
* ComputeMenuButtonGeometry --
1063
*
1064
* After changes in a menu button's text or bitmap, this procedure
1065
* recomputes the menu button's geometry and passes this information
1066
* along to the geometry manager for the window.
1067
*
1068
* Results:
1069
* None.
1070
*
1071
* Side effects:
1072
* The menu button's window may change size.
1073
*
1074
*----------------------------------------------------------------------
1075
*/
1076
1077
static void
1078
ComputeMenuButtonGeometry(mbPtr)
1079
register MenuButton *mbPtr; /* Widget record for menu button. */
1080
{
1081
int width, height, mm, pixels;
1082
1083
mbPtr->inset = mbPtr->highlightWidth + mbPtr->borderWidth;
1084
if (mbPtr->image != None) {
1085
Tk_SizeOfImage(mbPtr->image, &width, &height);
1086
if (mbPtr->width > 0) {
1087
width = mbPtr->width;
1088
}
1089
if (mbPtr->height > 0) {
1090
height = mbPtr->height;
1091
}
1092
} else if (mbPtr->bitmap != None) {
1093
Tk_SizeOfBitmap(mbPtr->display, mbPtr->bitmap, &width, &height);
1094
if (mbPtr->width > 0) {
1095
width = mbPtr->width;
1096
}
1097
if (mbPtr->height > 0) {
1098
height = mbPtr->height;
1099
}
1100
} else {
1101
mbPtr->numChars = strlen(mbPtr->text);
1102
TkComputeTextGeometry(mbPtr->fontPtr, mbPtr->text,
1103
mbPtr->numChars, mbPtr->wrapLength, &mbPtr->textWidth,
1104
&mbPtr->textHeight);
1105
width = mbPtr->textWidth;
1106
height = mbPtr->textHeight;
1107
if (mbPtr->width > 0) {
1108
width = mbPtr->width * XTextWidth(mbPtr->fontPtr, "0", 1);
1109
}
1110
if (mbPtr->height > 0) {
1111
height = mbPtr->height * (mbPtr->fontPtr->ascent
1112
+ mbPtr->fontPtr->descent);
1113
}
1114
width += 2*mbPtr->padX;
1115
height += 2*mbPtr->padY;
1116
}
1117
1118
if (mbPtr->indicatorOn) {
1119
mm = WidthMMOfScreen(Tk_Screen(mbPtr->tkwin));
1120
pixels = WidthOfScreen(Tk_Screen(mbPtr->tkwin));
1121
mbPtr->indicatorHeight= (INDICATOR_HEIGHT * pixels)/(10*mm);
1122
mbPtr->indicatorWidth = (INDICATOR_WIDTH * pixels)/(10*mm)
1123
+ 2*mbPtr->indicatorHeight;
1124
width += mbPtr->indicatorWidth;
1125
} else {
1126
mbPtr->indicatorHeight = 0;
1127
mbPtr->indicatorWidth = 0;
1128
}
1129
1130
Tk_GeometryRequest(mbPtr->tkwin, (int) (width + 2*mbPtr->inset),
1131
(int) (height + 2*mbPtr->inset));
1132
Tk_SetInternalBorder(mbPtr->tkwin, mbPtr->inset);
1133
}
1134
1135
/*
1136
*--------------------------------------------------------------
1137
*
1138
* MenuButtonTextVarProc --
1139
*
1140
* This procedure is invoked when someone changes the variable
1141
* whose contents are to be displayed in a menu button.
1142
*
1143
* Results:
1144
* NULL is always returned.
1145
*
1146
* Side effects:
1147
* The text displayed in the menu button will change to match the
1148
* variable.
1149
*
1150
*--------------------------------------------------------------
1151
*/
1152
1153
/* ARGSUSED */
1154
static char *
1155
MenuButtonTextVarProc(clientData, interp, name1, name2, flags)
1156
ClientData clientData; /* Information about button. */
1157
Tcl_Interp *interp; /* Interpreter containing variable. */
1158
char *name1; /* Name of variable. */
1159
char *name2; /* Second part of variable name. */
1160
int flags; /* Information about what happened. */
1161
{
1162
register MenuButton *mbPtr = (MenuButton *) clientData;
1163
char *value;
1164
1165
/*
1166
* If the variable is unset, then immediately recreate it unless
1167
* the whole interpreter is going away.
1168
*/
1169
1170
if (flags & TCL_TRACE_UNSETS) {
1171
if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
1172
Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text,
1173
TCL_GLOBAL_ONLY);
1174
Tcl_TraceVar(interp, mbPtr->textVarName,
1175
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1176
MenuButtonTextVarProc, clientData);
1177
}
1178
return (char *) NULL;
1179
}
1180
1181
value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY);
1182
if (value == NULL) {
1183
value = "";
1184
}
1185
if (mbPtr->text != NULL) {
1186
ckfree(mbPtr->text);
1187
}
1188
mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
1189
strcpy(mbPtr->text, value);
1190
ComputeMenuButtonGeometry(mbPtr);
1191
1192
if ((mbPtr->tkwin != NULL) && Tk_IsMapped(mbPtr->tkwin)
1193
&& !(mbPtr->flags & REDRAW_PENDING)) {
1194
Tcl_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
1195
mbPtr->flags |= REDRAW_PENDING;
1196
}
1197
return (char *) NULL;
1198
}
1199
1200
/*
1201
*----------------------------------------------------------------------
1202
*
1203
* MenuButtonImageProc --
1204
*
1205
* This procedure is invoked by the image code whenever the manager
1206
* for an image does something that affects the size of contents
1207
* of an image displayed in a button.
1208
*
1209
* Results:
1210
* None.
1211
*
1212
* Side effects:
1213
* Arranges for the button to get redisplayed.
1214
*
1215
*----------------------------------------------------------------------
1216
*/
1217
1218
static void
1219
MenuButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
1220
ClientData clientData; /* Pointer to widget record. */
1221
int x, y; /* Upper left pixel (within image)
1222
* that must be redisplayed. */
1223
int width, height; /* Dimensions of area to redisplay
1224
* (may be <= 0). */
1225
int imgWidth, imgHeight; /* New dimensions of image. */
1226
{
1227
register MenuButton *mbPtr = (MenuButton *) clientData;
1228
1229
if (mbPtr->tkwin != NULL) {
1230
ComputeMenuButtonGeometry(mbPtr);
1231
if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) {
1232
Tcl_DoWhenIdle(DisplayMenuButton, (ClientData) mbPtr);
1233
mbPtr->flags |= REDRAW_PENDING;
1234
}
1235
}
1236
}
1237
1238