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