~ubuntu-branches/ubuntu/dapper/perl-tk/dapper

« back to all changes in this revision

Viewing changes to pTk/mTk/generic/tkEntry.c

  • Committer: Bazaar Package Importer
  • Author(s): Michael C. Schultheiss
  • Date: 2006-01-16 16:54:02 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060116165402-1ppygm8hh8ahel2x
Tags: 1:804.027-2
* Incorporate changes from NMU (Thanks to Steve Kowalik.
  Closes: #348086)
* debian/control: Update Standards-Version (no changes needed)

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * tkEntry.c --
 
2
 * Entry.c --
3
3
 *
4
 
 *      This module implements entry widgets for the Tk
5
 
 *      toolkit.  An entry displays a string and allows
6
 
 *      the string to be edited.
 
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.
7
8
 *
8
9
 * Copyright (c) 1990-1994 The Regents of the University of California.
9
 
 * Copyright (c) 1994-1996 Sun Microsystems, Inc.
 
10
 * Copyright (c) 1994-1997 Sun Microsystems, Inc.
 
11
 * Copyright (c) 2000 Ajuba Solutions.
 
12
 * Copyright (c) 2002 ActiveState Corporation.
10
13
 *
11
14
 * See the file "license.terms" for information on usage and redistribution
12
15
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
13
16
 *
14
 
 * RCS: @(#) $Id: tkEntry.c,v 1.2 1998/09/14 18:23:09 stanton Exp $
 
17
 * RCS: @(#) $Id: tkEntry.c,v 1.35 2003/02/25 00:46:41 hobbs Exp $
15
18
 */
16
19
 
17
20
#include "tkInt.h"
18
21
#include "tkVMacro.h"
19
22
#include "default.h"
20
23
 
21
 
#define ENTRY_VALIDATE
 
24
enum EntryType {
 
25
    TK_ENTRY, TK_SPINBOX
 
26
};
22
27
 
23
28
/*
24
 
 * A data structure of the following type is kept for each entry
 
29
 * A data structure of the following type is kept for each Entry
25
30
 * widget managed by this file:
26
31
 */
27
32
 
28
33
typedef struct {
29
 
    Tk_Window tkwin;            /* Window that embodies the entry. NULL
 
34
    Tk_Window tkwin;            /* Window that embodies the entry. NULL
30
35
                                 * means that the window has been destroyed
31
36
                                 * but the data structures haven't yet been
32
37
                                 * cleaned up.*/
33
 
    Display *display;           /* Display containing widget.  Used, among
 
38
    Display *display;           /* Display containing widget.  Used, among
34
39
                                 * other things, so that resources can be
35
40
                                 * freed even after tkwin has gone away. */
36
 
    Tcl_Interp *interp;         /* Interpreter associated with entry. */
37
 
    Tcl_Command widgetCmd;      /* Token for entry's widget command. */
 
41
    Tcl_Interp *interp;         /* Interpreter associated with entry. */
 
42
    Tcl_Command widgetCmd;      /* Token for entry's widget command. */
 
43
    Tk_OptionTable optionTable; /* Table that defines configuration options
 
44
                                 * available for this widget. */
 
45
    enum EntryType type;        /* Specialized type of Entry widget */
38
46
 
39
47
    /*
40
48
     * Fields that are set by widget commands other than "configure".
41
49
     */
42
50
 
43
 
    char *string;               /* Pointer to storage for string;
 
51
    CONST char *string;         /* Pointer to storage for string;
44
52
                                 * NULL-terminated;  malloc-ed. */
45
 
    int insertPos;              /* Index of character before which next
46
 
                                 * typed character will be inserted. */
 
53
    int insertPos;              /* Character index before which next typed
 
54
                                 * character will be inserted. */
47
55
 
48
56
    /*
49
57
     * Information about what's selected, if any.
50
58
     */
51
59
 
52
 
    int selectFirst;            /* Index of first selected character (-1 means
53
 
                                 * nothing selected. */
54
 
    int selectLast;             /* Index of last selected character (-1 means
55
 
                                 * nothing selected. */
56
 
    int selectAnchor;           /* Fixed end of selection (i.e. "select to"
 
60
    int selectFirst;            /* Character index of first selected
 
61
                                 * character (-1 means nothing selected. */
 
62
    int selectLast;             /* Character index just after last selected
 
63
                                 * character (-1 means nothing selected. */
 
64
    int selectAnchor;           /* Fixed end of selection (i.e. "select to"
57
65
                                 * operation will use this as one end of the
58
66
                                 * selection). */
59
67
 
61
69
     * Information for scanning:
62
70
     */
63
71
 
64
 
    int scanMarkX;              /* X-position at which scan started (e.g.
 
72
    int scanMarkX;              /* X-position at which scan started (e.g.
65
73
                                 * button was pressed here). */
66
 
    int scanMarkIndex;          /* Index of character that was at left of
67
 
                                 * window when scan started. */
 
74
    int scanMarkIndex;          /* Character index of character that was at
 
75
                                 * left of window when scan started. */
68
76
 
69
77
    /*
70
78
     * Configuration settings that are updated by Tk_ConfigureWidget.
71
79
     */
72
80
 
73
 
    Tk_3DBorder normalBorder;   /* Used for drawing border around whole
 
81
    Tk_3DBorder normalBorder;   /* Used for drawing border around whole
74
82
                                 * window, plus used for background. */
75
 
    int borderWidth;            /* Width of 3-D border around window. */
76
 
    Tk_Cursor cursor;           /* Current cursor for window, or None. */
77
 
    int exportSelection;        /* Non-zero means tie internal entry selection
 
83
    Tk_3DBorder disabledBorder; /* Used for drawing  border around whole
 
84
                                 * window in disabled state, plus used for
 
85
                                 * background. */
 
86
    Tk_3DBorder readonlyBorder; /* Used for drawing  border around whole
 
87
                                 * window in readonly state, plus used for
 
88
                                 * background. */
 
89
    int borderWidth;            /* Width of 3-D border around window. */
 
90
    Tk_Cursor cursor;           /* Current cursor for window, or None. */
 
91
    int exportSelection;        /* Non-zero means tie internal entry selection
78
92
                                 * to X selection. */
79
 
    Tk_Font tkfont;             /* Information about text font, or NULL. */
80
 
    XColor *fgColorPtr;         /* Text color in normal mode. */
 
93
    Tk_Font tkfont;             /* Information about text font, or NULL. */
 
94
    XColor *fgColorPtr;         /* Text color in normal mode. */
 
95
    XColor *dfgColorPtr;        /* Text color in disabled mode. */
81
96
    XColor *highlightBgColorPtr;/* Color for drawing traversal highlight
82
97
                                 * area when highlight is off. */
83
 
    XColor *highlightColorPtr;  /* Color for drawing traversal highlight. */
84
 
    int highlightWidth;         /* Width in pixels of highlight to draw
 
98
    XColor *highlightColorPtr;  /* Color for drawing traversal highlight. */
 
99
    int highlightWidth;         /* Width in pixels of highlight to draw
85
100
                                 * around widget when it has the focus.
86
101
                                 * <= 0 means don't draw a highlight. */
87
 
    Tk_3DBorder insertBorder;   /* Used to draw vertical bar for insertion
 
102
    Tk_3DBorder insertBorder;   /* Used to draw vertical bar for insertion
88
103
                                 * cursor. */
89
 
    int insertBorderWidth;      /* Width of 3-D border around insert cursor. */
90
 
    int insertOffTime;          /* Number of milliseconds cursor should spend
 
104
    int insertBorderWidth;      /* Width of 3-D border around insert cursor. */
 
105
    int insertOffTime;          /* Number of milliseconds cursor should spend
91
106
                                 * in "off" state for each blink. */
92
 
    int insertOnTime;           /* Number of milliseconds cursor should spend
 
107
    int insertOnTime;           /* Number of milliseconds cursor should spend
93
108
                                 * in "on" state for each blink. */
94
 
    int insertWidth;            /* Total width of insert cursor. */
95
 
    Tk_Justify justify;         /* Justification to use for text within
 
109
    int insertWidth;            /* Total width of insert cursor. */
 
110
    Tk_Justify justify;         /* Justification to use for text within
96
111
                                 * window. */
97
 
    int relief;                 /* 3-D effect: TK_RELIEF_RAISED, etc. */
98
 
    Tk_3DBorder selBorder;      /* Border and background for selected
 
112
    int relief;                 /* 3-D effect: TK_RELIEF_RAISED, etc. */
 
113
    Tk_3DBorder selBorder;      /* Border and background for selected
99
114
                                 * characters. */
100
 
    int selBorderWidth;         /* Width of border around selection. */
101
 
    XColor *selFgColorPtr;      /* Foreground color for selected text. */
102
 
    char *showChar;             /* Value of -show option.  If non-NULL, first
103
 
                                 * character is used for displaying all
104
 
                                 * characters in entry.  Malloc'ed. */
105
 
    Tk_State state;             /* Normal or disabled.  Entry is read-only
 
115
    int selBorderWidth;         /* Width of border around selection. */
 
116
    XColor *selFgColorPtr;      /* Foreground color for selected text. */
 
117
    int state;                  /* Normal or disabled.  Entry is read-only
106
118
                                 * when disabled. */
107
 
    Var textVarName;            /* Name of variable (malloc'ed) or NULL.
 
119
    Tcl_Obj *textVarName;       /* Name of variable (malloc'ed) or NULL.
108
120
                                 * If non-NULL, entry's string tracks the
109
121
                                 * contents of this variable and vice versa. */
110
 
    char *takeFocus;            /* Value of -takefocus option;  not used in
 
122
    char *takeFocus;            /* Value of -takefocus option;  not used in
111
123
                                 * the C code, but used by keyboard traversal
112
124
                                 * scripts.  Malloc'ed, but may be NULL. */
113
 
    int prefWidth;              /* Desired width of window, measured in
 
125
    int prefWidth;              /* Desired width of window, measured in
114
126
                                 * average characters. */
115
 
    LangCallback *scrollCmd;    /* Command prefix for communicating with
 
127
    Tcl_Obj *scrollCmd;         /* Command prefix for communicating with
116
128
                                 * scrollbar(s).  Malloc'ed.  NULL means
117
129
                                 * no command to issue. */
 
130
    char *showChar;             /* Value of -show option.  If non-NULL, first
 
131
                                 * character is used for displaying all
 
132
                                 * characters in entry.  Malloc'ed.
 
133
                                 * This is only used by the Entry widget. */
118
134
 
119
135
    /*
120
136
     * Fields whose values are derived from the current values of the
121
137
     * configuration settings above.
122
138
     */
123
139
 
124
 
    int numChars;               /* Number of non-NULL characters in
125
 
                                 * string (may be 0). */
126
 
    char *displayString;        /* If non-NULL, points to string with same
 
140
    CONST char *displayString;  /* String to use when displaying.  This may
 
141
                                 * be a pointer to string, or a pointer to
 
142
                                 * malloced memory with the same character
127
143
                                 * length as string but whose characters
128
 
                                 * are all equal to showChar.  Malloc'ed. */
129
 
    int inset;                  /* Number of pixels on the left and right
 
144
                                 * are all equal to showChar. */
 
145
    int numBytes;               /* Length of string in bytes. */
 
146
    int numChars;               /* Length of string in characters.  Both
 
147
                                 * string and displayString have the same
 
148
                                 * character length, but may have different
 
149
                                 * byte lengths due to being made from
 
150
                                 * different UTF-8 characters. */
 
151
    int numDisplayBytes;        /* Length of displayString in bytes. */
 
152
    int inset;                  /* Number of pixels on the left and right
130
153
                                 * sides that are taken up by XPAD, borderWidth
131
154
                                 * (if any), and highlightWidth (if any). */
132
 
    Tk_TextLayout textLayout;   /* Cached text layout information. */
133
 
    int layoutX, layoutY;       /* Origin for layout. */
134
 
    int leftIndex;              /* Index of left-most character visible in
135
 
                                 * window. */
136
 
    int leftX;                  /* X position at which character at leftIndex
 
155
    Tk_TextLayout textLayout;   /* Cached text layout information. */
 
156
    int layoutX, layoutY;       /* Origin for layout. */
 
157
    int leftX;                  /* X position at which character at leftIndex
137
158
                                 * is drawn (varies depending on justify). */
 
159
    int leftIndex;              /* Character index of left-most character
 
160
                                 * visible in window. */
138
161
    Tcl_TimerToken insertBlinkHandler;
139
162
                                /* Timer handler used to blink cursor on and
140
163
                                 * off. */
141
 
    GC textGC;                  /* For drawing normal text. */
142
 
    GC selTextGC;               /* For drawing selected text. */
143
 
    GC highlightGC;             /* For drawing traversal highlight. */
144
 
    int avgWidth;               /* Width of average character. */
145
 
    int flags;                  /* Miscellaneous flags;  see below for
 
164
    GC textGC;                  /* For drawing normal text. */
 
165
    GC selTextGC;               /* For drawing selected text. */
 
166
    GC highlightGC;             /* For drawing traversal highlight. */
 
167
    int avgWidth;               /* Width of average character. */
 
168
    int xWidth;                 /* Extra width to reserve for widget.
 
169
                                 * Used by spinboxes for button space. */
 
170
    int flags;                  /* Miscellaneous flags;  see below for
146
171
                                 * definitions. */
147
 
    Tk_Tile tile, disabledTile, fgTile;
148
 
    GC tileGC;
149
 
    Tk_TSOffset tsoffset;
150
 
#ifdef ENTRY_VALIDATE
151
 
    LangCallback *validateCmd;  /* Command prefix to use when invoking
 
172
 
 
173
    int validate;               /* Non-zero means try to validate */
 
174
    Tcl_Obj *validateCmd;       /* Command prefix to use when invoking
152
175
                                 * validate command.  NULL means don't
153
176
                                 * invoke commands.  Malloc'ed. */
154
 
    int validate;               /* Non-zero means try to validate */
155
 
    LangCallback *invalidCmd;   /* Command called when a validation returns 0
 
177
    Tcl_Obj *invalidCmd;        /* Command called when a validation returns 0
156
178
                                 * (successfully fails), defaults to {}. */
157
 
#endif /* ENTRY_VALIDATE */
 
179
 
158
180
} Entry;
159
181
 
160
182
/*
 
183
 * A data structure of the following type is kept for each spinbox
 
184
 * widget managed by this file:
 
185
 */
 
186
 
 
187
typedef struct {
 
188
    Entry entry;                /* A pointer to the generic entry structure.
 
189
                                 * This must be the first element of the
 
190
                                 * Spinbox. */
 
191
 
 
192
    /*
 
193
     * Spinbox specific configuration settings.
 
194
     */
 
195
 
 
196
    Tk_3DBorder activeBorder;   /* Used for drawing border around active
 
197
                                 * buttons. */
 
198
    Tk_3DBorder buttonBorder;   /* Used for drawing border around buttons. */
 
199
    Tk_Cursor bCursor;          /* cursor for buttons, or None. */
 
200
    int bdRelief;               /* 3-D effect: TK_RELIEF_RAISED, etc. */
 
201
    int buRelief;               /* 3-D effect: TK_RELIEF_RAISED, etc. */
 
202
    Tcl_Obj *command;           /* Command to invoke for spin buttons.
 
203
                                 * NULL means no command to issue. */
 
204
 
 
205
    /*
 
206
     * Spinbox specific fields for use with configuration settings above.
 
207
     */
 
208
 
 
209
    int wrap;                   /* whether to wrap around when spinning */
 
210
 
 
211
    int selElement;             /* currently selected control */
 
212
    int curElement;             /* currently mouseover control */
 
213
 
 
214
    int repeatDelay;            /* repeat delay */
 
215
    int repeatInterval;         /* repeat interval */
 
216
 
 
217
    double fromValue;           /* Value corresponding to left/top of dial */
 
218
    double toValue;             /* Value corresponding to right/bottom
 
219
                                 * of dial */
 
220
    double increment;           /* If > 0, all values are rounded to an
 
221
                                 * even multiple of this value. */
 
222
    char *formatBuf;            /* string into which to format value.
 
223
                                 * Malloc'ed. */
 
224
    char *reqFormat;            /* Sprintf conversion specifier used for the
 
225
                                 * value that the users requests. Malloc'ed. */
 
226
    char *valueFormat;          /* Sprintf conversion specifier used for
 
227
                                 * the value. */
 
228
    char digitFormat[10];       /* Sprintf conversion specifier computed from
 
229
                                 * digits and other information; used for
 
230
                                 * the value. */
 
231
 
 
232
    char *valueStr;             /* Values List. Malloc'ed. */
 
233
    Tcl_Obj *listObj;           /* Pointer to the list object being used */
 
234
    int eIndex;                 /* Holds the current index into elements */
 
235
    int nElements;              /* Holds the current count of elements */
 
236
 
 
237
} Spinbox;
 
238
 
 
239
/*
161
240
 * Assigned bits of "flags" fields of Entry structures, and what those
162
241
 * bits mean:
163
242
 *
164
 
 * REDRAW_PENDING:              Non-zero means a DoWhenIdle handler has
165
 
 *                              already been queued to redisplay the entry.
166
 
 * BORDER_NEEDED:               Non-zero means 3-D border must be redrawn
167
 
 *                              around window during redisplay.  Normally
168
 
 *                              only text portion needs to be redrawn.
169
 
 * CURSOR_ON:                   Non-zero means insert cursor is displayed at
170
 
 *                              present.  0 means it isn't displayed.
171
 
 * GOT_FOCUS:                   Non-zero means this window has the input
172
 
 *                              focus.
173
 
 * UPDATE_SCROLLBAR:            Non-zero means scrollbar should be updated
174
 
 *                              during next redisplay operation.
175
 
 * GOT_SELECTION:               Non-zero means we've claimed the selection.
 
243
 * REDRAW_PENDING:              Non-zero means a DoWhenIdle handler has
 
244
 *                              already been queued to redisplay the entry.
 
245
 * BORDER_NEEDED:               Non-zero means 3-D border must be redrawn
 
246
 *                              around window during redisplay.  Normally
 
247
 *                              only text portion needs to be redrawn.
 
248
 * CURSOR_ON:                   Non-zero means insert cursor is displayed at
 
249
 *                              present.  0 means it isn't displayed.
 
250
 * GOT_FOCUS:                   Non-zero means this window has the input
 
251
 *                              focus.
 
252
 * UPDATE_SCROLLBAR:            Non-zero means scrollbar should be updated
 
253
 *                              during next redisplay operation.
 
254
 * GOT_SELECTION:               Non-zero means we've claimed the selection.
 
255
 * ENTRY_DELETED:               This entry has been effectively destroyed.
176
256
 * VALIDATING:                  Non-zero means we are in a validateCmd
177
257
 * VALIDATE_VAR:                Non-zero means we are attempting to validate
178
258
 *                              the entry's textvariable with validateCmd
179
259
 * VALIDATE_ABORT:              Non-zero if validatecommand signals an abort
180
 
 *                              for current procedure and make no changes */
 
260
 *                              for current procedure and make no changes
 
261
 * ENTRY_VAR_TRACED:            Non-zero if a var trace is set.
 
262
 */
181
263
 
182
 
#define REDRAW_PENDING          1
183
 
#define BORDER_NEEDED           2
184
 
#define CURSOR_ON               4
185
 
#define GOT_FOCUS               8
186
 
#define UPDATE_SCROLLBAR        0x10
187
 
#define GOT_SELECTION           0x20
188
 
#ifdef ENTRY_VALIDATE
189
 
#define VALIDATING              0x40
190
 
#define VALIDATE_VAR            0x80
191
 
#define VALIDATE_ABORT          0x100
192
 
#endif /* ENTRY_VALIDATE */
 
264
#define REDRAW_PENDING          1
 
265
#define BORDER_NEEDED           2
 
266
#define CURSOR_ON               4
 
267
#define GOT_FOCUS               8
 
268
#define UPDATE_SCROLLBAR        0x10
 
269
#define GOT_SELECTION           0x20
 
270
#define ENTRY_DELETED           0x40
 
271
#define VALIDATING              0x80
 
272
#define VALIDATE_VAR            0x100
 
273
#define VALIDATE_ABORT          0x200
 
274
#define ENTRY_VAR_TRACED        0x400
193
275
 
194
276
/*
195
277
 * The following macro defines how many extra pixels to leave on each
199
281
#define XPAD 1
200
282
#define YPAD 1
201
283
 
202
 
#ifdef ENTRY_VALIDATE
203
 
/*
204
 
 * Definitions for validate values:
205
 
 */
206
 
 
207
 
#define VALIDATE_NONE           0
208
 
#define VALIDATE_ALL            1
209
 
#define VALIDATE_KEY            2
210
 
#define VALIDATE_FOCUS          3
211
 
#define VALIDATE_FOCUSIN        4
212
 
#define VALIDATE_FOCUSOUT       5
213
 
 
214
 
#define DEF_ENTRY_VALIDATE      VALIDATE_NONE
215
 
 
216
 
static int      ValidateParseProc _ANSI_ARGS_((ClientData clientData,
217
 
                    Tcl_Interp *interp, Tk_Window tkwin,
218
 
                    Arg value, char *entry, int offset));
219
 
static Arg      ValidatePrintProc _ANSI_ARGS_((ClientData clientData,
220
 
                    Tk_Window tkwin, char *entry, int offset,
221
 
                    Tcl_FreeProc **freeProcPtr));
222
 
 
223
 
static Tk_CustomOption validateOption = {
224
 
        ValidateParseProc,
225
 
        ValidatePrintProc,
226
 
        (ClientData) NULL};
227
 
#endif /* ENTRY_VALIDATE */
228
 
 
229
 
/*
230
 
 * Custom options for handling "-state" , "-tile" and "-offset"
231
 
 */
232
 
 
233
 
static Tk_CustomOption stateOption = {
234
 
    Tk_StateParseProc,
235
 
    Tk_StatePrintProc,
236
 
    (ClientData) NULL   /* only "normal" and "disabled" */
237
 
};
238
 
 
239
 
static Tk_CustomOption tileOption = {
240
 
    Tk_TileParseProc,
241
 
    Tk_TilePrintProc,
242
 
    (ClientData) NULL
243
 
};
244
 
 
245
 
static Tk_CustomOption offsetOption = {
246
 
    Tk_OffsetParseProc,
247
 
    Tk_OffsetPrintProc,
248
 
    (ClientData) NULL
249
 
};
250
 
 
251
 
/*
252
 
 * Information used for argv parsing.
253
 
 */
254
 
 
255
 
static Tk_ConfigSpec configSpecs[] = {
256
 
    {TK_CONFIG_BORDER, "-background", "background", "Background",
257
 
        DEF_ENTRY_BG_COLOR, Tk_Offset(Entry, normalBorder),
258
 
        TK_CONFIG_COLOR_ONLY},
259
 
    {TK_CONFIG_BORDER, "-background", "background", "Background",
260
 
        DEF_ENTRY_BG_MONO, Tk_Offset(Entry, normalBorder),
261
 
        TK_CONFIG_MONO_ONLY},
262
 
    {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
263
 
        (char *) NULL, 0, 0},
264
 
    {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
265
 
        (char *) NULL, 0, 0},
266
 
    {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
267
 
        DEF_ENTRY_BORDER_WIDTH, Tk_Offset(Entry, borderWidth), 0},
268
 
    {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
269
 
        DEF_ENTRY_CURSOR, Tk_Offset(Entry, cursor), TK_CONFIG_NULL_OK},
270
 
    {TK_CONFIG_CUSTOM, "-disabledtile", "disabledTile", "Tile", (char *) NULL,
271
 
        Tk_Offset(Entry, disabledTile),TK_CONFIG_DONT_SET_DEFAULT, &tileOption},
272
 
    {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection",
273
 
        "ExportSelection", DEF_ENTRY_EXPORT_SELECTION,
274
 
        Tk_Offset(Entry, exportSelection), 0},
275
 
    {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
276
 
        (char *) NULL, 0, 0},
277
 
    {TK_CONFIG_FONT, "-font", "font", "Font",
278
 
        DEF_ENTRY_FONT, Tk_Offset(Entry, tkfont), 0},
279
 
    {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
280
 
        DEF_ENTRY_FG, Tk_Offset(Entry, fgColorPtr), 0},
281
 
    {TK_CONFIG_SYNONYM, "-fgtile", "foregroundTile", (char *) NULL,
282
 
        (char *) NULL, 0, 0},
283
 
    {TK_CONFIG_CUSTOM, "-foregroundtile", "foregroundTile", "Tile", (char *) NULL,
284
 
        Tk_Offset(Entry, fgTile),TK_CONFIG_DONT_SET_DEFAULT, &tileOption},
285
 
    {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
286
 
        "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
287
 
        Tk_Offset(Entry, highlightBgColorPtr), 0},
288
 
    {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
289
 
        DEF_ENTRY_HIGHLIGHT, Tk_Offset(Entry, highlightColorPtr), 0},
290
 
    {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
291
 
        "HighlightThickness",
292
 
        DEF_ENTRY_HIGHLIGHT_WIDTH, Tk_Offset(Entry, highlightWidth), 0},
293
 
    {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
294
 
        DEF_ENTRY_INSERT_BG, Tk_Offset(Entry, insertBorder), 0},
295
 
    {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
296
 
        DEF_ENTRY_INSERT_BD_COLOR, Tk_Offset(Entry, insertBorderWidth),
297
 
        TK_CONFIG_COLOR_ONLY},
298
 
    {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
299
 
        DEF_ENTRY_INSERT_BD_MONO, Tk_Offset(Entry, insertBorderWidth),
300
 
        TK_CONFIG_MONO_ONLY},
301
 
    {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
302
 
        DEF_ENTRY_INSERT_OFF_TIME, Tk_Offset(Entry, insertOffTime), 0},
303
 
    {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
304
 
        DEF_ENTRY_INSERT_ON_TIME, Tk_Offset(Entry, insertOnTime), 0},
305
 
    {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
306
 
        DEF_ENTRY_INSERT_WIDTH, Tk_Offset(Entry, insertWidth), 0},
307
 
#ifdef ENTRY_VALIDATE
308
 
    {TK_CONFIG_CALLBACK, "-invalidcommand", "invalidCommand", "InvalidCommand",
309
 
        (char *) NULL, Tk_Offset(Entry, invalidCmd), TK_CONFIG_DONT_SET_DEFAULT},
310
 
    {TK_CONFIG_SYNONYM, "-invcmd", "invalidCommand", (char *) NULL,
311
 
        (char *) NULL, 0, 0},
312
 
#endif /* ENTRY_VALIDATE */
313
 
    {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
314
 
        DEF_ENTRY_JUSTIFY, Tk_Offset(Entry, justify), 0},
315
 
    {TK_CONFIG_CUSTOM, "-offset", "offset", "Offset", "0 0",
316
 
        Tk_Offset(Entry, tsoffset),TK_CONFIG_DONT_SET_DEFAULT, &offsetOption},
317
 
    {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
318
 
        DEF_ENTRY_RELIEF, Tk_Offset(Entry, relief), 0},
319
 
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
320
 
        DEF_ENTRY_SELECT_COLOR, Tk_Offset(Entry, selBorder),
321
 
        TK_CONFIG_COLOR_ONLY},
322
 
    {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
323
 
        DEF_ENTRY_SELECT_MONO, Tk_Offset(Entry, selBorder),
324
 
        TK_CONFIG_MONO_ONLY},
325
 
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
326
 
        DEF_ENTRY_SELECT_BD_COLOR, Tk_Offset(Entry, selBorderWidth),
327
 
        TK_CONFIG_COLOR_ONLY},
328
 
    {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
329
 
        DEF_ENTRY_SELECT_BD_MONO, Tk_Offset(Entry, selBorderWidth),
330
 
        TK_CONFIG_MONO_ONLY},
331
 
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
332
 
        DEF_ENTRY_SELECT_FG_COLOR, Tk_Offset(Entry, selFgColorPtr),
333
 
        TK_CONFIG_COLOR_ONLY},
334
 
    {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
335
 
        DEF_ENTRY_SELECT_FG_MONO, Tk_Offset(Entry, selFgColorPtr),
336
 
        TK_CONFIG_MONO_ONLY},
337
 
    {TK_CONFIG_STRING, "-show", "show", "Show",
338
 
        DEF_ENTRY_SHOW, Tk_Offset(Entry, showChar), TK_CONFIG_NULL_OK},
339
 
    {TK_CONFIG_CUSTOM, "-state", "state", "State",
340
 
        DEF_ENTRY_STATE, Tk_Offset(Entry, state), 0, &stateOption},
341
 
    {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
342
 
        DEF_ENTRY_TAKE_FOCUS, Tk_Offset(Entry, takeFocus), TK_CONFIG_NULL_OK},
343
 
    {TK_CONFIG_SCALARVAR, "-textvariable", "textVariable", "Variable",
344
 
        DEF_ENTRY_TEXT_VARIABLE, Tk_Offset(Entry, textVarName),
345
 
        TK_CONFIG_NULL_OK},
346
 
    {TK_CONFIG_CUSTOM, "-tile", "tile", "Tile", (char *) NULL,
347
 
        Tk_Offset(Entry, tile),TK_CONFIG_DONT_SET_DEFAULT, &tileOption},
348
 
#ifdef ENTRY_VALIDATE
349
 
    {TK_CONFIG_CUSTOM, "-validate", "validate", "Validate",
350
 
       DEF_ENTRY_VALIDATE, Tk_Offset(Entry, validate),
351
 
       TK_CONFIG_DONT_SET_DEFAULT, &validateOption},
352
 
    {TK_CONFIG_CALLBACK, "-validatecommand", "validateCommand", "ValidateCommand",
353
 
       (char *) NULL, Tk_Offset(Entry, validateCmd),
354
 
       TK_CONFIG_DONT_SET_DEFAULT},
355
 
    {TK_CONFIG_SYNONYM, "-vcmd", "validateCommand", (char *) NULL,
356
 
        (char *) NULL, 0, 0},
357
 
#endif /* ENTRY_VALIDATE */
358
 
    {TK_CONFIG_INT, "-width", "width", "Width",
359
 
        DEF_ENTRY_WIDTH, Tk_Offset(Entry, prefWidth), 0},
360
 
    {TK_CONFIG_CALLBACK, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
361
 
        DEF_ENTRY_SCROLL_COMMAND, Tk_Offset(Entry, scrollCmd),
362
 
        TK_CONFIG_NULL_OK},
363
 
    {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
364
 
        (char *) NULL, 0, 0}
 
284
/*
 
285
 * A comparison function for double values.  For Spinboxes.
 
286
 */
 
287
#define MIN_DBL_VAL             1E-9
 
288
#define DOUBLES_EQ(d1, d2)      (fabs((d1) - (d2)) < MIN_DBL_VAL)
 
289
 
 
290
/*
 
291
 * The following enum is used to define a type for the -state option
 
292
 * of the Entry widget.  These values are used as indices into the
 
293
 * string table below.
 
294
 */
 
295
 
 
296
enum state {
 
297
    STATE_DISABLED, STATE_NORMAL, STATE_READONLY
 
298
};
 
299
 
 
300
static char *stateStrings[] = {
 
301
    "disabled", "normal", "readonly", (char *) NULL
 
302
};
 
303
 
 
304
/*
 
305
 * Definitions for -validate option values:
 
306
 */
 
307
 
 
308
static char *validateStrings[] = {
 
309
    "all", "key", "focus", "focusin", "focusout", "none", (char *) NULL
 
310
};
 
311
enum validateType {
 
312
    VALIDATE_ALL, VALIDATE_KEY, VALIDATE_FOCUS,
 
313
    VALIDATE_FOCUSIN, VALIDATE_FOCUSOUT, VALIDATE_NONE,
 
314
    /*
 
315
     * These extra enums are for use with EntryValidateChange
 
316
     */
 
317
    VALIDATE_FORCED, VALIDATE_DELETE, VALIDATE_INSERT, VALIDATE_BUTTON
 
318
};
 
319
#define DEF_ENTRY_VALIDATE      "none"
 
320
#define DEF_ENTRY_INVALIDCMD    ""
 
321
 
 
322
/*
 
323
 * Information used for Entry objv parsing.
 
324
 */
 
325
 
 
326
static Tk_OptionSpec entryOptSpec[] = {
 
327
    {TK_OPTION_BORDER, "-background", "background", "Background",
 
328
        DEF_ENTRY_BG_COLOR, -1, Tk_Offset(Entry, normalBorder),
 
329
        0, (ClientData) DEF_ENTRY_BG_MONO, 0},
 
330
    {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
 
331
        (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
 
332
    {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
 
333
        (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
 
334
    {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
 
335
        DEF_ENTRY_BORDER_WIDTH, -1, Tk_Offset(Entry, borderWidth),
 
336
        0, 0, 0},
 
337
    {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
 
338
        DEF_ENTRY_CURSOR, -1, Tk_Offset(Entry, cursor),
 
339
        TK_OPTION_NULL_OK, 0, 0},
 
340
    {TK_OPTION_BORDER, "-disabledbackground", "disabledBackground",
 
341
         "DisabledBackground", DEF_ENTRY_DISABLED_BG_COLOR, -1,
 
342
         Tk_Offset(Entry, disabledBorder), TK_OPTION_NULL_OK,
 
343
         (ClientData) DEF_ENTRY_DISABLED_BG_MONO, 0},
 
344
    {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
 
345
         "DisabledForeground", DEF_ENTRY_DISABLED_FG, -1,
 
346
         Tk_Offset(Entry, dfgColorPtr), TK_OPTION_NULL_OK, 0, 0},
 
347
    {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
 
348
        "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, -1,
 
349
        Tk_Offset(Entry, exportSelection), 0, 0, 0},
 
350
    {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
 
351
        (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
 
352
    {TK_OPTION_FONT, "-font", "font", "Font",
 
353
        DEF_ENTRY_FONT, -1, Tk_Offset(Entry, tkfont), 0, 0, 0},
 
354
    {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
 
355
        DEF_ENTRY_FG, -1, Tk_Offset(Entry, fgColorPtr), 0,
 
356
        0, 0},
 
357
    {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
 
358
        "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
 
359
        -1, Tk_Offset(Entry, highlightBgColorPtr),
 
360
        0, 0, 0},
 
361
    {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
 
362
        DEF_ENTRY_HIGHLIGHT, -1, Tk_Offset(Entry, highlightColorPtr),
 
363
        0, 0, 0},
 
364
    {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
 
365
        "HighlightThickness", DEF_ENTRY_HIGHLIGHT_WIDTH, -1,
 
366
        Tk_Offset(Entry, highlightWidth), 0, 0, 0},
 
367
    {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground",
 
368
        DEF_ENTRY_INSERT_BG,
 
369
        -1, Tk_Offset(Entry, insertBorder),
 
370
        0, 0, 0},
 
371
    {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth",
 
372
        "BorderWidth", DEF_ENTRY_INSERT_BD_COLOR, -1,
 
373
        Tk_Offset(Entry, insertBorderWidth), 0,
 
374
        (ClientData) DEF_ENTRY_INSERT_BD_MONO, 0},
 
375
    {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime",
 
376
        DEF_ENTRY_INSERT_OFF_TIME, -1, Tk_Offset(Entry, insertOffTime),
 
377
        0, 0, 0},
 
378
    {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime",
 
379
        DEF_ENTRY_INSERT_ON_TIME, -1, Tk_Offset(Entry, insertOnTime),
 
380
        0, 0, 0},
 
381
    {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
 
382
        DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth),
 
383
        0, 0, 0},
 
384
    {TK_OPTION_CALLBACK, "-invalidcommand", "invalidCommand", "InvalidCommand",
 
385
        DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd),
 
386
        TK_OPTION_NULL_OK, 0, 0},
 
387
    {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL,
 
388
        (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0},
 
389
    {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
 
390
        DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0},
 
391
    {TK_OPTION_BORDER, "-readonlybackground", "readonlyBackground",
 
392
         "ReadonlyBackground", DEF_ENTRY_READONLY_BG_COLOR, -1,
 
393
         Tk_Offset(Entry, readonlyBorder), TK_OPTION_NULL_OK,
 
394
         (ClientData) DEF_ENTRY_READONLY_BG_MONO, 0},
 
395
    {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
 
396
        DEF_ENTRY_RELIEF, -1, Tk_Offset(Entry, relief),
 
397
        0, 0, 0},
 
398
    {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground",
 
399
        DEF_ENTRY_SELECT_COLOR, -1, Tk_Offset(Entry, selBorder),
 
400
        0, (ClientData) DEF_ENTRY_SELECT_MONO, 0},
 
401
    {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth",
 
402
        "BorderWidth", DEF_ENTRY_SELECT_BD_COLOR, -1,
 
403
        Tk_Offset(Entry, selBorderWidth),
 
404
        0, (ClientData) DEF_ENTRY_SELECT_BD_MONO, 0},
 
405
    {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
 
406
        DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
 
407
        0, (ClientData) DEF_ENTRY_SELECT_FG_MONO, 0},
 
408
    {TK_OPTION_STRING, "-show", "show", "Show",
 
409
        DEF_ENTRY_SHOW, -1, Tk_Offset(Entry, showChar),
 
410
        TK_OPTION_NULL_OK, 0, 0},
 
411
    {TK_OPTION_STRING_TABLE, "-state", "state", "State",
 
412
        DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state),
 
413
        0, (ClientData) stateStrings, 0},
 
414
    {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
 
415
        DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus),
 
416
        TK_OPTION_NULL_OK, 0, 0},
 
417
    {TK_OPTION_OBJ, "-textvariable", "textVariable", "Variable",
 
418
        DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName),
 
419
        TK_OPTION_NULL_OK, 0, 0},
 
420
    {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
 
421
       DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate),
 
422
       0, (ClientData) validateStrings, 0},
 
423
    {TK_OPTION_CALLBACK, "-validatecommand", "validateCommand", "ValidateCommand",
 
424
       (char *) NULL, -1, Tk_Offset(Entry, validateCmd),
 
425
       TK_OPTION_NULL_OK, 0, 0},
 
426
    {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL,
 
427
        (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0},
 
428
    {TK_OPTION_INT, "-width", "width", "Width",
 
429
        DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0},
 
430
    {TK_OPTION_CALLBACK, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
 
431
        DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd),
 
432
        TK_OPTION_NULL_OK, 0, 0},
 
433
    {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
 
434
        (char *) NULL, 0, -1, 0, 0, 0}
 
435
};
 
436
 
 
437
/*
 
438
 * Information used for Spinbox objv parsing.
 
439
 */
 
440
 
 
441
#define DEF_SPINBOX_REPEAT_DELAY        "400"
 
442
#define DEF_SPINBOX_REPEAT_INTERVAL     "100"
 
443
 
 
444
#define DEF_SPINBOX_CMD                 ""
 
445
 
 
446
#define DEF_SPINBOX_FROM                "0"
 
447
#define DEF_SPINBOX_TO                  "0"
 
448
#define DEF_SPINBOX_INCREMENT           "1"
 
449
#define DEF_SPINBOX_FORMAT              ""
 
450
 
 
451
#define DEF_SPINBOX_VALUES              ""
 
452
#define DEF_SPINBOX_WRAP                "0"
 
453
 
 
454
static Tk_OptionSpec sbOptSpec[] = {
 
455
    {TK_OPTION_BORDER, "-activebackground", "activeBackground", "Background",
 
456
        DEF_BUTTON_ACTIVE_BG_COLOR, -1, Tk_Offset(Spinbox, activeBorder),
 
457
        0, (ClientData) DEF_BUTTON_ACTIVE_BG_MONO, 0},
 
458
    {TK_OPTION_BORDER, "-background", "background", "Background",
 
459
        DEF_ENTRY_BG_COLOR, -1, Tk_Offset(Entry, normalBorder),
 
460
        0, (ClientData) DEF_ENTRY_BG_MONO, 0},
 
461
    {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
 
462
        (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
 
463
    {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
 
464
        (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
 
465
    {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
 
466
        DEF_ENTRY_BORDER_WIDTH, -1, Tk_Offset(Entry, borderWidth),
 
467
        0, 0, 0},
 
468
    {TK_OPTION_BORDER, "-buttonbackground", "Button.background", "Background",
 
469
        DEF_BUTTON_BG_COLOR, -1, Tk_Offset(Spinbox, buttonBorder),
 
470
        0, (ClientData) DEF_BUTTON_BG_MONO, 0},
 
471
    {TK_OPTION_CURSOR, "-buttoncursor", "Button.cursor", "Cursor",
 
472
        DEF_BUTTON_CURSOR, -1, Tk_Offset(Spinbox, bCursor),
 
473
        TK_OPTION_NULL_OK, 0, 0},
 
474
    {TK_OPTION_RELIEF, "-buttondownrelief", "Button.relief", "Relief",
 
475
        DEF_BUTTON_RELIEF, -1, Tk_Offset(Spinbox, bdRelief),
 
476
        0, 0, 0},
 
477
    {TK_OPTION_RELIEF, "-buttonuprelief", "Button.relief", "Relief",
 
478
        DEF_BUTTON_RELIEF, -1, Tk_Offset(Spinbox, buRelief),
 
479
        0, 0, 0},
 
480
    {TK_OPTION_CALLBACK, "-command", "command", "Command",
 
481
        DEF_SPINBOX_CMD, -1, Tk_Offset(Spinbox, command),
 
482
        TK_OPTION_NULL_OK, 0, 0},
 
483
    {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
 
484
        DEF_ENTRY_CURSOR, -1, Tk_Offset(Entry, cursor),
 
485
        TK_OPTION_NULL_OK, 0, 0},
 
486
    {TK_OPTION_BORDER, "-disabledbackground", "disabledBackground",
 
487
         "DisabledBackground", DEF_ENTRY_DISABLED_BG_COLOR, -1,
 
488
         Tk_Offset(Entry, disabledBorder), TK_OPTION_NULL_OK,
 
489
         (ClientData) DEF_ENTRY_DISABLED_BG_MONO, 0},
 
490
    {TK_OPTION_COLOR, "-disabledforeground", "disabledForeground",
 
491
         "DisabledForeground", DEF_ENTRY_DISABLED_FG, -1,
 
492
         Tk_Offset(Entry, dfgColorPtr), TK_OPTION_NULL_OK, 0, 0},
 
493
    {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
 
494
        "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, -1,
 
495
        Tk_Offset(Entry, exportSelection), 0, 0, 0},
 
496
    {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
 
497
        (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
 
498
    {TK_OPTION_FONT, "-font", "font", "Font",
 
499
        DEF_ENTRY_FONT, -1, Tk_Offset(Entry, tkfont), 0, 0, 0},
 
500
    {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
 
501
        DEF_ENTRY_FG, -1, Tk_Offset(Entry, fgColorPtr), 0,
 
502
        0, 0},
 
503
    {TK_OPTION_STRING, "-format", "format", "Format",
 
504
        DEF_SPINBOX_FORMAT, -1, Tk_Offset(Spinbox, reqFormat),
 
505
        TK_OPTION_NULL_OK, 0, 0},
 
506
    {TK_OPTION_DOUBLE, "-from", "from", "From",
 
507
        DEF_SPINBOX_FROM, -1, Tk_Offset(Spinbox, fromValue), 0, 0, 0},
 
508
    {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
 
509
        "HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
 
510
        -1, Tk_Offset(Entry, highlightBgColorPtr),
 
511
        0, 0, 0},
 
512
    {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
 
513
        DEF_ENTRY_HIGHLIGHT, -1, Tk_Offset(Entry, highlightColorPtr),
 
514
        0, 0, 0},
 
515
    {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
 
516
        "HighlightThickness", DEF_ENTRY_HIGHLIGHT_WIDTH, -1,
 
517
        Tk_Offset(Entry, highlightWidth), 0, 0, 0},
 
518
    {TK_OPTION_DOUBLE, "-increment", "increment", "Increment",
 
519
        DEF_SPINBOX_INCREMENT, -1, Tk_Offset(Spinbox, increment), 0, 0, 0},
 
520
    {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground",
 
521
        DEF_ENTRY_INSERT_BG, -1, Tk_Offset(Entry, insertBorder),
 
522
        0, 0, 0},
 
523
    {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth",
 
524
        "BorderWidth", DEF_ENTRY_INSERT_BD_COLOR, -1,
 
525
        Tk_Offset(Entry, insertBorderWidth), 0,
 
526
        (ClientData) DEF_ENTRY_INSERT_BD_MONO, 0},
 
527
    {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime",
 
528
        DEF_ENTRY_INSERT_OFF_TIME, -1, Tk_Offset(Entry, insertOffTime),
 
529
        0, 0, 0},
 
530
    {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime",
 
531
        DEF_ENTRY_INSERT_ON_TIME, -1, Tk_Offset(Entry, insertOnTime),
 
532
        0, 0, 0},
 
533
    {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
 
534
        DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth),
 
535
        0, 0, 0},
 
536
    {TK_OPTION_CALLBACK, "-invalidcommand", "invalidCommand", "InvalidCommand",
 
537
        DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd),
 
538
        TK_OPTION_NULL_OK, 0, 0},
 
539
    {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL,
 
540
        (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0},
 
541
    {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
 
542
        DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0},
 
543
    {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
 
544
        DEF_ENTRY_RELIEF, -1, Tk_Offset(Entry, relief),
 
545
        0, 0, 0},
 
546
    {TK_OPTION_BORDER, "-readonlybackground", "readonlyBackground",
 
547
         "ReadonlyBackground", DEF_ENTRY_READONLY_BG_COLOR, -1,
 
548
         Tk_Offset(Entry, readonlyBorder), TK_OPTION_NULL_OK,
 
549
         (ClientData) DEF_ENTRY_READONLY_BG_MONO, 0},
 
550
    {TK_OPTION_INT, "-repeatdelay", "repeatDelay", "RepeatDelay",
 
551
        DEF_SPINBOX_REPEAT_DELAY, -1, Tk_Offset(Spinbox, repeatDelay),
 
552
        0, 0, 0},
 
553
    {TK_OPTION_INT, "-repeatinterval", "repeatInterval", "RepeatInterval",
 
554
        DEF_SPINBOX_REPEAT_INTERVAL, -1, Tk_Offset(Spinbox, repeatInterval),
 
555
        0, 0, 0},
 
556
    {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground",
 
557
        DEF_ENTRY_SELECT_COLOR, -1, Tk_Offset(Entry, selBorder),
 
558
        0, (ClientData) DEF_ENTRY_SELECT_MONO, 0},
 
559
    {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth",
 
560
        "BorderWidth", DEF_ENTRY_SELECT_BD_COLOR, -1,
 
561
        Tk_Offset(Entry, selBorderWidth),
 
562
        0, (ClientData) DEF_ENTRY_SELECT_BD_MONO, 0},
 
563
    {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
 
564
        DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
 
565
        0, (ClientData) DEF_ENTRY_SELECT_FG_MONO, 0},
 
566
    {TK_OPTION_STRING_TABLE, "-state", "state", "State",
 
567
        DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state),
 
568
        0, (ClientData) stateStrings, 0},
 
569
    {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
 
570
        DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus),
 
571
        TK_CONFIG_NULL_OK, 0, 0},
 
572
    {TK_OPTION_OBJ, "-textvariable", "textVariable", "Variable",
 
573
        DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName),
 
574
        TK_CONFIG_NULL_OK, 0, 0},
 
575
    {TK_OPTION_DOUBLE, "-to", "to", "To",
 
576
        DEF_SPINBOX_TO, -1, Tk_Offset(Spinbox, toValue), 0, 0, 0},
 
577
    {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
 
578
       DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate),
 
579
       0, (ClientData) validateStrings, 0},
 
580
    {TK_OPTION_CALLBACK, "-validatecommand", "validateCommand", "ValidateCommand",
 
581
       (char *) NULL, -1, Tk_Offset(Entry, validateCmd),
 
582
       TK_CONFIG_NULL_OK, 0, 0},
 
583
    {TK_OPTION_STRING, "-values", "values", "Values",
 
584
         DEF_SPINBOX_VALUES, -1, Tk_Offset(Spinbox, valueStr),
 
585
         TK_OPTION_NULL_OK, 0, 0},
 
586
    {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL,
 
587
        (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0},
 
588
    {TK_OPTION_INT, "-width", "width", "Width",
 
589
        DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0},
 
590
    {TK_OPTION_BOOLEAN, "-wrap", "wrap", "Wrap",
 
591
        DEF_SPINBOX_WRAP, -1, Tk_Offset(Spinbox, wrap), 0, 0, 0},
 
592
    {TK_OPTION_CALLBACK, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
 
593
        DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd),
 
594
        TK_CONFIG_NULL_OK, 0, 0},
 
595
    {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
 
596
        (char *) NULL, 0, -1, 0, 0, 0}
 
597
};
 
598
 
 
599
/*
 
600
 * The following tables define the entry widget commands (and sub-
 
601
 * commands) and map the indexes into the string tables into
 
602
 * enumerated types used to dispatch the entry widget command.
 
603
 */
 
604
 
 
605
static CONST char *entryCmdNames[] = {
 
606
    "bbox", "cget", "configure", "delete", "get", "icursor", "index",
 
607
    "insert", "scan", "selection", "validate", "xview", (char *) NULL
 
608
};
 
609
 
 
610
enum entryCmd {
 
611
    COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE,
 
612
    COMMAND_GET, COMMAND_ICURSOR, COMMAND_INDEX, COMMAND_INSERT,
 
613
    COMMAND_SCAN, COMMAND_SELECTION, COMMAND_VALIDATE, COMMAND_XVIEW
 
614
};
 
615
 
 
616
static CONST char *selCmdNames[] = {
 
617
    "adjust", "clear", "from", "present", "range", "to", (char *) NULL
 
618
};
 
619
 
 
620
enum selCmd {
 
621
    SELECTION_ADJUST, SELECTION_CLEAR, SELECTION_FROM,
 
622
    SELECTION_PRESENT, SELECTION_RANGE, SELECTION_TO
 
623
};
 
624
 
 
625
/*
 
626
 * The following tables define the spinbox widget commands (and sub-
 
627
 * commands) and map the indexes into the string tables into
 
628
 * enumerated types used to dispatch the spinbox widget command.
 
629
 */
 
630
 
 
631
static CONST char *sbCmdNames[] = {
 
632
    "bbox", "cget", "configure", "delete", "get", "icursor", "identify",
 
633
    "index", "insert", "invoke", "scan", "selection", "set",
 
634
    "validate", "xview", (char *) NULL
 
635
};
 
636
 
 
637
enum sbCmd {
 
638
    SB_CMD_BBOX, SB_CMD_CGET, SB_CMD_CONFIGURE, SB_CMD_DELETE,
 
639
    SB_CMD_GET, SB_CMD_ICURSOR, SB_CMD_IDENTIFY, SB_CMD_INDEX,
 
640
    SB_CMD_INSERT, SB_CMD_INVOKE, SB_CMD_SCAN, SB_CMD_SELECTION,
 
641
    SB_CMD_SET, SB_CMD_VALIDATE, SB_CMD_XVIEW
 
642
};
 
643
 
 
644
static CONST char *sbSelCmdNames[] = {
 
645
    "adjust", "clear", "element", "from", "present", "range", "to",
 
646
    (char *) NULL
 
647
};
 
648
 
 
649
enum sbselCmd {
 
650
    SB_SEL_ADJUST, SB_SEL_CLEAR, SB_SEL_ELEMENT, SB_SEL_FROM,
 
651
    SB_SEL_PRESENT, SB_SEL_RANGE, SB_SEL_TO
 
652
};
 
653
 
 
654
/*
 
655
 * Extra for selection of elements
 
656
 */
 
657
 
 
658
static CONST char *selElementNames[] = {
 
659
    "none", "buttondown", "buttonup", (char *) NULL, "entry"
 
660
};
 
661
enum selelement {
 
662
    SEL_NONE, SEL_BUTTONDOWN, SEL_BUTTONUP, SEL_NULL, SEL_ENTRY
365
663
};
366
664
 
367
665
/*
368
666
 * Flags for GetEntryIndex procedure:
369
667
 */
370
668
 
371
 
#define ZERO_OK                 1
372
 
#define LAST_PLUS_ONE_OK        2
 
669
#define ZERO_OK                 1
 
670
#define LAST_PLUS_ONE_OK        2
373
671
 
374
672
/*
375
673
 * Forward declarations for procedures defined later in this file:
376
674
 */
377
675
 
378
 
static int              ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
379
 
                            Entry *entryPtr, int argc, char **argv,
380
 
                            int flags));
381
 
static void             DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
 
676
static int              ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
 
677
                            Entry *entryPtr, int objc,
 
678
                            Tcl_Obj *CONST objv[], int flags));
 
