4 * This module implements entry widgets for the Tk
5 * toolkit. An entry displays a string and allows
6 * the string to be edited.
8 * Copyright 1990 Regents of the University of California.
9 * Permission to use, copy, modify, and distribute this
10 * software and its documentation for any purpose and without
11 * fee is hereby granted, provided that the above copyright
12 * notice appear in all copies. The University of California
13 * makes no representations about the suitability of this
14 * software for any purpose. It is provided "as is" without
15 * express or implied warranty.
19 static char rcsid
[] = "$Header: /user6/ouster/wish/RCS/tkEntry.c,v 1.37 92/08/21 16:09:15 ouster Exp $ SPRITE (Berkeley)";
27 * A data structure of the following type is kept for each entry
28 * widget managed by this file:
32 Tk_Window tkwin
; /* Window that embodies the entry. NULL
33 * means that the window has been destroyed
34 * but the data structures haven't yet been
36 Tcl_Interp
*interp
; /* Interpreter associated with entry. */
37 int numChars
; /* Number of non-NULL characters in
38 * string (may be 0). */
39 char *string
; /* Pointer to storage for string;
40 * NULL-terminated; malloc-ed. */
41 char *textVarName
; /* Name of variable (malloc'ed) or NULL.
42 * If non-NULL, entry's string tracks the
43 * contents of this variable and vice versa. */
44 Tk_Uid state
; /* Normal or disabled. Entry is read-only
48 * Information used when displaying widget:
51 Tk_3DBorder normalBorder
; /* Used for drawing border around whole
52 * window, plus used for background. */
53 int borderWidth
; /* Width of 3-D border around window. */
54 int relief
; /* 3-D effect: TK_RELIEF_RAISED, etc. */
55 XFontStruct
*fontPtr
; /* Information about text font, or NULL. */
56 XColor
*fgColorPtr
; /* Text color in normal mode. */
57 GC textGC
; /* For drawing normal text. */
58 Tk_3DBorder selBorder
; /* Border and background for selected
60 int selBorderWidth
; /* Width of border around selection. */
61 XColor
*selFgColorPtr
; /* Foreground color for selected text. */
62 GC selTextGC
; /* For drawing selected text. */
63 Tk_3DBorder cursorBorder
; /* Used to draw vertical bar for insertion
65 int cursorWidth
; /* Total width of insert cursor. */
66 int cursorBorderWidth
; /* Width of 3-D border around insert cursor. */
67 int cursorOnTime
; /* Number of milliseconds cursor should spend
68 * in "on" state for each blink. */
69 int cursorOffTime
; /* Number of milliseconds cursor should spend
70 * in "off" state for each blink. */
71 Tk_TimerToken cursorBlinkHandler
;
72 /* Timer handler used to blink cursor on and
74 int avgWidth
; /* Width of average character. */
75 int prefWidth
; /* Desired width of window, measured in
76 * average characters. */
77 int offset
; /* 0 if window is flat, or borderWidth if
78 * raised or sunken. */
79 int leftIndex
; /* Index of left-most character visible in
81 int cursorPos
; /* Index of character before which next
82 * typed character will be inserted. */
85 * Information about what's selected, if any.
88 int selectFirst
; /* Index of first selected character (-1 means
89 * nothing selected. */
90 int selectLast
; /* Index of last selected character (-1 means
91 * nothing selected. */
92 int selectAnchor
; /* Fixed end of selection (i.e. "select to"
93 * operation will use this as one end of the
95 int exportSelection
; /* Non-zero means tie internal entry selection
99 * Information for scanning:
102 int scanMarkX
; /* X-position at which scan started (e.g.
103 * button was pressed here). */
104 int scanMarkIndex
; /* Index of character that was at left of
105 * window when scan started. */
108 * Miscellaneous information:
111 Cursor cursor
; /* Current cursor for window, or None. */
112 char *scrollCmd
; /* Command prefix for communicating with
113 * scrollbar(s). Malloc'ed. NULL means
114 * no command to issue. */
115 int flags
; /* Miscellaneous flags; see below for
120 * Assigned bits of "flags" fields of Entry structures, and what those
123 * REDRAW_PENDING: Non-zero means a DoWhenIdle handler has
124 * already been queued to redisplay the entry.
125 * BORDER_NEEDED: Non-zero means 3-D border must be redrawn
126 * around window during redisplay. Normally
127 * only text portion needs to be redrawn.
128 * CURSOR_ON: Non-zero means cursor is displayed at
129 * present. 0 means it isn't displayed.
130 * GOT_FOCUS: Non-zero means this window has the input
134 #define REDRAW_PENDING 1
135 #define BORDER_NEEDED 2
140 * Information used for argv parsing.
143 static Tk_ConfigSpec configSpecs
[] = {
144 {TK_CONFIG_BORDER
, "-background", "background", "Background",
145 DEF_ENTRY_BG_COLOR
, Tk_Offset(Entry
, normalBorder
),
146 TK_CONFIG_COLOR_ONLY
},
147 {TK_CONFIG_BORDER
, "-background", "background", "Background",
148 DEF_ENTRY_BG_MONO
, Tk_Offset(Entry
, normalBorder
),
149 TK_CONFIG_MONO_ONLY
},
150 {TK_CONFIG_SYNONYM
, "-bd", "borderWidth", (char *) NULL
,
151 (char *) NULL
, 0, 0},
152 {TK_CONFIG_SYNONYM
, "-bg", "background", (char *) NULL
,
153 (char *) NULL
, 0, 0},
154 {TK_CONFIG_PIXELS
, "-borderwidth", "borderWidth", "BorderWidth",
155 DEF_ENTRY_BORDER_WIDTH
, Tk_Offset(Entry
, borderWidth
), 0},
156 {TK_CONFIG_ACTIVE_CURSOR
, "-cursor", "cursor", "Cursor",
157 DEF_ENTRY_CURSOR
, Tk_Offset(Entry
, cursor
), TK_CONFIG_NULL_OK
},
158 {TK_CONFIG_BORDER
, "-cursorbackground", "cursorBackground", "Foreground",
159 DEF_ENTRY_CURSOR_BG
, Tk_Offset(Entry
, cursorBorder
), 0},
160 {TK_CONFIG_PIXELS
, "-cursorborderwidth", "cursorBorderWidth", "BorderWidth",
161 DEF_ENTRY_CURSOR_BD_COLOR
, Tk_Offset(Entry
, cursorBorderWidth
),
162 TK_CONFIG_COLOR_ONLY
},
163 {TK_CONFIG_PIXELS
, "-cursorborderwidth", "cursorBorderWidth", "BorderWidth",
164 DEF_ENTRY_CURSOR_BD_MONO
, Tk_Offset(Entry
, cursorBorderWidth
),
165 TK_CONFIG_MONO_ONLY
},
166 {TK_CONFIG_INT
, "-cursorofftime", "cursorOffTime", "OffTime",
167 DEF_ENTRY_CURSOR_OFF_TIME
, Tk_Offset(Entry
, cursorOffTime
), 0},
168 {TK_CONFIG_INT
, "-cursorontime", "cursorOnTime", "OnTime",
169 DEF_ENTRY_CURSOR_ON_TIME
, Tk_Offset(Entry
, cursorOnTime
), 0},
170 {TK_CONFIG_PIXELS
, "-cursorwidth", "cursorWidth", "CursorWidth",
171 DEF_ENTRY_CURSOR_WIDTH
, Tk_Offset(Entry
, cursorWidth
), 0},
172 {TK_CONFIG_BOOLEAN
, "-exportselection", "exportSelection",
173 "ExportSelection", DEF_ENTRY_EXPORT_SELECTION
,
174 Tk_Offset(Entry
, exportSelection
), 0},
175 {TK_CONFIG_SYNONYM
, "-fg", "foreground", (char *) NULL
,
176 (char *) NULL
, 0, 0},
177 {TK_CONFIG_FONT
, "-font", "font", "Font",
178 DEF_ENTRY_FONT
, Tk_Offset(Entry
, fontPtr
), 0},
179 {TK_CONFIG_COLOR
, "-foreground", "foreground", "Foreground",
180 DEF_ENTRY_FG
, Tk_Offset(Entry
, fgColorPtr
), 0},
181 {TK_CONFIG_RELIEF
, "-relief", "relief", "Relief",
182 DEF_ENTRY_RELIEF
, Tk_Offset(Entry
, relief
), 0},
183 {TK_CONFIG_STRING
, "-scrollcommand", "scrollCommand", "ScrollCommand",
184 DEF_ENTRY_SCROLL_COMMAND
, Tk_Offset(Entry
, scrollCmd
), 0},
185 {TK_CONFIG_BORDER
, "-selectbackground", "selectBackground", "Foreground",
186 DEF_ENTRY_SELECT_COLOR
, Tk_Offset(Entry
, selBorder
),
187 TK_CONFIG_COLOR_ONLY
},
188 {TK_CONFIG_BORDER
, "-selectbackground", "selectBackground", "Foreground",
189 DEF_ENTRY_SELECT_MONO
, Tk_Offset(Entry
, selBorder
),
190 TK_CONFIG_MONO_ONLY
},
191 {TK_CONFIG_PIXELS
, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
192 DEF_ENTRY_SELECT_BD_COLOR
, Tk_Offset(Entry
, selBorderWidth
),
193 TK_CONFIG_COLOR_ONLY
},
194 {TK_CONFIG_PIXELS
, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
195 DEF_ENTRY_SELECT_BD_MONO
, Tk_Offset(Entry
, selBorderWidth
),
196 TK_CONFIG_MONO_ONLY
},
197 {TK_CONFIG_COLOR
, "-selectforeground", "selectForeground", "Background",
198 DEF_ENTRY_SELECT_FG_COLOR
, Tk_Offset(Entry
, selFgColorPtr
),
199 TK_CONFIG_COLOR_ONLY
},
200 {TK_CONFIG_COLOR
, "-selectforeground", "selectForeground", "Background",
201 DEF_ENTRY_SELECT_FG_MONO
, Tk_Offset(Entry
, selFgColorPtr
),
202 TK_CONFIG_MONO_ONLY
},
203 {TK_CONFIG_UID
, "-state", "state", "State",
204 DEF_ENTRY_STATE
, Tk_Offset(Entry
, state
), 0},
205 {TK_CONFIG_STRING
, "-textvariable", "textVariable", "Variable",
206 DEF_ENTRY_TEXT_VARIABLE
, Tk_Offset(Entry
, textVarName
),
208 {TK_CONFIG_INT
, "-width", "width", "Width",
209 DEF_ENTRY_WIDTH
, Tk_Offset(Entry
, prefWidth
), 0},
210 {TK_CONFIG_END
, (char *) NULL
, (char *) NULL
, (char *) NULL
,
215 * Flags for GetEntryIndex procedure:
219 #define LAST_PLUS_ONE_OK 2
222 * Forward declarations for procedures defined later in this file:
225 static int ConfigureEntry
_ANSI_ARGS_((Tcl_Interp
*interp
,
226 Entry
*entryPtr
, int argc
, char **argv
,
228 static void DeleteChars
_ANSI_ARGS_((Entry
*entryPtr
, int index
,
230 static void DestroyEntry
_ANSI_ARGS_((ClientData clientData
));
231 static void DisplayEntry
_ANSI_ARGS_((ClientData clientData
));
232 static int GetEntryIndex
_ANSI_ARGS_((Tcl_Interp
*interp
,
233 Entry
*entryPtr
, char *string
, int *indexPtr
));
234 static void InsertChars
_ANSI_ARGS_((Entry
*entryPtr
, int index
,
236 static void EntryBlinkProc
_ANSI_ARGS_((ClientData clientData
));
237 static void EntryEventProc
_ANSI_ARGS_((ClientData clientData
,
239 static void EntryFocusProc
_ANSI_ARGS_ ((ClientData clientData
,
241 static int EntryFetchSelection
_ANSI_ARGS_((ClientData clientData
,
242 int offset
, char *buffer
, int maxBytes
));
243 static void EntryLostSelection
_ANSI_ARGS_((
244 ClientData clientData
));
245 static void EventuallyRedraw
_ANSI_ARGS_((Entry
*entryPtr
));
246 static void EntryScanTo
_ANSI_ARGS_((Entry
*entryPtr
, int y
));
247 static void EntrySetValue
_ANSI_ARGS_((Entry
*entryPtr
,
249 static void EntrySelectTo
_ANSI_ARGS_((
250 Entry
*entryPtr
, int index
));
251 static char * EntryTextVarProc
_ANSI_ARGS_((ClientData clientData
,
252 Tcl_Interp
*interp
, char *name1
, char *name2
,
254 static void EntryUpdateScrollbar
_ANSI_ARGS_((Entry
*entryPtr
));
255 static int EntryWidgetCmd
_ANSI_ARGS_((ClientData clientData
,
256 Tcl_Interp
*interp
, int argc
, char **argv
));
259 *--------------------------------------------------------------
263 * This procedure is invoked to process the "entry" Tcl
264 * command. See the user documentation for details on what
268 * A standard Tcl result.
271 * See the user documentation.
273 *--------------------------------------------------------------
277 Tk_EntryCmd(clientData
, interp
, argc
, argv
)
278 ClientData clientData
; /* Main window associated with
280 Tcl_Interp
*interp
; /* Current interpreter. */
281 int argc
; /* Number of arguments. */
282 char **argv
; /* Argument strings. */
284 Tk_Window tkwin
= (Tk_Window
) clientData
;
285 register Entry
*entryPtr
;
289 Tcl_AppendResult(interp
, "wrong # args: should be \"",
290 argv
[0], " pathName ?options?\"", (char *) NULL
);
294 new = Tk_CreateWindowFromPath(interp
, tkwin
, argv
[1], (char *) NULL
);
300 * Initialize the fields of the structure that won't be initialized
301 * by ConfigureEntry, or that ConfigureEntry requires to be
302 * initialized already (e.g. resource pointers).
305 entryPtr
= (Entry
*) ckalloc(sizeof(Entry
));
306 entryPtr
->tkwin
= new;
307 entryPtr
->interp
= interp
;
308 entryPtr
->numChars
= 0;
309 entryPtr
->string
= (char *) ckalloc(1);
310 entryPtr
->string
[0] = '\0';
311 entryPtr
->textVarName
= NULL
;
312 entryPtr
->state
= tkNormalUid
;
313 entryPtr
->normalBorder
= NULL
;
314 entryPtr
->fontPtr
= NULL
;
315 entryPtr
->fgColorPtr
= NULL
;
316 entryPtr
->textGC
= None
;
317 entryPtr
->selBorder
= NULL
;
318 entryPtr
->selFgColorPtr
= NULL
;
319 entryPtr
->selTextGC
= NULL
;
320 entryPtr
->cursorBorder
= NULL
;
321 entryPtr
->cursorBlinkHandler
= (Tk_TimerToken
) NULL
;
322 entryPtr
->leftIndex
= 0;
323 entryPtr
->cursorPos
= 0;
324 entryPtr
->selectFirst
= -1;
325 entryPtr
->selectLast
= -1;
326 entryPtr
->selectAnchor
= 0;
327 entryPtr
->exportSelection
= 1;
328 entryPtr
->scanMarkX
= 0;
329 entryPtr
->cursor
= None
;
330 entryPtr
->scrollCmd
= NULL
;
333 Tk_SetClass(entryPtr
->tkwin
, "Entry");
334 Tk_CreateEventHandler(entryPtr
->tkwin
, ExposureMask
|StructureNotifyMask
,
335 EntryEventProc
, (ClientData
) entryPtr
);
336 Tk_CreateSelHandler(entryPtr
->tkwin
, XA_STRING
, EntryFetchSelection
,
337 (ClientData
) entryPtr
, XA_STRING
);
338 Tcl_CreateCommand(interp
, Tk_PathName(entryPtr
->tkwin
), EntryWidgetCmd
,
339 (ClientData
) entryPtr
, (void (*)()) NULL
);
340 if (ConfigureEntry(interp
, entryPtr
, argc
-2, argv
+2, 0) != TCL_OK
) {
343 Tk_CreateFocusHandler(entryPtr
->tkwin
, EntryFocusProc
,
344 (ClientData
) entryPtr
);
346 interp
->result
= Tk_PathName(entryPtr
->tkwin
);
350 Tk_DestroyWindow(entryPtr
->tkwin
);
355 *--------------------------------------------------------------
359 * This procedure is invoked to process the Tcl command
360 * that corresponds to a widget managed by this module.
361 * See the user documentation for details on what it does.
364 * A standard Tcl result.
367 * See the user documentation.
369 *--------------------------------------------------------------
373 EntryWidgetCmd(clientData
, interp
, argc
, argv
)
374 ClientData clientData
; /* Information about entry widget. */
375 Tcl_Interp
*interp
; /* Current interpreter. */
376 int argc
; /* Number of arguments. */
377 char **argv
; /* Argument strings. */
379 register Entry
*entryPtr
= (Entry
*) clientData
;
385 Tcl_AppendResult(interp
, "wrong # args: should be \"",
386 argv
[0], " option ?arg arg ...?\"", (char *) NULL
);
389 Tk_Preserve((ClientData
) entryPtr
);
391 length
= strlen(argv
[1]);
392 if ((c
== 'c') && (strncmp(argv
[1], "configure", length
) == 0)
395 result
= Tk_ConfigureInfo(interp
, entryPtr
->tkwin
, configSpecs
,
396 (char *) entryPtr
, (char *) NULL
, 0);
397 } else if (argc
== 3) {
398 result
= Tk_ConfigureInfo(interp
, entryPtr
->tkwin
, configSpecs
,
399 (char *) entryPtr
, argv
[2], 0);
401 result
= ConfigureEntry(interp
, entryPtr
, argc
-2, argv
+2,
402 TK_CONFIG_ARGV_ONLY
);
404 } else if ((c
== 'c') && (strncmp(argv
[1], "cursor", length
) == 0)
407 Tcl_AppendResult(interp
, "wrong # args: should be \"",
408 argv
[0], " cursor pos\"",
412 if (GetEntryIndex(interp
, entryPtr
, argv
[2], &entryPtr
->cursorPos
)
416 EventuallyRedraw(entryPtr
);
417 } else if ((c
== 'd') && (strncmp(argv
[1], "delete", length
) == 0)) {
420 if ((argc
< 3) || (argc
> 4)) {
421 Tcl_AppendResult(interp
, "wrong # args: should be \"",
422 argv
[0], " delete firstIndex ?lastIndex?\"",
426 if (GetEntryIndex(interp
, entryPtr
, argv
[2], &first
) != TCL_OK
) {
432 if (GetEntryIndex(interp
, entryPtr
, argv
[3], &last
) != TCL_OK
) {
436 if ((last
>= first
) && (entryPtr
->state
== tkNormalUid
)) {
437 DeleteChars(entryPtr
, first
, last
+1-first
);
439 } else if ((c
== 'g') && (strncmp(argv
[1], "get", length
) == 0)) {
441 Tcl_AppendResult(interp
, "wrong # args: should be \"",
442 argv
[0], " get\"", (char *) NULL
);
445 interp
->result
= entryPtr
->string
;
446 } else if ((c
== 'i') && (strncmp(argv
[1], "index", length
) == 0)
451 Tcl_AppendResult(interp
, "wrong # args: should be \"",
452 argv
[0], " index string\"", (char *) NULL
);
455 if (GetEntryIndex(interp
, entryPtr
, argv
[2], &index
) != TCL_OK
) {
458 sprintf(interp
->result
, "%d", index
);
459 } else if ((c
== 'i') && (strncmp(argv
[1], "insert", length
) == 0)
464 Tcl_AppendResult(interp
, "wrong # args: should be \"",
465 argv
[0], " insert index text\"",
469 if (GetEntryIndex(interp
, entryPtr
, argv
[2], &index
) != TCL_OK
) {
472 if (entryPtr
->state
== tkNormalUid
) {
473 InsertChars(entryPtr
, index
, argv
[3]);
475 } else if ((c
== 's') && (length
>= 2)
476 && (strncmp(argv
[1], "scan", length
) == 0)) {
480 Tcl_AppendResult(interp
, "wrong # args: should be \"",
481 argv
[0], " scan mark|dragto x\"", (char *) NULL
);
484 if (Tcl_GetInt(interp
, argv
[3], &x
) != TCL_OK
) {
487 if ((argv
[2][0] == 'm')
488 && (strncmp(argv
[2], "mark", strlen(argv
[2])) == 0)) {
489 entryPtr
->scanMarkX
= x
;
490 entryPtr
->scanMarkIndex
= entryPtr
->leftIndex
;
491 } else if ((argv
[2][0] == 'd')
492 && (strncmp(argv
[2], "dragto", strlen(argv
[2])) == 0)) {
493 EntryScanTo(entryPtr
, x
);
495 Tcl_AppendResult(interp
, "bad scan option \"", argv
[2],
496 "\": must be mark or dragto", (char *) NULL
);
499 } else if ((c
== 's') && (length
>= 2)
500 && (strncmp(argv
[1], "select", length
) == 0)) {
504 Tcl_AppendResult(interp
, "too few args: should be \"",
505 argv
[0], " select option ?index?\"", (char *) NULL
);
508 length
= strlen(argv
[2]);
510 if ((c
== 'c') && (argv
[2] != NULL
)
511 && (strncmp(argv
[2], "clear", length
) == 0)) {
513 Tcl_AppendResult(interp
, "wrong # args: should be \"",
514 argv
[0], " select clear\"", (char *) NULL
);
517 if (entryPtr
->selectFirst
!= -1) {
518 entryPtr
->selectFirst
= entryPtr
->selectLast
= -1;
519 EventuallyRedraw(entryPtr
);
524 if (GetEntryIndex(interp
, entryPtr
, argv
[3], &index
) != TCL_OK
) {
528 if ((c
== 'a') && (strncmp(argv
[2], "adjust", length
) == 0)) {
530 Tcl_AppendResult(interp
, "wrong # args: should be \"",
531 argv
[0], " select adjust index\"",
535 if (entryPtr
->selectFirst
>= 0) {
536 if (index
< (entryPtr
->selectFirst
+ entryPtr
->selectLast
)/2) {
537 entryPtr
->selectAnchor
= entryPtr
->selectLast
+ 1;
539 entryPtr
->selectAnchor
= entryPtr
->selectFirst
;
542 EntrySelectTo(entryPtr
, index
);
543 } else if ((c
== 'f') && (strncmp(argv
[2], "from", length
) == 0)) {
545 Tcl_AppendResult(interp
, "wrong # args: should be \"",
546 argv
[0], " select from index\"",
550 entryPtr
->selectAnchor
= index
;
551 } else if ((c
== 't') && (strncmp(argv
[2], "to", length
) == 0)) {
553 Tcl_AppendResult(interp
, "wrong # args: should be \"",
554 argv
[0], " select to index\"",
558 EntrySelectTo(entryPtr
, index
);
560 Tcl_AppendResult(interp
, "bad select option \"", argv
[2],
561 "\": must be adjust, clear, from, or to", (char *) NULL
);
564 } else if ((c
== 'v') && (strncmp(argv
[1], "view", length
) == 0)) {
568 Tcl_AppendResult(interp
, "wrong # args: should be \"",
569 argv
[0], " view index\"", (char *) NULL
);
572 if (GetEntryIndex(interp
, entryPtr
, argv
[2], &index
) != TCL_OK
) {
575 if ((index
>= entryPtr
->numChars
) && (index
> 0)) {
576 index
= entryPtr
->numChars
-1;
578 entryPtr
->leftIndex
= index
;
579 EventuallyRedraw(entryPtr
);
580 EntryUpdateScrollbar(entryPtr
);
582 Tcl_AppendResult(interp
, "bad option \"", argv
[1],
583 "\": must be configure, cursor, delete, get, index, ",
584 "insert, scan, select, or view", (char *) NULL
);
588 Tk_Release((ClientData
) entryPtr
);
592 Tk_Release((ClientData
) entryPtr
);
597 *----------------------------------------------------------------------
601 * This procedure is invoked by Tk_EventuallyFree or Tk_Release
602 * to clean up the internal structure of an entry at a safe time
603 * (when no-one is using it anymore).
609 * Everything associated with the entry is freed up.
611 *----------------------------------------------------------------------
615 DestroyEntry(clientData
)
616 ClientData clientData
; /* Info about entry widget. */
618 register Entry
*entryPtr
= (Entry
*) clientData
;
620 ckfree(entryPtr
->string
);
621 if (entryPtr
->normalBorder
!= NULL
) {
622 Tk_Free3DBorder(entryPtr
->normalBorder
);
624 if (entryPtr
->textVarName
!= NULL
) {
625 Tcl_UntraceVar(entryPtr
->interp
, entryPtr
->textVarName
,
626 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
627 EntryTextVarProc
, (ClientData
) entryPtr
);
628 ckfree(entryPtr
->textVarName
);
630 if (entryPtr
->fontPtr
!= NULL
) {
631 Tk_FreeFontStruct(entryPtr
->fontPtr
);
633 if (entryPtr
->fgColorPtr
!= NULL
) {
634 Tk_FreeColor(entryPtr
->fgColorPtr
);
636 if (entryPtr
->textGC
!= None
) {
637 Tk_FreeGC(entryPtr
->textGC
);
639 if (entryPtr
->selBorder
!= NULL
) {
640 Tk_Free3DBorder(entryPtr
->selBorder
);
642 if (entryPtr
->selFgColorPtr
!= NULL
) {
643 Tk_FreeColor(entryPtr
->selFgColorPtr
);
645 if (entryPtr
->selTextGC
!= None
) {
646 Tk_FreeGC(entryPtr
->selTextGC
);
648 if (entryPtr
->cursorBorder
!= NULL
) {
649 Tk_Free3DBorder(entryPtr
->cursorBorder
);
651 if (entryPtr
->cursorBlinkHandler
!= NULL
) {
652 Tk_DeleteTimerHandler(entryPtr
->cursorBlinkHandler
);
653 entryPtr
->cursorBlinkHandler
= NULL
;
655 if (entryPtr
->cursor
!= None
) {
656 Tk_FreeCursor(entryPtr
->cursor
);
658 if (entryPtr
->scrollCmd
!= NULL
) {
659 ckfree(entryPtr
->scrollCmd
);
661 ckfree((char *) entryPtr
);
665 *----------------------------------------------------------------------
669 * This procedure is called to process an argv/argc list, plus
670 * the Tk option database, in order to configure (or reconfigure)
674 * The return value is a standard Tcl result. If TCL_ERROR is
675 * returned, then interp->result contains an error message.
678 * Configuration information, such as colors, border width,
679 * etc. get set for entryPtr; old resources get freed,
682 *----------------------------------------------------------------------
686 ConfigureEntry(interp
, entryPtr
, argc
, argv
, flags
)
687 Tcl_Interp
*interp
; /* Used for error reporting. */
688 register Entry
*entryPtr
; /* Information about widget; may or may
689 * not already have values for some fields. */
690 int argc
; /* Number of valid entries in argv. */
691 char **argv
; /* Arguments. */
692 int flags
; /* Flags to pass to Tk_ConfigureWidget. */
696 int width
, height
, fontHeight
, oldExport
;
699 * Eliminate any existing trace on a variable monitored by the entry.
702 if (entryPtr
->textVarName
!= NULL
) {
703 Tcl_UntraceVar(interp
, entryPtr
->textVarName
,
704 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
705 EntryTextVarProc
, (ClientData
) entryPtr
);
708 oldExport
= entryPtr
->exportSelection
;
709 if (Tk_ConfigureWidget(interp
, entryPtr
->tkwin
, configSpecs
,
710 argc
, argv
, (char *) entryPtr
, flags
) != TCL_OK
) {
715 * If the entry is tied to the value of a variable, then set up
716 * a trace on the variable's value, create the variable if it doesn't
717 * exist, and set the entry's value from the variable's value.
720 if (entryPtr
->textVarName
!= NULL
) {
723 value
= Tcl_GetVar(interp
, entryPtr
->textVarName
, TCL_GLOBAL_ONLY
);
725 Tcl_SetVar(interp
, entryPtr
->textVarName
, entryPtr
->string
,
728 EntrySetValue(entryPtr
, value
);
730 Tcl_TraceVar(interp
, entryPtr
->textVarName
,
731 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
732 EntryTextVarProc
, (ClientData
) entryPtr
);
736 * A few other options also need special processing, such as parsing
737 * the geometry and setting the background from a 3-D border.
740 if ((entryPtr
->state
!= tkNormalUid
)
741 && (entryPtr
->state
!= tkDisabledUid
)) {
742 Tcl_AppendResult(interp
, "bad state value \"", entryPtr
->state
,
743 "\": must be normal or disabled", (char *) NULL
);
744 entryPtr
->state
= tkNormalUid
;
748 Tk_SetBackgroundFromBorder(entryPtr
->tkwin
, entryPtr
->normalBorder
);
750 gcValues
.foreground
= entryPtr
->fgColorPtr
->pixel
;
751 gcValues
.font
= entryPtr
->fontPtr
->fid
;
752 gcValues
.graphics_exposures
= False
;
753 new = Tk_GetGC(entryPtr
->tkwin
, GCForeground
|GCFont
|GCGraphicsExposures
,
755 if (entryPtr
->textGC
!= None
) {
756 Tk_FreeGC(entryPtr
->textGC
);
758 entryPtr
->textGC
= new;
760 gcValues
.foreground
= entryPtr
->selFgColorPtr
->pixel
;
761 gcValues
.font
= entryPtr
->fontPtr
->fid
;
762 new = Tk_GetGC(entryPtr
->tkwin
, GCForeground
|GCFont
, &gcValues
);
763 if (entryPtr
->selTextGC
!= None
) {
764 Tk_FreeGC(entryPtr
->selTextGC
);
766 entryPtr
->selTextGC
= new;
768 if (entryPtr
->cursorWidth
> 2*entryPtr
->fontPtr
->min_bounds
.width
) {
769 entryPtr
->cursorWidth
= 2*entryPtr
->fontPtr
->min_bounds
.width
;
770 if (entryPtr
->cursorWidth
== 0) {
771 entryPtr
->cursorWidth
= 2;
774 if (entryPtr
->cursorBorderWidth
> entryPtr
->cursorWidth
/2) {
775 entryPtr
->cursorBorderWidth
= entryPtr
->cursorWidth
/2;
779 * Restart the cursor timing sequence in case the on-time or off-time
783 if (entryPtr
->flags
& GOT_FOCUS
) {
784 EntryFocusProc((ClientData
) entryPtr
, 1);
788 * Claim the selection if we've suddenly started exporting it.
791 if (entryPtr
->exportSelection
&& (!oldExport
)
792 && (entryPtr
->selectFirst
!= -1)) {
793 Tk_OwnSelection(entryPtr
->tkwin
, EntryLostSelection
,
794 (ClientData
) entryPtr
);
798 * Register the desired geometry for the window, and arrange for
799 * the window to be redisplayed.
802 fontHeight
= entryPtr
->fontPtr
->ascent
+ entryPtr
->fontPtr
->descent
;
803 entryPtr
->avgWidth
= XTextWidth(entryPtr
->fontPtr
, "0", 1);
804 width
= entryPtr
->prefWidth
*entryPtr
->avgWidth
+ (15*fontHeight
)/10;
805 height
= fontHeight
+ 2*entryPtr
->borderWidth
+ 2;
806 Tk_GeometryRequest(entryPtr
->tkwin
, width
, height
);
807 Tk_SetInternalBorder(entryPtr
->tkwin
, entryPtr
->borderWidth
);
808 if (entryPtr
->relief
!= TK_RELIEF_FLAT
) {
809 entryPtr
->offset
= entryPtr
->borderWidth
;
811 entryPtr
->offset
= 0;
813 EventuallyRedraw(entryPtr
);
814 EntryUpdateScrollbar(entryPtr
);
819 *--------------------------------------------------------------
823 * This procedure redraws the contents of an entry window.
829 * Information appears on the screen.
831 *--------------------------------------------------------------
835 DisplayEntry(clientData
)
836 ClientData clientData
; /* Information about window. */
838 register Entry
*entryPtr
= (Entry
*) clientData
;
839 register Tk_Window tkwin
= entryPtr
->tkwin
;
840 int startX
, baseY
, selStartX
, selEndX
, index
, cursorX
;
844 entryPtr
->flags
&= ~REDRAW_PENDING
;
845 if ((entryPtr
->tkwin
== NULL
) || !Tk_IsMapped(tkwin
)) {
850 * In order to avoid screen flashes, this procedure redraws the
851 * textual area of the entry into off-screen memory, then copies
852 * it back on-screen in a single operation. This means there's
853 * no point in time where the on-screen image has been cleared.
856 pixmap
= XCreatePixmap(Tk_Display(tkwin
), Tk_WindowId(tkwin
),
857 Tk_Width(tkwin
), Tk_Height(tkwin
),
858 Tk_DefaultDepth(Tk_Screen(tkwin
)));
861 * Compute x-coordinate of the "leftIndex" character, plus limit
862 * of visible x-coordinates (actually, pixel just after last visible
863 * one), plus vertical position of baseline of text.
866 startX
= entryPtr
->offset
;
867 xBound
= Tk_Width(tkwin
) - entryPtr
->offset
;
868 baseY
= (Tk_Height(tkwin
) + entryPtr
->fontPtr
->ascent
869 - entryPtr
->fontPtr
->descent
)/2;
872 * Draw the background in three layers. From bottom to top the
873 * layers are: normal background, selection background, and
874 * insertion cursor background.
877 Tk_Fill3DRectangle(Tk_Display(tkwin
), pixmap
, entryPtr
->normalBorder
,
878 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
), 0, TK_RELIEF_FLAT
);
880 if (entryPtr
->selectLast
>= entryPtr
->leftIndex
) {
881 if (entryPtr
->selectFirst
<= entryPtr
->leftIndex
) {
883 index
= entryPtr
->leftIndex
;
885 (void) TkMeasureChars(entryPtr
->fontPtr
,
886 entryPtr
->string
+entryPtr
->leftIndex
,
887 entryPtr
->selectFirst
- entryPtr
->leftIndex
, startX
,
888 xBound
, TK_PARTIAL_OK
|TK_NEWLINES_NOT_SPECIAL
, &selStartX
);
889 index
= entryPtr
->selectFirst
;
891 if (selStartX
< xBound
) {
892 (void) TkMeasureChars(entryPtr
->fontPtr
,
893 entryPtr
->string
+ index
, entryPtr
->selectLast
+1 - index
,
894 selStartX
, xBound
, TK_PARTIAL_OK
|TK_NEWLINES_NOT_SPECIAL
,
896 Tk_Fill3DRectangle(Tk_Display(tkwin
), pixmap
, entryPtr
->selBorder
,
897 selStartX
- entryPtr
->selBorderWidth
,
898 baseY
- entryPtr
->fontPtr
->ascent
899 - entryPtr
->selBorderWidth
,
900 (selEndX
- selStartX
) + 2*entryPtr
->selBorderWidth
,
901 entryPtr
->fontPtr
->ascent
+ entryPtr
->fontPtr
->descent
902 + 2*entryPtr
->selBorderWidth
,
903 entryPtr
->selBorderWidth
, TK_RELIEF_RAISED
);
910 * Draw a special background for the insertion cursor, overriding
911 * even the selection background. As a special workaround to keep the
912 * cursor visible on mono displays, write background in the cursor
913 * area (instead of nothing) when the cursor isn't on. Otherwise
914 * the selection would hide the cursor.
917 if ((entryPtr
->cursorPos
>= entryPtr
->leftIndex
)
918 && (entryPtr
->state
== tkNormalUid
)
919 && (entryPtr
->flags
& GOT_FOCUS
)) {
920 (void) TkMeasureChars(entryPtr
->fontPtr
,
921 entryPtr
->string
+ entryPtr
->leftIndex
,
922 entryPtr
->cursorPos
- entryPtr
->leftIndex
, startX
,
923 xBound
, TK_PARTIAL_OK
|TK_NEWLINES_NOT_SPECIAL
, &cursorX
);
924 if (cursorX
< xBound
) {
925 if (entryPtr
->flags
& CURSOR_ON
) {
926 Tk_Fill3DRectangle(Tk_Display(tkwin
), pixmap
,
927 entryPtr
->cursorBorder
,
928 cursorX
- (entryPtr
->cursorWidth
)/2,
929 baseY
- entryPtr
->fontPtr
->ascent
,
930 entryPtr
->cursorWidth
,
931 entryPtr
->fontPtr
->ascent
+ entryPtr
->fontPtr
->descent
,
932 entryPtr
->cursorBorderWidth
, TK_RELIEF_RAISED
);
933 } else if (Tk_DefaultDepth(Tk_Screen(tkwin
)) == 1) {
934 Tk_Fill3DRectangle(Tk_Display(tkwin
), pixmap
,
935 entryPtr
->normalBorder
,
936 cursorX
- (entryPtr
->cursorWidth
)/2,
937 baseY
- entryPtr
->fontPtr
->ascent
,
938 entryPtr
->cursorWidth
,
939 entryPtr
->fontPtr
->ascent
+ entryPtr
->fontPtr
->descent
,
946 * Draw the text in three pieces: first the piece to the left of
947 * the selection, then the selection, then the piece to the right
951 if (entryPtr
->selectLast
< entryPtr
->leftIndex
) {
952 TkDisplayChars(Tk_Display(tkwin
), pixmap
, entryPtr
->textGC
,
953 entryPtr
->fontPtr
, entryPtr
->string
+ entryPtr
->leftIndex
,
954 entryPtr
->numChars
- entryPtr
->leftIndex
, startX
, baseY
,
955 TK_NEWLINES_NOT_SPECIAL
);
957 count
= entryPtr
->selectFirst
- entryPtr
->leftIndex
;
959 TkDisplayChars(Tk_Display(tkwin
), pixmap
, entryPtr
->textGC
,
960 entryPtr
->fontPtr
, entryPtr
->string
+ entryPtr
->leftIndex
,
961 count
, startX
, baseY
, TK_NEWLINES_NOT_SPECIAL
);
962 index
= entryPtr
->selectFirst
;
964 index
= entryPtr
->leftIndex
;
966 count
= entryPtr
->selectLast
+ 1 - index
;
967 if ((selStartX
< xBound
) && (count
> 0)) {
968 TkDisplayChars(Tk_Display(tkwin
), pixmap
, entryPtr
->selTextGC
,
969 entryPtr
->fontPtr
, entryPtr
->string
+ index
, count
,
970 selStartX
, baseY
, TK_NEWLINES_NOT_SPECIAL
);
972 count
= entryPtr
->numChars
- entryPtr
->selectLast
- 1;
973 if ((selEndX
< xBound
) && (count
> 0)) {
974 TkDisplayChars(Tk_Display(tkwin
), pixmap
, entryPtr
->textGC
,
976 entryPtr
->string
+ entryPtr
->selectLast
+ 1,
977 count
, selEndX
, baseY
, TK_NEWLINES_NOT_SPECIAL
);
982 * Draw the border last, so it will overwrite any text that extends
983 * past the viewable part of the window.
986 if (entryPtr
->relief
!= TK_RELIEF_FLAT
) {
987 Tk_Draw3DRectangle(Tk_Display(tkwin
), pixmap
,
988 entryPtr
->normalBorder
, 0, 0, Tk_Width(tkwin
),
989 Tk_Height(tkwin
), entryPtr
->borderWidth
,
994 * Everything's been redisplayed; now copy the pixmap onto the screen
995 * and free up the pixmap.
998 XCopyArea(Tk_Display(tkwin
), pixmap
, Tk_WindowId(tkwin
), entryPtr
->textGC
,
999 0, 0, Tk_Width(tkwin
), Tk_Height(tkwin
), 0, 0);
1000 XFreePixmap(Tk_Display(tkwin
), pixmap
);
1001 entryPtr
->flags
&= ~BORDER_NEEDED
;
1005 *----------------------------------------------------------------------
1009 * Add new characters to an entry widget.
1015 * New information gets added to entryPtr; it will be redisplayed
1016 * soon, but not necessarily immediately.
1018 *----------------------------------------------------------------------
1022 InsertChars(entryPtr
, index
, string
)
1023 register Entry
*entryPtr
; /* Entry that is to get the new
1025 int index
; /* Add the new elements before this
1027 char *string
; /* New characters to add (NULL-terminated
1033 length
= strlen(string
);
1037 new = (char *) ckalloc((unsigned) (entryPtr
->numChars
+ length
+ 1));
1038 strncpy(new, entryPtr
->string
, index
);
1039 strcpy(new+index
, string
);
1040 strcpy(new+index
+length
, entryPtr
->string
+index
);
1041 ckfree(entryPtr
->string
);
1042 entryPtr
->string
= new;
1043 entryPtr
->numChars
+= length
;
1046 * Inserting characters invalidates all indexes into the string.
1047 * Touch up the indexes so that they still refer to the same
1048 * characters (at new positions).
1051 if (entryPtr
->selectFirst
>= index
) {
1052 entryPtr
->selectFirst
+= length
;
1054 if (entryPtr
->selectLast
>= index
) {
1055 entryPtr
->selectLast
+= length
;
1057 if (entryPtr
->selectAnchor
>= index
) {
1058 entryPtr
->selectAnchor
+= length
;
1060 if (entryPtr
->leftIndex
> index
) {
1061 entryPtr
->leftIndex
+= length
;
1063 if (entryPtr
->cursorPos
>= index
) {
1064 entryPtr
->cursorPos
+= length
;
1067 if (entryPtr
->textVarName
!= NULL
) {
1068 Tcl_SetVar(entryPtr
->interp
, entryPtr
->textVarName
, entryPtr
->string
,
1071 EventuallyRedraw(entryPtr
);
1072 EntryUpdateScrollbar(entryPtr
);
1076 *----------------------------------------------------------------------
1080 * Remove one or more characters from an entry widget.
1086 * Memory gets freed, the entry gets modified and (eventually)
1089 *----------------------------------------------------------------------
1093 DeleteChars(entryPtr
, index
, count
)
1094 register Entry
*entryPtr
; /* Entry widget to modify. */
1095 int index
; /* Index of first character to delete. */
1096 int count
; /* How many characters to delete. */
1100 if ((index
+ count
) > entryPtr
->numChars
) {
1101 count
= entryPtr
->numChars
- index
;
1107 new = (char *) ckalloc((unsigned) (entryPtr
->numChars
+ 1 - count
));
1108 strncpy(new, entryPtr
->string
, index
);
1109 strcpy(new+index
, entryPtr
->string
+index
+count
);
1110 ckfree(entryPtr
->string
);
1111 entryPtr
->string
= new;
1112 entryPtr
->numChars
-= count
;
1115 * Deleting characters results in the remaining characters being
1116 * renumbered. Update the various indexes into the string to reflect
1119 if (entryPtr
->selectFirst
>= index
) {
1120 if (entryPtr
->selectFirst
>= (index
+count
)) {
1121 entryPtr
->selectFirst
-= count
;
1123 entryPtr
->selectFirst
= index
;
1126 if (entryPtr
->selectLast
>= index
) {
1127 if (entryPtr
->selectLast
>= (index
+count
)) {
1128 entryPtr
->selectLast
-= count
;
1130 entryPtr
->selectLast
= index
-1;
1133 if (entryPtr
->selectLast
< entryPtr
->selectFirst
) {
1134 entryPtr
->selectFirst
= entryPtr
->selectLast
= -1;
1136 if (entryPtr
->selectAnchor
>= index
) {
1137 if (entryPtr
->selectAnchor
>= (index
+count
)) {
1138 entryPtr
->selectAnchor
-= count
;
1140 entryPtr
->selectAnchor
= index
;
1143 if (entryPtr
->leftIndex
> index
) {
1144 if (entryPtr
->leftIndex
>= (index
+count
)) {
1145 entryPtr
->leftIndex
-= count
;
1147 entryPtr
->leftIndex
= index
;
1150 if (entryPtr
->cursorPos
>= index
) {
1151 if (entryPtr
->cursorPos
>= (index
+count
)) {
1152 entryPtr
->cursorPos
-= count
;
1154 entryPtr
->cursorPos
= index
;
1158 if (entryPtr
->textVarName
!= NULL
) {
1159 Tcl_SetVar(entryPtr
->interp
, entryPtr
->textVarName
, entryPtr
->string
,
1162 EventuallyRedraw(entryPtr
);
1163 EntryUpdateScrollbar(entryPtr
);
1167 *----------------------------------------------------------------------
1171 * Replace the contents of a text entry with a given value. This
1172 * procedure is invoked when updating the entry from the entry's
1173 * associated variable.
1179 * The string displayed in the entry will change. Any selection
1180 * in the entry is lost and the insertion point gets set to the
1181 * end of the entry. Note: this procedure does *not* update the
1182 * entry's associated variable, since that could result in an
1185 *----------------------------------------------------------------------
1189 EntrySetValue(entryPtr
, value
)
1190 register Entry
*entryPtr
; /* Entry whose value is to be
1192 char *value
; /* New text to display in entry. */
1194 ckfree(entryPtr
->string
);
1195 entryPtr
->numChars
= strlen(value
);
1196 entryPtr
->string
= (char *) ckalloc((unsigned) (entryPtr
->numChars
+ 1));
1197 strcpy(entryPtr
->string
, value
);
1198 entryPtr
->selectFirst
= entryPtr
->selectLast
= -1;
1199 entryPtr
->leftIndex
= 0;
1200 entryPtr
->cursorPos
= entryPtr
->numChars
;
1202 EventuallyRedraw(entryPtr
);
1203 EntryUpdateScrollbar(entryPtr
);
1207 *--------------------------------------------------------------
1211 * This procedure is invoked by the Tk dispatcher for various
1212 * events on entryes.
1218 * When the window gets deleted, internal structures get
1219 * cleaned up. When it gets exposed, it is redisplayed.
1221 *--------------------------------------------------------------
1225 EntryEventProc(clientData
, eventPtr
)
1226 ClientData clientData
; /* Information about window. */
1227 XEvent
*eventPtr
; /* Information about event. */
1229 Entry
*entryPtr
= (Entry
*) clientData
;
1230 if (eventPtr
->type
== Expose
) {
1231 EventuallyRedraw(entryPtr
);
1232 entryPtr
->flags
|= BORDER_NEEDED
;
1233 } else if (eventPtr
->type
== DestroyNotify
) {
1234 Tcl_DeleteCommand(entryPtr
->interp
, Tk_PathName(entryPtr
->tkwin
));
1235 entryPtr
->tkwin
= NULL
;
1236 if (entryPtr
->flags
& REDRAW_PENDING
) {
1237 Tk_CancelIdleCall(DisplayEntry
, (ClientData
) entryPtr
);
1239 Tk_EventuallyFree((ClientData
) entryPtr
, DestroyEntry
);
1240 } else if (eventPtr
->type
== ConfigureNotify
) {
1241 Tk_Preserve((ClientData
) entryPtr
);
1242 EventuallyRedraw(entryPtr
);
1243 EntryUpdateScrollbar(entryPtr
);
1244 Tk_Release((ClientData
) entryPtr
);
1249 *--------------------------------------------------------------
1253 * Parse an index into an entry and return either its value
1257 * A standard Tcl result. If all went well, then *indexPtr is
1258 * filled in with the index (into entryPtr) corresponding to
1259 * string. The index value is guaranteed to lie between 0 and
1260 * the number of characters in the string, inclusive. If an
1261 * error occurs then an error message is left in interp->result.
1266 *--------------------------------------------------------------
1270 GetEntryIndex(interp
, entryPtr
, string
, indexPtr
)
1271 Tcl_Interp
*interp
; /* For error messages. */
1272 Entry
*entryPtr
; /* Entry for which the index is being
1274 char *string
; /* Specifies character in entryPtr. */
1275 int *indexPtr
; /* Where to store converted index. */
1279 length
= strlen(string
);
1281 if (string
[0] == 'e') {
1282 if (strncmp(string
, "end", length
) == 0) {
1283 *indexPtr
= entryPtr
->numChars
;
1288 * Some of the paths here leave messages in interp->result,
1289 * so we have to clear it out before storing our own message.
1292 Tcl_SetResult(interp
, (char *) NULL
, TCL_STATIC
);
1293 Tcl_AppendResult(interp
, "bad entry index \"", string
,
1294 "\"", (char *) NULL
);
1297 } else if (string
[0] == 'c') {
1298 if (strncmp(string
, "cursor", length
) == 0) {
1299 *indexPtr
= entryPtr
->cursorPos
;
1303 } else if (string
[0] == 's') {
1304 if (entryPtr
->selectFirst
== -1) {
1305 interp
->result
= "selection isn't in entry";
1311 if (strncmp(string
, "sel.first", length
) == 0) {
1312 *indexPtr
= entryPtr
->selectFirst
;
1313 } else if (strncmp(string
, "sel.last", length
) == 0) {
1314 *indexPtr
= entryPtr
->selectLast
;
1318 } else if (string
[0] == '@') {
1321 if (Tcl_GetInt(interp
, string
+1, &x
) != TCL_OK
) {
1324 if (entryPtr
->numChars
== 0) {
1327 *indexPtr
= entryPtr
->leftIndex
+ TkMeasureChars(entryPtr
->fontPtr
,
1328 entryPtr
->string
+ entryPtr
->leftIndex
,
1329 entryPtr
->numChars
- entryPtr
->leftIndex
,
1330 entryPtr
->offset
, x
, TK_NEWLINES_NOT_SPECIAL
, &dummy
);
1333 if (Tcl_GetInt(interp
, string
, indexPtr
) != TCL_OK
) {
1338 } else if (*indexPtr
> entryPtr
->numChars
) {
1339 *indexPtr
= entryPtr
->numChars
;
1346 *----------------------------------------------------------------------
1350 * Given a y-coordinate (presumably of the curent mouse location)
1351 * drag the view in the window to implement the scan operation.
1357 * The view in the window may change.
1359 *----------------------------------------------------------------------
1363 EntryScanTo(entryPtr
, x
)
1364 register Entry
*entryPtr
; /* Information about widget. */
1365 int x
; /* X-coordinate to use for scan
1371 * Compute new leftIndex for entry by amplifying the difference
1372 * between the current position and the place where the scan
1373 * started (the "mark" position). If we run off the left or right
1374 * side of the entry, then reset the mark point so that the current
1375 * position continues to correspond to the edge of the window.
1376 * This means that the picture will start dragging as soon as the
1377 * mouse reverses direction (without this reset, might have to slide
1378 * mouse a long ways back before the picture starts moving again).
1381 newLeftIndex
= entryPtr
->scanMarkIndex
1382 - (10*(x
- entryPtr
->scanMarkX
))/entryPtr
->avgWidth
;
1383 if (newLeftIndex
>= entryPtr
->numChars
) {
1384 newLeftIndex
= entryPtr
->scanMarkIndex
= entryPtr
->numChars
-1;
1385 entryPtr
->scanMarkX
= x
;
1387 if (newLeftIndex
< 0) {
1388 newLeftIndex
= entryPtr
->scanMarkIndex
= 0;
1389 entryPtr
->scanMarkX
= x
;
1391 if (newLeftIndex
!= entryPtr
->leftIndex
) {
1392 entryPtr
->leftIndex
= newLeftIndex
;
1393 EventuallyRedraw(entryPtr
);
1394 EntryUpdateScrollbar(entryPtr
);
1399 *----------------------------------------------------------------------
1403 * Modify the selection by moving its un-anchored end. This could
1404 * make the selection either larger or smaller.
1410 * The selection changes.
1412 *----------------------------------------------------------------------
1416 EntrySelectTo(entryPtr
, index
)
1417 register Entry
*entryPtr
; /* Information about widget. */
1418 int index
; /* Index of element that is to
1419 * become the "other" end of the
1422 int newFirst
, newLast
;
1425 * Grab the selection if we don't own it already.
1428 if ((entryPtr
->selectFirst
== -1) && (entryPtr
->exportSelection
)) {
1429 Tk_OwnSelection(entryPtr
->tkwin
, EntryLostSelection
,
1430 (ClientData
) entryPtr
);
1436 if (index
>= entryPtr
->numChars
) {
1437 index
= entryPtr
->numChars
-1;
1439 if (entryPtr
->selectAnchor
> entryPtr
->numChars
) {
1440 entryPtr
->selectAnchor
= entryPtr
->numChars
;
1442 if (entryPtr
->selectAnchor
<= index
) {
1443 newFirst
= entryPtr
->selectAnchor
;
1447 newLast
= entryPtr
->selectAnchor
- 1;
1449 newFirst
= newLast
= -1;
1452 if ((entryPtr
->selectFirst
== newFirst
)
1453 && (entryPtr
->selectLast
== newLast
)) {
1456 entryPtr
->selectFirst
= newFirst
;
1457 entryPtr
->selectLast
= newLast
;
1458 EventuallyRedraw(entryPtr
);
1462 *----------------------------------------------------------------------
1464 * EntryFetchSelection --
1466 * This procedure is called back by Tk when the selection is
1467 * requested by someone. It returns part or all of the selection
1468 * in a buffer provided by the caller.
1471 * The return value is the number of non-NULL bytes stored
1472 * at buffer. Buffer is filled (or partially filled) with a
1473 * NULL-terminated string containing part or all of the selection,
1474 * as given by offset and maxBytes.
1479 *----------------------------------------------------------------------
1483 EntryFetchSelection(clientData
, offset
, buffer
, maxBytes
)
1484 ClientData clientData
; /* Information about entry widget. */
1485 int offset
; /* Offset within selection of first
1486 * character to be returned. */
1487 char *buffer
; /* Location in which to place
1489 int maxBytes
; /* Maximum number of bytes to place
1490 * at buffer, not including terminating
1491 * NULL character. */
1493 Entry
*entryPtr
= (Entry
*) clientData
;
1496 if ((entryPtr
->selectFirst
< 0) || !(entryPtr
->exportSelection
)) {
1499 count
= entryPtr
->selectLast
+ 1 - entryPtr
->selectFirst
- offset
;
1500 if (count
> maxBytes
) {
1506 strncpy(buffer
, entryPtr
->string
+ entryPtr
->selectFirst
+ offset
, count
);
1507 buffer
[count
] = '\0';
1512 *----------------------------------------------------------------------
1514 * EntryLostSelection --
1516 * This procedure is called back by Tk when the selection is
1517 * grabbed away from an entry widget.
1523 * The existing selection is unhighlighted, and the window is
1524 * marked as not containing a selection.
1526 *----------------------------------------------------------------------
1530 EntryLostSelection(clientData
)
1531 ClientData clientData
; /* Information about entry widget. */
1533 Entry
*entryPtr
= (Entry
*) clientData
;
1535 if ((entryPtr
->selectFirst
!= -1) && entryPtr
->exportSelection
) {
1536 entryPtr
->selectFirst
= -1;
1537 entryPtr
->selectLast
= -1;
1538 EventuallyRedraw(entryPtr
);
1543 *----------------------------------------------------------------------
1545 * EventuallyRedraw --
1547 * Ensure that an entry is eventually redrawn on the display.
1553 * Information gets redisplayed. Right now we don't do selective
1554 * redisplays: the whole window will be redrawn. This doesn't
1555 * seem to hurt performance noticeably, but if it does then this
1558 *----------------------------------------------------------------------
1562 EventuallyRedraw(entryPtr
)
1563 register Entry
*entryPtr
; /* Information about widget. */
1565 if ((entryPtr
->tkwin
== NULL
) || !Tk_IsMapped(entryPtr
->tkwin
)) {
1570 * Right now we don't do selective redisplays: the whole window
1571 * will be redrawn. This doesn't seem to hurt performance noticeably,
1572 * but if it does then this could be changed.
1575 if (!(entryPtr
->flags
& REDRAW_PENDING
)) {
1576 entryPtr
->flags
|= REDRAW_PENDING
;
1577 Tk_DoWhenIdle(DisplayEntry
, (ClientData
) entryPtr
);
1582 *----------------------------------------------------------------------
1584 * EntryUpdateScrollbar --
1586 * This procedure is invoked whenever information has changed in
1587 * an entry in a way that would invalidate a scrollbar display.
1588 * If there is an associated scrollbar, then this command updates
1589 * it by invoking a Tcl command.
1595 * A Tcl command is invoked, and an additional command may be
1596 * invoked to process errors in the command.
1598 *----------------------------------------------------------------------
1602 EntryUpdateScrollbar(entryPtr
)
1603 register Entry
*entryPtr
; /* Information about widget. */
1606 int result
, last
, charsInWindow
, endX
;
1608 if (entryPtr
->scrollCmd
== NULL
) {
1613 * The most painful part here is guessing how many characters
1614 * actually fit in the window. This is only an estimate in the
1615 * case where the window isn't completely filled with characters.
1618 charsInWindow
= TkMeasureChars(entryPtr
->fontPtr
,
1619 entryPtr
->string
+ entryPtr
->leftIndex
,
1620 entryPtr
->numChars
- entryPtr
->leftIndex
, entryPtr
->offset
,
1621 Tk_Width(entryPtr
->tkwin
),
1622 TK_AT_LEAST_ONE
|TK_NEWLINES_NOT_SPECIAL
, &endX
);
1623 if (charsInWindow
== 0) {
1624 last
= entryPtr
->leftIndex
;
1626 last
= entryPtr
->leftIndex
+ charsInWindow
- 1;
1628 if (endX
< Tk_Width(entryPtr
->tkwin
)) {
1629 charsInWindow
+= (Tk_Width(entryPtr
->tkwin
) - endX
)/entryPtr
->avgWidth
;
1631 sprintf(args
, " %d %d %d %d", entryPtr
->numChars
, charsInWindow
,
1632 entryPtr
->leftIndex
, last
);
1633 result
= Tcl_VarEval(entryPtr
->interp
, entryPtr
->scrollCmd
, args
,
1635 if (result
!= TCL_OK
) {
1636 TkBindError(entryPtr
->interp
);
1638 Tcl_SetResult(entryPtr
->interp
, (char *) NULL
, TCL_STATIC
);
1642 *----------------------------------------------------------------------
1646 * This procedure is called as a timer handler to blink the
1647 * insertion cursor off and on.
1653 * The cursor gets turned on or off, redisplay gets invoked,
1654 * and this procedure reschedules itself.
1656 *----------------------------------------------------------------------
1660 EntryBlinkProc(clientData
)
1661 ClientData clientData
; /* Pointer to record describing entry. */
1663 register Entry
*entryPtr
= (Entry
*) clientData
;
1665 if (!(entryPtr
->flags
& GOT_FOCUS
) || (entryPtr
->cursorOffTime
== 0)) {
1668 if (entryPtr
->flags
& CURSOR_ON
) {
1669 entryPtr
->flags
&= ~CURSOR_ON
;
1670 entryPtr
->cursorBlinkHandler
= Tk_CreateTimerHandler(
1671 entryPtr
->cursorOffTime
, EntryBlinkProc
, (ClientData
) entryPtr
);
1673 entryPtr
->flags
|= CURSOR_ON
;
1674 entryPtr
->cursorBlinkHandler
= Tk_CreateTimerHandler(
1675 entryPtr
->cursorOnTime
, EntryBlinkProc
, (ClientData
) entryPtr
);
1677 EventuallyRedraw(entryPtr
);
1681 *----------------------------------------------------------------------
1685 * This procedure is called whenever the entry gets or loses the
1686 * input focus. It's also called whenever the window is reconfigured
1687 * while it has the focus.
1693 * The cursor gets turned on or off.
1695 *----------------------------------------------------------------------
1699 EntryFocusProc(clientData
, gotFocus
)
1700 ClientData clientData
; /* Pointer to structure describing entry. */
1701 int gotFocus
; /* 1 means window is getting focus, 0 means
1702 * it's losing it. */
1704 register Entry
*entryPtr
= (Entry
*) clientData
;
1706 if (entryPtr
->cursorBlinkHandler
!= NULL
) {
1707 Tk_DeleteTimerHandler(entryPtr
->cursorBlinkHandler
);
1708 entryPtr
->cursorBlinkHandler
= NULL
;
1711 entryPtr
->flags
|= GOT_FOCUS
| CURSOR_ON
;
1712 if (entryPtr
->cursorOffTime
!= 0) {
1713 entryPtr
->cursorBlinkHandler
= Tk_CreateTimerHandler(
1714 entryPtr
->cursorOnTime
, EntryBlinkProc
,
1715 (ClientData
) entryPtr
);
1718 entryPtr
->flags
&= ~(GOT_FOCUS
| CURSOR_ON
);
1719 entryPtr
->cursorBlinkHandler
= (Tk_TimerToken
) NULL
;
1721 EventuallyRedraw(entryPtr
);
1725 *--------------------------------------------------------------
1727 * EntryTextVarProc --
1729 * This procedure is invoked when someone changes the variable
1730 * whose contents are to be displayed in an entry.
1733 * NULL is always returned.
1736 * The text displayed in the entry will change to match the
1739 *--------------------------------------------------------------
1744 EntryTextVarProc(clientData
, interp
, name1
, name2
, flags
)
1745 ClientData clientData
; /* Information about button. */
1746 Tcl_Interp
*interp
; /* Interpreter containing variable. */
1747 char *name1
; /* Name of variable. */
1748 char *name2
; /* Second part of variable name. */
1749 int flags
; /* Information about what happened. */
1751 register Entry
*entryPtr
= (Entry
*) clientData
;
1755 * If the variable is unset, then immediately recreate it unless
1756 * the whole interpreter is going away.
1759 if (flags
& TCL_TRACE_UNSETS
) {
1760 if ((flags
& TCL_TRACE_DESTROYED
) && !(flags
& TCL_INTERP_DESTROYED
)) {
1761 Tcl_SetVar2(interp
, name1
, name2
, entryPtr
->string
,
1762 flags
& TCL_GLOBAL_ONLY
);
1763 Tcl_TraceVar2(interp
, name1
, name2
,
1764 TCL_GLOBAL_ONLY
|TCL_TRACE_WRITES
|TCL_TRACE_UNSETS
,
1765 EntryTextVarProc
, clientData
);
1767 return (char *) NULL
;
1771 * Update the entry's text with the value of the variable, unless
1772 * the entry already has that value (this happens when the variable
1773 * changes value because we changed it because someone typed in
1777 value
= Tcl_GetVar2(interp
, name1
, name2
, flags
& TCL_GLOBAL_ONLY
);
1778 if (value
== NULL
) {
1781 if (strcmp(value
, entryPtr
->string
) != 0) {
1782 EntrySetValue(entryPtr
, value
);
1784 return (char *) NULL
;