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