679
static void             DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
382
680
                            int count));
383
 
static void             DestroyEntry _ANSI_ARGS_((char *memPtr));
384
 
static void             DisplayEntry _ANSI_ARGS_((ClientData clientData));
385
 
static void             EntryBlinkProc _ANSI_ARGS_((ClientData clientData));
386
 
static void             EntryCmdDeletedProc _ANSI_ARGS_((
 
681
static void             DestroyEntry _ANSI_ARGS_((char *memPtr));
 
682
static void             DisplayEntry _ANSI_ARGS_((ClientData clientData));
 
683
static void             EntryBlinkProc _ANSI_ARGS_((ClientData clientData));
 
684
static void             EntryCmdDeletedProc _ANSI_ARGS_((
387
685
                            ClientData clientData));
388
 
static void             EntryComputeGeometry _ANSI_ARGS_((Entry *entryPtr));
389
 
static void             EntryEventProc _ANSI_ARGS_((ClientData clientData,
 
686
static void             EntryComputeGeometry _ANSI_ARGS_((Entry *entryPtr));
 
687
static void             EntryEventProc _ANSI_ARGS_((ClientData clientData,
390
688
                            XEvent *eventPtr));
391
 
static void             EntryFocusProc _ANSI_ARGS_ ((Entry *entryPtr,
 
689
static void             EntryFocusProc _ANSI_ARGS_ ((Entry *entryPtr,
392
690
                            int gotFocus));
393
 
static int              EntryFetchSelection _ANSI_ARGS_((ClientData clientData,
 
691
static int              EntryFetchSelection _ANSI_ARGS_((ClientData clientData,
394
692
                            int offset, char *buffer, int maxBytes));
395
 
static void             EntryLostSelection _ANSI_ARGS_((
 
693
static void             EntryLostSelection _ANSI_ARGS_((
396
694
                            ClientData clientData));
397
 
static void             EventuallyRedraw _ANSI_ARGS_((Entry *entryPtr));
398
 
static void             EntryScanTo _ANSI_ARGS_((Entry *entryPtr, int y));
399
 
static void             EntrySetValue _ANSI_ARGS_((Entry *entryPtr,
400
 
                            char *value));
401
 
static void             EntrySelectTo _ANSI_ARGS_((
 
695
static void             EventuallyRedraw _ANSI_ARGS_((Entry *entryPtr));
 
696
static void             EntryScanTo _ANSI_ARGS_((Entry *entryPtr, int y));
 
697
static void             EntrySetValue _ANSI_ARGS_((Entry *entryPtr,
 
698
                            CONST char *value));
 
699
static void             EntrySelectTo _ANSI_ARGS_((
402
700
                            Entry *entryPtr, int index));
403
 
static char *           EntryTextVarProc _ANSI_ARGS_((ClientData clientData,
404
 
                            Tcl_Interp *interp, Var name1, char *name2,
405
 
                            int flags));
406
 
static void             EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
407
 
#ifdef ENTRY_VALIDATE
408
 
static int              EntryValidate _ANSI_ARGS_((Entry *entryPtr,
 
701
static char *           EntryTextVarProc _ANSI_ARGS_((ClientData clientData,
 
702
                            Tcl_Interp *interp, Tcl_Obj *name1,
 
703
                            CONST char *name2, int flags));
 
704
static void             EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
 
705
static int              EntryValidate _ANSI_ARGS_((Entry *entryPtr,
409
706
                            LangCallback *cmd,char *string));
410
 
static int              EntryValidateChange _ANSI_ARGS_((Entry *entryPtr,
411
 
                            char *string, char *new, int index, int type));
412
 
static void             ExpandPercents _ANSI_ARGS_((Entry *entryPtr,
413
 
                            char *before, char *add, char *new, int index,
414
 
                            int type, Tcl_DString *dsPtr));
415
 
#endif /* ENTRY_VALIDATE */
416
 
static void             EntryValueChanged _ANSI_ARGS_((Entry *entryPtr));
417
 
static void             EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr,
 
707
static int              EntryValidateChange _ANSI_ARGS_((Entry *entryPtr,
 
708
                            char *change, CONST char *new, int index,
 
709
                            int type));
 
710
static void             ExpandPercents _ANSI_ARGS_((Entry *entryPtr,
 
711
                            CONST char *before, char *change, CONST char *new,
 
712
                            int index, int type, Tcl_DString *dsPtr));
 
713
static void             EntryValueChanged _ANSI_ARGS_((Entry *entryPtr,
 
714
                            CONST char *newValue));
 
715
static void             EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr,
418
716
                            double *firstPtr, double *lastPtr));
419
 
static int              EntryWidgetCmd _ANSI_ARGS_((ClientData clientData,
420
 
                            Tcl_Interp *interp, int argc, char **argv));
421
 
static void             EntryWorldChanged _ANSI_ARGS_((
 
717
static int              EntryWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
 
718
                            Tcl_Interp *interp, int objc,
 
719
                            Tcl_Obj *CONST objv[]));
 
720
static void             EntryWorldChanged _ANSI_ARGS_((
422
721
                            ClientData instanceData));
423
 
static int              GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp,
424
 
                            Entry *entryPtr, Arg arg, int *indexPtr));
425
 
static void             InsertChars _ANSI_ARGS_((Entry *entryPtr, int index,
 
722
static int              GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp,
 
723
                            Entry *entryPtr, Tcl_Obj *arg, int *indexPtr));
 
724
static void             InsertChars _ANSI_ARGS_((Entry *entryPtr, int index,
426
725
                            char *string));
427
 
static void             TileChangedProc _ANSI_ARGS_((ClientData clientData,
428
 
                            Tk_Tile tile, Tk_Item *itemPtr));
429
 
 
430
 
/*
431
 
 * The structure below defines entry class behavior by means of procedures
 
726
 
 
727
/*
 
728
 * These forward declarations are the spinbox specific ones:
 
729
 */
 
730
 
 
731
static int              SpinboxWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
 
732
                            Tcl_Interp *interp, int objc,
 
733
                            Tcl_Obj *CONST objv[]));
 
734
static int              GetSpinboxElement _ANSI_ARGS_((Spinbox *sbPtr,
 
735
                            int x, int y));
 
736
static int              SpinboxInvoke _ANSI_ARGS_((Tcl_Interp *interp,
 
737
                            Spinbox *sbPtr, int element));
 
738
static int              ComputeFormat _ANSI_ARGS_((Spinbox *sbPtr));
 
739
 
 
740
/*
 
741
 * The structure below defines widget class behavior by means of procedures
432
742
 * that can be invoked from generic window code.
433
743
 */
434
744
 
435
 
static TkClassProcs entryClass = {
436
 
    NULL,                       /* createProc. */
437
 
    EntryWorldChanged,          /* geometryProc. */
438
 
    NULL                        /* modalProc. */
 
745
static Tk_ClassProcs entryClass = {
 
746
    sizeof(Tk_ClassProcs),      /* size */
 
747
    EntryWorldChanged,          /* worldChangedProc */
439
748
};
440
749
 
441
 
 
 
750
 
442
751
/*
443
752
 *--------------------------------------------------------------
444
753
 *
445
 
 * Tk_EntryCmd --
 
754
 * Tk_EntryObjCmd --
446
755
 *
447
 
 *      This procedure is invoked to process the "entry" Tcl
448
 
 *      command.  See the user documentation for details on what
449
 
 *      it does.
 
756
 *      This procedure is invoked to process the "entry" Tcl
 
757
 *      command.  See the user documentation for details on what
 
758
 *      it does.
450
759
 *
451
760
 * Results:
452
 
 *      A standard Tcl result.
 
761
 *      A standard Tcl result.
453
762
 *
454
763
 * Side effects:
455
 
 *      See the user documentation.
 
764
 *      See the user documentation.
456
765
 *
457
766
 *--------------------------------------------------------------
458
767
 */
459
768
 
460
769
int
461
 
Tk_EntryCmd(clientData, interp, argc, argv)
462
 
    ClientData clientData;      /* Main window associated with
463
 
                                 * interpreter. */
464
 
    Tcl_Interp *interp;         /* Current interpreter. */
465
 
    int argc;                   /* Number of arguments. */
466
 
    char **argv;                /* Argument strings. */
 
770
Tk_EntryObjCmd(clientData, interp, objc, objv)
 
771
    ClientData clientData;      /* NULL. */
 
772
    Tcl_Interp *interp;         /* Current interpreter. */
 
773
    int objc;                   /* Number of arguments. */
 
774
    Tcl_Obj *CONST objv[];      /* Argument objects. */
467
775
{
468
 
    Tk_Window tkwin = (Tk_Window) clientData;
469
776
    register Entry *entryPtr;
470
 
    Tk_Window new;
471
 
 
472
 
    if (argc < 2) {
473
 
        Tcl_AppendResult(interp, "wrong # args: should be \"",
474
 
                argv[0], " pathName ?options?\"", (char *) NULL);
475
 
        return TCL_ERROR;
476
 
    }
477
 
 
478
 
    new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
479
 
    if (new == NULL) {
480
 
        return TCL_ERROR;
481
 
    }
 
777
    Tk_OptionTable optionTable;
 
778
    Tk_Window tkwin;
 
779
    char *tmp;
 
780
 
 
781
    if (objc < 2) {
 
782
        Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
 
783
        return TCL_ERROR;
 
784
    }
 
785
 
 
786
    tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
 
787
            Tcl_GetString(objv[1]), (char *) NULL);
 
788
    if (tkwin == NULL) {
 
789
        return TCL_ERROR;
 
790
    }
 
791
 
 
792
    /*
 
793
     * Create the option table for this widget class.  If it has already
 
794
     * been created, Tk will return the cached value.
 
795
     */
 
796
 
 
797
    optionTable = Tk_CreateOptionTable(interp, entryOptSpec);
482
798
 
483
799
    /*
484
800
     * Initialize the fields of the structure that won't be initialized
485
801
     * by ConfigureEntry, or that ConfigureEntry requires to be
486
 
     * initialized already (e.g. resource pointers).
 
802
     * initialized already (e.g. resource pointers).  Only the non-NULL/0
 
803
     * data must be initialized as memset covers the rest.
487
804
     */
488
805
 
489
 
    entryPtr = (Entry *) ckalloc(sizeof(Entry));
490
 
    entryPtr->tkwin = new;
491
 
    entryPtr->display = Tk_Display(new);
492
 
    entryPtr->interp = interp;
493
 
    entryPtr->widgetCmd = Tcl_CreateCommand(interp,
494
 
            Tk_PathName(entryPtr->tkwin), EntryWidgetCmd,
 
806
    entryPtr                    = (Entry *) ckalloc(sizeof(Entry));
 
807
    memset((VOID *) entryPtr, 0, sizeof(Entry));
 
808
 
 
809
    entryPtr->tkwin             = tkwin;
 
810
    entryPtr->display           = Tk_Display(tkwin);
 
811
    entryPtr->interp            = interp;
 
812
    entryPtr->widgetCmd         = Tcl_CreateObjCommand(interp,
 
813
            Tk_PathName(entryPtr->tkwin), EntryWidgetObjCmd,
495
814
            (ClientData) entryPtr, EntryCmdDeletedProc);
496
 
    entryPtr->string = (char *) ckalloc(1);
497
 
    entryPtr->string[0] = '\0';
498
 
    entryPtr->insertPos = 0;
499
 
    entryPtr->selectFirst = -1;
500
 
    entryPtr->selectLast = -1;
501
 
    entryPtr->selectAnchor = 0;
502
 
    entryPtr->scanMarkX = 0;
503
 
    entryPtr->scanMarkIndex = 0;
504
 
 
505
 
    entryPtr->normalBorder = NULL;
506
 
    entryPtr->borderWidth = 0;
507
 
    entryPtr->cursor = None;
508
 
    entryPtr->exportSelection = 1;
509
 
    entryPtr->tkfont = NULL;
510
 
    entryPtr->fgColorPtr = NULL;
511
 
    entryPtr->highlightBgColorPtr = NULL;
512
 
    entryPtr->highlightColorPtr = NULL;
513
 
    entryPtr->highlightWidth = 0;
514
 
    entryPtr->insertBorder = NULL;
515
 
    entryPtr->insertBorderWidth = 0;
516
 
    entryPtr->insertOffTime = 0;
517
 
    entryPtr->insertOnTime = 0;
518
 
    entryPtr->insertWidth = 0;
519
 
    entryPtr->justify = TK_JUSTIFY_LEFT;
520
 
    entryPtr->relief = TK_RELIEF_FLAT;
521
 
    entryPtr->selBorder = NULL;
522
 
    entryPtr->selBorderWidth = 0;
523
 
    entryPtr->selFgColorPtr = NULL;
524
 
    entryPtr->showChar = NULL;
525
 
    entryPtr->state = TK_STATE_NORMAL;
526
 
    entryPtr->textVarName = NULL;
527
 
    entryPtr->takeFocus = NULL;
528
 
    entryPtr->prefWidth = 0;
529
 
    entryPtr->scrollCmd = NULL;
530
 
 
531
 
    entryPtr->numChars = 0;
532
 
    entryPtr->displayString = NULL;
533
 
    entryPtr->inset = XPAD;
534
 
    entryPtr->textLayout = NULL;
535
 
    entryPtr->layoutX = 0;
536
 
    entryPtr->layoutY = 0;
537
 
    entryPtr->leftIndex = 0;
538
 
    entryPtr->leftX = 0;
539
 
    entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
540
 
    entryPtr->textGC = None;
541
 
    entryPtr->selTextGC = None;
542
 
    entryPtr->highlightGC = None;
543
 
    entryPtr->avgWidth = 1;
544
 
    entryPtr->flags = 0;
545
 
    entryPtr->tile = NULL;
546
 
    entryPtr->disabledTile = NULL;
547
 
    entryPtr->fgTile = NULL;
548
 
    entryPtr->tileGC = NULL;
549
 
    entryPtr->tsoffset.flags = 0;
550
 
    entryPtr->tsoffset.xoffset = 0;
551
 
    entryPtr->tsoffset.yoffset = 0;
552
 
#ifdef ENTRY_VALIDATE
553
 
    entryPtr->validateCmd = NULL;
554
 
    entryPtr->validate = VALIDATE_NONE;
555
 
    entryPtr->invalidCmd = NULL;
556
 
#endif /* ENTRY_VALIDATE */
557
 
 
558
 
    TkClassOption(entryPtr->tkwin, "Entry",&argc,&argv);
559
 
    TkSetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr);
 
815
    entryPtr->optionTable       = optionTable;
 
816
    entryPtr->type              = TK_ENTRY;
 
817
    tmp                         = (char *) ckalloc(1);
 
818
    tmp[0]                      = '\0';
 
819
    entryPtr->string            = tmp;
 
820
    entryPtr->selectFirst       = -1;
 
821
    entryPtr->selectLast        = -1;
 
822
 
 
823
    entryPtr->cursor            = None;
 
824
    entryPtr->exportSelection   = 1;
 
825
    entryPtr->justify           = TK_JUSTIFY_LEFT;
 
826
    entryPtr->relief            = TK_RELIEF_FLAT;
 
827
    entryPtr->state             = STATE_NORMAL;
 
828
    entryPtr->displayString     = entryPtr->string;
 
829
    entryPtr->inset             = XPAD;
 
830
    entryPtr->textGC            = None;
 
831
    entryPtr->selTextGC         = None;
 
832
    entryPtr->highlightGC       = None;
 
833
    entryPtr->avgWidth          = 1;
 
834
    entryPtr->validate          = VALIDATE_NONE;
 
835
 
 
836
    /*
 
837
     * Keep a hold of the associated tkwin until we destroy the listbox,
 
838
     * otherwise Tk might free it while we still need it.
 
839
     */
 
840
 
 
841
    Tcl_Preserve((ClientData) entryPtr->tkwin);
 
842
 
 
843
    Tk_SetClass(entryPtr->tkwin, "Entry");
 
844
    Tk_SetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr);
560
845
    Tk_CreateEventHandler(entryPtr->tkwin,
561
846
            ExposureMask|StructureNotifyMask|FocusChangeMask,
562
847
            EntryEventProc, (ClientData) entryPtr);
563
848
    Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING,
564
849
            EntryFetchSelection, (ClientData) entryPtr, XA_STRING);
565
 
    if (ConfigureEntry(interp, entryPtr, argc-2, argv+2, 0) != TCL_OK) {
566
 
        goto error;
 
850
 
 
851
    if ((Tk_InitOptions(interp, (char *) entryPtr, optionTable, tkwin)
 
852
            != TCL_OK) ||
 
853
            (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK)) {
 
854
        Tk_DestroyWindow(entryPtr->tkwin);
 
855
        return TCL_ERROR;
567
856
    }
568
857
 
569
 
    interp->result = Tk_PathName(entryPtr->tkwin);
 
858
    Tcl_SetResult(interp, Tk_PathName(entryPtr->tkwin), TCL_STATIC);
570
859
    return TCL_OK;
 
860
}
571
861
 
572
 
    error:
573
 
    Tk_DestroyWindow(entryPtr->tkwin);
574
 
    return TCL_ERROR;
575
 
}
576
 
 
577
862
/*
578
863
 *--------------------------------------------------------------
579
864
 *
580
 
 * EntryWidgetCmd --
 
865
 * EntryWidgetObjCmd --
581
866
 *
582
 
 *      This procedure is invoked to process the Tcl command
583
 
 *      that corresponds to a widget managed by this module.
584
 
 *      See the user documentation for details on what it does.
 
867
 *      This procedure is invoked to process the Tcl command
 
868
 *      that corresponds to a widget managed by this module.
 
869
 *      See the user documentation for details on what it does.
585
870
 *
586
871
 * Results:
587
 
 *      A standard Tcl result.
 
872
 *      A standard Tcl result.
588
873
 *
589
874
 * Side effects:
590
 
 *      See the user documentation.
 
875
 *      See the user documentation.
591
876
 *
592
877
 *--------------------------------------------------------------
593
878
 */
594
879
 
595
880
static int
596
 
EntryWidgetCmd(clientData, interp, argc, argv)
597
 
    ClientData clientData;              /* Information about entry widget. */
598
 
    Tcl_Interp *interp;                 /* Current interpreter. */
599
 
    int argc;                           /* Number of arguments. */
600
 
    char **argv;                        /* Argument strings. */
 
881
EntryWidgetObjCmd(clientData, interp, objc, objv)
 
882
    ClientData clientData;      /* Information about entry widget. */
 
883
    Tcl_Interp *interp;         /* Current interpreter. */
 
884
    int objc;                   /* Number of arguments. */
 
885
    Tcl_Obj *CONST objv[];      /* Argument objects. */
601
886
{
602
 
    register Entry *entryPtr = (Entry *) clientData;
603
 
    int result = TCL_OK;
604
 
    size_t length;
605
 
    int c;
 
887
    Entry *entryPtr = (Entry *) clientData;
 
888
    int cmdIndex, selIndex, result;
 
889
    Tcl_Obj *objPtr;
606
890
 
607
 
    if (argc < 2) {
608
 
        Tcl_AppendResult(interp, "wrong # args: should be \"",
609
 
                argv[0], " option ?arg arg ...?\"", (char *) NULL);
 
891
    if (objc < 2) {
 
892
        Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
610
893
        return TCL_ERROR;
611
894
    }
 
895
 
 
896
    /*
 
897
     * Parse the widget command by looking up the second token in
 
898
     * the list of valid command names.
 
899
     */
 
900
 
 
901
    result = Tcl_GetIndexFromObj(interp, objv[1], entryCmdNames,
 
902
            "option", 0, &cmdIndex);
 
903
    if (result != TCL_OK) {
 
904
        return result;
 
905
    }
 
906
 
612
907
    Tcl_Preserve((ClientData) entryPtr);
613
 
    c = argv[1][0];
614
 
    length = strlen(argv[1]);
615
 
    if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
616
 
        int index;
617
 
        int x, y, width, height;
618
 
 
619
 
        if (argc != 3) {
620
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
621
 
                    argv[0], " bbox index\"",
622
 
                    (char *) NULL);
623
 
            goto error;
624
 
        }
625
 
        if (GetEntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
626
 
            goto error;
627
 
        }
628
 
        if ((index == entryPtr->numChars) && (index > 0)) {
629
 
            index--;
630
 
        }
631
 
        Tk_CharBbox(entryPtr->textLayout, index, &x, &y, &width, &height);
632
 
        sprintf(interp->result, "%d %d %d %d",
633
 
                x + entryPtr->layoutX, y + entryPtr->layoutY, width, height);
634
 
    } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
635
 
            && (length >= 2)) {
636
 
        if (argc != 3) {
637
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
638
 
                    argv[0], " cget option\"",
639
 
                    (char *) NULL);
640
 
            goto error;
641
 
        }
642
 
        result = Tk_ConfigureValue(interp, entryPtr->tkwin, configSpecs,
643
 
                (char *) entryPtr, argv[2], 0);
644
 
    } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
645
 
            && (length >= 2)) {
646
 
        if (argc == 2) {
647
 
            result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs,
648
 
                    (char *) entryPtr, (char *) NULL, 0);
649
 
        } else if (argc == 3) {
650
 
            result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs,
651
 
                    (char *) entryPtr, argv[2], 0);
652
 
        } else {
653
 
            result = ConfigureEntry(interp, entryPtr, argc-2, argv+2,
654
 
                    TK_CONFIG_ARGV_ONLY);
655
 
        }
656
 
    } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
657
 
        int first, last;
658
 
 
659
 
        if ((argc < 3) || (argc > 4)) {
660
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
661
 
                    argv[0], " delete firstIndex ?lastIndex?\"",
662
 
                    (char *) NULL);
663
 
            goto error;
664
 
        }
