summaryrefslogtreecommitdiff
path: root/tk/generic/tkEntry.c
diff options
context:
space:
mode:
Diffstat (limited to 'tk/generic/tkEntry.c')
-rw-r--r--tk/generic/tkEntry.c2103
1 files changed, 1393 insertions, 710 deletions
diff --git a/tk/generic/tkEntry.c b/tk/generic/tkEntry.c
index 86da2fd92e2..6ed11d6f9b7 100644
--- a/tk/generic/tkEntry.c
+++ b/tk/generic/tkEntry.c
@@ -6,7 +6,7 @@
* the string to be edited.
*
* Copyright (c) 1990-1994 The Regents of the University of California.
- * Copyright (c) 1994-1996 Sun Microsystems, Inc.
+ * Copyright (c) 1994-1997 Sun Microsystems, Inc.
*
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
@@ -32,6 +32,9 @@ typedef struct {
* freed even after tkwin has gone away. */
Tcl_Interp *interp; /* Interpreter associated with entry. */
Tcl_Command widgetCmd; /* Token for entry's widget command. */
+ Tk_OptionTable optionTable; /* Table that defines configuration options
+ * available for this widget. */
+
/*
* Fields that are set by widget commands other than "configure".
@@ -39,17 +42,17 @@ typedef struct {
char *string; /* Pointer to storage for string;
* NULL-terminated; malloc-ed. */
- int insertPos; /* Index of character before which next
- * typed character will be inserted. */
+ int insertPos; /* Character index before which next typed
+ * character will be inserted. */
/*
* Information about what's selected, if any.
*/
- int selectFirst; /* Index of first selected character (-1 means
- * nothing selected. */
- int selectLast; /* Index of last selected character (-1 means
- * nothing selected. */
+ int selectFirst; /* Character index of first selected
+ * character (-1 means nothing selected. */
+ int selectLast; /* Character index just after last selected
+ * character (-1 means nothing selected. */
int selectAnchor; /* Fixed end of selection (i.e. "select to"
* operation will use this as one end of the
* selection). */
@@ -60,8 +63,8 @@ typedef struct {
int scanMarkX; /* X-position at which scan started (e.g.
* button was pressed here). */
- int scanMarkIndex; /* Index of character that was at left of
- * window when scan started. */
+ int scanMarkIndex; /* Character index of character that was at
+ * left of window when scan started. */
/*
* Configuration settings that are updated by Tk_ConfigureWidget.
@@ -99,7 +102,7 @@ typedef struct {
char *showChar; /* Value of -show option. If non-NULL, first
* character is used for displaying all
* characters in entry. Malloc'ed. */
- Tk_Uid state; /* Normal or disabled. Entry is read-only
+ int state; /* Normal or disabled. Entry is read-only
* when disabled. */
char *textVarName; /* Name of variable (malloc'ed) or NULL.
* If non-NULL, entry's string tracks the
@@ -118,20 +121,27 @@ typedef struct {
* configuration settings above.
*/
- int numChars; /* Number of non-NULL characters in
- * string (may be 0). */
- char *displayString; /* If non-NULL, points to string with same
+ int numBytes; /* Length of string in bytes. */
+ int numChars; /* Length of string in characters. Both
+ * string and displayString have the same
+ * character length, but may have different
+ * byte lengths due to being made from
+ * different UTF-8 characters. */
+ char *displayString; /* String to use when displaying. This may
+ * be a pointer to string, or a pointer to
+ * malloced memory with the same character
* length as string but whose characters
- * are all equal to showChar. Malloc'ed. */
+ * are all equal to showChar. */
+ int numDisplayBytes; /* Length of displayString in bytes. */
int inset; /* Number of pixels on the left and right
* sides that are taken up by XPAD, borderWidth
* (if any), and highlightWidth (if any). */
Tk_TextLayout textLayout; /* Cached text layout information. */
int layoutX, layoutY; /* Origin for layout. */
- int leftIndex; /* Index of left-most character visible in
- * window. */
int leftX; /* X position at which character at leftIndex
* is drawn (varies depending on justify). */
+ int leftIndex; /* Character index of left-most character
+ * visible in window. */
Tcl_TimerToken insertBlinkHandler;
/* Timer handler used to blink cursor on and
* off. */
@@ -141,6 +151,14 @@ typedef struct {
int avgWidth; /* Width of average character. */
int flags; /* Miscellaneous flags; see below for
* definitions. */
+ Tk_TSOffset tsoffset;
+
+ char *validateCmd; /* Command prefix to use when invoking
+ * validate command. NULL means don't
+ * invoke commands. Malloc'ed. */
+ int validate; /* Non-zero means try to validate */
+ char *invalidCmd; /* Command called when a validation returns 0
+ * (successfully fails), defaults to {}. */
} Entry;
/*
@@ -159,6 +177,12 @@ typedef struct {
* UPDATE_SCROLLBAR: Non-zero means scrollbar should be updated
* during next redisplay operation.
* GOT_SELECTION: Non-zero means we've claimed the selection.
+ * ENTRY_DELETED: This entry has been effectively destroyed.
+ * VALIDATING: Non-zero means we are in a validateCmd
+ * VALIDATE_VAR: Non-zero means we are attempting to validate
+ * the entry's textvariable with validateCmd
+ * VALIDATE_ABORT: Non-zero if validatecommand signals an abort
+ * for current procedure and make no changes
*/
#define REDRAW_PENDING 1
@@ -167,6 +191,10 @@ typedef struct {
#define GOT_FOCUS 8
#define UPDATE_SCROLLBAR 0x10
#define GOT_SELECTION 0x20
+#define ENTRY_DELETED 0x40
+#define VALIDATING 0x80
+#define VALIDATE_VAR 0x100
+#define VALIDATE_ABORT 0x200
/*
* The following macro defines how many extra pixels to leave on each
@@ -177,93 +205,139 @@ typedef struct {
#define YPAD 1
/*
+ * The following enum is used to define a type for the -state option
+ * of the Entry widget. These values are used as indices into the
+ * string table below.
+ */
+
+enum state {
+ STATE_DISABLED, STATE_NORMAL
+};
+
+static char *stateStrings[] = {
+ "disabled", "normal", (char *) NULL
+};
+
+/*
+ * Definitions for -validate option values:
+ */
+
+static char *validateStrings[] = {
+ "all", "key", "focus", "focusin", "focusout", "none", (char *) NULL
+};
+enum validateType {
+ VALIDATE_ALL, VALIDATE_KEY, VALIDATE_FOCUS,
+ VALIDATE_FOCUSIN, VALIDATE_FOCUSOUT, VALIDATE_NONE,
+ /*
+ * These extra enums are for use with EntryValidateChange
+ */
+ VALIDATE_FORCED, VALIDATE_DELETE, VALIDATE_INSERT
+};
+#define DEF_ENTRY_VALIDATE "none"
+#define DEF_ENTRY_INVALIDCMD ""
+
+/*
* Information used for argv parsing.
*/
-static Tk_ConfigSpec configSpecs[] = {
- {TK_CONFIG_BORDER, "-background", "background", "Background",
- DEF_ENTRY_BG_COLOR, Tk_Offset(Entry, normalBorder),
- TK_CONFIG_COLOR_ONLY},
- {TK_CONFIG_BORDER, "-background", "background", "Background",
- DEF_ENTRY_BG_MONO, Tk_Offset(Entry, normalBorder),
- TK_CONFIG_MONO_ONLY},
- {TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
- (char *) NULL, 0, 0},
- {TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
- (char *) NULL, 0, 0},
- {TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
- DEF_ENTRY_BORDER_WIDTH, Tk_Offset(Entry, borderWidth), 0},
- {TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
- DEF_ENTRY_CURSOR, Tk_Offset(Entry, cursor), TK_CONFIG_NULL_OK},
- {TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection",
- "ExportSelection", DEF_ENTRY_EXPORT_SELECTION,
- Tk_Offset(Entry, exportSelection), 0},
- {TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
- (char *) NULL, 0, 0},
- {TK_CONFIG_FONT, "-font", "font", "Font",
- DEF_ENTRY_FONT, Tk_Offset(Entry, tkfont), 0},
- {TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
- DEF_ENTRY_FG, Tk_Offset(Entry, fgColorPtr), 0},
- {TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
+static Tk_OptionSpec optionSpecs[] = {
+ {TK_OPTION_BORDER, "-background", "background", "Background",
+ DEF_ENTRY_BG_COLOR, -1, Tk_Offset(Entry, normalBorder),
+ 0, (ClientData) DEF_ENTRY_BG_MONO, 0},
+ {TK_OPTION_SYNONYM, "-bd", (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, (ClientData) "-borderwidth", 0},
+ {TK_OPTION_SYNONYM, "-bg", (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, (ClientData) "-background", 0},
+ {TK_OPTION_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
+ DEF_ENTRY_BORDER_WIDTH, -1, Tk_Offset(Entry, borderWidth),
+ 0, 0, 0},
+ {TK_OPTION_CURSOR, "-cursor", "cursor", "Cursor",
+ DEF_ENTRY_CURSOR, -1, Tk_Offset(Entry, cursor),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_BOOLEAN, "-exportselection", "exportSelection",
+ "ExportSelection", DEF_ENTRY_EXPORT_SELECTION, -1,
+ Tk_Offset(Entry, exportSelection), 0, 0, 0},
+ {TK_OPTION_SYNONYM, "-fg", "foreground", (char *) NULL,
+ (char *) NULL, 0, -1, 0, (ClientData) "-foreground", 0},
+ {TK_OPTION_FONT, "-font", "font", "Font",
+ DEF_ENTRY_FONT, -1, Tk_Offset(Entry, tkfont), 0, 0, 0},
+ {TK_OPTION_COLOR, "-foreground", "foreground", "Foreground",
+ DEF_ENTRY_FG, -1, Tk_Offset(Entry, fgColorPtr), 0,
+ 0, 0},
+ {TK_OPTION_COLOR, "-highlightbackground", "highlightBackground",
"HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
- Tk_Offset(Entry, highlightBgColorPtr), 0},
- {TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
- DEF_ENTRY_HIGHLIGHT, Tk_Offset(Entry, highlightColorPtr), 0},
- {TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
- "HighlightThickness",
- DEF_ENTRY_HIGHLIGHT_WIDTH, Tk_Offset(Entry, highlightWidth), 0},
- {TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
- DEF_ENTRY_INSERT_BG, Tk_Offset(Entry, insertBorder), 0},
- {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
- DEF_ENTRY_INSERT_BD_COLOR, Tk_Offset(Entry, insertBorderWidth),
- TK_CONFIG_COLOR_ONLY},
- {TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
- DEF_ENTRY_INSERT_BD_MONO, Tk_Offset(Entry, insertBorderWidth),
- TK_CONFIG_MONO_ONLY},
- {TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
- DEF_ENTRY_INSERT_OFF_TIME, Tk_Offset(Entry, insertOffTime), 0},
- {TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
- DEF_ENTRY_INSERT_ON_TIME, Tk_Offset(Entry, insertOnTime), 0},
- {TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
- DEF_ENTRY_INSERT_WIDTH, Tk_Offset(Entry, insertWidth), 0},
- {TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
- DEF_ENTRY_JUSTIFY, Tk_Offset(Entry, justify), 0},
- {TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
- DEF_ENTRY_RELIEF, Tk_Offset(Entry, relief), 0},
- {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
- DEF_ENTRY_SELECT_COLOR, Tk_Offset(Entry, selBorder),
- TK_CONFIG_COLOR_ONLY},
- {TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
- DEF_ENTRY_SELECT_MONO, Tk_Offset(Entry, selBorder),
- TK_CONFIG_MONO_ONLY},
- {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
- DEF_ENTRY_SELECT_BD_COLOR, Tk_Offset(Entry, selBorderWidth),
- TK_CONFIG_COLOR_ONLY},
- {TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
- DEF_ENTRY_SELECT_BD_MONO, Tk_Offset(Entry, selBorderWidth),
- TK_CONFIG_MONO_ONLY},
- {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
- DEF_ENTRY_SELECT_FG_COLOR, Tk_Offset(Entry, selFgColorPtr),
- TK_CONFIG_COLOR_ONLY},
- {TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
- DEF_ENTRY_SELECT_FG_MONO, Tk_Offset(Entry, selFgColorPtr),
- TK_CONFIG_MONO_ONLY},
- {TK_CONFIG_STRING, "-show", "show", "Show",
- DEF_ENTRY_SHOW, Tk_Offset(Entry, showChar), TK_CONFIG_NULL_OK},
- {TK_CONFIG_UID, "-state", "state", "State",
- DEF_ENTRY_STATE, Tk_Offset(Entry, state), 0},
- {TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
- DEF_ENTRY_TAKE_FOCUS, Tk_Offset(Entry, takeFocus), TK_CONFIG_NULL_OK},
- {TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
- DEF_ENTRY_TEXT_VARIABLE, Tk_Offset(Entry, textVarName),
- TK_CONFIG_NULL_OK},
- {TK_CONFIG_INT, "-width", "width", "Width",
- DEF_ENTRY_WIDTH, Tk_Offset(Entry, prefWidth), 0},
- {TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
- DEF_ENTRY_SCROLL_COMMAND, Tk_Offset(Entry, scrollCmd),
- TK_CONFIG_NULL_OK},
- {TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
- (char *) NULL, 0, 0}
+ -1, Tk_Offset(Entry, highlightBgColorPtr),
+ 0, 0, 0},
+ {TK_OPTION_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
+ DEF_ENTRY_HIGHLIGHT, -1, Tk_Offset(Entry, highlightColorPtr),
+ 0, 0, 0},
+ {TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
+ "HighlightThickness", DEF_ENTRY_HIGHLIGHT_WIDTH, -1,
+ Tk_Offset(Entry, highlightWidth), 0, 0, 0},
+ {TK_OPTION_BORDER, "-insertbackground", "insertBackground", "Foreground",
+ DEF_ENTRY_INSERT_BG,
+ -1, Tk_Offset(Entry, insertBorder),
+ 0, 0, 0},
+ {TK_OPTION_PIXELS, "-insertborderwidth", "insertBorderWidth",
+ "BorderWidth", DEF_ENTRY_INSERT_BD_COLOR, -1,
+ Tk_Offset(Entry, insertBorderWidth), 0,
+ (ClientData) DEF_ENTRY_INSERT_BD_MONO, 0},
+ {TK_OPTION_INT, "-insertofftime", "insertOffTime", "OffTime",
+ DEF_ENTRY_INSERT_OFF_TIME, -1, Tk_Offset(Entry, insertOffTime),
+ 0, 0, 0},
+ {TK_OPTION_INT, "-insertontime", "insertOnTime", "OnTime",
+ DEF_ENTRY_INSERT_ON_TIME, -1, Tk_Offset(Entry, insertOnTime),
+ 0, 0, 0},
+ {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
+ DEF_ENTRY_INSERT_WIDTH, -1, Tk_Offset(Entry, insertWidth),
+ 0, 0, 0},
+ {TK_OPTION_STRING, "-invalidcommand", "invalidCommand", "InvalidCommand",
+ DEF_ENTRY_INVALIDCMD, -1, Tk_Offset(Entry, invalidCmd),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_SYNONYM, "-invcmd", (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, (ClientData) "-invalidcommand", 0},
+ {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
+ DEF_ENTRY_JUSTIFY, -1, Tk_Offset(Entry, justify), 0, 0, 0},
+ {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
+ DEF_ENTRY_RELIEF, -1, Tk_Offset(Entry, relief),
+ 0, 0, 0},
+ {TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground",
+ DEF_ENTRY_SELECT_COLOR, -1, Tk_Offset(Entry, selBorder),
+ 0, (ClientData) DEF_ENTRY_SELECT_MONO, 0},
+ {TK_OPTION_PIXELS, "-selectborderwidth", "selectBorderWidth",
+ "BorderWidth", DEF_ENTRY_SELECT_BD_COLOR, -1,
+ Tk_Offset(Entry, selBorderWidth),
+ 0, (ClientData) DEF_ENTRY_SELECT_BD_MONO, 0},
+ {TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
+ DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
+ 0, (ClientData) DEF_ENTRY_SELECT_FG_MONO, 0},
+ {TK_OPTION_STRING, "-show", "show", "Show",
+ DEF_ENTRY_SHOW, -1, Tk_Offset(Entry, showChar),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_STRING_TABLE, "-state", "state", "State",
+ DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state),
+ 0, (ClientData) stateStrings, 0},
+ {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
+ DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
+ DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
+ DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate),
+ 0, (ClientData) validateStrings, 0},
+ {TK_OPTION_STRING, "-validatecommand", "validateCommand", "ValidateCommand",
+ (char *) NULL, -1, Tk_Offset(Entry, validateCmd),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_SYNONYM, "-vcmd", (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, (ClientData) "-validatecommand", 0},
+ {TK_OPTION_INT, "-width", "width", "Width",
+ DEF_ENTRY_WIDTH, -1, Tk_Offset(Entry, prefWidth), 0, 0, 0},
+ {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
+ DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd),
+ TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_END, (char *) NULL, (char *) NULL, (char *) NULL,
+ (char *) NULL, 0, -1, 0, 0, 0}
};
/*
@@ -274,12 +348,38 @@ static Tk_ConfigSpec configSpecs[] = {
#define LAST_PLUS_ONE_OK 2
/*
+ * The following tables define the entry widget commands (and sub-
+ * commands) and map the indexes into the string tables into
+ * enumerated types used to dispatch the entry widget command.
+ */
+
+static char *commandNames[] = {
+ "bbox", "cget", "configure", "delete", "get", "icursor", "index",
+ "insert", "scan", "selection", "validate", "xview", (char *) NULL
+};
+
+enum command {
+ COMMAND_BBOX, COMMAND_CGET, COMMAND_CONFIGURE, COMMAND_DELETE,
+ COMMAND_GET, COMMAND_ICURSOR, COMMAND_INDEX, COMMAND_INSERT,
+ COMMAND_SCAN, COMMAND_SELECTION, COMMAND_VALIDATE, COMMAND_XVIEW
+};
+
+static char *selCommandNames[] = {
+ "adjust", "clear", "from", "present", "range", "to", (char *) NULL
+};
+
+enum selcommand {
+ SELECTION_ADJUST, SELECTION_CLEAR, SELECTION_FROM,
+ SELECTION_PRESENT, SELECTION_RANGE, SELECTION_TO
+};
+
+/*
* Forward declarations for procedures defined later in this file:
*/
static int ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
- Entry *entryPtr, int argc, char **argv,
- int flags));
+ Entry *entryPtr, int objc,
+ Tcl_Obj *CONST objv[], int flags));
static void DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
int count));
static void DestroyEntry _ANSI_ARGS_((char *memPtr));
@@ -306,11 +406,19 @@ static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, char *name1, char *name2,
int flags));
static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
+static int EntryValidate _ANSI_ARGS_((Entry *entryPtr,
+ char *cmd));
+static int EntryValidateChange _ANSI_ARGS_((Entry *entryPtr,
+ char *change, char *new, int index, int type));
+static void ExpandPercents _ANSI_ARGS_((Entry *entryPtr,
+ char *before, char *change, char *new,
+ int index, int type, Tcl_DString *dsPtr));
static void EntryValueChanged _ANSI_ARGS_((Entry *entryPtr));
static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr,
double *firstPtr, double *lastPtr));
-static int EntryWidgetCmd _ANSI_ARGS_((ClientData clientData,
- Tcl_Interp *interp, int argc, char **argv));
+static int EntryWidgetObjCmd _ANSI_ARGS_((ClientData clientData,
+ Tcl_Interp *interp, int objc,
+ Tcl_Obj *CONST objv[]));
static void EntryWorldChanged _ANSI_ARGS_((
ClientData instanceData));
static int GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp,
@@ -333,7 +441,7 @@ static TkClassProcs entryClass = {
/*
*--------------------------------------------------------------
*
- * Tk_EntryCmd --
+ * Tk_EntryObjCmd --
*
* This procedure is invoked to process the "entry" Tcl
* command. See the user documentation for details on what
@@ -349,25 +457,43 @@ static TkClassProcs entryClass = {
*/
int
-Tk_EntryCmd(clientData, interp, argc, argv)
- ClientData clientData; /* Main window associated with
- * interpreter. */
+Tk_EntryObjCmd(clientData, interp, objc, objv)
+ ClientData clientData; /* Either NULL or pointer to option table. */
Tcl_Interp *interp; /* Current interpreter. */
- int argc; /* Number of arguments. */
- char **argv; /* Argument strings. */
+ int objc; /* Number of arguments. */
+ Tcl_Obj *CONST objv[]; /* Argument objects. */
{
- Tk_Window tkwin = (Tk_Window) clientData;
register Entry *entryPtr;
- Tk_Window new;
+ Tk_OptionTable optionTable;
+ Tk_Window tkwin;
+
+ optionTable = (Tk_OptionTable) clientData;
+ if (optionTable == NULL) {
+ Tcl_CmdInfo info;
+ char *name;
+
+ /*
+ * We haven't created the option table for this widget class
+ * yet. Do it now and save the table as the clientData for
+ * the command, so we'll have access to it in future
+ * invocations of the command.
+ */
+
+ optionTable = Tk_CreateOptionTable(interp, optionSpecs);
+ name = Tcl_GetString(objv[0]);
+ Tcl_GetCommandInfo(interp, name, &info);
+ info.objClientData = (ClientData) optionTable;
+ Tcl_SetCommandInfo(interp, name, &info);
+ }
- if (argc < 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " pathName ?options?\"", (char *) NULL);
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "pathName ?options?");
return TCL_ERROR;
}
- new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
- if (new == NULL) {
+ tkwin = Tk_CreateWindowFromPath(interp, Tk_MainWindow(interp),
+ Tcl_GetString(objv[1]), (char *) NULL);
+ if (tkwin == NULL) {
return TCL_ERROR;
}
@@ -377,62 +503,67 @@ Tk_EntryCmd(clientData, interp, argc, argv)
* initialized already (e.g. resource pointers).
*/
- entryPtr = (Entry *) ckalloc(sizeof(Entry));
- entryPtr->tkwin = new;
- entryPtr->display = Tk_Display(new);
- entryPtr->interp = interp;
- entryPtr->widgetCmd = Tcl_CreateCommand(interp,
- Tk_PathName(entryPtr->tkwin), EntryWidgetCmd,
+ entryPtr = (Entry *) ckalloc(sizeof(Entry));
+ entryPtr->tkwin = tkwin;
+ entryPtr->display = Tk_Display(tkwin);
+ entryPtr->interp = interp;
+ entryPtr->widgetCmd = Tcl_CreateObjCommand(interp,
+ Tk_PathName(entryPtr->tkwin), EntryWidgetObjCmd,
(ClientData) entryPtr, EntryCmdDeletedProc);
- entryPtr->string = (char *) ckalloc(1);
- entryPtr->string[0] = '\0';
- entryPtr->insertPos = 0;
- entryPtr->selectFirst = -1;
- entryPtr->selectLast = -1;
- entryPtr->selectAnchor = 0;
- entryPtr->scanMarkX = 0;
- entryPtr->scanMarkIndex = 0;
-
- entryPtr->normalBorder = NULL;
- entryPtr->borderWidth = 0;
- entryPtr->cursor = None;
- entryPtr->exportSelection = 1;
- entryPtr->tkfont = NULL;
- entryPtr->fgColorPtr = NULL;
- entryPtr->highlightBgColorPtr = NULL;
- entryPtr->highlightColorPtr = NULL;
- entryPtr->highlightWidth = 0;
- entryPtr->insertBorder = NULL;
- entryPtr->insertBorderWidth = 0;
- entryPtr->insertOffTime = 0;
- entryPtr->insertOnTime = 0;
- entryPtr->insertWidth = 0;
- entryPtr->justify = TK_JUSTIFY_LEFT;
- entryPtr->relief = TK_RELIEF_FLAT;
- entryPtr->selBorder = NULL;
- entryPtr->selBorderWidth = 0;
- entryPtr->selFgColorPtr = NULL;
- entryPtr->showChar = NULL;
- entryPtr->state = tkNormalUid;
- entryPtr->textVarName = NULL;
- entryPtr->takeFocus = NULL;
- entryPtr->prefWidth = 0;
- entryPtr->scrollCmd = NULL;
-
- entryPtr->numChars = 0;
- entryPtr->displayString = NULL;
- entryPtr->inset = XPAD;
- entryPtr->textLayout = NULL;
- entryPtr->layoutX = 0;
- entryPtr->layoutY = 0;
- entryPtr->leftIndex = 0;
- entryPtr->leftX = 0;
- entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
- entryPtr->textGC = None;
- entryPtr->selTextGC = None;
- entryPtr->highlightGC = None;
- entryPtr->avgWidth = 1;
- entryPtr->flags = 0;
+ entryPtr->optionTable = optionTable;
+ entryPtr->string = (char *) ckalloc(1);
+ entryPtr->string[0] = '\0';
+ entryPtr->insertPos = 0;
+ entryPtr->selectFirst = -1;
+ entryPtr->selectLast = -1;
+ entryPtr->selectAnchor = 0;
+ entryPtr->scanMarkX = 0;
+ entryPtr->scanMarkIndex = 0;
+
+ entryPtr->normalBorder = NULL;
+ entryPtr->borderWidth = 0;
+ entryPtr->cursor = None;
+ entryPtr->exportSelection = 1;
+ entryPtr->tkfont = NULL;
+ entryPtr->fgColorPtr = NULL;
+ entryPtr->highlightBgColorPtr = NULL;
+ entryPtr->highlightColorPtr = NULL;
+ entryPtr->highlightWidth = 0;
+ entryPtr->insertBorder = NULL;
+ entryPtr->insertBorderWidth = 0;
+ entryPtr->insertOffTime = 0;
+ entryPtr->insertOnTime = 0;
+ entryPtr->insertWidth = 0;
+ entryPtr->justify = TK_JUSTIFY_LEFT;
+ entryPtr->relief = TK_RELIEF_FLAT;
+ entryPtr->selBorder = NULL;
+ entryPtr->selBorderWidth = 0;
+ entryPtr->selFgColorPtr = NULL;
+ entryPtr->showChar = NULL;
+ entryPtr->state = STATE_NORMAL;
+ entryPtr->textVarName = NULL;
+ entryPtr->takeFocus = NULL;
+ entryPtr->prefWidth = 0;
+ entryPtr->scrollCmd = NULL;
+ entryPtr->numBytes = 0;
+ entryPtr->numChars = 0;
+ entryPtr->displayString = entryPtr->string;
+ entryPtr->numDisplayBytes = 0;
+ entryPtr->inset = XPAD;
+ entryPtr->textLayout = NULL;
+ entryPtr->layoutX = 0;
+ entryPtr->layoutY = 0;
+ entryPtr->leftX = 0;
+ entryPtr->leftIndex = 0;
+ entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
+ entryPtr->textGC = None;
+ entryPtr->selTextGC = None;
+ entryPtr->highlightGC = None;
+ entryPtr->avgWidth = 1;
+ entryPtr->flags = 0;
+ entryPtr->validateCmd = NULL;
+ entryPtr->validate = VALIDATE_NONE;
+ entryPtr->invalidCmd = NULL;
Tk_SetClass(entryPtr->tkwin, "Entry");
TkSetClassProcs(entryPtr->tkwin, &entryClass, (ClientData) entryPtr);
@@ -441,22 +572,22 @@ Tk_EntryCmd(clientData, interp, argc, argv)
EntryEventProc, (ClientData) entryPtr);
Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING,
EntryFetchSelection, (ClientData) entryPtr, XA_STRING);
- if (ConfigureEntry(interp, entryPtr, argc-2, argv+2, 0) != TCL_OK) {
- goto error;
- }
- interp->result = Tk_PathName(entryPtr->tkwin);
+ if ((Tk_InitOptions(interp, (char *) entryPtr, optionTable, tkwin)
+ != TCL_OK) ||
+ (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK)) {
+ Tk_DestroyWindow(entryPtr->tkwin);
+ return TCL_ERROR;
+ }
+
+ Tcl_SetResult(interp, Tk_PathName(entryPtr->tkwin), TCL_STATIC);
return TCL_OK;
-
- error:
- Tk_DestroyWindow(entryPtr->tkwin);
- return TCL_ERROR;
}
/*
*--------------------------------------------------------------
*
- * EntryWidgetCmd --
+ * EntryWidgetObjCmd --
*
* This procedure is invoked to process the Tcl command
* that corresponds to a widget managed by this module.
@@ -472,321 +603,414 @@ Tk_EntryCmd(clientData, interp, argc, argv)
*/
static int
-EntryWidgetCmd(clientData, interp, argc, argv)
- ClientData clientData; /* Information about entry widget. */
- Tcl_Interp *interp; /* Current interpreter. */
- int argc; /* Number of arguments. */
- char **argv; /* Argument strings. */
+EntryWidgetObjCmd(clientData, interp, objc, objv)
+ ClientData clientData; /* Information about entry widget. */
+ Tcl_Interp *interp; /* Current interpreter. */
+ int objc; /* Number of arguments. */
+ Tcl_Obj *CONST objv[]; /* Argument objects. */
{
- register Entry *entryPtr = (Entry *) clientData;
- int result = TCL_OK;
- size_t length;
- int c;
+ Entry *entryPtr = (Entry *) clientData;
+ int cmdIndex, selIndex, result;
+ Tcl_Obj *objPtr;
- if (argc < 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " option ?arg arg ...?\"", (char *) NULL);
+ if (objc < 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "option ?arg arg ...?");
return TCL_ERROR;
}
Tcl_Preserve((ClientData) entryPtr);
- c = argv[1][0];
- length = strlen(argv[1]);
- if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
- int index;
- int x, y, width, height;
-
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " bbox index\"",
- (char *) NULL);
- goto error;
- }
- if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
- goto error;
- }
- if ((index == entryPtr->numChars) && (index > 0)) {
- index--;
- }
- Tk_CharBbox(entryPtr->textLayout, index, &x, &y, &width, &height);
- sprintf(interp->result, "%d %d %d %d",
- x + entryPtr->layoutX, y + entryPtr->layoutY, width, height);
- } else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
- && (length >= 2)) {
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " cget option\"",
- (char *) NULL);
- goto error;
- }
- result = Tk_ConfigureValue(interp, entryPtr->tkwin, configSpecs,
- (char *) entryPtr, argv[2], 0);
- } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
- && (length >= 2)) {
- if (argc == 2) {
- result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs,
- (char *) entryPtr, (char *) NULL, 0);
- } else if (argc == 3) {
- result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs,
- (char *) entryPtr, argv[2], 0);
- } else {
- result = ConfigureEntry(interp, entryPtr, argc-2, argv+2,
- TK_CONFIG_ARGV_ONLY);
- }
- } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
- int first, last;
-
- if ((argc < 3) || (argc > 4)) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " delete firstIndex ?lastIndex?\"",
- (char *) NULL);
- goto error;
- }
- if (GetEntryIndex(interp, entryPtr, argv[2], &first) != TCL_OK) {
- goto error;
- }
- if (argc == 3) {
- last = first+1;
- } else {
- if (GetEntryIndex(interp, entryPtr, argv[3], &last) != TCL_OK) {
+
+ /*
+ * Parse the widget command by looking up the second token in
+ * the list of valid command names.
+ */
+
+ result = Tcl_GetIndexFromObj(interp, objv[1], commandNames,
+ "option", 0, &cmdIndex);
+ if (result != TCL_OK) {
+ return result;
+ }
+
+ switch (cmdIndex) {
+ case COMMAND_BBOX: {
+ int index, x, y, width, height;
+ char buf[TCL_INTEGER_SPACE * 4];
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "index");
goto error;
}
- }
- if ((last >= first) && (entryPtr->state == tkNormalUid)) {
- DeleteChars(entryPtr, first, last-first);
- }
- } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
- if (argc != 2) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " get\"", (char *) NULL);
- goto error;
- }
- interp->result = entryPtr->string;
- } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0)
- && (length >= 2)) {
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " icursor pos\"",
- (char *) NULL);
- goto error;
- }
- if (GetEntryIndex(interp, entryPtr, argv[2], &entryPtr->insertPos)
- != TCL_OK) {
- goto error;
- }
- EventuallyRedraw(entryPtr);
- } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
- && (length >= 3)) {
- int index;
-
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " index string\"", (char *) NULL);
- goto error;
- }
- if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
- goto error;
- }
- sprintf(interp->result, "%d", index);
- } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
- && (length >= 3)) {
- int index;
-
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " insert index text\"",
- (char *) NULL);
- goto error;
- }
- if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
- goto error;
- }
- if (entryPtr->state == tkNormalUid) {
- InsertChars(entryPtr, index, argv[3]);
- }
- } else if ((c == 's') && (length >= 2)
- && (strncmp(argv[1], "scan", length) == 0)) {
- int x;
-
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " scan mark|dragto x\"", (char *) NULL);
- goto error;
- }
- if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) {
- goto error;
- }
- if ((argv[2][0] == 'm')
- && (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
- entryPtr->scanMarkX = x;
- entryPtr->scanMarkIndex = entryPtr->leftIndex;
- } else if ((argv[2][0] == 'd')
- && (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
- EntryScanTo(entryPtr, x);
- } else {
- Tcl_AppendResult(interp, "bad scan option \"", argv[2],
- "\": must be mark or dragto", (char *) NULL);
- goto error;
- }
- } else if ((c == 's') && (length >= 2)
- && (strncmp(argv[1], "selection", length) == 0)) {
- int index, index2;
-
- if (argc < 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " select option ?index?\"", (char *) NULL);
- goto error;
- }
- length = strlen(argv[2]);
- c = argv[2][0];
- if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) {
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " selection clear\"", (char *) NULL);
- goto error;
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
+ &index) != TCL_OK) {
+ goto error;
}
- if (entryPtr->selectFirst != -1) {
- entryPtr->selectFirst = entryPtr->selectLast = -1;
- EventuallyRedraw(entryPtr);
+ if ((index == entryPtr->numChars) && (index > 0)) {
+ index--;
}
- goto done;
- } else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) {
- if (argc != 3) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " selection present\"", (char *) NULL);
+ Tk_CharBbox(entryPtr->textLayout, index, &x, &y,
+ &width, &height);
+ sprintf(buf, "%d %d %d %d", x + entryPtr->layoutX,
+ y + entryPtr->layoutY, width, height);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ break;
+ }
+
+ case COMMAND_CGET: {
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "option");
goto error;
}
- if (entryPtr->selectFirst == -1) {
- interp->result = "0";
+
+ objPtr = Tk_GetOptionValue(interp, (char *) entryPtr,
+ entryPtr->optionTable, objv[2], entryPtr->tkwin);
+ if (objPtr == NULL) {
+ goto error;
} else {
- interp->result = "1";
+ Tcl_SetObjResult(interp, objPtr);
}
- goto done;
+ break;
}
- if (argc >= 4) {
- if (GetEntryIndex(interp, entryPtr, argv[3], &index) != TCL_OK) {
- goto error;
+
+ case COMMAND_CONFIGURE: {
+ if (objc <= 3) {
+ objPtr = Tk_GetOptionInfo(interp, (char *) entryPtr,
+ entryPtr->optionTable,
+ (objc == 3) ? objv[2] : (Tcl_Obj *) NULL,
+ entryPtr->tkwin);
+ if (objPtr == NULL) {
+ goto error;
+ } else {
+ Tcl_SetObjResult(interp, objPtr);
+ }
+ } else {
+ result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0);
}
+ break;
}
- if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " selection adjust index\"",
- (char *) NULL);
+
+ case COMMAND_DELETE: {
+ int first, last;
+
+ if ((objc < 3) || (objc > 4)) {
+ Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
goto error;
}
- if (entryPtr->selectFirst >= 0) {
- int half1, half2;
-
- half1 = (entryPtr->selectFirst + entryPtr->selectLast)/2;
- half2 = (entryPtr->selectFirst + entryPtr->selectLast + 1)/2;
- if (index < half1) {
- entryPtr->selectAnchor = entryPtr->selectLast;
- } else if (index > half2) {
- entryPtr->selectAnchor = entryPtr->selectFirst;
- } else {
- /*
- * We're at about the halfway point in the selection;
- * just keep the existing anchor.
- */
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
+ &first) != TCL_OK) {
+ goto error;
+ }
+ if (objc == 3) {
+ last = first + 1;
+ } else {
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[3]),
+ &last) != TCL_OK) {
+ goto error;
}
}
- EntrySelectTo(entryPtr, index);
- } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " selection from index\"",
- (char *) NULL);
+ if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
+ DeleteChars(entryPtr, first, last - first);
+ }
+ break;
+ }
+
+ case COMMAND_GET: {
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
goto error;
}
- entryPtr->selectAnchor = index;
- } else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) {
- if (argc != 5) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " selection range start end\"",
- (char *) NULL);
+ Tcl_SetResult(interp, entryPtr->string, TCL_STATIC);
+ break;
+ }
+
+ case COMMAND_ICURSOR: {
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "pos");
goto error;
}
- if (GetEntryIndex(interp, entryPtr, argv[4], &index2) != TCL_OK) {
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
+ &entryPtr->insertPos) != TCL_OK) {
+ goto error;
+ }
+ EventuallyRedraw(entryPtr);
+ break;
+ }
+
+ case COMMAND_INDEX: {
+ int index;
+
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "string");
goto error;
}
- if (index >= index2) {
- entryPtr->selectFirst = entryPtr->selectLast = -1;
- } else {
- entryPtr->selectFirst = index;
- entryPtr->selectLast = index2;
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
+ &index) != TCL_OK) {
+ goto error;
}
- if (!(entryPtr->flags & GOT_SELECTION)
- && (entryPtr->exportSelection)) {
- Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
- EntryLostSelection, (ClientData) entryPtr);
- entryPtr->flags |= GOT_SELECTION;
+ Tcl_SetObjResult(interp, Tcl_NewIntObj(index));
+ break;
+ }
+
+ case COMMAND_INSERT: {
+ int index;
+
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 2, objv, "index text");
+ goto error;
}
- EventuallyRedraw(entryPtr);
- } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
- if (argc != 4) {
- Tcl_AppendResult(interp, "wrong # args: should be \"",
- argv[0], " selection to index\"",
- (char *) NULL);
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
+ &index) != TCL_OK) {
+ goto error;
+ }
+ if (entryPtr->state == STATE_NORMAL) {
+ InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ }
+ break;
+ }
+
+ case COMMAND_SCAN: {
+ int x;
+ char *minorCmd;
+
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 2, objv, "mark|dragto x");
goto error;
}
- EntrySelectTo(entryPtr, index);
- } else {
- Tcl_AppendResult(interp, "bad selection option \"", argv[2],
- "\": must be adjust, clear, from, present, range, or to",
- (char *) NULL);
- goto error;
+ if (Tcl_GetIntFromObj(interp, objv[3], &x) != TCL_OK) {
+ goto error;
+ }
+
+ minorCmd = Tcl_GetString(objv[2]);
+ if (minorCmd[0] == 'm'
+ && (strncmp(minorCmd, "mark", strlen(minorCmd)) == 0)) {
+ entryPtr->scanMarkX = x;
+ entryPtr->scanMarkIndex = entryPtr->leftIndex;
+ } else if ((minorCmd[0] == 'd')
+ && (strncmp(minorCmd, "dragto", strlen(minorCmd)) == 0)) {
+ EntryScanTo(entryPtr, x);
+ } else {
+ Tcl_AppendResult(interp, "bad scan option \"",
+ Tcl_GetString(objv[2]), "\": must be mark or dragto",
+ (char *) NULL);
+ goto error;
+ }
+ break;
}
- } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
- int index, type, count, charsPerPage;
- double fraction, first, last;
-
- if (argc == 2) {
- EntryVisibleRange(entryPtr, &first, &last);
- sprintf(interp->result, "%g %g", first, last);
- goto done;
- } else if (argc == 3) {
- if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
+
+ case COMMAND_SELECTION: {
+ int index, index2;
+
+ if (objc < 3) {
+ Tcl_WrongNumArgs(interp, 2, objv, "option ?index?");
goto error;
}
- } else {
- type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
- index = entryPtr->leftIndex;
- switch (type) {
- case TK_SCROLL_ERROR:
- goto error;
- case TK_SCROLL_MOVETO:
- index = (int) ((fraction * entryPtr->numChars) + 0.5);
+
+ /*
+ * Parse the selection sub-command, using the command
+ * table "selCommandNames" defined above.
+ */
+
+ result = Tcl_GetIndexFromObj(interp, objv[2], selCommandNames,
+ "selection option", 0, &selIndex);
+ if (result != TCL_OK) {
+ goto error;
+ }
+
+ switch(selIndex) {
+ case SELECTION_ADJUST: {
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "index");
+ goto error;
+ }
+ if (GetEntryIndex(interp, entryPtr,
+ Tcl_GetString(objv[3]), &index) != TCL_OK) {
+ goto error;
+ }
+ if (entryPtr->selectFirst >= 0) {
+ int half1, half2;
+
+ half1 = (entryPtr->selectFirst
+ + entryPtr->selectLast)/2;
+ half2 = (entryPtr->selectFirst
+ + entryPtr->selectLast + 1)/2;
+ if (index < half1) {
+ entryPtr->selectAnchor = entryPtr->selectLast;
+ } else if (index > half2) {
+ entryPtr->selectAnchor = entryPtr->selectFirst;
+ } else {
+ /*
+ * We're at about the halfway point in the
+ * selection; just keep the existing anchor.
+ */
+ }
+ }
+ EntrySelectTo(entryPtr, index);
break;
- case TK_SCROLL_PAGES:
- charsPerPage = ((Tk_Width(entryPtr->tkwin)
- - 2*entryPtr->inset) / entryPtr->avgWidth) - 2;
- if (charsPerPage < 1) {
- charsPerPage = 1;
+ }
+
+ case SELECTION_CLEAR: {
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
+ goto error;
}
- index += charsPerPage*count;
+ if (entryPtr->selectFirst >= 0) {
+ entryPtr->selectFirst = -1;
+ entryPtr->selectLast = -1;
+ EventuallyRedraw(entryPtr);
+ }
+ goto done;
+ }
+
+ case SELECTION_FROM: {
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "index");
+ goto error;
+ }
+ if (GetEntryIndex(interp, entryPtr,
+ Tcl_GetString(objv[3]), &index) != TCL_OK) {
+ goto error;
+ }
+ entryPtr->selectAnchor = index;
break;
- case TK_SCROLL_UNITS:
- index += count;
+ }
+
+ case SELECTION_PRESENT: {
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 3, objv, (char *) NULL);
+ goto error;
+ }
+ if (entryPtr->selectFirst < 0) {
+ Tcl_SetResult(interp, "0", TCL_STATIC);
+ } else {
+ Tcl_SetResult(interp, "1", TCL_STATIC);
+ }
+ goto done;
+ }
+
+ case SELECTION_RANGE: {
+ if (objc != 5) {
+ Tcl_WrongNumArgs(interp, 3, objv, "start end");
+ goto error;
+ }
+ if (GetEntryIndex(interp, entryPtr,
+ Tcl_GetString(objv[3]), &index) != TCL_OK) {
+ goto error;
+ }
+ if (GetEntryIndex(interp, entryPtr,
+ Tcl_GetString(objv[4]),& index2) != TCL_OK) {
+ goto error;
+ }
+ if (index >= index2) {
+ entryPtr->selectFirst = -1;
+ entryPtr->selectLast = -1;
+ } else {
+ entryPtr->selectFirst = index;
+ entryPtr->selectLast = index2;
+ }
+ if (!(entryPtr->flags & GOT_SELECTION)
+ && (entryPtr->exportSelection)) {
+ Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
+ EntryLostSelection, (ClientData) entryPtr);
+ entryPtr->flags |= GOT_SELECTION;
+ }
+ EventuallyRedraw(entryPtr);
break;
+ }
+
+ case SELECTION_TO: {
+ if (objc != 4) {
+ Tcl_WrongNumArgs(interp, 3, objv, "index");
+ goto error;
+ }
+ if (GetEntryIndex(interp, entryPtr,
+ Tcl_GetString(objv[3]), &index) != TCL_OK) {
+ goto error;
+ }
+ EntrySelectTo(entryPtr, index);
+ break;
+ }
}
+ break;
}
- if (index >= entryPtr->numChars) {
- index = entryPtr->numChars-1;
- }
- if (index < 0) {
- index = 0;
+
+ case COMMAND_VALIDATE: {
+ int code;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, (char *) NULL);
+ goto error;
+ }
+ selIndex = entryPtr->validate;
+ entryPtr->validate = VALIDATE_ALL;
+ code = EntryValidateChange(entryPtr, (char *) NULL,
+ entryPtr->string, -1, VALIDATE_FORCED);
+ if (entryPtr->validate != VALIDATE_NONE) {
+ entryPtr->validate = selIndex;
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj((code == TCL_OK)));
+ break;
+ }
+
+ case COMMAND_XVIEW: {
+ int index;
+
+ if (objc == 2) {
+ double first, last;
+ char buf[TCL_DOUBLE_SPACE * 2];
+
+ EntryVisibleRange(entryPtr, &first, &last);
+ sprintf(buf, "%g %g", first, last);
+ Tcl_SetResult(interp, buf, TCL_VOLATILE);
+ goto done;
+ } else if (objc == 3) {
+ if (GetEntryIndex(interp, entryPtr, Tcl_GetString(objv[2]),
+ &index) != TCL_OK) {
+ goto error;
+ }
+ } else {
+ double fraction;
+ int count;
+
+ index = entryPtr->leftIndex;
+ switch (Tk_GetScrollInfoObj(interp, objc, objv, &fraction,
+ &count)) {
+ case TK_SCROLL_ERROR: {
+ goto error;
+ }
+ case TK_SCROLL_MOVETO: {
+ index = (int) ((fraction * entryPtr->numChars) + 0.5);
+ break;
+ }
+ case TK_SCROLL_PAGES: {
+ int charsPerPage;
+
+ charsPerPage = ((Tk_Width(entryPtr->tkwin)
+ - 2 * entryPtr->inset)
+ / entryPtr->avgWidth) - 2;
+ if (charsPerPage < 1) {
+ charsPerPage = 1;
+ }
+ index += count * charsPerPage;
+ break;
+ }
+ case TK_SCROLL_UNITS: {
+ index += count;
+ break;
+ }
+ }
+ }
+ if (index >= entryPtr->numChars) {
+ index = entryPtr->numChars - 1;
+ }
+ if (index < 0) {
+ index = 0;
+ }
+ entryPtr->leftIndex = index;
+ entryPtr->flags |= UPDATE_SCROLLBAR;
+ EntryComputeGeometry(entryPtr);
+ EventuallyRedraw(entryPtr);
+ break;
}
- entryPtr->leftIndex = index;
- entryPtr->flags |= UPDATE_SCROLLBAR;
- EntryComputeGeometry(entryPtr);
- EventuallyRedraw(entryPtr);
- } else {
- Tcl_AppendResult(interp, "bad option \"", argv[1],
- "\": must be bbox, cget, configure, delete, get, ",
- "icursor, index, insert, scan, selection, or xview",
- (char *) NULL);
- goto error;
}
+
done:
Tcl_Release((ClientData) entryPtr);
return result;
@@ -818,7 +1042,13 @@ static void
DestroyEntry(memPtr)
char *memPtr; /* Info about entry widget. */
{
- register Entry *entryPtr = (Entry *) memPtr;
+ Entry *entryPtr = (Entry *) memPtr;
+ entryPtr->flags |= ENTRY_DELETED;
+
+ Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd);
+ if (entryPtr->flags & REDRAW_PENDING) {
+ Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr);
+ }
/*
* Free up all the stuff that requires special handling, then
@@ -839,11 +1069,13 @@ DestroyEntry(memPtr)
Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
}
Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler);
- if (entryPtr->displayString != NULL) {
+ if (entryPtr->displayString != entryPtr->string) {
ckfree(entryPtr->displayString);
}
Tk_FreeTextLayout(entryPtr->textLayout);
- Tk_FreeOptions(configSpecs, (char *) entryPtr, entryPtr->display, 0);
+ Tk_FreeConfigOptions((char *) entryPtr, entryPtr->optionTable,
+ entryPtr->tkwin);
+ entryPtr->tkwin = NULL;
ckfree((char *) entryPtr);
}
@@ -858,7 +1090,7 @@ DestroyEntry(memPtr)
*
* Results:
* The return value is a standard Tcl result. If TCL_ERROR is
- * returned, then interp->result contains an error message.
+ * returned, then the interp's result contains an error message.
*
* Side effects:
* Configuration information, such as colors, border width,
@@ -869,14 +1101,17 @@ DestroyEntry(memPtr)
*/
static int
-ConfigureEntry(interp, entryPtr, argc, argv, flags)
+ConfigureEntry(interp, entryPtr, objc, objv, flags)
Tcl_Interp *interp; /* Used for error reporting. */
- register Entry *entryPtr; /* Information about widget; may or may
- * not already have values for some fields. */
- int argc; /* Number of valid entries in argv. */
- char **argv; /* Arguments. */
+ Entry *entryPtr; /* Information about widget; may or may not
+ * already have values for some fields. */
+ int objc; /* Number of valid entries in argv. */
+ Tcl_Obj *CONST objv[]; /* Argument objects. */
int flags; /* Flags to pass to Tk_ConfigureWidget. */
{
+ Tk_SavedOptions savedOptions;
+ Tcl_Obj *errorResult = NULL;
+ int error;
int oldExport;
/*
@@ -890,9 +1125,83 @@ ConfigureEntry(interp, entryPtr, argc, argv, flags)
}
oldExport = entryPtr->exportSelection;
- if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs,
- argc, argv, (char *) entryPtr, flags) != TCL_OK) {
- return TCL_ERROR;
+
+ for (error = 0; error <= 1; error++) {
+ if (!error) {
+ /*
+ * First pass: set options to new values.
+ */
+
+ if (Tk_SetOptions(interp, (char *) entryPtr,
+ entryPtr->optionTable, objc, objv,
+ entryPtr->tkwin, &savedOptions, (int *) NULL) != TCL_OK) {
+ continue;
+ }
+ } else {
+ /*
+ * Second pass: restore options to old values.
+ */
+
+ errorResult = Tcl_GetObjResult(interp);
+ Tcl_IncrRefCount(errorResult);
+ Tk_RestoreSavedOptions(&savedOptions);
+ }
+
+ /*
+ * A few other options also need special processing, such as parsing
+ * the geometry and setting the background from a 3-D border.
+ */
+
+ Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder);
+
+ if (entryPtr->insertWidth <= 0) {
+ entryPtr->insertWidth = 2;
+ }
+ if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) {
+ entryPtr->insertBorderWidth = entryPtr->insertWidth/2;
+ }
+
+ /*
+ * Restart the cursor timing sequence in case the on-time or
+ * off-time just changed. Set validate temporarily to none,
+ * so the configure doesn't cause it to be triggered.
+ */
+
+ if (entryPtr->flags & GOT_FOCUS) {
+ int validate = entryPtr->validate;
+ entryPtr->validate = VALIDATE_NONE;
+ EntryFocusProc(entryPtr, 1);
+ entryPtr->validate = validate;
+ }
+
+ /*
+ * Claim the selection if we've suddenly started exporting it.
+ */
+
+ if (entryPtr->exportSelection && (!oldExport)
+ && (entryPtr->selectFirst != -1)
+ && !(entryPtr->flags & GOT_SELECTION)) {
+ Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
+ (ClientData) entryPtr);
+ entryPtr->flags |= GOT_SELECTION;
+ }
+
+ /*
+ * Recompute the window's geometry and arrange for it to be
+ * redisplayed.
+ */
+
+ Tk_SetInternalBorder(entryPtr->tkwin,
+ entryPtr->borderWidth + entryPtr->highlightWidth);
+ if (entryPtr->highlightWidth <= 0) {
+ entryPtr->highlightWidth = 0;
+ }
+ entryPtr->inset = entryPtr->highlightWidth
+ + entryPtr->borderWidth + XPAD;
+ break;
+ }
+ if (!error) {
+ Tk_FreeSavedOptions(&savedOptions);
}
/*
@@ -915,63 +1224,14 @@ ConfigureEntry(interp, entryPtr, argc, argv, flags)
EntryTextVarProc, (ClientData) entryPtr);
}
- /*
- * A few other options also need special processing, such as parsing
- * the geometry and setting the background from a 3-D border.
- */
-
- if ((entryPtr->state != tkNormalUid)
- && (entryPtr->state != tkDisabledUid)) {
- Tcl_AppendResult(interp, "bad state value \"", entryPtr->state,
- "\": must be normal or disabled", (char *) NULL);
- entryPtr->state = tkNormalUid;
+ EntryWorldChanged((ClientData) entryPtr);
+ if (error) {
+ Tcl_SetObjResult(interp, errorResult);
+ Tcl_DecrRefCount(errorResult);
return TCL_ERROR;
+ } else {
+ return TCL_OK;
}
-
- Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder);
-
- if (entryPtr->insertWidth <= 0) {
- entryPtr->insertWidth = 2;
- }
- if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) {
- entryPtr->insertBorderWidth = entryPtr->insertWidth/2;
- }
-
- /*
- * Restart the cursor timing sequence in case the on-time or off-time
- * just changed.
- */
-
- if (entryPtr->flags & GOT_FOCUS) {
- EntryFocusProc(entryPtr, 1);
- }
-
- /*
- * Claim the selection if we've suddenly started exporting it.
- */
-
- if (entryPtr->exportSelection && (!oldExport)
- && (entryPtr->selectFirst != -1)
- && !(entryPtr->flags & GOT_SELECTION)) {
- Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
- (ClientData) entryPtr);
- entryPtr->flags |= GOT_SELECTION;
- }
-
- /*
- * Recompute the window's geometry and arrange for it to be
- * redisplayed.
- */
-
- Tk_SetInternalBorder(entryPtr->tkwin,
- entryPtr->borderWidth + entryPtr->highlightWidth);
- if (entryPtr->highlightWidth <= 0) {
- entryPtr->highlightWidth = 0;
- }
- entryPtr->inset = entryPtr->highlightWidth + entryPtr->borderWidth + XPAD;
-
- EntryWorldChanged((ClientData) entryPtr);
- return TCL_OK;
}
/*
@@ -997,7 +1257,7 @@ EntryWorldChanged(instanceData)
ClientData instanceData; /* Information about widget. */
{
XGCValues gcValues;
- GC gc;
+ GC gc = None;
unsigned long mask;
Entry *entryPtr;
@@ -1008,12 +1268,15 @@ EntryWorldChanged(instanceData)
entryPtr->avgWidth = 1;
}
+ if (entryPtr->normalBorder != NULL) {
+ Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder);
+ }
+
gcValues.foreground = entryPtr->fgColorPtr->pixel;
gcValues.font = Tk_FontId(entryPtr->tkfont);
gcValues.graphics_exposures = False;
mask = GCForeground | GCFont | GCGraphicsExposures;
- gc = Tk_GetGCColor(entryPtr->tkwin, mask, &gcValues, entryPtr->fgColorPtr,
- NULL);
+ gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues);
if (entryPtr->textGC != None) {
Tk_FreeGC(entryPtr->display, entryPtr->textGC);
}
@@ -1022,8 +1285,7 @@ EntryWorldChanged(instanceData)
gcValues.foreground = entryPtr->selFgColorPtr->pixel;
gcValues.font = Tk_FontId(entryPtr->tkfont);
mask = GCForeground | GCFont;
- gc = Tk_GetGCColor(entryPtr->tkwin, mask, &gcValues,
- entryPtr->selFgColorPtr, NULL);
+ gc = Tk_GetGC(entryPtr->tkwin, mask, &gcValues);
if (entryPtr->selTextGC != None) {
Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
}
@@ -1059,9 +1321,9 @@ static void
DisplayEntry(clientData)
ClientData clientData; /* Information about window. */
{
- register Entry *entryPtr = (Entry *) clientData;
- register Tk_Window tkwin = entryPtr->tkwin;
- int baseY, selStartX, selEndX, cursorX, x, w;
+ Entry *entryPtr = (Entry *) clientData;
+ Tk_Window tkwin = entryPtr->tkwin;
+ int baseY, selStartX, selEndX, cursorX;
int xBound;
Tk_FontMetrics fm;
Pixmap pixmap;
@@ -1119,19 +1381,21 @@ DisplayEntry(clientData)
*/
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
- 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
- if (showSelection && (entryPtr->selectLast > entryPtr->leftIndex)) {
+ 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
+
+ if (showSelection
+ && (entryPtr->selectLast > entryPtr->leftIndex)) {
if (entryPtr->selectFirst <= entryPtr->leftIndex) {
selStartX = entryPtr->leftX;
} else {
Tk_CharBbox(entryPtr->textLayout, entryPtr->selectFirst,
- &x, NULL, NULL, NULL);
- selStartX = x + entryPtr->layoutX;
+ &selStartX, NULL, NULL, NULL);
+ selStartX += entryPtr->layoutX;
}
if ((selStartX - entryPtr->selBorderWidth) < xBound) {
- Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast - 1,
- &x, NULL, &w, NULL);
- selEndX = x + w + entryPtr->layoutX;
+ Tk_CharBbox(entryPtr->textLayout, entryPtr->selectLast,
+ &selEndX, NULL, NULL, NULL);
+ selEndX += entryPtr->layoutX;
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder,
selStartX - entryPtr->selBorderWidth,
baseY - fm.ascent - entryPtr->selBorderWidth,
@@ -1151,33 +1415,22 @@ DisplayEntry(clientData)
*/
if ((entryPtr->insertPos >= entryPtr->leftIndex)
- && (entryPtr->state == tkNormalUid)
+ && (entryPtr->state == STATE_NORMAL)
&& (entryPtr->flags & GOT_FOCUS)) {
- if (entryPtr->insertPos == 0) {
- cursorX = 0;
- } else if (entryPtr->insertPos >= entryPtr->numChars) {
- int idx = entryPtr->numChars >= 1 ? entryPtr->numChars - 1 : 0;
- Tk_CharBbox(entryPtr->textLayout, idx,
- &x, NULL, &w, NULL);
- cursorX = x + w;
- } else {
- Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos,
- &x, NULL, NULL, NULL);
- cursorX = x;
- }
+ Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &cursorX, NULL,
+ NULL, NULL);
cursorX += entryPtr->layoutX;
cursorX -= (entryPtr->insertWidth)/2;
if (cursorX < xBound) {
if (entryPtr->flags & CURSOR_ON) {
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder,
- cursorX, baseY - fm.ascent,
- entryPtr->insertWidth, fm.ascent + fm.descent,
- entryPtr->insertBorderWidth, TK_RELIEF_RAISED);
+ cursorX, baseY - fm.ascent, entryPtr->insertWidth,
+ fm.ascent + fm.descent, entryPtr->insertBorderWidth,
+ TK_RELIEF_RAISED);
} else if (entryPtr->insertBorder == entryPtr->selBorder) {
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
- cursorX, baseY - fm.ascent,
- entryPtr->insertWidth, fm.ascent + fm.descent,
- 0, TK_RELIEF_FLAT);
+ cursorX, baseY - fm.ascent, entryPtr->insertWidth,
+ fm.ascent + fm.descent, 0, TK_RELIEF_FLAT);
}
}
}
@@ -1191,18 +1444,19 @@ DisplayEntry(clientData)
entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY,
entryPtr->leftIndex, entryPtr->numChars);
- if (showSelection && (entryPtr->selTextGC != entryPtr->textGC) &&
- (entryPtr->selectFirst < entryPtr->selectLast)) {
- int first;
+ if (showSelection
+ && (entryPtr->selTextGC != entryPtr->textGC)
+ && (entryPtr->selectFirst < entryPtr->selectLast)) {
+ int selFirst;
- if (entryPtr->selectFirst - entryPtr->leftIndex < 0) {
- first = entryPtr->leftIndex;
+ if (entryPtr->selectFirst < entryPtr->leftIndex) {
+ selFirst = entryPtr->leftIndex;
} else {
- first = entryPtr->selectFirst;
+ selFirst = entryPtr->selectFirst;
}
Tk_DrawTextLayout(entryPtr->display, pixmap, entryPtr->selTextGC,
entryPtr->textLayout, entryPtr->layoutX, entryPtr->layoutY,
- first, entryPtr->selectLast);
+ selFirst, entryPtr->selectLast);
}
/*
@@ -1213,19 +1467,22 @@ DisplayEntry(clientData)
if (entryPtr->relief != TK_RELIEF_FLAT) {
Tk_Draw3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
entryPtr->highlightWidth, entryPtr->highlightWidth,
- Tk_Width(tkwin) - 2*entryPtr->highlightWidth,
- Tk_Height(tkwin) - 2*entryPtr->highlightWidth,
+ Tk_Width(tkwin) - 2 * entryPtr->highlightWidth,
+ Tk_Height(tkwin) - 2 * entryPtr->highlightWidth,
entryPtr->borderWidth, entryPtr->relief);
}
if (entryPtr->highlightWidth != 0) {
- GC gc;
+ GC fgGC, bgGC;
+ bgGC = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap);
if (entryPtr->flags & GOT_FOCUS) {
- gc = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap);
+ fgGC = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap);
+ TkpDrawHighlightBorder(tkwin, fgGC, bgGC,
+ entryPtr->highlightWidth, pixmap);
} else {
- gc = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap);
+ TkpDrawHighlightBorder(tkwin, bgGC, bgGC,
+ entryPtr->highlightWidth, pixmap);
}
- Tk_DrawFocusHighlight(tkwin, gc, entryPtr->highlightWidth, pixmap);
}
/*
@@ -1262,38 +1519,53 @@ DisplayEntry(clientData)
static void
EntryComputeGeometry(entryPtr)
- Entry *entryPtr; /* Widget record for entry. */
+ Entry *entryPtr; /* Widget record for entry. */
{
int totalLength, overflow, maxOffScreen, rightX;
int height, width, i;
Tk_FontMetrics fm;
- char *p, *displayString;
+ char *p;
+
+ if (entryPtr->displayString != entryPtr->string) {
+ ckfree(entryPtr->displayString);
+ entryPtr->displayString = entryPtr->string;
+ entryPtr->numDisplayBytes = entryPtr->numBytes;
+ }
/*
* If we're displaying a special character instead of the value of
* the entry, recompute the displayString.
*/
- if (entryPtr->displayString != NULL) {
- ckfree(entryPtr->displayString);
- entryPtr->displayString = NULL;
- }
if (entryPtr->showChar != NULL) {
- entryPtr->displayString = (char *) ckalloc((unsigned)
- (entryPtr->numChars + 1));
- for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0;
- i--, p++) {
- *p = entryPtr->showChar[0];
+ Tcl_UniChar ch;
+ char buf[TCL_UTF_MAX];
+ int size;
+
+ /*
+ * Normalize the special character so we can safely duplicate it
+ * in the display string. If we didn't do this, then two malformed
+ * characters might end up looking like one valid UTF character in
+ * the resulting string.
+ */
+
+ Tcl_UtfToUniChar(entryPtr->showChar, &ch);
+ size = Tcl_UniCharToUtf(ch, buf);
+
+ entryPtr->numDisplayBytes = entryPtr->numChars * size;
+ entryPtr->displayString =
+ (char *) ckalloc((unsigned) (entryPtr->numDisplayBytes + 1));
+
+ p = entryPtr->displayString;
+ for (i = entryPtr->numChars; --i >= 0; ) {
+ p += Tcl_UniCharToUtf(ch, p);
}
- *p = 0;
- displayString = entryPtr->displayString;
- } else {
- displayString = entryPtr->string;
+ *p = '\0';
}
Tk_FreeTextLayout(entryPtr->textLayout);
entryPtr->textLayout = Tk_ComputeTextLayout(entryPtr->tkfont,
- displayString, entryPtr->numChars, 0, entryPtr->justify,
- TK_IGNORE_NEWLINES, &totalLength, &height);
+ entryPtr->displayString, entryPtr->numChars, 0,
+ entryPtr->justify, TK_IGNORE_NEWLINES, &totalLength, &height);
entryPtr->layoutY = (Tk_Height(entryPtr->tkwin) - height) / 2;
@@ -1328,13 +1600,13 @@ EntryComputeGeometry(entryPtr)
Tk_CharBbox(entryPtr->textLayout, maxOffScreen,
&rightX, NULL, NULL, NULL);
if (rightX < overflow) {
- maxOffScreen += 1;
+ maxOffScreen++;
}
if (entryPtr->leftIndex > maxOffScreen) {
entryPtr->leftIndex = maxOffScreen;
}
- Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex,
- &rightX, NULL, NULL, NULL);
+ Tk_CharBbox(entryPtr->textLayout, entryPtr->leftIndex, &rightX,
+ NULL, NULL, NULL);
entryPtr->leftX = entryPtr->inset;
entryPtr->layoutX = entryPtr->leftX - rightX;
}
@@ -1371,28 +1643,59 @@ EntryComputeGeometry(entryPtr)
*/
static void
-InsertChars(entryPtr, index, string)
- register Entry *entryPtr; /* Entry that is to get the new
- * elements. */
+InsertChars(entryPtr, index, value)
+ Entry *entryPtr; /* Entry that is to get the new elements. */
int index; /* Add the new elements before this
- * element. */
- char *string; /* New characters to add (NULL-terminated
+ * character index. */
+ char *value; /* New characters to add (NULL-terminated
* string). */
{
- int length;
- char *new;
+ int byteIndex, byteCount, oldChars, charsAdded, newByteCount;
+ char *new, *string;
- length = strlen(string);
- if (length == 0) {
+ string = entryPtr->string;
+ byteIndex = Tcl_UtfAtIndex(string, index) - string;
+ byteCount = strlen(value);
+ if (byteCount == 0) {
return;
}
- new = (char *) ckalloc((unsigned) (entryPtr->numChars + length + 1));
- strncpy(new, entryPtr->string, (size_t) index);
- strcpy(new+index, string);
- strcpy(new+index+length, entryPtr->string+index);
- ckfree(entryPtr->string);
+
+ newByteCount = entryPtr->numBytes + byteCount + 1;
+ new = (char *) ckalloc((unsigned) newByteCount);
+ memcpy(new, string, (size_t) byteIndex);
+ strcpy(new + byteIndex, value);
+ strcpy(new + byteIndex + byteCount, string + byteIndex);
+
+ if ((entryPtr->validate == VALIDATE_KEY ||
+ entryPtr->validate == VALIDATE_ALL) &&
+ EntryValidateChange(entryPtr, value, new, index,
+ VALIDATE_INSERT) != TCL_OK) {
+ ckfree(new);
+ return;
+ }
+
+ ckfree(string);
entryPtr->string = new;
- entryPtr->numChars += length;
+
+ /*
+ * The following construction is used because inserting improperly
+ * formed UTF-8 sequences between other improperly formed UTF-8
+ * sequences could result in actually forming valid UTF-8 sequences;
+ * the number of characters added may not be Tcl_NumUtfChars(string, -1),
+ * because of context. The actual number of characters added is how
+ * many characters are in the string now minus the number that
+ * used to be there.
+ */
+
+ oldChars = entryPtr->numChars;
+ entryPtr->numChars = Tcl_NumUtfChars(new, -1);
+ charsAdded = entryPtr->numChars - oldChars;
+ entryPtr->numBytes += byteCount;
+
+ if (entryPtr->displayString == string) {
+ entryPtr->displayString = new;
+ entryPtr->numDisplayBytes = entryPtr->numBytes;
+ }
/*
* Inserting characters invalidates all indexes into the string.
@@ -1403,19 +1706,20 @@ InsertChars(entryPtr, index, string)
*/
if (entryPtr->selectFirst >= index) {
- entryPtr->selectFirst += length;
+ entryPtr->selectFirst += charsAdded;
}
if (entryPtr->selectLast > index) {
- entryPtr->selectLast += length;
+ entryPtr->selectLast += charsAdded;
}
- if ((entryPtr->selectAnchor > index) || (entryPtr->selectFirst >= index)) {
- entryPtr->selectAnchor += length;
+ if ((entryPtr->selectAnchor > index)
+ || (entryPtr->selectFirst >= index)) {
+ entryPtr->selectAnchor += charsAdded;
}
if (entryPtr->leftIndex > index) {
- entryPtr->leftIndex += length;
+ entryPtr->leftIndex += charsAdded;
}
if (entryPtr->insertPos >= index) {
- entryPtr->insertPos += length;
+ entryPtr->insertPos += charsAdded;
}
EntryValueChanged(entryPtr);
}
@@ -1439,11 +1743,12 @@ InsertChars(entryPtr, index, string)
static void
DeleteChars(entryPtr, index, count)
- register Entry *entryPtr; /* Entry widget to modify. */
+ Entry *entryPtr; /* Entry widget to modify. */
int index; /* Index of first character to delete. */
int count; /* How many characters to delete. */
{
- char *new;
+ int byteIndex, byteCount, newByteCount;
+ char *new, *string, *todelete;
if ((index + count) > entryPtr->numChars) {
count = entryPtr->numChars - index;
@@ -1452,12 +1757,38 @@ DeleteChars(entryPtr, index, count)
return;
}
- new = (char *) ckalloc((unsigned) (entryPtr->numChars + 1 - count));
- strncpy(new, entryPtr->string, (size_t) index);
- strcpy(new+index, entryPtr->string+index+count);
+ string = entryPtr->string;
+ byteIndex = Tcl_UtfAtIndex(string, index) - string;
+ byteCount = Tcl_UtfAtIndex(string + byteIndex, count) - (string + byteIndex);
+
+ newByteCount = entryPtr->numBytes + 1 - byteCount;
+ new = (char *) ckalloc((unsigned) newByteCount);
+ memcpy(new, string, (size_t) byteIndex);
+ strcpy(new + byteIndex, string + byteIndex + byteCount);
+
+ todelete = (char *) ckalloc((unsigned) (byteCount + 1));
+ memcpy(todelete, string + byteIndex, (size_t) byteCount);
+ todelete[byteCount] = '\0';
+
+ if ((entryPtr->validate == VALIDATE_KEY ||
+ entryPtr->validate == VALIDATE_ALL) &&
+ EntryValidateChange(entryPtr, todelete, new, index,
+ VALIDATE_DELETE) != TCL_OK) {
+ ckfree(new);
+ ckfree(todelete);
+ return;
+ }
+
+ ckfree(todelete);
ckfree(entryPtr->string);
entryPtr->string = new;
entryPtr->numChars -= count;
+ entryPtr->numBytes -= byteCount;
+
+ if (entryPtr->displayString == string) {
+ entryPtr->displayString = new;
+ entryPtr->numDisplayBytes = entryPtr->numBytes;
+ }
/*
* Deleting characters results in the remaining characters being
@@ -1466,21 +1797,22 @@ DeleteChars(entryPtr, index, count)
*/
if (entryPtr->selectFirst >= index) {
- if (entryPtr->selectFirst >= (index+count)) {
+ if (entryPtr->selectFirst >= (index + count)) {
entryPtr->selectFirst -= count;
} else {
entryPtr->selectFirst = index;
}
}
if (entryPtr->selectLast >= index) {
- if (entryPtr->selectLast >= (index+count)) {
+ if (entryPtr->selectLast >= (index + count)) {
entryPtr->selectLast -= count;
} else {
entryPtr->selectLast = index;
}
}
if (entryPtr->selectLast <= entryPtr->selectFirst) {
- entryPtr->selectFirst = entryPtr->selectLast = -1;
+ entryPtr->selectFirst = -1;
+ entryPtr->selectLast = -1;
}
if (entryPtr->selectAnchor >= index) {
if (entryPtr->selectAnchor >= (index+count)) {
@@ -1490,14 +1822,14 @@ DeleteChars(entryPtr, index, count)
}
}
if (entryPtr->leftIndex > index) {
- if (entryPtr->leftIndex >= (index+count)) {
+ if (entryPtr->leftIndex >= (index + count)) {
entryPtr->leftIndex -= count;
} else {
entryPtr->leftIndex = index;
}
}
if (entryPtr->insertPos >= index) {
- if (entryPtr->insertPos >= (index+count)) {
+ if (entryPtr->insertPos >= (index + count)) {
entryPtr->insertPos -= count;
} else {
entryPtr->insertPos = index;
@@ -1583,24 +1915,74 @@ EntryValueChanged(entryPtr)
static void
EntrySetValue(entryPtr, value)
- register Entry *entryPtr; /* Entry whose value is to be
- * changed. */
- char *value; /* New text to display in entry. */
+ Entry *entryPtr; /* Entry whose value is to be changed. */
+ char *value; /* New text to display in entry. */
{
+ char *oldSource;
+ int code, valueLen, malloced = 0;
+
+ if (strcmp(value, entryPtr->string) == 0) {
+ return;
+ }
+ valueLen = strlen(value);
+
+ if (entryPtr->flags & VALIDATE_VAR) {
+ entryPtr->flags |= VALIDATE_ABORT;
+ } else {
+ /*
+ * If we validate, we create a copy of the value, as it may
+ * point to volatile memory, like the value of the -textvar
+ * which may get freed during validation
+ */
+ oldSource = (char *) ckalloc((unsigned) (valueLen + 1));
+ strcpy(oldSource, value);
+ value = oldSource;
+ malloced = 1;
+
+ entryPtr->flags |= VALIDATE_VAR;
+ code = EntryValidateChange(entryPtr, (char *) NULL, value, -1,
+ VALIDATE_FORCED);
+ entryPtr->flags &= ~VALIDATE_VAR;
+ /*
+ * If VALIDATE_ABORT has been set, then this operation should be
+ * aborted because the validatecommand did something else instead
+ */
+ if (entryPtr->flags & VALIDATE_ABORT) {
+ entryPtr->flags &= ~VALIDATE_ABORT;
+ ckfree(value);
+ return;
+ }
+ }
+
+ oldSource = entryPtr->string;
ckfree(entryPtr->string);
- entryPtr->numChars = strlen(value);
- entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numChars + 1));
- strcpy(entryPtr->string, value);
- if (entryPtr->selectFirst != -1) {
+
+ if (malloced) {
+ entryPtr->string = value;
+ } else {
+ entryPtr->string = (char *) ckalloc((unsigned) (valueLen + 1));
+ strcpy(entryPtr->string, value);
+ }
+ entryPtr->numBytes = valueLen;
+ entryPtr->numChars = Tcl_NumUtfChars(value, valueLen);
+
+ if (entryPtr->displayString == oldSource) {
+ entryPtr->displayString = entryPtr->string;
+ entryPtr->numDisplayBytes = entryPtr->numBytes;
+ }
+
+ if (entryPtr->selectFirst >= 0) {
if (entryPtr->selectFirst >= entryPtr->numChars) {
- entryPtr->selectFirst = entryPtr->selectLast = -1;
+ entryPtr->selectFirst = -1;
+ entryPtr->selectLast = -1;
} else if (entryPtr->selectLast > entryPtr->numChars) {
entryPtr->selectLast = entryPtr->numChars;
}
}
if (entryPtr->leftIndex >= entryPtr->numChars) {
- entryPtr->leftIndex = entryPtr->numChars-1;
- if (entryPtr->leftIndex < 0) {
+ if (entryPtr->numChars > 0) {
+ entryPtr->leftIndex = entryPtr->numChars - 1;
+ } else {
entryPtr->leftIndex = 0;
}
}
@@ -1641,14 +2023,7 @@ EntryEventProc(clientData, eventPtr)
EventuallyRedraw(entryPtr);
entryPtr->flags |= BORDER_NEEDED;
} else if (eventPtr->type == DestroyNotify) {
- if (entryPtr->tkwin != NULL) {
- entryPtr->tkwin = NULL;
- Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd);
- }
- if (entryPtr->flags & REDRAW_PENDING) {
- Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr);
- }
- Tcl_EventuallyFree((ClientData) entryPtr, DestroyEntry);
+ DestroyEntry((char *) clientData);
} else if (eventPtr->type == ConfigureNotify) {
Tcl_Preserve((ClientData) entryPtr);
entryPtr->flags |= UPDATE_SCROLLBAR;
@@ -1689,7 +2064,6 @@ EntryCmdDeletedProc(clientData)
ClientData clientData; /* Pointer to widget record for widget. */
{
Entry *entryPtr = (Entry *) clientData;
- Tk_Window tkwin = entryPtr->tkwin;
/*
* This procedure could be invoked either because the window was
@@ -1698,14 +2072,13 @@ EntryCmdDeletedProc(clientData)
* destroys the widget.
*/
- if (tkwin != NULL) {
- entryPtr->tkwin = NULL;
- Tk_DestroyWindow(tkwin);
+ if (!(entryPtr->flags & ENTRY_DELETED)) {
+ Tk_DestroyWindow(entryPtr->tkwin);
}
}
/*
- *--------------------------------------------------------------
+ *---------------------------------------------------------------------------
*
* GetEntryIndex --
*
@@ -1714,15 +2087,15 @@ EntryCmdDeletedProc(clientData)
*
* Results:
* A standard Tcl result. If all went well, then *indexPtr is
- * filled in with the index (into entryPtr) corresponding to
+ * filled in with the character index (into entryPtr) corresponding to
* string. The index value is guaranteed to lie between 0 and
* the number of characters in the string, inclusive. If an
- * error occurs then an error message is left in interp->result.
+ * error occurs then an error message is left in the interp's result.
*
* Side effects:
* None.
*
- *--------------------------------------------------------------
+ *---------------------------------------------------------------------------
*/
static int
@@ -1731,7 +2104,8 @@ GetEntryIndex(interp, entryPtr, string, indexPtr)
Entry *entryPtr; /* Entry for which the index is being
* specified. */
char *string; /* Specifies character in entryPtr. */
- int *indexPtr; /* Where to store converted index. */
+ int *indexPtr; /* Where to store converted character
+ * index. */
{
size_t length;
@@ -1744,7 +2118,7 @@ GetEntryIndex(interp, entryPtr, string, indexPtr)
badIndex:
/*
- * Some of the paths here leave messages in interp->result,
+ * Some of the paths here leave messages in the interp's result,
* so we have to clear it out before storing our own message.
*/
@@ -1766,8 +2140,8 @@ GetEntryIndex(interp, entryPtr, string, indexPtr)
goto badIndex;
}
} else if (string[0] == 's') {
- if (entryPtr->selectFirst == -1) {
- interp->result = "selection isn't in entry";
+ if (entryPtr->selectFirst < 0) {
+ Tcl_SetResult(interp, "selection isn't in entry", TCL_STATIC);
return TCL_ERROR;
}
if (length < 5) {
@@ -1783,7 +2157,7 @@ GetEntryIndex(interp, entryPtr, string, indexPtr)
} else if (string[0] == '@') {
int x, roundUp;
- if (Tcl_GetInt(interp, string+1, &x) != TCL_OK) {
+ if (Tcl_GetInt(interp, string + 1, &x) != TCL_OK) {
goto badIndex;
}
if (x < entryPtr->inset) {
@@ -1815,7 +2189,7 @@ GetEntryIndex(interp, entryPtr, string, indexPtr)
*indexPtr = 0;
} else if (*indexPtr > entryPtr->numChars) {
*indexPtr = entryPtr->numChars;
- }
+ }
}
if(*indexPtr > entryPtr->numChars)
*indexPtr = entryPtr->numChars;
@@ -1841,9 +2215,8 @@ GetEntryIndex(interp, entryPtr, string, indexPtr)
static void
EntryScanTo(entryPtr, x)
- register Entry *entryPtr; /* Information about widget. */
- int x; /* X-coordinate to use for scan
- * operation. */
+ Entry *entryPtr; /* Information about widget. */
+ int x; /* X-coordinate to use for scan operation. */
{
int newLeftIndex;
@@ -1859,19 +2232,24 @@ EntryScanTo(entryPtr, x)
*/
newLeftIndex = entryPtr->scanMarkIndex
- - (10*(x - entryPtr->scanMarkX))/entryPtr->avgWidth;
+ - (10 * (x - entryPtr->scanMarkX)) / entryPtr->avgWidth;
if (newLeftIndex >= entryPtr->numChars) {
- newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars-1;
+ newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars - 1;
entryPtr->scanMarkX = x;
}
if (newLeftIndex < 0) {
newLeftIndex = entryPtr->scanMarkIndex = 0;
entryPtr->scanMarkX = x;
}
+
if (newLeftIndex != entryPtr->leftIndex) {
entryPtr->leftIndex = newLeftIndex;
entryPtr->flags |= UPDATE_SCROLLBAR;
EntryComputeGeometry(entryPtr);
+ if (newLeftIndex != entryPtr->leftIndex) {
+ entryPtr->scanMarkIndex = entryPtr->leftIndex;
+ entryPtr->scanMarkX = x;
+ }
EventuallyRedraw(entryPtr);
}
}
@@ -1895,10 +2273,9 @@ EntryScanTo(entryPtr, x)
static void
EntrySelectTo(entryPtr, index)
- register Entry *entryPtr; /* Information about widget. */
- int index; /* Index of element that is to
- * become the "other" end of the
- * selection. */
+ Entry *entryPtr; /* Information about widget. */
+ int index; /* Character index of element that is to
+ * become the "other" end of the selection. */
{
int newFirst, newLast;
@@ -1961,38 +2338,35 @@ EntrySelectTo(entryPtr, index)
static int
EntryFetchSelection(clientData, offset, buffer, maxBytes)
- ClientData clientData; /* Information about entry widget. */
- int offset; /* Offset within selection of first
- * character to be returned. */
- char *buffer; /* Location in which to place
- * selection. */
- int maxBytes; /* Maximum number of bytes to place
- * at buffer, not including terminating
- * NULL character. */
+ ClientData clientData; /* Information about entry widget. */
+ int offset; /* Byte offset within selection of first
+ * character to be returned. */
+ char *buffer; /* Location in which to place selection. */
+ int maxBytes; /* Maximum number of bytes to place at
+ * buffer, not including terminating NULL
+ * character. */
{
Entry *entryPtr = (Entry *) clientData;
- int count;
- char *displayString;
+ int byteCount;
+ char *string, *selStart, *selEnd;
if ((entryPtr->selectFirst < 0) || !(entryPtr->exportSelection)) {
return -1;
}
- count = entryPtr->selectLast - entryPtr->selectFirst - offset;
- if (count > maxBytes) {
- count = maxBytes;
+ string = entryPtr->displayString;
+ selStart = Tcl_UtfAtIndex(string, entryPtr->selectFirst);
+ selEnd = Tcl_UtfAtIndex(selStart,
+ entryPtr->selectLast - entryPtr->selectFirst);
+ byteCount = selEnd - selStart - offset;
+ if (byteCount > maxBytes) {
+ byteCount = maxBytes;
}
- if (count <= 0) {
+ if (byteCount <= 0) {
return 0;
}
- if (entryPtr->displayString == NULL) {
- displayString = entryPtr->string;
- } else {
- displayString = entryPtr->displayString;
- }
- strncpy(buffer, displayString + entryPtr->selectFirst + offset,
- (size_t) count);
- buffer[count] = '\0';
- return count;
+ memcpy(buffer, selStart + offset, (size_t) byteCount);
+ buffer[byteCount] = '\0';
+ return byteCount;
}
/*
@@ -2015,7 +2389,7 @@ EntryFetchSelection(clientData, offset, buffer, maxBytes)
static void
EntryLostSelection(clientData)
- ClientData clientData; /* Information about entry widget. */
+ ClientData clientData; /* Information about entry widget. */
{
Entry *entryPtr = (Entry *) clientData;
@@ -2028,7 +2402,7 @@ EntryLostSelection(clientData)
*/
#ifdef ALWAYS_SHOW_SELECTION
- if ((entryPtr->selectFirst != -1) && entryPtr->exportSelection) {
+ if ((entryPtr->selectFirst >= 0) && entryPtr->exportSelection) {
entryPtr->selectFirst = -1;
entryPtr->selectLast = -1;
EventuallyRedraw(entryPtr);
@@ -2057,7 +2431,7 @@ EntryLostSelection(clientData)
static void
EventuallyRedraw(entryPtr)
- register Entry *entryPtr; /* Information about widget. */
+ Entry *entryPtr; /* Information about widget. */
{
if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) {
return;
@@ -2096,11 +2470,11 @@ EventuallyRedraw(entryPtr)
static void
EntryVisibleRange(entryPtr, firstPtr, lastPtr)
- Entry *entryPtr; /* Information about widget. */
- double *firstPtr; /* Return position of first visible
- * character in widget. */
- double *lastPtr; /* Return position of char just after
- * last visible one. */
+ Entry *entryPtr; /* Information about widget. */
+ double *firstPtr; /* Return position of first visible
+ * character in widget. */
+ double *lastPtr; /* Return position of char just after last
+ * visible one. */
{
int charsInWindow;
@@ -2110,22 +2484,18 @@ EntryVisibleRange(entryPtr, firstPtr, lastPtr)
} else {
charsInWindow = Tk_PointToChar(entryPtr->textLayout,
Tk_Width(entryPtr->tkwin) - entryPtr->inset
- - entryPtr->layoutX - 1, 0) + 1;
- if (charsInWindow > entryPtr->numChars) {
- /*
- * If all chars were visible, then charsInWindow will be
- * the index just after the last char that was visible.
- */
-
- charsInWindow = entryPtr->numChars;
+ - entryPtr->layoutX - 1, 0);
+ if (charsInWindow < entryPtr->numChars) {
+ charsInWindow++;
}
charsInWindow -= entryPtr->leftIndex;
if (charsInWindow == 0) {
charsInWindow = 1;
}
- *firstPtr = ((double) entryPtr->leftIndex)/entryPtr->numChars;
- *lastPtr = ((double) (entryPtr->leftIndex + charsInWindow))
- /entryPtr->numChars;
+
+ *firstPtr = (double) entryPtr->leftIndex / entryPtr->numChars;
+ *lastPtr = (double) (entryPtr->leftIndex + charsInWindow)
+ / entryPtr->numChars;
}
}
@@ -2153,7 +2523,7 @@ static void
EntryUpdateScrollbar(entryPtr)
Entry *entryPtr; /* Information about widget. */
{
- char args[100];
+ char args[TCL_DOUBLE_SPACE * 2];
int code;
double first, last;
Tcl_Interp *interp;
@@ -2198,9 +2568,10 @@ static void
EntryBlinkProc(clientData)
ClientData clientData; /* Pointer to record describing entry. */
{
- register Entry *entryPtr = (Entry *) clientData;
+ Entry *entryPtr = (Entry *) clientData;
- if (!(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) {
+ if ((entryPtr->state == STATE_DISABLED) ||
+ !(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) {
return;
}
if (entryPtr->flags & CURSOR_ON) {
@@ -2235,7 +2606,7 @@ EntryBlinkProc(clientData)
static void
EntryFocusProc(entryPtr, gotFocus)
- register Entry *entryPtr; /* Entry that got or lost focus. */
+ Entry *entryPtr; /* Entry that got or lost focus. */
int gotFocus; /* 1 means window is getting focus, 0 means
* it's losing it. */
{
@@ -2247,9 +2618,21 @@ EntryFocusProc(entryPtr, gotFocus)
entryPtr->insertOnTime, EntryBlinkProc,
(ClientData) entryPtr);
}
+ if (entryPtr->validate == VALIDATE_ALL ||
+ entryPtr->validate == VALIDATE_FOCUS ||
+ entryPtr->validate == VALIDATE_FOCUSIN) {
+ EntryValidateChange(entryPtr, (char *) NULL,
+ entryPtr->string, -1, VALIDATE_FOCUSIN);
+ }
} else {
entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON);
entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
+ if (entryPtr->validate == VALIDATE_ALL ||
+ entryPtr->validate == VALIDATE_FOCUS ||
+ entryPtr->validate == VALIDATE_FOCUSOUT) {
+ EntryValidateChange(entryPtr, (char *) NULL,
+ entryPtr->string, -1, VALIDATE_FOCUSOUT);
+ }
}
EventuallyRedraw(entryPtr);
}
@@ -2281,7 +2664,7 @@ EntryTextVarProc(clientData, interp, name1, name2, flags)
char *name2; /* Not used. */
int flags; /* Information about what happened. */
{
- register Entry *entryPtr = (Entry *) clientData;
+ Entry *entryPtr = (Entry *) clientData;
char *value;
/*
@@ -2311,8 +2694,308 @@ EntryTextVarProc(clientData, interp, name1, name2, flags)
if (value == NULL) {
value = "";
}
- if (strcmp(value, entryPtr->string) != 0) {
- EntrySetValue(entryPtr, value);
- }
+ EntrySetValue(entryPtr, value);
return (char *) NULL;
}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EntryValidate --
+ *
+ * This procedure is invoked when any character is added or
+ * removed from the entry widget, or a focus has trigerred validation.
+ *
+ * Results:
+ * TCL_OK if the validatecommand passes the new string.
+ * TCL_BREAK if the vcmd executed OK, but rejects the string.
+ * TCL_ERROR if an error occurred while executing the vcmd
+ * or a valid Tcl_Bool is not returned.
+ *
+ * Side effects:
+ * An error condition may arise
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+EntryValidate(entryPtr, cmd)
+ register Entry *entryPtr; /* Entry that needs validation. */
+ register char *cmd; /* Validation command (NULL-terminated
+ * string). */
+{
+ register Tcl_Interp *interp = entryPtr->interp;
+ int code, bool;
+
+ code = Tcl_EvalEx(interp, cmd, -1, TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT);
+
+ if (code != TCL_OK && code != TCL_RETURN) {
+ Tcl_AddErrorInfo(interp,
+ "\n\t(in validation command executed by entry)");
+ Tcl_BackgroundError(interp);
+ return TCL_ERROR;
+ }
+
+ if (Tcl_GetBooleanFromObj(interp, Tcl_GetObjResult(interp),
+ &bool) != TCL_OK) {
+ Tcl_AddErrorInfo(interp,
+ "\nvalid boolean not returned by validation command");
+ Tcl_BackgroundError(interp);
+ Tcl_SetResult(interp, NULL, 0);
+ return TCL_ERROR;
+ }
+
+ Tcl_SetResult(interp, NULL, 0);
+ return (bool ? TCL_OK : TCL_BREAK);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * EntryValidateChange --
+ *
+ * This procedure is invoked when any character is added or
+ * removed from the entry widget, or a focus has trigerred validation.
+ *
+ * Results:
+ * TCL_OK if the validatecommand accepts the new string,
+ * TCL_ERROR if any problems occured with validatecommand.
+ *
+ * Side effects:
+ * The insertion/deletion may be aborted, and the
+ * validatecommand might turn itself off (if an error
+ * or loop condition arises).
+ *
+ *--------------------------------------------------------------
+ */
+
+static int
+EntryValidateChange(entryPtr, change, new, index, type)
+ register Entry *entryPtr; /* Entry that needs validation. */
+ char *change; /* Characters to be added/deleted
+ * (NULL-terminated string). */
+ char *new; /* Potential new value of entry string */
+ int index; /* index of insert/delete, -1 otherwise */
+ int type; /* forced, delete, insert,
+ * focusin or focusout */
+{
+ int code, varValidate = (entryPtr->flags & VALIDATE_VAR);
+ char *p;
+ Tcl_DString script;
+
+ if (entryPtr->validateCmd == NULL ||
+ entryPtr->validate == VALIDATE_NONE) {
+ return (varValidate ? TCL_ERROR : TCL_OK);
+ }
+
+ /*
+ * If we're already validating, then we're hitting a loop condition
+ * Return and set validate to 0 to disallow further validations
+ * and prevent current validation from finishing
+ */
+ if (entryPtr->flags & VALIDATING) {
+ entryPtr->validate = VALIDATE_NONE;
+ return (varValidate ? TCL_ERROR : TCL_OK);
+ }
+
+ entryPtr->flags |= VALIDATING;
+
+ /*
+ * Now form command string and run through the -validatecommand
+ */
+
+ Tcl_DStringInit(&script);
+ ExpandPercents(entryPtr, entryPtr->validateCmd,
+ change, new, index, type, &script);
+ Tcl_DStringAppend(&script, "", 1);
+
+ p = Tcl_DStringValue(&script);
+ code = EntryValidate(entryPtr, p);
+ Tcl_DStringFree(&script);
+
+ /*
+ * If e->validate has become VALIDATE_NONE during the validation, or
+ * we now have VALIDATE_VAR set (from EntrySetValue) and didn't before,
+ * it means that a loop condition almost occured. Do not allow
+ * this validation result to finish.
+ */
+ if (entryPtr->validate == VALIDATE_NONE
+ || (!varValidate && (entryPtr->flags & VALIDATE_VAR))) {
+ code = TCL_ERROR;
+ }
+ /*
+ * If validate will return ERROR, then disallow further validations
+ * Otherwise, if it didn't accept the new string (returned TCL_BREAK)
+ * then eval the invalidCmd (if it's set)
+ */
+ if (code == TCL_ERROR) {
+ entryPtr->validate = VALIDATE_NONE;
+ } else if (code == TCL_BREAK) {
+ /*
+ * If we were doing forced validation (like via a variable
+ * trace) and the command returned 0, the we turn off validation
+ * because we assume that textvariables have precedence in
+ * managing the value. We also don't call the invcmd, as it
+ * may want to do entry manipulation which the setting of the
+ * var will later wipe anyway.
+ */
+ if (varValidate) {
+ entryPtr->validate = VALIDATE_NONE;
+ } else if (entryPtr->invalidCmd != NULL) {
+ Tcl_DStringInit(&script);
+ ExpandPercents(entryPtr, entryPtr->invalidCmd,
+ change, new, index, type, &script);
+ Tcl_DStringAppend(&script, "", 1);
+ p = Tcl_DStringValue(&script);
+ if (Tcl_EvalEx(entryPtr->interp, p, -1,
+ TCL_EVAL_GLOBAL | TCL_EVAL_DIRECT) != TCL_OK) {
+ Tcl_AddErrorInfo(entryPtr->interp,
+ "\n\t(in invalidcommand executed by entry)");
+ Tcl_BackgroundError(entryPtr->interp);
+ code = TCL_ERROR;
+ entryPtr->validate = VALIDATE_NONE;
+ }
+ Tcl_DStringFree(&script);
+ }
+ }
+
+ entryPtr->flags &= ~VALIDATING;
+
+ return code;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * ExpandPercents --
+ *
+ * Given a command and an event, produce a new command
+ * by replacing % constructs in the original command
+ * with information from the X event.
+ *
+ * Results:
+ * The new expanded command is appended to the dynamic string
+ * given by dsPtr.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+static void
+ExpandPercents(entryPtr, before, change, new, index, type, dsPtr)
+ register Entry *entryPtr; /* Entry that needs validation. */
+ register char *before; /* Command containing percent
+ * expressions to be replaced. */
+ char *change; /* Characters to added/deleted
+ * (NULL-terminated string). */
+ char *new; /* Potential new value of entry string */
+ int index; /* index of insert/delete */
+ int type; /* INSERT or DELETE */
+ Tcl_DString *dsPtr; /* Dynamic string in which to append
+ * new command. */
+{
+ int spaceNeeded, cvtFlags; /* Used to substitute string as proper Tcl
+ * list element. */
+ int number, length;
+ register char *string;
+ Tcl_UniChar ch;
+ char numStorage[2*TCL_INTEGER_SPACE];
+
+ while (1) {
+ if (*before == '\0') {
+ break;
+ }
+ /*
+ * Find everything up to the next % character and append it
+ * to the result string.
+ */
+
+ string = before;
+ /* No need to convert '%', as it is in ascii range */
+ string = Tcl_UtfFindFirst(before, '%');
+ if (string == (char *) NULL) {
+ Tcl_DStringAppend(dsPtr, before, -1);
+ break;
+ } else if (string != before) {
+ Tcl_DStringAppend(dsPtr, before, string-before);
+ before = string;
+ }
+
+ /*
+ * There's a percent sequence here. Process it.
+ */
+
+ before++; /* skip over % */
+ if (*before != '\0') {
+ before += Tcl_UtfToUniChar(before, &ch);
+ } else {
+ ch = '%';
+ }
+ switch (ch) {
+ case 'd': /* Type of call that caused validation */
+ switch (type) {
+ case VALIDATE_INSERT:
+ number = 1;
+ break;
+ case VALIDATE_DELETE:
+ number = 0;
+ break;
+ default:
+ number = -1;
+ break;
+ }
+ sprintf(numStorage, "%d", number);
+ string = numStorage;
+ break;
+ case 'i': /* index of insert/delete */
+ sprintf(numStorage, "%d", index);
+ string = numStorage;
+ break;
+ case 'P': /* 'Peeked' new value of the string */
+ string = new;
+ break;
+ case 's': /* Current string value of entry */
+ string = entryPtr->string;
+ break;
+ case 'S': /* string to be inserted/deleted, if any */
+ string = change;
+ break;
+ case 'v': /* type of validation currently set */
+ string = validateStrings[entryPtr->validate];
+ break;
+ case 'V': /* type of validation in effect */
+ switch (type) {
+ case VALIDATE_INSERT:
+ case VALIDATE_DELETE:
+ string = validateStrings[VALIDATE_KEY];
+ break;
+ case VALIDATE_FORCED:
+ string = "forced";
+ break;
+ default:
+ string = validateStrings[type];
+ break;
+ }
+ break;
+ case 'W': /* widget name */
+ string = Tk_PathName(entryPtr->tkwin);
+ break;
+ default:
+ length = Tcl_UniCharToUtf(ch, numStorage);
+ numStorage[length] = '\0';
+ string = numStorage;
+ break;
+ }
+
+ spaceNeeded = Tcl_ScanCountedElement(string, -1, &cvtFlags);
+ length = Tcl_DStringLength(dsPtr);
+ Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
+ spaceNeeded = Tcl_ConvertCountedElement(string, -1,
+ Tcl_DStringValue(dsPtr) + length,
+ cvtFlags | TCL_DONT_USE_BRACES);
+ Tcl_DStringSetLength(dsPtr, length + spaceNeeded);
+ }
+}
+