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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 42 - (hide annotations) (download)
Fri Oct 14 01:50:00 2016 UTC (7 years, 5 months ago) by dashley
Original Path: projs/trunk/shared_source/tk_base/tkmenubutton.c
File MIME type: text/plain
File size: 30571 byte(s)
Move shared source code to commonize.
1 dashley 25 /* $Header: /cvsroot/esrg/sfesrg/esrgpcpj/shared/tk_base/tkmenubutton.c,v 1.1.1.1 2001/06/13 05:05:54 dtashley Exp $ */
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    
956     /* $History: tkMenubutton.c $
957     *
958     * ***************** Version 1 *****************
959     * User: Dtashley Date: 1/02/01 Time: 2:57a
960     * Created in $/IjuScripter, IjuConsole/Source/Tk Base
961     * Initial check-in.
962     */
963    
964     /* End of TKMENUBUTTON.C */

dashley@gmail.com
ViewVC Help
Powered by ViewVC 1.1.25