665
 
        if (GetEntryIndex(interp, entryPtr, objv[2], &first) != TCL_OK) {
666
 
            goto error;
667
 
        }
668
 
        if (argc == 3) {
669
 
            last = first+1;
670
 
        } else {
671
 
            if (GetEntryIndex(interp, entryPtr, objv[3], &last) != TCL_OK) {
672
 
                goto error;
673
 
            }
674
 
        }
675
 
        if ((last >= first) && (entryPtr->state == TK_STATE_NORMAL)) {
676
 
            DeleteChars(entryPtr, first, last-first);
677
 
        }
678
 
    } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
679
 
        if (argc != 2) {
680
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
681
 
                    argv[0], " get\"", (char *) NULL);
682
 
            goto error;
683
 
        }
684
 
        interp->result = entryPtr->string;
685
 
    } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0)
686
 
            && (length >= 2)) {
687
 
        if (argc != 3) {
688
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
689
 
                    argv[0], " icursor pos\"",
690
 
                    (char *) NULL);
691
 
            goto error;
692
 
        }
693
 
        if (GetEntryIndex(interp, entryPtr, objv[2], &entryPtr->insertPos)
694
 
                != TCL_OK) {
695
 
            goto error;
696
 
        }
697
 
        EventuallyRedraw(entryPtr);
698
 
    } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
699
 
            && (length >= 3)) {
700
 
        int index;
701
 
 
702
 
        if (argc != 3) {
703
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
704
 
                    argv[0], " index string\"", (char *) NULL);
705
 
            goto error;
706
 
        }
707
 
        if (GetEntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
708
 
            goto error;
709
 
        }
710
 
        sprintf(interp->result, "%d", index);
711
 
    } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
712
 
            && (length >= 3)) {
713
 
        int index;
714
 
 
715
 
        if (argc != 4) {
716
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
717
 
                    argv[0], " insert index text\"",
718
 
                    (char *) NULL);
719
 
            goto error;
720
 
        }
721
 
        if (GetEntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
722
 
            goto error;
723
 
        }
724
 
        if (entryPtr->state == TK_STATE_NORMAL) {
725
 
            InsertChars(entryPtr, index, argv[3]);
726
 
        }
727
 
    } else if ((c == 's') && (length >= 2)
728
 
            && (strncmp(argv[1], "scan", length) == 0)) {
729
 
        int x;
730
 
 
731
 
        if (argc != 4) {
732
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
733
 
                    argv[0], " scan mark|dragto x\"", (char *) NULL);
734
 
            goto error;
735
 
        }
736
 
        if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) {
737
 
            goto error;
738
 
        }
739
 
        if ((argv[2][0] == 'm')
740
 
                && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
741
 
            entryPtr->scanMarkX = x;
742
 
            entryPtr->scanMarkIndex = entryPtr->leftIndex;
743
 
        } else if ((argv[2][0] == 'd')
744
 
                && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
745
 
            EntryScanTo(entryPtr, x);
746
 
        } else {
747
 
            Tcl_AppendResult(interp, "bad scan option \"", argv[2],
748
 
                    "\": must be mark or dragto", (char *) NULL);
749
 
            goto error;
750
 
        }
751
 
    } else if ((c == 's') && (length >= 2)
752
 
            && (strncmp(argv[1], "selection", length) == 0)) {
753
 
        int index, index2;
754
 
 
755
 
        if (argc < 3) {
756
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
757
 
                    argv[0], " select option ?index?\"", (char *) NULL);
758
 
            goto error;
759
 
        }
760
 
        length = strlen(argv[2]);
761
 
        c = argv[2][0];
762
 
        if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) {
763
 
            if (argc != 3) {
764
 
                Tcl_AppendResult(interp, "wrong # args: should be \"",
765
 
                        argv[0], " selection clear\"", (char *) NULL);
766
 
                goto error;
767
 
            }
768
 
            if (entryPtr->selectFirst != -1) {
769
 
                entryPtr->selectFirst = entryPtr->selectLast = -1;
770
 
                EventuallyRedraw(entryPtr);
771
 
            }
772
 
            goto done;
773
 
        } else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) {
774
 
            if (argc != 3) {
775
 
                Tcl_AppendResult(interp, "wrong # args: should be \"",
776
 
                        argv[0], " selection present\"", (char *) NULL);
777
 
                goto error;
778
 
            }
779
 
            if (entryPtr->selectFirst == -1) {
780
 
                interp->result = "0";
 
908
    switch ((enum entryCmd) cmdIndex) {
 
909
        case COMMAND_BBOX: {
 
910
            int index, x, y, width, height;
 
911
            char buf[TCL_INTEGER_SPACE * 4];
 
912
 
 
913
            if (objc != 3) {
 
914
                Tcl_WrongNumArgs(interp, 2, objv, "index");
 
915
                goto error;
 
916
            }
 
917
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
918
                    &index) != TCL_OK) {
 
919
                goto error;
 
920
            }
 
921
            if ((index == entryPtr->numChars) && (index > 0)) {
 
922
                index--;
 
923
            }
 
924
            Tk_CharBbox(entryPtr->textLayout, index, &x, &y,
 
925
                    &width, &height);
 
926
            Tcl_IntResults(interp, 4, 0,
 
927
                    x + entryPtr->layoutX,
 
928
                    y + entryPtr->layoutY, width, height);
 
929
            break;
 
930
        }
 
931
 
 
932
        case COMMAND_CGET: {
 
933
            if (objc != 3) {
 
934
                Tcl_WrongNumArgs(interp, 2, objv, "option");
 
935
                goto error;
 
936
            }
 
937
 
 
938
            objPtr = Tk_GetOptionValue(interp, (char *) entryPtr,
 
939
                    entryPtr->optionTable, objv[2], entryPtr->tkwin);
 
940
            if (objPtr == NULL) {
 
941
                 goto error;
781
942
            } else {
782
 
                interp->result = "1";
783
 
            }
784
 
            goto done;
785
 
        }
786
 
        if (argc >= 4) {
787
 
            if (GetEntryIndex(interp, entryPtr, objv[3], &index) != TCL_OK) {
788
 
                goto error;
789
 
            }
790
 
        }
791
 
        if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
792
 
            if (argc != 4) {
793
 
                Tcl_AppendResult(interp, "wrong # args: should be \"",
794
 
                        argv[0], " selection adjust index\"",
795
 
                        (char *) NULL);
796
 
                goto error;
797
 
            }
798
 
            if (entryPtr->selectFirst >= 0) {
799
 
                int half1, half2;
 
943
                Tcl_SetObjResult(interp, objPtr);
 
944
            }
 
945
            break;
 
946
        }
800
947
 
801
 
                half1 = (entryPtr->selectFirst + entryPtr->selectLast)/2;
802
 
                half2 = (entryPtr->selectFirst + entryPtr->selectLast + 1)/2;
803
 
                if (index < half1) {
804
 
                    entryPtr->selectAnchor = entryPtr->selectLast;
805
 
                } else if (index > half2) {
806
 
                    entryPtr->selectAnchor = entryPtr->selectFirst;
 
948
        case COMMAND_CONFIGURE: {
 
949
            if (objc <= 3) {
 
950
                objPtr = Tk_GetOptionInfo(interp, (char *) entryPtr,
 
951
                        entryPtr->optionTable,
 
952
                        (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
 
953
                        entryPtr->tkwin);
 
954
                if (objPtr == NULL) {
 
955
                    goto error;
807
956
                } else {
808
 
                    /*
809
 
                     * We're at about the halfway point in the selection;
810
 
                     * just keep the existing anchor.
811
 
                     */
812
 
                }
813
 
            }
814
 
            EntrySelectTo(entryPtr, index);
815
 
        } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
816
 
            if (argc != 4) {
817
 
                Tcl_AppendResult(interp, "wrong # args: should be \"",
818
 
                        argv[0], " selection from index\"",
819
 
                        (char *) NULL);
820
 
                goto error;
821
 
            }
822
 
            entryPtr->selectAnchor = index;
823
 
        } else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) {
824
 
            if (argc != 5) {
825
 
                Tcl_AppendResult(interp, "wrong # args: should be \"",
826
 
                        argv[0], " selection range start end\"",
827
 
                        (char *) NULL);
828
 
                goto error;
829
 
            }
830
 
            if (GetEntryIndex(interp, entryPtr, objv[4], &index2) != TCL_OK) {
831
 
                goto error;
832
 
            }
833
 
            if (index >= index2) {
834
 
                entryPtr->selectFirst = entryPtr->selectLast = -1;
835
 
            } else {
836
 
                entryPtr->selectFirst = index;
837
 
                entryPtr->selectLast = index2;
838
 
            }
839
 
            if (!(entryPtr->flags & GOT_SELECTION)
840
 
                    && (entryPtr->exportSelection)) {
841
 
                Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
842
 
                        EntryLostSelection, (ClientData) entryPtr);
843
 
                entryPtr->flags |= GOT_SELECTION;
844
 
            }
845
 
            EventuallyRedraw(entryPtr);
846
 
        } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
847
 
            if (argc != 4) {
848
 
                Tcl_AppendResult(interp, "wrong # args: should be \"",
849
 
                        argv[0], " selection to index\"",
850
 
                        (char *) NULL);
851
 
                goto error;
852
 
            }
853
 
            EntrySelectTo(entryPtr, index);
854
 
        } else {
855
 
            Tcl_AppendResult(interp, "bad selection option \"", argv[2],
856
 
                    "\": must be adjust, clear, from, present, range, or to",
857
 
                    (char *) NULL);
858
 
            goto error;
859
 
        }
860
 
#ifdef ENTRY_VALIDATE
861
 
    } else if ((c == 'v') && (strncmp(argv[1], "validate", length) == 0)) {
862
 
        int code, x;
863
 
        if (argc != 2) {
864
 
            Tcl_AppendResult(interp, "wrong # args: should be \"",
865
 
                    argv[0], " validate\"", (char *) NULL);
866
 
            goto error;
867
 
        }
868
 
        x = entryPtr->validate;
869
 
        entryPtr->validate = VALIDATE_ALL;
870
 
        code = EntryValidateChange(entryPtr, (char *) NULL,
871
 
                                   entryPtr->string, -1, -1);
872
 
        if (entryPtr->validate) {
873
 
            entryPtr->validate = x;
874
 
        }
875
 
        sprintf(interp->result, "%d", (code == TCL_OK) ? 1 : 0);
876
 
#endif /* ENTRY_VALIDATE */
877
 
    } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
878
 
        int index, type, count, charsPerPage;
879
 
        double fraction, first, last;
880
 
 
881
 
        if (argc == 2) {
882
 
            EntryVisibleRange(entryPtr, &first, &last);
883
 
            sprintf(interp->result, "%g %g", first, last);
884
 
            goto done;
885
 
        } else if (argc == 3) {
886
 
            if (GetEntryIndex(interp, entryPtr, objv[2], &index) != TCL_OK) {
887
 
                goto error;
888
 
            }
889
 
        } else {
890
 
            type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
891
 
            index = entryPtr->leftIndex;
892
 
            switch (type) {
893
 
                case TK_SCROLL_ERROR:
894
 
                    goto error;
895
 
                case TK_SCROLL_MOVETO:
896
 
                    index = (int) ((fraction * entryPtr->numChars) + 0.5);
897
 
                    break;
898
 
                case TK_SCROLL_PAGES:
899
 
                    charsPerPage = ((Tk_Width(entryPtr->tkwin)
900
 
                            - 2*entryPtr->inset) / entryPtr->avgWidth) - 2;
901
 
                    if (charsPerPage < 1) {
902
 
                        charsPerPage = 1;
903
 
                    }
904
 
                    index += charsPerPage*count;
905
 
                    break;
906
 
                case TK_SCROLL_UNITS:
907
 
                    index += count;
908
 
                    break;
909
 
            }
910
 
        }
911
 
        if (index >= entryPtr->numChars) {
912
 
            index = entryPtr->numChars-1;
913
 
        }
914
 
        if (index < 0) {
915
 
            index = 0;
916
 
        }
917
 
        entryPtr->leftIndex = index;
918
 
        entryPtr->flags |= UPDATE_SCROLLBAR;
919
 
        EntryComputeGeometry(entryPtr);
920
 
        EventuallyRedraw(entryPtr);
921
 
    } else {
922
 
        Tcl_AppendResult(interp, "bad option \"", argv[1],
923
 
                "\": must be bbox, cget, configure, delete, get, ",
924
 
#ifdef ENTRY_VALIDATE
925
 
                "icursor, index, insert, scan, selection, validate, or xview",
926
 
#else
927
 
                "icursor, index, insert, scan, selection, or xview",
928
 
#endif /* ENTRY_VALIDATE */
929
 
                (char *) NULL);
930
 
        goto error;
 
957
                    Tcl_SetObjResult(interp, objPtr);
 
958
                }
 
959
            } else {
 
960
                result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0);
 
961
            }
 
962
            break;
 
963
        }
 
964
 
 
965
        case COMMAND_DELETE: {
 
966
            int first, last;
 
967
 
 
968
            if ((objc < 3) || (objc > 4)) {
 
969
                Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
 
970
                goto error;
 
971
            }
 
972
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
973
                    &first) != TCL_OK) {
 
974
                goto error;
 
975
            }
 
976
            if (objc == 3) {
 
977
                last = first + 1;
 
978
            } else {
 
979
                if (GetEntryIndex(interp, entryPtr, objv[3],
 
980
                        &last) != TCL_OK) {
 
981
                    goto error;
 
982
                }
 
983
            }
 
984
            if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
 
985
                DeleteChars(entryPtr, first, last - first);
 
986
            }
 
987
            break;
 
988
        }
 
989
 
 
990
        case COMMAND_GET: {
 
991
            if (objc != 2) {
 
992
                Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
 
993
                goto error;
 
994
            }
 
995
            Tcl_SetStringObj(Tcl_GetObjResult(interp), entryPtr->string, -1);
 
996
            break;
 
997
        }
 
998
 
 
999
        case COMMAND_ICURSOR: {
 
1000
            if (objc != 3) {
 
1001
                Tcl_WrongNumArgs(interp, 2, objv, "pos");
 
1002
                goto error;
 
1003
            }
 
1004
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
1005
                    &entryPtr->insertPos) != TCL_OK) {
 
1006
                goto error;
 
1007
            }
 
1008
            EventuallyRedraw(entryPtr);
 
1009
            break;
 
1010
        }
 
1011
 
 
1012
        case COMMAND_INDEX: {
 
1013
            int index;
 
1014
 
 
1015
            if (objc != 3) {
 
1016
                Tcl_WrongNumArgs(interp, 2, objv, "string");
 
1017
                goto error;
 
1018
            }
 
1019
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
1020
                    &index) != TCL_OK) {
 
1021
                goto error;
 
1022
            }
 
1023
            Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
 
1024
            break;
 
1025
        }
 
1026
 
 
1027
        case COMMAND_INSERT: {
 
1028
            int index;
 
1029
 
 
1030
            if (objc != 4) {
 
1031
                Tcl_WrongNumArgs(interp, 2, objv, "index text");
 
1032
                goto error;
 
1033
            }
 
1034
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
1035
                    &index) != TCL_OK) {
 
1036
                goto error;
 
1037
            }
 
1038
            if (entryPtr->state == STATE_NORMAL) {
 
1039
                InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
 
1040
            }
 
1041
            break;
 
1042
        }
 
1043
 
 
1044
        case COMMAND_SCAN: {
 
1045
            int x;
 
1046
            char *minorCmd;
 
1047
 
 
1048
            if (objc != 4) {
 
1049
                Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x");
 
1050
                goto error;
 
1051
            }
 
1052
            if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
 
1053
                goto error;
 
1054
            }
 
1055
 
 
1056
            minorCmd = Tcl_GetString(objv[2]);
 
1057
            if (minorCmd[0] == 'm'
 
1058
                    && (strncmp(minorCmd, "mark", strlen(minorCmd)) == 0)) {
 
1059
                entryPtr->scanMarkX = x;
 
1060
                entryPtr->scanMarkIndex = entryPtr->leftIndex;
 
1061
            } else if ((minorCmd[0] == 'd')
 
1062
                && (strncmp(minorCmd, "dragto", strlen(minorCmd)) == 0)) {
 
1063
                EntryScanTo(entryPtr, x);
 
1064
            } else {
 
1065
                Tcl_AppendResult(interp, "bad scan option \"",
 
1066
                        Tcl_GetString(objv[2]), "\": must be mark or dragto",
 
1067
                        (char *) NULL);
 
1068
                goto error;
 
1069
            }
 
1070
            break;
 
1071
        }
 
1072
 
 
1073
        case COMMAND_SELECTION: {
 
1074
            int index, index2;
 
1075
 
 
1076
            if (objc < 3) {
 
1077
                Tcl_WrongNumArgs(interp, 2, objv, "option ?index?");
 
1078
                goto error;
 
1079
            }
 
1080
 
 
1081
            /*
 
1082
             * Parse the selection sub-command, using the command
 
1083
             * table "selCmdNames" defined above.
 
1084
             */
 
1085
 
 
1086
            result = Tcl_GetIndexFromObj(interp, objv[2], selCmdNames,
 
1087
                    "selection option", 0, &selIndex);
 
1088
            if (result != TCL_OK) {
 
1089
                goto error;
 
1090
            }
 
1091
 
 
1092
            /*
 
1093
             * Disabled entries don't allow the selection to be modified,
 
1094
             * but 'selection present' must return a boolean.
 
1095
             */
 
1096
 
 
1097
            if ((entryPtr->state == STATE_DISABLED)
 
1098
                    && (selIndex != SELECTION_PRESENT)) {
 
1099
                goto done;
 
1100
            }
 
1101
 
 
1102
            switch (selIndex) {
 
1103
                case SELECTION_ADJUST: {
 
1104
                    if (objc != 4) {
 
1105
                        Tcl_WrongNumArgs(interp, 3, objv, "index");
 
1106
                        goto error;
 
1107
                    }
 
1108
                    if (GetEntryIndex(interp, entryPtr,
 
1109
                            objv[3], &index) != TCL_OK) {
 
1110
                        goto error;
 
1111
                    }
 
1112
                    if (entryPtr->selectFirst >= 0) {
 
1113
                        int half1, half2;
 
1114
 
 
1115
                        half1 = (entryPtr->selectFirst
 
1116
                                + entryPtr->selectLast)/2;
 
1117
                        half2 = (entryPtr->selectFirst
 
1118
                                + entryPtr->selectLast + 1)/2;
 
1119
                        if (index < half1) {
 
1120
                            entryPtr->selectAnchor = entryPtr->selectLast;
 
1121
                        } else if (index > half2) {
 
1122
                            entryPtr->selectAnchor = entryPtr->selectFirst;
 
1123
                        } else {
 
1124
                          /*
 
1125
                           * We're at about the halfway point in the
 
1126
                           * selection; just keep the existing anchor.
 
1127
                           */
 
1128
                        }
 
1129
                    }
 
1130
                    EntrySelectTo(entryPtr, index);
 
1131
                    break;
 
1132
                }
 
1133
 
 
1134
                case SELECTION_CLEAR: {
 
1135
                    if (objc != 3) {
 
1136
                        Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
 
1137
                        goto error;
 
1138
                    }
 
1139
                    if (entryPtr->selectFirst >= 0) {
 
1140
                        entryPtr->selectFirst = -1;
 
1141
                        entryPtr->selectLast = -1;
 
1142
                        EventuallyRedraw(entryPtr);
 
1143
                    }
 
1144
                    goto done;
 
1145
                }
 
1146
 
 
1147
                case SELECTION_FROM: {
 
1148
                    if (objc != 4) {
 
1149
                        Tcl_WrongNumArgs(interp, 3, objv, "index");
 
1150
                        goto error;
 
1151
                    }
 
1152
                    if (GetEntryIndex(interp, entryPtr,
 
1153
                            objv[3], &index) != TCL_OK) {
 
1154
                        goto error;
 
1155
                    }
 
1156
                    entryPtr->selectAnchor = index;
 
1157
                    break;
 
1158
                }
 
1159
 
 
1160
                case SELECTION_PRESENT: {
 
1161
                    if (objc != 3) {
 
1162
                        Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
 
1163
                        goto error;
 
1164
                    }
 
1165
                    Tcl_SetObjResult(interp,
 
1166
                            Tcl_NewBooleanObj((entryPtr->selectFirst >= 0)));
 
1167
                    goto done;
 
1168
                }
 
1169
 
 
1170
                case SELECTION_RANGE: {
 
1171
                    if (objc != 5) {
 
1172
                        Tcl_WrongNumArgs(interp, 3, objv, "start end");
 
1173
                        goto error;
 
1174
                    }
 
1175
                    if (GetEntryIndex(interp, entryPtr,
 
1176
                            objv[3], &index) != TCL_OK) {
 
1177
                        goto error;
 
1178
                    }
 
1179
                    if (GetEntryIndex(interp, entryPtr,
 
1180
                            objv[4],& index2) != TCL_OK) {
 
1181
                        goto error;
 
1182
                    }
 
1183
                    if (index >= index2) {
 
1184
                        entryPtr->selectFirst = -1;
 
1185
                        entryPtr->selectLast = -1;
 
1186
                    } else {
 
1187
                        entryPtr->selectFirst = index;
 
1188
                        entryPtr->selectLast = index2;
 
1189
                    }
 
1190
                    if (!(entryPtr->flags & GOT_SELECTION)
 
1191
                            && (entryPtr->exportSelection)) {
 
1192
                        Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
 
1193
                                EntryLostSelection, (ClientData) entryPtr);
 
1194
                        entryPtr->flags |= GOT_SELECTION;
 
1195
                    }
 
1196
                    EventuallyRedraw(entryPtr);
 
1197
                    break;
 
1198
                }
 
1199
 
 
1200
                case SELECTION_TO: {
 
1201
                    if (objc != 4) {
 
1202
                        Tcl_WrongNumArgs(interp, 3, objv, "index");
 
1203
                        goto error;
 
1204
                    }
 
1205
                    if (GetEntryIndex(interp, entryPtr,
 
1206
                            objv[3], &index) != TCL_OK) {
 
1207
                        goto error;
 
1208
                    }
 
1209
                    EntrySelectTo(entryPtr, index);
 
1210
                    break;
 
1211
                }
 
1212
            }
 
1213
            break;
 
1214
        }
 
1215
 
 
1216
        case COMMAND_VALIDATE: {
 
1217
            int code;
 
1218
 
 
1219
            if (objc != 2) {
 
1220
                Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
 
1221
                goto error;
 
1222
            }
 
1223
            selIndex = entryPtr->validate;
 
1224
            entryPtr->validate = VALIDATE_ALL;
 
1225
            code = EntryValidateChange(entryPtr, (char *) NULL,
 
1226
                                       entryPtr->string, -1, VALIDATE_FORCED);
 
1227
            if (entryPtr->validate != VALIDATE_NONE) {
 
1228
                entryPtr->validate = selIndex;
 
1229
            }
 
1230
            Tcl_SetObjResult(interp, Tcl_NewBooleanObj((code == TCL_OK)));
 
1231
            break;
 
1232
        }
 
1233
 
 
1234
        case COMMAND_XVIEW: {
 
1235
            int index;
 
1236
 
 
1237
            if (objc == 2) {
 
1238
                double first, last;
 
1239
                char buf[TCL_DOUBLE_SPACE * 2];
 
1240
 
 
1241
                EntryVisibleRange(entryPtr, &first, &last);
 
1242
                Tcl_DoubleResults(interp,2,0,first, last);
 
1243
                goto done;
 
1244
            } else if (objc == 3) {
 
1245
                if (GetEntryIndex(interp, entryPtr, objv[2],
 
1246
                        &index) != TCL_OK) {
 
1247
                    goto error;
 
1248
                }
 
1249
            } else {
 
1250
                double fraction;
 
1251
                int count;
 
1252
 
 
1253
                index = entryPtr->leftIndex;
 
1254
                switch (Tk_GetScrollInfoObj(interp, objc, objv, &fraction,
 
1255
                        &count)) {
 
1256
                    case TK_SCROLL_ERROR: {
 
1257
                        goto error;
 
1258
                    }
 
1259
                    case TK_SCROLL_MOVETO: {
 
1260
                        index = (int) ((fraction * entryPtr->numChars) + 0.5);
 
1261
                        break;
 
1262
                    }
 
1263
                    case TK_SCROLL_PAGES: {
 
1264
                        int charsPerPage;
 
1265
 
 
1266
                        charsPerPage = ((Tk_Width(entryPtr->tkwin)
 
1267
                                - 2 * entryPtr->inset)
 
1268
                                / entryPtr->avgWidth) - 2;
 
1269
                        if (charsPerPage < 1) {
 
1270
                            charsPerPage = 1;
 
1271
                        }
 
1272
                        index += count * charsPerPage;
 
1273
                        break;
 
1274
                    }
 
1275
                    case TK_SCROLL_UNITS: {
 
1276
                        index += count;
 
1277
                        break;
 
1278
                    }
 
1279
                }
 
1280
            }
 
1281
            if (index >= entryPtr->numChars) {
 
1282
                index = entryPtr->numChars - 1;
 
1283
            }
 
1284
            if (index < 0) {
 
1285
                index = 0;
 
1286
            }
 
1287
            entryPtr->leftIndex = index;
 
1288
            entryPtr->flags |= UPDATE_SCROLLBAR;
 
1289
            EntryComputeGeometry(entryPtr);
 
1290
            EventuallyRedraw(entryPtr);
 
1291
            break;
 
1292
        }
931
1293
    }
 
1294
 
932
1295
    done:
933
1296
    Tcl_Release((ClientData) entryPtr);
934
1297
    return result;
937
1300
    Tcl_Release((ClientData) entryPtr);
938
1301
    return TCL_ERROR;
939
1302
}
940
 
 
 
1303
 
941
1304
/*
942
1305
 *----------------------------------------------------------------------
943
1306
 *
944
1307
 * DestroyEntry --
945
1308
 *
946
 
 *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
947
 
 *      to clean up the internal structure of an entry at a safe time
948
 
 *      (when no-one is using it anymore).
 
1309
 *      This procedure is invoked by Tcl_EventuallyFree or Tcl_Release
 
1310
 *      to clean up the internal structure of an entry at a safe time
 
1311
 *      (when no-one is using it anymore).
949
1312
 *
950
1313
 * Results:
951
 
 *      None.
 
1314
 *      None.
952
1315
 *
953
1316
 * Side effects:
954
 
 *      Everything associated with the entry is freed up.
 
1317
 *      Everything associated with the entry is freed up.
955
1318
 *
956
1319
 *----------------------------------------------------------------------
957
1320
 */
958
1321
 
959
1322
static void
960
1323
DestroyEntry(memPtr)
961
 
    char *memPtr;               /* Info about entry widget. */
 
1324
    char *memPtr;               /* Info about entry widget. */
