OSDN Git Service

2d74fffee9f7970a1ab9485da66fe4c139bd2dc6
[pf3gnuchains/pf3gnuchains3x.git] / tk / generic / tkButton.c
1 /* 
2  * tkButton.c --
3  *
4  *      This module implements a collection of button-like
5  *      widgets for the Tk toolkit.  The widgets implemented
6  *      include labels, buttons, checkbuttons, and radiobuttons.
7  *
8  * Copyright (c) 1990-1994 The Regents of the University of California.
9  * Copyright (c) 1994-1998 Sun Microsystems, Inc.
10  *
11  * See the file "license.terms" for information on usage and redistribution
12  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13  *
14  * RCS: @(#) $Id$
15  */
16
17 #include "tkButton.h"
18 #include "default.h"
19
20 typedef struct ThreadSpecificData { 
21     int defaultsInitialized;
22 } ThreadSpecificData;
23 static Tcl_ThreadDataKey dataKey;
24
25 /*
26  * Class names for buttons, indexed by one of the type values defined
27  * in tkButton.h.
28  */
29
30 static char *classNames[] = {"Label", "Button", "Checkbutton", "Radiobutton"};
31
32 /*
33  * The following table defines the legal values for the -default option.
34  * It is used together with the "enum defaultValue" declaration in tkButton.h.
35  */
36
37 static char *defaultStrings[] = {
38     "active", "disabled", "normal", (char *) NULL
39 };
40
41 /*
42  * The following table defines the legal values for the -state option.
43  * It is used together with the "enum state" declaration in tkButton.h.
44  */
45
46 static char *stateStrings[] = {
47     "active", "disabled", "normal", (char *) NULL
48 };
49
50 /*
51  * The following table defines the legal values for the -compound option.
52  * It is used with the "enum compound" declaration in tkButton.h
53  */
54
55 static char *compoundStrings[] = {
56     "bottom", "center", "left", "none", "right", "top", (char *) NULL
57 };
58
59 /*
60  * Information used for parsing configuration options.  There is a
61  * separate table for each of the four widget classes.
62  */
63
64 static Tk_OptionSpec labelOptionSpecs[] = {
65     {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground",
66         DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder),
67         0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0},
68     {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background",
69         DEF_BUTTON_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg),
70         TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0},
71     {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
72         DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0},
73     {TK_OPTION_BORDER, "-background", "background", "Background",
74         DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder),
75         0, (ClientData) DEF_BUTTON_BG_MONO, 0},
76     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
77         (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
78     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
79         (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
80     {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap",
81         DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap),
82         TK_OPTION_NULL_OK, 0, 0},
83     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
84         DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr),
85         Tk_Offset(TkButton, borderWidth), 0, 0, 0},
86     {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
87          DEF_BUTTON_COMPOUND, -1, Tk_Offset(TkButton, compound), 0,
88          (ClientData) compoundStrings, 0},
89     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
90         DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor),
91         TK_OPTION_NULL_OK, 0, 0},
92     {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
93         "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR,
94         -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK,
95         (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0},
96     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
97         (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
98     {TK_OPTION_FONT, "-font", "font", "Font",
99         DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0},
100     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
101         DEF_BUTTON_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0},
102     {TK_OPTION_STRING, "-height", "height", "Height",
103         DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0},
104     {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground",
105         "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR,
106         -1, Tk_Offset(TkButton, highlightBorder), 0,
107         (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0},
108     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
109         DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr),
110         0, 0, 0},
111     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
112         "HighlightThickness", DEF_LABEL_HIGHLIGHT_WIDTH,
113         Tk_Offset(TkButton, highlightWidthPtr),
114         Tk_Offset(TkButton, highlightWidth), 0, 0, 0},
115     {TK_OPTION_STRING, "-image", "image", "Image",
116         DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1,
117         TK_OPTION_NULL_OK, 0, 0},
118     {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
119         DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0},
120     {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
121         DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padXPtr),
122         Tk_Offset(TkButton, padX), 0, 0, 0},
123     {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
124         DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padYPtr),
125         Tk_Offset(TkButton, padY), 0, 0, 0},
126     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
127         DEF_LABCHKRAD_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0},
128     {TK_OPTION_STRING_TABLE, "-state", "state", "State",
129         DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state),
130         0, (ClientData) stateStrings, 0},
131     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
132         DEF_LABEL_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1,
133         TK_OPTION_NULL_OK, 0, 0},
134     {TK_OPTION_STRING, "-text", "text", "Text",
135         DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0},
136     {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
137         DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1,
138         TK_OPTION_NULL_OK, 0, 0},
139     {TK_OPTION_INT, "-underline", "underline", "Underline",
140         DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0},
141     {TK_OPTION_STRING, "-width", "width", "Width",
142         DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0},
143     {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength",
144         DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr),
145         Tk_Offset(TkButton, wrapLength), 0, 0, 0},
146     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
147         (char *) NULL, 0, 0, 0, 0}
148 };
149
150 static Tk_OptionSpec buttonOptionSpecs[] = {
151     {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground",
152         DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder),
153         0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0},
154     {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background",
155         DEF_BUTTON_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg),
156         TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0},
157     {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
158         DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0},
159     {TK_OPTION_BORDER, "-background", "background", "Background",
160         DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder),
161         0, (ClientData) DEF_BUTTON_BG_MONO, 0},
162     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
163         (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
164     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
165         (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
166     {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap",
167         DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap),
168         TK_OPTION_NULL_OK, 0, 0},
169     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
170         DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr),
171         Tk_Offset(TkButton, borderWidth), 0, 0, 0},
172     {TK_OPTION_STRING, "-command", "command", "Command",
173         DEF_BUTTON_COMMAND, Tk_Offset(TkButton, commandPtr), -1,
174         TK_OPTION_NULL_OK, 0, 0},
175     {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
176          DEF_BUTTON_COMPOUND, -1, Tk_Offset(TkButton, compound), 0,
177          (ClientData) compoundStrings, 0},
178     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
179         DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor),
180         TK_OPTION_NULL_OK, 0, 0},
181     {TK_OPTION_STRING_TABLE, "-default", "default", "Default",
182         DEF_BUTTON_DEFAULT, -1, Tk_Offset(TkButton, defaultState),
183         0, (ClientData) defaultStrings, 0},
184     {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
185         "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR,
186         -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK,
187         (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0},
188     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
189         (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
190     {TK_OPTION_FONT, "-font", "font", "Font",
191         DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0},
192     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
193         DEF_BUTTON_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0},
194     {TK_OPTION_STRING, "-height", "height", "Height",
195         DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0},
196     {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground",
197         "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR,
198         -1, Tk_Offset(TkButton, highlightBorder), 0,
199         (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0},
200     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
201         DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr),
202         0, 0, 0},
203     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
204         "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH,
205         Tk_Offset(TkButton, highlightWidthPtr),
206         Tk_Offset(TkButton, highlightWidth), 0, 0, 0},
207     {TK_OPTION_STRING, "-image", "image", "Image",
208         DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1,
209         TK_OPTION_NULL_OK, 0, 0},
210     {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
211         DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0},
212     {TK_OPTION_RELIEF, "-overrelief", "overRelief", "OverRelief",
213          DEF_BUTTON_OVER_RELIEF, -1, Tk_Offset(TkButton, overRelief),
214          TK_OPTION_NULL_OK, 0, 0},
215     {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
216         DEF_BUTTON_PADX, Tk_Offset(TkButton, padXPtr),
217         Tk_Offset(TkButton, padX), 0, 0, 0},
218     {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
219         DEF_BUTTON_PADY, Tk_Offset(TkButton, padYPtr),
220         Tk_Offset(TkButton, padY), 0, 0, 0},
221     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
222         DEF_BUTTON_RELIEF, -1, Tk_Offset(TkButton, relief),
223          0, 0, 0},
224     {TK_OPTION_INT, "-repeatdelay", "repeatDelay", "RepeatDelay",
225          DEF_BUTTON_REPEAT_DELAY, -1, Tk_Offset(TkButton, repeatDelay),
226          0, 0, 0},
227     {TK_OPTION_INT, "-repeatinterval", "repeatInterval", "RepeatInterval",
228          DEF_BUTTON_REPEAT_INTERVAL, -1, Tk_Offset(TkButton, repeatInterval),
229          0, 0, 0},
230     {TK_OPTION_STRING_TABLE, "-state", "state", "State",
231         DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state),
232         0, (ClientData) stateStrings, 0},
233     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
234         DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1,
235         TK_OPTION_NULL_OK, 0, 0},
236     {TK_OPTION_STRING, "-text", "text", "Text",
237         DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0},
238     {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
239         DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1,
240         TK_OPTION_NULL_OK, 0, 0},
241     {TK_OPTION_INT, "-underline", "underline", "Underline",
242         DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0},
243     {TK_OPTION_STRING, "-width", "width", "Width",
244         DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0},
245     {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength",
246         DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr),
247         Tk_Offset(TkButton, wrapLength), 0, 0, 0},
248     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
249         (char *) NULL, 0, -1, 0, 0, 0}
250 };
251
252 static Tk_OptionSpec checkbuttonOptionSpecs[] = {
253     {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground",
254         DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder),
255         0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0},
256     {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background",
257         DEF_CHKRAD_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg),
258         TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0},
259     {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
260         DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0},
261     {TK_OPTION_BORDER, "-background", "background", "Background",
262         DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder),
263         0, (ClientData) DEF_BUTTON_BG_MONO, 0},
264     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
265         (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
266     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
267         (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
268     {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap",
269         DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap),
270         TK_OPTION_NULL_OK, 0, 0},
271     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
272         DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr),
273         Tk_Offset(TkButton, borderWidth), 0, 0, 0},
274     {TK_OPTION_STRING, "-command", "command", "Command",
275         DEF_BUTTON_COMMAND, Tk_Offset(TkButton, commandPtr), -1,
276         TK_OPTION_NULL_OK, 0, 0},
277     {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
278          DEF_BUTTON_COMPOUND, -1, Tk_Offset(TkButton, compound), 0,
279          (ClientData) compoundStrings, 0},
280     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
281         DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor),
282         TK_OPTION_NULL_OK, 0, 0},
283     {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
284         "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR,
285         -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK,
286         (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0},
287     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
288         (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
289     {TK_OPTION_FONT, "-font", "font", "Font",
290         DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0},
291     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
292         DEF_CHKRAD_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0},
293     {TK_OPTION_STRING, "-height", "height", "Height",
294         DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0},
295     {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground",
296         "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR,
297         -1, Tk_Offset(TkButton, highlightBorder), 0,
298         (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0},
299     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
300         DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr),
301         0, 0, 0},
302     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
303         "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH,
304         Tk_Offset(TkButton, highlightWidthPtr),
305         Tk_Offset(TkButton, highlightWidth), 0, 0, 0},
306     {TK_OPTION_STRING, "-image", "image", "Image",
307         DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1,
308         TK_OPTION_NULL_OK, 0, 0},
309     {TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn",
310         DEF_BUTTON_INDICATOR, -1, Tk_Offset(TkButton, indicatorOn), 0, 0, 0},
311     {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
312         DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0},
313     {TK_OPTION_RELIEF, "-offrelief", "offRelief", "OffRelief",
314          DEF_BUTTON_RELIEF, -1, Tk_Offset(TkButton, offRelief), 0, 0, 0},
315     {TK_OPTION_STRING, "-offvalue", "offValue", "Value",
316         DEF_BUTTON_OFF_VALUE, Tk_Offset(TkButton, offValuePtr), -1, 0, 0, 0},
317     {TK_OPTION_STRING, "-onvalue", "onValue", "Value",
318         DEF_BUTTON_ON_VALUE, Tk_Offset(TkButton, onValuePtr), -1, 0, 0, 0},
319     {TK_OPTION_RELIEF, "-overrelief", "overRelief", "OverRelief",
320          DEF_BUTTON_OVER_RELIEF, -1, Tk_Offset(TkButton, overRelief),
321          TK_OPTION_NULL_OK, 0, 0},
322     {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
323         DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padXPtr),
324         Tk_Offset(TkButton, padX), 0, 0, 0},
325     {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
326         DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padYPtr),
327         Tk_Offset(TkButton, padY), 0, 0, 0},
328     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
329         DEF_LABCHKRAD_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0},
330     {TK_OPTION_BORDER, "-selectcolor", "selectColor", "Background",
331         DEF_BUTTON_SELECT_COLOR, -1, Tk_Offset(TkButton, selectBorder),
332         TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_SELECT_MONO, 0},
333     {TK_OPTION_STRING, "-selectimage", "selectImage", "SelectImage",
334         DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImagePtr), -1,
335         TK_OPTION_NULL_OK, 0, 0},
336     {TK_OPTION_STRING_TABLE, "-state", "state", "State",
337         DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state),
338         0, (ClientData) stateStrings, 0},
339     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
340         DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1,
341         TK_OPTION_NULL_OK, 0, 0},
342     {TK_OPTION_STRING, "-text", "text", "Text",
343         DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0},
344     {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
345         DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1,
346         TK_OPTION_NULL_OK, 0, 0},
347     {TK_OPTION_INT, "-underline", "underline", "Underline",
348         DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0},
349     {TK_OPTION_STRING, "-variable", "variable", "Variable",
350         DEF_CHECKBUTTON_VARIABLE, Tk_Offset(TkButton, selVarNamePtr), -1,
351         TK_OPTION_NULL_OK, 0, 0},
352     {TK_OPTION_STRING, "-width", "width", "Width",
353         DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0},
354     {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength",
355         DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr),
356         Tk_Offset(TkButton, wrapLength), 0, 0, 0},
357     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
358         (char *) NULL, 0, -1, 0, 0, 0}
359 };
360
361 static Tk_OptionSpec radiobuttonOptionSpecs[] = {
362     {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Foreground",
363         DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(TkButton, activeBorder),
364         0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0},
365     {TK_OPTION_COLOR, "-activeforeground", "activeForeground", "Background",
366         DEF_CHKRAD_ACTIVE_FG_COLOR, -1, Tk_Offset(TkButton, activeFg),
367         TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_ACTIVE_FG_MONO, 0},
368     {TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
369         DEF_BUTTON_ANCHOR, -1, Tk_Offset(TkButton, anchor), 0, 0, 0},
370     {TK_OPTION_BORDER, "-background", "background", "Background",
371         DEF_BUTTON_BG_COLOR, -1, Tk_Offset(TkButton, normalBorder),
372         0, (ClientData) DEF_BUTTON_BG_MONO, 0},
373     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
374         (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
375     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
376         (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
377     {TK_OPTION_BITMAP, "-bitmap", "bitmap", "Bitmap",
378         DEF_BUTTON_BITMAP, -1, Tk_Offset(TkButton, bitmap),
379         TK_OPTION_NULL_OK, 0, 0},
380     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
381         DEF_BUTTON_BORDER_WIDTH, Tk_Offset(TkButton, borderWidthPtr),
382         Tk_Offset(TkButton, borderWidth), 0, 0, 0},
383     {TK_OPTION_STRING, "-command", "command", "Command",
384         DEF_BUTTON_COMMAND, Tk_Offset(TkButton, commandPtr), -1,
385         TK_OPTION_NULL_OK, 0, 0},
386     {TK_OPTION_STRING_TABLE, "-compound", "compound", "Compound",
387          DEF_BUTTON_COMPOUND, -1, Tk_Offset(TkButton, compound), 0,
388          (ClientData) compoundStrings, 0},
389     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
390         DEF_BUTTON_CURSOR, -1, Tk_Offset(TkButton, cursor),
391         TK_OPTION_NULL_OK, 0, 0},
392     {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
393         "DisabledForeground", DEF_BUTTON_DISABLED_FG_COLOR,
394         -1, Tk_Offset(TkButton, disabledFg), TK_OPTION_NULL_OK,
395         (ClientData) DEF_BUTTON_DISABLED_FG_MONO, 0},
396     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
397         (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
398     {TK_OPTION_FONT, "-font", "font", "Font",
399         DEF_BUTTON_FONT, -1, Tk_Offset(TkButton, tkfont), 0, 0, 0},
400     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
401         DEF_CHKRAD_FG, -1, Tk_Offset(TkButton, normalFg), 0, 0, 0},
402     {TK_OPTION_STRING, "-height", "height", "Height",
403         DEF_BUTTON_HEIGHT, Tk_Offset(TkButton, heightPtr), -1, 0, 0, 0},
404     {TK_OPTION_BORDER, "-highlightbackground", "highlightBackground",
405         "HighlightBackground", DEF_BUTTON_HIGHLIGHT_BG_COLOR,
406         -1, Tk_Offset(TkButton, highlightBorder), 0,
407         (ClientData) DEF_BUTTON_HIGHLIGHT_BG_MONO, 0},
408     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
409         DEF_BUTTON_HIGHLIGHT, -1, Tk_Offset(TkButton, highlightColorPtr),
410         0, 0, 0},
411     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
412         "HighlightThickness", DEF_BUTTON_HIGHLIGHT_WIDTH,
413         Tk_Offset(TkButton, highlightWidthPtr),
414         Tk_Offset(TkButton, highlightWidth), 0, 0, 0},
415     {TK_OPTION_STRING, "-image", "image", "Image",
416         DEF_BUTTON_IMAGE, Tk_Offset(TkButton, imagePtr), -1,
417         TK_OPTION_NULL_OK, 0, 0},
418     {TK_OPTION_BOOLEAN, "-indicatoron", "indicatorOn", "IndicatorOn",
419         DEF_BUTTON_INDICATOR, -1, Tk_Offset(TkButton, indicatorOn),
420         0, 0, 0},
421     {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
422         DEF_BUTTON_JUSTIFY, -1, Tk_Offset(TkButton, justify), 0, 0, 0},
423     {TK_OPTION_RELIEF, "-offrelief", "offRelief", "OffRelief",
424          DEF_BUTTON_RELIEF, -1, Tk_Offset(TkButton, offRelief), 0, 0, 0},
425     {TK_OPTION_RELIEF, "-overrelief", "overRelief", "OverRelief",
426          DEF_BUTTON_OVER_RELIEF, -1, Tk_Offset(TkButton, overRelief),
427          TK_OPTION_NULL_OK, 0, 0},
428     {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
429         DEF_LABCHKRAD_PADX, Tk_Offset(TkButton, padXPtr),
430         Tk_Offset(TkButton, padX), 0, 0, 0},
431     {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
432         DEF_LABCHKRAD_PADY, Tk_Offset(TkButton, padYPtr),
433         Tk_Offset(TkButton, padY), 0, 0, 0},
434     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
435         DEF_LABCHKRAD_RELIEF, -1, Tk_Offset(TkButton, relief), 0, 0, 0},
436     {TK_OPTION_BORDER, "-selectcolor", "selectColor", "Background",
437         DEF_BUTTON_SELECT_COLOR, -1, Tk_Offset(TkButton, selectBorder),
438         TK_OPTION_NULL_OK, (ClientData) DEF_BUTTON_SELECT_MONO, 0},
439     {TK_OPTION_STRING, "-selectimage", "selectImage", "SelectImage",
440         DEF_BUTTON_SELECT_IMAGE, Tk_Offset(TkButton, selectImagePtr), -1,
441         TK_OPTION_NULL_OK, 0, 0},
442     {TK_OPTION_STRING_TABLE, "-state", "state", "State",
443         DEF_BUTTON_STATE, -1, Tk_Offset(TkButton, state),
444         0, (ClientData) stateStrings, 0},
445     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
446         DEF_BUTTON_TAKE_FOCUS, Tk_Offset(TkButton, takeFocusPtr), -1,
447         TK_OPTION_NULL_OK, 0, 0},
448     {TK_OPTION_STRING, "-text", "text", "Text",
449         DEF_BUTTON_TEXT, Tk_Offset(TkButton, textPtr), -1, 0, 0, 0},
450     {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
451         DEF_BUTTON_TEXT_VARIABLE, Tk_Offset(TkButton, textVarNamePtr), -1,
452         TK_OPTION_NULL_OK, 0, 0},
453     {TK_OPTION_INT, "-underline", "underline", "Underline",
454         DEF_BUTTON_UNDERLINE, -1, Tk_Offset(TkButton, underline), 0, 0, 0},
455     {TK_OPTION_STRING, "-value", "value", "Value",
456         DEF_BUTTON_VALUE, Tk_Offset(TkButton, onValuePtr), -1, 0, 0, 0},
457     {TK_OPTION_STRING, "-variable", "variable", "Variable",
458         DEF_RADIOBUTTON_VARIABLE, Tk_Offset(TkButton, selVarNamePtr), -1,
459         0, 0, 0},
460     {TK_OPTION_STRING, "-width", "width", "Width",
461         DEF_BUTTON_WIDTH, Tk_Offset(TkButton, widthPtr), -1, 0, 0, 0},
462     {TK_OPTION_PIXELS, "-wraplength", "wrapLength", "WrapLength",
463         DEF_BUTTON_WRAP_LENGTH, Tk_Offset(TkButton, wrapLengthPtr),
464         Tk_Offset(TkButton, wrapLength), 0, 0, 0},
465     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
466         (char *) NULL, 0, -1, 0, 0, 0}
467 };
468
469 /*
470  * The following table maps from one of the type values defined in
471  * tkButton.h, such as TYPE_LABEL, to the option template for that
472  * class of widgets.
473  */
474
475 static Tk_OptionSpec *optionSpecs[] = {
476     labelOptionSpecs,
477     buttonOptionSpecs,
478     checkbuttonOptionSpecs,
479     radiobuttonOptionSpecs
480 };
481
482 /*
483  * The following tables define the widget commands supported by
484  * each of the classes, and map the indexes into the string tables
485  * into a single enumerated type used to dispatch the widget command.
486  */
487
488 static CONST char *commandNames[][8] = {
489     {"cget", "configure", (char *) NULL},
490     {"cget", "configure", "flash", "invoke", (char *) NULL},
491     {"cget", "configure", "deselect", "flash", "invoke", "select",
492             "toggle", (char *) NULL},
493     {"cget", "configure", "deselect", "flash", "invoke", "select",
494             (char *) NULL}
495 };
496 enum command {
497     COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DESELECT, COMMAND_FLASH,
498     COMMAND_INVOKE, COMMAND_SELECT, COMMAND_TOGGLE
499 };
500 static enum command map[][8] = {
501     {COMMAND_CGET, COMMAND_CONFIGURE},
502     {COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_FLASH, COMMAND_INVOKE},
503     {COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DESELECT, COMMAND_FLASH,
504             COMMAND_INVOKE, COMMAND_SELECT, COMMAND_TOGGLE},
505     {COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DESELECT, COMMAND_FLASH,
506             COMMAND_INVOKE, COMMAND_SELECT}
507 };
508
509 /*
510  * Forward declarations for procedures defined later in this file:
511  */
512
513 static void             ButtonCmdDeletedProc _ANSI_ARGS_((
514                             ClientData clientData));
515 static int              ButtonCreate _ANSI_ARGS_((ClientData clientData,
516                             Tcl_Interp *interp, int objc,
517                             Tcl_Obj *CONST objv[], int type));
518 static void             ButtonEventProc _ANSI_ARGS_((ClientData clientData,
519                             XEvent *eventPtr));
520 static void             ButtonImageProc _ANSI_ARGS_((ClientData clientData,
521                             int x, int y, int width, int height,
522                             int imgWidth, int imgHeight));
523 static void             ButtonSelectImageProc _ANSI_ARGS_((
524                             ClientData clientData, int x, int y, int width,
525                             int height, int imgWidth, int imgHeight));
526 static char *           ButtonTextVarProc _ANSI_ARGS_((ClientData clientData,
527                             Tcl_Interp *interp, CONST char *name1,
528                             CONST char *name2, int flags));
529 static char *           ButtonVarProc _ANSI_ARGS_((ClientData clientData,
530                             Tcl_Interp *interp, CONST char *name1,
531                             CONST char *name2, int flags));
532 static int              ButtonWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
533                             Tcl_Interp *interp, int objc,
534                             Tcl_Obj *CONST objv[]));
535 static int              ConfigureButton _ANSI_ARGS_((Tcl_Interp *interp,
536                             TkButton *butPtr, int objc,
537                             Tcl_Obj *CONST objv[]));
538 static void             DestroyButton _ANSI_ARGS_((TkButton *butPtr));
539 \f
540 /*
541  *--------------------------------------------------------------
542  *
543  * Tk_ButtonCmd, Tk_CheckbuttonCmd, Tk_LabelCmd, Tk_RadiobuttonCmd --
544  *
545  *      These procedures are invoked to process the "button", "label",
546  *      "radiobutton", and "checkbutton" Tcl commands.  See the
547  *      user documentation for details on what they do.
548  *
549  * Results:
550  *      A standard Tcl result.
551  *
552  * Side effects:
553  *      See the user documentation.  These procedures are just wrappers;
554  *      they call ButtonCreate to do all of the real work.
555  *
556  *--------------------------------------------------------------
557  */
558
559 int
560 Tk_ButtonObjCmd(clientData, interp, objc, objv)
561     ClientData clientData;      /* Either NULL or pointer to option table. */
562     Tcl_Interp *interp;         /* Current interpreter. */
563     int objc;                   /* Number of arguments. */
564     Tcl_Obj *CONST objv[];      /* Argument values. */
565 {
566     return ButtonCreate(clientData, interp, objc, objv, TYPE_BUTTON);
567 }
568
569 int
570 Tk_CheckbuttonObjCmd(clientData, interp, objc, objv)
571     ClientData clientData;      /* Either NULL or pointer to option table. */
572     Tcl_Interp *interp;         /* Current interpreter. */
573     int objc;                   /* Number of arguments. */
574     Tcl_Obj *CONST objv[];      /* Argument values. */
575 {
576     return ButtonCreate(clientData, interp, objc, objv, TYPE_CHECK_BUTTON);
577 }
578
579 int
580 Tk_LabelObjCmd(clientData, interp, objc, objv)
581     ClientData clientData;      /* Either NULL or pointer to option table. */
582     Tcl_Interp *interp;         /* Current interpreter. */
583     int objc;                   /* Number of arguments. */
584     Tcl_Obj *CONST objv[];      /* Argument values. */
585 {
586     return ButtonCreate(clientData, interp, objc, objv, TYPE_LABEL);
587 }
588
589 int
590 Tk_RadiobuttonObjCmd(clientData, interp, objc, objv)
591     ClientData clientData;      /* Either NULL or pointer to option table. */
592     Tcl_Interp *interp;         /* Current interpreter. */
593     int objc;                   /* Number of arguments. */
594     Tcl_Obj *CONST objv[];      /* Argument values. */
595 {
596     return ButtonCreate(clientData, interp, objc, objv, TYPE_RADIO_BUTTON);
597 }
598 \f
599 /*
600  *--------------------------------------------------------------
601  *
602  * ButtonCreate --
603  *
604  *      This procedure does all the real work of implementing the
605  *      "button", "label", "radiobutton", and "checkbutton" Tcl
606  *      commands.  See the user documentation for details on what it does.
607  *
608  * Results:
609  *      A standard Tcl result.
610  *
611  * Side effects:
612  *      See the user documentation.
613  *
614  *--------------------------------------------------------------
615  */
616
617 static int
618 ButtonCreate(clientData, interp, objc, objv, type)
619     ClientData clientData;      /* NULL. */
620     Tcl_Interp *interp;         /* Current interpreter. */
621     int objc;                   /* Number of arguments. */
622     Tcl_Obj *CONST objv[];      /* Argument values. */
623     int type;                   /* Type of button to create: TYPE_LABEL,
624                                  * TYPE_BUTTON, TYPE_CHECK_BUTTON, or
625                                  * TYPE_RADIO_BUTTON. */
626 {
627     TkButton *butPtr;
628     Tk_OptionTable optionTable;
629     Tk_Window tkwin;
630     ThreadSpecificData *tsdPtr = (ThreadSpecificData *) 
631         Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
632
633     if (!tsdPtr->defaultsInitialized) {
634         TkpButtonSetDefaults(optionSpecs[type]);
635         tsdPtr->defaultsInitialized = 1;
636     }
637
638     if (objc < 2) {
639         Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
640         return TCL_ERROR;
641     }
642
643     /*
644      * Create the new window.
645      */
646
647     tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
648             Tcl_GetString(objv[1]), (char *) NULL);
649     if (tkwin == NULL) {
650         return TCL_ERROR;
651     }
652
653     /*
654      * Create the option table for this widget class.  If it has already
655      * been created, the cached pointer will be returned.
656      */
657
658     optionTable = Tk_CreateOptionTable(interp, optionSpecs[type]);
659
660     Tk_SetClass(tkwin, classNames[type]);
661     butPtr = TkpCreateButton(tkwin);
662
663     Tk_SetClassProcs(tkwin, &tkpButtonProcs, (ClientData) butPtr);
664
665     /*
666      * Initialize the data structure for the button.
667      */
668
669     butPtr->tkwin = tkwin;
670     butPtr->display = Tk_Display(tkwin);
671     butPtr->interp = interp;
672     butPtr->widgetCmd = Tcl_CreateObjCommand(interp, Tk_PathName(tkwin),
673             ButtonWidgetObjCmd, (ClientData) butPtr, ButtonCmdDeletedProc);
674     butPtr->type = type;
675     butPtr->optionTable = optionTable;
676     butPtr->textPtr = NULL;
677     butPtr->underline = -1;
678     butPtr->textVarNamePtr = NULL;
679     butPtr->bitmap = None;
680     butPtr->imagePtr = NULL;
681     butPtr->image = NULL;
682     butPtr->selectImagePtr = NULL;
683     butPtr->selectImage = NULL;
684     butPtr->state = STATE_NORMAL;
685     butPtr->normalBorder = NULL;
686     butPtr->activeBorder = NULL;
687     butPtr->borderWidthPtr = NULL;
688     butPtr->borderWidth = 0;
689     butPtr->relief = TK_RELIEF_FLAT;
690     butPtr->highlightWidthPtr = NULL;
691     butPtr->highlightWidth = 0;
692     butPtr->highlightBorder = NULL;
693     butPtr->highlightColorPtr = NULL;
694     butPtr->inset = 0;
695     butPtr->tkfont = NULL;
696     butPtr->normalFg = NULL;
697     butPtr->activeFg = NULL;
698     butPtr->disabledFg = NULL;
699     butPtr->normalTextGC = None;
700     butPtr->activeTextGC = None;
701     butPtr->disabledGC = None;
702     butPtr->gray = None;
703     butPtr->copyGC = None;
704     butPtr->widthPtr = NULL;
705     butPtr->width = 0;
706     butPtr->heightPtr = NULL;
707     butPtr->height = 0;
708     butPtr->wrapLengthPtr = NULL;
709     butPtr->wrapLength = 0;
710     butPtr->padXPtr = NULL;
711     butPtr->padX = 0;
712     butPtr->padYPtr = NULL;
713     butPtr->padY = 0;
714     butPtr->anchor = TK_ANCHOR_CENTER;
715     butPtr->justify = TK_JUSTIFY_CENTER;
716     butPtr->indicatorOn = 0;
717     butPtr->selectBorder = NULL;
718     butPtr->textWidth = 0;
719     butPtr->textHeight = 0;
720     butPtr->textLayout = NULL;
721     butPtr->indicatorSpace = 0;
722     butPtr->indicatorDiameter = 0;
723     butPtr->defaultState = DEFAULT_DISABLED;
724     butPtr->selVarNamePtr = NULL;
725     butPtr->onValuePtr = NULL;
726     butPtr->offValuePtr = NULL;
727     butPtr->cursor = None;
728     butPtr->takeFocusPtr = NULL;
729     butPtr->commandPtr = NULL;
730     butPtr->flags = 0;
731
732     Tk_CreateEventHandler(butPtr->tkwin,
733             ExposureMask|StructureNotifyMask|FocusChangeMask,
734             ButtonEventProc, (ClientData) butPtr);
735
736     if (Tk_InitOptions(interp, (char *) butPtr, optionTable, tkwin)
737             != TCL_OK) {
738         Tk_DestroyWindow(butPtr->tkwin);
739         return TCL_ERROR;
740     }
741     if (ConfigureButton(interp, butPtr, objc - 2, objv + 2) != TCL_OK) {
742         Tk_DestroyWindow(butPtr->tkwin);
743         return TCL_ERROR;
744     }
745
746     Tcl_SetStringObj(Tcl_GetObjResult(interp), Tk_PathName(butPtr->tkwin),
747             -1);
748     return TCL_OK;
749 }
750 \f
751 /*
752  *--------------------------------------------------------------
753  *
754  * ButtonWidgetCmd --
755  *
756  *      This procedure is invoked to process the Tcl command
757  *      that corresponds to a widget managed by this module.
758  *      See the user documentation for details on what it does.
759  *
760  * Results:
761  *      A standard Tcl result.
762  *
763  * Side effects:
764  *      See the user documentation.
765  *
766  *--------------------------------------------------------------
767  */
768
769 static int
770 ButtonWidgetObjCmd(clientData, interp, objc, objv)
771     ClientData clientData;      /* Information about button widget. */
772     Tcl_Interp *interp;         /* Current interpreter. */
773     int objc;                   /* Number of arguments. */
774     Tcl_Obj *CONST objv[];      /* Argument values. */
775 {
776     TkButton *butPtr = (TkButton *) clientData;
777     int index;
778     int result;
779     Tcl_Obj *objPtr;
780
781     if (objc < 2) {
782         Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
783         return TCL_ERROR;
784     }
785     result = Tcl_GetIndexFromObj(interp, objv[1], commandNames[butPtr->type],
786             "option", 0, &index);
787     if (result != TCL_OK) {
788         return result;
789     }
790     Tcl_Preserve((ClientData) butPtr);
791
792     switch (map[butPtr->type][index]) {
793         case COMMAND_CGET: {
794             if (objc != 3) {
795                 Tcl_WrongNumArgs(interp, 1, objv, "cget option");
796                 goto error;
797             }
798             objPtr = Tk_GetOptionValue(interp, (char *) butPtr,
799                     butPtr->optionTable, objv[2], butPtr->tkwin);
800             if (objPtr == NULL) {
801                  goto error;
802             } else {
803                 Tcl_SetObjResult(interp, objPtr);
804             }
805             break;
806         }
807
808         case COMMAND_CONFIGURE: {
809             if (objc <= 3) {
810                 objPtr = Tk_GetOptionInfo(interp, (char *) butPtr,
811                         butPtr->optionTable,
812                         (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
813                         butPtr->tkwin);
814                 if (objPtr == NULL) {
815                     goto error;
816                 } else {
817                     Tcl_SetObjResult(interp, objPtr);
818                 }
819             } else {
820                 result = ConfigureButton(interp, butPtr, objc-2, objv+2);
821             }
822             break;
823         }
824
825         case COMMAND_DESELECT: {
826             if (objc > 2) {
827                 Tcl_WrongNumArgs(interp, 1, objv, "deselect");
828                 goto error;
829             }
830             if (butPtr->type == TYPE_CHECK_BUTTON) {
831                 if (Tcl_ObjSetVar2(interp, butPtr->selVarNamePtr, NULL,
832                         butPtr->offValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
833                         == NULL) {
834                     goto error;
835                 }
836             } else if (butPtr->flags & SELECTED) {
837                 if (Tcl_ObjSetVar2(interp,
838                         butPtr->selVarNamePtr, NULL, Tcl_NewObj(),
839                         TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
840                         == NULL) {
841                     goto error;
842                 }
843             }
844             break;
845         }
846
847         case COMMAND_FLASH: {
848             int i;
849
850             if (objc > 2) {
851                 Tcl_WrongNumArgs(interp, 1, objv, "flash");
852                 goto error;
853             }
854             if (butPtr->state != STATE_DISABLED) {
855                 for (i = 0; i < 4; i++) {
856                     if (butPtr->state == STATE_NORMAL) {
857                         butPtr->state = STATE_ACTIVE; 
858                         Tk_SetBackgroundFromBorder(butPtr->tkwin,
859                                 butPtr->activeBorder);
860                     } else {
861                         butPtr->state = STATE_NORMAL; 
862                         Tk_SetBackgroundFromBorder(butPtr->tkwin,
863                                 butPtr->normalBorder);
864                     }
865                     TkpDisplayButton((ClientData) butPtr);
866     
867                     /*
868                      * Special note: must cancel any existing idle handler
869                      * for TkpDisplayButton;  it's no longer needed, and
870                      * TkpDisplayButton cleared the REDRAW_PENDING flag.
871                      */
872     
873                     Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr);
874                     XFlush(butPtr->display);
875                     Tcl_Sleep(50);
876                 }
877             }
878             break;
879         }
880
881         case COMMAND_INVOKE: {
882             if (objc > 2) {
883                 Tcl_WrongNumArgs(interp, 1, objv, "invoke");
884                 goto error;
885             }
886             if (butPtr->state != STATE_DISABLED) {
887                 result = TkInvokeButton(butPtr);
888             }
889             break;
890         }
891
892         case COMMAND_SELECT: {
893             if (objc > 2) {
894                 Tcl_WrongNumArgs(interp, 1, objv, "select");
895                 goto error;
896             }
897             if (Tcl_ObjSetVar2(interp, butPtr->selVarNamePtr, NULL,
898                     butPtr->onValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
899                     == NULL) {
900                 goto error;
901             }
902             break;
903         }
904
905         case COMMAND_TOGGLE: {
906             if (objc > 2) {
907                 Tcl_WrongNumArgs(interp, 1, objv, "toggle");
908                 goto error;
909             }
910             if (Tcl_ObjSetVar2(interp, butPtr->selVarNamePtr, NULL,
911                     (butPtr->flags & SELECTED) ? butPtr->offValuePtr
912                     : butPtr->onValuePtr,
913                     TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
914                     == NULL) {
915                 goto error;
916             }
917             break;
918         }
919     }
920     Tcl_Release((ClientData) butPtr);
921     return result;
922
923     error:
924     Tcl_Release((ClientData) butPtr);
925     return TCL_ERROR;
926 }
927 \f
928 /*
929  *----------------------------------------------------------------------
930  *
931  * DestroyButton --
932  *
933  *      This procedure is invoked by ButtonEventProc to free all the
934  *      resources of a button and clean up its state.
935  *
936  * Results:
937  *      None.
938  *
939  * Side effects:
940  *      Everything associated with the widget is freed.
941  *
942  *----------------------------------------------------------------------
943  */
944
945 static void
946 DestroyButton(butPtr)
947     TkButton *butPtr;           /* Info about button widget. */
948 {
949     butPtr->flags |= BUTTON_DELETED;
950     TkpDestroyButton(butPtr);
951
952     if (butPtr->flags & REDRAW_PENDING) {
953         Tcl_CancelIdleCall(TkpDisplayButton, (ClientData) butPtr);
954     }
955
956     /*
957      * Free up all the stuff that requires special handling, then
958      * let Tk_FreeOptions handle all the standard option-related
959      * stuff.
960      */
961
962     Tcl_DeleteCommandFromToken(butPtr->interp, butPtr->widgetCmd);
963     if (butPtr->textVarNamePtr != NULL) {
964         Tcl_UntraceVar(butPtr->interp, Tcl_GetString(butPtr->textVarNamePtr),
965                 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
966                 ButtonTextVarProc, (ClientData) butPtr);
967     }
968     if (butPtr->image != NULL) {
969         Tk_FreeImage(butPtr->image);
970     }
971     if (butPtr->selectImage != NULL) {
972         Tk_FreeImage(butPtr->selectImage);
973     }
974     if (butPtr->normalTextGC != None) {
975         Tk_FreeGC(butPtr->display, butPtr->normalTextGC);
976     }
977     if (butPtr->activeTextGC != None) {
978         Tk_FreeGC(butPtr->display, butPtr->activeTextGC);
979     }
980     if (butPtr->disabledGC != None) {
981         Tk_FreeGC(butPtr->display, butPtr->disabledGC);
982     }
983     if (butPtr->gray != None) {
984         Tk_FreeBitmap(butPtr->display, butPtr->gray);
985     }
986     if (butPtr->copyGC != None) {
987         Tk_FreeGC(butPtr->display, butPtr->copyGC);
988     }
989     if (butPtr->textLayout != NULL) {
990         Tk_FreeTextLayout(butPtr->textLayout);
991     }
992     if (butPtr->selVarNamePtr != NULL) {
993         Tcl_UntraceVar(butPtr->interp, Tcl_GetString(butPtr->selVarNamePtr),
994                 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
995                 ButtonVarProc, (ClientData) butPtr);
996     }
997     Tk_FreeConfigOptions((char *) butPtr, butPtr->optionTable,
998             butPtr->tkwin);
999     butPtr->tkwin = NULL;
1000     Tcl_EventuallyFree((ClientData) butPtr, TCL_DYNAMIC);
1001 }
1002 \f
1003 /*
1004  *----------------------------------------------------------------------
1005  *
1006  * ConfigureButton --
1007  *
1008  *      This procedure is called to process an objc/objv list to set
1009  *      configuration options for a button widget.
1010  *
1011  * Results:
1012  *      The return value is a standard Tcl result.  If TCL_ERROR is
1013  *      returned, then an error message is left in interp's result.
1014  *
1015  * Side effects:
1016  *      Configuration information, such as text string, colors, font,
1017  *      etc. get set for butPtr;  old resources get freed, if there
1018  *      were any.  The button is redisplayed.
1019  *
1020  *----------------------------------------------------------------------
1021  */
1022
1023 static int
1024 ConfigureButton(interp, butPtr, objc, objv)
1025     Tcl_Interp *interp;         /* Used for error reporting. */
1026     register TkButton *butPtr;  /* Information about widget;  may or may
1027                                  * not already have values for some fields. */
1028     int objc;                   /* Number of arguments. */
1029     Tcl_Obj *CONST objv[];      /* Argument values. */
1030 {
1031     Tk_SavedOptions savedOptions;
1032     Tcl_Obj *errorResult = NULL;
1033     int error, haveImage;
1034     Tk_Image image;
1035
1036     /*
1037      * Eliminate any existing trace on variables monitored by the button.
1038      */
1039
1040     if (butPtr->textVarNamePtr != NULL) {
1041         Tcl_UntraceVar(interp, Tcl_GetString(butPtr->textVarNamePtr), 
1042                 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1043                 ButtonTextVarProc, (ClientData) butPtr);
1044     }
1045     if (butPtr->selVarNamePtr != NULL) {
1046         Tcl_UntraceVar(interp, Tcl_GetString(butPtr->selVarNamePtr), 
1047                 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1048                 ButtonVarProc, (ClientData) butPtr);
1049     }
1050
1051     /*
1052      * The following loop is potentially executed twice.  During the
1053      * first pass configuration options get set to their new values.
1054      * If there is an error in this pass, we execute a second pass
1055      * to restore all the options to their previous values.
1056      */
1057
1058     for (error = 0; error <= 1; error++) {
1059         if (!error) {
1060             /*
1061              * First pass: set options to new values.
1062              */
1063
1064             if (Tk_SetOptions(interp, (char *) butPtr,
1065                     butPtr->optionTable, objc, objv,
1066                     butPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
1067                 continue;
1068             }
1069         } else {
1070             /*
1071              * Second pass: restore options to old values.
1072              */
1073
1074             errorResult = Tcl_GetObjResult(interp);
1075             Tcl_IncrRefCount(errorResult);
1076             Tk_RestoreSavedOptions(&savedOptions);
1077         }
1078
1079         /*
1080          * A few options need special processing, such as setting the
1081          * background from a 3-D border, or filling in complicated
1082          * defaults that couldn't be specified to Tk_SetOptions.
1083          */
1084
1085         if ((butPtr->state == STATE_ACTIVE)
1086                 && !Tk_StrictMotif(butPtr->tkwin)) {
1087             Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->activeBorder);
1088         } else {
1089             Tk_SetBackgroundFromBorder(butPtr->tkwin, butPtr->normalBorder);
1090         }
1091         if (butPtr->borderWidth < 0) {
1092             butPtr->borderWidth = 0;
1093         }
1094         if (butPtr->highlightWidth < 0) {
1095             butPtr->highlightWidth = 0;
1096         }
1097         if (butPtr->padX < 0) {
1098             butPtr->padX = 0;
1099         }
1100         if (butPtr->padY < 0) {
1101             butPtr->padY = 0;
1102         }
1103
1104         if (butPtr->type >= TYPE_CHECK_BUTTON) {
1105             Tcl_Obj *valuePtr, *namePtr;
1106     
1107             if (butPtr->selVarNamePtr == NULL) {
1108                 butPtr->selVarNamePtr = Tcl_NewStringObj(
1109                         Tk_Name(butPtr->tkwin), -1);
1110                 Tcl_IncrRefCount(butPtr->selVarNamePtr);
1111             }
1112             namePtr = butPtr->selVarNamePtr;
1113     
1114             /*
1115              * Select the button if the associated variable has the
1116              * appropriate value, initialize the variable if it doesn't
1117              * exist, then set a trace on the variable to monitor future
1118              * changes to its value.
1119              */
1120     
1121             valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL, TCL_GLOBAL_ONLY);
1122             butPtr->flags &= ~SELECTED;
1123             if (valuePtr != NULL) {
1124                 if (strcmp(Tcl_GetString(valuePtr),
1125                         Tcl_GetString(butPtr->onValuePtr)) == 0) {
1126                     butPtr->flags |= SELECTED;
1127                 }
1128             } else {
1129                 if (Tcl_ObjSetVar2(interp, namePtr, NULL,
1130                         (butPtr->type == TYPE_CHECK_BUTTON)
1131                         ? butPtr->offValuePtr : Tcl_NewObj(),
1132                         TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
1133                         == NULL) {
1134                     continue;
1135                 }
1136
1137                 /*
1138                  * If a radiobutton has the empty string as value
1139                  * it should be selected.
1140                  */
1141
1142                 if ((butPtr->type == TYPE_RADIO_BUTTON) &&
1143                         (*Tcl_GetString(butPtr->onValuePtr) == 0)) {
1144                     butPtr->flags |= SELECTED;
1145                 }
1146             }
1147         }
1148
1149         /*
1150          * Get the images for the widget, if there are any.  Allocate the
1151          * new images before freeing the old ones, so that the reference
1152          * counts don't go to zero and cause image data to be discarded.
1153          */
1154     
1155         if (butPtr->imagePtr != NULL) {
1156             image = Tk_GetImage(butPtr->interp, butPtr->tkwin,
1157                     Tcl_GetString(butPtr->imagePtr), ButtonImageProc,
1158                     (ClientData) butPtr);
1159             if (image == NULL) {
1160                 continue;
1161             }
1162         } else {
1163             image = NULL;
1164         }
1165         if (butPtr->image != NULL) {
1166             Tk_FreeImage(butPtr->image);
1167         }
1168         butPtr->image = image;
1169         if (butPtr->selectImagePtr != NULL) {
1170             image = Tk_GetImage(butPtr->interp, butPtr->tkwin,
1171                     Tcl_GetString(butPtr->selectImagePtr),
1172                     ButtonSelectImageProc, (ClientData) butPtr);
1173             if (image == NULL) {
1174                 continue;
1175             }
1176         } else {
1177             image = NULL;
1178         }
1179         if (butPtr->selectImage != NULL) {
1180             Tk_FreeImage(butPtr->selectImage);
1181         }
1182         butPtr->selectImage = image;
1183
1184         haveImage = 0;
1185         if (butPtr->imagePtr != NULL || butPtr->bitmap != None) {
1186             haveImage = 1;
1187         }
1188         if ((!haveImage || butPtr->compound != COMPOUND_NONE)
1189                 && (butPtr->textVarNamePtr != NULL)) {
1190             /*
1191              * The button must display the value of a variable: set up a trace
1192              * on the variable's value, create the variable if it doesn't
1193              * exist, and fetch its current value.
1194              */
1195     
1196             Tcl_Obj *valuePtr, *namePtr;
1197
1198             namePtr = butPtr->textVarNamePtr;
1199             valuePtr = Tcl_ObjGetVar2(interp, namePtr, NULL, TCL_GLOBAL_ONLY);
1200             if (valuePtr == NULL) {
1201                 if (Tcl_ObjSetVar2(interp, namePtr, NULL, butPtr->textPtr,
1202                         TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
1203                         == NULL) {
1204                     continue;
1205                 }
1206             } else {
1207                 if (butPtr->textPtr != NULL) {
1208                     Tcl_DecrRefCount(butPtr->textPtr);
1209                 }
1210                 butPtr->textPtr = valuePtr;
1211                 Tcl_IncrRefCount(butPtr->textPtr);
1212             }
1213         }
1214     
1215         if ((butPtr->bitmap != None) || (butPtr->imagePtr != NULL)) {
1216             /*
1217              * The button must display the contents of an image or
1218              * bitmap.
1219              */
1220
1221             if (Tk_GetPixelsFromObj(interp, butPtr->tkwin, butPtr->widthPtr,
1222                     &butPtr->width) != TCL_OK) {
1223                 widthError:
1224                 Tcl_AddErrorInfo(interp, "\n    (processing -width option)");
1225                 continue;
1226             }
1227             if (Tk_GetPixelsFromObj(interp, butPtr->tkwin, butPtr->heightPtr,
1228                     &butPtr->height) != TCL_OK) {
1229                 heightError:
1230                 Tcl_AddErrorInfo(interp, "\n    (processing -height option)");
1231                 continue;
1232             }
1233         } else {
1234             /*
1235              * The button displays an ordinary text string.
1236              */
1237
1238             if (Tcl_GetIntFromObj(interp, butPtr->widthPtr, &butPtr->width)
1239                     != TCL_OK) {
1240                 goto widthError;
1241             }
1242             if (Tcl_GetIntFromObj(interp, butPtr->heightPtr, &butPtr->height)
1243                     != TCL_OK) {
1244                 goto heightError;
1245             }
1246         }
1247         break;
1248     }
1249     if (!error) {
1250         Tk_FreeSavedOptions(&savedOptions);
1251     }
1252
1253     /*
1254      * Reestablish the variable traces, if they're needed.
1255      */
1256
1257     if (butPtr->textVarNamePtr != NULL) {
1258         Tcl_TraceVar(interp, Tcl_GetString(butPtr->textVarNamePtr),
1259                 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1260                 ButtonTextVarProc, (ClientData) butPtr);
1261     }
1262     if (butPtr->selVarNamePtr != NULL) {
1263         Tcl_TraceVar(interp, Tcl_GetString(butPtr->selVarNamePtr),
1264                 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1265                 ButtonVarProc, (ClientData) butPtr);
1266     }
1267     
1268     TkButtonWorldChanged((ClientData) butPtr);
1269     if (error) {
1270         Tcl_SetObjResult(interp, errorResult);
1271         Tcl_DecrRefCount(errorResult);
1272         return TCL_ERROR;
1273     } else {
1274         return TCL_OK;
1275     }
1276 }
1277 \f
1278 /*
1279  *---------------------------------------------------------------------------
1280  *
1281  * TkButtonWorldChanged --
1282  *
1283  *      This procedure is called when the world has changed in some
1284  *      way and the widget needs to recompute all its graphics contexts
1285  *      and determine its new geometry.
1286  *
1287  * Results:
1288  *      None.
1289  *
1290  * Side effects:
1291  *      Button will be relayed out and redisplayed.
1292  *
1293  *---------------------------------------------------------------------------
1294  */
1295  
1296 void
1297 TkButtonWorldChanged(instanceData)
1298     ClientData instanceData;    /* Information about widget. */
1299 {
1300     XGCValues gcValues;
1301     GC newGC;
1302     unsigned long mask;
1303     TkButton *butPtr;
1304
1305     butPtr = (TkButton *) instanceData;
1306
1307     /*
1308      * Recompute GCs.
1309      */
1310
1311     gcValues.font = Tk_FontId(butPtr->tkfont);
1312     gcValues.foreground = butPtr->normalFg->pixel;
1313     gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel;
1314     
1315     /*
1316      * Note: GraphicsExpose events are disabled in normalTextGC because it's
1317      * used to copy stuff from an off-screen pixmap onto the screen (we know
1318      * that there's no problem with obscured areas).
1319      */
1320
1321     gcValues.graphics_exposures = False;
1322     mask = GCForeground | GCBackground | GCFont | GCGraphicsExposures;
1323     newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues);
1324     if (butPtr->normalTextGC != None) {
1325         Tk_FreeGC(butPtr->display, butPtr->normalTextGC);
1326     }
1327     butPtr->normalTextGC = newGC;
1328
1329     if (butPtr->activeFg != NULL) {
1330         gcValues.foreground = butPtr->activeFg->pixel;
1331         gcValues.background = Tk_3DBorderColor(butPtr->activeBorder)->pixel;
1332         mask = GCForeground | GCBackground | GCFont;
1333         newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues);
1334         if (butPtr->activeTextGC != None) {
1335             Tk_FreeGC(butPtr->display, butPtr->activeTextGC);
1336         }
1337         butPtr->activeTextGC = newGC;
1338     }
1339
1340     /*
1341      * Allocate the disabled graphics context, for drawing the widget in
1342      * its disabled state
1343      */
1344     gcValues.background = Tk_3DBorderColor(butPtr->normalBorder)->pixel;
1345     if ((butPtr->disabledFg != NULL) && (butPtr->imagePtr == NULL)) {
1346         gcValues.foreground = butPtr->disabledFg->pixel;
1347         mask = GCForeground | GCBackground | GCFont;
1348     } else {
1349         gcValues.foreground = gcValues.background;
1350         mask = GCForeground;
1351         if (butPtr->compound != COMPOUND_NONE) {
1352             mask |= GCFont;
1353         }
1354         if (butPtr->gray == None) {
1355             butPtr->gray = Tk_GetBitmap(NULL, butPtr->tkwin, "gray50");
1356         }
1357         if (butPtr->gray != None) {
1358             gcValues.fill_style = FillStippled;
1359             gcValues.stipple = butPtr->gray;
1360             mask |= GCFillStyle | GCStipple;
1361         }
1362     }
1363     newGC = Tk_GetGC(butPtr->tkwin, mask, &gcValues);
1364     if (butPtr->disabledGC != None) {
1365         Tk_FreeGC(butPtr->display, butPtr->disabledGC);
1366     }
1367     butPtr->disabledGC = newGC;
1368
1369     if (butPtr->copyGC == None) {
1370         butPtr->copyGC = Tk_GetGC(butPtr->tkwin, 0, &gcValues);
1371     }
1372
1373     TkpComputeButtonGeometry(butPtr);
1374
1375     /*
1376      * Lastly, arrange for the button to be redisplayed.
1377      */
1378
1379     if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) {
1380         Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1381         butPtr->flags |= REDRAW_PENDING;
1382     }
1383 }
1384 \f
1385 /*
1386  *--------------------------------------------------------------
1387  *
1388  * ButtonEventProc --
1389  *
1390  *      This procedure is invoked by the Tk dispatcher for various
1391  *      events on buttons.
1392  *
1393  * Results:
1394  *      None.
1395  *
1396  * Side effects:
1397  *      When the window gets deleted, internal structures get
1398  *      cleaned up.  When it gets exposed, it is redisplayed.
1399  *
1400  *--------------------------------------------------------------
1401  */
1402
1403 static void
1404 ButtonEventProc(clientData, eventPtr)
1405     ClientData clientData;      /* Information about window. */
1406     XEvent *eventPtr;           /* Information about event. */
1407 {
1408     TkButton *butPtr = (TkButton *) clientData;
1409     if ((eventPtr->type == Expose) && (eventPtr->xexpose.count == 0)) {
1410         goto redraw;
1411     } else if (eventPtr->type == ConfigureNotify) {
1412         /*
1413          * Must redraw after size changes, since layout could have changed
1414          * and borders will need to be redrawn.
1415          */
1416
1417         goto redraw;
1418     } else if (eventPtr->type == DestroyNotify) {
1419         DestroyButton(butPtr);
1420     } else if (eventPtr->type == FocusIn) {
1421         if (eventPtr->xfocus.detail != NotifyInferior) {
1422             butPtr->flags |= GOT_FOCUS;
1423             if (butPtr->highlightWidth > 0) {
1424                 goto redraw;
1425             }
1426         }
1427     } else if (eventPtr->type == FocusOut) {
1428         if (eventPtr->xfocus.detail != NotifyInferior) {
1429             butPtr->flags &= ~GOT_FOCUS;
1430             if (butPtr->highlightWidth > 0) {
1431                 goto redraw;
1432             }
1433         }
1434     }
1435     return;
1436
1437     redraw:
1438     if ((butPtr->tkwin != NULL) && !(butPtr->flags & REDRAW_PENDING)) {
1439         Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1440         butPtr->flags |= REDRAW_PENDING;
1441     }
1442 }
1443 \f
1444 /*
1445  *----------------------------------------------------------------------
1446  *
1447  * ButtonCmdDeletedProc --
1448  *
1449  *      This procedure is invoked when a widget command is deleted.  If
1450  *      the widget isn't already in the process of being destroyed,
1451  *      this command destroys it.
1452  *
1453  * Results:
1454  *      None.
1455  *
1456  * Side effects:
1457  *      The widget is destroyed.
1458  *
1459  *----------------------------------------------------------------------
1460  */
1461
1462 static void
1463 ButtonCmdDeletedProc(clientData)
1464     ClientData clientData;      /* Pointer to widget record for widget. */
1465 {
1466     TkButton *butPtr = (TkButton *) clientData;
1467
1468     /*
1469      * This procedure could be invoked either because the window was
1470      * destroyed and the command was then deleted or because the command
1471      * was deleted, and then this procedure destroys the widget.  The
1472      * BUTTON_DELETED flag distinguishes these cases.
1473      */
1474
1475     if (!(butPtr->flags & BUTTON_DELETED)) {
1476         Tk_DestroyWindow(butPtr->tkwin);
1477     }
1478 }
1479 \f
1480 /*
1481  *----------------------------------------------------------------------
1482  *
1483  * TkInvokeButton --
1484  *
1485  *      This procedure is called to carry out the actions associated
1486  *      with a button, such as invoking a Tcl command or setting a
1487  *      variable.  This procedure is invoked, for example, when the
1488  *      button is invoked via the mouse.
1489  *
1490  * Results:
1491  *      A standard Tcl return value.  Information is also left in
1492  *      the interp's result.
1493  *
1494  * Side effects:
1495  *      Depends on the button and its associated command.
1496  *
1497  *----------------------------------------------------------------------
1498  */
1499
1500 int
1501 TkInvokeButton(butPtr)
1502     TkButton *butPtr;                   /* Information about button. */
1503 {
1504     Tcl_Obj *namePtr = butPtr->selVarNamePtr;
1505
1506     if (butPtr->type == TYPE_CHECK_BUTTON) {
1507         if (butPtr->flags & SELECTED) {
1508             if (Tcl_ObjSetVar2(butPtr->interp, namePtr, NULL,
1509                     butPtr->offValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
1510                     == NULL) {
1511                 return TCL_ERROR;
1512             }
1513         } else {
1514             if (Tcl_ObjSetVar2(butPtr->interp, namePtr, NULL,
1515                     butPtr->onValuePtr, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
1516                     == NULL) {
1517                 return TCL_ERROR;
1518             }
1519         }
1520     } else if (butPtr->type == TYPE_RADIO_BUTTON) {
1521         if (Tcl_ObjSetVar2(butPtr->interp, namePtr, NULL, butPtr->onValuePtr,
1522                 TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG)
1523                 == NULL) {
1524             return TCL_ERROR;
1525         }
1526     }
1527     if ((butPtr->type != TYPE_LABEL) && (butPtr->commandPtr != NULL)) {
1528         return Tcl_EvalObjEx(butPtr->interp, butPtr->commandPtr,
1529                 TCL_EVAL_GLOBAL);
1530     }
1531     return TCL_OK;
1532 }
1533 \f
1534 /*
1535  *--------------------------------------------------------------
1536  *
1537  * ButtonVarProc --
1538  *
1539  *      This procedure is invoked when someone changes the
1540  *      state variable associated with a radio button.  Depending
1541  *      on the new value of the button's variable, the button
1542  *      may be selected or deselected.
1543  *
1544  * Results:
1545  *      NULL is always returned.
1546  *
1547  * Side effects:
1548  *      The button may become selected or deselected.
1549  *
1550  *--------------------------------------------------------------
1551  */
1552
1553         /* ARGSUSED */
1554 static char *
1555 ButtonVarProc(clientData, interp, name1, name2, flags)
1556     ClientData clientData;      /* Information about button. */
1557     Tcl_Interp *interp;         /* Interpreter containing variable. */
1558     CONST char *name1;          /* Name of variable. */
1559     CONST char *name2;          /* Second part of variable name. */
1560     int flags;                  /* Information about what happened. */
1561 {
1562     register TkButton *butPtr = (TkButton *) clientData;
1563     char *name, *value;
1564     Tcl_Obj *valuePtr;
1565
1566     name = Tcl_GetString(butPtr->selVarNamePtr);
1567
1568     /*
1569      * If the variable is being unset, then just re-establish the
1570      * trace unless the whole interpreter is going away.
1571      */
1572
1573     if (flags & TCL_TRACE_UNSETS) {
1574         butPtr->flags &= ~SELECTED;
1575         if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
1576             Tcl_TraceVar(interp, name,
1577                     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1578                     ButtonVarProc, clientData);
1579         }
1580         goto redisplay;
1581     }
1582
1583     /*
1584      * Use the value of the variable to update the selected status of
1585      * the button.
1586      */
1587
1588     valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY);
1589     if (valuePtr == NULL) {
1590         value = "";
1591     } else {
1592         value = Tcl_GetString(valuePtr);
1593     }
1594     if (strcmp(value, Tcl_GetString(butPtr->onValuePtr)) == 0) {
1595         if (butPtr->flags & SELECTED) {
1596             return (char *) NULL;
1597         }
1598         butPtr->flags |= SELECTED;
1599     } else if (butPtr->flags & SELECTED) {
1600         butPtr->flags &= ~SELECTED;
1601     } else {
1602         return (char *) NULL;
1603     }
1604
1605     redisplay:
1606     if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin)
1607             && !(butPtr->flags & REDRAW_PENDING)) {
1608         Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1609         butPtr->flags |= REDRAW_PENDING;
1610     }
1611     return (char *) NULL;
1612 }
1613 \f
1614 /*
1615  *--------------------------------------------------------------
1616  *
1617  * ButtonTextVarProc --
1618  *
1619  *      This procedure is invoked when someone changes the variable
1620  *      whose contents are to be displayed in a button.
1621  *
1622  * Results:
1623  *      NULL is always returned.
1624  *
1625  * Side effects:
1626  *      The text displayed in the button will change to match the
1627  *      variable.
1628  *
1629  *--------------------------------------------------------------
1630  */
1631
1632         /* ARGSUSED */
1633 static char *
1634 ButtonTextVarProc(clientData, interp, name1, name2, flags)
1635     ClientData clientData;      /* Information about button. */
1636     Tcl_Interp *interp;         /* Interpreter containing variable. */
1637     CONST char *name1;          /* Not used. */
1638     CONST char *name2;          /* Not used. */
1639     int flags;                  /* Information about what happened. */
1640 {
1641     TkButton *butPtr = (TkButton *) clientData;
1642     char *name;
1643     Tcl_Obj *valuePtr;
1644
1645     if (butPtr->flags & BUTTON_DELETED) {
1646         return (char *) NULL;
1647     }
1648
1649     name = Tcl_GetString(butPtr->textVarNamePtr);
1650
1651     /*
1652      * If the variable is unset, then immediately recreate it unless
1653      * the whole interpreter is going away.
1654      */
1655
1656     if (flags & TCL_TRACE_UNSETS) {
1657         if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
1658             Tcl_SetVar2Ex(interp, name, NULL, butPtr->textPtr, 
1659                     TCL_GLOBAL_ONLY);
1660             Tcl_TraceVar(interp, name,
1661                     TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1662                     ButtonTextVarProc, clientData);
1663         }
1664         return (char *) NULL;
1665     }
1666
1667     valuePtr = Tcl_GetVar2Ex(interp, name, NULL, TCL_GLOBAL_ONLY);
1668     if (valuePtr == NULL) {
1669         valuePtr = Tcl_NewObj();
1670     }
1671     Tcl_DecrRefCount(butPtr->textPtr);
1672     butPtr->textPtr = valuePtr;
1673     Tcl_IncrRefCount(butPtr->textPtr);
1674     TkpComputeButtonGeometry(butPtr);
1675
1676     if ((butPtr->tkwin != NULL) && Tk_IsMapped(butPtr->tkwin)
1677             && !(butPtr->flags & REDRAW_PENDING)) {
1678         Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1679         butPtr->flags |= REDRAW_PENDING;
1680     }
1681     return (char *) NULL;
1682 }
1683 \f
1684 /*
1685  *----------------------------------------------------------------------
1686  *
1687  * ButtonImageProc --
1688  *
1689  *      This procedure is invoked by the image code whenever the manager
1690  *      for an image does something that affects the size or contents
1691  *      of an image displayed in a button.
1692  *
1693  * Results:
1694  *      None.
1695  *
1696  * Side effects:
1697  *      Arranges for the button to get redisplayed.
1698  *
1699  *----------------------------------------------------------------------
1700  */
1701
1702 static void
1703 ButtonImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
1704     ClientData clientData;              /* Pointer to widget record. */
1705     int x, y;                           /* Upper left pixel (within image)
1706                                          * that must be redisplayed. */
1707     int width, height;                  /* Dimensions of area to redisplay
1708                                          * (may be <= 0). */
1709     int imgWidth, imgHeight;            /* New dimensions of image. */
1710 {
1711     register TkButton *butPtr = (TkButton *) clientData;
1712
1713     if (butPtr->tkwin != NULL) {
1714         TkpComputeButtonGeometry(butPtr);
1715         if (Tk_IsMapped(butPtr->tkwin) && !(butPtr->flags & REDRAW_PENDING)) {
1716             Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1717             butPtr->flags |= REDRAW_PENDING;
1718         }
1719     }
1720 }
1721 \f
1722 /*
1723  *----------------------------------------------------------------------
1724  *
1725  * ButtonSelectImageProc --
1726  *
1727  *      This procedure is invoked by the image code whenever the manager
1728  *      for an image does something that affects the size or contents
1729  *      of the image displayed in a button when it is selected.
1730  *
1731  * Results:
1732  *      None.
1733  *
1734  * Side effects:
1735  *      May arrange for the button to get redisplayed.
1736  *
1737  *----------------------------------------------------------------------
1738  */
1739
1740 static void
1741 ButtonSelectImageProc(clientData, x, y, width, height, imgWidth, imgHeight)
1742     ClientData clientData;              /* Pointer to widget record. */
1743     int x, y;                           /* Upper left pixel (within image)
1744                                          * that must be redisplayed. */
1745     int width, height;                  /* Dimensions of area to redisplay
1746                                          * (may be <= 0). */
1747     int imgWidth, imgHeight;            /* New dimensions of image. */
1748 {
1749     register TkButton *butPtr = (TkButton *) clientData;
1750
1751     /*
1752      * Don't recompute geometry:  it's controlled by the primary image.
1753      */
1754
1755     if ((butPtr->flags & SELECTED) && (butPtr->tkwin != NULL)
1756             && Tk_IsMapped(butPtr->tkwin)
1757             && !(butPtr->flags & REDRAW_PENDING)) {
1758         Tcl_DoWhenIdle(TkpDisplayButton, (ClientData) butPtr);
1759         butPtr->flags |= REDRAW_PENDING;
1760     }
1761 }