tkButton.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:59k
源码类别:

通讯编程

开发平台:

Visual C++

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