962
1325
{
963
 
    register Entry *entryPtr = (Entry *) memPtr;
 
1326
    Entry *entryPtr = (Entry *) memPtr;
964
1327
 
965
1328
    /*
966
1329
     * Free up all the stuff that requires special handling, then
968
1331
     * stuff.
969
1332
     */
970
1333
 
971
 
    ckfree(entryPtr->string);
 
1334
    ckfree((char *)entryPtr->string);
972
1335
    if (entryPtr->textVarName != NULL) {
973
 
        Tcl_UntraceVar(entryPtr->interp, entryPtr->textVarName,
 
1336
        Lang_UntraceVar(entryPtr->interp, entryPtr->textVarName,
974
1337
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
975
1338
                EntryTextVarProc, (ClientData) entryPtr);
 
1339
        entryPtr->flags &= ~ENTRY_VAR_TRACED;
976
1340
    }
977
1341
    if (entryPtr->textGC != None) {
978
1342
        Tk_FreeGC(entryPtr->display, entryPtr->textGC);
980
1344
    if (entryPtr->selTextGC != None) {
981
1345
        Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
982
1346
    }
983
 
    if (entryPtr->tile != NULL) {
984
 
        Tk_FreeTile(entryPtr->tile);
985
 
    }
986
 
    if (entryPtr->disabledTile != NULL) {
987
 
        Tk_FreeTile(entryPtr->disabledTile);
988
 
    }
989
 
    if (entryPtr->fgTile != NULL) {
990
 
        Tk_FreeTile(entryPtr->fgTile);
991
 
    }
992
 
    if (entryPtr->tileGC != NULL) {
993
 
        Tk_FreeGC(entryPtr->display, entryPtr->tileGC);
994
 
    }
995
1347
    Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler);
996
 
    if (entryPtr->displayString != NULL) {
997
 
        ckfree(entryPtr->displayString);
 
1348
    if (entryPtr->displayString != entryPtr->string) {
 
1349
        ckfree((char *)entryPtr->displayString);
 
1350
    }
 
1351
    if (entryPtr->type == TK_SPINBOX) {
 
1352
        Spinbox *sbPtr = (Spinbox *) entryPtr;
 
1353
 
 
1354
        if (sbPtr->listObj != NULL) {
 
1355
            Tcl_DecrRefCount(sbPtr->listObj);
 
1356
            sbPtr->listObj = NULL;
 
1357
        }
 
1358
        if (sbPtr->formatBuf) {
 
1359
            ckfree(sbPtr->formatBuf);
 
1360
        }
998
1361
    }
999
1362
    Tk_FreeTextLayout(entryPtr->textLayout);
1000
 
    Tk_FreeOptions(configSpecs, (char *) entryPtr, entryPtr->display, 0);
 
1363
    Tk_FreeConfigOptions((char *) entryPtr, entryPtr->optionTable,
 
1364
            entryPtr->tkwin);
 
1365
    Tcl_Release((ClientData) entryPtr->tkwin);
 
1366
    entryPtr->tkwin = NULL;
 
1367
 
1001
1368
    ckfree((char *) entryPtr);
1002
1369
}
1003
 
 
1004
 
/*
1005
 
 *----------------------------------------------------------------------
1006
 
 *
1007
 
 * TileChangedProc
1008
 
 *
1009
 
 * Results:
1010
 
 *      None.
1011
 
 *
1012
 
 *----------------------------------------------------------------------
1013
 
 */
1014
 
/* ARGSUSED */
1015
 
static void
1016
 
TileChangedProc(clientData, tile, itemPtr)
1017
 
    ClientData clientData;
1018
 
    Tk_Tile tile;
1019
 
    Tk_Item *itemPtr;                   /* Not used */
1020
 
{
1021
 
    register Entry *entryPtr = (Entry *) clientData;
1022
1370
 
1023
 
    ConfigureEntry(entryPtr->interp, entryPtr, 0, NULL, 0);
1024
 
}
1025
 
 
1026
1371
/*
1027
1372
 *----------------------------------------------------------------------
1028
1373
 *
1029
1374
 * ConfigureEntry --
1030
1375
 *
1031
 
 *      This procedure is called to process an argv/argc list, plus
1032
 
 *      the Tk option database, in order to configure (or reconfigure)
1033
 
 *      an entry widget.
 
1376
 *      This procedure is called to process an argv/argc list, plus
 
1377
 *      the Tk option database, in order to configure (or reconfigure)
 
1378
 *      an entry widget.
1034
1379
 *
1035
1380
 * Results:
1036
 
 *      The return value is a standard Tcl result.  If TCL_ERROR is
1037
 
 *      returned, then interp->result contains an error message.
 
1381
 *      The return value is a standard Tcl result.  If TCL_ERROR is
 
1382
 *      returned, then the interp's result contains an error message.
1038
1383
 *
1039
1384
 * Side effects:
1040
 
 *      Configuration information, such as colors, border width,
1041
 
 *      etc. get set for entryPtr;  old resources get freed,
1042
 
 *      if there were any.
 
1385
 *      Configuration information, such as colors, border width,
 
1386
 *      etc. get set for entryPtr;  old resources get freed,
 
1387
 *      if there were any.
1043
1388
 *
1044
1389
 *----------------------------------------------------------------------
1045
1390
 */
1046
1391
 
1047
1392
static int
1048
 
ConfigureEntry(interp, entryPtr, argc, argv, flags)
1049
 
    Tcl_Interp *interp;         /* Used for error reporting. */
1050
 
    register Entry *entryPtr;   /* Information about widget;  may or may
1051
 
                                 * not already have values for some fields. */
1052
 
    int argc;                   /* Number of valid entries in argv. */
1053
 
    char **argv;                /* Arguments. */
1054
 
    int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
 
1393
ConfigureEntry(interp, entryPtr, objc, objv, flags)
 
1394
    Tcl_Interp *interp;         /* Used for error reporting. */
 
1395
    Entry *entryPtr;            /* Information about widget; may or may not
 
1396
                                 * already have values for some fields. */
 
1397
    int objc;                   /* Number of valid entries in argv. */
 
1398
    Tcl_Obj *CONST objv[];      /* Argument objects. */
 
1399
    int flags;                  /* Flags to pass to Tk_ConfigureWidget. */
1055
1400
{
1056
 
    int oldExport;
 
1401
    Tk_SavedOptions savedOptions;
 
1402
    Tk_3DBorder border;
 
1403
    Tcl_Obj *errorResult = NULL;
 
1404
    Spinbox *sbPtr = (Spinbox *) entryPtr;      /* Only used when this widget
 
1405
                                                 * is of type TK_SPINBOX */
 
1406
    char *oldValues = NULL;             /* lint initialization */
 
1407
    char *oldFormat = NULL;             /* lint initialization */
 
1408
    int error;
 
1409
    int oldExport = 0;                  /* lint initialization */
 
1410
    int valuesChanged = 0;              /* lint initialization */
 
1411
    double oldFrom = 0.0;               /* lint initialization */
 
1412
    double oldTo = 0.0;                 /* lint initialization */
1057
1413
 
1058
1414
    /*
1059
1415
     * Eliminate any existing trace on a variable monitored by the entry.
1060
1416
     */
1061
1417
 
1062
 
    if (entryPtr->textVarName != NULL) {
1063
 
        Tcl_UntraceVar(interp, entryPtr->textVarName,
 
1418
    if ((entryPtr->textVarName != NULL)
 
1419
            && (entryPtr->flags & ENTRY_VAR_TRACED)) {
 
1420
        Lang_UntraceVar(interp, entryPtr->textVarName,
1064
1421
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1065
1422
                EntryTextVarProc, (ClientData) entryPtr);
1066
 
    }
1067
 
 
1068
 
    oldExport = entryPtr->exportSelection;
1069
 
    if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs,
1070
 
            argc, argv, (char *) entryPtr, flags) != TCL_OK) {
1071
 
        return TCL_ERROR;
1072
 
    }
1073
 
 
1074
 
    /*
1075
 
     * If the entry is tied to the value of a variable, then set up
1076
 
     * a trace on the variable's value, create the variable if it doesn't
1077
 
     * exist, and set the entry's value from the variable's value.
 
1423
        entryPtr->flags &= ~ENTRY_VAR_TRACED;
 
1424
    }
 
1425
 
 
1426
    /*
 
1427
     * Store old values that we need to effect certain behavior if
 
1428
     * they change value
 
1429
     */
 
1430
    oldExport           = entryPtr->exportSelection;
 
1431
    if (entryPtr->type == TK_SPINBOX) {
 
1432
        oldValues       = sbPtr->valueStr;
 
1433
        oldFormat       = sbPtr->reqFormat;
 
1434
        oldFrom         = sbPtr->fromValue;
 
1435
        oldTo           = sbPtr->toValue;
 
1436
    }
 
1437
 
 
1438
    for (error = 0; error <= 1; error++) {
 
1439
        if (!error) {
 
1440
            /*
 
1441
             * First pass: set options to new values.
 
1442
             */
 
1443
 
 
1444
            if (Tk_SetOptions(interp, (char *) entryPtr,
 
1445
                    entryPtr->optionTable, objc, objv,
 
1446
                    entryPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
 
1447
                continue;
 
1448
            }
 
1449
        } else {
 
1450
            /*
 
1451
             * Second pass: restore options to old values.
 
1452
             */
 
1453
 
 
1454
            errorResult = Tcl_GetObjResult(interp);
 
1455
            Tcl_IncrRefCount(errorResult);
 
1456
            Tk_RestoreSavedOptions(&savedOptions);
 
1457
        }
 
1458
 
 
1459
        /*
 
1460
         * A few other options also need special processing, such as parsing
 
1461
         * the geometry and setting the background from a 3-D border.
 
1462
         */
 
1463
 
 
1464
        if ((entryPtr->state == STATE_DISABLED) &&
 
1465
                (entryPtr->disabledBorder != NULL)) {
 
1466
            border = entryPtr->disabledBorder;
 
1467
        } else if ((entryPtr->state == STATE_READONLY) &&
 
1468
                (entryPtr->readonlyBorder != NULL)) {
 
1469
            border = entryPtr->readonlyBorder;
 
1470
        } else {
 
1471
            border = entryPtr->normalBorder;
 
1472
        }
 
1473
        Tk_SetBackgroundFromBorder(entryPtr->tkwin, border);
 
1474
 
 
1475
        if (entryPtr->insertWidth <= 0) {
 
1476
            entryPtr->insertWidth = 2;
 
1477
        }
 
1478
        if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) {
 
1479
            entryPtr->insertBorderWidth = entryPtr->insertWidth/2;
 
1480
        }
 
1481
 
 
1482
        if (entryPtr->type == TK_SPINBOX) {
 
1483
            if (sbPtr->fromValue > sbPtr->toValue) {
 
1484
                Tcl_SetResult(interp,
 
1485
                        "-to value must be greater than -from value",
 
1486
                        TCL_VOLATILE);
 
1487
                continue;
 
1488
            }
 
1489
 
 
1490
            if (sbPtr->reqFormat && (oldFormat != sbPtr->reqFormat)) {
 
1491
                /*
 
1492
                 * Make sure that the given format is somewhat correct, and
 
1493
                 * calculate the minimum space we'll need for the values as
 
1494
                 * strings.
 
1495
                 */
 
1496
                int min, max;
 
1497
                size_t formatLen, formatSpace = TCL_DOUBLE_SPACE;
 
1498
                char fbuf[4], *fmt = sbPtr->reqFormat;
 
1499
 
 
1500
                formatLen = strlen(fmt);
 
1501
                if ((fmt[0] != '%') || (fmt[formatLen-1] != 'f')) {
 
1502
                    badFormatOpt:
 
1503
                    Tcl_AppendResult(interp, "bad spinbox format specifier \"",
 
1504
                            sbPtr->reqFormat, "\"", (char *) NULL);
 
1505
                    continue;
 
1506
                }
 
1507
                if ((sscanf(fmt, "%%%d.%d%[f]", &min, &max, fbuf) == 3)
 
1508
                        && (max >= 0)) {
 
1509
                    formatSpace = min + max + 1;
 
1510
                } else if (((sscanf(fmt, "%%.%d%[f]", &min, fbuf) == 2)
 
1511
                        || (sscanf(fmt, "%%%d%[f]", &min, fbuf) == 2)
 
1512
                        || (sscanf(fmt, "%%%d.%[f]", &min, fbuf) == 2))
 
1513
                        && (min >= 0)) {
 
1514
                    formatSpace = min + 1;
 
1515
                } else {
 
1516
                    goto badFormatOpt;
 
1517
                }
 
1518
                if (formatSpace < TCL_DOUBLE_SPACE) {
 
1519
                    formatSpace = TCL_DOUBLE_SPACE;
 
1520
                }
 
1521
                sbPtr->formatBuf = ckrealloc(sbPtr->formatBuf, formatSpace);
 
1522
                /*
 
1523
                 * We perturb the value of oldFrom to allow us to go into
 
1524
                 * the branch below that will reformat the displayed value.
 
1525
                 */
 
1526
                oldFrom = sbPtr->fromValue - 1;
 
1527
            }
 
1528
 
 
1529
            /*
 
1530
             * See if we have to rearrange our listObj data
 
1531
             */
 
1532
            if (oldValues != sbPtr->valueStr) {
 
1533
                if (sbPtr->listObj != NULL) {
 
1534
                    Tcl_DecrRefCount(sbPtr->listObj);
 
1535
                }
 
1536
                sbPtr->listObj = NULL;
 
1537
                if (sbPtr->valueStr != NULL) {
 
1538
                    Tcl_Obj *newObjPtr;
 
1539
                    int nelems;
 
1540
 
 
1541
                    newObjPtr = Tcl_NewStringObj(sbPtr->valueStr, -1);
 
1542
                    if (Tcl_ListObjLength(interp, newObjPtr, &nelems)
 
1543
                            != TCL_OK) {
 
1544
                        valuesChanged = -1;
 
1545
                        continue;
 
1546
                    }
 
1547
                    sbPtr->listObj = newObjPtr;
 
1548
                    Tcl_IncrRefCount(sbPtr->listObj);
 
1549
                    sbPtr->nElements = nelems;
 
1550
                    sbPtr->eIndex = 0;
 
1551
                    valuesChanged++;
 
1552
                }
 
1553
            }
 
1554
        }
 
1555
 
 
1556
        /*
 
1557
         * Restart the cursor timing sequence in case the on-time or
 
1558
         * off-time just changed.  Set validate temporarily to none,
 
1559
         * so the configure doesn't cause it to be triggered.
 
1560
         */
 
1561
 
 
1562
        if (entryPtr->flags & GOT_FOCUS) {
 
1563
            int validate = entryPtr->validate;
 
1564
            entryPtr->validate = VALIDATE_NONE;
 
1565
            EntryFocusProc(entryPtr, 1);
 
1566
            entryPtr->validate = validate;
 
1567
        }
 
1568
 
 
1569
        /*
 
1570
         * Claim the selection if we've suddenly started exporting it.
 
1571
         */
 
1572
 
 
1573
        if (entryPtr->exportSelection && (!oldExport)
 
1574
                && (entryPtr->selectFirst != -1)
 
1575
                && !(entryPtr->flags & GOT_SELECTION)) {
 
1576
            Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
 
1577
                    (ClientData) entryPtr);
 
1578
            entryPtr->flags |= GOT_SELECTION;
 
1579
        }
 
1580
 
 
1581
        /*
 
1582
         * Recompute the window's geometry and arrange for it to be
 
1583
         * redisplayed.
 
1584
         */
 
1585
 
 
1586
        Tk_SetInternalBorder(entryPtr->tkwin,
 
1587
                entryPtr->borderWidth + entryPtr->highlightWidth);
 
1588
        if (entryPtr->highlightWidth <= 0) {
 
1589
            entryPtr->highlightWidth = 0;
 
1590
        }
 
1591
        entryPtr->inset = entryPtr->highlightWidth
 
1592
                + entryPtr->borderWidth + XPAD;
 
1593
        break;
 
1594
    }
 
1595
    if (!error) {
 
1596
        Tk_FreeSavedOptions(&savedOptions);
 
1597
    }
 
1598
 
 
1599
    /*
 
1600
     * If the entry is tied to the value of a variable, create the variable if
 
1601
     * it doesn't exist, and set the entry's value from the variable's value.
1078
1602
     */
1079
1603
 
1080
1604
    if (entryPtr->textVarName != NULL) {
1081
 
        Arg value;
 
1605
        Tcl_Obj *value;
1082
1606
 
1083
 
        value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
 
1607
        value = Tcl_ObjGetVar2(interp, entryPtr->textVarName, NULL, TCL_GLOBAL_ONLY);
1084
1608
        if (value == NULL) {
1085
 
            EntryValueChanged(entryPtr);
 
1609
            EntryValueChanged(entryPtr, NULL);
1086
1610
        } else {
1087
 
            EntrySetValue(entryPtr, LangString(value));
1088
 
        }
1089
 
        Tcl_TraceVar(interp, entryPtr->textVarName,
 
1611
            EntrySetValue(entryPtr, Tcl_GetString(value));
 
1612
        }
 
1613
    }
 
1614
 
 
1615
    if (entryPtr->type == TK_SPINBOX) {
 
1616
        ComputeFormat(sbPtr);
 
1617
 
 
1618
        if (valuesChanged > 0) {
 
1619
            Tcl_Obj *objPtr;
 
1620
 
 
1621
            /*
 
1622
             * No check for error return, because there shouldn't be one
 
1623
             * given the check for valid list above
 
1624
             */
 
1625
            Tcl_ListObjIndex(interp, sbPtr->listObj, 0, &objPtr);
 
1626
            EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
 
1627
        } else if ((sbPtr->valueStr == NULL)
 
1628
                && !DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)
 
1629
                && (!DOUBLES_EQ(sbPtr->fromValue, oldFrom)
 
1630
                        || !DOUBLES_EQ(sbPtr->toValue, oldTo))) {
 
1631
            /*
 
1632
             * If the valueStr is empty and -from && -to are specified, check
 
1633
             * to see if the current string is within the range.  If not,
 
1634
             * it will be constrained to the nearest edge.  If the current
 
1635
             * string isn't a double value, we set it to -from.
 
1636
             */
 
1637
            int code;
 
1638
            double dvalue;
 
1639
 
 
1640
            code = Tcl_GetDouble(NULL, entryPtr->string, &dvalue);
 
1641
            if (code != TCL_OK) {
 
1642
                dvalue = sbPtr->fromValue;
 
1643
            } else {
 
1644
                if (dvalue > sbPtr->toValue) {
 
1645
                    dvalue = sbPtr->toValue;
 
1646
                } else if (dvalue < sbPtr->fromValue) {
 
1647
                    dvalue = sbPtr->fromValue;
 
1648
                }
 
1649
            }
 
1650
            sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
 
1651
            EntryValueChanged(entryPtr, sbPtr->formatBuf);
 
1652
        }
 
1653
    }
 
1654
 
 
1655
    /*
 
1656
     * Set up a trace on the variable's value after we've possibly
 
1657
     * constrained the value according to new -from/-to values.
 
1658
     */
 
1659
 
 
1660
    if ((entryPtr->textVarName != NULL)
 
1661
            && !(entryPtr->flags & ENTRY_VAR_TRACED)) {
 
1662
        Lang_TraceVar(interp, entryPtr->textVarName,
1090
1663
                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1091
1664
                EntryTextVarProc, (ClientData) entryPtr);
1092
 
    }
1093
 
 
1094
 
    /*
1095
 
     * A few other options also need special processing, such as parsing
1096
 
     * the geometry and setting the background from a 3-D border.
1097
 
     */
1098
 
 
1099
 
    if (entryPtr->insertWidth <= 0) {
1100
 
        entryPtr->insertWidth = 2;
1101
 
    }
1102
 
    if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) {
1103
 
        entryPtr->insertBorderWidth = entryPtr->insertWidth/2;
1104
 
    }
1105
 
 
1106
 
    /*
1107
 
     * Restart the cursor timing sequence in case the on-time or off-time
1108
 
     * just changed.
1109
 
     */
1110
 
 
1111
 
    if (entryPtr->flags & GOT_FOCUS) {
1112
 
        EntryFocusProc(entryPtr, 1);
1113
 
    }
1114
 
 
1115
 
    /*
1116
 
     * Claim the selection if we've suddenly started exporting it.
1117
 
     */
1118
 
 
1119
 
    if (entryPtr->exportSelection && (!oldExport)
1120
 
            && (entryPtr->selectFirst != -1)
1121
 
            && !(entryPtr->flags & GOT_SELECTION)) {
1122
 
        Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
1123
 
                (ClientData) entryPtr);
1124
 
        entryPtr->flags |= GOT_SELECTION;
1125
 
    }
1126
 
 
1127
 
    /*
1128
 
     * Recompute the window's geometry and arrange for it to be
1129
 
     * redisplayed.
1130
 
     */
1131
 
 
1132
 
    Tk_SetInternalBorder(entryPtr->tkwin,
1133
 
            entryPtr->borderWidth + entryPtr->highlightWidth);
1134
 
    if (entryPtr->highlightWidth <= 0) {
1135
 
        entryPtr->highlightWidth = 0;
1136
 
    }
1137
 
    entryPtr->inset = entryPtr->highlightWidth + entryPtr->borderWidth + XPAD;
 
1665
        entryPtr->flags |= ENTRY_VAR_TRACED;
 
1666
    }
1138
1667
 
1139
1668
    EntryWorldChanged((ClientData) entryPtr);
1140
 
    return TCL_OK;
 
1669
    if (error) {
 
1670
        Tcl_SetObjResult(interp, errorResult);
 
1671
        Tcl_DecrRefCount(errorResult);
 
1672
        return TCL_ERROR;
 
1673
    } else {
 
1674
        return TCL_OK;
 
1675
    }
1141
1676
}
1142
 
 
 
1677
 
1143
1678
/*
1144
1679
 *---------------------------------------------------------------------------
1145
1680
 *
1147
1682
 *
1148
1683
 *      This procedure is called when the world has changed in some
1149
1684
 *      way and the widget needs to recompute all its graphics contexts
1150
 
 *      and determine its new geometry.
 
1685
 *      and determine its new geometry.
1151
1686
 *
1152
1687
 * Results:
1153
1688
 *      None.
1160
1695
 
1161
1696
static void
1162
1697
EntryWorldChanged(instanceData)
1163
 
    ClientData instanceData;    /* Information about widget. */
 
1698
    ClientData instanceData;    /* Information about widget. */
1164
1699
{
1165
1700
    XGCValues gcValues;
1166
1701
    GC gc = None;
1167
1702
    unsigned long mask;
1168
 
    Entry *entryPtr;
1169
 
    Pixmap pixmap;
1170
 
 
1171
 
    entryPtr = (Entry *) instanceData;
 
1703
    Tk_3DBorder border;
 
1704
    XColor *colorPtr;
 
1705
    Entry *entryPtr = (Entry *) instanceData;
1172
1706
 
1173
1707
    entryPtr->avgWidth = Tk_TextWidth(entryPtr->tkfont, "0", 1);
1174
1708
    if (entryPtr->avgWidth == 0) {
1175
1709
        entryPtr->avgWidth = 1;
1176
1710
    }
1177
1711
 
1178
 
    Tk_SetTileChangedProc(entryPtr->tile, TileChangedProc,
1179
 
            (ClientData)entryPtr, (Tk_Item *) NULL);
1180
 
    Tk_SetTileChangedProc(entryPtr->disabledTile, TileChangedProc,
1181
 
            (ClientData)entryPtr, (Tk_Item *) NULL);
1182
 
    Tk_SetTileChangedProc(entryPtr->fgTile, TileChangedProc,
1183
 
            (ClientData)entryPtr, (Tk_Item *) NULL);
1184
 
 
1185
 
    if ((pixmap = Tk_PixmapOfTile(entryPtr->tile)) != None) {
1186
 
        gcValues.fill_style = FillTiled;
1187
 
        gcValues.tile = pixmap;
1188
 
        gc = Tk_GetGC(entryPtr->tkwin, GCTile|GCFillStyle, &gcValues);
1189
 
    } else if (entryPtr->normalBorder != NULL) {
1190
 
        Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder);
1191
 
    }
1192
 
    if (entryPtr->tileGC != None) {
1193
 
        Tk_FreeGC(entryPtr->display, entryPtr->tileGC);
1194
 
    }
1195
 
    entryPtr->tileGC = gc;
1196
 
 
1197
 
    gcValues.foreground = entryPtr->fgColorPtr->pixel;
 
1712
    if (entryPtr->type == TK_SPINBOX) {
 
1713
        /*
 
1714
         * Compute the button width for a spinbox
 
1715
         */
 
1716
 
 
1717
        entryPtr->xWidth = entryPtr->avgWidth + 2 * (1+XPAD);
 
1718
        if (entryPtr->xWidth < 11) {
 
1719
            entryPtr->xWidth = 11; /* we want a min visible size */
 
1720
        }
 
1721
    }
 
1722
 
 
1723
    /*
 
1724
     * Default background and foreground are from the normal state.
 
1725
     * In a disabled state, both of those may be overridden; in the readonly
 
1726
     * state, the background may be overridden.
 
1727
     */
 
1728
 
 
1729
    border      = entryPtr->normalBorder;
 
1730
    colorPtr    = entryPtr->fgColorPtr;
 
1731
    switch (entryPtr->state) {
 
1732
        case STATE_DISABLED:
 
1733
            if (entryPtr->disabledBorder != NULL) {
 
1734
                border = entryPtr->disabledBorder;
 
1735
            }
 
1736
            if (entryPtr->dfgColorPtr != NULL) {
 
1737
                colorPtr = entryPtr->dfgColorPtr;
 
1738
            }
 
1739
            break;
 
1740
        case STATE_READONLY:
 
1741
            if (entryPtr->readonlyBorder != NULL) {
 
1742
                border = entryPtr->readonlyBorder;
 
1743
            }
 
1744
            break;
 
1745
    }
 
1746
 
 
1747
    Tk_SetBackgroundFromBorder(entryPtr->tkwin, border);
 
1748
    gcValues.foreground = colorPtr->pixel;
1198
1749
    gcValues.font = Tk_FontId(entryPtr->tkfont);
1199
1750
    gcValues.graphics_exposures = False;
1200
1751
    mask = GCForeground | GCFont | GCGraphicsExposures;
1222
1773
    entryPtr->flags |= UPDATE_SCROLLBAR;
1223
1774
    EventuallyRedraw(entryPtr);
1224
1775
}
1225
 
 
 
1776
 
1226
1777
/*
1227
1778
 *--------------------------------------------------------------
1228
1779
 *
1229
1780
 * DisplayEntry --
1230
1781
 *
1231
 
 *      This procedure redraws the contents of an entry window.
 
1782
 *      This procedure redraws the contents of an entry window.
1232
1783
 *
1233
1784
 * Results:
1234
 
 *      None.
 
1785
 *      None.
1235
1786
 *
1236
1787
 * Side effects:
1237
 
 *      Information appears on the screen.
 
1788
 *      Information appears on the screen.
1238
1789
 *
1239
1790
 *--------------------------------------------------------------
1240
1791
 */
1241
1792
 
1242
1793
static void
1243
1794
DisplayEntry(clientData)
1244
 
    ClientData clientData;      /* Information about window. */
 
1795
    ClientData clientData;      /* Information about window. */
1245
1796
{
1246
 
    register Entry *entryPtr = (Entry *) clientData;
1247
 
    register Tk_Window tkwin = entryPtr->tkwin;
1248
 
    int baseY, selStartX, selEndX, cursorX, x, w;
1249
 
    int xBound;
 
1797
    Entry *entryPtr = (Entry *) clientData;
 
1798
    Tk_Window tkwin = entryPtr->tkwin;
 
1799
    int baseY, selStartX, selEndX, cursorX;
 
1800
    int showSelection, xBound;
1250
1801
    Tk_FontMetrics fm;
1251
1802
    Pixmap pixmap;
1252
 
    int showSelection;
1253
 
    Pixmap tilepixmap;
1254
 
    Tk_Tile tile;
 
1803
    Tk_3DBorder border;
1255
1804
 
1256
1805
    entryPtr->flags &= ~REDRAW_PENDING;
1257
 
    if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
 
1806
    if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(tkwin)) {
1258
1807
        return;
1259
1808
    }
1260
1809
 
1266
1815
 
1267
1816
    if (entryPtr->flags & UPDATE_SCROLLBAR) {
1268
1817
        entryPtr->flags &= ~UPDATE_SCROLLBAR;
 
1818
 
 
1819
        /*
 
1820
         * Preserve/Release because updating the scrollbar can have
 
1821
         * the side-effect of destroying or unmapping the entry widget.
 
1822
         */
 
1823
 
 
1824
        Tcl_Preserve((ClientData) entryPtr);
1269
1825
        EntryUpdateScrollbar(entryPtr);
 
1826
 
 
1827
        if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(tkwin)) {
 
1828
            Tcl_Release((ClientData) entryPtr);
 
1829
            return;
 
1830
        }
 
1831
        Tcl_Release((ClientData) entryPtr);
1270
1832
    }
1271
1833
 
1272
1834
    /*
1284
1846
     * one, plus vertical position of baseline of text.
1285
1847
     */
1286
1848
 
1287
 
    xBound = Tk_Width(tkwin) - entryPtr->inset;
 
1849
    xBound = Tk_Width(tkwin) - entryPtr->inset - entryPtr->xWidth;
1288
1850
    baseY = (Tk_Height(tkwin) + fm.ascent - fm.descent) / 2;
1289
1851
 
1290
1852
    /*
1304
1866
     * insertion cursor background.
1305
1867
     */
1306
1868
 
1307
 
    if ((entryPtr->state == TK_STATE_DISABLED) &&
1308
 
            (entryPtr->disabledTile != NULL)) {
1309
 
        tile = entryPtr->disabledTile;
1310
 
    } else {
1311
 
        tile = entryPtr->tile;
1312
 
    }
1313
 
    if ((tilepixmap = Tk_PixmapOfTile(tile)) != None) {
1314
 
        Tk_SetTileOrigin(tkwin, entryPtr->tileGC, 0, 0);
1315
 
        XFillRectangle(entryPtr->display, pixmap, entryPtr->tileGC, 0, 0,
1316
 
                Tk_Width(tkwin), Tk_Height(tkwin));
1317
 
        XSetTSOrigin(entryPtr->display, entryPtr->tileGC, 0, 0);
1318
 
    } else {
1319
 
        Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
1320
 
                0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
1321
 
    }
1322
 
    if (showSelection && (entryPtr->selectLast > entryPtr->leftIndex)) {
 
1869
    if ((entryPtr->state == STATE_DISABLED) &&
 
1870
            (entryPtr->disabledBorder != NULL)) {
 
1871
        border = entryPtr->disabledBorder;
 
1872
    } else if ((entryPtr->state == STATE_READONLY) &&
 
1873
            (entryPtr->readonlyBorder != NULL)) {
 
1874
        border = entryPtr->readonlyBorder;
 
1875
    } else {
 
1876
        border = entryPtr->normalBorder;
 
1877
    }
 
1878
    Tk_Fill3DRectangle(tkwin, pixmap, border,
 
1879
            0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
 
1880
 
 
1881
    if (showSelection && (entryPtr->state != STATE_DISABLED)
 
1882
            && (entryPtr->selectLast > entryPtr->leftIndex)) {
1323
1883
        if (entryPtr->selectFirst <= entryPtr->leftIndex) {
1324
1884
            selStartX = entryPtr->leftX;
1325
1885
        } else {
1326
1886
            Tk_CharBbox(entryPtr->textLayout, entryPtr->selectFirst,
1327
 
                    &x, NULL, NULL, NULL);
1328
 
            selStartX = x + entryPtr->layoutX;
 
1887
                    &selStartX, NULL, NULL, NULL);
 
1888
            selStartX += entryPtr->layoutX;
1329
1889
        }
1330
1890
        if ((selStartX - entryPtr->selBorderWidth) < xBound) {
1331
 
            Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast - 1,
1332
 
                    &x, NULL, &w, NULL);
1333
 
            selEndX = x + w + entryPtr->layoutX;
 
1891
            Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast,
 
1892
                    &selEndX, NULL, NULL, NULL);
 
1893
            selEndX += entryPtr->layoutX;
1334
1894
            Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder,
1335
1895
                    selStartX - entryPtr->selBorderWidth,
1336
1896
                    baseY - fm.ascent - entryPtr->selBorderWidth,
1349
1909
     * cursor isn't on.  Otherwise the selection would hide the cursor.
1350
1910
     */
1351
1911
 
1352
 
    if ((entryPtr->insertPos >= entryPtr->leftIndex)
1353
 
            && (entryPtr->state == TK_STATE_NORMAL)
1354
 
            && (entryPtr->flags & GOT_FOCUS)) {
1355
 
        if (entryPtr->insertPos == 0) {
1356
 
            cursorX = 0;
1357
 
        } else if (entryPtr->insertPos >= entryPtr->numChars) {
1358
 
            Tk_CharBbox(entryPtr->textLayout, entryPtr->numChars - 1,
1359
 
                    &x, NULL, &w, NULL);
1360
 
            cursorX = x + w;
1361
 
        } else {
1362
 
            Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos,
1363
 
                    &x, NULL, NULL, NULL);
1364
 
            cursorX = x;
1365
 
        }
 
1912
    if ((entryPtr->state == STATE_NORMAL) && (entryPtr->flags & GOT_FOCUS)) {
 
1913
        Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &cursorX, NULL,
 
1914
                NULL, NULL);
1366
1915
        cursorX += entryPtr->layoutX;
1367
1916
        cursorX -= (entryPtr->insertWidth)/2;
1368
 
        if (cursorX < xBound) {
1369
 
            if (entryPtr->flags & CURSOR_ON) {
1370
 
                Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder,
1371
 
                        cursorX, baseY - fm.ascent,
1372
 
                        entryPtr->insertWidth, fm.ascent + fm.descent,
1373
 
                        entryPtr->insertBorderWidth, TK_RELIEF_RAISED);
1374
 
            } else if (entryPtr->insertBorder == entryPtr->selBorder) {
1375
 
                Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
1376
 
                        cursorX, baseY - fm.ascent,
1377
 
                        entryPtr->insertWidth, fm.ascent + fm.descent,
1378
 
                        0, TK_RELIEF_FLAT);
 
1917
        Tk_SetCaretPos(entryPtr->tkwin, cursorX, baseY - fm.ascent,
 
1918
                fm.ascent + fm.descent);
 
1919
        if (entryPtr->insertPos >= entryPtr->leftIndex) {
 
1920
            if (cursorX < xBound) {
 
1921
                if (entryPtr->flags & CURSOR_ON) {
 
1922
                    Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder,
 
1923
                            cursorX, baseY - fm.ascent, entryPtr->insertWidth,
 
1924
                            fm.ascent + fm.descent,
 
1925
                            entryPtr->insertBorderWidth,
 
1926
                            TK_RELIEF_RAISED);
 
1927
                } else if (entryPtr->insertBorder == entryPtr->selBorder) {
 
1928
                    Tk_Fill3DRectangle(tkwin, pixmap, border,
 
1929
                            cursorX, baseY - fm.ascent, entryPtr->insertWidth,
 
1930
                            fm.ascent + fm.descent, 0, TK_RELIEF_FLAT);
 
1931
                }
1379
1932
            }
1380
1933
        }
1381
1934
    }
1389
1942
            entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY,
1390
1943
            entryPtr->leftIndex, entryPtr->numChars);
1391
1944
 
1392
 
    if (showSelection && (entryPtr->selTextGC != entryPtr->textGC) &&
1393
 
            (entryPtr->selectFirst < entryPtr->selectLast)) {
1394
 
        int first;
 
1945
    if (showSelection && (entryPtr->state != STATE_DISABLED)
 
1946
            && (entryPtr->selTextGC != entryPtr->textGC)
 
1947
            && (entryPtr->selectFirst < entryPtr->selectLast)) {
 
1948
        int selFirst;
1395
1949
 
1396
 
        if (entryPtr->selectFirst - entryPtr->leftIndex < 0) {
1397
 
            first = entryPtr->leftIndex;
 
1950
        if (entryPtr->selectFirst < entryPtr->leftIndex) {
 
1951
            selFirst = entryPtr->leftIndex;
1398
1952
        } else {
1399
 
            first = entryPtr->selectFirst;
 
1953
            selFirst = entryPtr->selectFirst;
1400
1954
        }
1401
1955
        Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC,
1402
1956
                entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY,
1403
 
                first, entryPtr->selectLast);
 
1957
                selFirst, entryPtr->selectLast);
 
1958
    }
 
1959
 
 
1960
    if (entryPtr->type == TK_SPINBOX) {
 
1961
        int startx, height, inset, pad, tHeight, xWidth;
 
1962
        Spinbox *sbPtr = (Spinbox *) entryPtr;
 
1963
 
 
1964
        /*
 
1965
         * Draw the spin button controls.
 
1966
         */
 
1967
        xWidth = entryPtr->xWidth;
 
1968
        pad    = XPAD + 1;
 
1969
        inset  = entryPtr->inset - XPAD;
 
1970
        startx = Tk_Width(tkwin) - (xWidth + inset);
 
1971
        height = (Tk_Height(tkwin) - 2*inset)/2;
 
1972
#if 0
 
1973
        Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
 
1974
                startx, inset, xWidth, height, 1, sbPtr->buRelief);
 
1975
        Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
 
1976
                startx, inset+height, xWidth, height, 1, sbPtr->bdRelief);
 
1977
#else
 
1978
        Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
 
1979
                startx, inset, xWidth, height, 1,
 
1980
                (sbPtr->selElement == SEL_BUTTONUP) ?
 
1981
                TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
 
1982
        Tk_Fill3DRectangle(tkwin, pixmap, sbPtr->buttonBorder,
 
1983
                startx, inset+height, xWidth, height, 1,
 
1984
                (sbPtr->selElement == SEL_BUTTONDOWN) ?
 
1985
                TK_RELIEF_SUNKEN : TK_RELIEF_RAISED);
 
