/[dtapublic]/projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmenubutton.c
ViewVC logotype

Contents of /projs/trunk/shared_source/c_tk_base_7_5_w_mods/tkmenubutton.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 69 - (show annotations) (download)
Sat Nov 5 10:54:17 2016 UTC (6 years, 3 months ago) by dashley
File MIME type: text/plain
File size: 30241 byte(s)
License and property (keyword) changes.
1 /* $Header$ */
2
3 /*
4 * tkMenubutton.c --
5 *
6 * This module implements button-like widgets that are used
7 * to invoke pull-down menus.
8 *
9 * Copyright (c) 1990-1994 The Regents of the University of California.
10 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
11 *
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
14 *
15 * RCS: @(#) $Id: tkmenubutton.c,v 1.1.1.1 2001/06/13 05:05:54 dtashley Exp $
16 */
17
18 #include "tkMenubutton.h"
19 #include "tkPort.h"
20 #include "default.h"
21
22 /*
23 * The following table defines the legal values for the -direction
24 * option. It is used together with the "enum direction" declaration
25 * in tkMenubutton.h.
26 */
27
28 static char *directionStrings[] = {
29 "above", "below", "flush", "left", "right", (char *) NULL
30 };
31
32 /*
33 * The following table defines the legal values for the -state option.
34 * It is used together with the "enum state" declaration in tkMenubutton.h.
35 */
36
37 static char *stateStrings[] = {
38 "active", "disabled", "normal", (char *) NULL
39 };
40
41 /*
42 * Information used for parsing configuration specs:
43 */
44
45 static Tk_OptionSpec optionSpecs[] = {
46 {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground",
47 DEF_MENUBUTTON_ACTIVE_BG_COLOR, -1,
48 Tk_Offset(TkMenuButton, activeBorder), 0,
49 (ClientData) DEF_MENUBUTTON_ACTIVE_BG_MONO, 0},
50 {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background",
51 DEF_MENUBUTTON_ACTIVE_FG_COLOR, -1,
52 Tk_Offset(TkMenuButton, activeFg),
53 0, (ClientData) DEF_MENUBUTTON_ACTIVE_FG_MONO, 0},
54 {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
55 DEF_MENUBUTTON_ANCHOR, -1,
56 Tk_Offset(TkMenuButton, anchor), 0, 0, 0},
57 {TK_OPTION_BORDER, "-background", "background", "Background",
58 DEF_MENUBUTTON_BG_COLOR, -1, Tk_Offset(TkMenuButton, normalBorder),
59 0, (ClientData) DEF_MENUBUTTON_BG_MONO, 0},
60 {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
61 (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
62 {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
63 (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
64 {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap",
65 DEF_MENUBUTTON_BITMAP, -1, Tk_Offset(TkMenuButton, bitmap),
66 TK_OPTION_NULL_OK, 0, 0},
67 {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
68 DEF_MENUBUTTON_BORDER_WIDTH, -1,
69 Tk_Offset(TkMenuButton, borderWidth), 0, 0, 0},
70 {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
71 DEF_MENUBUTTON_CURSOR, -1, Tk_Offset(TkMenuButton, cursor),
72 TK_OPTION_NULL_OK, 0, 0},
73 {TK_OPTION_STRING_TABLE, "-direction", "direction", "Direction",
74 DEF_MENUBUTTON_DIRECTION, -1, Tk_Offset(TkMenuButton, direction),
75 0, (ClientData) directionStrings, 0},
76 {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
77 "DisabledForeground", DEF_MENUBUTTON_DISABLED_FG_COLOR,
78 -1, Tk_Offset(TkMenuButton, disabledFg), TK_OPTION_NULL_OK,
79 (ClientData) DEF_MENUBUTTON_DISABLED_FG_MONO, 0},
80 {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
81 (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
82 {TK_OPTION_FONT, "-font", "font", "Font",
83 DEF_MENUBUTTON_FONT, -1, Tk_Offset(TkMenuButton, tkfont), 0, 0, 0},
84 {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
85 DEF_MENUBUTTON_FG, -1, Tk_Offset(TkMenuButton, normalFg), 0, 0, 0},
86 {TK_OPTION_STRING, "-height", "height", "Height",
87 DEF_MENUBUTTON_HEIGHT, -1, Tk_Offset(TkMenuButton, heightString),
88 0, 0, 0},
89 {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
90 "HighlightBackground", DEF_MENUBUTTON_HIGHLIGHT_BG_COLOR,
91 -1, Tk_Offset(TkMenuButton, highlightBgColorPtr), 0, 0, 0},
92 {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
93 DEF_MENUBUTTON_HIGHLIGHT, -1,
94 Tk_Offset(TkMenuButton, highlightColorPtr), 0, 0, 0},
95 {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
96 "HighlightThickness", DEF_MENUBUTTON_HIGHLIGHT_WIDTH,
97 -1, Tk_Offset(TkMenuButton, highlightWidth), 0, 0, 0},
98 {TK_OPTION_STRING, "-image", "image", "Image",
99 DEF_MENUBUTTON_IMAGE, -1, Tk_Offset(TkMenuButton, imageString),
100 TK_OPTION_NULL_OK, 0, 0},
101 {TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn",
102 DEF_MENUBUTTON_INDICATOR, -1, Tk_Offset(TkMenuButton, indicatorOn),
103 0, 0, 0},
104 {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
105 DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkMenuButton, justify), 0, 0, 0},
106 {TK_OPTION_STRING, "-menu", "menu", "Menu",
107 DEF_MENUBUTTON_MENU, -1, Tk_Offset(TkMenuButton, menuName),
108 TK_OPTION_NULL_OK, 0, 0},
109 {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
110 DEF_MENUBUTTON_PADX, -1, Tk_Offset(TkMenuButton, padX),
111 0, 0, 0},
112 {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
113 DEF_MENUBUTTON_PADY, -1, Tk_Offset(TkMenuButton, padY),
114 0, 0, 0},
115 {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
116 DEF_MENUBUTTON_RELIEF, -1, Tk_Offset(TkMenuButton, relief),
117 0, 0, 0},
118 {TK_OPTION_STRING_TABLE, "-state", "state", "State",
119 DEF_MENUBUTTON_STATE, -1, Tk_Offset(TkMenuButton, state),
120 0, (ClientData) stateStrings, 0},
121 {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
122 DEF_MENUBUTTON_TAKE_FOCUS, -1,
123 Tk_Offset(TkMenuButton, takeFocus), TK_OPTION_NULL_OK, 0, 0},
124 {TK_OPTION_STRING, "-text", "text", "Text",
125 DEF_MENUBUTTON_TEXT, -1, Tk_Offset(TkMenuButton, text), 0, 0, 0},
126 {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
127 DEF_MENUBUTTON_TEXT_VARIABLE, -1,
128 Tk_Offset(TkMenuButton, textVarName), TK_OPTION_NULL_OK, 0, 0},
129 {TK_OPTION_INT, "-underline", "underline", "Underline",
130 DEF_MENUBUTTON_UNDERLINE, -1, Tk_Offset(TkMenuButton, underline),
131 0, 0, 0},
132 {TK_OPTION_STRING, "-width", "width", "Width",
133 DEF_MENUBUTTON_WIDTH, -1, Tk_Offset(TkMenuButton, widthString),
134 0, 0, 0},
135 {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength",
136 DEF_MENUBUTTON_WRAP_LENGTH, -1, Tk_Offset(TkMenuButton, wrapLength),
137 0, 0, 0},
138 {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
139 (char *) NULL, 0, 0}
140 };
141
142 /*
143 * The following tables define the menubutton widget commands and map the
144 * indexes into the string tables into a single enumerated type used
145 * to dispatch the scale widget command.
146 */
147
148 static char *commandNames[] = {
149 "cget", "configure", (char *) NULL
150 };
151
152 enum command {
153 COMMAND_CGET, COMMAND_CONFIGURE
154 };
155
156 /*
157 * Forward declarations for procedures defined later in this file:
158 */
159
160 static void MenuButtonCmdDeletedProc _ANSI_ARGS_((
161 ClientData clientData));
162 static void MenuButtonEventProc _ANSI_ARGS_((ClientData clientData,
163 XEvent *eventPtr));
164 static void MenuButtonImageProc _ANSI_ARGS_((ClientData clientData,
165 int x, int y, int width, int height, int imgWidth,
166 int imgHeight));
167 static char * MenuButtonTextVarProc _ANSI_ARGS_((
168 ClientData clientData, Tcl_Interp *interp,
169 char *name1, char *name2, int flags));
170 static int MenuButtonWidgetObjCmd _ANSI_ARGS_((
171 ClientData clientData, Tcl_Interp *interp,
172 int objc, Tcl_Obj *CONST objv[]));
173 static int ConfigureMenuButton _ANSI_ARGS_((Tcl_Interp *interp,
174 TkMenuButton *mbPtr, int objc,
175 Tcl_Obj *CONST objv[]));
176 static void DestroyMenuButton _ANSI_ARGS_((char *memPtr));
177
178 /*
179 *--------------------------------------------------------------
180 *
181 * Tk_MenubuttonObjCmd --
182 *
183 * This procedure is invoked to process the "button", "label",
184 * "radiobutton", and "checkbutton" Tcl commands. See the
185 * user documentation for details on what it does.
186 *
187 * Results:
188 * A standard Tcl result.
189 *
190 * Side effects:
191 * See the user documentation.
192 *
193 *--------------------------------------------------------------
194 */
195
196 int
197 Tk_MenubuttonObjCmd(clientData, interp, objc, objv)
198 ClientData clientData; /* Either NULL or pointer to
199 * option table. */
200 Tcl_Interp *interp; /* Current interpreter. */
201 int objc; /* Number of arguments. */
202 Tcl_Obj *CONST objv[]; /* Argument objects. */
203 {
204 register TkMenuButton *mbPtr;
205 Tk_OptionTable optionTable;
206 Tk_Window tkwin;
207
208 optionTable = (Tk_OptionTable) clientData;
209 if (optionTable == NULL) {
210 Tcl_CmdInfo info;
211 char *name;
212
213 /*
214 * We haven't created the option table for this widget class
215 * yet. Do it now and save the table as the clientData for
216 * the command, so we'll have access to it in future
217 * invocations of the command.
218 */
219
220 optionTable = Tk_CreateOptionTable(interp, optionSpecs);
221 name = Tcl_GetString(objv[0]);
222 Tcl_GetCommandInfo(interp, name, &info);
223 info.objClientData = (ClientData) optionTable;
224 Tcl_SetCommandInfo(interp, name, &info);
225 }
226
227 if (objc < 2) {
228 Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
229 return TCL_ERROR;
230 }
231
232 /*
233 * Create the new window.
234 */
235
236 tkwin = Tk_CreateWindowFromPath(interp,
237 Tk_MainWindow(interp), Tcl_GetString(objv[1]), (char *) NULL);
238 if (tkwin == NULL) {
239 return TCL_ERROR;
240 }
241
242 Tk_SetClass(tkwin, "Menubutton");
243 mbPtr = TkpCreateMenuButton(tkwin);
244
245 TkSetClassProcs(tkwin, &tkpMenubuttonClass, (ClientData) mbPtr);
246
247 /*
248 * Initialize the data structure for the button.
249 */
250
251 mbPtr->tkwin = tkwin;
252 mbPtr->display = Tk_Display (tkwin);
253 mbPtr->interp = interp;
254 mbPtr->widgetCmd = Tcl_CreateObjCommand(interp,
255 Tk_PathName(mbPtr->tkwin), MenuButtonWidgetObjCmd,
256 (ClientData) mbPtr, MenuButtonCmdDeletedProc);
257 mbPtr->optionTable = optionTable;
258 mbPtr->menuName = NULL;
259 mbPtr->text = NULL;
260 mbPtr->underline = -1;
261 mbPtr->textVarName = NULL;
262 mbPtr->bitmap = None;
263 mbPtr->imageString = NULL;
264 mbPtr->image = NULL;
265 mbPtr->state = STATE_NORMAL;
266 mbPtr->normalBorder = NULL;
267 mbPtr->activeBorder = NULL;
268 mbPtr->borderWidth = 0;
269 mbPtr->relief = TK_RELIEF_FLAT;
270 mbPtr->highlightWidth = 0;
271 mbPtr->highlightBgColorPtr = NULL;
272 mbPtr->highlightColorPtr = NULL;
273 mbPtr->inset = 0;
274 mbPtr->tkfont = NULL;
275 mbPtr->normalFg = NULL;
276 mbPtr->activeFg = NULL;
277 mbPtr->disabledFg = NULL;
278 mbPtr->normalTextGC = None;
279 mbPtr->activeTextGC = None;
280 mbPtr->gray = None;
281 mbPtr->disabledGC = None;
282 mbPtr->leftBearing = 0;
283 mbPtr->rightBearing = 0;
284 mbPtr->widthString = NULL;
285 mbPtr->heightString = NULL;
286 mbPtr->width = 0;
287 mbPtr->width = 0;
288 mbPtr->wrapLength = 0;
289 mbPtr->padX = 0;
290 mbPtr->padY = 0;
291 mbPtr->anchor = TK_ANCHOR_CENTER;
292 mbPtr->justify = TK_JUSTIFY_CENTER;
293 mbPtr->textLayout = NULL;
294 mbPtr->indicatorOn = 0;
295 mbPtr->indicatorWidth = 0;
296 mbPtr->indicatorHeight = 0;
297 mbPtr->direction = DIRECTION_FLUSH;
298 mbPtr->cursor = None;
299 mbPtr->takeFocus = NULL;
300 mbPtr->flags = 0;
301
302 Tk_CreateEventHandler(mbPtr->tkwin,
303 ExposureMask|StructureNotifyMask|FocusChangeMask,
304 MenuButtonEventProc, (ClientData) mbPtr);
305
306 if (Tk_InitOptions(interp, (char *) mbPtr, optionTable, tkwin)
307 != TCL_OK) {
308 Tk_DestroyWindow(mbPtr->tkwin);
309 return TCL_ERROR;
310 }
311
312 if (ConfigureMenuButton(interp, mbPtr, objc-2, objv+2) != TCL_OK) {
313 Tk_DestroyWindow(mbPtr->tkwin);
314 return TCL_ERROR;
315 }
316
317 Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_PathName(mbPtr->tkwin),
318 -1);
319 return TCL_OK;
320 }
321
322 /*
323 *--------------------------------------------------------------
324 *
325 * MenuButtonWidgetObjCmd --
326 *
327 * This procedure is invoked to process the Tcl command
328 * that corresponds to a widget managed by this module.
329 * See the user documentation for details on what it does.
330 *
331 * Results:
332 * A standard Tcl result.
333 *
334 * Side effects:
335 * See the user documentation.
336 *
337 *--------------------------------------------------------------
338 */
339
340 static int
341 MenuButtonWidgetObjCmd(clientData, interp, objc, objv)
342 ClientData clientData; /* Information about button widget. */
343 Tcl_Interp *interp; /* Current interpreter. */
344 int objc; /* Number of arguments. */
345 Tcl_Obj *CONST objv[]; /* Argument objects. */
346 {
347 register TkMenuButton *mbPtr = (TkMenuButton *) clientData;
348 int result, index;
349 Tcl_Obj *objPtr;
350
351 if (objc < 2) {
352 Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
353 return TCL_ERROR;
354 }
355 result = Tcl_GetIndexFromObj(interp, objv[1],
356 commandNames, "option", 0, &index);
357 if (result != TCL_OK) {
358 return result;
359 }
360 Tcl_Preserve((ClientData) mbPtr);
361
362 switch (index) {
363 case COMMAND_CGET: {
364 if (objc != 3) {
365 Tcl_WrongNumArgs(interp, 1, objv, "cget option");
366 goto error;
367 }
368
369 objPtr = Tk_GetOptionValue(interp, (char *) mbPtr,
370 mbPtr->optionTable, objv[2], mbPtr->tkwin);
371 if (objPtr == NULL) {
372 goto error;
373 } else {
374 Tcl_SetObjResult(interp, objPtr);
375 }
376 break;
377 }
378
379 case COMMAND_CONFIGURE: {
380 if (objc <= 3) {
381 objPtr = Tk_GetOptionInfo(interp, (char *) mbPtr,
382 mbPtr->optionTable,
383 (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
384 mbPtr->tkwin);
385 if (objPtr == NULL) {
386 goto error;
387 } else {
388 Tcl_SetObjResult(interp, objPtr);
389 }
390 } else {
391 result = ConfigureMenuButton(interp, mbPtr, objc-2,
392 objv+2);
393 }
394 break;
395 }
396 }
397 Tcl_Release((ClientData) mbPtr);
398 return result;
399
400 error:
401 Tcl_Release((ClientData) mbPtr);
402 return TCL_ERROR;
403 }
404
405 /*
406 *----------------------------------------------------------------------
407 *
408 * DestroyMenuButton --
409 *
410 * This procedure is invoked to recycle all of the resources
411 * associated with a menubutton widget. It is invoked as a
412 * when-idle handler in order to make sure that there is no
413 * other use of the menubutton pending at the time of the deletion.
414 *
415 * Results:
416 * None.
417 *
418 * Side effects:
419 * Everything associated with the widget is freed up.
420 *
421 *----------------------------------------------------------------------
422 */
423
424 static void
425 DestroyMenuButton(memPtr)
426 char *memPtr; /* Info about button widget. */
427 {
428 register TkMenuButton *mbPtr = (TkMenuButton *) memPtr;
429 TkpDestroyMenuButton(mbPtr);
430
431 if (mbPtr->flags & REDRAW_PENDING) {
432 Tcl_CancelIdleCall(TkpDisplayMenuButton, (ClientData) mbPtr);
433 }
434
435 /*
436 * Free up all the stuff that requires special handling, then
437 * let Tk_FreeOptions handle all the standard option-related
438 * stuff.
439 */
440
441 Tcl_DeleteCommandFromToken(mbPtr->interp, mbPtr->widgetCmd);
442 if (mbPtr->textVarName != NULL) {
443 Tcl_UntraceVar(mbPtr->interp, mbPtr->textVarName,
444 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
445 MenuButtonTextVarProc, (ClientData) mbPtr);
446 }
447 if (mbPtr->image != NULL) {
448 Tk_FreeImage(mbPtr->image);
449 }
450 if (mbPtr->normalTextGC != None) {
451 Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC);
452 }
453 if (mbPtr->activeTextGC != None) {
454 Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC);
455 }
456 if (mbPtr->disabledGC != None) {
457 Tk_FreeGC(mbPtr->display, mbPtr->disabledGC);
458 }
459 if (mbPtr->gray != None) {
460 Tk_FreeBitmap(mbPtr->display, mbPtr->gray);
461 }
462 if (mbPtr->textLayout != NULL) {
463 Tk_FreeTextLayout(mbPtr->textLayout);
464 }
465 Tk_FreeConfigOptions((char *) mbPtr, mbPtr->optionTable,
466 mbPtr->tkwin);
467 mbPtr->tkwin = NULL;
468 Tcl_EventuallyFree((ClientData) mbPtr, TCL_DYNAMIC);
469 }
470
471 /*
472 *----------------------------------------------------------------------
473 *
474 * ConfigureMenuButton --
475 *
476 * This procedure is called to process an argv/argc list, plus
477 * the Tk option database, in order to configure (or
478 * reconfigure) a menubutton widget.
479 *
480 * Results:
481 * The return value is a standard Tcl result. If TCL_ERROR is
482 * returned, then the interp's result contains an error message.
483 *
484 * Side effects:
485 * Configuration information, such as text string, colors, font,
486 * etc. get set for mbPtr; old resources get freed, if there
487 * were any. The menubutton is redisplayed.
488 *
489 *----------------------------------------------------------------------
490 */
491
492 static int
493 ConfigureMenuButton(interp, mbPtr, objc, objv)
494 Tcl_Interp *interp; /* Used for error reporting. */
495 register TkMenuButton *mbPtr;
496 /* Information about widget; may or may
497 * not already have values for some
498 * fields. */
499 int objc; /* Number of valid entries in objv. */
500 Tcl_Obj *CONST objv[]; /* Arguments. */
501 {
502 Tk_SavedOptions savedOptions;
503 Tcl_Obj *errorResult = NULL;
504 int error;
505 Tk_Image image;
506
507 /*
508 * Eliminate any existing trace on variables monitored by the
509 * menubutton.
510 */
511
512 if (mbPtr->textVarName != NULL) {
513 Tcl_UntraceVar(interp, mbPtr->textVarName,
514 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
515 MenuButtonTextVarProc, (ClientData) mbPtr);
516 }
517
518 /*
519 * The following loop is potentially executed twice. During the
520 * first pass configuration options get set to their new values.
521 * If there is an error in this pass, we execute a second pass
522 * to restore all the options to their previous values.
523 */
524
525 for (error = 0; error <= 1; error++) {
526 if (!error) {
527 /*
528 * First pass: set options to new values.
529 */
530
531 if (Tk_SetOptions(interp, (char *) mbPtr,
532 mbPtr->optionTable, objc, objv,
533 mbPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
534 continue;
535 }
536 } else {
537 /*
538 * Second pass: restore options to old values.
539 */
540
541 errorResult = Tcl_GetObjResult(interp);
542 Tcl_IncrRefCount(errorResult);
543 Tk_RestoreSavedOptions(&savedOptions);
544 }
545
546 /*
547 * A few options need special processing, such as setting the
548 * background from a 3-D border, or filling in complicated
549 * defaults that couldn't be specified to Tk_SetOptions.
550 */
551
552 if ((mbPtr->state == STATE_ACTIVE)
553 && !Tk_StrictMotif(mbPtr->tkwin)) {
554 Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->activeBorder);
555 } else {
556 Tk_SetBackgroundFromBorder(mbPtr->tkwin, mbPtr->normalBorder);
557 }
558
559 if (mbPtr->highlightWidth < 0) {
560 mbPtr->highlightWidth = 0;
561 }
562
563 if (mbPtr->padX < 0) {
564 mbPtr->padX = 0;
565 }
566 if (mbPtr->padY < 0) {
567 mbPtr->padY = 0;
568 }
569
570 /*
571 * Get the image for the widget, if there is one. Allocate the
572 * new image before freeing the old one, so that the reference
573 * count doesn't go to zero and cause image data to be discarded.
574 */
575
576 if (mbPtr->imageString != NULL) {
577 image = Tk_GetImage(mbPtr->interp, mbPtr->tkwin,
578 mbPtr->imageString, MenuButtonImageProc,
579 (ClientData) mbPtr);
580 if (image == NULL) {
581 return TCL_ERROR;
582 }
583 } else {
584 image = NULL;
585 }
586 if (mbPtr->image != NULL) {
587 Tk_FreeImage(mbPtr->image);
588 }
589 mbPtr->image = image;
590
591 /*
592 * Recompute the geometry for the button.
593 */
594
595 if ((mbPtr->bitmap != None) || (mbPtr->image != NULL)) {
596 if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->widthString,
597 &mbPtr->width) != TCL_OK) {
598 widthError:
599 Tcl_AddErrorInfo(interp, "\n (processing -width option)");
600 continue;
601 }
602 if (Tk_GetPixels(interp, mbPtr->tkwin, mbPtr->heightString,
603 &mbPtr->height) != TCL_OK) {
604 heightError:
605 Tcl_AddErrorInfo(interp, "\n (processing -height option)");
606 continue;
607 }
608 } else {
609 if (Tcl_GetInt(interp, mbPtr->widthString, &mbPtr->width)
610 != TCL_OK) {
611 goto widthError;
612 }
613 if (Tcl_GetInt(interp, mbPtr->heightString, &mbPtr->height)
614 != TCL_OK) {
615 goto heightError;
616 }
617 }
618 break;
619 }
620
621 if (!error) {
622 Tk_FreeSavedOptions(&savedOptions);
623 }
624
625 if ((mbPtr->image == NULL) && (mbPtr->bitmap == None)
626 && (mbPtr->textVarName != NULL)) {
627
628 /*
629 * The menubutton displays the value of a variable.
630 * Set up a trace to watch for any changes in it, create
631 * the variable if it doesn't exist, and fetch its
632 * current value.
633 */
634
635 char *value;
636
637 value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY);
638 if (value == NULL) {
639 Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text,
640 TCL_GLOBAL_ONLY);
641 } else {
642 if (mbPtr->text != NULL) {
643 ckfree(mbPtr->text);
644 }
645 mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
646 strcpy(mbPtr->text, value);
647 }
648 Tcl_TraceVar(interp, mbPtr->textVarName,
649 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
650 MenuButtonTextVarProc, (ClientData) mbPtr);
651 }
652
653 TkMenuButtonWorldChanged((ClientData) mbPtr);
654 if (error) {
655 Tcl_SetObjResult(interp, errorResult);
656 Tcl_DecrRefCount(errorResult);
657 return TCL_ERROR;
658 } else {
659 return TCL_OK;
660 }
661 }
662
663 /*
664 *---------------------------------------------------------------------------
665 *
666 * TkMenuButtonWorldChanged --
667 *
668 * This procedure is called when the world has changed in some
669 * way and the widget needs to recompute all its graphics contexts
670 * and determine its new geometry.
671 *
672 * Results:
673 * None.
674 *
675 * Side effects:
676 * TkMenuButton will be relayed out and redisplayed.
677 *
678 *---------------------------------------------------------------------------
679 */
680
681 void
682 TkMenuButtonWorldChanged(instanceData)
683 ClientData instanceData; /* Information about widget. */
684 {
685 XGCValues gcValues;
686 GC gc;
687 unsigned long mask;
688 TkMenuButton *mbPtr;
689
690 mbPtr = (TkMenuButton *) instanceData;
691
692 gcValues.font = Tk_FontId(mbPtr->tkfont);
693 gcValues.foreground = mbPtr->normalFg->pixel;
694 gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel;
695
696 /*
697 * Note: GraphicsExpose events are disabled in GC's because they're
698 * used to copy stuff from an off-screen pixmap onto the screen (we know
699 * that there's no problem with obscured areas).
700 */
701
702 gcValues.graphics_exposures = False;
703 mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
704 gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues);
705 if (mbPtr->normalTextGC != None) {
706 Tk_FreeGC(mbPtr->display, mbPtr->normalTextGC);
707 }
708 mbPtr->normalTextGC = gc;
709
710 gcValues.font = Tk_FontId(mbPtr->tkfont);
711 gcValues.foreground = mbPtr->activeFg->pixel;
712 gcValues.background = Tk_3DBorderColor(mbPtr->activeBorder)->pixel;
713 mask = GCForeground | GCBackground | GCFont;
714 gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues);
715 if (mbPtr->activeTextGC != None) {
716 Tk_FreeGC(mbPtr->display, mbPtr->activeTextGC);
717 }
718 mbPtr->activeTextGC = gc;
719
720 gcValues.font = Tk_FontId(mbPtr->tkfont);
721 gcValues.background = Tk_3DBorderColor(mbPtr->normalBorder)->pixel;
722 if ((mbPtr->disabledFg != NULL) && (mbPtr->imageString == NULL)) {
723 gcValues.foreground = mbPtr->disabledFg->pixel;
724 mask = GCForeground | GCBackground | GCFont;
725 } else {
726 gcValues.foreground = gcValues.background;
727 mask = GCForeground;
728 if (mbPtr->gray == None) {
729 mbPtr->gray = Tk_GetBitmap(NULL, mbPtr->tkwin,
730 Tk_GetUid("gray50"));
731 }
732 if (mbPtr->gray != None) {
733 gcValues.fill_style = FillStippled;
734 gcValues.stipple = mbPtr->gray;
735 mask |= GCFillStyle | GCStipple;
736 }
737 }
738 gc = Tk_GetGC(mbPtr->tkwin, mask, &gcValues);
739 if (mbPtr->disabledGC != None) {
740 Tk_FreeGC(mbPtr->display, mbPtr->disabledGC);
741 }
742 mbPtr->disabledGC = gc;
743
744 TkpComputeMenuButtonGeometry(mbPtr);
745
746 /*
747 * Lastly, arrange for the button to be redisplayed.
748 */
749
750 if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) {
751 Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
752 mbPtr->flags |= REDRAW_PENDING;
753 }
754 }
755
756 /*
757 *--------------------------------------------------------------
758 *
759 * MenuButtonEventProc --
760 *
761 * This procedure is invoked by the Tk dispatcher for various
762 * events on buttons.
763 *
764 * Results:
765 * None.
766 *
767 * Side effects:
768 * When the window gets deleted, internal structures get
769 * cleaned up. When it gets exposed, it is redisplayed.
770 *
771 *--------------------------------------------------------------
772 */
773
774 static void
775 MenuButtonEventProc(clientData, eventPtr)
776 ClientData clientData; /* Information about window. */
777 XEvent *eventPtr; /* Information about event. */
778 {
779 TkMenuButton *mbPtr = (TkMenuButton *) clientData;
780 if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
781 goto redraw;
782 } else if (eventPtr->type == ConfigureNotify) {
783 /*
784 * Must redraw after size changes, since layout could have changed
785 * and borders will need to be redrawn.
786 */
787
788 goto redraw;
789 } else if (eventPtr->type == DestroyNotify) {
790 DestroyMenuButton((char *) mbPtr);
791 } else if (eventPtr->type == FocusIn) {
792 if (eventPtr->xfocus.detail != NotifyInferior) {
793 mbPtr->flags |= GOT_FOCUS;
794 if (mbPtr->highlightWidth > 0) {
795 goto redraw;
796 }
797 }
798 } else if (eventPtr->type == FocusOut) {
799 if (eventPtr->xfocus.detail != NotifyInferior) {
800 mbPtr->flags &= ~GOT_FOCUS;
801 if (mbPtr->highlightWidth > 0) {
802 goto redraw;
803 }
804 }
805 }
806 return;
807
808 redraw:
809 if ((mbPtr->tkwin != NULL) && !(mbPtr->flags & REDRAW_PENDING)) {
810 Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
811 mbPtr->flags |= REDRAW_PENDING;
812 }
813 }
814
815 /*
816 *----------------------------------------------------------------------
817 *
818 * MenuButtonCmdDeletedProc --
819 *
820 * This procedure is invoked when a widget command is deleted. If
821 * the widget isn't already in the process of being destroyed,
822 * this command destroys it.
823 *
824 * Results:
825 * None.
826 *
827 * Side effects:
828 * The widget is destroyed.
829 *
830 *----------------------------------------------------------------------
831 */
832
833 static void
834 MenuButtonCmdDeletedProc(clientData)
835 ClientData clientData; /* Pointer to widget record for widget. */
836 {
837 TkMenuButton *mbPtr = (TkMenuButton *) clientData;
838 Tk_Window tkwin = mbPtr->tkwin;
839
840 /*
841 * This procedure could be invoked either because the window was
842 * destroyed and the command was then deleted (in which case tkwin
843 * is NULL) or because the command was deleted, and then this procedure
844 * destroys the widget.
845 */
846
847 if (tkwin != NULL) {
848 Tk_DestroyWindow(tkwin);
849 }
850 }
851
852 /*
853 *--------------------------------------------------------------
854 *
855 * MenuButtonTextVarProc --
856 *
857 * This procedure is invoked when someone changes the variable
858 * whose contents are to be displayed in a menu button.
859 *
860 * Results:
861 * NULL is always returned.
862 *
863 * Side effects:
864 * The text displayed in the menu button will change to match the
865 * variable.
866 *
867 *--------------------------------------------------------------
868 */
869
870 /* ARGSUSED */
871 static char *
872 MenuButtonTextVarProc(clientData, interp, name1, name2, flags)
873 ClientData clientData; /* Information about button. */
874 Tcl_Interp *interp; /* Interpreter containing variable. */
875 char *name1; /* Name of variable. */
876 char *name2; /* Second part of variable name. */
877 int flags; /* Information about what happened. */
878 {
879 register TkMenuButton *mbPtr = (TkMenuButton *) clientData;
880 char *value;
881
882 /*
883 * If the variable is unset, then immediately recreate it unless
884 * the whole interpreter is going away.
885 */
886
887 if (flags & TCL_TRACE_UNSETS) {
888 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
889 Tcl_SetVar(interp, mbPtr->textVarName, mbPtr->text,
890 TCL_GLOBAL_ONLY);
891 Tcl_TraceVar(interp, mbPtr->textVarName,
892 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
893 MenuButtonTextVarProc, clientData);
894 }
895 return (char *) NULL;
896 }
897
898 value = Tcl_GetVar(interp, mbPtr->textVarName, TCL_GLOBAL_ONLY);
899 if (value == NULL) {
900 value = "";
901 }
902 if (mbPtr->text != NULL) {
903 ckfree(mbPtr->text);
904 }
905 mbPtr->text = (char *) ckalloc((unsigned) (strlen(value) + 1));
906 strcpy(mbPtr->text, value);
907 TkpComputeMenuButtonGeometry(mbPtr);
908
909 if ((mbPtr->tkwin != NULL) && Tk_IsMapped(mbPtr->tkwin)
910 && !(mbPtr->flags & REDRAW_PENDING)) {
911 Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
912 mbPtr->flags |= REDRAW_PENDING;
913 }
914 return (char *) NULL;
915 }
916
917 /*
918 *----------------------------------------------------------------------
919 *
920 * MenuButtonImageProc --
921 *
922 * This procedure is invoked by the image code whenever the manager
923 * for an image does something that affects the size of contents
924 * of an image displayed in a button.
925 *
926 * Results:
927 * None.
928 *
929 * Side effects:
930 * Arranges for the button to get redisplayed.
931 *
932 *----------------------------------------------------------------------
933 */
934
935 static void
936 MenuButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
937 ClientData clientData; /* Pointer to widget record. */
938 int x, y; /* Upper left pixel (within image)
939 * that must be redisplayed. */
940 int width, height; /* Dimensions of area to redisplay
941 * (may be <= 0). */
942 int imgWidth, imgHeight; /* New dimensions of image. */
943 {
944 register TkMenuButton *mbPtr = (TkMenuButton *) clientData;
945
946 if (mbPtr->tkwin != NULL) {
947 TkpComputeMenuButtonGeometry(mbPtr);
948 if (Tk_IsMapped(mbPtr->tkwin) && !(mbPtr->flags & REDRAW_PENDING)) {
949 Tcl_DoWhenIdle(TkpDisplayMenuButton, (ClientData) mbPtr);
950 mbPtr->flags |= REDRAW_PENDING;
951 }
952 }
953 }
954
955 /* End of tkmenubutton.c */

Properties

Name Value
svn:keywords Header

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25