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