1986
#endif
 
1987
 
 
1988
        xWidth -= 2*pad;
 
1989
        /*
 
1990
         * Only draw the triangles if we have enough display space
 
1991
         */
 
1992
        if ((xWidth > 1)) {
 
1993
            XPoint points[3];
 
1994
            int starty, space, offset;
 
1995
 
 
1996
            space = height - 2*pad;
 
1997
            /*
 
1998
             * Ensure width of triangle is odd to guarantee a sharp tip
 
1999
             */
 
2000
            if (!(xWidth % 2)) {
 
2001
                xWidth++;
 
2002
            }
 
2003
            tHeight = (xWidth + 1) / 2;
 
2004
            if (tHeight > space) {
 
2005
                tHeight = space;
 
2006
            }
 
2007
            space   = (space - tHeight) / 2;
 
2008
            startx += pad;
 
2009
            starty  = inset + height - pad - space;
 
2010
            offset  = (sbPtr->selElement == SEL_BUTTONUP);
 
2011
            /*
 
2012
             * The points are slightly different for the up and down arrows
 
2013
             * because (for *.x), we need to account for a bug in the way
 
2014
             * XFillPolygon draws triangles, and we want to shift
 
2015
             * the arrows differently when allowing for depressed behavior.
 
2016
             */
 
2017
            points[0].x = startx + offset;
 
2018
            points[0].y = starty + (offset ? 0 : -1);
 
2019
            points[1].x = startx + xWidth/2 + offset;
 
2020
            points[1].y = starty - tHeight + (offset ? 0 : -1);
 
2021
            points[2].x = startx + xWidth + offset;
 
2022
            points[2].y = points[0].y;
 
2023
            XFillPolygon(entryPtr->display, pixmap, entryPtr->textGC,
 
2024
                    points, 3, Convex, CoordModeOrigin);
 
2025
 
 
2026
            starty = inset + height + pad + space;
 
2027
            offset = (sbPtr->selElement == SEL_BUTTONDOWN);
 
2028
            points[0].x = startx + 1 + offset;
 
2029
            points[0].y = starty + (offset ? 1 : 0);
 
2030
            points[1].x = startx + xWidth/2 + offset;
 
2031
            points[1].y = starty + tHeight + (offset ? 0 : -1);
 
2032
            points[2].x = startx - 1 + xWidth + offset;
 
2033
            points[2].y = points[0].y;
 
2034
            XFillPolygon(entryPtr->display, pixmap, entryPtr->textGC,
 
2035
                    points, 3, Convex, CoordModeOrigin);
 
2036
        }
1404
2037
    }
1405
2038
 
1406
2039
    /*
1408
2041
     * any text that extends past the viewable part of the window.
1409
2042
     */
1410
2043
 
 
2044
    xBound = entryPtr->highlightWidth;
1411
2045
    if (entryPtr->relief != TK_RELIEF_FLAT) {
1412
 
        Tk_Draw3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
1413
 
                entryPtr->highlightWidth, entryPtr->highlightWidth,
1414
 
                Tk_Width(tkwin) - 2*entryPtr->highlightWidth,
1415
 
                Tk_Height(tkwin) - 2*entryPtr->highlightWidth,
 
2046
        Tk_Draw3DRectangle(tkwin, pixmap, border, xBound, xBound,
 
2047
                Tk_Width(tkwin) - 2 * xBound,
 
2048
                Tk_Height(tkwin) - 2 * xBound,
1416
2049
                entryPtr->borderWidth, entryPtr->relief);
1417
2050
    }
1418
 
    if (entryPtr->highlightWidth != 0) {
1419
 
        GC gc;
 
2051
    if (xBound > 0) {
 
2052
        GC fgGC, bgGC;
1420
2053
 
 
2054
        bgGC = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap);
1421
2055
        if (entryPtr->flags & GOT_FOCUS) {
1422
 
            gc = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap);
 
2056
            fgGC = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap);
 
2057
            TkpDrawHighlightBorder(tkwin, fgGC, bgGC, xBound, pixmap);
1423
2058
        } else {
1424
 
            gc = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap);
 
2059
            TkpDrawHighlightBorder(tkwin, bgGC, bgGC, xBound, pixmap);
1425
2060
        }
1426
 
        Tk_DrawFocusHighlight(tkwin, gc, entryPtr->highlightWidth, pixmap);
1427
2061
    }
1428
2062
 
1429
2063
    /*
1437
2071
    Tk_FreePixmap(entryPtr->display, pixmap);
1438
2072
    entryPtr->flags &= ~BORDER_NEEDED;
1439
2073
}
1440
 
 
 
2074
 
1441
2075
/*
1442
2076
 *----------------------------------------------------------------------
1443
2077
 *
1444
2078
 * EntryComputeGeometry --
1445
2079
 *
1446
 
 *      This procedure is invoked to recompute information about where
1447
 
 *      in its window an entry's string will be displayed.  It also
1448
 
 *      computes the requested size for the window.
 
2080
 *      This procedure is invoked to recompute information about where
 
2081
 *      in its window an entry's string will be displayed.  It also
 
2082
 *      computes the requested size for the window.
1449
2083
 *
1450
2084
 * Results:
1451
 
 *      None.
 
2085
 *      None.
1452
2086
 *
1453
2087
 * Side effects:
1454
 
 *      The leftX and tabOrigin fields are recomputed for entryPtr,
1455
 
 *      and leftIndex may be adjusted.  Tk_GeometryRequest is called
1456
 
 *      to register the desired dimensions for the window.
 
2088
 *      The leftX and tabOrigin fields are recomputed for entryPtr,
 
2089
 *      and leftIndex may be adjusted.  Tk_GeometryRequest is called
 
2090
 *      to register the desired dimensions for the window.
1457
2091
 *
1458
2092
 *----------------------------------------------------------------------
1459
2093
 */
1460
2094
 
1461
2095
static void
1462
2096
EntryComputeGeometry(entryPtr)
1463
 
    Entry *entryPtr;                    /* Widget record for entry. */
 
2097
    Entry *entryPtr;            /* Widget record for entry. */
1464
2098
{
1465
2099
    int totalLength, overflow, maxOffScreen, rightX;
1466
2100
    int height, width, i;
1467
2101
    Tk_FontMetrics fm;
1468
 
    char *p, *displayString;
 
2102
    char *p;
 
2103
 
 
2104
    if (entryPtr->displayString != entryPtr->string) {
 
2105
        ckfree((char *)entryPtr->displayString);
 
2106
        entryPtr->displayString = entryPtr->string;
 
2107
        entryPtr->numDisplayBytes = entryPtr->numBytes;
 
2108
    }
1469
2109
 
1470
2110
    /*
1471
2111
     * If we're displaying a special character instead of the value of
1472
2112
     * the entry, recompute the displayString.
1473
2113
     */
1474
2114
 
1475
 
    if (entryPtr->displayString != NULL) {
1476
 
        ckfree(entryPtr->displayString);
1477
 
        entryPtr->displayString = NULL;
1478
 
    }
1479
2115
    if (entryPtr->showChar != NULL) {
1480
 
        entryPtr->displayString = (char *) ckalloc((unsigned)
1481
 
                (entryPtr->numChars + 1));
1482
 
        for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0;
1483
 
                i--, p++) {
1484
 
            *p = entryPtr->showChar[0];
 
2116
        Tcl_UniChar ch;
 
2117
        char buf[TCL_UTF_MAX];
 
2118
        int size;
 
2119
 
 
2120
        /*
 
2121
         * Normalize the special character so we can safely duplicate it
 
2122
         * in the display string.  If we didn't do this, then two malformed
 
2123
         * characters might end up looking like one valid UTF character in
 
2124
         * the resulting string.
 
2125
         */
 
2126
 
 
2127
        Tcl_UtfToUniChar(entryPtr->showChar, &ch);
 
2128
        size = Tcl_UniCharToUtf(ch, buf);
 
2129
 
 
2130
        entryPtr->numDisplayBytes = entryPtr->numChars * size;
 
2131
        p = (char *) ckalloc((unsigned) (entryPtr->numDisplayBytes + 1));
 
2132
        entryPtr->displayString = p;
 
2133
 
 
2134
        for (i = entryPtr->numChars; --i >= 0; ) {
 
2135
            p += Tcl_UniCharToUtf(ch, p);
1485
2136
        }
1486
 
        *p = 0;
1487
 
        displayString = entryPtr->displayString;
1488
 
    } else {
1489
 
        displayString = entryPtr->string;
 
2137
        *p = '\0';
1490
2138
    }
 
2139
 
1491
2140
    Tk_FreeTextLayout(entryPtr->textLayout);
1492
2141
    entryPtr->textLayout = Tk_ComputeTextLayout(entryPtr->tkfont,
1493
 
            displayString, entryPtr->numChars, 0, entryPtr->justify,
1494
 
            TK_IGNORE_NEWLINES, &totalLength, &height);
 
2142
            entryPtr->displayString, entryPtr->numChars, 0,
 
2143
            entryPtr->justify, TK_IGNORE_NEWLINES, &totalLength, &height);
1495
2144
 
1496
2145
    entryPtr->layoutY = (Tk_Height(entryPtr->tkwin) - height) / 2;
1497
2146
 
1502
2151
     * window unless the entire window is full.
1503
2152
     */
1504
2153
 
1505
 
    overflow = totalLength - (Tk_Width(entryPtr->tkwin) - 2*entryPtr->inset);
 
2154
    overflow = totalLength -
 
2155
        (Tk_Width(entryPtr->tkwin) - 2*entryPtr->inset - entryPtr->xWidth);
1506
2156
    if (overflow <= 0) {
1507
2157
        entryPtr->leftIndex = 0;
1508
2158
        if (entryPtr->justify == TK_JUSTIFY_LEFT) {
1509
2159
            entryPtr->leftX = entryPtr->inset;
1510
2160
        } else if (entryPtr->justify == TK_JUSTIFY_RIGHT) {
1511
2161
            entryPtr->leftX = Tk_Width(entryPtr->tkwin) - entryPtr->inset
1512
 
                    - totalLength;
 
2162
                - entryPtr->xWidth - totalLength;
1513
2163
        } else {
1514
 
            entryPtr->leftX = (Tk_Width(entryPtr->tkwin) - totalLength)/2;
 
2164
            entryPtr->leftX = (Tk_Width(entryPtr->tkwin)
 
2165
                    - entryPtr->xWidth - totalLength)/2;
1515
2166
        }
1516
2167
        entryPtr->layoutX = entryPtr->leftX;
1517
2168
    } else {
1526
2177
        Tk_CharBbox(entryPtr->textLayout, maxOffScreen,
1527
2178
                &rightX, NULL, NULL, NULL);
1528
2179
        if (rightX < overflow) {
1529
 
            maxOffScreen += 1;
 
2180
            maxOffScreen++;
1530
2181
        }
1531
2182
        if (entryPtr->leftIndex > maxOffScreen) {
1532
2183
            entryPtr->leftIndex = maxOffScreen;
1533
2184
        }
1534
 
        Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex,
1535
 
                &rightX, NULL, NULL, NULL);
 
2185
        Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex, &rightX,
 
2186
                NULL, NULL, NULL);
1536
2187
        entryPtr->leftX = entryPtr->inset;
1537
2188
        entryPtr->layoutX = entryPtr->leftX - rightX;
1538
2189
    }
1548
2199
            width = totalLength + 2*entryPtr->inset;
1549
2200
        }
1550
2201
    }
 
2202
 
 
2203
    /*
 
2204
     * Add one extra length for the spin buttons
 
2205
     */
 
2206
    width += entryPtr->xWidth;
 
2207
 
1551
2208
    Tk_GeometryRequest(entryPtr->tkwin, width, height);
1552
2209
}
1553
 
 
 
2210
 
1554
2211
/*
1555
2212
 *----------------------------------------------------------------------
1556
2213
 *
1557
2214
 * InsertChars --
1558
2215
 *
1559
 
 *      Add new characters to an entry widget.
 
2216
 *      Add new characters to an entry widget.
1560
2217
 *
1561
2218
 * Results:
1562
 
 *      None.
 
2219
 *      None.
1563
2220
 *
1564
2221
 * Side effects:
1565
 
 *      New information gets added to entryPtr;  it will be redisplayed
1566
 
 *      soon, but not necessarily immediately.
 
2222
 *      New information gets added to entryPtr;  it will be redisplayed
 
2223
 *      soon, but not necessarily immediately.
1567
2224
 *
1568
2225
 *----------------------------------------------------------------------
1569
2226
 */
1570
2227
 
1571
2228
static void
1572
 
InsertChars(entryPtr, index, string)
1573
 
    register Entry *entryPtr;   /* Entry that is to get the new
1574
 
                                 * elements. */
1575
 
    int index;                  /* Add the new elements before this
1576
 
                                 * element. */
1577
 
    char *string;               /* New characters to add (NULL-terminated
 
2229
InsertChars(entryPtr, index, value)
 
2230
    Entry *entryPtr;            /* Entry that is to get the new elements. */
 
2231
    int index;                  /* Add the new elements before this
 
2232
                                 * character index. */
 
2233
    char *value;                /* New characters to add (NULL-terminated
1578
2234
                                 * string). */
