4 * This module implements entry widgets for the
5 * toolkit. An entry displays a string and allows
6 * the string to be edited.
8 * Copyright (c) 1990-1994 The Regents of the University of California.
9 * Copyright (c) 1994-1995 Sun Microsystems, Inc.
10 * Copyright (c) 1995 Christian Werner
12 * See the file "license.terms" for information on usage and redistribution
13 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
21 * A data structure of the following type is kept for each entry
22 * widget managed by this file:
26 CkWindow *winPtr; /* Window that embodies the entry. NULL
27 * means that the window has been destroyed
28 * but the data structures haven't yet been
30 Tcl_Interp *interp; /* Interpreter associated with entry. */
31 Tcl_Command widgetCmd; /* Token for entry's widget command. */
33 int numBytes; /* Number of bytes in string. */
35 int numChars; /* Number of non-NULL characters in
36 * string (may be 0). */
37 char *string; /* Pointer to storage for string;
38 * NULL-terminated; malloc-ed. */
39 char *textVarName; /* Name of variable (malloc'ed) or NULL.
40 * If non-NULL, entry's string tracks the
41 * contents of this variable and vice versa. */
42 Ck_Uid state; /* Normal or disabled. Entry is read-only
46 * Information used when displaying widget:
49 int normalBg; /* Normal background color. */
50 int normalFg; /* Normal foreground color. */
51 int normalAttr; /* Normal video attributes. */
52 int selBg; /* Select background color. */
53 int selFg; /* Select foreground color. */
54 int selAttr; /* Select video attributes. */
55 Ck_Justify justify; /* Justification to use for text within
57 int leftX; /* X position at which leftIndex is drawn
58 * (varies depending on justify). */
59 int leftIndex; /* Index of left-most character visible in
61 int tabOrigin; /* Origin for tabs (left edge of string[0]). */
62 int insertPos; /* Index of character before which next
63 * typed character will be inserted. */
64 char *showChar; /* Value of -show option. If non-NULL, first
65 * character is used for displaying all
66 * characters in entry. Malloc'ed. */
67 char *displayString; /* If non-NULL, points to string with same
68 * length as string but whose characters
69 * are all equal to showChar. Malloc'ed. */
70 int prefWidth; /* Preferred width for window. */
73 * Information about what's selected, if any.
76 int selectFirst; /* Index of first selected character (-1 means
77 * nothing selected. */
78 int selectLast; /* Index of last selected character (-1 means
79 * nothing selected. */
80 int selectAnchor; /* Fixed end of selection (i.e. "select to"
81 * operation will use this as one end of the
85 * Miscellaneous information:
88 char *takeFocus; /* Value of -takefocus option; not used in
89 * the C code, but used by keyboard traversal
90 * scripts. Malloc'ed, but may be NULL. */
91 char *scrollCmd; /* Command prefix for communicating with
92 * scrollbar(s). Malloc'ed. NULL means
93 * no command to issue. */
94 int flags; /* Miscellaneous flags; see below for
99 * Assigned bits of "flags" fields of Entry structures, and what those
102 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has
103 * already been queued to redisplay the entry.
104 * GOT_FOCUS: Non-zero means this window has the input
106 * UPDATE_SCROLLBAR: Non-zero means scrollbar should be updated
107 * during next redisplay operation.
110 #define REDRAW_PENDING 1
112 #define UPDATE_SCROLLBAR 4
115 * Information used for argv parsing.
118 static Ck_ConfigSpec configSpecs[] = {
119 {CK_CONFIG_ATTR, "-attributes", "attributes", "Attributes",
120 DEF_ENTRY_ATTR, Ck_Offset(Entry, normalAttr), 0},
121 {CK_CONFIG_COLOR, "-background", "background", "Background",
122 DEF_ENTRY_BG_COLOR, Ck_Offset(Entry, normalBg),
123 CK_CONFIG_COLOR_ONLY},
124 {CK_CONFIG_COLOR, "-background", "background", "Background",
125 DEF_ENTRY_BG_MONO, Ck_Offset(Entry, normalBg),
126 CK_CONFIG_MONO_ONLY},
127 {CK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
128 (char *) NULL, 0, 0},
129 {CK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
130 (char *) NULL, 0, 0},
131 {CK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
132 DEF_ENTRY_FG, Ck_Offset(Entry, normalFg), 0},
133 {CK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
134 DEF_ENTRY_JUSTIFY, Ck_Offset(Entry, justify), 0},
135 {CK_CONFIG_ATTR, "-selectattributes", "selectAttributes",
136 "SelectAttributes", DEF_ENTRY_SELECT_ATTR_COLOR,
137 Ck_Offset(Entry, selAttr), CK_CONFIG_COLOR_ONLY},
138 {CK_CONFIG_ATTR, "-selectattributes", "selectAttributes",
139 "SelectAttributes", DEF_ENTRY_SELECT_ATTR_MONO,
140 Ck_Offset(Entry, selAttr), CK_CONFIG_MONO_ONLY},
141 {CK_CONFIG_COLOR, "-selectbackground", "selectBackground", "Foreground",
142 DEF_ENTRY_SELECT_BG_COLOR, Ck_Offset(Entry, selBg),
143 CK_CONFIG_COLOR_ONLY},
144 {CK_CONFIG_COLOR, "-selectbackground", "selectBackground", "Foreground",
145 DEF_ENTRY_SELECT_BG_MONO, Ck_Offset(Entry, selBg),
146 CK_CONFIG_MONO_ONLY},
147 {CK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
148 DEF_ENTRY_SELECT_FG_COLOR, Ck_Offset(Entry, selFg),
149 CK_CONFIG_COLOR_ONLY},
150 {CK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
151 DEF_ENTRY_SELECT_FG_MONO, Ck_Offset(Entry, selFg),
152 CK_CONFIG_MONO_ONLY},
153 {CK_CONFIG_STRING, "-show", "show", "Show",
154 DEF_ENTRY_SHOW, Ck_Offset(Entry, showChar), CK_CONFIG_NULL_OK},
155 {CK_CONFIG_UID, "-state", "state", "State",
156 DEF_ENTRY_STATE, Ck_Offset(Entry, state), 0},
157 {CK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
158 DEF_ENTRY_TAKE_FOCUS, Ck_Offset(Entry, takeFocus), CK_CONFIG_NULL_OK},
159 {CK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
160 DEF_ENTRY_TEXT_VARIABLE, Ck_Offset(Entry, textVarName),
162 {CK_CONFIG_INT, "-width", "width", "Width",
163 DEF_ENTRY_WIDTH, Ck_Offset(Entry, prefWidth), 0},
164 {CK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
165 DEF_ENTRY_SCROLL_COMMAND, Ck_Offset(Entry, scrollCmd),
167 {CK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
172 * Flags for GetEntryIndex procedure:
176 #define LAST_PLUS_ONE_OK 2
179 * Forward declarations for procedures defined later in this file:
182 static int ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
183 Entry *entryPtr, int argc, char **argv,
185 static void DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
187 static void DestroyEntry _ANSI_ARGS_((ClientData clientData));
188 static void DisplayEntry _ANSI_ARGS_((ClientData clientData));
189 static void EntryComputeGeometry _ANSI_ARGS_((Entry *entryPtr));
190 static void EntryEventProc _ANSI_ARGS_((ClientData clientData,
192 static void EntryFocusProc _ANSI_ARGS_ ((Entry *entryPtr,
194 static void EventuallyRedraw _ANSI_ARGS_((Entry *entryPtr));
195 static void EntryCmdDeletedProc _ANSI_ARGS_((
196 ClientData clientData));
197 static void EntrySetValue _ANSI_ARGS_((Entry *entryPtr,
199 static void EntrySelectTo _ANSI_ARGS_((
200 Entry *entryPtr, int index));
201 static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData,
202 Tcl_Interp *interp, char *name1, char *name2,
204 static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
205 static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr,
206 double *firstPtr, double *lastPtr));
207 static int EntryWidgetCmd _ANSI_ARGS_((ClientData clientData,
208 Tcl_Interp *interp, int argc, char **argv));
209 static int GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp,
210 Entry *entryPtr, char *string, int *indexPtr));
211 static void InsertChars _ANSI_ARGS_((Entry *entryPtr, int index,
215 *--------------------------------------------------------------
219 * This procedure is invoked to process the "entry" Tcl
220 * command. See the user documentation for details on what
224 * A standard Tcl result.
227 * See the user documentation.
229 *--------------------------------------------------------------
233 Ck_EntryCmd(clientData, interp, argc, argv)
234 ClientData clientData; /* Main window associated with
236 Tcl_Interp *interp; /* Current interpreter. */
237 int argc; /* Number of arguments. */
238 char **argv; /* Argument strings. */
240 CkWindow *mainPtr = (CkWindow *) clientData;
241 register Entry *entryPtr;
245 Tcl_AppendResult(interp, "wrong # args: should be \"",
246 argv[0], " pathName ?options?\"", (char *) NULL);
250 new = Ck_CreateWindowFromPath(interp, mainPtr, argv[1], 0);
256 * Initialize the fields of the structure that won't be initialized
257 * by ConfigureEntry, or that ConfigureEntry requires to be
258 * initialized already (e.g. resource pointers).
261 entryPtr = (Entry *) ckalloc(sizeof (Entry));
262 entryPtr->winPtr = new;
263 entryPtr->interp = interp;
264 entryPtr->widgetCmd = Tcl_CreateCommand(interp,
265 entryPtr->winPtr->pathName, EntryWidgetCmd,
266 (ClientData) entryPtr, EntryCmdDeletedProc);
268 entryPtr->numBytes = 0;
270 entryPtr->numChars = 0;
271 entryPtr->string = (char *) ckalloc(1);
272 entryPtr->string[0] = '\0';
273 entryPtr->textVarName = NULL;
274 entryPtr->state = ckNormalUid;
275 entryPtr->normalBg = 0;
276 entryPtr->normalFg = 0;
277 entryPtr->normalAttr = 0;
280 entryPtr->selAttr = 0;
281 entryPtr->justify = CK_JUSTIFY_LEFT;
282 entryPtr->prefWidth = 0;
283 entryPtr->leftIndex = 0;
284 entryPtr->tabOrigin = 0;
285 entryPtr->insertPos = 0;
286 entryPtr->showChar = NULL;
287 entryPtr->displayString = NULL;
288 entryPtr->prefWidth = 1;
289 entryPtr->selectFirst = -1;
290 entryPtr->selectLast = -1;
291 entryPtr->selectAnchor = 0;
292 entryPtr->takeFocus = NULL;
293 entryPtr->scrollCmd = NULL;
296 Ck_SetClass(entryPtr->winPtr, "Entry");
297 Ck_CreateEventHandler(entryPtr->winPtr,
298 CK_EV_EXPOSE | CK_EV_MAP | CK_EV_DESTROY,
299 EntryEventProc, (ClientData) entryPtr);
300 if (ConfigureEntry(interp, entryPtr, argc-2, argv+2, 0) != TCL_OK) {
304 interp->result = entryPtr->winPtr->pathName;
308 Ck_DestroyWindow(entryPtr->winPtr);
313 *--------------------------------------------------------------
317 * This procedure is invoked to process the Tcl command
318 * that corresponds to a widget managed by this module.
319 * See the user documentation for details on what it does.
322 * A standard Tcl result.
325 * See the user documentation.
327 *--------------------------------------------------------------
331 EntryWidgetCmd(clientData, interp, argc, argv)
332 ClientData clientData; /* Information about entry widget. */
333 Tcl_Interp *interp; /* Current interpreter. */
334 int argc; /* Number of arguments. */
335 char **argv; /* Argument strings. */
337 register Entry *entryPtr = (Entry *) clientData;
343 Tcl_AppendResult(interp, "wrong # args: should be \"",
344 argv[0], " option ?arg arg ...?\"", (char *) NULL);
347 Ck_Preserve((ClientData) entryPtr);
349 length = strlen(argv[1]);
350 if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
353 Tcl_AppendResult(interp, "wrong # args: should be \"",
354 argv[0], " cget option\"",
358 result = Ck_ConfigureValue(interp, entryPtr->winPtr, configSpecs,
359 (char *) entryPtr, argv[2], 0);
360 } else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
363 result = Ck_ConfigureInfo(interp, entryPtr->winPtr, configSpecs,
364 (char *) entryPtr, (char *) NULL, 0);
365 } else if (argc == 3) {
366 result = Ck_ConfigureInfo(interp, entryPtr->winPtr, configSpecs,
367 (char *) entryPtr, argv[2], 0);
369 result = ConfigureEntry(interp, entryPtr, argc-2, argv+2,
370 CK_CONFIG_ARGV_ONLY);
372 } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
375 if ((argc < 3) || (argc > 4)) {
376 Tcl_AppendResult(interp, "wrong # args: should be \"",
377 argv[0], " delete firstIndex ?lastIndex?\"",
381 if (GetEntryIndex(interp, entryPtr, argv[2], &first) != TCL_OK) {
387 if (GetEntryIndex(interp, entryPtr, argv[3], &last) != TCL_OK) {
391 if ((last >= first) && (entryPtr->state == ckNormalUid)) {
392 DeleteChars(entryPtr, first, last-first);
394 } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
396 Tcl_AppendResult(interp, "wrong # args: should be \"",
397 argv[0], " get\"", (char *) NULL);
400 interp->result = entryPtr->string;
401 } else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0)
404 Tcl_AppendResult(interp, "wrong # args: should be \"",
405 argv[0], " icursor pos\"",
409 if (GetEntryIndex(interp, entryPtr, argv[2], &entryPtr->insertPos)
413 EventuallyRedraw(entryPtr);
414 } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
419 Tcl_AppendResult(interp, "wrong # args: should be \"",
420 argv[0], " index string\"", (char *) NULL);
423 if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
426 sprintf(interp->result, "%d", index);
427 } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
432 Tcl_AppendResult(interp, "wrong # args: should be \"",
433 argv[0], " insert index text\"",
437 if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
440 if (entryPtr->state == ckNormalUid) {
441 InsertChars(entryPtr, index, argv[3]);
443 } else if ((c == 's') && (length >= 2)
444 && (strncmp(argv[1], "selection", length) == 0)) {
448 Tcl_AppendResult(interp, "wrong # args: should be \"",
449 argv[0], " select option ?index?\"", (char *) NULL);
452 length = strlen(argv[2]);
454 if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) {
456 Tcl_AppendResult(interp, "wrong # args: should be \"",
457 argv[0], " selection clear\"", (char *) NULL);
460 if (entryPtr->selectFirst != -1) {
461 entryPtr->selectFirst = entryPtr->selectLast = -1;
462 EventuallyRedraw(entryPtr);
465 } else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) {
467 Tcl_AppendResult(interp, "wrong # args: should be \"",
468 argv[0], " selection present\"", (char *) NULL);
471 if (entryPtr->selectFirst == -1) {
472 interp->result = "0";
474 interp->result = "1";
479 if (GetEntryIndex(interp, entryPtr, argv[3], &index) != TCL_OK) {
483 if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
485 Tcl_AppendResult(interp, "wrong # args: should be \"",
486 argv[0], " selection adjust index\"",
490 if (entryPtr->selectFirst >= 0) {
493 half1 = (entryPtr->selectFirst + entryPtr->selectLast)/2;
494 half2 = (entryPtr->selectFirst + entryPtr->selectLast + 1)/2;
496 entryPtr->selectAnchor = entryPtr->selectLast;
497 } else if (index > half2) {
498 entryPtr->selectAnchor = entryPtr->selectFirst;
501 * We're at about the halfway point in the selection;
502 * just keep the existing anchor.
506 EntrySelectTo(entryPtr, index);
507 } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
509 Tcl_AppendResult(interp, "wrong # args: should be \"",
510 argv[0], " selection from index\"",
514 entryPtr->selectAnchor = index;
515 } else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) {
517 Tcl_AppendResult(interp, "wrong # args: should be \"",
518 argv[0], " selection range start end\"",
522 if (GetEntryIndex(interp, entryPtr, argv[4], &index2) != TCL_OK) {
525 if (index >= index2) {
526 entryPtr->selectFirst = entryPtr->selectLast = -1;
528 entryPtr->selectFirst = index;
529 entryPtr->selectLast = index2;
531 EventuallyRedraw(entryPtr);
532 } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
534 Tcl_AppendResult(interp, "wrong # args: should be \"",
535 argv[0], " selection to index\"",
539 EntrySelectTo(entryPtr, index);
541 Tcl_AppendResult(interp, "bad selection option \"", argv[2],
542 "\": must be adjust, clear, from, present, range, or to",
546 } else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
547 int index, type, count, charsPerPage;
548 double fraction, first, last;
551 EntryVisibleRange(entryPtr, &first, &last);
552 sprintf(interp->result, "%g %g", first, last);
554 } else if (argc == 3) {
555 if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
559 type = Ck_GetScrollInfo(interp, argc, argv, &fraction, &count);
560 index = entryPtr->leftIndex;
562 case CK_SCROLL_ERROR:
564 case CK_SCROLL_MOVETO:
565 index = (int) (fraction * entryPtr->numChars);
567 case CK_SCROLL_PAGES:
568 charsPerPage = entryPtr->winPtr->width - 2;
569 if (charsPerPage < 1)
571 index += charsPerPage*count;
573 case CK_SCROLL_UNITS:
578 if (index >= entryPtr->numChars) {
579 index = entryPtr->numChars-1;
584 entryPtr->leftIndex = index;
585 entryPtr->flags |= UPDATE_SCROLLBAR;
586 EntryComputeGeometry(entryPtr);
587 EventuallyRedraw(entryPtr);
589 Tcl_AppendResult(interp, "bad option \"", argv[1],
590 "\": must be cget, configure, delete, get, ",
591 "icursor, index, insert, selection, or xview",
596 Ck_Release((ClientData) entryPtr);
600 Ck_Release((ClientData) entryPtr);
605 *----------------------------------------------------------------------
609 * This procedure is invoked by Ck_EventuallyFree or Ck_Release
610 * to clean up the internal structure of an entry at a safe time
611 * (when no-one is using it anymore).
617 * Everything associated with the entry is freed up.
619 *----------------------------------------------------------------------
623 DestroyEntry(clientData)
624 ClientData clientData; /* Info about entry widget. */
626 Entry *entryPtr = (Entry *) clientData;
629 * Free up all the stuff that requires special handling, then
630 * let Ck_FreeOptions handle all the standard option-related
634 ckfree(entryPtr->string);
635 if (entryPtr->textVarName != NULL) {
636 Tcl_UntraceVar(entryPtr->interp, entryPtr->textVarName,
637 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
638 EntryTextVarProc, (ClientData) entryPtr);
640 if (entryPtr->displayString != NULL) {
641 ckfree(entryPtr->displayString);
643 Ck_FreeOptions(configSpecs, (char *) entryPtr, 0);
644 ckfree((char *) entryPtr);
648 *----------------------------------------------------------------------
650 * EntryCmdDeletedProc --
652 * This procedure is invoked when a widget command is deleted. If
653 * the widget isn't already in the process of being destroyed,
654 * this command destroys it.
660 * The widget is destroyed.
662 *----------------------------------------------------------------------
666 EntryCmdDeletedProc(clientData)
667 ClientData clientData; /* Pointer to widget record for widget. */
669 Entry *entryPtr = (Entry *) clientData;
670 CkWindow *winPtr = entryPtr->winPtr;
673 * This procedure could be invoked either because the window was
674 * destroyed and the command was then deleted (in which case winPtr
675 * is NULL) or because the command was deleted, and then this procedure
676 * destroys the widget.
679 if (winPtr != NULL) {
680 entryPtr->winPtr = NULL;
681 Ck_DestroyWindow(winPtr);
686 *----------------------------------------------------------------------
690 * This procedure is called to process an argv/argc list, plus
691 * the Tk option database, in order to configure (or reconfigure)
695 * The return value is a standard Tcl result. If TCL_ERROR is
696 * returned, then interp->result contains an error message.
699 * Configuration information, such as colors, border width,
700 * etc. get set for entryPtr; old resources get freed,
703 *----------------------------------------------------------------------
707 ConfigureEntry(interp, entryPtr, argc, argv, flags)
708 Tcl_Interp *interp; /* Used for error reporting. */
709 register Entry *entryPtr; /* Information about widget; may or may
710 * not already have values for some fields. */
711 int argc; /* Number of valid entries in argv. */
712 char **argv; /* Arguments. */
713 int flags; /* Flags to pass to Tk_ConfigureWidget. */
716 * Eliminate any existing trace on a variable monitored by the entry.
719 if (entryPtr->textVarName != NULL) {
720 Tcl_UntraceVar(interp, entryPtr->textVarName,
721 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
722 EntryTextVarProc, (ClientData) entryPtr);
725 if (Ck_ConfigureWidget(interp, entryPtr->winPtr, configSpecs,
726 argc, argv, (char *) entryPtr, flags) != TCL_OK) {
731 * If the entry is tied to the value of a variable, then set up
732 * a trace on the variable's value, create the variable if it doesn't
733 * exist, and set the entry's value from the variable's value.
736 if (entryPtr->textVarName != NULL) {
739 value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
741 Tcl_SetVar(interp, entryPtr->textVarName, entryPtr->string,
744 EntrySetValue(entryPtr, value);
746 Tcl_TraceVar(interp, entryPtr->textVarName,
747 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
748 EntryTextVarProc, (ClientData) entryPtr);
752 * A few other options also need special processing, such as parsing
753 * the geometry and setting the colors.
756 if ((entryPtr->state != ckNormalUid)
757 && (entryPtr->state != ckDisabledUid)) {
758 Tcl_AppendResult(interp, "bad state value \"", entryPtr->state,
759 "\": must be normal or disabled", (char *) NULL);
760 entryPtr->state = ckNormalUid;
765 * Recompute the window's geometry and arrange for it to be
769 EntryComputeGeometry(entryPtr);
770 entryPtr->flags |= UPDATE_SCROLLBAR;
771 EventuallyRedraw(entryPtr);
776 *--------------------------------------------------------------
780 * This procedure redraws the contents of an entry window.
786 * Information appears on the screen.
788 *--------------------------------------------------------------
792 DisplayEntry(clientData)
793 ClientData clientData; /* Information about window. */
795 register Entry *entryPtr = (Entry *) clientData;
796 CkWindow *winPtr = entryPtr->winPtr;
797 int y, startX, leftIndex, selectFirst, selectLast, insertPos, dummy;
800 entryPtr->flags &= ~REDRAW_PENDING;
801 if ((entryPtr->winPtr == NULL) || !(winPtr->flags & CK_MAPPED))
805 * Update the scrollbar if that's needed.
808 if (entryPtr->flags & UPDATE_SCROLLBAR) {
809 EntryUpdateScrollbar(entryPtr);
813 * Compute x-coordinate of the pixel just after last visible
814 * one, plus vertical position of baseline of text.
817 y = winPtr->height / 2;
819 if (entryPtr->displayString == NULL) {
820 displayString = entryPtr->string;
822 displayString = entryPtr->displayString;
825 Ck_SetWindowAttr(winPtr, entryPtr->normalFg, entryPtr->normalBg,
826 entryPtr->normalAttr);
827 Ck_ClearToBot(winPtr, 0, 0);
830 leftIndex = Tcl_UtfAtIndex(displayString, entryPtr->leftIndex) -
832 selectFirst = Tcl_UtfAtIndex(displayString, entryPtr->selectFirst) -
834 selectLast = Tcl_UtfAtIndex(displayString, entryPtr->selectLast) -
836 insertPos = Tcl_UtfAtIndex(displayString, entryPtr->insertPos) -
839 leftIndex = entryPtr->leftIndex;
840 selectFirst = entryPtr->selectFirst;
841 selectLast = entryPtr->selectLast;
842 insertPos = entryPtr->insertPos;
845 CkDisplayChars(winPtr->mainPtr, winPtr->window,
846 displayString + leftIndex,
847 strlen(displayString) - leftIndex,
848 entryPtr->leftX, y, entryPtr->tabOrigin,
849 CK_NEWLINES_NOT_SPECIAL);
851 if (entryPtr->selectLast >= entryPtr->leftIndex) {
852 if (entryPtr->selectFirst < entryPtr->leftIndex) {
855 CkMeasureChars(winPtr->mainPtr,
856 displayString + leftIndex,
857 selectFirst - leftIndex, entryPtr->leftX,
858 winPtr->width, entryPtr->tabOrigin, CK_NEWLINES_NOT_SPECIAL,
861 if (startX < winPtr->width) {
862 Ck_SetWindowAttr(winPtr, entryPtr->selFg, entryPtr->selBg,
864 wmove(winPtr->window, y, startX + entryPtr->leftX);
865 CkDisplayChars(winPtr->mainPtr, winPtr->window,
866 displayString + selectFirst,
867 selectLast - selectFirst,
868 entryPtr->leftX + startX, y, entryPtr->tabOrigin,
869 CK_NEWLINES_NOT_SPECIAL);
870 Ck_SetWindowAttr(winPtr, entryPtr->normalFg, entryPtr->normalBg,
871 entryPtr->normalAttr);
875 CkMeasureChars(winPtr->mainPtr, displayString + leftIndex,
876 insertPos - leftIndex, entryPtr->leftX,
877 winPtr->width, entryPtr->tabOrigin, CK_NEWLINES_NOT_SPECIAL,
880 if (startX >= 0 && startX < winPtr->width) {
881 wmove(winPtr->window, y, startX);
882 if (entryPtr->state == ckNormalUid)
883 Ck_SetHWCursor(winPtr, 1);
885 Ck_SetHWCursor(winPtr, 0);
887 wmove(winPtr->window, y, 0);
888 Ck_SetHWCursor(winPtr, 0);
891 Ck_EventuallyRefresh(winPtr);
895 *----------------------------------------------------------------------
897 * EntryComputeGeometry --
899 * This procedure is invoked to recompute information about where
900 * in its window an entry's string will be displayed. It also
901 * computes the requested size for the window.
907 * The tabOrigin fields are recomputed for entryPtr,
908 * and leftIndex may be adjusted. Ck_GeometryRequest is called
909 * to register the desired dimensions for the window.
911 *----------------------------------------------------------------------
915 EntryComputeGeometry(entryPtr)
916 Entry *entryPtr; /* Widget record for entry. */
918 int totalLength, overflow, maxOffScreen;
919 int width, i, rightX, dummy;
920 char *p, *displayString;
921 CkWindow *winPtr = entryPtr->winPtr;
924 * If we're displaying a special character instead of the value of
925 * the entry, recompute the displayString.
928 if (entryPtr->displayString != NULL) {
929 ckfree(entryPtr->displayString);
930 entryPtr->displayString = NULL;
932 if (entryPtr->showChar != NULL) {
936 entryPtr->displayString = (char *) ckalloc(entryPtr->numChars * 3 + 1);
937 ulen = Tcl_UtfNext(entryPtr->showChar) - entryPtr->showChar;
938 for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0;
940 memcpy(p, entryPtr->showChar, ulen);
944 entryPtr->displayString = (char *) ckalloc(entryPtr->numChars + 1);
945 for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0;
947 *p = entryPtr->showChar[0];
951 displayString = entryPtr->displayString;
953 displayString = entryPtr->string;
957 * Recompute where the leftmost character on the display will
958 * be drawn (entryPtr->leftX) and adjust leftIndex if necessary
959 * so that we don't let characters hang off the edge of the
960 * window unless the entire window is full.
963 CkMeasureChars(winPtr->mainPtr, displayString, strlen(displayString),
965 CK_NEWLINES_NOT_SPECIAL, &totalLength, &dummy);
966 if (entryPtr->insertPos == entryPtr->numChars)
968 overflow = totalLength - entryPtr->winPtr->width;
970 entryPtr->leftIndex = 0;
971 if (entryPtr->justify == CK_JUSTIFY_LEFT) {
973 } else if (entryPtr->justify == CK_JUSTIFY_RIGHT) {
974 entryPtr->leftX = entryPtr->winPtr->width - totalLength;
976 entryPtr->leftX = (entryPtr->winPtr->width - totalLength) / 2;
978 entryPtr->tabOrigin = entryPtr->leftX;
983 * The whole string can't fit in the window. Compute the
984 * maximum number of characters that may be off-screen to
985 * the left without leaving empty space on the right of the
986 * window, then don't let leftIndex be any greater than that.
989 maxOffScreen = CkMeasureChars(winPtr->mainPtr,
990 displayString, strlen(displayString),
991 0, overflow, 0, CK_NEWLINES_NOT_SPECIAL|CK_PARTIAL_OK, &rightX,
993 if (rightX < overflow) {
996 if (entryPtr->leftIndex > maxOffScreen) {
997 entryPtr->leftIndex = maxOffScreen;
1000 leftIndex = Tcl_UtfAtIndex(displayString, entryPtr->leftIndex) -
1003 leftIndex = entryPtr->leftIndex;
1005 CkMeasureChars(winPtr->mainPtr, displayString, leftIndex,
1007 CK_NEWLINES_NOT_SPECIAL|CK_PARTIAL_OK, &rightX, &dummy);
1008 entryPtr->leftX = 0;
1009 entryPtr->tabOrigin = entryPtr->leftX - rightX;
1012 if (entryPtr->prefWidth > 0) {
1013 width = entryPtr->prefWidth;
1014 } else if (totalLength == 0) {
1017 width = totalLength;
1019 Ck_GeometryRequest(entryPtr->winPtr, width, 1);
1023 *----------------------------------------------------------------------
1027 * Add new characters to an entry widget.
1033 * New information gets added to entryPtr; it will be redisplayed
1034 * soon, but not necessarily immediately.
1036 *----------------------------------------------------------------------
1040 InsertChars(entryPtr, index, string)
1041 register Entry *entryPtr; /* Entry that is to get the new
1043 int index; /* Add the new elements before this
1045 char *string; /* New characters to add (NULL-terminated
1048 int length, clength;
1054 length = strlen(string);
1059 clength = Tcl_NumUtfChars(string, -1);
1060 new = (char *) ckalloc((unsigned) (entryPtr->numBytes + length + 1));
1061 inspos = Tcl_UtfAtIndex(entryPtr->string, index) - entryPtr->string;
1062 strncpy(new, entryPtr->string, (size_t) inspos);
1063 strcpy(new+inspos, string);
1064 strcpy(new+inspos+length, entryPtr->string+inspos);
1065 ckfree(entryPtr->string);
1066 entryPtr->string = new;
1067 entryPtr->numChars += clength;
1068 entryPtr->numBytes += length;
1071 new = (char *) ckalloc((unsigned) (entryPtr->numChars + length + 1));
1072 strncpy(new, entryPtr->string, (size_t) index);
1073 strcpy(new+index, string);
1074 strcpy(new+index+length, entryPtr->string+index);
1075 ckfree(entryPtr->string);
1076 entryPtr->string = new;
1077 entryPtr->numChars += length;
1081 * Inserting characters invalidates all indexes into the string.
1082 * Touch up the indexes so that they still refer to the same
1083 * characters (at new positions). When updating the selection
1084 * end-points, don't include the new text in the selection unless
1085 * it was completely surrounded by the selection.
1088 if (entryPtr->selectFirst >= index) {
1089 entryPtr->selectFirst += clength;
1091 if (entryPtr->selectLast > index) {
1092 entryPtr->selectLast += clength;
1094 if ((entryPtr->selectAnchor > index) || (entryPtr->selectFirst >= index)) {
1095 entryPtr->selectAnchor += clength;
1097 if (entryPtr->leftIndex > index) {
1098 entryPtr->leftIndex += clength;
1100 if (entryPtr->insertPos >= index) {
1101 entryPtr->insertPos += clength;
1104 if (entryPtr->textVarName != NULL) {
1105 Tcl_SetVar(entryPtr->interp, entryPtr->textVarName, entryPtr->string,
1108 entryPtr->flags |= UPDATE_SCROLLBAR;
1109 EntryComputeGeometry(entryPtr);
1110 EventuallyRedraw(entryPtr);
1114 *----------------------------------------------------------------------
1118 * Remove one or more characters from an entry widget.
1124 * Memory gets freed, the entry gets modified and (eventually)
1127 *----------------------------------------------------------------------
1131 DeleteChars(entryPtr, index, count)
1132 register Entry *entryPtr; /* Entry widget to modify. */
1133 int index; /* Index of first character to delete. */
1134 int count; /* How many characters to delete. */
1138 int delpos, delcount;
1141 if ((index + count) > entryPtr->numChars) {
1142 count = entryPtr->numChars - index;
1149 delpos = Tcl_UtfAtIndex(entryPtr->string, index) - entryPtr->string;
1150 delcount = Tcl_UtfAtIndex(entryPtr->string + delpos, count) -
1151 (entryPtr->string + delpos);
1152 new = (char *) ckalloc((unsigned) (entryPtr->numBytes + 1 - delcount));
1153 strncpy(new, entryPtr->string, (size_t) delpos);
1154 strcpy(new+delpos, entryPtr->string+delpos+delcount);
1155 entryPtr->numChars = Tcl_NumUtfChars(new, -1);
1156 entryPtr->numBytes = strlen(new);
1158 new = (char *) ckalloc((unsigned) (entryPtr->numChars + 1 - count));
1159 strncpy(new, entryPtr->string, (size_t) index);
1160 strcpy(new+index, entryPtr->string+index+count);
1161 entryPtr->numChars -= count;
1163 ckfree(entryPtr->string);
1164 entryPtr->string = new;
1167 * Deleting characters results in the remaining characters being
1168 * renumbered. Update the various indexes into the string to reflect
1172 if (entryPtr->selectFirst >= index) {
1173 if (entryPtr->selectFirst >= (index+count)) {
1174 entryPtr->selectFirst -= count;
1176 entryPtr->selectFirst = index;
1179 if (entryPtr->selectLast >= index) {
1180 if (entryPtr->selectLast >= (index+count)) {
1181 entryPtr->selectLast -= count;
1183 entryPtr->selectLast = index;
1186 if (entryPtr->selectLast <= entryPtr->selectFirst) {
1187 entryPtr->selectFirst = entryPtr->selectLast = -1;
1189 if (entryPtr->selectAnchor >= index) {
1190 if (entryPtr->selectAnchor >= (index+count)) {
1191 entryPtr->selectAnchor -= count;
1193 entryPtr->selectAnchor = index;
1196 if (entryPtr->leftIndex > index) {
1197 if (entryPtr->leftIndex >= (index+count)) {
1198 entryPtr->leftIndex -= count;
1200 entryPtr->leftIndex = index;
1203 if (entryPtr->insertPos >= index) {
1204 if (entryPtr->insertPos >= (index+count)) {
1205 entryPtr->insertPos -= count;
1207 entryPtr->insertPos = index;
1211 if (entryPtr->textVarName != NULL) {
1212 Tcl_SetVar(entryPtr->interp, entryPtr->textVarName, entryPtr->string,
1215 entryPtr->flags |= UPDATE_SCROLLBAR;
1216 EntryComputeGeometry(entryPtr);
1217 EventuallyRedraw(entryPtr);
1221 *----------------------------------------------------------------------
1225 * Replace the contents of a text entry with a given value. This
1226 * procedure is invoked when updating the entry from the entry's
1227 * associated variable.
1233 * The string displayed in the entry will change. Any selection
1234 * in the entry is lost and the insertion point gets set to the
1235 * end of the entry. Note: this procedure does *not* update the
1236 * entry's associated variable, since that could result in an
1239 *----------------------------------------------------------------------
1243 EntrySetValue(entryPtr, value)
1244 register Entry *entryPtr; /* Entry whose value is to be
1246 char *value; /* New text to display in entry. */
1248 ckfree(entryPtr->string);
1250 entryPtr->numBytes = strlen(value);
1251 entryPtr->numChars = Tcl_NumUtfChars(value, -1);
1252 entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numBytes + 1));
1254 entryPtr->numChars = strlen(value);
1255 entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numChars + 1));
1257 strcpy(entryPtr->string, value);
1258 entryPtr->selectFirst = entryPtr->selectLast = -1;
1259 entryPtr->leftIndex = 0;
1260 entryPtr->insertPos = entryPtr->numChars;
1262 entryPtr->flags |= UPDATE_SCROLLBAR;
1263 EntryComputeGeometry(entryPtr);
1264 EventuallyRedraw(entryPtr);
1268 *--------------------------------------------------------------
1272 * This procedure is invoked by the dispatcher for various
1273 * events on entryes.
1279 * When the window gets deleted, internal structures get
1280 * cleaned up. When it gets exposed, it is redisplayed.
1282 *--------------------------------------------------------------
1286 EntryEventProc(clientData, eventPtr)
1287 ClientData clientData; /* Information about window. */
1288 CkEvent *eventPtr; /* Information about event. */
1290 Entry *entryPtr = (Entry *) clientData;
1292 if (eventPtr->type == CK_EV_EXPOSE) {
1293 Ck_Preserve((ClientData) entryPtr);
1294 entryPtr->flags |= UPDATE_SCROLLBAR;
1295 EntryComputeGeometry(entryPtr);
1296 EventuallyRedraw(entryPtr);
1297 Ck_Release((ClientData) entryPtr);
1298 } else if (eventPtr->type == CK_EV_DESTROY) {
1299 if (entryPtr->winPtr != NULL) {
1300 entryPtr->winPtr = NULL;
1301 Tcl_DeleteCommand(entryPtr->interp,
1302 Tcl_GetCommandName(entryPtr->interp, entryPtr->widgetCmd));
1304 if (entryPtr->flags & REDRAW_PENDING) {
1305 Tk_CancelIdleCall(DisplayEntry, (ClientData) entryPtr);
1307 Ck_EventuallyFree((ClientData) entryPtr, (Ck_FreeProc *) DestroyEntry);
1308 } else if (eventPtr->type == CK_EV_FOCUSIN) {
1309 EntryFocusProc(entryPtr, 1);
1310 } else if (eventPtr->type == CK_EV_FOCUSOUT) {
1311 EntryFocusProc(entryPtr, 0);
1316 *--------------------------------------------------------------
1320 * Parse an index into an entry and return either its value
1324 * A standard Tcl result. If all went well, then *indexPtr is
1325 * filled in with the index (into entryPtr) corresponding to
1326 * string. The index value is guaranteed to lie between 0 and
1327 * the number of characters in the string, inclusive. If an
1328 * error occurs then an error message is left in interp->result.
1333 *--------------------------------------------------------------
1337 GetEntryIndex(interp, entryPtr, string, indexPtr)
1338 Tcl_Interp *interp; /* For error messages. */
1339 Entry *entryPtr; /* Entry for which the index is being
1341 char *string; /* Specifies character in entryPtr. */
1342 int *indexPtr; /* Where to store converted index. */
1346 CkWindow *winPtr = entryPtr->winPtr;
1348 length = strlen(string);
1350 if (string[0] == 'a') {
1351 if (strncmp(string, "anchor", length) == 0) {
1352 *indexPtr = entryPtr->selectAnchor;
1357 * Some of the paths here leave messages in interp->result,
1358 * so we have to clear it out before storing our own message.
1361 Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
1362 Tcl_AppendResult(interp, "bad entry index \"", string,
1363 "\"", (char *) NULL);
1366 } else if (string[0] == 'e') {
1367 if (strncmp(string, "end", length) == 0) {
1368 *indexPtr = entryPtr->numChars;
1372 } else if (string[0] == 'i') {
1373 if (strncmp(string, "insert", length) == 0) {
1374 *indexPtr = entryPtr->insertPos;
1378 } else if (string[0] == 's') {
1379 if (entryPtr->selectFirst == -1) {
1380 interp->result = "selection isn't in entry";
1386 if (strncmp(string, "sel.first", length) == 0) {
1387 *indexPtr = entryPtr->selectFirst;
1388 } else if (strncmp(string, "sel.last", length) == 0) {
1389 *indexPtr = entryPtr->selectLast;
1393 } else if (string[0] == '@') {
1396 if (Tcl_GetInt(interp, string+1, &x) != TCL_OK) {
1403 if (x >= entryPtr->winPtr->width) {
1404 x = entryPtr->winPtr->width - 1;
1407 if (entryPtr->numChars == 0) {
1410 char *string = (entryPtr->displayString == NULL) ?
1411 entryPtr->string : entryPtr->displayString;
1413 *indexPtr = CkMeasureChars(winPtr->mainPtr, string, strlen(string),
1414 entryPtr->tabOrigin, x,
1415 entryPtr->tabOrigin, CK_NEWLINES_NOT_SPECIAL, &dummy, &dummy);
1417 *indexPtr = entryPtr->leftX + entryPtr->leftIndex + x;
1420 if (*indexPtr >= entryPtr->numChars)
1421 *indexPtr = entryPtr->numChars;
1423 if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
1428 } else if (*indexPtr > entryPtr->numChars) {
1429 *indexPtr = entryPtr->numChars;
1436 *----------------------------------------------------------------------
1440 * Modify the selection by moving its un-anchored end. This could
1441 * make the selection either larger or smaller.
1447 * The selection changes.
1449 *----------------------------------------------------------------------
1453 EntrySelectTo(entryPtr, index)
1454 register Entry *entryPtr; /* Information about widget. */
1455 int index; /* Index of element that is to
1456 * become the "other" end of the
1459 int newFirst, newLast;
1462 * Pick new starting and ending points for the selection.
1465 if (entryPtr->selectAnchor > entryPtr->numChars) {
1466 entryPtr->selectAnchor = entryPtr->numChars;
1468 if (entryPtr->selectAnchor <= index) {
1469 newFirst = entryPtr->selectAnchor;
1473 newLast = entryPtr->selectAnchor;
1475 newFirst = newLast = -1;
1478 if ((entryPtr->selectFirst == newFirst)
1479 && (entryPtr->selectLast == newLast)) {
1482 entryPtr->selectFirst = newFirst;
1483 entryPtr->selectLast = newLast;
1484 EventuallyRedraw(entryPtr);
1488 *----------------------------------------------------------------------
1490 * EventuallyRedraw --
1492 * Ensure that an entry is eventually redrawn on the display.
1498 * Information gets redisplayed. Right now we don't do selective
1499 * redisplays: the whole window will be redrawn. This doesn't
1500 * seem to hurt performance noticeably, but if it does then this
1503 *----------------------------------------------------------------------
1507 EventuallyRedraw(entryPtr)
1508 Entry *entryPtr; /* Information about widget. */
1510 if ((entryPtr->winPtr == NULL) || !(entryPtr->winPtr->flags & CK_MAPPED)) {
1515 * Right now we don't do selective redisplays: the whole window
1516 * will be redrawn. This doesn't seem to hurt performance noticeably,
1517 * but if it does then this could be changed.
1520 if (!(entryPtr->flags & REDRAW_PENDING)) {
1521 entryPtr->flags |= REDRAW_PENDING;
1522 Tk_DoWhenIdle(DisplayEntry, (ClientData) entryPtr);
1527 *----------------------------------------------------------------------
1529 * EntryVisibleRange --
1531 * Return information about the range of the entry that is
1532 * currently visible.
1535 * *firstPtr and *lastPtr are modified to hold fractions between
1536 * 0 and 1 identifying the range of characters visible in the
1542 *----------------------------------------------------------------------
1546 EntryVisibleRange(entryPtr, firstPtr, lastPtr)
1547 Entry *entryPtr; /* Information about widget. */
1548 double *firstPtr; /* Return position of first visible
1549 * character in widget. */
1550 double *lastPtr; /* Return position of char just after
1551 * last visible one. */
1553 char *displayString;
1554 int charsInWindow, endX, dummy;
1555 CkWindow *winPtr = entryPtr->winPtr;
1557 if (entryPtr->displayString == NULL) {
1558 displayString = entryPtr->string;
1560 displayString = entryPtr->displayString;
1562 if (entryPtr->numChars == 0) {
1566 int leftIndex, total;
1569 leftIndex = Tcl_UtfAtIndex(displayString, entryPtr->leftIndex) -
1571 total = entryPtr->numBytes - leftIndex;
1573 leftIndex = entryPtr->leftIndex;
1574 total = entryPtr->numChars - leftIndex;
1576 charsInWindow = CkMeasureChars(winPtr->mainPtr,
1577 displayString + leftIndex, total, 0,
1578 entryPtr->winPtr->width, 0,
1579 CK_AT_LEAST_ONE|CK_NEWLINES_NOT_SPECIAL, &endX, &dummy);
1580 *firstPtr = ((double) leftIndex)/entryPtr->numChars;
1581 *lastPtr = ((double) (leftIndex + charsInWindow))
1582 /entryPtr->numChars;
1587 *----------------------------------------------------------------------
1589 * EntryUpdateScrollbar --
1591 * This procedure is invoked whenever information has changed in
1592 * an entry in a way that would invalidate a scrollbar display.
1593 * If there is an associated scrollbar, then this procedure updates
1594 * it by invoking a Tcl command.
1600 * A Tcl command is invoked, and an additional command may be
1601 * invoked to process errors in the command.
1603 *----------------------------------------------------------------------
1607 EntryUpdateScrollbar(entryPtr)
1608 Entry *entryPtr; /* Information about widget. */
1614 if (entryPtr->scrollCmd == NULL) {
1618 EntryVisibleRange(entryPtr, &first, &last);
1619 sprintf(args, " %g %g", first, last);
1620 code = Tcl_VarEval(entryPtr->interp, entryPtr->scrollCmd, args,
1622 if (code != TCL_OK) {
1623 Tcl_AddErrorInfo(entryPtr->interp,
1624 "\n (horizontal scrolling command executed by entry)");
1625 Tk_BackgroundError(entryPtr->interp);
1627 Tcl_SetResult(entryPtr->interp, (char *) NULL, TCL_STATIC);
1631 *----------------------------------------------------------------------
1635 * This procedure is called whenever the entry gets or loses the
1636 * input focus. It's also called whenever the window is reconfigured
1637 * while it has the focus.
1643 * The cursor gets turned on or off.
1645 *----------------------------------------------------------------------
1649 EntryFocusProc(entryPtr, gotFocus)
1650 Entry *entryPtr; /* Entry that got or lost focus. */
1651 int gotFocus; /* 1 means window is getting focus, 0 means
1652 * it's losing it. */
1655 entryPtr->flags |= GOT_FOCUS;
1657 entryPtr->flags &= ~GOT_FOCUS;
1661 *--------------------------------------------------------------
1663 * EntryTextVarProc --
1665 * This procedure is invoked when someone changes the variable
1666 * whose contents are to be displayed in an entry.
1669 * NULL is always returned.
1672 * The text displayed in the entry will change to match the
1675 *--------------------------------------------------------------
1679 EntryTextVarProc(clientData, interp, name1, name2, flags)
1680 ClientData clientData; /* Information about button. */
1681 Tcl_Interp *interp; /* Interpreter containing variable. */
1682 char *name1; /* Not used. */
1683 char *name2; /* Not used. */
1684 int flags; /* Information about what happened. */
1686 register Entry *entryPtr = (Entry *) clientData;
1690 * If the variable is unset, then immediately recreate it unless
1691 * the whole interpreter is going away.
1694 if (flags & TCL_TRACE_UNSETS) {
1695 if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
1696 Tcl_SetVar(interp, entryPtr->textVarName, entryPtr->string,
1698 Tcl_TraceVar(interp, entryPtr->textVarName,
1699 TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
1700 EntryTextVarProc, clientData);
1702 return (char *) NULL;
1706 * Update the entry's text with the value of the variable, unless
1707 * the entry already has that value (this happens when the variable
1708 * changes value because we changed it because someone typed in
1712 value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
1713 if (value == NULL) {
1716 if (strcmp(value, entryPtr->string) != 0) {
1717 EntrySetValue(entryPtr, value);
1719 return (char *) NULL;