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

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * Entry.c --
  3.  *
  4.  * This module implements entry and spinbox widgets for the Tk toolkit.
  5.  * An entry displays a string and allows the string to be edited.
  6.  * A spinbox expands on the entry by adding up/down buttons that control
  7.  * the value of the entry widget.
  8.  *
  9.  * Copyright (c) 1990-1994 The Regents of the University of California.
  10.  * Copyright (c) 1994-1997 Sun Microsystems, Inc.
  11.  * Copyright (c) 2000 Ajuba Solutions.
  12.  * Copyright (c) 2002 ActiveState Corporation.
  13.  *
  14.  * See the file "license.terms" for information on usage and redistribution
  15.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  16.  *
  17.  * RCS: @(#) $Id: tkEntry.c,v 1.35.2.4 2007/04/29 02:24:02 das Exp $
  18.  */
  19. #include "tkInt.h"
  20. #include "default.h"
  21. #include "tkEntry.h"
  22. /*
  23.  * The following macro defines how many extra pixels to leave on each
  24.  * side of the text in the entry.
  25.  */
  26. #define XPAD 1
  27. #define YPAD 1
  28. /*
  29.  * A comparison function for double values.  For Spinboxes.
  30.  */
  31. #define MIN_DBL_VAL 1E-9
  32. #define DOUBLES_EQ(d1, d2) (fabs((d1) - (d2)) < MIN_DBL_VAL)
  33. static char *stateStrings[] = {
  34.     "disabled", "normal", "readonly", (char *) NULL
  35. };
  36. /*
  37.  * Definitions for -validate option values:
  38.  */
  39. static char *validateStrings[] = {
  40.     "all", "key", "focus", "focusin", "focusout", "none", (char *) NULL
  41. };
  42. enum validateType {
  43.     VALIDATE_ALL, VALIDATE_KEY, VALIDATE_FOCUS,
  44.     VALIDATE_FOCUSIN, VALIDATE_FOCUSOUT, VALIDATE_NONE,
  45.     /*
  46.      * These extra enums are for use with EntryValidateChange
  47.      */
  48.     VALIDATE_FORCED, VALIDATE_DELETE, VALIDATE_INSERT, VALIDATE_BUTTON
  49. };
  50. #define DEF_ENTRY_VALIDATE "none"
  51. #define DEF_ENTRY_INVALIDCMD ""
  52. /*
  53.  * Information used for Entry objv parsing.
  54.  */
  55. static Tk_OptionSpec entryOptSpec[] = {
  56.     {TK_OPTION_BORDER, "-background", "background", "Background",
  57. DEF_ENTRY_BG_COLOR, -1, Tk_Offset(Entry, normalBorder),
  58. 0, (ClientData) DEF_ENTRY_BG_MONO, 0},
  59.     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
  60. (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
  61.     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
  62. (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
  63.     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  64. DEF_ENTRY_BORDER_WIDTH, -1, Tk_Offset(Entry, borderWidth), 
  65.         0, 0, 0},
  66.     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
  67. DEF_ENTRY_CURSOR, -1, Tk_Offset(Entry, cursor),
  68. TK_OPTION_NULL_OK, 0, 0},
  69.     {TK_OPTION_BORDER, "-disabledbackground", "disabledBackground",
  70.  "DisabledBackground", DEF_ENTRY_DISABLED_BG_COLOR, -1,
  71.  Tk_Offset(Entry, disabledBorder), TK_OPTION_NULL_OK,
  72.  (ClientData) DEF_ENTRY_DISABLED_BG_MONO, 0},
  73.     {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
  74.  "DisabledForeground", DEF_ENTRY_DISABLED_FG, -1,
  75.  Tk_Offset(Entry, dfgColorPtr), TK_OPTION_NULL_OK, 0, 0},
  76.     {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
  77.         "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, -1, 
  78.         Tk_Offset(Entry, exportSelection), 0, 0, 0},
  79.     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
  80. (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
  81.     {TK_OPTION_FONT, "-font", "font", "Font",
  82. DEF_ENTRY_FONT, -1, Tk_Offset(Entry, tkfont), 0, 0, 0},
  83.     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
  84. DEF_ENTRY_FG, -1, Tk_Offset(Entry, fgColorPtr), 0, 
  85.         0, 0},
  86.     {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
  87. "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
  88. -1, Tk_Offset(Entry, highlightBgColorPtr), 
  89.         0, 0, 0},
  90.     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  91. DEF_ENTRY_HIGHLIGHT, -1, Tk_Offset(Entry, highlightColorPtr),
  92. 0, 0, 0},
  93.     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
  94. "HighlightThickness", DEF_ENTRY_HIGHLIGHT_WIDTH, -1, 
  95. Tk_Offset(Entry, highlightWidth), 0, 0, 0},
  96.     {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground",
  97. DEF_ENTRY_INSERT_BG,
  98. -1, Tk_Offset(Entry, insertBorder), 
  99.         0, 0, 0},
  100.     {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth", 
  101.         "BorderWidth", DEF_ENTRY_INSERT_BD_COLOR, -1, 
  102.         Tk_Offset(Entry, insertBorderWidth), 0, 
  103.         (ClientData) DEF_ENTRY_INSERT_BD_MONO, 0},
  104.     {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime",
  105.         DEF_ENTRY_INSERT_OFF_TIME, -1, Tk_Offset(Entry, insertOffTime), 
  106.         0, 0, 0},
  107.     {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime",
  108.         DEF_ENTRY_INSERT_ON_TIME, -1, Tk_Offset(Entry, insertOnTime), 
  109.         0, 0, 0},
  110.     {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
  111. DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth), 
  112.         0, 0, 0},
  113.     {TK_OPTION_STRING, "-invalidcommand", "invalidCommand", "InvalidCommand",
  114. DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd),
  115. TK_OPTION_NULL_OK, 0, 0},
  116.     {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL,
  117. (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0},
  118.     {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
  119. DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0},
  120.     {TK_OPTION_BORDER, "-readonlybackground", "readonlyBackground",
  121.  "ReadonlyBackground", DEF_ENTRY_READONLY_BG_COLOR, -1,
  122.  Tk_Offset(Entry, readonlyBorder), TK_OPTION_NULL_OK,
  123.  (ClientData) DEF_ENTRY_READONLY_BG_MONO, 0},
  124.     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
  125. DEF_ENTRY_RELIEF, -1, Tk_Offset(Entry, relief), 
  126.         0, 0, 0},
  127.     {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground",
  128.         DEF_ENTRY_SELECT_COLOR, -1, Tk_Offset(Entry, selBorder),
  129.         0, (ClientData) DEF_ENTRY_SELECT_MONO, 0},
  130.     {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", 
  131.         "BorderWidth", DEF_ENTRY_SELECT_BD_COLOR, -1, 
  132.         Tk_Offset(Entry, selBorderWidth), 
  133.         0, (ClientData) DEF_ENTRY_SELECT_BD_MONO, 0},
  134.     {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
  135. DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
  136. TK_CONFIG_NULL_OK, (ClientData) DEF_ENTRY_SELECT_FG_MONO, 0},
  137.     {TK_OPTION_STRING, "-show", "show", "Show",
  138.         DEF_ENTRY_SHOW, -1, Tk_Offset(Entry, showChar), 
  139.         TK_OPTION_NULL_OK, 0, 0},
  140.     {TK_OPTION_STRING_TABLE, "-state", "state", "State",
  141. DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state), 
  142.         0, (ClientData) stateStrings, 0},
  143.     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
  144. DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus), 
  145.         TK_OPTION_NULL_OK, 0, 0},
  146.     {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
  147. DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName),
  148. TK_OPTION_NULL_OK, 0, 0},
  149.     {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
  150.        DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate),
  151.        0, (ClientData) validateStrings, 0},
  152.     {TK_OPTION_STRING, "-validatecommand", "validateCommand", "ValidateCommand",
  153.        (char *) NULL, -1, Tk_Offset(Entry, validateCmd),
  154.        TK_OPTION_NULL_OK, 0, 0},
  155.     {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL,
  156. (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0},
  157.     {TK_OPTION_INT, "-width", "width", "Width",
  158. DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0},
  159.     {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
  160. DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd),
  161. TK_OPTION_NULL_OK, 0, 0},
  162.     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
  163. (char *) NULL, 0, -1, 0, 0, 0}
  164. };
  165. /*
  166.  * Information used for Spinbox objv parsing.
  167.  */
  168. #define DEF_SPINBOX_REPEAT_DELAY "400"
  169. #define DEF_SPINBOX_REPEAT_INTERVAL "100"
  170. #define DEF_SPINBOX_CMD ""
  171. #define DEF_SPINBOX_FROM "0"
  172. #define DEF_SPINBOX_TO "0"
  173. #define DEF_SPINBOX_INCREMENT "1"
  174. #define DEF_SPINBOX_FORMAT ""
  175. #define DEF_SPINBOX_VALUES ""
  176. #define DEF_SPINBOX_WRAP "0"
  177. static Tk_OptionSpec sbOptSpec[] = {
  178.     {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Background",
  179. DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(Spinbox, activeBorder),
  180. 0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0},
  181.     {TK_OPTION_BORDER, "-background", "background", "Background",
  182. DEF_ENTRY_BG_COLOR, -1, Tk_Offset(Entry, normalBorder),
  183. 0, (ClientData) DEF_ENTRY_BG_MONO, 0},
  184.     {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
  185. (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
  186.     {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
  187. (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
  188.     {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
  189. DEF_ENTRY_BORDER_WIDTH, -1, Tk_Offset(Entry, borderWidth), 
  190.         0, 0, 0},
  191.     {TK_OPTION_BORDER, "-buttonbackground", "Button.background", "Background",
  192. DEF_BUTTON_BG_COLOR, -1, Tk_Offset(Spinbox, buttonBorder),
  193. 0, (ClientData) DEF_BUTTON_BG_MONO, 0},
  194.     {TK_OPTION_CURSOR, "-buttoncursor", "Button.cursor", "Cursor",
  195. DEF_BUTTON_CURSOR, -1, Tk_Offset(Spinbox, bCursor),
  196. TK_OPTION_NULL_OK, 0, 0},
  197.     {TK_OPTION_RELIEF, "-buttondownrelief", "Button.relief", "Relief",
  198. DEF_BUTTON_RELIEF, -1, Tk_Offset(Spinbox, bdRelief),
  199.         0, 0, 0},
  200.     {TK_OPTION_RELIEF, "-buttonuprelief", "Button.relief", "Relief",
  201. DEF_BUTTON_RELIEF, -1, Tk_Offset(Spinbox, buRelief),
  202.         0, 0, 0},
  203.     {TK_OPTION_STRING, "-command", "command", "Command",
  204. DEF_SPINBOX_CMD, -1, Tk_Offset(Spinbox, command),
  205. TK_OPTION_NULL_OK, 0, 0},
  206.     {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
  207. DEF_ENTRY_CURSOR, -1, Tk_Offset(Entry, cursor),
  208. TK_OPTION_NULL_OK, 0, 0},
  209.     {TK_OPTION_BORDER, "-disabledbackground", "disabledBackground",
  210.  "DisabledBackground", DEF_ENTRY_DISABLED_BG_COLOR, -1,
  211.  Tk_Offset(Entry, disabledBorder), TK_OPTION_NULL_OK,
  212.  (ClientData) DEF_ENTRY_DISABLED_BG_MONO, 0},
  213.     {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
  214.  "DisabledForeground", DEF_ENTRY_DISABLED_FG, -1,
  215.  Tk_Offset(Entry, dfgColorPtr), TK_OPTION_NULL_OK, 0, 0},
  216.     {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
  217.         "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, -1, 
  218.         Tk_Offset(Entry, exportSelection), 0, 0, 0},
  219.     {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
  220. (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
  221.     {TK_OPTION_FONT, "-font", "font", "Font",
  222. DEF_ENTRY_FONT, -1, Tk_Offset(Entry, tkfont), 0, 0, 0},
  223.     {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
  224. DEF_ENTRY_FG, -1, Tk_Offset(Entry, fgColorPtr), 0, 
  225.         0, 0},
  226.     {TK_OPTION_STRING, "-format", "format", "Format",
  227. DEF_SPINBOX_FORMAT, -1, Tk_Offset(Spinbox, reqFormat),
  228. TK_OPTION_NULL_OK, 0, 0},
  229.     {TK_OPTION_DOUBLE, "-from", "from", "From",
  230. DEF_SPINBOX_FROM, -1, Tk_Offset(Spinbox, fromValue), 0, 0, 0},
  231.     {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
  232. "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
  233. -1, Tk_Offset(Entry, highlightBgColorPtr), 
  234.         0, 0, 0},
  235.     {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
  236. DEF_ENTRY_HIGHLIGHT, -1, Tk_Offset(Entry, highlightColorPtr),
  237. 0, 0, 0},
  238.     {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
  239. "HighlightThickness", DEF_ENTRY_HIGHLIGHT_WIDTH, -1, 
  240. Tk_Offset(Entry, highlightWidth), 0, 0, 0},
  241.     {TK_OPTION_DOUBLE, "-increment", "increment", "Increment",
  242. DEF_SPINBOX_INCREMENT, -1, Tk_Offset(Spinbox, increment), 0, 0, 0},
  243.     {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground",
  244. DEF_ENTRY_INSERT_BG, -1, Tk_Offset(Entry, insertBorder), 
  245.         0, 0, 0},
  246.     {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth", 
  247.         "BorderWidth", DEF_ENTRY_INSERT_BD_COLOR, -1, 
  248.         Tk_Offset(Entry, insertBorderWidth), 0, 
  249.         (ClientData) DEF_ENTRY_INSERT_BD_MONO, 0},
  250.     {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime",
  251.         DEF_ENTRY_INSERT_OFF_TIME, -1, Tk_Offset(Entry, insertOffTime), 
  252.         0, 0, 0},
  253.     {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime",
  254.         DEF_ENTRY_INSERT_ON_TIME, -1, Tk_Offset(Entry, insertOnTime), 
  255.         0, 0, 0},
  256.     {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
  257. DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth), 
  258.         0, 0, 0},
  259.     {TK_OPTION_STRING, "-invalidcommand", "invalidCommand", "InvalidCommand",
  260. DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd),
  261. TK_OPTION_NULL_OK, 0, 0},
  262.     {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL,
  263. (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0},
  264.     {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
  265. DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0},
  266.     {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
  267. DEF_ENTRY_RELIEF, -1, Tk_Offset(Entry, relief), 
  268.         0, 0, 0},
  269.     {TK_OPTION_BORDER, "-readonlybackground", "readonlyBackground",
  270.  "ReadonlyBackground", DEF_ENTRY_READONLY_BG_COLOR, -1,
  271.  Tk_Offset(Entry, readonlyBorder), TK_OPTION_NULL_OK,
  272.  (ClientData) DEF_ENTRY_READONLY_BG_MONO, 0},
  273.     {TK_OPTION_INT, "-repeatdelay", "repeatDelay", "RepeatDelay",
  274.         DEF_SPINBOX_REPEAT_DELAY, -1, Tk_Offset(Spinbox, repeatDelay), 
  275.         0, 0, 0},
  276.     {TK_OPTION_INT, "-repeatinterval", "repeatInterval", "RepeatInterval",
  277.         DEF_SPINBOX_REPEAT_INTERVAL, -1, Tk_Offset(Spinbox, repeatInterval), 
  278.         0, 0, 0},
  279.     {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground",
  280.         DEF_ENTRY_SELECT_COLOR, -1, Tk_Offset(Entry, selBorder),
  281.         0, (ClientData) DEF_ENTRY_SELECT_MONO, 0},
  282.     {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth", 
  283.         "BorderWidth", DEF_ENTRY_SELECT_BD_COLOR, -1, 
  284.         Tk_Offset(Entry, selBorderWidth), 
  285.         0, (ClientData) DEF_ENTRY_SELECT_BD_MONO, 0},
  286.     {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
  287. DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
  288. TK_CONFIG_NULL_OK, (ClientData) DEF_ENTRY_SELECT_FG_MONO, 0},
  289.     {TK_OPTION_STRING_TABLE, "-state", "state", "State",
  290. DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state), 
  291.         0, (ClientData) stateStrings, 0},
  292.     {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
  293. DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus), 
  294.         TK_CONFIG_NULL_OK, 0, 0},
  295.     {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
  296. DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName),
  297. TK_CONFIG_NULL_OK, 0, 0},
  298.     {TK_OPTION_DOUBLE, "-to", "to", "To",
  299. DEF_SPINBOX_TO, -1, Tk_Offset(Spinbox, toValue), 0, 0, 0},
  300.     {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
  301.        DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate),
  302.        0, (ClientData) validateStrings, 0},
  303.     {TK_OPTION_STRING, "-validatecommand", "validateCommand", "ValidateCommand",
  304.        (char *) NULL, -1, Tk_Offset(Entry, validateCmd),
  305.        TK_CONFIG_NULL_OK, 0, 0},
  306.     {TK_OPTION_STRING, "-values", "values", "Values",
  307.  DEF_SPINBOX_VALUES, -1, Tk_Offset(Spinbox, valueStr),
  308.  TK_OPTION_NULL_OK, 0, 0},
  309.     {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL,
  310. (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0},
  311.     {TK_OPTION_INT, "-width", "width", "Width",
  312. DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0},
  313.     {TK_OPTION_BOOLEAN, "-wrap", "wrap", "Wrap",
  314. DEF_SPINBOX_WRAP, -1, Tk_Offset(Spinbox, wrap), 0, 0, 0},
  315.     {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
  316. DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd),
  317. TK_CONFIG_NULL_OK, 0, 0},
  318.     {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
  319. (char *) NULL, 0, -1, 0, 0, 0}
  320. };
  321. /*
  322.  * The following tables define the entry widget commands (and sub-
  323.  * commands) and map the indexes into the string tables into 
  324.  * enumerated types used to dispatch the entry widget command.
  325.  */
  326. static CONST char *entryCmdNames[] = {
  327.     "bbox", "cget", "configure", "delete", "get", "icursor", "index", 
  328.     "insert", "scan", "selection", "validate", "xview", (char *) NULL
  329. };
  330. enum entryCmd {
  331.     COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE, 
  332.     COMMAND_GET, COMMAND_ICURSOR, COMMAND_INDEX, COMMAND_INSERT, 
  333.     COMMAND_SCAN, COMMAND_SELECTION, COMMAND_VALIDATE, COMMAND_XVIEW
  334. };
  335. static CONST char *selCmdNames[] = {
  336.     "adjust", "clear", "from", "present", "range", "to", (char *) NULL
  337. };
  338. enum selCmd {
  339.     SELECTION_ADJUST, SELECTION_CLEAR, SELECTION_FROM,
  340.     SELECTION_PRESENT, SELECTION_RANGE, SELECTION_TO
  341. };
  342. /*
  343.  * The following tables define the spinbox widget commands (and sub-
  344.  * commands) and map the indexes into the string tables into 
  345.  * enumerated types used to dispatch the spinbox widget command.
  346.  */
  347. static CONST char *sbCmdNames[] = {
  348.     "bbox", "cget", "configure", "delete", "get", "icursor", "identify",
  349.     "index", "insert", "invoke", "scan", "selection", "set",
  350.     "validate", "xview", (char *) NULL
  351. };
  352. enum sbCmd {
  353.     SB_CMD_BBOX, SB_CMD_CGET, SB_CMD_CONFIGURE, SB_CMD_DELETE, 
  354.     SB_CMD_GET, SB_CMD_ICURSOR, SB_CMD_IDENTIFY, SB_CMD_INDEX,
  355.     SB_CMD_INSERT, SB_CMD_INVOKE, SB_CMD_SCAN, SB_CMD_SELECTION,
  356.     SB_CMD_SET, SB_CMD_VALIDATE, SB_CMD_XVIEW
  357. };
  358. static CONST char *sbSelCmdNames[] = {
  359.     "adjust", "clear", "element", "from", "present", "range", "to",
  360.     (char *) NULL
  361. };
  362. enum sbselCmd {
  363.     SB_SEL_ADJUST, SB_SEL_CLEAR, SB_SEL_ELEMENT, SB_SEL_FROM, 
  364.     SB_SEL_PRESENT, SB_SEL_RANGE, SB_SEL_TO
  365. };
  366. /*
  367.  * Extra for selection of elements
  368.  */
  369. /* 
  370.  * This is the string array  corresponding to the enum in selelement.
  371.  * If you modify them, you must modify the strings here.
  372.  */
  373.  
  374. static CONST char *selElementNames[] = {
  375.     "none", "buttondown", "buttonup", (char *) NULL, "entry"
  376. };
  377. /*
  378.  * Flags for GetEntryIndex procedure:
  379.  */
  380. #define ZERO_OK 1
  381. #define LAST_PLUS_ONE_OK 2
  382. /*
  383.  * Forward declarations for procedures defined later in this file:
  384.  */
  385. static int ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
  386.     Entry *entryPtr, int objc, 
  387.                             Tcl_Obj *CONST objv[], int flags));
  388. static void DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
  389.     int count));
  390. static void DestroyEntry _ANSI_ARGS_((char *memPtr));
  391. static void DisplayEntry _ANSI_ARGS_((ClientData clientData));
  392. static void EntryBlinkProc _ANSI_ARGS_((ClientData clientData));
  393. static void EntryCmdDeletedProc _ANSI_ARGS_((
  394.     ClientData clientData));
  395. static void EntryComputeGeometry _ANSI_ARGS_((Entry *entryPtr));
  396. static void EntryEventProc _ANSI_ARGS_((ClientData clientData,
  397.     XEvent *eventPtr));
  398. static void EntryFocusProc _ANSI_ARGS_ ((Entry *entryPtr,
  399.     int gotFocus));
  400. static int EntryFetchSelection _ANSI_ARGS_((ClientData clientData,
  401.     int offset, char *buffer, int maxBytes));
  402. static void EntryLostSelection _ANSI_ARGS_((
  403.     ClientData clientData));
  404. static void EventuallyRedraw _ANSI_ARGS_((Entry *entryPtr));
  405. static void EntryScanTo _ANSI_ARGS_((Entry *entryPtr, int y));
  406. static void EntrySetValue _ANSI_ARGS_((Entry *entryPtr,
  407.     CONST char *value));
  408. static void EntrySelectTo _ANSI_ARGS_((
  409.     Entry *entryPtr, int index));
  410. static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData,
  411.     Tcl_Interp *interp, CONST char *name1,
  412.     CONST char *name2, int flags));
  413. static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
  414. static int EntryValidate _ANSI_ARGS_((Entry *entryPtr,
  415.     char *cmd));
  416. static int EntryValidateChange _ANSI_ARGS_((Entry *entryPtr,
  417.     char *change, CONST char *new, int index,
  418.     int type));
  419. static void ExpandPercents _ANSI_ARGS_((Entry *entryPtr,
  420.     CONST char *before, char *change, CONST char *new,
  421.     int index, int type, Tcl_DString *dsPtr));
  422. static void EntryValueChanged _ANSI_ARGS_((Entry *entryPtr,
  423.     CONST char *newValue));
  424. static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr,
  425.     double *firstPtr, double *lastPtr));
  426. static int EntryWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
  427.     Tcl_Interp *interp, int objc, 
  428.     Tcl_Obj *CONST objv[]));
  429. static void EntryWorldChanged _ANSI_ARGS_((
  430.     ClientData instanceData));
  431. static int GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp,
  432.     Entry *entryPtr, char *string, int *indexPtr));
  433. static void InsertChars _ANSI_ARGS_((Entry *entryPtr, int index,
  434.     char *string));
  435. /*
  436.  * These forward declarations are the spinbox specific ones:
  437.  */
  438. static int SpinboxWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
  439.     Tcl_Interp *interp, int objc, 
  440.     Tcl_Obj *CONST objv[]));
  441. static int GetSpinboxElement _ANSI_ARGS_((Spinbox *sbPtr,
  442.     int x, int y));
  443. static int SpinboxInvoke _ANSI_ARGS_((Tcl_Interp *interp,
  444.     Spinbox *sbPtr, int element));
  445. static int ComputeFormat _ANSI_ARGS_((Spinbox *sbPtr));
  446. /*
  447.  * The structure below defines widget class behavior by means of procedures
  448.  * that can be invoked from generic window code.
  449.  */
  450. static Tk_ClassProcs entryClass = {
  451.     sizeof(Tk_ClassProcs), /* size */
  452.     EntryWorldChanged, /* worldChangedProc */
  453. };
  454. /*
  455.  *--------------------------------------------------------------
  456.  *
  457.  * Tk_EntryObjCmd --
  458.  *
  459.  * This procedure is invoked to process the "entry" Tcl
  460.  * command.  See the user documentation for details on what
  461.  * it does.
  462.  *
  463.  * Results:
  464.  * A standard Tcl result.
  465.  *
  466.  * Side effects:
  467.  * See the user documentation.
  468.  *
  469.  *--------------------------------------------------------------
  470.  */
  471. int
  472. Tk_EntryObjCmd(clientData, interp, objc, objv)
  473.     ClientData clientData; /* NULL. */
  474.     Tcl_Interp *interp; /* Current interpreter. */
  475.     int objc; /* Number of arguments. */
  476.     Tcl_Obj *CONST objv[];      /* Argument objects. */
  477. {
  478.     register Entry *entryPtr;
  479.     Tk_OptionTable optionTable;
  480.     Tk_Window tkwin;
  481.     char *tmp;
  482.     if (objc < 2) {
  483. Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
  484. return TCL_ERROR;
  485.     }
  486.     tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
  487.             Tcl_GetString(objv[1]), (char *) NULL);
  488.     if (tkwin == NULL) {
  489. return TCL_ERROR;
  490.     }
  491.     /*
  492.      * Create the option table for this widget class.  If it has already
  493.      * been created, Tk will return the cached value.
  494.      */
  495.     optionTable = Tk_CreateOptionTable(interp, entryOptSpec);
  496.     /*
  497.      * Initialize the fields of the structure that won't be initialized
  498.      * by ConfigureEntry, or that ConfigureEntry requires to be
  499.      * initialized already (e.g. resource pointers).  Only the non-NULL/0
  500.      * data must be initialized as memset covers the rest.
  501.      */
  502.     entryPtr = (Entry *) ckalloc(sizeof(Entry));
  503.     memset((VOID *) entryPtr, 0, sizeof(Entry));
  504.     entryPtr->tkwin = tkwin;
  505.     entryPtr->display = Tk_Display(tkwin);
  506.     entryPtr->interp = interp;
  507.     entryPtr->widgetCmd = Tcl_CreateObjCommand(interp,
  508.     Tk_PathName(entryPtr->tkwin), EntryWidgetObjCmd,
  509.     (ClientData) entryPtr, EntryCmdDeletedProc);
  510.     entryPtr->optionTable = optionTable;
  511.     entryPtr->type = TK_ENTRY;
  512.     tmp = (char *) ckalloc(1);
  513.     tmp[0] = '';
  514.     entryPtr->string = tmp;
  515.     entryPtr->selectFirst = -1;
  516.     entryPtr->selectLast = -1;
  517.     entryPtr->cursor = None;
  518.     entryPtr->exportSelection = 1;
  519.     entryPtr->justify = TK_JUSTIFY_LEFT;
  520.     entryPtr->relief = TK_RELIEF_FLAT;
  521.     entryPtr->state = STATE_NORMAL;
  522.     entryPtr->displayString = entryPtr->string;
  523.     entryPtr->inset = XPAD;
  524.     entryPtr->textGC = None;
  525.     entryPtr->selTextGC = None;
  526.     entryPtr->highlightGC = None;
  527.     entryPtr->avgWidth = 1;
  528.     entryPtr->validate = VALIDATE_NONE;
  529.     /*
  530.      * Keep a hold of the associated tkwin until we destroy the listbox,
  531.      * otherwise Tk might free it while we still need it.
  532.      */
  533.     Tcl_Preserve((ClientData) entryPtr->tkwin);
  534.     Tk_SetClass(entryPtr->tkwin, "Entry");
  535.     Tk_SetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr);
  536.     Tk_CreateEventHandler(entryPtr->tkwin,
  537.     ExposureMask|StructureNotifyMask|FocusChangeMask,
  538.     EntryEventProc, (ClientData) entryPtr);
  539.     Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING,
  540.     EntryFetchSelection, (ClientData) entryPtr, XA_STRING);
  541.     if ((Tk_InitOptions(interp, (char *) entryPtr, optionTable, tkwin)
  542.     != TCL_OK) ||
  543.     (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK)) {
  544. Tk_DestroyWindow(entryPtr->tkwin);
  545. return TCL_ERROR;
  546.     }
  547.     Tcl_SetResult(interp, Tk_PathName(entryPtr->tkwin), TCL_STATIC);
  548.     return TCL_OK;
  549. }
  550. /*
  551.  *--------------------------------------------------------------
  552.  *
  553.  * EntryWidgetObjCmd --
  554.  *
  555.  * This procedure is invoked to process the Tcl command
  556.  * that corresponds to a widget managed by this module.
  557.  * See the user documentation for details on what it does.
  558.  *
  559.  * Results:
  560.  * A standard Tcl result.
  561.  *
  562.  * Side effects:
  563.  * See the user documentation.
  564.  *
  565.  *--------------------------------------------------------------
  566.  */
  567. static int
  568. EntryWidgetObjCmd(clientData, interp, objc, objv)
  569.     ClientData clientData; /* Information about entry widget. */
  570.     Tcl_Interp *interp; /* Current interpreter. */
  571.     int objc; /* Number of arguments. */
  572.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  573. {
  574.     Entry *entryPtr = (Entry *) clientData;
  575.     int cmdIndex, selIndex, result;
  576.     Tcl_Obj *objPtr;
  577.     if (objc < 2) {
  578. Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
  579. return TCL_ERROR;
  580.     }
  581.     /* 
  582.      * Parse the widget command by looking up the second token in
  583.      * the list of valid command names. 
  584.      */
  585.     result = Tcl_GetIndexFromObj(interp, objv[1], entryCmdNames,
  586.     "option", 0, &cmdIndex);
  587.     if (result != TCL_OK) {
  588. return result;
  589.     }
  590.     Tcl_Preserve((ClientData) entryPtr);
  591.     switch ((enum entryCmd) cmdIndex) {
  592.         case COMMAND_BBOX: {
  593.     int index, x, y, width, height;
  594.     char buf[TCL_INTEGER_SPACE * 4];
  595.     if (objc != 3) {
  596.         Tcl_WrongNumArgs(interp, 2, objv, "index");
  597. goto error;
  598.     }
  599.     if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), 
  600.                     &index) != TCL_OK) {
  601.         goto error;
  602.     }
  603.     if ((index == entryPtr->numChars) && (index > 0)) {
  604.         index--;
  605.     }
  606.     Tk_CharBbox(entryPtr->textLayout, index, &x, &y, 
  607.                     &width, &height);
  608.     sprintf(buf, "%d %d %d %d", x + entryPtr->layoutX,
  609.     y + entryPtr->layoutY, width, height);
  610.     Tcl_SetResult(interp, buf, TCL_VOLATILE);
  611.     break;
  612.         case COMMAND_CGET: {
  613.     if (objc != 3) {
  614.         Tcl_WrongNumArgs(interp, 2, objv, "option");
  615. goto error;
  616.     }
  617.     
  618.     objPtr = Tk_GetOptionValue(interp, (char *) entryPtr,
  619.     entryPtr->optionTable, objv[2], entryPtr->tkwin);
  620.     if (objPtr == NULL) {
  621.  goto error;
  622.     } else {
  623. Tcl_SetObjResult(interp, objPtr);
  624.     }
  625.     break;
  626. }
  627.         case COMMAND_CONFIGURE: {
  628.     if (objc <= 3) {
  629. objPtr = Tk_GetOptionInfo(interp, (char *) entryPtr,
  630. entryPtr->optionTable,
  631. (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
  632. entryPtr->tkwin);
  633. if (objPtr == NULL) {
  634.     goto error;
  635. } else {
  636.     Tcl_SetObjResult(interp, objPtr);
  637. }
  638.     } else {
  639. result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0);
  640.     }
  641.     break;
  642. }
  643.         case COMMAND_DELETE: {
  644.     int first, last;
  645.     if ((objc < 3) || (objc > 4)) {
  646.         Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
  647. goto error;
  648.     }
  649.     if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), 
  650.                     &first) != TCL_OK) {
  651.         goto error;
  652.     }
  653.     if (objc == 3) {
  654.         last = first + 1;
  655.     } else {
  656.         if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[3]), 
  657.                         &last) != TCL_OK) {
  658.     goto error;
  659. }
  660.     }
  661.     if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
  662.         DeleteChars(entryPtr, first, last - first);
  663.     }
  664.     break;
  665. }
  666.         case COMMAND_GET: {
  667.     if (objc != 2) {
  668.         Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
  669. goto error;
  670.     }
  671.     Tcl_SetStringObj(Tcl_GetObjResult(interp), entryPtr->string, -1);
  672.     break;
  673. }
  674.         case COMMAND_ICURSOR: {
  675.     if (objc != 3) {
  676.         Tcl_WrongNumArgs(interp, 2, objv, "pos");
  677. goto error;
  678.     }
  679.     if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
  680.                     &entryPtr->insertPos) != TCL_OK) {
  681.         goto error;
  682.     }
  683.     EventuallyRedraw(entryPtr);
  684.     break;
  685. }
  686.         case COMMAND_INDEX: {
  687.     int index;
  688.     if (objc != 3) {
  689.         Tcl_WrongNumArgs(interp, 2, objv, "string");
  690. goto error;
  691.     }
  692.     if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), 
  693.                     &index) != TCL_OK) {
  694.         goto error;
  695.     }
  696.     Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
  697.     break;
  698. }
  699.         case COMMAND_INSERT: {
  700.     int index;
  701.     if (objc != 4) {
  702.         Tcl_WrongNumArgs(interp, 2, objv, "index text");
  703. goto error;
  704.     }
  705.     if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), 
  706.                     &index) != TCL_OK) {
  707.         goto error;
  708.     }
  709.     if (entryPtr->state == STATE_NORMAL) {
  710.         InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
  711.     }
  712.     break;
  713. }
  714.         case COMMAND_SCAN: {
  715.     int x;
  716.     char *minorCmd;
  717.     if (objc != 4) {
  718.         Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x");
  719. goto error;
  720.     }
  721.     if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
  722.         goto error;
  723.     }
  724.     minorCmd = Tcl_GetString(objv[2]);
  725.     if (minorCmd[0] == 'm' 
  726.                     && (strncmp(minorCmd, "mark", strlen(minorCmd)) == 0)) {
  727.         entryPtr->scanMarkX = x;
  728. entryPtr->scanMarkIndex = entryPtr->leftIndex;
  729.     } else if ((minorCmd[0] == 'd')
  730. && (strncmp(minorCmd, "dragto", strlen(minorCmd)) == 0)) {
  731.         EntryScanTo(entryPtr, x);
  732.     } else {
  733.         Tcl_AppendResult(interp, "bad scan option "", 
  734.                         Tcl_GetString(objv[2]), "": must be mark or dragto", 
  735.                         (char *) NULL);
  736. goto error;
  737.     }
  738.     break;
  739. }
  740.     
  741. case COMMAND_SELECTION: {
  742.     int index, index2;
  743.     if (objc < 3) {
  744. Tcl_WrongNumArgs(interp, 2, objv, "option ?index?");
  745. goto error;
  746.     }
  747.     
  748.     /* 
  749.      * Parse the selection sub-command, using the command
  750.      * table "selCmdNames" defined above.
  751.      */
  752.     
  753.     result = Tcl_GetIndexFromObj(interp, objv[2], selCmdNames,
  754.     "selection option", 0, &selIndex);
  755.     if (result != TCL_OK) {
  756. goto error;
  757.     }
  758.     /*
  759.      * Disabled entries don't allow the selection to be modified,
  760.      * but 'selection present' must return a boolean.
  761.      */
  762.     if ((entryPtr->state == STATE_DISABLED)
  763.     && (selIndex != SELECTION_PRESENT)) {
  764. goto done;
  765.     }
  766.     switch (selIndex) {
  767.         case SELECTION_ADJUST: {
  768.     if (objc != 4) {
  769.         Tcl_WrongNumArgs(interp, 3, objv, "index");
  770. goto error;
  771.     }
  772.     if (GetEntryIndex(interp, entryPtr, 
  773.                             Tcl_GetString(objv[3]), &index) != TCL_OK) {
  774.         goto error;
  775.     }
  776.     if (entryPtr->selectFirst >= 0) {
  777.         int half1, half2;
  778. half1 = (entryPtr->selectFirst 
  779.         + entryPtr->selectLast)/2;
  780. half2 = (entryPtr->selectFirst 
  781. + entryPtr->selectLast + 1)/2;
  782. if (index < half1) {
  783.     entryPtr->selectAnchor = entryPtr->selectLast;
  784. } else if (index > half2) {
  785.     entryPtr->selectAnchor = entryPtr->selectFirst;
  786. } else {
  787.   /*
  788.    * We're at about the halfway point in the 
  789.    * selection; just keep the existing anchor.
  790.    */
  791. }
  792.     }
  793.     EntrySelectTo(entryPtr, index);
  794.     break;
  795. }
  796.         case SELECTION_CLEAR: {
  797.     if (objc != 3) {
  798.         Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
  799. goto error;
  800.     }
  801.     if (entryPtr->selectFirst >= 0) {
  802.         entryPtr->selectFirst = -1;
  803. entryPtr->selectLast = -1;
  804. EventuallyRedraw(entryPtr);
  805.     }
  806.     goto done;
  807. }
  808.         case SELECTION_FROM: {
  809.     if (objc != 4) {
  810.         Tcl_WrongNumArgs(interp, 3, objv, "index");
  811. goto error;
  812.     }
  813.     if (GetEntryIndex(interp, entryPtr, 
  814.                             Tcl_GetString(objv[3]), &index) != TCL_OK) {
  815.         goto error;
  816.     }
  817.     entryPtr->selectAnchor = index;
  818.     break;
  819. }
  820.         case SELECTION_PRESENT: {
  821.     if (objc != 3) {
  822.         Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
  823. goto error;
  824.     }
  825.     Tcl_SetObjResult(interp,
  826.     Tcl_NewBooleanObj((entryPtr->selectFirst >= 0)));
  827.     goto done;
  828. }
  829.         case SELECTION_RANGE: {
  830.     if (objc != 5) {
  831.         Tcl_WrongNumArgs(interp, 3, objv, "start end");
  832. goto error;
  833.     }
  834.     if (GetEntryIndex(interp, entryPtr, 
  835.                             Tcl_GetString(objv[3]), &index) != TCL_OK) {
  836.         goto error;
  837.     }
  838.     if (GetEntryIndex(interp, entryPtr, 
  839.                             Tcl_GetString(objv[4]),& index2) != TCL_OK) {
  840.         goto error;
  841.     }
  842.     if (index >= index2) {
  843.         entryPtr->selectFirst = -1;
  844. entryPtr->selectLast = -1;
  845.     } else {
  846.         entryPtr->selectFirst = index;
  847. entryPtr->selectLast = index2;
  848.     }
  849.     if (!(entryPtr->flags & GOT_SELECTION)
  850.     && (entryPtr->exportSelection)) {
  851.         Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, 
  852.         EntryLostSelection, (ClientData) entryPtr);
  853. entryPtr->flags |= GOT_SELECTION;
  854.     }
  855.     EventuallyRedraw(entryPtr);
  856.     break;
  857. }
  858.         case SELECTION_TO: {
  859.     if (objc != 4) {
  860.         Tcl_WrongNumArgs(interp, 3, objv, "index");
  861. goto error;
  862.     }
  863.     if (GetEntryIndex(interp, entryPtr, 
  864.                             Tcl_GetString(objv[3]), &index) != TCL_OK) {
  865.         goto error;
  866.     }
  867.     EntrySelectTo(entryPtr, index);
  868.     break;
  869. }
  870.     }
  871.     break;
  872. }
  873.         case COMMAND_VALIDATE: {
  874.     int code;
  875.     if (objc != 2) {
  876. Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
  877. goto error;
  878.     }
  879.     selIndex = entryPtr->validate;
  880.     entryPtr->validate = VALIDATE_ALL;
  881.     code = EntryValidateChange(entryPtr, (char *) NULL,
  882.        entryPtr->string, -1, VALIDATE_FORCED);
  883.     if (entryPtr->validate != VALIDATE_NONE) {
  884. entryPtr->validate = selIndex;
  885.     }
  886.     Tcl_SetObjResult(interp, Tcl_NewBooleanObj((code == TCL_OK)));
  887.     break;
  888. }
  889.         case COMMAND_XVIEW: {
  890.     int index;
  891.     if (objc == 2) {
  892.         double first, last;
  893. char buf[TCL_DOUBLE_SPACE * 2];
  894.     
  895. EntryVisibleRange(entryPtr, &first, &last);
  896. sprintf(buf, "%g %g", first, last);
  897. Tcl_SetResult(interp, buf, TCL_VOLATILE);
  898. goto done;
  899.     } else if (objc == 3) {
  900.         if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]), 
  901.                         &index) != TCL_OK) {
  902.     goto error;
  903. }
  904.     } else {
  905.         double fraction;
  906. int count;
  907. index = entryPtr->leftIndex;
  908. switch (Tk_GetScrollInfoObj(interp, objc, objv, &fraction, 
  909.                         &count)) {
  910.     case TK_SCROLL_ERROR: {
  911.         goto error;
  912.     }
  913.     case TK_SCROLL_MOVETO: {
  914.         index = (int) ((fraction * entryPtr->numChars) + 0.5);
  915. break;
  916.     }
  917.     case TK_SCROLL_PAGES: {
  918.         int charsPerPage;
  919.     
  920. charsPerPage = ((Tk_Width(entryPtr->tkwin)
  921.              - 2 * entryPtr->inset) 
  922.                                 / entryPtr->avgWidth) - 2;
  923. if (charsPerPage < 1) {
  924.     charsPerPage = 1;
  925. }
  926. index += count * charsPerPage;
  927. break;
  928.     }
  929.     case TK_SCROLL_UNITS: {
  930.         index += count;
  931. break;
  932.     }
  933. }
  934.     }
  935.     if (index >= entryPtr->numChars) {
  936.         index = entryPtr->numChars - 1;
  937.     }
  938.     if (index < 0) {
  939.         index = 0;
  940.     }
  941.     entryPtr->leftIndex = index;
  942.     entryPtr->flags |= UPDATE_SCROLLBAR;
  943.     EntryComputeGeometry(entryPtr);
  944.     EventuallyRedraw(entryPtr);
  945.     break;
  946. }
  947.     }
  948.     done:
  949.     Tcl_Release((ClientData) entryPtr);
  950.     return result;
  951.     error:
  952.     Tcl_Release((ClientData) entryPtr);
  953.     return TCL_ERROR;
  954. }
  955. /*
  956.  *----------------------------------------------------------------------
  957.  *
  958.  * DestroyEntry --
  959.  *
  960.  * This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
  961.  * to clean up the internal structure of an entry at a safe time
  962.  * (when no-one is using it anymore).
  963.  *
  964.  * Results:
  965.  * None.
  966.  *
  967.  * Side effects:
  968.  * Everything associated with the entry is freed up.
  969.  *
  970.  *----------------------------------------------------------------------
  971.  */
  972. static void
  973. DestroyEntry(memPtr)
  974.     char *memPtr; /* Info about entry widget. */
  975. {
  976.     Entry *entryPtr = (Entry *) memPtr;
  977.     /*
  978.      * Free up all the stuff that requires special handling, then
  979.      * let Tk_FreeOptions handle all the standard option-related
  980.      * stuff.
  981.      */
  982.     ckfree((char *)entryPtr->string);
  983.     if (entryPtr->textVarName != NULL) {
  984. Tcl_UntraceVar(entryPtr->interp, entryPtr->textVarName,
  985. TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  986. EntryTextVarProc, (ClientData) entryPtr);
  987. entryPtr->flags &= ~ENTRY_VAR_TRACED;
  988.     }
  989.     if (entryPtr->textGC != None) {
  990. Tk_FreeGC(entryPtr->display, entryPtr->textGC);
  991.     }
  992.     if (entryPtr->selTextGC != None) {
  993. Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
  994.     }
  995.     Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler);
  996.     if (entryPtr->displayString != entryPtr->string) {
  997. ckfree((char *)entryPtr->displayString);
  998.     }
  999.     if (entryPtr->type == TK_SPINBOX) {
  1000. Spinbox *sbPtr = (Spinbox *) entryPtr;
  1001. if (sbPtr->listObj != NULL) {
  1002.     Tcl_DecrRefCount(sbPtr->listObj);
  1003.     sbPtr->listObj = NULL;
  1004. }
  1005. if (sbPtr->formatBuf) {
  1006.     ckfree(sbPtr->formatBuf);
  1007. }
  1008.     }
  1009.     Tk_FreeTextLayout(entryPtr->textLayout);
  1010.     Tk_FreeConfigOptions((char *) entryPtr, entryPtr->optionTable,
  1011.     entryPtr->tkwin);
  1012.     Tcl_Release((ClientData) entryPtr->tkwin);
  1013.     entryPtr->tkwin = NULL;
  1014.     ckfree((char *) entryPtr);
  1015. }
  1016. /*
  1017.  *----------------------------------------------------------------------
  1018.  *
  1019.  * ConfigureEntry --
  1020.  *
  1021.  * This procedure is called to process an argv/argc list, plus
  1022.  * the Tk option database, in order to configure (or reconfigure)
  1023.  * an entry widget.
  1024.  *
  1025.  * Results:
  1026.  * The return value is a standard Tcl result.  If TCL_ERROR is
  1027.  * returned, then the interp's result contains an error message.
  1028.  *
  1029.  * Side effects:
  1030.  * Configuration information, such as colors, border width,
  1031.  * etc. get set for entryPtr;  old resources get freed,
  1032.  * if there were any.
  1033.  *
  1034.  *----------------------------------------------------------------------
  1035.  */
  1036. static int
  1037. ConfigureEntry(interp, entryPtr, objc, objv, flags)
  1038.     Tcl_Interp *interp; /* Used for error reporting. */
  1039.     Entry *entryPtr; /* Information about widget; may or may not
  1040.  * already have values for some fields. */
  1041.     int objc; /* Number of valid entries in argv. */
  1042.     Tcl_Obj *CONST objv[]; /* Argument objects. */
  1043.     int flags; /* Flags to pass to Tk_ConfigureWidget. */
  1044. {
  1045.     Tk_SavedOptions savedOptions;
  1046.     Tk_3DBorder border;
  1047.     Tcl_Obj *errorResult = NULL;
  1048.     Spinbox *sbPtr = (Spinbox *) entryPtr; /* Only used when this widget
  1049.  * is of type TK_SPINBOX */
  1050.     char *oldValues = NULL; /* lint initialization */
  1051.     char *oldFormat = NULL; /* lint initialization */
  1052.     int error;
  1053.     int oldExport = 0; /* lint initialization */
  1054.     int valuesChanged = 0; /* lint initialization */
  1055.     double oldFrom = 0.0; /* lint initialization */
  1056.     double oldTo = 0.0; /* lint initialization */
  1057.     /*
  1058.      * Eliminate any existing trace on a variable monitored by the entry.
  1059.      */
  1060.     if ((entryPtr->textVarName != NULL)
  1061.     && (entryPtr->flags & ENTRY_VAR_TRACED)) {
  1062. Tcl_UntraceVar(interp, entryPtr->textVarName, 
  1063. TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  1064. EntryTextVarProc, (ClientData) entryPtr);
  1065. entryPtr->flags &= ~ENTRY_VAR_TRACED;
  1066.     }
  1067.     /*
  1068.      * Store old values that we need to effect certain behavior if
  1069.      * they change value
  1070.      */
  1071.     oldExport = entryPtr->exportSelection;
  1072.     if (entryPtr->type == TK_SPINBOX) {
  1073. oldValues = sbPtr->valueStr;
  1074. oldFormat = sbPtr->reqFormat;
  1075. oldFrom = sbPtr->fromValue;
  1076. oldTo = sbPtr->toValue;
  1077.     }
  1078.     for (error = 0; error <= 1; error++) {
  1079. if (!error) {
  1080.     /*
  1081.      * First pass: set options to new values.
  1082.      */
  1083.     if (Tk_SetOptions(interp, (char *) entryPtr,
  1084.     entryPtr->optionTable, objc, objv,
  1085.     entryPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
  1086. continue;
  1087.     }
  1088. } else {
  1089.     /*
  1090.      * Second pass: restore options to old values.
  1091.      */
  1092.     errorResult = Tcl_GetObjResult(interp);
  1093.     Tcl_IncrRefCount(errorResult);
  1094.     Tk_RestoreSavedOptions(&savedOptions);
  1095. }
  1096. /*
  1097.  * A few other options also need special processing, such as parsing
  1098.  * the geometry and setting the background from a 3-D border.
  1099.  */
  1100. if ((entryPtr->state == STATE_DISABLED) &&
  1101. (entryPtr->disabledBorder != NULL)) {
  1102.     border = entryPtr->disabledBorder;
  1103. } else if ((entryPtr->state == STATE_READONLY) &&
  1104. (entryPtr->readonlyBorder != NULL)) {
  1105.     border = entryPtr->readonlyBorder;
  1106. } else {
  1107.     border = entryPtr->normalBorder;
  1108. }
  1109. Tk_SetBackgroundFromBorder(entryPtr->tkwin, border);
  1110. if (entryPtr->insertWidth <= 0) {
  1111.     entryPtr->insertWidth = 2;
  1112. }
  1113. if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) {
  1114.     entryPtr->insertBorderWidth = entryPtr->insertWidth/2;
  1115. }
  1116. if (entryPtr->type == TK_SPINBOX) {
  1117.     if (sbPtr->fromValue > sbPtr->toValue) {
  1118. Tcl_SetResult(interp,
  1119. "-to value must be greater than -from value",
  1120. TCL_VOLATILE);
  1121. continue;
  1122.     }
  1123.     if (sbPtr->reqFormat && (oldFormat != sbPtr->reqFormat)) {
  1124. /*
  1125.  * Make sure that the given format is somewhat correct, and
  1126.  * calculate the minimum space we'll need for the values as
  1127.  * strings.
  1128.  */
  1129. int min, max;
  1130. size_t formatLen, formatSpace = TCL_DOUBLE_SPACE;
  1131. char fbuf[4], *fmt = sbPtr->reqFormat;
  1132. formatLen = strlen(fmt);
  1133. if ((fmt[0] != '%') || (fmt[formatLen-1] != 'f')) {
  1134.     badFormatOpt:
  1135.     Tcl_AppendResult(interp, "bad spinbox format specifier "",
  1136.     sbPtr->reqFormat, """, (char *) NULL);
  1137.     continue;
  1138. }
  1139. if ((sscanf(fmt, "%%%d.%d%[f]", &min, &max, fbuf) == 3)
  1140. && (max >= 0)) {
  1141.     formatSpace = min + max + 1;
  1142. } else if (((sscanf(fmt, "%%.%d%[f]", &min, fbuf) == 2)
  1143. || (sscanf(fmt, "%%%d%[f]", &min, fbuf) == 2)
  1144. || (sscanf(fmt, "%%%d.%[f]", &min, fbuf) == 2))
  1145. && (min >= 0)) {
  1146.     formatSpace = min + 1;
  1147. } else {
  1148.     goto badFormatOpt;
  1149. }
  1150. if (formatSpace < TCL_DOUBLE_SPACE) {
  1151.     formatSpace = TCL_DOUBLE_SPACE;
  1152. }
  1153. sbPtr->formatBuf = ckrealloc(sbPtr->formatBuf, formatSpace);
  1154. /*
  1155.  * We perturb the value of oldFrom to allow us to go into
  1156.  * the branch below that will reformat the displayed value.
  1157.  */
  1158. oldFrom = sbPtr->fromValue - 1;
  1159.     }
  1160.     /*
  1161.      * See if we have to rearrange our listObj data
  1162.      */
  1163.     if (oldValues != sbPtr->valueStr) {
  1164. if (sbPtr->listObj != NULL) {
  1165.     Tcl_DecrRefCount(sbPtr->listObj);
  1166. }
  1167. sbPtr->listObj = NULL;
  1168. if (sbPtr->valueStr != NULL) {
  1169.     Tcl_Obj *newObjPtr;
  1170.     int nelems;
  1171.     newObjPtr = Tcl_NewStringObj(sbPtr->valueStr, -1);
  1172.     if (Tcl_ListObjLength(interp, newObjPtr, &nelems)
  1173.     != TCL_OK) {
  1174. valuesChanged = -1;
  1175. continue;
  1176.     }
  1177.     sbPtr->listObj = newObjPtr;
  1178.     Tcl_IncrRefCount(sbPtr->listObj);
  1179.     sbPtr->nElements = nelems;
  1180.     sbPtr->eIndex = 0;
  1181.     valuesChanged++;
  1182. }
  1183.     }
  1184. }
  1185. /*
  1186.  * Restart the cursor timing sequence in case the on-time or 
  1187.  * off-time just changed.  Set validate temporarily to none,
  1188.  * so the configure doesn't cause it to be triggered.
  1189.  */
  1190. if (entryPtr->flags & GOT_FOCUS) {
  1191.     int validate = entryPtr->validate;
  1192.     entryPtr->validate = VALIDATE_NONE;
  1193.     EntryFocusProc(entryPtr, 1);
  1194.     entryPtr->validate = validate;
  1195. }
  1196. /*
  1197.  * Claim the selection if we've suddenly started exporting it.
  1198.  */
  1199. if (entryPtr->exportSelection && (!oldExport)
  1200.         && (entryPtr->selectFirst != -1)
  1201.         && !(entryPtr->flags & GOT_SELECTION)) {
  1202.     Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
  1203.     (ClientData) entryPtr);
  1204.     entryPtr->flags |= GOT_SELECTION;
  1205. }
  1206. /*
  1207.  * Recompute the window's geometry and arrange for it to be
  1208.  * redisplayed.
  1209.  */
  1210. Tk_SetInternalBorder(entryPtr->tkwin,
  1211.         entryPtr->borderWidth + entryPtr->highlightWidth);
  1212. if (entryPtr->highlightWidth <= 0) {
  1213.     entryPtr->highlightWidth = 0;
  1214. }
  1215. entryPtr->inset = entryPtr->highlightWidth 
  1216.         + entryPtr->borderWidth + XPAD;
  1217. break;
  1218.     }
  1219.     if (!error) {
  1220. Tk_FreeSavedOptions(&savedOptions);
  1221.     }
  1222.     /*
  1223.      * If the entry is tied to the value of a variable, create the variable if
  1224.      * it doesn't exist, and set the entry's value from the variable's value.
  1225.      */
  1226.     if (entryPtr->textVarName != NULL) {
  1227. CONST char *value;
  1228. value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
  1229. if (value == NULL) {
  1230.     EntryValueChanged(entryPtr, NULL);
  1231. } else {
  1232.     EntrySetValue(entryPtr, value);
  1233. }
  1234.     }
  1235.     if (entryPtr->type == TK_SPINBOX) {
  1236. ComputeFormat(sbPtr);
  1237. if (valuesChanged > 0) {
  1238.     Tcl_Obj *objPtr;
  1239.     /*
  1240.      * No check for error return, because there shouldn't be one
  1241.      * given the check for valid list above
  1242.      */
  1243.     Tcl_ListObjIndex(interp, sbPtr->listObj, 0, &objPtr);
  1244.     EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
  1245. } else if ((sbPtr->valueStr == NULL)
  1246. && !DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)
  1247. && (!DOUBLES_EQ(sbPtr->fromValue, oldFrom)
  1248. || !DOUBLES_EQ(sbPtr->toValue, oldTo))) {
  1249.     /*
  1250.      * If the valueStr is empty and -from && -to are specified, check
  1251.      * to see if the current string is within the range.  If not,
  1252.      * it will be constrained to the nearest edge.  If the current
  1253.      * string isn't a double value, we set it to -from.
  1254.      */
  1255.     int code;
  1256.     double dvalue;
  1257.     code = Tcl_GetDouble(NULL, entryPtr->string, &dvalue);
  1258.     if (code != TCL_OK) {
  1259. dvalue = sbPtr->fromValue;
  1260.     } else {
  1261. if (dvalue > sbPtr->toValue) {
  1262.     dvalue = sbPtr->toValue;
  1263. } else if (dvalue < sbPtr->fromValue) {
  1264.     dvalue = sbPtr->fromValue;
  1265. }
  1266.     }
  1267.     sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
  1268.     EntryValueChanged(entryPtr, sbPtr->formatBuf);
  1269. }
  1270.     }
  1271.     /*
  1272.      * Set up a trace on the variable's value after we've possibly
  1273.      * constrained the value according to new -from/-to values.
  1274.      */
  1275.     if ((entryPtr->textVarName != NULL)
  1276.     && !(entryPtr->flags & ENTRY_VAR_TRACED)) {
  1277. Tcl_TraceVar(interp, entryPtr->textVarName,
  1278. TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
  1279. EntryTextVarProc, (ClientData) entryPtr);
  1280. entryPtr->flags |= ENTRY_VAR_TRACED;
  1281.     }
  1282.     EntryWorldChanged((ClientData) entryPtr);
  1283.     if (error) {
  1284.         Tcl_SetObjResult(interp, errorResult);
  1285. Tcl_DecrRefCount(errorResult);
  1286. return TCL_ERROR;
  1287.     } else {
  1288.         return TCL_OK;
  1289.     }
  1290. }
  1291. /*
  1292.  *---------------------------------------------------------------------------
  1293.  *
  1294.  * EntryWorldChanged --
  1295.  *
  1296.  *      This procedure is called when the world has changed in some
  1297.  *      way and the widget needs to recompute all its graphics contexts
  1298.  * and determine its new geometry.
  1299.  *
  1300.  * Results:
  1301.  *      None.
  1302.  *
  1303.  * Side effects:
  1304.  *      Entry will be relayed out and redisplayed.
  1305.  *
  1306.  *---------------------------------------------------------------------------
  1307.  */
  1308.  
  1309. static void
  1310. EntryWorldChanged(instanceData)
  1311.     ClientData instanceData; /* Information about widget. */
  1312. {
  1313.     XGCValues gcValues;
  1314.     GC gc = None;
  1315.     unsigned long mask;
  1316.     Tk_3DBorder border;
  1317.     XColor *colorPtr;
  1318.     Entry *entryPtr = (Entry *) instanceData;
  1319.     entryPtr->avgWidth = Tk_TextWidth(entryPtr->tkfont, "0", 1);
  1320.     if (entryPtr->avgWidth == 0) {
  1321. entryPtr->avgWidth = 1;
  1322.     }
  1323.     if (entryPtr->type == TK_SPINBOX) {
  1324. /*
  1325.  * Compute the button width for a spinbox
  1326.  */
  1327. entryPtr->xWidth = entryPtr->avgWidth + 2 * (1+XPAD);
  1328. if (entryPtr->xWidth < 11) {
  1329.     entryPtr->xWidth = 11; /* we want a min visible size */
  1330. }
  1331.     }
  1332.     /*
  1333.      * Default background and foreground are from the normal state.
  1334.      * In a disabled state, both of those may be overridden; in the readonly
  1335.      * state, the background may be overridden.
  1336.      */
  1337.     border = entryPtr->normalBorder;
  1338.     colorPtr = entryPtr->fgColorPtr;
  1339.     switch (entryPtr->state) {
  1340. case STATE_DISABLED:
  1341.     if (entryPtr->disabledBorder != NULL) {
  1342. border = entryPtr->disabledBorder;
  1343.     }
  1344.     if (entryPtr->dfgColorPtr != NULL) {
  1345. colorPtr = entryPtr->dfgColorPtr;
  1346.     }
  1347.     break;
  1348. case STATE_READONLY:
  1349.     if (entryPtr->readonlyBorder != NULL) {
  1350. border = entryPtr->readonlyBorder;
  1351.     }
  1352.     break;
  1353.     }
  1354.     Tk_SetBackgroundFromBorder(entryPtr->tkwin, border);
  1355.     gcValues.foreground = colorPtr->pixel;
  1356.     gcValues.font = Tk_FontId(entryPtr->tkfont);
  1357.     gcValues.graphics_exposures = False;
  1358.     mask = GCForeground | GCFont | GCGraphicsExposures;
  1359.     gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues);
  1360.     if (entryPtr->textGC != None) {
  1361. Tk_FreeGC(entryPtr->display, entryPtr->textGC);
  1362.     }
  1363.     entryPtr->textGC = gc;
  1364.     if (entryPtr->selFgColorPtr != NULL) {
  1365. gcValues.foreground = entryPtr->selFgColorPtr->pixel;
  1366.     }
  1367.     gcValues.font = Tk_FontId(entryPtr->tkfont);
  1368.     mask = GCForeground | GCFont;
  1369.     gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues);
  1370.     if (entryPtr->selTextGC != None) {
  1371. Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
  1372.     }
  1373.     entryPtr->selTextGC = gc;
  1374.     /*
  1375.      * Recompute the window's geometry and arrange for it to be
  1376.      * redisplayed.
  1377.      */
  1378.     EntryComputeGeometry(entryPtr);
  1379.     entryPtr->flags |= UPDATE_SCROLLBAR;
  1380.     EventuallyRedraw(entryPtr);
  1381. }
  1382. #ifndef MAC_OSX_TK 
  1383. /*
  1384.  *--------------------------------------------------------------
  1385.  *
  1386.  * TkpDrawEntryBorderAndFocus --
  1387.  *
  1388.  * This procedure redraws the border of an entry widget.
  1389.  *      It overrides the generic border drawing code if the 
  1390.  *      entry widget parameters are such that the native widget
  1391.  *      drawing is a good fit.
  1392.  *      This version just returns o, so platforms that don't
  1393.  *      do special native drawing don't have to implement it.
  1394.  *
  1395.  * Results:
  1396.  * 1 if it has drawn the border, 0 if not.
  1397.  *
  1398.  * Side effects:
  1399.  * May draw the entry border into pixmap.
  1400.  *
  1401.  *--------------------------------------------------------------
  1402.  */
  1403. int
  1404. TkpDrawEntryBorderAndFocus(entryPtr, pixmap, isSpinbox)
  1405.     Entry *entryPtr;
  1406.     Drawable pixmap;
  1407.     int isSpinbox;
  1408. {
  1409.     return 0;
  1410. }
  1411. /*
  1412.  *--------------------------------------------------------------
  1413.  *
  1414.  * TkpDrawSpinboxButtons --
  1415.  *
  1416.  * This procedure redraws the buttons of an spinbox widget.
  1417.  *      It overrides the generic button drawing code if the 
  1418.  *      spinbox widget parameters are such that the native widget
  1419.  *      drawing is a good fit.
  1420.  *      This version just returns 0, so platforms that don't
  1421.  *      do special native drawing don't have to implement it.
  1422.  *
  1423.  * Results:
  1424.  * 1 if it has drawn the border, 0 if not.
  1425.  *
  1426.  * Side effects:
  1427.  * May draw the entry border into pixmap.
  1428.  *
  1429.  *--------------------------------------------------------------
  1430.  */
  1431. int
  1432. TkpDrawSpinboxButtons(sbPtr, pixmap)
  1433.     Spinbox *sbPtr; 
  1434.     Pixmap pixmap;
  1435. {
  1436.     return 0;
  1437. }
  1438. #endif /* Not MAC_OSX_TK */
  1439. /*
  1440.  *--------------------------------------------------------------
  1441.  *
  1442.  * DisplayEntry --
  1443.  *
  1444.  * This procedure redraws the contents of an entry window.
  1445.  *
  1446.  * Results:
  1447.  * None.
  1448.  *
  1449.  * Side effects:
  1450.  * Information appears on the screen.
  1451.  *
  1452.  *--------------------------------------------------------------
  1453.  */
  1454. static void
  1455. DisplayEntry(clientData)
  1456.     ClientData clientData; /* Information about window. */
  1457. {
  1458.     Entry *entryPtr = (Entry *) clientData;
  1459.     Tk_Window tkwin = entryPtr->tkwin;
  1460.     int baseY, selStartX, selEndX, cursorX;
  1461.     int showSelection, xBound;
  1462.     Tk_FontMetrics fm;
  1463.     Pixmap pixmap;
  1464.     Tk_3DBorder border;
  1465.     entryPtr->flags &= ~REDRAW_PENDING;
  1466.     if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(tkwin)) {
  1467. return;
  1468.     }
  1469.     Tk_GetFontMetrics(entryPtr->tkfont, &fm);
  1470.     /*
  1471.      * Update the scrollbar if that's needed.
  1472.      */
  1473.     if (entryPtr->flags & UPDATE_SCROLLBAR) {
  1474. entryPtr->flags &= ~UPDATE_SCROLLBAR;
  1475.         /*
  1476.  * Preserve/Release because updating the scrollbar can have
  1477.  * the side-effect of destroying or unmapping the entry widget.
  1478.  */
  1479. Tcl_Preserve((ClientData) entryPtr);
  1480. EntryUpdateScrollbar(entryPtr);
  1481. if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(tkwin)) {
  1482.     Tcl_Release((ClientData) entryPtr);
  1483.     return;
  1484. }
  1485. Tcl_Release((ClientData) entryPtr);
  1486.     }
  1487. #ifndef TK_NO_DOUBLE_BUFFERING
  1488.     /*
  1489.      * In order to avoid screen flashes, this procedure redraws the
  1490.      * textual area of the entry into off-screen memory, then copies
  1491.      * it back on-screen in a single operation.  This means there's
  1492.      * no point in time where the on-screen image has been cleared.
  1493.      */
  1494.     pixmap = Tk_GetPixmap(entryPtr->display, Tk_WindowId(tkwin),
  1495.     Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
  1496. #else
  1497.     pixmap = Tk_WindowId(tkwin);
  1498. #endif /* TK_NO_DOUBLE_BUFFERING */
  1499.     /*
  1500.      * Compute x-coordinate of the pixel just after last visible
  1501.      * one, plus vertical position of baseline of text.
  1502.      */
  1503.     xBound = Tk_Width(tkwin) - entryPtr->inset - entryPtr->xWidth;
  1504.     baseY = (Tk_Height(tkwin) + fm.ascent - fm.descent) / 2;
  1505.     /*
  1506.      * On Windows and Mac, we need to hide the selection whenever we
  1507.      * don't have the focus.
  1508.      */
  1509.     if (TkpAlwaysShowSelection(entryPtr->tkwin)) {
  1510. showSelection = 1;
  1511.     } else {
  1512. showSelection = (entryPtr->flags & GOT_FOCUS);
  1513.     }
  1514.     /*
  1515.      * Draw the background in three layers.  From bottom to top the
  1516.      * layers are:  normal background, selection background, and
  1517.      * insertion cursor background.
  1518.      */
  1519.     if ((entryPtr->state == STATE_DISABLED) &&
  1520.     (entryPtr->disabledBorder != NULL)) {
  1521. border = entryPtr->disabledBorder;
  1522.     } else if ((entryPtr->state == STATE_READONLY) &&
  1523.     (entryPtr->readonlyBorder != NULL)) {
  1524. border = entryPtr->readonlyBorder;
  1525.     } else {
  1526. border = entryPtr->normalBorder;
  1527.     }
  1528.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  1529.     0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
  1530.     if (showSelection && (entryPtr->state != STATE_DISABLED)
  1531.     && (entryPtr->selectLast > entryPtr->leftIndex)) {
  1532. if (entryPtr->selectFirst <= entryPtr->leftIndex) {
  1533.     selStartX = entryPtr->leftX;
  1534. } else {
  1535.     Tk_CharBbox(entryPtr->textLayout, entryPtr->selectFirst,
  1536.     &selStartX, NULL, NULL, NULL);
  1537.     selStartX += entryPtr->layoutX;
  1538. }
  1539. if ((selStartX - entryPtr->selBorderWidth) < xBound) {
  1540.     Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast,
  1541.     &selEndX, NULL, NULL, NULL);
  1542.     selEndX += entryPtr->layoutX;
  1543.     Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder,
  1544.     selStartX - entryPtr->selBorderWidth,
  1545.     baseY - fm.ascent - entryPtr->selBorderWidth,
  1546.     (selEndX - selStartX) + 2*entryPtr->selBorderWidth,
  1547.     (fm.ascent + fm.descent) + 2*entryPtr->selBorderWidth,
  1548.     entryPtr->selBorderWidth, 
  1549. #ifndef MAC_OSX_TK
  1550.     TK_RELIEF_RAISED
  1551. #else
  1552.     MAC_OSX_ENTRY_SELECT_RELIEF
  1553. #endif
  1554.     );
  1555.     }
  1556.     /*
  1557.      * Draw a special background for the insertion cursor, overriding
  1558.      * even the selection background.  As a special hack to keep the
  1559.      * cursor visible when the insertion cursor color is the same as
  1560.      * the color for selected text (e.g., on mono displays), write
  1561.      * background in the cursor area (instead of nothing) when the
  1562.      * cursor isn't on.  Otherwise the selection would hide the cursor.
  1563.      */
  1564.     if ((entryPtr->state == STATE_NORMAL) && (entryPtr->flags & GOT_FOCUS)) {
  1565. Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &cursorX, NULL,
  1566. NULL, NULL);
  1567. cursorX += entryPtr->layoutX;
  1568. cursorX -= (entryPtr->insertWidth)/2;
  1569. Tk_SetCaretPos(entryPtr->tkwin, cursorX, baseY - fm.ascent,
  1570. fm.ascent + fm.descent);
  1571. if (entryPtr->insertPos >= entryPtr->leftIndex) {
  1572.     if (cursorX < xBound) {
  1573. if (entryPtr->flags & CURSOR_ON) {
  1574.     Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder,
  1575.     cursorX, baseY - fm.ascent, entryPtr->insertWidth,
  1576.     fm.ascent + fm.descent,
  1577.     entryPtr->insertBorderWidth,
  1578.     TK_RELIEF_RAISED);
  1579. } else if (entryPtr->insertBorder == entryPtr->selBorder) {
  1580.     Tk_Fill3DRectangle(tkwin, pixmap, border,
  1581.     cursorX, baseY - fm.ascent, entryPtr->insertWidth,
  1582.     fm.ascent + fm.descent, 0, TK_RELIEF_FLAT);
  1583. }
  1584.     }
  1585. }
  1586.     }
  1587.     /*
  1588.      * Draw the text in two pieces:  first the unselected portion, then the
  1589.      * selected portion on top of it.
  1590.      */
  1591.     Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->textGC,
  1592.     entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY,
  1593.     entryPtr->leftIndex, entryPtr->numChars);
  1594.     if (showSelection && (entryPtr->state != STATE_DISABLED)
  1595.     && (entryPtr->selTextGC != entryPtr->textGC)
  1596.     && (entryPtr->selectFirst < entryPtr->selectLast)) {
  1597. int selFirst;
  1598. if (entryPtr->selectFirst < entryPtr->leftIndex) {
  1599.     selFirst = entryPtr->leftIndex;
  1600. } else {
  1601.     selFirst = entryPtr->selectFirst;
  1602. }
  1603. Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC,
  1604. entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY,
  1605. selFirst, entryPtr->selectLast);
  1606.     }
  1607.     if (entryPtr->type == TK_SPINBOX) {
  1608. int startx, height, inset, pad, tHeight, xWidth;
  1609. Spinbox *sbPtr = (Spinbox *) entryPtr;
  1610. /*
  1611.  * Draw the spin button controls.
  1612.  */
  1613.         if (TkpDrawSpinboxButtons(sbPtr, pixmap) == 0) {
  1614.             xWidth = entryPtr->xWidth;
  1615.             pad    = XPAD + 1;
  1616.             inset  = entryPtr->inset - XPAD;
  1617.             startx = Tk_Width(tkwin) - (xWidth + inset);
  1618.             height = (Tk_Height(tkwin) - 2*inset)/2;
  1619. #if 0
  1620.             Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
  1621.                     startx, inset, xWidth, height, 1, sbPtr->buRelief);
  1622.             Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
  1623.                     startx, inset+height, xWidth, height, 1, sbPtr->bdRelief);
  1624. #else
  1625.     Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
  1626.     startx, inset, xWidth, height, 1,
  1627.     (sbPtr->selElement == SEL_BUTTONUP) ?
  1628.     TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
  1629.     Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
  1630.     startx, inset+height, xWidth, height, 1,
  1631.     (sbPtr->selElement == SEL_BUTTONDOWN) ?
  1632.     TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
  1633. #endif
  1634.     
  1635.             xWidth -= 2*pad;
  1636.             /*
  1637.              * Only draw the triangles if we have enough display space
  1638.              */
  1639.             if ((xWidth > 1)) {
  1640.                 XPoint points[3];
  1641.                 int starty, space, offset;
  1642.                 space = height - 2*pad;
  1643.                 /*
  1644.                  * Ensure width of triangle is odd to guarantee a sharp tip
  1645.                  */
  1646.                 if (!(xWidth % 2)) {
  1647.                     xWidth++;
  1648.                 }
  1649.                 tHeight = (xWidth + 1) / 2;
  1650.                 if (tHeight > space) {
  1651.                     tHeight = space;
  1652.                 }
  1653.                 space   = (space - tHeight) / 2;
  1654.                 startx += pad;
  1655.                 starty  = inset + height - pad - space;
  1656.                 offset  = (sbPtr->selElement == SEL_BUTTONUP);
  1657.                 /*
  1658.                  * The points are slightly different for the up and down arrows
  1659.                  * because (for *.x), we need to account for a bug in the way
  1660.                  * XFillPolygon draws triangles, and we want to shift
  1661.                  * the arrows differently when allowing for depressed behavior.
  1662.                  */
  1663.                 points[0].x = startx + offset;
  1664.                 points[0].y = starty + (offset ? 0 : -1);
  1665.                 points[1].x = startx + xWidth/2 + offset;
  1666.                 points[1].y = starty - tHeight + (offset ? 0 : -1);
  1667.                 points[2].x = startx + xWidth + offset;
  1668.                 points[2].y = points[0].y;
  1669.                 XFillPolygon(entryPtr->display, pixmap, entryPtr->textGC,
  1670.                         points, 3, Convex, CoordModeOrigin);
  1671.                 starty = inset + height + pad + space;
  1672.                 offset = (sbPtr->selElement == SEL_BUTTONDOWN);
  1673.                 points[0].x = startx + 1 + offset;
  1674.                 points[0].y = starty + (offset ? 1 : 0);
  1675.                 points[1].x = startx + xWidth/2 + offset;
  1676.                 points[1].y = starty + tHeight + (offset ? 0 : -1);
  1677.                 points[2].x = startx - 1 + xWidth + offset;
  1678.                 points[2].y = points[0].y;
  1679.                 XFillPolygon(entryPtr->display, pixmap, entryPtr->textGC,
  1680.                         points, 3, Convex, CoordModeOrigin);
  1681.             }
  1682.         }
  1683.     }
  1684.     /*
  1685.      * Draw the border and focus highlight last, so they will overwrite
  1686.      * any text that extends past the viewable part of the window.
  1687.      */
  1688.     if (!TkpDrawEntryBorderAndFocus(entryPtr, pixmap, 
  1689.             (entryPtr->type == TK_SPINBOX))) {
  1690.         xBound = entryPtr->highlightWidth;
  1691.         if (entryPtr->relief != TK_RELIEF_FLAT) {
  1692.     Tk_Draw3DRectangle(tkwin, pixmap, border, xBound, xBound,
  1693.                     Tk_Width(tkwin) - 2 * xBound,
  1694.     Tk_Height(tkwin) - 2 * xBound,
  1695.     entryPtr->borderWidth, entryPtr->relief);
  1696.         }
  1697.         if (xBound > 0) {
  1698.     GC fgGC, bgGC;
  1699.     bgGC = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap);
  1700.     if (entryPtr->flags & GOT_FOCUS) {
  1701.         fgGC = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap);
  1702.         TkpDrawHighlightBorder(tkwin, fgGC, bgGC, xBound, pixmap);
  1703.     } else {
  1704.         TkpDrawHighlightBorder(tkwin, bgGC, bgGC, xBound, pixmap);
  1705.     }
  1706.         }
  1707.     }
  1708. #ifndef TK_NO_DOUBLE_BUFFERING
  1709.     /*
  1710.      * Everything's been redisplayed;  now copy the pixmap onto the screen
  1711.      * and free up the pixmap.
  1712.      */
  1713.     XCopyArea(entryPtr->display, pixmap, Tk_WindowId(tkwin), entryPtr->textGC,
  1714.     0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
  1715.     0, 0);
  1716.     Tk_FreePixmap(entryPtr->display, pixmap);
  1717. #endif /* TK_NO_DOUBLE_BUFFERING */
  1718.     entryPtr->flags &= ~BORDER_NEEDED;
  1719. }
  1720. /*
  1721.  *----------------------------------------------------------------------
  1722.  *
  1723.  * EntryComputeGeometry --
  1724.  *
  1725.  * This procedure is invoked to recompute information about where
  1726.  * in its window an entry's string will be displayed.  It also
  1727.  * computes the requested size for the window.
  1728.  *
  1729.  * Results:
  1730.  * None.
  1731.  *
  1732.  * Side effects:
  1733.  * The leftX and tabOrigin fields are recomputed for entryPtr,
  1734.  * and leftIndex may be adjusted.  Tk_GeometryRequest is called
  1735.  * to register the desired dimensions for the window.
  1736.  *
  1737.  *----------------------------------------------------------------------
  1738.  */
  1739. static void
  1740. EntryComputeGeometry(entryPtr)
  1741.     Entry *entryPtr; /* Widget record for entry. */
  1742. {
  1743.     int totalLength, overflow, maxOffScreen, rightX;
  1744.     int height, width, i;
  1745.     Tk_FontMetrics fm;
  1746.     char *p;
  1747.     if (entryPtr->displayString != entryPtr->string) {
  1748. ckfree((char *)entryPtr->displayString);
  1749. entryPtr->displayString = entryPtr->string;
  1750. entryPtr->numDisplayBytes = entryPtr->numBytes;
  1751.     }
  1752.     /*
  1753.      * If we're displaying a special character instead of the value of
  1754.      * the entry, recompute the displayString.
  1755.      */
  1756.     if (entryPtr->showChar != NULL) {
  1757. Tcl_UniChar ch;
  1758. char buf[TCL_UTF_MAX];
  1759. int size;
  1760. /*
  1761.  * Normalize the special character so we can safely duplicate it
  1762.  * in the display string.  If we didn't do this, then two malformed
  1763.  * characters might end up looking like one valid UTF character in
  1764.  * the resulting string.
  1765.  */
  1766. Tcl_UtfToUniChar(entryPtr->showChar, &ch);
  1767. size = Tcl_UniCharToUtf(ch, buf);
  1768. entryPtr->numDisplayBytes = entryPtr->numChars * size;
  1769. p = (char *) ckalloc((unsigned) (entryPtr->numDisplayBytes + 1));
  1770. entryPtr->displayString = p;
  1771. for (i = entryPtr->numChars; --i >= 0; ) {
  1772.     p += Tcl_UniCharToUtf(ch, p);
  1773. }
  1774. *p = '';
  1775.     }
  1776.     Tk_FreeTextLayout(entryPtr->textLayout);
  1777.     entryPtr->textLayout = Tk_ComputeTextLayout(entryPtr->tkfont,
  1778.     entryPtr->displayString, entryPtr->numChars, 0,
  1779.     entryPtr->justify, TK_IGNORE_NEWLINES, &totalLength, &height);
  1780.     entryPtr->layoutY = (Tk_Height(entryPtr->tkwin) - height) / 2;
  1781.     /*
  1782.      * Recompute where the leftmost character on the display will
  1783.      * be drawn (entryPtr->leftX) and adjust leftIndex if necessary
  1784.      * so that we don't let characters hang off the edge of the
  1785.      * window unless the entire window is full.
  1786.      */
  1787.     overflow = totalLength -
  1788. (Tk_Width(entryPtr->tkwin) - 2*entryPtr->inset - entryPtr->xWidth);
  1789.     if (overflow <= 0) {
  1790. entryPtr->leftIndex = 0;
  1791. if (entryPtr->justify == TK_JUSTIFY_LEFT) {
  1792.     entryPtr->leftX = entryPtr->inset;
  1793. } else if (entryPtr->justify == TK_JUSTIFY_RIGHT) {
  1794.     entryPtr->leftX = Tk_Width(entryPtr->tkwin) - entryPtr->inset
  1795. - entryPtr->xWidth - totalLength;
  1796. } else {
  1797.     entryPtr->leftX = (Tk_Width(entryPtr->tkwin)
  1798.     - entryPtr->xWidth - totalLength)/2;
  1799. }
  1800. entryPtr->layoutX = entryPtr->leftX;
  1801.     } else {
  1802. /*
  1803.  * The whole string can't fit in the window.  Compute the
  1804.  * maximum number of characters that may be off-screen to
  1805.  * the left without leaving empty space on the right of the
  1806.  * window, then don't let leftIndex be any greater than that.
  1807.  */
  1808. maxOffScreen = Tk_PointToChar(entryPtr->textLayout, overflow, 0);
  1809. Tk_CharBbox(entryPtr->textLayout, maxOffScreen,
  1810. &rightX, NULL, NULL, NULL);
  1811. if (rightX < overflow) {
  1812.     maxOffScreen++;
  1813. }
  1814. if (entryPtr->leftIndex > maxOffScreen) {
  1815.     entryPtr->leftIndex = maxOffScreen;
  1816. }
  1817. Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex, &rightX,
  1818. NULL, NULL, NULL);
  1819. entryPtr->leftX = entryPtr->inset;
  1820. entryPtr->layoutX = entryPtr->leftX - rightX;
  1821.     }
  1822.     Tk_GetFontMetrics(entryPtr->tkfont, &fm);
  1823.     height = fm.linespace + 2*entryPtr->inset + 2*(YPAD-XPAD);
  1824.     if (entryPtr->prefWidth > 0) {
  1825. width = entryPtr->prefWidth*entryPtr->avgWidth + 2*entryPtr->inset;
  1826.     } else {
  1827. if (totalLength == 0) {
  1828.     width = entryPtr->avgWidth + 2*entryPtr->inset;
  1829. } else {
  1830.     width = totalLength + 2*entryPtr->inset;
  1831. }
  1832.     }
  1833.     /*
  1834.      * Add one extra length for the spin buttons
  1835.      */
  1836.     width += entryPtr->xWidth;
  1837.     Tk_GeometryRequest(entryPtr->tkwin, width, height);
  1838. }
  1839. /*
  1840.  *----------------------------------------------------------------------
  1841.  *
  1842.  * InsertChars --
  1843.  *
  1844.  * Add new characters to an entry widget.
  1845.  *
  1846.  * Results:
  1847.  * None.
  1848.  *
  1849.  * Side effects:
  1850.  * New information gets added to entryPtr;  it will be redisplayed
  1851.  * soon, but not necessarily immediately.
  1852.  *
  1853.  *----------------------------------------------------------------------
  1854.  */
  1855. static void
  1856. InsertChars(entryPtr, index, value)
  1857.     Entry *entryPtr; /* Entry that is to get the new elements. */
  1858.     int index; /* Add the new elements before this
  1859.  * character index. */
  1860.     char *value; /* New characters to add (NULL-terminated
  1861.  * string). */
  1862. {
  1863.     int byteIndex, byteCount, oldChars, charsAdded, newByteCount;
  1864.     CONST char *string;
  1865.     char *new;
  1866.     string = entryPtr->string;
  1867.     byteIndex = Tcl_UtfAtIndex(string, index) - string;
  1868.     byteCount = strlen(value);
  1869.     if (byteCount == 0) {
  1870. return;
  1871.     }
  1872.     newByteCount = entryPtr->numBytes + byteCount + 1;
  1873.     new = (char *) ckalloc((unsigned) newByteCount);
  1874.     memcpy(new, string, (size_t) byteIndex);
  1875.     strcpy(new + byteIndex, value);
  1876.     strcpy(new + byteIndex + byteCount, string + byteIndex);
  1877.     if ((entryPtr->validate == VALIDATE_KEY ||
  1878.  entryPtr->validate == VALIDATE_ALL) &&
  1879. EntryValidateChange(entryPtr, value, new, index,
  1880.     VALIDATE_INSERT) != TCL_OK) {
  1881. ckfree(new);
  1882. return;
  1883.     }
  1884.     ckfree((char *)string);
  1885.     entryPtr->string = new;
  1886.     /*
  1887.      * The following construction is used because inserting improperly
  1888.      * formed UTF-8 sequences between other improperly formed UTF-8
  1889.      * sequences could result in actually forming valid UTF-8 sequences;
  1890.      * the number of characters added may not be Tcl_NumUtfChars(string, -1),
  1891.      * because of context.  The actual number of characters added is how
  1892.      * many characters are in the string now minus the number that
  1893.      * used to be there.
  1894.      */
  1895.     oldChars = entryPtr->numChars;
  1896.     entryPtr->numChars = Tcl_NumUtfChars(new, -1);
  1897.     charsAdded = entryPtr->numChars - oldChars;
  1898.     entryPtr->numBytes += byteCount;
  1899.     if (entryPtr->displayString == string) {
  1900. entryPtr->displayString = new;
  1901. entryPtr->numDisplayBytes = entryPtr->numBytes;
  1902.     }
  1903.     /*
  1904.      * Inserting characters invalidates all indexes into the string.
  1905.      * Touch up the indexes so that they still refer to the same
  1906.      * characters (at new positions).  When updating the selection
  1907.      * end-points, don't include the new text in the selection unless
  1908.      * it was completely surrounded by the selection.
  1909.      */
  1910.     if (entryPtr->selectFirst >= index) {
  1911. entryPtr->selectFirst += charsAdded;
  1912.     }
  1913.     if (entryPtr->selectLast > index) {
  1914. entryPtr->selectLast += charsAdded;
  1915.     }
  1916.     if ((entryPtr->selectAnchor > index)
  1917.     || (entryPtr->selectFirst >= index)) {
  1918. entryPtr->selectAnchor += charsAdded;
  1919.     }
  1920.     if (entryPtr->leftIndex > index) {
  1921. entryPtr->leftIndex += charsAdded;
  1922.     }
  1923.     if (entryPtr->insertPos >= index) {
  1924. entryPtr->insertPos += charsAdded;
  1925.     }
  1926.     EntryValueChanged(entryPtr, NULL);
  1927. }
  1928. /*
  1929.  *----------------------------------------------------------------------
  1930.  *
  1931.  * DeleteChars --
  1932.  *
  1933.  * Remove one or more characters from an entry widget.
  1934.  *
  1935.  * Results:
  1936.  * None.
  1937.  *
  1938.  * Side effects:
  1939.  * Memory gets freed, the entry gets modified and (eventually)
  1940.  * redisplayed.
  1941.  *
  1942.  *----------------------------------------------------------------------
  1943.  */
  1944. static void
  1945. DeleteChars(entryPtr, index, count)
  1946.     Entry *entryPtr; /* Entry widget to modify. */
  1947.     int index; /* Index of first character to delete. */
  1948.     int count; /* How many characters to delete. */
  1949. {
  1950.     int byteIndex, byteCount, newByteCount;
  1951.     CONST char *string;
  1952.     char *new, *todelete;
  1953.     if ((index + count) > entryPtr->numChars) {
  1954. count = entryPtr->numChars - index;
  1955.     }
  1956.     if (count <= 0) {
  1957. return;
  1958.     }
  1959.     string = entryPtr->string;
  1960.     byteIndex = Tcl_UtfAtIndex(string, index) - string;
  1961.     byteCount = Tcl_UtfAtIndex(string + byteIndex, count) - (string + byteIndex);
  1962.     newByteCount = entryPtr->numBytes + 1 - byteCount;
  1963.     new = (char *) ckalloc((unsigned) newByteCount);
  1964.     memcpy(new, string, (size_t) byteIndex);
  1965.     strcpy(new + byteIndex, string + byteIndex + byteCount);
  1966.     todelete = (char *) ckalloc((unsigned) (byteCount + 1));
  1967.     memcpy(todelete, string + byteIndex, (size_t) byteCount);
  1968.     todelete[byteCount] = '';
  1969.     if ((entryPtr->validate == VALIDATE_KEY ||
  1970.  entryPtr->validate == VALIDATE_ALL) &&
  1971. EntryValidateChange(entryPtr, todelete, new, index,
  1972.     VALIDATE_DELETE) != TCL_OK) {
  1973. ckfree(new);
  1974. ckfree(todelete);
  1975. return;
  1976.     }
  1977.     ckfree(todelete);
  1978.     ckfree((char *)entryPtr->string);
  1979.     entryPtr->string = new;
  1980.     entryPtr->numChars -= count;
  1981.     entryPtr->numBytes -= byteCount;
  1982.     if (entryPtr->displayString == string) {
  1983. entryPtr->displayString = new;
  1984. entryPtr->numDisplayBytes = entryPtr->numBytes;
  1985.     }
  1986.     /*
  1987.      * Deleting characters results in the remaining characters being
  1988.      * renumbered.  Update the various indexes into the string to reflect
  1989.      * this change.
  1990.      */
  1991.     if (entryPtr->selectFirst >= index) {
  1992. if (entryPtr->selectFirst >= (index + count)) {
  1993.     entryPtr->selectFirst -= count;
  1994. } else {
  1995.     entryPtr->selectFirst = index;
  1996. }
  1997.     }
  1998.     if (entryPtr->selectLast >= index) {
  1999. if (entryPtr->selectLast >= (index + count)) {
  2000.     entryPtr->selectLast -= count;
  2001. } else {
  2002.     entryPtr->selectLast = index;
  2003. }
  2004.     }
  2005.     if (entryPtr->selectLast <= entryPtr->selectFirst) {
  2006. entryPtr->selectFirst = -1;
  2007. entryPtr->selectLast = -1;
  2008.     }
  2009.     if (entryPtr->selectAnchor >= index) {
  2010. if (entryPtr->selectAnchor >= (index+count)) {
  2011.     entryPtr->selectAnchor -= count;
  2012. } else {
  2013.     entryPtr->selectAnchor = index;
  2014. }