1579
2235
{
1580
 
    int length;
 
2236
    int byteIndex, byteCount, oldChars, charsAdded, newByteCount;
 
2237
    CONST char *string;
1581
2238
    char *new;
1582
2239
 
1583
 
    length = strlen(string);
1584
 
    if (length == 0) {
 
2240
    string = entryPtr->string;
 
2241
    byteIndex = Tcl_UtfAtIndex(string, index) - string;
 
2242
    byteCount = strlen(value);
 
2243
    if (byteCount == 0) {
1585
2244
        return;
1586
2245
    }
1587
 
    new = (char *) ckalloc((unsigned) (entryPtr->numChars + length + 1));
1588
 
    strncpy(new, entryPtr->string, (size_t) index);
1589
 
    strcpy(new+index, string);
1590
 
    strcpy(new+index+length, entryPtr->string+index);
1591
 
#ifdef ENTRY_VALIDATE
 
2246
 
 
2247
    newByteCount = entryPtr->numBytes + byteCount + 1;
 
2248
    new = (char *) ckalloc((unsigned) newByteCount);
 
2249
    memcpy(new, string, (size_t) byteIndex);
 
2250
    strcpy(new + byteIndex, value);
 
2251
    strcpy(new + byteIndex + byteCount, string + byteIndex);
 
2252
 
1592
2253
    if ((entryPtr->validate == VALIDATE_KEY ||
1593
2254
         entryPtr->validate == VALIDATE_ALL) &&
1594
 
        EntryValidateChange(entryPtr, string, new, index, 1) != TCL_OK) {
 
2255
        EntryValidateChange(entryPtr, value, new, index,
 
2256
                            VALIDATE_INSERT) != TCL_OK) {
1595
2257
        ckfree(new);
1596
2258
        return;
1597
2259
    }
1598
 
#endif /* ENTRY_VALIDATE */
1599
 
    ckfree(entryPtr->string);
 
2260
 
 
2261
    ckfree((char *)string);
1600
2262
    entryPtr->string = new;
1601
 
    entryPtr->numChars += length;
 
2263
 
 
2264
    /*
 
2265
     * The following construction is used because inserting improperly
 
2266
     * formed UTF-8 sequences between other improperly formed UTF-8
 
2267
     * sequences could result in actually forming valid UTF-8 sequences;
 
2268
     * the number of characters added may not be Tcl_NumUtfChars(string, -1),
 
2269
     * because of context.  The actual number of characters added is how
 
2270
     * many characters are in the string now minus the number that
 
2271
     * used to be there.
 
2272
     */
 
2273
 
 
2274
    oldChars = entryPtr->numChars;
 
2275
    entryPtr->numChars = Tcl_NumUtfChars(new, -1);
 
2276
    charsAdded = entryPtr->numChars - oldChars;
 
2277
    entryPtr->numBytes += byteCount;
 
2278
 
 
2279
    if (entryPtr->displayString == string) {
 
2280
        entryPtr->displayString = new;
 
2281
        entryPtr->numDisplayBytes = entryPtr->numBytes;
 
2282
    }
1602
2283
 
1603
2284
    /*
1604
2285
     * Inserting characters invalidates all indexes into the string.
1609
2290
     */
1610
2291
 
1611
2292
    if (entryPtr->selectFirst >= index) {
1612
 
        entryPtr->selectFirst += length;
 
2293
        entryPtr->selectFirst += charsAdded;
1613
2294
    }
1614
2295
    if (entryPtr->selectLast > index) {
1615
 
        entryPtr->selectLast += length;
 
2296
        entryPtr->selectLast += charsAdded;
1616
2297
    }
1617
 
    if ((entryPtr->selectAnchor > index) || (entryPtr->selectFirst >= index)) {
1618
 
        entryPtr->selectAnchor += length;
 
2298
    if ((entryPtr->selectAnchor > index)
 
2299
            || (entryPtr->selectFirst >= index)) {
 
2300
        entryPtr->selectAnchor += charsAdded;
1619
2301
    }
1620
2302
    if (entryPtr->leftIndex > index) {
1621
 
        entryPtr->leftIndex += length;
 
2303
        entryPtr->leftIndex += charsAdded;
1622
2304
    }
1623
2305
    if (entryPtr->insertPos >= index) {
1624
 
        entryPtr->insertPos += length;
 
2306
        entryPtr->insertPos += charsAdded;
1625
2307
    }
1626
 
    EntryValueChanged(entryPtr);
 
2308
    EntryValueChanged(entryPtr, NULL);
1627
2309
}
1628
 
 
 
2310
 
1629
2311
/*
1630
2312
 *----------------------------------------------------------------------
1631
2313
 *
1632
2314
 * DeleteChars --
1633
2315
 *
1634
 
 *      Remove one or more characters from an entry widget.
 
2316
 *      Remove one or more characters from an entry widget.
1635
2317
 *
1636
2318
 * Results:
1637
 
 *      None.
 
2319
 *      None.
1638
2320
 *
1639
2321
 * Side effects:
1640
 
 *      Memory gets freed, the entry gets modified and (eventually)
1641
 
 *      redisplayed.
 
2322
 *      Memory gets freed, the entry gets modified and (eventually)
 
2323
 *      redisplayed.
1642
2324
 *
1643
2325
 *----------------------------------------------------------------------
1644
2326
 */
1645
2327
 
1646
2328
static void
1647
2329
DeleteChars(entryPtr, index, count)
1648
 
    register Entry *entryPtr;   /* Entry widget to modify. */
1649
 
    int index;                  /* Index of first character to delete. */
1650
 
    int count;                  /* How many characters to delete. */
 
2330
    Entry *entryPtr;            /* Entry widget to modify. */
 
2331
    int index;                  /* Index of first character to delete. */
 
2332
    int count;                  /* How many characters to delete. */
1651
2333
{
1652
 
    char *new;
1653
 
#ifdef ENTRY_VALIDATE
1654
 
    char *string;
1655
 
#endif /* ENTRY_VALIDATE */
 
2334
    int byteIndex, byteCount, newByteCount;
 
2335
    CONST char *string;
 
2336
    char *new, *todelete;
1656
2337
 
1657
2338
    if ((index + count) > entryPtr->numChars) {
1658
2339
        count = entryPtr->numChars - index;
1661
2342
        return;
1662
2343
    }
1663
2344
 
1664
 
    new = (char *) ckalloc((unsigned) (entryPtr->numChars + 1 - count));
1665
 
    strncpy(new, entryPtr->string, (size_t) index);
1666
 
    strcpy(new+index, entryPtr->string+index+count);
1667
 
#ifdef ENTRY_VALIDATE
1668
 
    string = (char *) ckalloc((unsigned) (1 + count));
1669
 
    strncpy(string, entryPtr->string+index, (size_t) count);
1670
 
    string[count] = '\0';
 
2345
    string = entryPtr->string;
 
2346
    byteIndex = Tcl_UtfAtIndex(string, index) - string;
 
2347
    byteCount = Tcl_UtfAtIndex(string + byteIndex, count) - (string + byteIndex);
 
2348
 
 
2349
    newByteCount = entryPtr->numBytes + 1 - byteCount;
 
2350
    new = (char *) ckalloc((unsigned) newByteCount);
 
2351
    memcpy(new, string, (size_t) byteIndex);
 
2352
    strcpy(new + byteIndex, string + byteIndex + byteCount);
 
2353
 
 
2354
    todelete = (char *) ckalloc((unsigned) (byteCount + 1));
 
2355
    memcpy(todelete, string + byteIndex, (size_t) byteCount);
 
2356
    todelete[byteCount] = '\0';
1671
2357
 
1672
2358
    if ((entryPtr->validate == VALIDATE_KEY ||
1673
2359
         entryPtr->validate == VALIDATE_ALL) &&
1674
 
        EntryValidateChange(entryPtr, string, new, index, 0) != TCL_OK) {
 
2360
        EntryValidateChange(entryPtr, todelete, new, index,
 
2361
                            VALIDATE_DELETE) != TCL_OK) {
1675
2362
        ckfree(new);
1676
 
        ckfree(string);
 
2363
        ckfree(todelete);
1677
2364
        return;
1678
2365
    }
1679
2366
 
1680
 
    ckfree(string);
1681
 
#endif /* ENTRY_VALIDATE */
1682
 
    ckfree(entryPtr->string);
 
2367
    ckfree(todelete);
 
2368
    ckfree((char *)entryPtr->string);
1683
2369
    entryPtr->string = new;
1684
2370
    entryPtr->numChars -= count;
 
2371
    entryPtr->numBytes -= byteCount;
 
2372
 
 
2373
    if (entryPtr->displayString == string) {
 
2374
        entryPtr->displayString = new;
 
2375
        entryPtr->numDisplayBytes = entryPtr->numBytes;
 
2376
    }
1685
2377
 
1686
2378
    /*
1687
2379
     * Deleting characters results in the remaining characters being
1690
2382
     */
1691
2383
 
1692
2384
    if (entryPtr->selectFirst >= index) {
1693
 
        if (entryPtr->selectFirst >= (index+count)) {
 
2385
        if (entryPtr->selectFirst >= (index + count)) {
1694
2386
            entryPtr->selectFirst -= count;
1695
2387
        } else {
1696
2388
            entryPtr->selectFirst = index;
1697
2389
        }
1698
2390
    }
1699
2391
    if (entryPtr->selectLast >= index) {
1700
 
        if (entryPtr->selectLast >= (index+count)) {
 
2392
        if (entryPtr->selectLast >= (index + count)) {
1701
2393
            entryPtr->selectLast -= count;
1702
2394
        } else {
1703
2395
            entryPtr->selectLast = index;
1704
2396
        }
1705
2397
    }
1706
2398
    if (entryPtr->selectLast <= entryPtr->selectFirst) {
1707
 
        entryPtr->selectFirst = entryPtr->selectLast = -1;
 
2399
        entryPtr->selectFirst = -1;
 
2400
        entryPtr->selectLast = -1;
1708
2401
    }
1709
2402
    if (entryPtr->selectAnchor >= index) {
1710
2403
        if (entryPtr->selectAnchor >= (index+count)) {
1714
2407
        }
1715
2408
    }
1716
2409
    if (entryPtr->leftIndex > index) {
1717
 
        if (entryPtr->leftIndex >= (index+count)) {
 
2410
        if (entryPtr->leftIndex >= (index + count)) {
1718
2411
            entryPtr->leftIndex -= count;
1719
2412
        } else {
1720
2413
            entryPtr->leftIndex = index;
1721
2414
        }
1722
2415
    }
1723
2416
    if (entryPtr->insertPos >= index) {
1724
 
        if (entryPtr->insertPos >= (index+count)) {
 
2417
        if (entryPtr->insertPos >= (index + count)) {
1725
2418
            entryPtr->insertPos -= count;
1726
2419
        } else {
1727
2420
            entryPtr->insertPos = index;
1728
2421
        }
1729
2422
    }
1730
 
    EntryValueChanged(entryPtr);
 
2423
    EntryValueChanged(entryPtr, NULL);
1731
2424
}
1732
 
 
 
2425
 
1733
2426
/*
1734
2427
 *----------------------------------------------------------------------
1735
2428
 *
1736
2429
 * EntryValueChanged --
1737
2430
 *
1738
 
 *      This procedure is invoked when characters are inserted into
1739
 
 *      an entry or deleted from it.  It updates the entry's associated
1740
 
 *      variable, if there is one, and does other bookkeeping such
1741
 
 *      as arranging for redisplay.
 
2431
 *      This procedure is invoked when characters are inserted into
 
2432
 *      an entry or deleted from it.  It updates the entry's associated
 
2433
 *      variable, if there is one, and does other bookkeeping such
 
2434
 *      as arranging for redisplay.
1742
2435
 *
1743
2436
 * Results:
1744
 
 *      None.
 
2437
 *      None.
1745
2438
 *
1746
2439
 * Side effects:
1747
 
 *      None.
 
2440
 *      None.
1748
2441
 *
1749
2442
 *----------------------------------------------------------------------
1750
2443
 */
1751
2444
 
1752
2445
static void
1753
 
EntryValueChanged(entryPtr)
1754
 
    Entry *entryPtr;            /* Entry whose value just changed. */
 
2446
EntryValueChanged(entryPtr, newValue)
 
2447
    Entry *entryPtr;            /* Entry whose value just changed. */
 
2448
    CONST char *newValue;       /* If this value is not NULL, we first
 
2449
                                 * force the value of the entry to this */
1755
2450
{
1756
 
    char *newValue;
 
2451
    if (newValue != NULL) {
 
2452
        EntrySetValue(entryPtr, newValue);
 
2453
    }
1757
2454
 
1758
2455
    if (entryPtr->textVarName == NULL) {
1759
2456
        newValue = NULL;
1760
2457
    } else {
1761
 
        newValue = Tcl_SetVar(entryPtr->interp, entryPtr->textVarName,
1762
 
                entryPtr->string, TCL_GLOBAL_ONLY);
 
2458
        Tcl_Obj *temp = Tcl_NewStringObj(entryPtr->string,-1);
 
2459
        newValue = Tcl_GetString(Tcl_ObjSetVar2(entryPtr->interp, entryPtr->textVarName, NULL,
 
2460
                temp, TCL_GLOBAL_ONLY));
 
2461
        Tcl_DecrRefCount(temp);
1763
2462
    }
1764
2463
 
1765
2464
    if ((newValue != NULL) && (strcmp(newValue, entryPtr->string) != 0)) {
1782
2481
        EventuallyRedraw(entryPtr);
1783
2482
    }
1784
2483
}
1785
 
 
 
2484
 
1786
2485
/*
1787
2486
 *----------------------------------------------------------------------
1788
2487
 *
1789
2488
 * EntrySetValue --
1790
2489
 *
1791
 
 *      Replace the contents of a text entry with a given value.  This
1792
 
 *      procedure is invoked when updating the entry from the entry's
1793
 
 *      associated variable.
 
2490
 *      Replace the contents of a text entry with a given value.  This
 
2491
 *      procedure is invoked when updating the entry from the entry's
 
2492
 *      associated variable.
1794
2493
 *
1795
2494
 * Results:
1796
 
 *      None.
 
2495
 *      None.
1797
2496
 *
1798
2497
 * Side effects:
1799
 
 *      The string displayed in the entry will change.  The selection,
1800
 
 *      insertion point, and view may have to be adjusted to keep them
1801
 
 *      within the bounds of the new string.  Note: this procedure does
1802
 
 *      *not* update the entry's associated variable, since that could
1803
 
 *      result in an infinite loop.
 
2498
 *      The string displayed in the entry will change.  The selection,
 
2499
 *      insertion point, and view may have to be adjusted to keep them
 
2500
 *      within the bounds of the new string.  Note: this procedure does
 
2501
 *      *not* update the entry's associated variable, since that could
 
2502
 *      result in an infinite loop.
1804
2503
 *
1805
2504
 *----------------------------------------------------------------------
1806
2505
 */
1807
2506
 
1808
2507
static void
1809
2508
EntrySetValue(entryPtr, value)
1810
 
    register Entry *entryPtr;           /* Entry whose value is to be
1811
 
                                         * changed. */
1812
 
    char *value;                        /* New text to display in entry. */
 
2509
    Entry *entryPtr;            /* Entry whose value is to be changed. */
 
2510
    CONST char *value;          /* New text to display in entry. */
1813
2511
{
1814
 
#ifdef ENTRY_VALIDATE
1815
 
    int code;
 
2512
    CONST char *oldSource;
 
2513
    int valueLen, malloced = 0;
1816
2514
 
1817
2515
    if (strcmp(value, entryPtr->string) == 0) {
1818
2516
        return;
1819
2517
    }
 
2518
    valueLen = strlen(value);
1820
2519
 
1821
2520
    if (entryPtr->flags & VALIDATE_VAR) {
1822
2521
        /* Recursing : assume we are in fixup code and it knows
1823
2522
           what it is doing
1824
2523
        */
1825
2524
    } else {
 
2525
        /*
 
2526
         * If we validate, we create a copy of the value, as it may
 
2527
         * point to volatile memory, like the value of the -textvar
 
2528
         * which may get freed during validation
 
2529
         */
 
2530
        char *tmp = (char *) ckalloc((unsigned) (valueLen + 1));
 
2531
        strcpy(tmp, value);
 
2532
        value = tmp;
 
2533
        malloced = 1;
 
2534
 
1826
2535
        entryPtr->flags |= VALIDATE_VAR;
1827
 
        code = EntryValidateChange(entryPtr, (char *) NULL, value, -1, -1);
1828
 
        if (code != TCL_OK || (entryPtr->flags & VALIDATE_ABORT)) {
1829
 
            /*
1830
 
             * If VALIDATE_ABORT has been set, then this operation should be
1831
 
             * aborted because the validatecommand did something else instead
1832
 
             * Set variable to what that 'something' was.
1833
 
             */
1834
 
            EntryValueChanged(entryPtr);
 
2536
        (void) EntryValidateChange(entryPtr, (char *) NULL, value, -1,
 
2537
                VALIDATE_FORCED);
 
2538
        entryPtr->flags &= ~VALIDATE_VAR;
 
2539
        /*
 
2540
         * If VALIDATE_ABORT has been set, then this operation should be
 
2541
         * aborted because the validatecommand did something else instead
 
2542
         */
 
2543
        if (entryPtr->flags & VALIDATE_ABORT) {
1835
2544
            entryPtr->flags &= ~VALIDATE_ABORT;
1836
 
            entryPtr->flags &= ~VALIDATE_VAR;
 
2545
            ckfree((char *)value);
1837
2546
            return;
1838
2547
        }
1839
2548
        entryPtr->flags &= ~VALIDATE_VAR;
1840
2549
    }
1841
 
#endif /* ENTRY_VALIDATE */
1842
 
 
1843
 
    ckfree(entryPtr->string);
1844
 
    entryPtr->numChars = strlen(value);
1845
 
    entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numChars + 1));
1846
 
    strcpy(entryPtr->string, value);
1847
 
    if (entryPtr->selectFirst != -1) {
 
2550
 
 
2551
    oldSource = entryPtr->string;
 
2552
    ckfree((char *)entryPtr->string);
 
2553
 
 
2554
    if (malloced) {
 
2555
        entryPtr->string = value;
 
2556
    } else {
 
2557
        char *tmp = (char *) ckalloc((unsigned) (valueLen + 1));
 
2558
        strcpy(tmp, value);
 
2559
        entryPtr->string = tmp;
 
2560
    }
 
2561
    entryPtr->numBytes = valueLen;
 
2562
    entryPtr->numChars = Tcl_NumUtfChars(value, valueLen);
 
2563
 
 
2564
    if (entryPtr->displayString == oldSource) {
 
2565
        entryPtr->displayString = entryPtr->string;
 
2566
        entryPtr->numDisplayBytes = entryPtr->numBytes;
 
2567
    }
 
2568
 
 
2569
    if (entryPtr->selectFirst >= 0) {
1848
2570
        if (entryPtr->selectFirst >= entryPtr->numChars) {
1849
 
            entryPtr->selectFirst = entryPtr->selectLast = -1;
 
2571
            entryPtr->selectFirst = -1;
 
2572
            entryPtr->selectLast = -1;
1850
2573
        } else if (entryPtr->selectLast > entryPtr->numChars) {
1851
2574
            entryPtr->selectLast = entryPtr->numChars;
1852
2575
        }
1853
2576
    }
1854
2577
    if (entryPtr->leftIndex >= entryPtr->numChars) {
1855
 
        entryPtr->leftIndex = entryPtr->numChars-1;
1856
 
        if (entryPtr->leftIndex < 0) {
 
2578
        if (entryPtr->numChars > 0) {
 
2579
            entryPtr->leftIndex = entryPtr->numChars - 1;
 
2580
        } else {
1857
2581
            entryPtr->leftIndex = 0;
1858
2582
        }
1859
2583
    }
1865
2589
    EntryComputeGeometry(entryPtr);
1866
2590
    EventuallyRedraw(entryPtr);
1867
2591
}
1868
 
 
 
2592
 
1869
2593
/*
1870
2594
 *--------------------------------------------------------------
1871
2595
 *
1872
2596
 * EntryEventProc --
1873
2597
 *
1874
 
 *      This procedure is invoked by the Tk dispatcher for various
1875
 
 *      events on entryes.
 
2598
 *      This procedure is invoked by the Tk dispatcher for various
 
2599
 *      events on entries.
1876
2600
 *
1877
2601
 * Results:
1878
 
 *      None.
 
2602
 *      None.
1879
2603
 *
1880
2604
 * Side effects:
1881
 
 *      When the window gets deleted, internal structures get
1882
 
 *      cleaned up.  When it gets exposed, it is redisplayed.
 
2605
 *      When the window gets deleted, internal structures get
 
2606
 *      cleaned up.  When it gets exposed, it is redisplayed.
1883
2607
 *
1884
2608
 *--------------------------------------------------------------
1885
2609
 */
1886
2610
 
1887
2611
static void
1888
2612
EntryEventProc(clientData, eventPtr)
1889
 
    ClientData clientData;      /* Information about window. */
1890
 
    XEvent *eventPtr;           /* Information about event. */
 
2613
    ClientData clientData;      /* Information about window. */
 
2614
    XEvent *eventPtr;           /* Information about event. */
1891
2615
{
1892
2616
    Entry *entryPtr = (Entry *) clientData;
1893
 
    if (eventPtr->type == Expose) {
1894
 
        EventuallyRedraw(entryPtr);
1895
 
        entryPtr->flags |= BORDER_NEEDED;
1896
 
    } else if (eventPtr->type == DestroyNotify) {
1897
 
        if (entryPtr->tkwin != NULL) {
1898
 
            entryPtr->tkwin = NULL;
1899
 
            Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd);
1900
 
        }
1901
 
        if (entryPtr->flags & REDRAW_PENDING) {
1902
 
            Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr);
1903
 
        }
1904
 
        Tcl_EventuallyFree((ClientData) entryPtr, DestroyEntry);
1905
 
    } else if (eventPtr->type == ConfigureNotify) {
1906
 
        Tcl_Preserve((ClientData) entryPtr);
1907
 
        entryPtr->flags |= UPDATE_SCROLLBAR;
1908
 
        EntryComputeGeometry(entryPtr);
1909
 
        EventuallyRedraw(entryPtr);
1910
 
        Tcl_Release((ClientData) entryPtr);
1911
 
    } else if (eventPtr->type == FocusIn) {
1912
 
        if (eventPtr->xfocus.detail != NotifyInferior) {
1913
 
            EntryFocusProc(entryPtr, 1);
1914
 
        }
1915
 
    } else if (eventPtr->type == FocusOut) {
1916
 
        if (eventPtr->xfocus.detail != NotifyInferior) {
1917
 
            EntryFocusProc(entryPtr, 0);
1918
 
        }
 
2617
 
 
2618
    if ((entryPtr->type == TK_SPINBOX) && (eventPtr->type == MotionNotify)) {
 
2619
        Spinbox *sbPtr = (Spinbox *) clientData;
 
2620
        int elem;
 
2621
 
 
2622
        elem = GetSpinboxElement(sbPtr, eventPtr->xmotion.x,
 
2623
                eventPtr->xmotion.y);
 
2624
        if (elem != sbPtr->curElement) {
 
2625
            Tk_Cursor cursor;
 
2626
 
 
2627
            sbPtr->curElement = elem;
 
2628
            if (elem == SEL_ENTRY) {
 
2629
                cursor = entryPtr->cursor;
 
2630
            } else if ((elem == SEL_BUTTONDOWN) || (elem == SEL_BUTTONUP)) {
 
2631
                cursor = sbPtr->bCursor;
 
2632
            } else {
 
2633
                cursor = None;
 
2634
            }
 
2635
            if (cursor != None) {
 
2636
                Tk_DefineCursor(entryPtr->tkwin, cursor);
 
2637
            } else {
 
2638
                Tk_UndefineCursor(entryPtr->tkwin);
 
2639
            }
 
2640
        }
 
2641
        return;
 
2642
    }
 
2643
 
 
2644
    switch (eventPtr->type) {
 
2645
        case Expose:
 
2646
            EventuallyRedraw(entryPtr);
 
2647
            entryPtr->flags |= BORDER_NEEDED;
 
2648
            break;
 
2649
        case DestroyNotify:
 
2650
            if (!(entryPtr->flags & ENTRY_DELETED)) {
 
2651
                entryPtr->flags |= (ENTRY_DELETED | VALIDATE_ABORT);
 
2652
                Tcl_DeleteCommandFromToken(entryPtr->interp,
 
2653
                        entryPtr->widgetCmd);
 
2654
                if (entryPtr->flags & REDRAW_PENDING) {
 
2655
                    Tcl_CancelIdleCall(DisplayEntry, clientData);
 
2656
                }
 
2657
                Tcl_EventuallyFree(clientData, DestroyEntry);
 
2658
            }
 
2659
            break;
 
2660
        case ConfigureNotify:
 
2661
            Tcl_Preserve((ClientData) entryPtr);
 
2662
            entryPtr->flags |= UPDATE_SCROLLBAR;
 
2663
            EntryComputeGeometry(entryPtr);
 
2664
            EventuallyRedraw(entryPtr);
 
2665
            Tcl_Release((ClientData) entryPtr);
 
2666
            break;
 
2667
        case FocusIn:
 
2668
        case FocusOut:
 
2669
            if (eventPtr->xfocus.detail != NotifyInferior) {
 
2670
                EntryFocusProc(entryPtr, (eventPtr->type == FocusIn));
 
2671
            }
 
2672
            break;
1919
2673
    }
1920
2674
}
1921
 
 
 
2675
 
1922
2676
/*
1923
2677
 *----------------------------------------------------------------------
1924
2678
 *
1925
2679
 * EntryCmdDeletedProc --
1926
2680
 *
1927
 
 *      This procedure is invoked when a widget command is deleted.  If
1928
 
 *      the widget isn't already in the process of being destroyed,
1929
 
 *      this command destroys it.
 
2681
 *      This procedure is invoked when a widget command is deleted.  If
 
2682
 *      the widget isn't already in the process of being destroyed,
 
2683
 *      this command destroys it.
1930
2684
 *
1931
2685
 * Results:
1932
 
 *      None.
 
2686
 *      None.
1933
2687
 *
1934
2688
 * Side effects:
1935
 
 *      The widget is destroyed.
 
2689
 *      The widget is destroyed.
1936
2690
 *
1937
2691
 *----------------------------------------------------------------------
1938
2692
 */
1939
2693
 
1940
2694
static void
1941
2695
EntryCmdDeletedProc(clientData)
1942
 
    ClientData clientData;      /* Pointer to widget record for widget. */
 
2696
    ClientData clientData;      /* Pointer to widget record for widget. */
1943
2697
{
1944
2698
    Entry *entryPtr = (Entry *) clientData;
1945
 
    Tk_Window tkwin = entryPtr->tkwin;
1946
2699
 
1947
2700
    /*
1948
2701
     * This procedure could be invoked either because the window was
1951
2704
     * destroys the widget.
1952
2705
     */
1953
2706
 
1954
 
    if (tkwin != NULL) {
1955
 
        entryPtr->tkwin = NULL;
1956
 
        Tk_DestroyWindow(tkwin);
 
2707
    if (!(entryPtr->flags & ENTRY_DELETED)) {
 
2708
        Tk_DestroyWindow(entryPtr->tkwin);
1957
2709
    }
1958
2710
}
1959
 
 
 
2711
 
1960
2712
/*
1961
 
 *--------------------------------------------------------------
 
2713
 *---------------------------------------------------------------------------
1962
2714
 *
1963
2715
 * GetEntryIndex --
1964
2716
 *
1965
 
 *      Parse an index into an entry and return either its value
1966
 
 *      or an error.
 
2717
 *      Parse an index into an entry and return either its value
 
2718
 *      or an error.
1967
2719
 *
1968
2720
 * Results:
1969
 
 *      A standard Tcl result.  If all went well, then *indexPtr is
1970
 
 *      filled in with the index (into entryPtr) corresponding to
1971
 
 *      string.  The index value is guaranteed to lie between 0 and
1972
 
 *      the number of characters in the string, inclusive.  If an
1973
 
 *      error occurs then an error message is left in interp->result.
 
2721
 *      A standard Tcl result.  If all went well, then *indexPtr is
 
2722
 *      filled in with the character index (into entryPtr) corresponding to
 
2723
 *      string.  The index value is guaranteed to lie between 0 and
 
2724
 *      the number of characters in the string, inclusive.  If an
 
2725
 *      error occurs then an error message is left in the interp's result.
1974
2726
 *
1975
2727
 * Side effects:
1976
 
 *      None.
 
2728
 *      None.
1977
2729
 *
1978
 
 *--------------------------------------------------------------
 
2730
 *---------------------------------------------------------------------------
1979
2731
 */
1980
2732
 
1981
2733
static int
1982
2734
GetEntryIndex(interp, entryPtr, arg, indexPtr)
1983
 
    Tcl_Interp *interp;         /* For error messages. */
1984
 
    Entry *entryPtr;            /* Entry for which the index is being
 
2735
    Tcl_Interp *interp;         /* For error messages. */
 
2736
    Entry *entryPtr;            /* Entry for which the index is being
1985
2737
                                 * specified. */
1986
 
    Arg  arg;                   /* Specifies character in entryPtr. */
1987
 
    int *indexPtr;              /* Where to store converted index. */
 
2738
    Tcl_Obj *arg;               /* Specifies character in entryPtr. */
 
2739
    int *indexPtr;              /* Where to store converted index. */
1988
2740
{
1989
2741
    size_t length;
1990
 
    char *string = LangString(arg);
 
2742
    char *string = Tcl_GetString(arg);
1991
2743
 
1992
2744
    length = strlen(string);
1993
2745
 
1998
2750
            badIndex:
1999
2751
 
2000
2752
            /*
2001
 
             * Some of the paths here leave messages in interp->result,
 
2753
             * Some of the paths here leave messages in the interp's result,
2002
2754
             * so we have to clear it out before storing our own message.
2003
2755
             */
2004
2756
 
2005
2757
            Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
2006
 
            Tcl_AppendResult(interp, "bad entry index \"", string,
2007
 
                    "\"", (char *) NULL);
 
2758
            Tcl_AppendResult(interp, "bad ",
 
2759
                    (entryPtr->type == TK_ENTRY) ? "entry" : "spinbox",
 
2760
                    " index \"", string, "\"", (char *) NULL);
2008
2761
            return TCL_ERROR;
2009
2762
        }
2010
2763
    } else if (string[0] == 'e') {
2020
2773
            goto badIndex;
2021
2774
        }
2022
2775
    } else if (string[0] == 's') {
2023
 
        if (entryPtr->selectFirst == -1) {
2024
 
            interp->result = "selection isn't in entry";
 
2776
        if (entryPtr->selectFirst < 0) {
 
2777
            Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
 
2778
            Tcl_AppendResult(interp, "selection isn't in widget ",
 
2779
                    Tk_PathName(entryPtr->tkwin), (char *) NULL);
2025
2780
            return TCL_ERROR;
2026
2781
        }
2027
2782
        if (length < 5) {
2035
2790
            goto badIndex;
2036
2791
        }
2037
2792
    } else if (string[0] == '@') {
2038
 
        int x, roundUp;
2039
 
 
2040
 
        Arg tmp = LangStringArg(string+1);
2041
 
 
2042
 
        if (Tcl_GetInt(interp, tmp, &x) != TCL_OK) {
2043
 
            LangFreeArg(tmp,TCL_DYNAMIC);
 
2793
        int x, roundUp, maxWidth;
 
2794
 
 
2795
        Tcl_Obj *tmp = LangStringArg(string+1);
 
2796
 
 
2797
        if (Tcl_GetIntFromObj(interp, tmp, &x) != TCL_OK) {
 
2798
            LangFreeArg(tmp,TCL_DYNAMIC);
2044
2799
            goto badIndex;
2045
2800
        }
2046
 
        LangFreeArg(tmp,TCL_DYNAMIC);
 
2801
        LangFreeArg(tmp,TCL_DYNAMIC);
2047
2802
        if (x < entryPtr->inset) {
2048
2803
            x = entryPtr->inset;
2049
2804
        }
2050
2805
        roundUp = 0;
2051
 
        if (x >= (Tk_Width(entryPtr->tkwin) - entryPtr->inset)) {
2052
 
            x = Tk_Width(entryPtr->tkwin) - entryPtr->inset - 1;
 
2806
        maxWidth = Tk_Width(entryPtr->tkwin) - entryPtr->inset
 
2807
            - entryPtr->xWidth - 1;
 
2808
        if (x > maxWidth) {
 
2809
            x = maxWidth;
2053
2810
            roundUp = 1;
2054
2811
        }
2055
2812
        *indexPtr = Tk_PointToChar(entryPtr->textLayout,
2067
2824
        }
2068
2825
    } else {
2069
2826
 
2070
 
        if (Tcl_GetInt(interp, arg, indexPtr) != TCL_OK) {
 
2827
        if (Tcl_GetIntFromObj(interp, arg, indexPtr) != TCL_OK) {
2071
2828
            goto badIndex;
2072
2829
        }
2073
2830
        if (*indexPtr < 0){
2078
2835
    }
2079
2836
    return TCL_OK;
2080
2837
}
2081
 
 
 
2838
 
2082
2839
/*
2083
2840
 *----------------------------------------------------------------------
2084
2841
 *
2085
2842
 * EntryScanTo --
2086
2843
 *
2087
 
 *      Given a y-coordinate (presumably of the curent mouse location)
2088
 
 *      drag the view in the window to implement the scan operation.
 
2844
 *      Given a y-coordinate (presumably of the curent mouse location)
 
2845
 *      drag the view in the window to implement the scan operation.
2089
2846
 *
2090
2847
 * Results:
2091
 
 *      None.
 
2848
 *      None.
2092
2849
 *
2093
2850
 * Side effects:
2094
 
 *      The view in the window may change.
 
2851
 *      The view in the window may change.
2095
2852
 *
2096
2853
 *----------------------------------------------------------------------
2097
2854
 */
2098
2855
 
2099
2856
static void
2100
2857
EntryScanTo(entryPtr, x)
2101
 
    register Entry *entryPtr;           /* Information about widget. */
2102
 
    int x;                              /* X-coordinate to use for scan
2103
 
                                         * operation. */
 
2858
    Entry *entryPtr;            /* Information about widget. */
 
2859
    int x;                      /* X-coordinate to use for scan operation. */
2104
2860
{
2105
2861
    int newLeftIndex;
2106
2862
 
2116
2872
     */
2117
2873
 
2118
2874
    newLeftIndex = entryPtr->scanMarkIndex
2119
 
            - (10*(x - entryPtr->scanMarkX))/entryPtr->avgWidth;
 
2875
            - (10 * (x - entryPtr->scanMarkX)) / entryPtr->avgWidth;
2120
2876
    if (newLeftIndex >= entryPtr->numChars) {
2121
 
        newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars-1;
 
2877
        newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars - 1;
2122
2878
        entryPtr->scanMarkX = x;
2123
2879
    }
2124
2880
    if (newLeftIndex < 0) {
2125
2881
        newLeftIndex = entryPtr->scanMarkIndex = 0;
2126
2882
        entryPtr->scanMarkX = x;
2127
2883
    }
 
2884
 
2128
2885
    if (newLeftIndex != entryPtr->leftIndex) {
2129
2886
        entryPtr->leftIndex = newLeftIndex;
2130
2887
        entryPtr->flags |= UPDATE_SCROLLBAR;
2131
2888
        EntryComputeGeometry(entryPtr);
 
2889
        if (newLeftIndex != entryPtr->leftIndex) {
 
2890
            entryPtr->scanMarkIndex = entryPtr->leftIndex;
 
2891
            entryPtr->scanMarkX = x;
 
2892
        }
2132
2893
        EventuallyRedraw(entryPtr);
2133
2894
    }
2134
2895
}
2135
 
 
 
2896
 
2136
2897
/*
2137
2898
 *----------------------------------------------------------------------
2138
2899
 *
2139
2900
 * EntrySelectTo --
2140
2901
 *
2141
 
 *      Modify the selection by moving its un-anchored end.  This could
2142
 
 *      make the selection either larger or smaller.
 
2902
 *      Modify the selection by moving its un-anchored end.  This could
 
2903
 *      make the selection either larger or smaller.
2143
2904
 *
2144
2905
 * Results:
2145
 
 *      None.
 
2906
 *      None.
2146
2907
 *
2147
2908
 * Side effects:
2148
 
 *      The selection changes.
 
2909
 *      The selection changes.
2149
2910
 *
2150
2911
 *----------------------------------------------------------------------
2151
2912
 */
2152
2913
 
2153
2914
static void
2154
2915
EntrySelectTo(entryPtr, index)
2155
 
    register Entry *entryPtr;           /* Information about widget. */
2156
 
    int index;                          /* Index of element that is to
2157
 
                                         * become the "other" end of the
2158
 
                                         * selection. */
 
2916
    Entry *entryPtr;            /* Information about widget. */
 
2917
    int index;                  /* Character index of element that is to
 
2918
                                 * become the "other" end of the selection. */
2159
2919
{
2160
2920
    int newFirst, newLast;
2161
2921
 
2194
2954
    entryPtr->selectLast = newLast;
2195
2955
    EventuallyRedraw(entryPtr);
2196
2956
}
2197
 
 
 
2957
 
2198
2958
/*
2199
2959
 *----------------------------------------------------------------------
2200
2960
 *
2201
2961
 * EntryFetchSelection --
2202
2962
 *
2203
 
 *      This procedure is called back by Tk when the selection is
2204
 
 *      requested by someone.  It returns part or all of the selection
2205
 
 *      in a buffer provided by the caller.
 
2963
 *      This procedure is called back by Tk when the selection is
 
2964
 *      requested by someone.  It returns part or all of the selection
 
2965
 *      in a buffer provided by the caller.
2206
2966
 *
2207
2967
 * Results:
2208
 
 *      The return value is the number of non-NULL bytes stored
2209
 
 *      at buffer.  Buffer is filled (or partially filled) with a
2210
 
 *      NULL-terminated string containing part or all of the selection,
2211
 
 *      as given by offset and maxBytes.
 
2968
 *      The return value is the number of non-NULL bytes stored
 
2969
 *      at buffer.  Buffer is filled (or partially filled) with a
 
2970
 *      NULL-terminated string containing part or all of the selection,
 
2971
 *      as given by offset and maxBytes.
2212
2972
 *
2213
2973
 * Side effects:
2214
 
 *      None.
 
2974
 *      None.
2215
2975
 *
2216
2976
 *----------------------------------------------------------------------
2217
2977
 */
2218
2978
 
2219
2979
static int
2220
2980
EntryFetchSelection(clientData, offset, buffer, maxBytes)
2221
 
    ClientData clientData;              /* Information about entry widget. */
2222
 
    int offset;                         /* Offset within selection of first
2223
 
                                         * character to be returned. */
2224
 
    char *buffer;                       /* Location in which to place
2225
 
                                         * selection. */
2226
 
    int maxBytes;                       /* Maximum number of bytes to place
2227
 
                                         * at buffer, not including terminating
2228
 
                                         * NULL character. */
 
2981
    ClientData clientData;      /* Information about entry widget. */
 
2982
    int offset;                 /* Byte offset within selection of first
 
2983
                                 * character to be returned. */
 
2984
    char *buffer;               /* Location in which to place selection. */
 
2985
    int maxBytes;               /* Maximum number of bytes to place at
 
2986
                                 * buffer, not including terminating NULL
 
2987
                                 * character. */
2229
2988
{
2230
2989
    Entry *entryPtr = (Entry *) clientData;
2231
 
    int count;
2232
 
    char *displayString;
 
2990
    int byteCount;
 
2991
    CONST char *string;
 
2992
    CONST char *selStart, *selEnd;
2233
2993
 
2234
2994
    if ((entryPtr->selectFirst < 0) || !(entryPtr->exportSelection)) {
2235
2995
        return -1;
2236
2996
    }
2237
 
    count = entryPtr->selectLast - entryPtr->selectFirst - offset;
2238
 
    if (count > maxBytes) {
2239
 
        count = maxBytes;
 
2997
    string = entryPtr->displayString;
 
2998
    selStart = Tcl_UtfAtIndex(string, entryPtr->selectFirst);
 
2999
    selEnd = Tcl_UtfAtIndex(selStart,
 
3000
            entryPtr->selectLast - entryPtr->selectFirst);
 
3001
    byteCount = selEnd - selStart - offset;
 
3002
    if (byteCount > maxBytes) {
 
3003
        byteCount = maxBytes;
2240
3004
    }
2241
 
    if (count <= 0) {
 
3005
    if (byteCount <= 0) {
2242
3006
        return 0;
2243
3007
    }
2244
 
    if (entryPtr->displayString == NULL) {
2245
 
        displayString = entryPtr->string;
2246
 
    } else {
2247
 
        displayString = entryPtr->displayString;
2248
 
    }
2249
 
    strncpy(buffer, displayString + entryPtr->selectFirst + offset,
2250
 
            (size_t) count);
2251
 
    buffer[count] = '\0';
2252
 
    return count;
 
3008
    memcpy(buffer, selStart + offset, (size_t) byteCount);
 
3009
    buffer[byteCount] = '\0';
 
3010
    return byteCount;
2253
3011
}
2254
 
 
 
3012
 
2255
3013
/*
2256
3014
 *----------------------------------------------------------------------
2257
3015
 *
2258
3016
 * EntryLostSelection --
2259
3017
 *
2260
 
 *      This procedure is called back by Tk when the selection is
2261
 
 *      grabbed away from an entry widget.
 
3018
 *      This procedure is called back by Tk when the selection is
 
3019
 *      grabbed away from an entry widget.
2262
3020
 *
2263
3021
 * Results:
2264
 
 *      None.
 
3022
 *      None.
2265
3023
 *
2266
3024
 * Side effects:
2267
 
 *      The existing selection is unhighlighted, and the window is
2268
 
 *      marked as not containing a selection.
 
3025
 *      The existing selection is unhighlighted, and the window is
 
3026
 *      marked as not containing a selection.
2269
3027
 *
2270
3028
 *----------------------------------------------------------------------
2271
3029
 */
2272
3030
 
2273
3031
static void
2274
3032
EntryLostSelection(clientData)
2275
 
    ClientData clientData;              /* Information about entry widget. */
 
3033
    ClientData clientData;      /* Information about entry widget. */
2276
3034
{
2277
3035
    Entry *entryPtr = (Entry *) clientData;
2278
3036
 
2285
3043
     */
2286
3044
 
2287
3045
#ifdef ALWAYS_SHOW_SELECTION
2288
 
    if ((entryPtr->selectFirst != -1) && entryPtr->exportSelection) {
 
3046
    if ((entryPtr->selectFirst >= 0) && entryPtr->exportSelection) {
2289
3047
        entryPtr->selectFirst = -1;
2290
3048
        entryPtr->selectLast = -1;
2291
3049
        EventuallyRedraw(entryPtr);
2292
3050
    }
2293
3051
#endif
2294
3052
}
2295
 
 
 
3053
 
2296
3054
/*
2297
3055
 *----------------------------------------------------------------------
2298
3056
 *
2299
3057
 * EventuallyRedraw --
2300
3058
 *
2301
 
 *      Ensure that an entry is eventually redrawn on the display.
 
3059
 *      Ensure that an entry is eventually redrawn on the display.
2302
3060
 *
2303
3061
 * Results:
2304
 
 *      None.
 
3062
 *      None.
2305
3063
 *
2306
3064
 * Side effects:
2307
 
 *      Information gets redisplayed.  Right now we don't do selective
2308
 
 *      redisplays:  the whole window will be redrawn.  This doesn't
2309
 
 *      seem to hurt performance noticeably, but if it does then this
2310
 
 *      could be changed.
 
3065
 *      Information gets redisplayed.  Right now we don't do selective
 
3066
 *      redisplays:  the whole window will be redrawn.  This doesn't
 
3067
 *      seem to hurt performance noticeably, but if it does then this
 
3068
 *      could be changed.
2311
3069
 *
2312
3070
 *----------------------------------------------------------------------
2313
3071
 */
2314
3072
 
2315
3073
static void
2316
3074
EventuallyRedraw(entryPtr)
2317
 
    register Entry *entryPtr;           /* Information about widget. */
 
3075
    Entry *entryPtr;            /* Information about widget. */
2318
3076
{
2319
 
    if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) {
 
3077
    if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(entryPtr->tkwin)) {
2320
3078
        return;
2321
3079
    }
2322
3080
 
2331
3089
        Tcl_DoWhenIdle(DisplayEntry, (ClientData) entryPtr);
2332
3090
    }
2333
3091
}
2334
 
 
 
3092
 
2335
3093
/*
2336
3094
 *----------------------------------------------------------------------
2337
3095
 *
2338
3096
 * EntryVisibleRange --
2339
3097
 *
2340
 
 *      Return information about the range of the entry that is
2341
 
 *      currently visible.
 
3098
 *      Return information about the range of the entry that is
 
3099
 *      currently visible.
2342
3100
 *
2343
3101
 * Results:
2344
 
 *      *firstPtr and *lastPtr are modified to hold fractions between
2345
 
 *      0 and 1 identifying the range of characters visible in the
2346
 
 *      entry.
 
3102
 *      *firstPtr and *lastPtr are modified to hold fractions between
 
3103
 *      0 and 1 identifying the range of characters visible in the
 
3104
 *      entry.
2347
3105
 *
2348
3106
 * Side effects:
2349
 
 *      None.
 
3107
 *      None.
2350
3108
 *
2351
3109
 *----------------------------------------------------------------------
2352
3110
 */
2353
3111
 
2354
3112
static void
2355
3113
EntryVisibleRange(entryPtr, firstPtr, lastPtr)
2356
 
    Entry *entryPtr;                    /* Information about widget. */
2357
 
    double *firstPtr;                   /* Return position of first visible
2358
 
                                         * character in widget. */
2359
 
    double *lastPtr;                    /* Return position of char just after
2360
 
                                         * last visible one. */
 
3114
    Entry *entryPtr;            /* Information about widget. */
 
3115
    double *firstPtr;           /* Return position of first visible
 
3116
                                 * character in widget. */
 
3117
    double *lastPtr;            /* Return position of char just after last
 
3118
                                 * visible one. */
2361
3119
{
2362
3120
    int charsInWindow;
2363
3121
 
2367
3125
    } else {
2368
3126
        charsInWindow = Tk_PointToChar(entryPtr->textLayout,
2369
3127
                Tk_Width(entryPtr->tkwin) - entryPtr->inset
2370
 
                        - entryPtr->layoutX - 1, 0) + 1;
2371
 
        if (charsInWindow > entryPtr->numChars) {
2372
 
            /*
2373
 
             * If all chars were visible, then charsInWindow will be
2374
 
             * the index just after the last char that was visible.
2375
 
             */
2376
 
        
2377
 
            charsInWindow = entryPtr->numChars;
 
3128
                - entryPtr->xWidth - entryPtr->layoutX - 1, 0);
 
3129
        if (charsInWindow < entryPtr->numChars) {
 
3130
            charsInWindow++;
2378
3131
        }
2379
3132
        charsInWindow -= entryPtr->leftIndex;
2380
3133
        if (charsInWindow == 0) {
2381
3134
            charsInWindow = 1;
2382
3135
        }
2383
 
        *firstPtr = ((double) entryPtr->leftIndex)/entryPtr->numChars;
2384
 
        *lastPtr = ((double) (entryPtr->leftIndex + charsInWindow))
2385
 
                /entryPtr->numChars;
 
3136
 
 
3137
        *firstPtr = (double) entryPtr->leftIndex / entryPtr->numChars;
 
3138
        *lastPtr = (double) (entryPtr->leftIndex + charsInWindow)
 
3139
                / entryPtr->numChars;
2386
3140
    }
2387
3141
}
2388
 
 
 
3142
 
2389
3143
/*
2390
3144
 *----------------------------------------------------------------------
2391
3145
 *
2392
3146
 * EntryUpdateScrollbar --
2393
3147
 *
2394
 
 *      This procedure is invoked whenever information has changed in
2395
 
 *      an entry in a way that would invalidate a scrollbar display.
2396
 
 *      If there is an associated scrollbar, then this procedure updates
2397
 
 *      it by invoking a Tcl command.
 
3148
 *      This procedure is invoked whenever information has changed in
 
3149
 *      an entry in a way that would invalidate a scrollbar display.
 
3150
 *      If there is an associated scrollbar, then this procedure updates
 
3151
 *      it by invoking a Tcl command.
2398
3152
 *
2399
3153
 * Results:
2400
 
 *      None.
 
3154
 *      None.
2401
3155
 *
2402
3156
 * Side effects:
2403
 
 *      A Tcl command is invoked, and an additional command may be
2404
 
 *      invoked to process errors in the command.
 
3157
 *      A Tcl command is invoked, and an additional command may be
 
3158
 *      invoked to process errors in the command.
2405
3159
 *
2406
3160
 *----------------------------------------------------------------------
2407
3161
 */
2408
3162
 
2409
3163
static void
2410
3164
EntryUpdateScrollbar(entryPtr)
2411
 
    Entry *entryPtr;                    /* Information about widget. */
 
3165
    Entry *entryPtr;                    /* Information about widget. */
2412
3166
{
2413
 
    char args[100];
 
3167
    char args[TCL_DOUBLE_SPACE * 2];
2414
3168
    int code;
2415
3169
    double first, last;
2416
3170
    Tcl_Interp *interp;
2425
3179
    code = LangDoCallback(entryPtr->interp, entryPtr->scrollCmd, 0, 2, " %g %g", first, last);
2426
3180
    if (code != TCL_OK) {
2427
3181
        Tcl_AddErrorInfo(interp,
2428
 
                "\n    (horizontal scrolling command executed by entry)");
 
3182
                "\n    (horizontal scrolling command executed by ");
 
3183
        Tcl_AddErrorInfo(interp, Tk_PathName(entryPtr->tkwin));
 
3184
        Tcl_AddErrorInfo(interp, ")");
2429
3185
        Tcl_BackgroundError(interp);
2430
3186
    }
2431
3187
    Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
2432
3188
    Tcl_Release((ClientData) interp);
2433
3189
}
2434
 
 
 
3190
 
2435
3191
/*
2436
3192
 *----------------------------------------------------------------------
2437
3193
 *
2438
3194
 * EntryBlinkProc --
2439
3195
 *
2440
 
 *      This procedure is called as a timer handler to blink the
2441
 
 *      insertion cursor off and on.
 
3196
 *      This procedure is called as a timer handler to blink the
 
3197
 *      insertion cursor off and on.
2442
3198
 *
2443
3199
 * Results:
2444
 
 *      None.
 
3200
 *      None.
2445
3201
 *
2446
3202
 * Side effects:
2447
 
 *      The cursor gets turned on or off, redisplay gets invoked,
2448
 
 *      and this procedure reschedules itself.
 
3203
 *      The cursor gets turned on or off, redisplay gets invoked,
 
3204
 *      and this procedure reschedules itself.
2449
3205
 *
2450
3206
 *----------------------------------------------------------------------
2451
3207
 */
2452
3208
 
2453
3209
static void
2454
3210
EntryBlinkProc(clientData)
2455
 
    ClientData clientData;      /* Pointer to record describing entry. */
 
3211
    ClientData clientData;      /* Pointer to record describing entry. */
2456
3212
{
2457
 
    register Entry *entryPtr = (Entry *) clientData;
 
3213
    Entry *entryPtr = (Entry *) clientData;
2458
3214
 
2459
 
    if (!(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) {
 
3215
    if ((entryPtr->state == STATE_DISABLED) ||
 
3216
            (entryPtr->state == STATE_READONLY) ||
 
3217
            !(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) {
2460
3218
        return;
2461
3219
    }
2462
3220
    if (entryPtr->flags & CURSOR_ON) {
2463
3221
        entryPtr->flags &= ~CURSOR_ON;
2464
3222
        entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
2465
 
                entryPtr->insertOffTime, EntryBlinkProc, (ClientData) entryPtr);
 
3223
            entryPtr->insertOffTime, EntryBlinkProc, (ClientData) entryPtr);
2466
3224
    } else {
2467
3225
        entryPtr->flags |= CURSOR_ON;
2468
3226
        entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
2469
 
                entryPtr->insertOnTime, EntryBlinkProc, (ClientData) entryPtr);
 
3227
            entryPtr->insertOnTime, EntryBlinkProc, (ClientData) entryPtr);
2470
3228
    }
2471
3229
    EventuallyRedraw(entryPtr);
2472
3230
}
2473
 
 
 
3231
 
2474
3232
/*
2475
3233
 *----------------------------------------------------------------------
2476
3234
 *
2477
3235
 * EntryFocusProc --
2478
3236
 *
2479
 
 *      This procedure is called whenever the entry gets or loses the
2480
 
 *      input focus.  It's also called whenever the window is reconfigured
2481
 
 *      while it has the focus.
 
3237
 *      This procedure is called whenever the entry gets or loses the
 
3238
 *      input focus.  It's also called whenever the window is reconfigured
 
3239
 *      while it has the focus.
2482
3240
 *
2483
3241
 * Results:
2484
 
 *      None.
 
3242
 *      None.
2485
3243
 *
2486
3244
 * Side effects:
2487
 
 *      The cursor gets turned on or off.
 
3245
 *      The cursor gets turned on or off.
2488
3246
 *
2489
3247
 *----------------------------------------------------------------------
2490
3248
 */
2491
3249
 
2492
3250
static void
2493
3251
EntryFocusProc(entryPtr, gotFocus)
2494
 
    register Entry *entryPtr;   /* Entry that got or lost focus. */
2495
 
    int gotFocus;               /* 1 means window is getting focus, 0 means
 
3252
    Entry *entryPtr;            /* Entry that got or lost focus. */
 
3253
    int gotFocus;               /* 1 means window is getting focus, 0 means
2496
3254
                                 * it's losing it. */
2497
3255
{
2498
3256
    Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler);
2503
3261
                    entryPtr->insertOnTime, EntryBlinkProc,
2504
3262
                    (ClientData) entryPtr);
2505
3263
        }
2506
 
#ifdef ENTRY_VALIDATE
2507
3264
        if (entryPtr->validate == VALIDATE_ALL ||
2508
3265
            entryPtr->validate == VALIDATE_FOCUS ||
2509
3266
            entryPtr->validate == VALIDATE_FOCUSIN) {
2510
3267
            EntryValidateChange(entryPtr, (char *) NULL,
2511
 
                                entryPtr->string, -1, -2);
 
3268
                                entryPtr->string, -1, VALIDATE_FOCUSIN);
2512
3269
        }
2513
 
#endif /* ENTRY_VALIDATE */
2514
3270
    } else {
2515
3271
        entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON);
2516
3272
        entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
2517
 
#ifdef ENTRY_VALIDATE
2518
3273
        if (entryPtr->validate == VALIDATE_ALL ||
2519
3274
            entryPtr->validate == VALIDATE_FOCUS ||
2520
3275
            entryPtr->validate == VALIDATE_FOCUSOUT) {
2521
3276
            EntryValidateChange(entryPtr, (char *) NULL,
2522
 
                                entryPtr->string, -1, -3);
 
3277
                                entryPtr->string, -1, VALIDATE_FOCUSOUT);
2523
3278
        }
2524
 
#endif /* ENTRY_VALIDATE */
2525
3279
    }
2526
3280
    EventuallyRedraw(entryPtr);
2527
3281
}
2528
 
 
 
3282
 
2529
3283
/*
2530
3284
 *--------------------------------------------------------------
2531
3285
 *
2532
3286
 * EntryTextVarProc --
2533
3287
 *
2534
 
 *      This procedure is invoked when someone changes the variable
2535
 
 *      whose contents are to be displayed in an entry.
 
3288
 *      This procedure is invoked when someone changes the variable
 
3289
 *      whose contents are to be displayed in an entry.
2536
3290
 *
2537
3291
 * Results:
2538
 
 *      NULL is always returned.
 
3292
 *      NULL is always returned.
2539
3293
 *
2540
3294
 * Side effects:
2541
 
 *      The text displayed in the entry will change to match the
2542
 
 *      variable.
 
3295
 *      The text displayed in the entry will change to match the
 
3296
 *      variable.
2543
3297
 *
2544
3298
 *--------------------------------------------------------------
2545
3299
 */
2547
3301
        /* ARGSUSED */
2548
3302
static char *
2549
3303
EntryTextVarProc(clientData, interp, name1, name2, flags)
2550
 
    ClientData clientData;      /* Information about button. */
2551
 
    Tcl_Interp *interp;         /* Interpreter containing variable. */
2552
 
    Var name1;                  /* Not used. */
2553
 
    char *name2;                /* Not used. */
2554
 
    int flags;                  /* Information about what happened. */
 
3304
    ClientData clientData;      /* Information about button. */
 
3305
    Tcl_Interp *interp;         /* Interpreter containing variable. */
 
3306
    Tcl_Obj *name1;             /* Not used. */
 
3307
    CONST char *name2;          /* Not used. */
 
3308
    int flags;                  /* Information about what happened. */
2555
3309
{
2556
 
    register Entry *entryPtr = (Entry *) clientData;
2557
 
    char *value;
 
3310
    Entry *entryPtr = (Entry *) clientData;
 
3311
    CONST char *value;
 
3312
 
 
3313
    if (entryPtr->flags & ENTRY_DELETED) {
 
3314
        /*
 
3315
         * Just abort early if we entered here while being deleted.
 
3316
         */
 
3317
        return (char *) NULL;
 
3318
    }
2558
3319
 
2559
3320
    /*
2560
3321
     * If the variable is unset, then immediately recreate it unless
2563
3324
 
2564
3325
    if (flags & TCL_TRACE_UNSETS) {
2565
3326
        if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
2566
 
            Tcl_SetVar(interp, entryPtr->textVarName, entryPtr->string,
2567
 
                    TCL_GLOBAL_ONLY);
2568
 
            Tcl_TraceVar(interp, entryPtr->textVarName,
 
3327
            Tcl_Obj *temp = Tcl_NewStringObj(entryPtr->string,-1);
 
3328
            Tcl_ObjSetVar2(entryPtr->interp, entryPtr->textVarName, NULL,
 
3329
                temp, TCL_GLOBAL_ONLY);
 
3330
            Tcl_DecrRefCount(temp);
 
3331
            Lang_TraceVar(interp, entryPtr->textVarName,
2569
3332
                    TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
2570
3333
                    EntryTextVarProc, clientData);
 
3334
            entryPtr->flags |= ENTRY_VAR_TRACED;
2571
3335
        }
2572
3336
        return (char *) NULL;
2573
3337
    }
2579
3343
     * the entry).
2580
3344
     */
2581
3345
 
2582
 
    value = LangString(Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY));
 
3346
    value = Tcl_GetString(Tcl_ObjGetVar2(interp, entryPtr->textVarName, NULL, TCL_GLOBAL_ONLY));
2583
3347
    if (value == NULL) {
2584
3348
        value = "";
2585
3349
    }
2586
 
#ifdef ENTRY_VALIDATE
2587
3350
    EntrySetValue(entryPtr, value);
2588
 
#else
2589
 
    if (strcmp(value, entryPtr->string) != 0) {
2590
 
        EntrySetValue(entryPtr, value);
2591
 
    }
2592
 
#endif /* ENTRY_VALIDATE */
2593
3351
    return (char *) NULL;
2594
3352
}
2595
 
#ifdef ENTRY_VALIDATE
2596
 
 
 
3353
 
2597
3354
/*
2598
3355
 *--------------------------------------------------------------
2599
3356
 *
2600
3357
 * EntryValidate --
2601
3358
 *
2602
 
 *      This procedure is invoked when any character is added or
2603
 
 *      removed from the entry widget, or a focus has trigerred validation.
 
3359
 *      This procedure is invoked when any character is added or
 
3360
 *      removed from the entry widget, or a focus has trigerred validation.
2604
3361
 *
2605
3362
 * Results:
2606
 
 *      TCL_OK if the validatecommand passes the new string.
 
3363
 *      TCL_OK if the validatecommand passes the new string.
2607
3364
 *      TCL_BREAK if the vcmd executed OK, but rejects the string.
2608
3365
 *      TCL_ERROR if an error occurred while executing the vcmd
2609
3366
 *      or a valid Tcl_Bool is not returned.
2616
3373
 
2617
3374
static int
2618
3375
EntryValidate(entryPtr, cmd, string)
2619
 
     register Entry *entryPtr;  /* Entry that needs validation. */
2620
 
     register LangCallback *cmd;        /* Validation command (NULL-terminated
 
3376
     register Entry *entryPtr;  /* Entry that needs validation. */
 
3377
     register LangCallback *cmd;        /* Validation command (NULL-terminated
2621
3378
                                 * string). */
2622
3379
     char *string;
2623
3380
{
2624
 
    int code;
2625
 
    Arg result;
 
3381
    register Tcl_Interp *interp = entryPtr->interp;
 
3382
    int code, bool;
2626
3383
 
2627
3384
    code = LangDoCallback(entryPtr->interp, cmd, 1, 1, "%s", string);
2628
3385
 
 
3386
    /*
 
3387
     * We accept TCL_OK and TCL_RETURN as valid return codes from the
 
3388
     * command callback.
 
3389
     */
2629
3390
    if (code != TCL_OK && code != TCL_RETURN) {
2630
 
        Tcl_AddErrorInfo(entryPtr->interp,
2631
 
                 "\n\t(in validation command executed by entry)");
2632
 
        Tcl_BackgroundError(entryPtr->interp);
2633
 
        return TCL_ERROR;
2634
 
    }
2635
 
 
2636
 
    result = Tcl_ResultArg(entryPtr->interp);
2637
 
 
2638
 
    if (Tcl_GetBoolean(entryPtr->interp,  result, &code) != TCL_OK) {
2639
 
        Tcl_AddErrorInfo(entryPtr->interp,
2640
 
                 "\nValid Tcl Boolean not returned by validation command");
2641
 
        Tcl_BackgroundError(entryPtr->interp);
2642
 
        Tcl_SetResult(entryPtr->interp, (char *) NULL, TCL_STATIC);
2643
 
        return TCL_ERROR;
2644
 
    }
2645
 
 
2646
 
    Tcl_SetResult(entryPtr->interp, (char *) NULL, TCL_STATIC);
2647
 
    return code ? TCL_OK : TCL_BREAK;
 
3391
        Tcl_AddErrorInfo(interp, "\n\t(in validation command executed by ");
 
3392
        Tcl_AddErrorInfo(interp, Tk_PathName(entryPtr->tkwin));
 
3393
        Tcl_AddErrorInfo(interp, ")");
 
3394
        Tcl_BackgroundError(interp);
 
3395
        return TCL_ERROR;
 
3396
    }
 
3397
 
 
3398
    /*
 
3399
     * The command callback should return an acceptable Tcl boolean.
 
3400
     */
 
3401
    if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp),
 
3402
                              &bool) != TCL_OK) {
 
3403
        Tcl_AddErrorInfo(interp,
 
3404
                 "\nvalid boolean not returned by validation command");
 
3405
        Tcl_BackgroundError(interp);
 
3406
        Tcl_SetResult(interp, NULL, 0);
 
3407
        return TCL_ERROR;
 
3408
    }
 
3409
 
 
3410
    Tcl_SetResult(interp, NULL, 0);
 
3411
    return (bool ? TCL_OK : TCL_BREAK);
2648
3412
}
2649
 
 
 
3413
 
2650
3414
/*
2651
3415
 *--------------------------------------------------------------
2652
3416
 *
2653
3417
 * EntryValidateChange --
2654
3418
 *
2655
 
 *      This procedure is invoked when any character is added or
2656
 
 *      removed from the entry widget, or a focus has trigerred validation.
 
3419
 *      This procedure is invoked when any character is added or
 
3420
 *      removed from the entry widget, or a focus has trigerred validation.
2657
3421
 *
2658
3422
 * Results:
2659
 
 *      TCL_OK if the validatecommand accepts the new string,
 
3423
 *      TCL_OK if the validatecommand accepts the new string,
2660
3424
 *      TCL_ERROR if any problems occured with validatecommand.
2661
3425
 *
2662
3426
 * Side effects:
2668
3432
 */
2669
3433
 
2670
3434
static int
2671
 
EntryValidateChange(entryPtr, string, new, index, type)
2672
 
     register Entry *entryPtr;  /* Entry that needs validation. */
2673
 
     char *string;              /* New characters to add (NULL-terminated
2674
 
                                 * string). */
2675
 
     char *new;                 /* Potential new value of entry string */
 
3435
EntryValidateChange(entryPtr, change, new, index, type)
 
3436
     register Entry *entryPtr;  /* Entry that needs validation. */
 
3437
     char *change;              /* Characters to be added/deleted
 
3438
                                 * (NULL-terminated string). */
 
3439
     CONST char *new;           /* Potential new value of entry string */
2676
3440
     int index;                 /* index of insert/delete, -1 otherwise */
2677
 
     int type;                  /* -1 == forced, 0 == delete, 1 == insert
2678
 
                                 * -2 == focusin, -3 == focusout */
 
3441
     int type;                  /* forced, delete, insert,
 
3442
                                 * focusin or focusout */
2679
3443
{
2680
 
    int code;
 
3444
    int code, varValidate = (entryPtr->flags & VALIDATE_VAR);
2681
3445
    char *p;
2682
 
    Arg result;
 
3446
    Tcl_Obj *result;
2683
3447
    Tcl_DString script;
2684
3448
 
2685
3449
    if (entryPtr->validateCmd == NULL ||
2686
3450
        entryPtr->validate == VALIDATE_NONE) {
2687
 
        return TCL_OK;
 
3451
        return (varValidate ? TCL_ERROR : TCL_OK);
2688
3452
    }
2689
3453
 
2690
3454
    /*
2693
3457
     * and prevent current validation from finishing
2694
3458
     */
2695
3459
    if (entryPtr->flags & VALIDATING) {
2696
 
        if (entryPtr->flags & VALIDATE_VAR) {
2697
 
            return TCL_OK;
2698
 
        }
2699
 
        else {
2700
 
            Tcl_SetResult(entryPtr->interp,"Validate recursed",TCL_STATIC);
2701
 
            return TCL_ERROR;
2702
 
        }
 
3460
        entryPtr->validate = VALIDATE_NONE;
 
3461
        return (varValidate ? TCL_ERROR : TCL_OK);
2703
3462
    }
2704
3463
 
2705
3464
    entryPtr->flags |= VALIDATING;
2711
3470
#ifndef _LANG
2712
3471
    Tcl_DStringInit(&script);
2713
3472
    ExpandPercents(entryPtr, entryPtr->validateCmd,
2714
 
                   string, new, index, type, &script);
 
3473
            change, new, index, type, &script);
2715
3474
    Tcl_DStringAppend(&script, "", 1);
2716
3475
 
2717
3476
    p = Tcl_DStringValue(&script);
2720
3479
#else
2721
3480
 
2722
3481
    code = LangDoCallback(entryPtr->interp, entryPtr->validateCmd, 1, 5, "%s %s %s %d %d",
2723
 
                          new, string,  entryPtr->string, index, type);
 
3482
                          new, change,  entryPtr->string, index, type);
2724
3483
    if (code != TCL_OK && code != TCL_RETURN) {
2725
3484
        Tcl_AddErrorInfo(entryPtr->interp,
2726
3485
                 "\n\t(in validation command executed by entry)");
2728
3487
        goto done;
2729
3488
    }
2730
3489
 
2731
 
    result = Tcl_ResultArg(entryPtr->interp);
 
3490
    result = Tcl_GetObjResult(entryPtr->interp);
2732
3491
 
2733
 
    if (Tcl_GetBoolean(entryPtr->interp,  result, &code) != TCL_OK) {
 
3492
    if (Tcl_GetBooleanFromObj(entryPtr->interp,  result, &code) != TCL_OK) {
2734
3493
        Tcl_AddErrorInfo(entryPtr->interp,
2735
3494
                 "\nValid Tcl Boolean not returned by validation command");
2736
3495
        Tcl_BackgroundError(entryPtr->interp);
2737
3496
        Tcl_SetResult(entryPtr->interp, (char *) NULL, TCL_STATIC);
2738
 
        code = TCL_ERROR;
 
3497
        code = TCL_ERROR;
2739
3498
        goto done;
2740
3499
    }
2741
3500
 
2745
3504
#endif
2746
3505
 
2747
3506
    /*
2748
 
     * If e->validate has become VALIDATE_NONE during the validation,
 
3507
     * If e->validate has become VALIDATE_NONE during the validation, or
 
3508
     * we now have VALIDATE_VAR set (from EntrySetValue) and didn't before,
2749
3509
     * it means that a loop condition almost occured.  Do not allow
2750
3510
     * this validation result to finish.
2751
3511
     */
2752
 
    if (entryPtr->validate == VALIDATE_NONE ) {
 
3512
 
 
3513
    if (entryPtr->validate == VALIDATE_NONE
 
3514
            || (!varValidate && (entryPtr->flags & VALIDATE_VAR))) {
2753
3515
        code = TCL_ERROR;
2754
3516
    }
 
3517
 
 
3518
    /*
 
3519
     * It's possible that the user deleted the entry during validation.
 
3520
     * In that case, abort future validation and return an error.
 
3521
     */
 
3522
 
 
3523
    if (entryPtr->flags & ENTRY_DELETED) {
 
3524
        return TCL_ERROR;
 
3525
    }
 
3526
 
2755
3527
    /*
2756
3528
     * If validate will return ERROR, then disallow further validations
2757
3529
     * Otherwise, if it didn't accept the new string (returned TCL_BREAK)
2758
3530
     * then eval the invalidCmd (if it's set)
2759
3531
     */
 
3532
 
2760
3533
    if (code == TCL_ERROR) {
2761
3534
        entryPtr->validate = VALIDATE_NONE;
2762
3535
    } else if (code == TCL_BREAK) {
2763
 
        if (entryPtr->invalidCmd != NULL) {
 
3536
        /*
 
3537
         * If we were doing forced validation (like via a variable
 
3538
         * trace) and the command returned 0, the we turn off validation
 
3539
         * because we assume that textvariables have precedence in
 
3540
         * managing the value.  We also don't call the invcmd, as it
 
3541
         * may want to do entry manipulation which the setting of the
 
3542
         * var will later wipe anyway.
 
3543
         */
 
3544
 
 
3545
        if (varValidate) {
 
3546
            entryPtr->validate = VALIDATE_NONE;
 
3547
        } else if (entryPtr->invalidCmd != NULL) {
2764
3548
#ifndef _LANG
2765
3549
            Tcl_DStringInit(&script);
2766
3550
            ExpandPercents(entryPtr, entryPtr->invalidCmd,
2767
 
                           string, new, index, type, &script);
 
3551
                           change, new, index, type, &script);
2768
3552
            Tcl_DStringAppend(&script, "", 1);
2769
3553
            p = Tcl_DStringValue(&script);
2770
 
            if (Tcl_Eval(entryPtr->interp, p) != TCL_OK) {
 
3554
            if (Tcl_EvalEx(entryPtr->interp, p, -1,
 
3555
                    TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT) != TCL_OK) {
2771
3556
                Tcl_AddErrorInfo(entryPtr->interp,
2772
3557
                                 "\n\t(in invalidcommand executed by entry)");
2773
3558
                Tcl_BackgroundError(entryPtr->interp);
2775
3560
                entryPtr->validate = VALIDATE_NONE;
2776
3561
            }
2777
3562
            Tcl_DStringFree(&script);
 
3563
 
 
3564
            /*
 
3565
             * It's possible that the user deleted the entry during validation.
 
3566
             * In that case, abort future validation and return an error.
 
3567
             */
 
3568
 
 
3569
            if (entryPtr->flags & ENTRY_DELETED) {
 
3570
                return TCL_ERROR;
 
3571
            }
2778
3572
#else
2779
3573
            if (LangDoCallback(entryPtr->interp, entryPtr->invalidCmd, 1, 5, "%s %s %s %d %d",
2780
 
                               new, string, entryPtr->string, index, type) != TCL_OK) {
 
3574
                               new, change, entryPtr->string, index, type) != TCL_OK) {
2781
3575
                Tcl_AddErrorInfo(entryPtr->interp,
2782
3576
                                 "\n\t(in invalidcommand executed by entry)");
2783
3577
                Tcl_BackgroundError(entryPtr->interp);
2792
3586
    entryPtr->flags &= ~VALIDATING;
2793
3587
    return code;
2794
3588
}
2795
 
 
 
3589
 
2796
3590
/*
2797
3591
 *--------------------------------------------------------------
2798
3592
 *
2799
3593
 * ExpandPercents --
2800
3594
 *
2801
 
 *      Given a command and an event, produce a new command
2802
 
 *      by replacing % constructs in the original command
2803
 
 *      with information from the X event.
 
3595
 *      Given a command and an event, produce a new command
 
3596
 *      by replacing % constructs in the original command
 
3597
 *      with information from the X event.
2804
3598
 *
2805
3599
 * Results:
2806
 
 *      The new expanded command is appended to the dynamic string
2807
 
 *      given by dsPtr.
 
3600
 *      The new expanded command is appended to the dynamic string
 
3601
 *      given by dsPtr.
2808
3602
 *
2809
3603
 * Side effects:
2810
 
 *      None.
 
3604
 *      None.
2811
3605
 *
2812
3606
 *--------------------------------------------------------------
2813
3607
 */
2814
3608
 
2815
3609
#ifndef _LANG
2816
3610
static void
2817
 
ExpandPercents(entryPtr, before, add, new, index, type, dsPtr)
2818
 
     register Entry *entryPtr;  /* Entry that needs validation. */
2819
 
     register char *before;     /* Command containing percent
 
3611
ExpandPercents(entryPtr, before, change, new, index, type, dsPtr)
 
3612
     register Entry *entryPtr;  /* Entry that needs validation. */
 
3613
     register CONST char *before;
 
3614
                                /* Command containing percent
2820
3615
                                 * expressions to be replaced. */
2821
 
     char *add;                 /* New characters to add (NULL-terminated
2822
 
                                 * string). */
2823
 
     char *new;                 /* Potential new value of entry string */
 
3616
     char *change;              /* Characters to added/deleted
 
3617
                                 * (NULL-terminated string). */
 
3618
     CONST char *new;           /* Potential new value of entry string */
2824
3619
     int index;                 /* index of insert/delete */
2825
3620
     int type;                  /* INSERT or DELETE */
2826
3621
     Tcl_DString *dsPtr;        /* Dynamic string in which to append
2827
3622
                                 * new command. */
2828
3623
{
2829
 
    int spaceNeeded, cvtFlags;  /* Used to substitute string as proper Tcl
 
3624
    int spaceNeeded, cvtFlags;  /* Used to substitute string as proper Tcl
2830
3625
                                 * list element. */
2831
3626
    int number, length;
2832
 
#define NUM_SIZE 40
2833
 
    register char *string;
2834
 
    char numStorage[NUM_SIZE+1];
 
3627
    register CONST char *string;
 
3628
    Tcl_UniChar ch;
 
3629
    char numStorage[2*TCL_INTEGER_SPACE];
2835
3630
 
2836
3631
    while (1) {
 
3632
        if (*before == '\0') {
 
3633
            break;
 
3634
        }
2837
3635
        /*
2838
3636
         * Find everything up to the next % character and append it
2839
3637
         * to the result string.
2840
3638
         */
2841
3639
 
2842
 
        for (string = before; (*string != 0) && (*string != '%'); string++) {
2843
 
            /* Empty loop body. */
2844
 
        }
2845
 
        if (string != before) {
 
3640
        string = before;
 
3641
        /* No need to convert '%', as it is in ascii range */
 
3642
        string = Tcl_UtfFindFirst(before, '%');
 
3643
        if (string == (char *) NULL) {
 
3644
            Tcl_DStringAppend(dsPtr, before, -1);
 
3645
            break;
 
3646
        } else if (string != before) {
2846
3647
            Tcl_DStringAppend(dsPtr, before, string-before);
2847
3648
            before = string;
2848
3649
        }
2849
 
        if (*before == 0) {
2850
 
            break;
2851
 
        }
2852
3650
 
2853
3651
        /*
2854
3652
         * There's a percent sequence here.  Process it.
2855
3653
         */
2856
3654
 
2857
 
        number = 0;
2858
 
        string = "??";
2859
 
        switch (before[1]) {
2860
 
          case 'd': /* Type of call that caused validation */
2861
 
            number = type;
2862
 
            goto doNumber;
2863
 
          case 'i': /* index of insert/delete */
2864
 
            number = index;
2865
 
            goto doNumber;
2866
 
          case 'P': /* 'Peeked' new value of the string */
2867
 
            string = new;
2868
 
            goto doString;
2869
 
          case 's': /* Current string value of entry */
2870
 
            string = entryPtr->string;
2871
 
            goto doString;
2872
 
          case 'S': /* string to be inserted/delete, if any */
2873
 
            string = add;
2874
 
            goto doString;
2875
 
          case 'v': /* type of validation */
2876
 
            string = ValidatePrintProc((ClientData) NULL, entryPtr->tkwin,
2877
 
                                       (char *) entryPtr, 0, 0);
2878
 
            goto doString;
2879
 
          case 'W': /* widget name */
2880
 
            string = Tk_PathName(entryPtr->tkwin);
2881
 
            goto doString;
2882
 
          default:
2883
 
            numStorage[0] = before[1];
2884
 
            numStorage[1] = '\0';
2885
 
            string = numStorage;
2886
 
            goto doString;
2887
 
        }
2888
 
 
2889
 
        doNumber:
2890
 
        sprintf(numStorage, "%d", number);
2891
 
        string = numStorage;
2892
 
 
2893
 
        doString:
2894
 
        spaceNeeded = Tcl_ScanElement(string, &cvtFlags);
 
3655
        before++; /* skip over % */
 
3656
        if (*before != '\0') {
 
3657
            before += Tcl_UtfToUniChar(before, &ch);
 
3658
        } else {
 
3659
            ch = '%';
 
3660
        }
 
3661
        if (type == VALIDATE_BUTTON) {
 
3662
            /*
 
3663
             * -command %-substitution
 
3664
             */
 
3665
            switch (ch) {
 
3666
                case 's': /* Current string value of spinbox */
 
3667
                    string = entryPtr->string;
 
3668
                    break;
 
3669
                case 'd': /* direction, up or down */
 
3670
                    string = change;
 
3671
                    break;
 
3672
                case 'W': /* widget name */
 
3673
                    string = Tk_PathName(entryPtr->tkwin);
 
3674
                    break;
 
3675
                default:
 
3676
                    length = Tcl_UniCharToUtf(ch, numStorage);
 
3677
                    numStorage[length] = '\0';
 
3678
                    string = numStorage;
 
3679
                    break;
 
3680
            }
 
3681
        } else {
 
3682
            /*
 
3683
             * -validatecommand / -invalidcommand %-substitution
 
3684
             */
 
3685
            switch (ch) {
 
3686
                case 'd': /* Type of call that caused validation */
 
3687
                    switch (type) {
 
3688
                        case VALIDATE_INSERT:
 
3689
                            number = 1;
 
3690
                            break;
 
3691
                        case VALIDATE_DELETE:
 
3692
                            number = 0;
 
3693
                            break;
 
3694
                        default:
 
3695
                            number = -1;
 
3696
                            break;
 
3697
                    }
 
3698
                    sprintf(numStorage, "%d", number);
 
3699
                    string = numStorage;
 
3700
                    break;
 
3701
                case 'i': /* index of insert/delete */
 
3702
                    sprintf(numStorage, "%d", index);
 
3703
                    string = numStorage;
 
3704
                    break;
 
3705
                case 'P': /* 'Peeked' new value of the string */
 
3706
                    string = new;
 
3707
                    break;
 
3708
                case 's': /* Current string value of spinbox */
 
3709
                    string = entryPtr->string;
 
3710
                    break;
 
3711
                case 'S': /* string to be inserted/deleted, if any */
 
3712
                    string = change;
 
3713
                    break;
 
3714
                case 'v': /* type of validation currently set */
 
3715
                    string = validateStrings[entryPtr->validate];
 
3716
                    break;
 
3717
                case 'V': /* type of validation in effect */
 
3718
                    switch (type) {
 
3719
                        case VALIDATE_INSERT:
 
3720
                        case VALIDATE_DELETE:
 
3721
                            string = validateStrings[VALIDATE_KEY];
 
3722
                            break;
 
3723
                        case VALIDATE_FORCED:
 
3724
                            string = "forced";
 
3725
                            break;
 
3726
                        default:
 
3727
                            string = validateStrings[type];
 
3728
                            break;
 
3729
                    }
 
3730
                    break;
 
3731
                case 'W': /* widget name */
 
3732
                    string = Tk_PathName(entryPtr->tkwin);
 
3733
                    break;
 
3734
                default:
 
3735
                    length = Tcl_UniCharToUtf(ch, numStorage);
 
3736
                    numStorage[length] = '\0';
 
3737
                    string = numStorage;
 
3738
                    break;
 
3739
            }
 
3740
        }
 
3741
 
 
3742
        spaceNeeded = Tcl_ScanCountedElement(string, -1, &cvtFlags);
2895
3743
        length = Tcl_DStringLength(dsPtr);
2896
3744
        Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
2897
 
        spaceNeeded = Tcl_ConvertElement(string,
 
3745
        spaceNeeded = Tcl_ConvertCountedElement(string, -1,
2898
3746
                Tcl_DStringValue(dsPtr) + length,
2899
3747
                cvtFlags | TCL_DONT_USE_BRACES);
2900
3748
        Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
2901
 
        before += 2;
2902
3749
    }
2903
3750
}
2904
 
#endif /* _LANG */
2905
 
 
 
3751
 
 
3752
#endif
2906
3753
/*
2907
3754
 *--------------------------------------------------------------
2908
3755
 *
2909
 
 * ValidateParseProc --
 
3756
 * Tk_SpinboxObjCmd --
2910
3757
 *
2911
 
 *      This procedure is invoked by Tk_ConfigureWidget during
2912
 
 *      option processing to handle "-validate" options for entry
2913
 
 *      widgets.
 
3758
 *      This procedure is invoked to process the "spinbox" Tcl
 
3759
 *      command.  See the user documentation for details on what
 
3760
 *      it does.
2914
3761
 *
2915
3762
 * Results:
2916
 
 *      A standard Tcl return value.
 
3763
 *      A standard Tcl result.
2917
3764
 *
2918
3765
 * Side effects:
2919
 
 *      The validation style for the entry widget may change.
 
3766
 *      See the user documentation.
2920
3767
 *
2921
3768
 *--------------------------------------------------------------
2922
3769
 */
2923
3770
 
2924
 
        /* ARGSUSED */
2925
 
static int
2926
 
ValidateParseProc(clientData, interp, tkwin, ovalue, widgRec, offset)
2927
 
    ClientData clientData;              /* Not used.*/
2928
 
    Tcl_Interp *interp;                 /* Used for reporting errors. */
2929
 
    Tk_Window tkwin;                    /* Window for text widget. */
2930
 
    Arg ovalue;                 /* Value of option. */
2931
 
    char *widgRec;                      /* Pointer to widgRec structure. */
2932
 
    int offset;                         /* Offset into item (ignored). */
 
3771
int
 
3772
Tk_SpinboxObjCmd(clientData, interp, objc, objv)
 
3773
    ClientData clientData;      /* NULL. */
 
3774
    Tcl_Interp *interp;         /* Current interpreter. */
 
3775
    int objc;                   /* Number of arguments. */
 
3776
    Tcl_Obj *CONST objv[];      /* Argument objects. */
2933
3777
{
2934
 
    int c;
2935
 
    size_t length;
2936
 
    char *value = LangString(ovalue);
2937
 
 
2938
 
    register int *validatePtr = (int *) (widgRec + offset);
2939
 
 
2940
 
    if(value == NULL || *value == 0) {
2941
 
        *validatePtr = VALIDATE_NONE;
2942
 
        return TCL_OK;
2943
 
    }
2944
 
 
2945
 
    c = value[0];
2946
 
    length = strlen(value);
2947
 
    if ((c == 'n') && (strncmp(value, "none", length) == 0)) {
2948
 
        *validatePtr = VALIDATE_NONE;
2949
 
    } else if ((c == 'a') && (strncmp(value, "all", length) == 0)) {
2950
 
        *validatePtr = VALIDATE_ALL;
2951
 
    } else if ((c == 'k') && (strncmp(value, "key", length) == 0)) {
2952
 
        *validatePtr = VALIDATE_KEY;
2953
 
    } else if (strcmp(value, "focus") == 0) {
2954
 
        *validatePtr = VALIDATE_FOCUS;
2955
 
    } else if (strcmp(value, "focusin") == 0) {
2956
 
        *validatePtr = VALIDATE_FOCUSIN;
2957
 
    } else if (strcmp(value, "focusout") == 0) {
2958
 
        *validatePtr = VALIDATE_FOCUSOUT;
2959
 
    } else {
2960
 
        Tcl_AppendResult(interp, "bad validation type \"", value,
2961
 
                "\": must be none, all, key, focus, focusin, or focusout",
2962
 
                (char *) NULL);
2963
 
        return TCL_ERROR;
2964
 
    }
 
3778
    register Entry *entryPtr;
 
3779
    register Spinbox *sbPtr;
 
3780
    Tk_OptionTable optionTable;
 
3781
    Tk_Window tkwin;
 
3782
    char *tmp;
 
3783
 
 
3784
    if (objc < 2) {
 
3785
        Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
 
3786
        return TCL_ERROR;
 
3787
    }
 
3788
 
 
3789
    tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
 
3790
            Tcl_GetString(objv[1]), (char *) NULL);
 
3791
    if (tkwin == NULL) {
 
3792
        return TCL_ERROR;
 
3793
    }
 
3794
 
 
3795
    /*
 
3796
     * Create the option table for this widget class.  If it has already
 
3797
     * been created, Tk will return the cached value.
 
3798
     */
 
3799
 
 
3800
    optionTable = Tk_CreateOptionTable(interp, sbOptSpec);
 
3801
 
 
3802
    /*
 
3803
     * Initialize the fields of the structure that won't be initialized
 
3804
     * by ConfigureEntry, or that ConfigureEntry requires to be
 
3805
     * initialized already (e.g. resource pointers).  Only the non-NULL/0
 
3806
     * data must be initialized as memset covers the rest.
 
3807
     */
 
3808
 
 
3809
    sbPtr                       = (Spinbox *) ckalloc(sizeof(Spinbox));
 
3810
    entryPtr                    = (Entry *) sbPtr;
 
3811
    memset((VOID *) sbPtr, 0, sizeof(Spinbox));
 
3812
 
 
3813
    entryPtr->tkwin             = tkwin;
 
3814
    entryPtr->display           = Tk_Display(tkwin);
 
3815
    entryPtr->interp            = interp;
 
3816
    entryPtr->widgetCmd         = Tcl_CreateObjCommand(interp,
 
3817
            Tk_PathName(entryPtr->tkwin), SpinboxWidgetObjCmd,
 
3818
            (ClientData) sbPtr, EntryCmdDeletedProc);
 
3819
    entryPtr->optionTable       = optionTable;
 
3820
    entryPtr->type              = TK_SPINBOX;
 
3821
    tmp                         = (char *) ckalloc(1);
 
3822
    tmp[0]                      = '\0';
 
3823
    entryPtr->string            = tmp;
 
3824
    entryPtr->selectFirst       = -1;
 
3825
    entryPtr->selectLast        = -1;
 
3826
 
 
3827
    entryPtr->cursor            = None;
 
3828
    entryPtr->exportSelection   = 1;
 
3829
    entryPtr->justify           = TK_JUSTIFY_LEFT;
 
3830
    entryPtr->relief            = TK_RELIEF_FLAT;
 
3831
    entryPtr->state             = STATE_NORMAL;
 
3832
    entryPtr->displayString     = entryPtr->string;
 
3833
    entryPtr->inset             = XPAD;
 
3834
    entryPtr->textGC            = None;
 
3835
    entryPtr->selTextGC         = None;
 
3836
    entryPtr->highlightGC       = None;
 
3837
    entryPtr->avgWidth          = 1;
 
3838
    entryPtr->validate          = VALIDATE_NONE;
 
3839
 
 
3840
    sbPtr->selElement           = SEL_NONE;
 
3841
    sbPtr->curElement           = SEL_NONE;
 
3842
    sbPtr->bCursor              = None;
 
3843
    sbPtr->repeatDelay          = 400;
 
3844
    sbPtr->repeatInterval       = 100;
 
3845
    sbPtr->fromValue            = 0.0;
 
3846
    sbPtr->toValue              = 100.0;
 
3847
    sbPtr->increment            = 1.0;
 
3848
    sbPtr->formatBuf            = (char *) ckalloc(TCL_DOUBLE_SPACE);
 
3849
    sbPtr->bdRelief             = TK_RELIEF_FLAT;
 
3850
    sbPtr->buRelief             = TK_RELIEF_FLAT;
 
3851
 
 
3852
    /*
 
3853
     * Keep a hold of the associated tkwin until we destroy the listbox,
 
3854
     * otherwise Tk might free it while we still need it.
 
3855
     */
 
3856
 
 
3857
    Tcl_Preserve((ClientData) entryPtr->tkwin);
 
3858
 
 
3859
    Tk_SetClass(entryPtr->tkwin, "Spinbox");
 
3860
    Tk_SetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr);
 
3861
    Tk_CreateEventHandler(entryPtr->tkwin,
 
3862
            PointerMotionMask|ExposureMask|StructureNotifyMask|FocusChangeMask,
 
3863
            EntryEventProc, (ClientData) entryPtr);
 
3864
    Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING,
 
3865
            EntryFetchSelection, (ClientData) entryPtr, XA_STRING);
 
3866
 
 
3867
    if (Tk_InitOptions(interp, (char *) sbPtr, optionTable, tkwin)
 
3868
            != TCL_OK) {
 
3869
        Tk_DestroyWindow(entryPtr->tkwin);
 
3870
        return TCL_ERROR;
 
3871
    }
 
3872
    if (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK) {
 
3873
        goto error;
 
3874
    }
 
3875
 
 
3876
    Tcl_SetResult(interp, Tk_PathName(entryPtr->tkwin), TCL_STATIC);
2965
3877
    return TCL_OK;
2966
 
}
2967
 
 
2968
 
/*
2969
 
 *--------------------------------------------------------------
2970
 
 *
2971
 
 * ValidatePrintProc --
2972
 
 *
2973
 
 *      This procedure is invoked by the Tk configuration code
2974
 
 *      to produce a printable string for the "-validate" configuration
2975
 
 *      option for entry widgets.
2976
 
 *
2977
 
 * Results:
2978
 
 *      The return value is a string describing the entry
2979
 
 *      widget's current validation style.
2980
 
 *
2981
 
 * Side effects:
2982
 
 *      None.
2983
 
 *
2984
 
 *--------------------------------------------------------------
2985
 
 */
2986
 
 
2987
 
        /* ARGSUSED */
2988
 
static Arg
2989
 
ValidatePrintProc(clientData, tkwin, widgRec, offset, freeProcPtr)
2990
 
    ClientData clientData;              /* Ignored. */
2991
 
    Tk_Window tkwin;                    /* Window for text widget. */
2992
 
    char *widgRec;                      /* Pointer to widgRec structure. */
2993
 
    int offset;                         /* Ignored. */
2994
 
    Tcl_FreeProc **freeProcPtr;         /* Pointer to variable to fill in with
2995
 
                                         * information about how to reclaim
2996
 
                                         * storage for return string. */
2997
 
{
2998
 
    register int *validatePtr = (int *) (widgRec + offset);
2999
 
    Arg result = NULL;
3000
 
 
3001
 
    switch (*validatePtr) {
3002
 
        case VALIDATE_NONE:
3003
 
            return LangStringArg("none");
3004
 
        case VALIDATE_ALL:
3005
 
            return LangStringArg("all");
3006
 
        case VALIDATE_KEY:
3007
 
            return LangStringArg("key");
3008
 
        case VALIDATE_FOCUS:
3009
 
            return LangStringArg("focus");
3010
 
        case VALIDATE_FOCUSIN:
3011
 
            return LangStringArg("focusin");
3012
 
            break;
3013
 
        case VALIDATE_FOCUSOUT:
3014
 
            return LangStringArg("focusout");
 
3878
 
 
3879
    error:
 
3880
    Tk_DestroyWindow(entryPtr->tkwin);
 
3881
    return TCL_ERROR;
 
3882
}
 
3883
 
 
3884
/*
 
3885
 *--------------------------------------------------------------
 
3886
 *
 
3887
 * SpinboxWidgetObjCmd --
 
3888
 *
 
3889
 *      This procedure is invoked to process the Tcl command
 
3890
 *      that corresponds to a widget managed by this module.
 
3891
 *      See the user documentation for details on what it does.
 
3892
 *
 
3893
 * Results:
 
3894
 *      A standard Tcl result.
 
3895
 *
 
3896
 * Side effects:
 
3897
 *      See the user documentation.
 
3898
 *
 
3899
 *--------------------------------------------------------------
 
3900
 */
 
3901
 
 
3902
static int
 
3903
SpinboxWidgetObjCmd(clientData, interp, objc, objv)
 
3904
    ClientData clientData;      /* Information about spinbox widget. */
 
3905
    Tcl_Interp *interp;         /* Current interpreter. */
 
3906
    int objc;                   /* Number of arguments. */
 
3907
    Tcl_Obj *CONST objv[];      /* Argument objects. */
 
3908
{
 
3909
    Entry *entryPtr = (Entry *) clientData;
 
3910
    Spinbox *sbPtr = (Spinbox *) clientData;
 
3911
    int cmdIndex, selIndex, result;
 
3912
    Tcl_Obj *objPtr;
 
3913
 
 
3914
    if (objc < 2) {
 
3915
        Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
 
3916
        return TCL_ERROR;
 
3917
    }
 
3918
 
 
3919
    /*
 
3920
     * Parse the widget command by looking up the second token in
 
3921
     * the list of valid command names.
 
3922
     */
 
3923
 
 
3924
    result = Tcl_GetIndexFromObj(interp, objv[1], sbCmdNames,
 
3925
            "option", 0, &cmdIndex);
 
3926
    if (result != TCL_OK) {
 
3927
        return result;
 
3928
    }
 
3929
 
 
3930
    Tcl_Preserve((ClientData) entryPtr);
 
3931
    switch ((enum sbCmd) cmdIndex) {
 
3932
        case SB_CMD_BBOX: {
 
3933
            int index, x, y, width, height;
 
3934
            char buf[TCL_INTEGER_SPACE * 4];
 
3935
 
 
3936
            if (objc != 3) {
 
3937
                Tcl_WrongNumArgs(interp, 2, objv, "index");
 
3938
                goto error;
 
3939
            }
 
3940
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
3941
                    &index) != TCL_OK) {
 
3942
                goto error;
 
3943
            }
 
3944
            if ((index == entryPtr->numChars) && (index > 0)) {
 
3945
                index--;
 
3946
            }
 
3947
            Tk_CharBbox(entryPtr->textLayout, index, &x, &y,
 
3948
                    &width, &height);
 
3949
            Tcl_IntResults(interp, 4, 0,
 
3950
                    x + entryPtr->layoutX,
 
3951
                    y + entryPtr->layoutY, width, height);
 
3952
            break;
 
3953
        }
 
3954
 
 
3955
        case SB_CMD_CGET: {
 
3956
            if (objc != 3) {
 
3957
                Tcl_WrongNumArgs(interp, 2, objv, "option");
 
3958
                goto error;
 
3959
            }
 
3960
 
 
3961
            objPtr = Tk_GetOptionValue(interp, (char *) entryPtr,
 
3962
                    entryPtr->optionTable, objv[2], entryPtr->tkwin);
 
3963
            if (objPtr == NULL) {
 
3964
                 goto error;
 
3965
            } else {
 
3966
                Tcl_SetObjResult(interp, objPtr);
 
3967
            }
 
3968
            break;
 
3969
        }
 
3970
 
 
3971
        case SB_CMD_CONFIGURE: {
 
3972
            if (objc <= 3) {
 
3973
                objPtr = Tk_GetOptionInfo(interp, (char *) entryPtr,
 
3974
                        entryPtr->optionTable,
 
3975
                        (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
 
3976
                        entryPtr->tkwin);
 
3977
                if (objPtr == NULL) {
 
3978
                    goto error;
 
3979
                } else {
 
3980
                    Tcl_SetObjResult(interp, objPtr);
 
3981
                }
 
3982
            } else {
 
3983
                result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0);
 
3984
            }
 
3985
            break;
 
3986
        }
 
3987
 
 
3988
        case SB_CMD_DELETE: {
 
3989
            int first, last;
 
3990
 
 
3991
            if ((objc < 3) || (objc > 4)) {
 
3992
                Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
 
3993
                goto error;
 
3994
            }
 
3995
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
3996
                    &first) != TCL_OK) {
 
3997
                goto error;
 
3998
            }
 
3999
            if (objc == 3) {
 
4000
                last = first + 1;
 
4001
            } else {
 
4002
                if (GetEntryIndex(interp, entryPtr, objv[3],
 
4003
                        &last) != TCL_OK) {
 
4004
                    goto error;
 
4005
                }
 
4006
            }
 
4007
            if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
 
4008
                DeleteChars(entryPtr, first, last - first);
 
4009
            }
 
4010
            break;
 
4011
        }
 
4012
 
 
4013
        case SB_CMD_GET: {
 
4014
            if (objc != 2) {
 
4015
                Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
 
4016
                goto error;
 
4017
            }
 
4018
            Tcl_SetStringObj(Tcl_GetObjResult(interp), entryPtr->string, -1);
 
4019
            break;
 
4020
        }
 
4021
 
 
4022
        case SB_CMD_ICURSOR: {
 
4023
            if (objc != 3) {
 
4024
                Tcl_WrongNumArgs(interp, 2, objv, "pos");
 
4025
                goto error;
 
4026
            }
 
4027
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
4028
                    &entryPtr->insertPos) != TCL_OK) {
 
4029
                goto error;
 
4030
            }
 
4031
            EventuallyRedraw(entryPtr);
 
4032
            break;
 
4033
        }
 
4034
 
 
4035
        case SB_CMD_IDENTIFY: {
 
4036
            int x, y, elem;
 
4037
 
 
4038
            if (objc != 4) {
 
4039
                Tcl_WrongNumArgs(interp, 2, objv, "x y");
 
4040
                goto error;
 
4041
            }
 
4042
            if ((Tcl_GetIntFromObj(interp, objv[2], &x) != TCL_OK) ||
 
4043
                    (Tcl_GetIntFromObj(interp, objv[3], &y) != TCL_OK)) {
 
4044
                goto error;
 
4045
            }
 
4046
            elem = GetSpinboxElement(sbPtr, x, y);
 
4047
            if (elem != SEL_NONE) {
 
4048
                Tcl_SetStringObj(Tcl_GetObjResult(interp),
 
4049
                        selElementNames[elem], -1);
 
4050
            }
 
4051
            break;
 
4052
        }
 
4053
 
 
4054
        case SB_CMD_INDEX: {
 
4055
            int index;
 
4056
 
 
4057
            if (objc != 3) {
 
4058
                Tcl_WrongNumArgs(interp, 2, objv, "string");
 
4059
                goto error;
 
4060
            }
 
4061
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
4062
                    &index) != TCL_OK) {
 
4063
                goto error;
 
4064
            }
 
4065
            Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
 
4066
            break;
 
4067
        }
 
4068
 
 
4069
        case SB_CMD_INSERT: {
 
4070
            int index;
 
4071
 
 
4072
            if (objc != 4) {
 
4073
                Tcl_WrongNumArgs(interp, 2, objv, "index text");
 
4074
                goto error;
 
4075
            }
 
4076
            if (GetEntryIndex(interp, entryPtr, objv[2],
 
4077
                    &index) != TCL_OK) {
 
4078
                goto error;
 
4079
            }
 
4080
            if (entryPtr->state == STATE_NORMAL) {
 
4081
                InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
 
4082
            }
 
4083
            break;
 
4084
        }
 
4085
 
 
4086
        case SB_CMD_INVOKE: {
 
4087
            if (objc != 3) {
 
4088
                Tcl_WrongNumArgs(interp, 2, objv, "elemName");
 
4089
                goto error;
 
4090
            }
 
4091
            result = Tcl_GetIndexFromObj(interp, objv[2],
 
4092
                    selElementNames, "element", 0, &cmdIndex);
 
4093
            if (result != TCL_OK) {
 
4094
                goto error;
 
4095
            }
 
4096
            if (entryPtr->state != STATE_DISABLED) {
 
4097
                if (SpinboxInvoke(interp, sbPtr, cmdIndex) != TCL_OK) {
 
4098
                    goto error;
 
4099
                }
 
4100
            }
 
4101
            break;
 
4102
        }
 
4103
 
 
4104
        case SB_CMD_SCAN: {
 
4105
            int x;
 
4106
            char *minorCmd;
 
4107
 
 
4108
            if (objc != 4) {
 
4109
                Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x");
 
4110
                goto error;
 
4111
            }
 
4112
            if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
 
4113
                goto error;
 
4114
            }
 
4115
 
 
4116
            minorCmd = Tcl_GetString(objv[2]);
 
4117
            if (minorCmd[0] == 'm'
 
4118
                    && (strncmp(minorCmd, "mark", strlen(minorCmd)) == 0)) {
 
4119
                entryPtr->scanMarkX = x;
 
4120
                entryPtr->scanMarkIndex = entryPtr->leftIndex;
 
4121
            } else if ((minorCmd[0] == 'd')
 
4122
                && (strncmp(minorCmd, "dragto", strlen(minorCmd)) == 0)) {
 
4123
                EntryScanTo(entryPtr, x);
 
4124
            } else {
 
4125
                Tcl_AppendResult(interp, "bad scan option \"",
 
4126
                        Tcl_GetString(objv[2]), "\": must be mark or dragto",
 
4127
                        (char *) NULL);
 
4128
                goto error;
 
4129
            }
 
4130
            break;
 
4131
        }
 
4132
 
 
4133
        case SB_CMD_SELECTION: {
 
4134
            int index, index2;
 
4135
 
 
4136
            if (objc < 3) {
 
4137
                Tcl_WrongNumArgs(interp, 2, objv, "option ?index?");
 
4138
                goto error;
 
4139
            }
 
4140
 
 
4141
            /*
 
4142
             * Parse the selection sub-command, using the command
 
4143
             * table "sbSelCmdNames" defined above.
 
4144
             */
 
4145
 
 
4146
            result = Tcl_GetIndexFromObj(interp, objv[2], sbSelCmdNames,
 
4147
                    "selection option", 0, &selIndex);
 
4148
            if (result != TCL_OK) {
 
4149
                goto error;
 
4150
            }
 
4151
 
 
4152
            /*
 
4153
             * Disabled entries don't allow the selection to be modified,
 
4154
             * but 'selection present' must return a boolean.
 
4155
             */
 
4156
 
 
4157
            if ((entryPtr->state == STATE_DISABLED)
 
4158
                    && (selIndex != SB_SEL_PRESENT)) {
 
4159
                goto done;
 
4160
            }
 
4161
 
 
4162
            switch (selIndex) {
 
4163
                case SB_SEL_ADJUST: {
 
4164
                    if (objc != 4) {
 
4165
                        Tcl_WrongNumArgs(interp, 3, objv, "index");
 
4166
                        goto error;
 
4167
                    }
 
4168
                    if (GetEntryIndex(interp, entryPtr,
 
4169
                            objv[3], &index) != TCL_OK) {
 
4170
                        goto error;
 
4171
                    }
 
4172
                    if (entryPtr->selectFirst >= 0) {
 
4173
                        int half1, half2;
 
4174
 
 
4175
                        half1 = (entryPtr->selectFirst
 
4176
                                + entryPtr->selectLast)/2;
 
4177
                        half2 = (entryPtr->selectFirst
 
4178
                                + entryPtr->selectLast + 1)/2;
 
4179
                        if (index < half1) {
 
4180
                            entryPtr->selectAnchor = entryPtr->selectLast;
 
4181
                        } else if (index > half2) {
 
4182
                            entryPtr->selectAnchor = entryPtr->selectFirst;
 
4183
                        } else {
 
4184
                          /*
 
4185
                           * We're at about the halfway point in the
 
4186
                           * selection; just keep the existing anchor.
 
4187
                           */
 
4188
                        }
 
4189
                    }
 
4190
                    EntrySelectTo(entryPtr, index);
 
4191
                    break;
 
4192
                }
 
4193
 
 
4194
                case SB_SEL_CLEAR: {
 
4195
                    if (objc != 3) {
 
4196
                        Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
 
4197
                        goto error;
 
4198
                    }
 
4199
                    if (entryPtr->selectFirst >= 0) {
 
4200
                        entryPtr->selectFirst = -1;
 
4201
                        entryPtr->selectLast = -1;
 
4202
                        EventuallyRedraw(entryPtr);
 
4203
                    }
 
4204
                    goto done;
 
4205
                }
 
4206
 
 
4207
                case SB_SEL_FROM: {
 
4208
                    if (objc != 4) {
 
4209
                        Tcl_WrongNumArgs(interp, 3, objv, "index");
 
4210
                        goto error;
 
4211
                    }
 
4212
                    if (GetEntryIndex(interp, entryPtr,
 
4213
                            objv[3], &index) != TCL_OK) {
 
4214
                        goto error;
 
4215
                    }
 
4216
                    entryPtr->selectAnchor = index;
 
4217
                    break;
 
4218
                }
 
4219
 
 
4220
                case SB_SEL_PRESENT: {
 
4221
                    if (objc != 3) {
 
4222
                        Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
 
4223
                        goto error;
 
4224
                    }
 
4225
                    Tcl_SetObjResult(interp,
 
4226
                            Tcl_NewBooleanObj((entryPtr->selectFirst >= 0)));
 
4227
                    goto done;
 
4228
                }
 
4229
 
 
4230
                case SB_SEL_RANGE: {
 
4231
                    if (objc != 5) {
 
4232
                        Tcl_WrongNumArgs(interp, 3, objv, "start end");
 
4233
                        goto error;
 
4234
                    }
 
4235
                    if (GetEntryIndex(interp, entryPtr,
 
4236
                            objv[3], &index) != TCL_OK) {
 
4237
                        goto error;
 
4238
                    }
 
4239
                    if (GetEntryIndex(interp, entryPtr,
 
4240
                            objv[4],& index2) != TCL_OK) {
 
4241
                        goto error;
 
4242
                    }
 
4243
                    if (index >= index2) {
 
4244
                        entryPtr->selectFirst = -1;
 
4245
                        entryPtr->selectLast = -1;
 
4246
                    } else {
 
4247
                        entryPtr->selectFirst = index;
 
4248
                        entryPtr->selectLast = index2;
 
4249
                    }
 
4250
                    if (!(entryPtr->flags & GOT_SELECTION)
 
4251
                            && (entryPtr->exportSelection)) {
 
4252
                        Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
 
4253
                                EntryLostSelection, (ClientData) entryPtr);
 
4254
                        entryPtr->flags |= GOT_SELECTION;
 
4255
                    }
 
4256
                    EventuallyRedraw(entryPtr);
 
4257
                    break;
 
4258
                }
 
4259
 
 
4260
                case SB_SEL_TO: {
 
4261
                    if (objc != 4) {
 
4262
                        Tcl_WrongNumArgs(interp, 3, objv, "index");
 
4263
                        goto error;
 
4264
                    }
 
4265
                    if (GetEntryIndex(interp, entryPtr,
 
4266
                            objv[3], &index) != TCL_OK) {
 
4267
                        goto error;
 
4268
                    }
 
4269
                    EntrySelectTo(entryPtr, index);
 
4270
                    break;
 
4271
                }
 
4272
 
 
4273
                case SB_SEL_ELEMENT: {
 
4274
                    if ((objc < 3) || (objc > 4)) {
 
4275
                        Tcl_WrongNumArgs(interp, 3, objv, "?elemName?");
 
4276
                        goto error;
 
4277
                    }
 
4278
                    if (objc == 3) {
 
4279
                        Tcl_SetStringObj(Tcl_GetObjResult(interp),
 
4280
                                selElementNames[sbPtr->selElement], -1);
 
4281
                    } else {
 
4282
                        int lastElement = sbPtr->selElement;
 
4283
 
 
4284
                        result = Tcl_GetIndexFromObj(interp, objv[3],
 
4285
                                selElementNames, "selection element", 0,
 
4286
                                &(sbPtr->selElement));
 
4287
                        if (result != TCL_OK) {
 
4288
                            goto error;
 
4289
                        }
 
4290
                        if (lastElement != sbPtr->selElement) {
 
4291
                            EventuallyRedraw(entryPtr);
 
4292
                        }
 
4293
                    }
 
4294
                    break;
 
4295
                }
 
4296
            }
 
4297
            break;
 
4298
        }
 
4299
 
 
4300
        case SB_CMD_SET: {
 
4301
            if (objc > 3) {
 
4302
                Tcl_WrongNumArgs(interp, 2, objv, "?string?");
 
4303
                goto error;
 
4304
            }
 
4305
            if (objc == 3) {
 
4306
                EntryValueChanged(entryPtr, Tcl_GetString(objv[2]));
 
4307
            }
 
4308
            Tcl_SetStringObj(Tcl_GetObjResult(interp), entryPtr->string, -1);
 
4309
            break;
 
4310
        }
 
4311
 
 
4312
        case SB_CMD_VALIDATE: {
 
4313
            int code;
 
4314
 
 
4315
            if (objc != 2) {
 
4316
                Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
 
4317
                goto error;
 
4318
            }
 
4319
            selIndex = entryPtr->validate;
 
4320
            entryPtr->validate = VALIDATE_ALL;
 
4321
            code = EntryValidateChange(entryPtr, (char *) NULL,
 
4322
                    entryPtr->string, -1, VALIDATE_FORCED);
 
4323
            if (entryPtr->validate != VALIDATE_NONE) {
 
4324
                entryPtr->validate = selIndex;
 
4325
            }
 
4326
            Tcl_SetObjResult(interp, Tcl_NewBooleanObj((code == TCL_OK)));
 
4327
            break;
 
4328
        }
 
4329
 
 
4330
        case SB_CMD_XVIEW: {
 
4331
            int index;
 
4332
 
 
4333
            if (objc == 2) {
 
4334
                double first, last;
 
4335
                char buf[TCL_DOUBLE_SPACE * 2];
 
4336
 
 
4337
                EntryVisibleRange(entryPtr, &first, &last);
 
4338
                sprintf(buf, "%g %g", first, last);
 
4339
                Tcl_SetResult(interp, buf, TCL_VOLATILE);
 
4340
                goto done;
 
4341
            } else if (objc == 3) {
 
4342
                if (GetEntryIndex(interp, entryPtr, objv[2],
 
4343
                        &index) != TCL_OK) {
 
4344
                    goto error;
 
4345
                }
 
4346
            } else {
 
4347
                double fraction;
 
4348
                int count;
 
4349
 
 
4350
                index = entryPtr->leftIndex;
 
4351
                switch (Tk_GetScrollInfoObj(interp, objc, objv, &fraction,
 
4352
                        &count)) {
 
4353
                    case TK_SCROLL_ERROR: {
 
4354
                        goto error;
 
4355
                    }
 
4356
                    case TK_SCROLL_MOVETO: {
 
4357
                        index = (int) ((fraction * entryPtr->numChars) + 0.5);
 
4358
                        break;
 
4359
                    }
 
4360
                    case TK_SCROLL_PAGES: {
 
4361
                        int charsPerPage;
 
4362
 
 
4363
                        charsPerPage = ((Tk_Width(entryPtr->tkwin)
 
4364
                                - 2 * entryPtr->inset - entryPtr->xWidth)
 
4365
                                / entryPtr->avgWidth) - 2;
 
4366
                        if (charsPerPage < 1) {
 
4367
                            charsPerPage = 1;
 
4368
                        }
 
4369
                        index += count * charsPerPage;
 
4370
                        break;
 
4371
                    }
 
4372
                    case TK_SCROLL_UNITS: {
 
4373
                        index += count;
 
4374
                        break;
 
4375
                    }
 
4376
                }
 
4377
            }
 
4378
            if (index >= entryPtr->numChars) {
 
4379
                index = entryPtr->numChars - 1;
 
4380
            }
 
4381
            if (index < 0) {
 
4382
                index = 0;
 
4383
            }
 
4384
            entryPtr->leftIndex = index;
 
4385
            entryPtr->flags |= UPDATE_SCROLLBAR;
 
4386
            EntryComputeGeometry(entryPtr);
 
4387
            EventuallyRedraw(entryPtr);
 
4388
            break;
 
4389
        }
 
4390
    }
 
4391
 
 
4392
    done:
 
4393
    Tcl_Release((ClientData) entryPtr);
 
4394
    return result;
 
4395
 
 
4396
    error:
 
4397
    Tcl_Release((ClientData) entryPtr);
 
4398
    return TCL_ERROR;
 
4399
}
 
4400
 
 
4401
/*
 
4402
 *---------------------------------------------------------------------------
 
4403
 *
 
4404
 * GetSpinboxElement --
 
4405
 *
 
4406
 *      Return the element associated with an x,y coord.
 
4407
 *
 
4408
 * Results:
 
4409
 *      Element type as enum selelement.
 
4410
 *
 
4411
 * Side effects:
 
4412
 *      None.
 
4413
 *
 
4414
 *---------------------------------------------------------------------------
 
4415
 */
 
4416
 
 
4417
static int
 
4418
GetSpinboxElement(sbPtr, x, y)
 
4419
    Spinbox *sbPtr;             /* Spinbox for which the index is being
 
4420
                                 * specified. */
 
4421
    int x;                      /* x coord */
 
4422
    int y;                      /* y coord */
 
4423
{
 
4424
    Entry *entryPtr = (Entry *) sbPtr;
 
4425
 
 
4426
    if ((x < 0) || (y < 0) || (y > Tk_Height(entryPtr->tkwin))
 
4427
            || (x > Tk_Width(entryPtr->tkwin))) {
 
4428
        return SEL_NONE;
 
4429
    }
 
4430
 
 
4431
    if (x > (Tk_Width(entryPtr->tkwin) - entryPtr->inset - entryPtr->xWidth)) {
 
4432
        if (y > (Tk_Height(entryPtr->tkwin) / 2)) {
 
4433
            return SEL_BUTTONDOWN;
 
4434
        } else {
 
4435
            return SEL_BUTTONUP;
 
4436
        }
 
4437
    }
 
4438
    return SEL_ENTRY;
 
4439
}
 
4440
 
 
4441
/*
 
4442
 *--------------------------------------------------------------
 
4443
 *
 
4444
 * SpinboxInvoke --
 
4445
 *
 
4446
 *      This procedure is invoked when the invoke method for the
 
4447
 *      widget is called.
 
4448
 *
 
4449
 * Results:
 
4450
 *      TCL_OK.
 
4451
 *
 
4452
 * Side effects:
 
4453
 *      An background error condition may arise when invoking the
 
4454
 *      callback.  The widget value may change.
 
4455
 *
 
4456
 *--------------------------------------------------------------
 
4457
 */
 
4458
 
 
4459
static int
 
4460
SpinboxInvoke(interp, sbPtr, element)
 
4461
    register Tcl_Interp *interp;        /* Current interpreter. */
 
4462
    register Spinbox *sbPtr;            /* Spinbox to invoke. */
 
4463
    int element;                        /* element to invoke, either the "up"
 
4464
                                         * or "down" button. */
 
4465
{
 
4466
    Entry *entryPtr = (Entry *) sbPtr;
 
4467
    char *type;
 
4468
    int code, up;
 
4469
    Tcl_DString script;
 
4470
 
 
4471
    switch (element) {
 
4472
        case SEL_BUTTONUP:
 
4473
            type = "up";
 
4474
            up = 1;
 
4475
            break;
 
4476
        case SEL_BUTTONDOWN:
 
4477
            type = "down";
 
4478
            up = 0;
3015
4479
            break;
3016
4480
        default:
3017
 
            return NULL;
3018
 
    }
3019
 
}
3020
 
#endif /* ENTRY_VALIDATE */
 
4481
            return TCL_OK;
 
4482
    }
 
4483
 
 
4484
    if (fabs(sbPtr->increment) > MIN_DBL_VAL) {
 
4485
        if (sbPtr->listObj != NULL) {
 
4486
            Tcl_Obj *objPtr;
 
4487
 
 
4488
            Tcl_ListObjIndex(interp, sbPtr->listObj, sbPtr->eIndex, &objPtr);
 
4489
            if (strcmp(Tcl_GetString(objPtr), entryPtr->string)) {
 
4490
                /*
 
4491
                 * Somehow the string changed from what we expected,
 
4492
                 * so let's do a search on the list to see if the current
 
4493
                 * value is there.  If not, move to the first element of
 
4494
                 * the list.
 
4495
                 */
 
4496
                int i, listc, elemLen, length = entryPtr->numChars;
 
4497
                char *bytes;
 
4498
                Tcl_Obj **listv;
 
4499
 
 
4500
                Tcl_ListObjGetElements(interp, sbPtr->listObj, &listc, &listv);
 
4501
                for (i = 0; i < listc; i++) {
 
4502
                    bytes = Tcl_GetStringFromObj(listv[i], &elemLen);
 
4503
                    if ((length == elemLen) &&
 
4504
                            (memcmp(bytes, entryPtr->string,
 
4505
                                    (size_t) length) == 0)) {
 
4506
                        sbPtr->eIndex = i;
 
4507
                        break;
 
4508
                    }
 
4509
                }
 
4510
            }
 
4511
            if (up) {
 
4512
                if (++sbPtr->eIndex >= sbPtr->nElements) {
 
4513
                    if (sbPtr->wrap) {
 
4514
                        sbPtr->eIndex = 0;
 
4515
                    } else {
 
4516
                        sbPtr->eIndex = sbPtr->nElements-1;
 
4517
                    }
 
4518
                }
 
4519
            } else {
 
4520
                if (--sbPtr->eIndex < 0) {
 
4521
                    if (sbPtr->wrap) {
 
4522
                        sbPtr->eIndex = sbPtr->nElements-1;
 
4523
                    } else {
 
4524
                        sbPtr->eIndex = 0;
 
4525
                    }
 
4526
                }
 
4527
            }
 
4528
            Tcl_ListObjIndex(interp, sbPtr->listObj, sbPtr->eIndex, &objPtr);
 
4529
            EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
 
4530
        } else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) {
 
4531
            double dvalue;
 
4532
 
 
4533
            if (Tcl_GetDouble(NULL, entryPtr->string, &dvalue) != TCL_OK) {
 
4534
                /*
 
4535
                 * If the string is empty, or isn't a valid double value,
 
4536
                 * just use the -from value
 
4537
                 */
 
4538
                dvalue = sbPtr->fromValue;
 
4539
            } else {
 
4540
                if (up) {
 
4541
                    dvalue += sbPtr->increment;
 
4542
                    if (dvalue > sbPtr->toValue) {
 
4543
                        if (sbPtr->wrap) {
 
4544
                            dvalue = sbPtr->fromValue;
 
4545
                        } else {
 
4546
                            dvalue = sbPtr->toValue;
 
4547
                        }
 
4548
                    } else if (dvalue < sbPtr->fromValue) {
 
4549
                        /*
 
4550
                         * It's possible that when pressing up, we are
 
4551
                         * still less than the fromValue, because the
 
4552
                         * user may have manipulated the value by hand.
 
4553
                         */
 
4554
                        dvalue = sbPtr->fromValue;
 
4555
                    }
 
4556
                } else {
 
4557
                    dvalue -= sbPtr->increment;
 
4558
                    if (dvalue < sbPtr->fromValue) {
 
4559
                        if (sbPtr->wrap) {
 
4560
                            dvalue = sbPtr->toValue;
 
4561
                        } else {
 
4562
                            dvalue = sbPtr->fromValue;
 
4563
                        }
 
4564
                    } else if (dvalue > sbPtr->toValue) {
 
4565
                        /*
 
4566
                         * It's possible that when pressing down, we are
 
4567
                         * still greater than the toValue, because the
 
4568
                         * user may have manipulated the value by hand.
 
4569
                         */
 
4570
                        dvalue = sbPtr->toValue;
 
4571
                    }
 
4572
                }
 
4573
            }
 
4574
            sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
 
4575
            EntryValueChanged(entryPtr, sbPtr->formatBuf);
 
4576
        }
 
4577
    }
 
4578
 
 
4579
    if (sbPtr->command != NULL) {
 
4580
#ifndef _LANG
 
4581
        Tcl_DStringInit(&script);
 
4582
        ExpandPercents(entryPtr, sbPtr->command, type, "", 0,
 
4583
                VALIDATE_BUTTON, &script);
 
4584
        Tcl_DStringAppend(&script, "", 1);
 
4585
 
 
4586
        code = Tcl_EvalEx(interp, Tcl_DStringValue(&script), -1,
 
4587
                TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
 
4588
        Tcl_DStringFree(&script);
 
4589
#else
 
4590
        code = LangDoCallback(entryPtr->interp, sbPtr->command, 1, 2,
 
4591
                              " %s %s", entryPtr->string, type);
 
4592
#endif
 
4593
 
 
4594
        if (code != TCL_OK) {
 
4595
            Tcl_AddErrorInfo(interp, "\n\t(in command executed by spinbox)");
 
4596
            Tcl_BackgroundError(interp);
 
4597
            /*
 
4598
             * Yes, it's an error, but a bg one, so we return OK
 
4599
             */
 
4600
            return TCL_OK;
 
4601
        }
 
4602
 
 
4603
        Tcl_SetResult(interp, NULL, 0);
 
4604
    }
 
4605
 
 
4606
    return TCL_OK;
 
4607
}
 
4608
 
 
4609
/*
 
4610
 *----------------------------------------------------------------------
 
4611
 *
 
4612
 * ComputeFormat --
 
4613
 *
 
4614
 *      This procedure is invoked to recompute the "format" fields
 
4615
 *      of a spinbox's widget record, which determines how the value
 
4616
 *      of the dial is converted to a string.
 
4617
 *
 
4618
 * Results:
 
4619
 *      Tcl result code.
 
4620
 *
 
4621
 * Side effects:
 
4622
 *      The format fields of the spinbox are modified.
 
4623
 *
 
4624
 *----------------------------------------------------------------------
 
4625
 */
 
4626
static int
 
4627
ComputeFormat(sbPtr)
 
4628
     Spinbox *sbPtr;                    /* Information about dial widget. */
 
4629
{
 
4630
    double maxValue, x;
 
4631
    int mostSigDigit, numDigits, leastSigDigit, afterDecimal;
 
4632
    int eDigits, fDigits;
 
4633
 
 
4634
    /*
 
4635
     * Compute the displacement from the decimal of the most significant
 
4636
     * digit required for any number in the dial's range.
 
4637
     */
 
4638
 
 
4639
    if (sbPtr->reqFormat) {
 
4640
        sbPtr->valueFormat = sbPtr->reqFormat;
 
4641
        return TCL_OK;
 
4642
    }
 
4643
 
 
4644
    maxValue = fabs(sbPtr->fromValue);
 
4645
    x = fabs(sbPtr->toValue);
 
4646
    if (x > maxValue) {
 
4647
        maxValue = x;
 
4648
    }
 
4649
    if (maxValue == 0) {
 
4650
        maxValue = 1;
 
4651
    }
 
4652
    mostSigDigit = (int) floor(log10(maxValue));
 
4653
 
 
4654
    if (fabs(sbPtr->increment) > MIN_DBL_VAL) {
 
4655
        /*
 
4656
         * A increment was specified, so use it.
 
4657
         */
 
4658
        leastSigDigit = (int) floor(log10(sbPtr->increment));
 
4659
    } else {
 
4660
        leastSigDigit = 0;
 
4661
    }
 
4662
    numDigits = mostSigDigit - leastSigDigit + 1;
 
4663
    if (numDigits < 1) {
 
4664
        numDigits = 1;
 
4665
    }
 
4666
 
 
4667
    /*
 
4668
     * Compute the number of characters required using "e" format and
 
4669
     * "f" format, and then choose whichever one takes fewer characters.
 
4670
     */
 
4671
 
 
4672
    eDigits = numDigits + 4;
 
4673
    if (numDigits > 1) {
 
4674
        eDigits++;                      /* Decimal point. */
 
4675
    }
 
4676
    afterDecimal = numDigits - mostSigDigit - 1;
 
4677
    if (afterDecimal < 0) {
 
4678
        afterDecimal = 0;
 
4679
    }
 
4680
    fDigits = (mostSigDigit >= 0) ? mostSigDigit + afterDecimal : afterDecimal;
 
4681
    if (afterDecimal > 0) {
 
4682
        fDigits++;                      /* Decimal point. */
 
4683
    }
 
4684
    if (mostSigDigit < 0) {
 
4685
        fDigits++;                      /* Zero to left of decimal point. */
 
4686
    }
 
4687
    if (fDigits <= eDigits) {
 
4688
        sprintf(sbPtr->digitFormat, "%%.%df", afterDecimal);
 
4689
    } else {
 
4690
        sprintf(sbPtr->digitFormat, "%%.%de", numDigits-1);
 
4691
    }
 
4692
    sbPtr->valueFormat = sbPtr->digitFormat;
 
4693
    return TCL_OK;
 
4694
}
 
4695
 
 
4696
 
 
4697
 
 
4698
 
 
4699
 
 
4700