Annotation of micropolis/src/tk/tkentry.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * tkEntry.c --
        !             3:  *
        !             4:  *     This module implements entry widgets for the Tk
        !             5:  *     toolkit.  An entry displays a string and allows
        !             6:  *     the string to be edited.
        !             7:  *
        !             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.
        !            16:  */
        !            17: 
        !            18: #ifndef lint
        !            19: static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkEntry.c,v 1.37 92/08/21 16:09:15 ouster Exp $ SPRITE (Berkeley)";
        !            20: #endif
        !            21: 
        !            22: #include "default.h"
        !            23: #include "tkconfig.h"
        !            24: #include "tkint.h"
        !            25: 
        !            26: /*
        !            27:  * A data structure of the following type is kept for each entry
        !            28:  * widget managed by this file:
        !            29:  */
        !            30: 
        !            31: typedef struct {
        !            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
        !            35:                                 * cleaned up.*/
        !            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
        !            45:                                 * when disabled. */
        !            46: 
        !            47:     /*
        !            48:      * Information used when displaying widget:
        !            49:      */
        !            50: 
        !            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
        !            59:                                 * characters. */
        !            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
        !            64:                                 * cursor. */
        !            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
        !            73:                                 * off. */
        !            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
        !            80:                                 * window. */
        !            81:     int cursorPos;             /* Index of character before which next
        !            82:                                 * typed character will be inserted. */
        !            83: 
        !            84:     /*
        !            85:      * Information about what's selected, if any.
        !            86:      */
        !            87: 
        !            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
        !            94:                                 * selection). */
        !            95:     int exportSelection;       /* Non-zero means tie internal entry selection
        !            96:                                 * to X selection. */
        !            97: 
        !            98:     /*
        !            99:      * Information for scanning:
        !           100:      */
        !           101: 
        !           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. */
        !           106: 
        !           107:     /*
        !           108:      * Miscellaneous information:
        !           109:      */
        !           110: 
        !           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
        !           116:                                 * definitions. */
        !           117: } Entry;
        !           118: 
        !           119: /*
        !           120:  * Assigned bits of "flags" fields of Entry structures, and what those
        !           121:  * bits mean:
        !           122:  *
        !           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
        !           131:  *                             focus.
        !           132:  */
        !           133: 
        !           134: #define REDRAW_PENDING         1
        !           135: #define BORDER_NEEDED          2
        !           136: #define CURSOR_ON              4
        !           137: #define GOT_FOCUS              8
        !           138: 
        !           139: /*
        !           140:  * Information used for argv parsing.
        !           141:  */
        !           142: 
        !           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),
        !           207:        TK_CONFIG_NULL_OK},
        !           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,
        !           211:        (char *) NULL, 0, 0}
        !           212: };
        !           213: 
        !           214: /*
        !           215:  * Flags for GetEntryIndex procedure:
        !           216:  */
        !           217: 
        !           218: #define ZERO_OK                        1
        !           219: #define LAST_PLUS_ONE_OK       2
        !           220: 
        !           221: /*
        !           222:  * Forward declarations for procedures defined later in this file:
        !           223:  */
        !           224: 
        !           225: static int             ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
        !           226:                            Entry *entryPtr, int argc, char **argv,
        !           227:                            int flags));
        !           228: static void            DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
        !           229:                            int count));
        !           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,
        !           235:                            char *string));
        !           236: static void            EntryBlinkProc _ANSI_ARGS_((ClientData clientData));
        !           237: static void            EntryEventProc _ANSI_ARGS_((ClientData clientData,
        !           238:                            XEvent *eventPtr));
        !           239: static void            EntryFocusProc _ANSI_ARGS_ ((ClientData clientData,
        !           240:                            int gotFocus));
        !           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,
        !           248:                            char *value));
        !           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,
        !           253:                            int flags));
        !           254: static void            EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
        !           255: static int             EntryWidgetCmd _ANSI_ARGS_((ClientData clientData,
        !           256:                            Tcl_Interp *interp, int argc, char **argv));
        !           257: 
        !           258: /*
        !           259:  *--------------------------------------------------------------
        !           260:  *
        !           261:  * Tk_EntryCmd --
        !           262:  *
        !           263:  *     This procedure is invoked to process the "entry" Tcl
        !           264:  *     command.  See the user documentation for details on what
        !           265:  *     it does.
        !           266:  *
        !           267:  * Results:
        !           268:  *     A standard Tcl result.
        !           269:  *
        !           270:  * Side effects:
        !           271:  *     See the user documentation.
        !           272:  *
        !           273:  *--------------------------------------------------------------
        !           274:  */
        !           275: 
        !           276: int
        !           277: Tk_EntryCmd(clientData, interp, argc, argv)
        !           278:     ClientData clientData;     /* Main window associated with
        !           279:                                 * interpreter. */
        !           280:     Tcl_Interp *interp;                /* Current interpreter. */
        !           281:     int argc;                  /* Number of arguments. */
        !           282:     char **argv;               /* Argument strings. */
        !           283: {
        !           284:     Tk_Window tkwin = (Tk_Window) clientData;
        !           285:     register Entry *entryPtr;
        !           286:     Tk_Window new;
        !           287: 
        !           288:     if (argc < 2) {
        !           289:        Tcl_AppendResult(interp, "wrong # args:  should be \"",
        !           290:                argv[0], " pathName ?options?\"", (char *) NULL);
        !           291:        return TCL_ERROR;
        !           292:     }
        !           293: 
        !           294:     new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
        !           295:     if (new == NULL) {
        !           296:        return TCL_ERROR;
        !           297:     }
        !           298: 
        !           299:     /*
        !           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).
        !           303:      */
        !           304: 
        !           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;
        !           331:     entryPtr->flags = 0;
        !           332: 
        !           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) {
        !           341:        goto error;
        !           342:     }
        !           343:     Tk_CreateFocusHandler(entryPtr->tkwin, EntryFocusProc,
        !           344:            (ClientData) entryPtr);
        !           345: 
        !           346:     interp->result = Tk_PathName(entryPtr->tkwin);
        !           347:     return TCL_OK;
        !           348: 
        !           349:     error:
        !           350:     Tk_DestroyWindow(entryPtr->tkwin);
        !           351:     return TCL_ERROR;
        !           352: }
        !           353: 
        !           354: /*
        !           355:  *--------------------------------------------------------------
        !           356:  *
        !           357:  * EntryWidgetCmd --
        !           358:  *
        !           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.
        !           362:  *
        !           363:  * Results:
        !           364:  *     A standard Tcl result.
        !           365:  *
        !           366:  * Side effects:
        !           367:  *     See the user documentation.
        !           368:  *
        !           369:  *--------------------------------------------------------------
        !           370:  */
        !           371: 
        !           372: static int
        !           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. */
        !           378: {
        !           379:     register Entry *entryPtr = (Entry *) clientData;
        !           380:     int result = TCL_OK;
        !           381:     int length;
        !           382:     char c;
        !           383: 
        !           384:     if (argc < 2) {
        !           385:        Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           386:                argv[0], " option ?arg arg ...?\"", (char *) NULL);
        !           387:        return TCL_ERROR;
        !           388:     }
        !           389:     Tk_Preserve((ClientData) entryPtr);
        !           390:     c = argv[1][0];
        !           391:     length = strlen(argv[1]);
        !           392:     if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
        !           393:            && (length >= 2)) {
        !           394:        if (argc == 2) {
        !           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);
        !           400:        } else {
        !           401:            result = ConfigureEntry(interp, entryPtr, argc-2, argv+2,
        !           402:                    TK_CONFIG_ARGV_ONLY);
        !           403:        }
        !           404:     } else if ((c == 'c') && (strncmp(argv[1], "cursor", length) == 0)
        !           405:            && (length >= 2)) {
        !           406:        if (argc != 3) {
        !           407:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           408:                    argv[0], " cursor pos\"",
        !           409:                    (char *) NULL);
        !           410:            goto error;
        !           411:        }
        !           412:        if (GetEntryIndex(interp, entryPtr, argv[2], &entryPtr->cursorPos)
        !           413:                != TCL_OK) {
        !           414:            goto error;
        !           415:        }
        !           416:        EventuallyRedraw(entryPtr);
        !           417:     } else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
        !           418:        int first, last;
        !           419: 
        !           420:        if ((argc < 3) || (argc > 4)) {
        !           421:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           422:                    argv[0], " delete firstIndex ?lastIndex?\"",
        !           423:                    (char *) NULL);
        !           424:            goto error;
        !           425:        }
        !           426:        if (GetEntryIndex(interp, entryPtr, argv[2], &first) != TCL_OK) {
        !           427:            goto error;
        !           428:        }
        !           429:        if (argc == 3) {
        !           430:            last = first;
        !           431:        } else {
        !           432:            if (GetEntryIndex(interp, entryPtr, argv[3], &last) != TCL_OK) {
        !           433:                goto error;
        !           434:            }
        !           435:        }
        !           436:        if ((last >= first) && (entryPtr->state == tkNormalUid)) {
        !           437:            DeleteChars(entryPtr, first, last+1-first);
        !           438:        }
        !           439:     } else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
        !           440:        if (argc != 2) {
        !           441:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           442:                    argv[0], " get\"", (char *) NULL);
        !           443:            goto error;
        !           444:        }
        !           445:        interp->result = entryPtr->string;
        !           446:     } else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
        !           447:            && (length >= 2)) {
        !           448:        int index;
        !           449: 
        !           450:        if (argc != 3) {
        !           451:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           452:                    argv[0], " index string\"", (char *) NULL);
        !           453:            goto error;
        !           454:        }
        !           455:        if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
        !           456:            goto error;
        !           457:        }
        !           458:        sprintf(interp->result, "%d", index);
        !           459:     } else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
        !           460:            && (length >= 2)) {
        !           461:        int index;
        !           462: 
        !           463:        if (argc != 4) {
        !           464:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           465:                    argv[0], " insert index text\"",
        !           466:                    (char *) NULL);
        !           467:            goto error;
        !           468:        }
        !           469:        if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
        !           470:            goto error;
        !           471:        }
        !           472:        if (entryPtr->state == tkNormalUid) {
        !           473:            InsertChars(entryPtr, index, argv[3]);
        !           474:        }
        !           475:     } else if ((c == 's') && (length >= 2)
        !           476:            && (strncmp(argv[1], "scan", length) == 0)) {
        !           477:        int x;
        !           478: 
        !           479:        if (argc != 4) {
        !           480:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           481:                    argv[0], " scan mark|dragto x\"", (char *) NULL);
        !           482:            goto error;
        !           483:        }
        !           484:        if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) {
        !           485:            goto error;
        !           486:        }
        !           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);
        !           494:        } else {
        !           495:            Tcl_AppendResult(interp, "bad scan option \"", argv[2],
        !           496:                    "\":  must be mark or dragto", (char *) NULL);
        !           497:            goto error;
        !           498:        }
        !           499:     } else if ((c == 's') && (length >= 2)
        !           500:            && (strncmp(argv[1], "select", length) == 0)) {
        !           501:        int index;
        !           502: 
        !           503:        if (argc < 3) {
        !           504:            Tcl_AppendResult(interp, "too few args: should be \"",
        !           505:                    argv[0], " select option ?index?\"", (char *) NULL);
        !           506:            goto error;
        !           507:        }
        !           508:        length = strlen(argv[2]);
        !           509:        c = argv[2][0];
        !           510:        if ((c == 'c') && (argv[2] != NULL)
        !           511:                && (strncmp(argv[2], "clear", length) == 0)) {
        !           512:            if (argc != 3) {
        !           513:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           514:                        argv[0], " select clear\"", (char *) NULL);
        !           515:                goto error;
        !           516:            }
        !           517:            if (entryPtr->selectFirst != -1) {
        !           518:                entryPtr->selectFirst = entryPtr->selectLast = -1;
        !           519:                EventuallyRedraw(entryPtr);
        !           520:            }
        !           521:            goto done;
        !           522:        }
        !           523:        if (argc >= 4) {
        !           524:            if (GetEntryIndex(interp, entryPtr, argv[3], &index) != TCL_OK) {
        !           525:                goto error;
        !           526:            }
        !           527:        }
        !           528:        if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
        !           529:            if (argc != 4) {
        !           530:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           531:                        argv[0], " select adjust index\"",
        !           532:                        (char *) NULL);
        !           533:                goto error;
        !           534:            }
        !           535:            if (entryPtr->selectFirst >= 0) {
        !           536:                if (index < (entryPtr->selectFirst + entryPtr->selectLast)/2) {
        !           537:                    entryPtr->selectAnchor = entryPtr->selectLast + 1;
        !           538:                } else {
        !           539:                    entryPtr->selectAnchor = entryPtr->selectFirst;
        !           540:                }
        !           541:            }
        !           542:            EntrySelectTo(entryPtr, index);
        !           543:        } else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
        !           544:            if (argc != 4) {
        !           545:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           546:                        argv[0], " select from index\"",
        !           547:                        (char *) NULL);
        !           548:                goto error;
        !           549:            }
        !           550:            entryPtr->selectAnchor = index;
        !           551:        } else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
        !           552:            if (argc != 4) {
        !           553:                Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           554:                        argv[0], " select to index\"",
        !           555:                        (char *) NULL);
        !           556:                goto error;
        !           557:            }
        !           558:            EntrySelectTo(entryPtr, index);
        !           559:        } else {
        !           560:            Tcl_AppendResult(interp, "bad select option \"", argv[2],
        !           561:                    "\": must be adjust, clear, from, or to", (char *) NULL);
        !           562:            goto error;
        !           563:        }
        !           564:     } else if ((c == 'v') && (strncmp(argv[1], "view", length) == 0)) {
        !           565:        int index;
        !           566: 
        !           567:        if (argc != 3) {
        !           568:            Tcl_AppendResult(interp, "wrong # args: should be \"",
        !           569:                    argv[0], " view index\"", (char *) NULL);
        !           570:            goto error;
        !           571:        }
        !           572:        if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
        !           573:            goto error;
        !           574:        }
        !           575:        if ((index >= entryPtr->numChars) && (index > 0)) {
        !           576:            index = entryPtr->numChars-1;
        !           577:        }
        !           578:        entryPtr->leftIndex = index;
        !           579:        EventuallyRedraw(entryPtr);
        !           580:        EntryUpdateScrollbar(entryPtr);
        !           581:     } else {
        !           582:        Tcl_AppendResult(interp, "bad option \"", argv[1],
        !           583:                "\": must be configure, cursor, delete, get, index, ",
        !           584:                "insert, scan, select, or view", (char *) NULL);
        !           585:        goto error;
        !           586:     }
        !           587:     done:
        !           588:     Tk_Release((ClientData) entryPtr);
        !           589:     return result;
        !           590: 
        !           591:     error:
        !           592:     Tk_Release((ClientData) entryPtr);
        !           593:     return TCL_ERROR;
        !           594: }
        !           595: 
        !           596: /*
        !           597:  *----------------------------------------------------------------------
        !           598:  *
        !           599:  * DestroyEntry --
        !           600:  *
        !           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).
        !           604:  *
        !           605:  * Results:
        !           606:  *     None.
        !           607:  *
        !           608:  * Side effects:
        !           609:  *     Everything associated with the entry is freed up.
        !           610:  *
        !           611:  *----------------------------------------------------------------------
        !           612:  */
        !           613: 
        !           614: static void
        !           615: DestroyEntry(clientData)
        !           616:     ClientData clientData;                     /* Info about entry widget. */
        !           617: {
        !           618:     register Entry *entryPtr = (Entry *) clientData;
        !           619: 
        !           620:     ckfree(entryPtr->string);
        !           621:     if (entryPtr->normalBorder != NULL) {
        !           622:        Tk_Free3DBorder(entryPtr->normalBorder);
        !           623:     }
        !           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);
        !           629:     }
        !           630:     if (entryPtr->fontPtr != NULL) {
        !           631:        Tk_FreeFontStruct(entryPtr->fontPtr);
        !           632:     }
        !           633:     if (entryPtr->fgColorPtr != NULL) {
        !           634:        Tk_FreeColor(entryPtr->fgColorPtr);
        !           635:     }
        !           636:     if (entryPtr->textGC != None) {
        !           637:        Tk_FreeGC(entryPtr->textGC);
        !           638:     }
        !           639:     if (entryPtr->selBorder != NULL) {
        !           640:        Tk_Free3DBorder(entryPtr->selBorder);
        !           641:     }
        !           642:     if (entryPtr->selFgColorPtr != NULL) {
        !           643:        Tk_FreeColor(entryPtr->selFgColorPtr);
        !           644:     }
        !           645:     if (entryPtr->selTextGC != None) {
        !           646:        Tk_FreeGC(entryPtr->selTextGC);
        !           647:     }
        !           648:     if (entryPtr->cursorBorder != NULL) {
        !           649:        Tk_Free3DBorder(entryPtr->cursorBorder);
        !           650:     }
        !           651:     if (entryPtr->cursorBlinkHandler != NULL) {
        !           652:         Tk_DeleteTimerHandler(entryPtr->cursorBlinkHandler);
        !           653:        entryPtr->cursorBlinkHandler = NULL;
        !           654:     }
        !           655:     if (entryPtr->cursor != None) {
        !           656:        Tk_FreeCursor(entryPtr->cursor);
        !           657:     }
        !           658:     if (entryPtr->scrollCmd != NULL) {
        !           659:         ckfree(entryPtr->scrollCmd);
        !           660:     }
        !           661:     ckfree((char *) entryPtr);
        !           662: }
        !           663: 
        !           664: /*
        !           665:  *----------------------------------------------------------------------
        !           666:  *
        !           667:  * ConfigureEntry --
        !           668:  *
        !           669:  *     This procedure is called to process an argv/argc list, plus
        !           670:  *     the Tk option database, in order to configure (or reconfigure)
        !           671:  *     an entry widget.
        !           672:  *
        !           673:  * Results:
        !           674:  *     The return value is a standard Tcl result.  If TCL_ERROR is
        !           675:  *     returned, then interp->result contains an error message.
        !           676:  *
        !           677:  * Side effects:
        !           678:  *     Configuration information, such as colors, border width,
        !           679:  *     etc. get set for entryPtr;  old resources get freed,
        !           680:  *     if there were any.
        !           681:  *
        !           682:  *----------------------------------------------------------------------
        !           683:  */
        !           684: 
        !           685: static int
        !           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. */
        !           693: {
        !           694:     XGCValues gcValues;
        !           695:     GC new;
        !           696:     int width, height, fontHeight, oldExport;
        !           697: 
        !           698:     /*
        !           699:      * Eliminate any existing trace on a variable monitored by the entry.
        !           700:      */
        !           701: 
        !           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);
        !           706:     }
        !           707: 
        !           708:     oldExport = entryPtr->exportSelection;
        !           709:     if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs,
        !           710:            argc, argv, (char *) entryPtr, flags) != TCL_OK) {
        !           711:        return TCL_ERROR;
        !           712:     }
        !           713: 
        !           714:     /*
        !           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.
        !           718:      */
        !           719: 
        !           720:     if (entryPtr->textVarName != NULL) {
        !           721:        char *value;
        !           722: 
        !           723:        value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
        !           724:        if (value == NULL) {
        !           725:            Tcl_SetVar(interp, entryPtr->textVarName, entryPtr->string,
        !           726:                    TCL_GLOBAL_ONLY);
        !           727:        } else {
        !           728:            EntrySetValue(entryPtr, value);
        !           729:        }
        !           730:        Tcl_TraceVar(interp, entryPtr->textVarName,
        !           731:                TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
        !           732:                EntryTextVarProc, (ClientData) entryPtr);
        !           733:     }
        !           734: 
        !           735:     /*
        !           736:      * A few other options also need special processing, such as parsing
        !           737:      * the geometry and setting the background from a 3-D border.
        !           738:      */
        !           739: 
        !           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;
        !           745:        return TCL_ERROR;
        !           746:     }
        !           747: 
        !           748:     Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder);
        !           749: 
        !           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,
        !           754:            &gcValues);
        !           755:     if (entryPtr->textGC != None) {
        !           756:        Tk_FreeGC(entryPtr->textGC);
        !           757:     }
        !           758:     entryPtr->textGC = new;
        !           759: 
        !           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);
        !           765:     }
        !           766:     entryPtr->selTextGC = new;
        !           767: 
        !           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;
        !           772:        }
        !           773:     }
        !           774:     if (entryPtr->cursorBorderWidth > entryPtr->cursorWidth/2) {
        !           775:        entryPtr->cursorBorderWidth = entryPtr->cursorWidth/2;
        !           776:     }
        !           777: 
        !           778:     /*
        !           779:      * Restart the cursor timing sequence in case the on-time or off-time
        !           780:      * just changed.
        !           781:      */
        !           782: 
        !           783:     if (entryPtr->flags & GOT_FOCUS) {
        !           784:        EntryFocusProc((ClientData) entryPtr, 1);
        !           785:     }
        !           786: 
        !           787:     /*
        !           788:      * Claim the selection if we've suddenly started exporting it.
        !           789:      */
        !           790: 
        !           791:     if (entryPtr->exportSelection && (!oldExport)
        !           792:            && (entryPtr->selectFirst != -1)) {
        !           793:        Tk_OwnSelection(entryPtr->tkwin, EntryLostSelection,
        !           794:                (ClientData) entryPtr);
        !           795:     }
        !           796: 
        !           797:     /*
        !           798:      * Register the desired geometry for the window, and arrange for
        !           799:      * the window to be redisplayed.
        !           800:      */
        !           801: 
        !           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;
        !           810:     } else {
        !           811:        entryPtr->offset = 0;
        !           812:     }
        !           813:     EventuallyRedraw(entryPtr);
        !           814:     EntryUpdateScrollbar(entryPtr);
        !           815:     return TCL_OK;
        !           816: }
        !           817: 
        !           818: /*
        !           819:  *--------------------------------------------------------------
        !           820:  *
        !           821:  * DisplayEntry --
        !           822:  *
        !           823:  *     This procedure redraws the contents of an entry window.
        !           824:  *
        !           825:  * Results:
        !           826:  *     None.
        !           827:  *
        !           828:  * Side effects:
        !           829:  *     Information appears on the screen.
        !           830:  *
        !           831:  *--------------------------------------------------------------
        !           832:  */
        !           833: 
        !           834: static void
        !           835: DisplayEntry(clientData)
        !           836:     ClientData clientData;     /* Information about window. */
        !           837: {
        !           838:     register Entry *entryPtr = (Entry *) clientData;
        !           839:     register Tk_Window tkwin = entryPtr->tkwin;
        !           840:     int startX, baseY, selStartX, selEndX, index, cursorX;
        !           841:     int xBound, count;
        !           842:     Pixmap pixmap;
        !           843: 
        !           844:     entryPtr->flags &= ~REDRAW_PENDING;
        !           845:     if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
        !           846:        return;
        !           847:     }
        !           848: 
        !           849:     /*
        !           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.
        !           854:      */
        !           855: 
        !           856:     pixmap = XCreatePixmap(Tk_Display(tkwin), Tk_WindowId(tkwin),
        !           857:            Tk_Width(tkwin), Tk_Height(tkwin),
        !           858:            Tk_DefaultDepth(Tk_Screen(tkwin)));
        !           859: 
        !           860:     /*
        !           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.
        !           864:      */
        !           865: 
        !           866:     startX = entryPtr->offset;
        !           867:     xBound = Tk_Width(tkwin) - entryPtr->offset;
        !           868:     baseY = (Tk_Height(tkwin) + entryPtr->fontPtr->ascent
        !           869:            - entryPtr->fontPtr->descent)/2;
        !           870: 
        !           871:     /*
        !           872:      * Draw the background in three layers.  From bottom to top the
        !           873:      * layers are:  normal background, selection background, and
        !           874:      * insertion cursor background.
        !           875:      */
        !           876: 
        !           877:     Tk_Fill3DRectangle(Tk_Display(tkwin), pixmap, entryPtr->normalBorder,
        !           878:            0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
        !           879: 
        !           880:     if (entryPtr->selectLast >= entryPtr->leftIndex) {
        !           881:        if (entryPtr->selectFirst <= entryPtr->leftIndex) {
        !           882:            selStartX = startX;
        !           883:            index = entryPtr->leftIndex;
        !           884:        } else {
        !           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;
        !           890:        }
        !           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,
        !           895:                    &selEndX);
        !           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);
        !           904:        } else {
        !           905:            selEndX = xBound;
        !           906:        }
        !           907:     }
        !           908: 
        !           909:     /*
        !           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.
        !           915:      */
        !           916: 
        !           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,
        !           940:                        0, TK_RELIEF_FLAT);
        !           941:            }
        !           942:        }
        !           943:     }
        !           944: 
        !           945:     /*
        !           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
        !           948:      * of the selection.
        !           949:      */
        !           950: 
        !           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);
        !           956:     } else {
        !           957:        count = entryPtr->selectFirst - entryPtr->leftIndex;
        !           958:        if (count > 0) {
        !           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;
        !           963:        } else {
        !           964:            index = entryPtr->leftIndex;
        !           965:        }
        !           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);
        !           971:        }
        !           972:        count = entryPtr->numChars - entryPtr->selectLast - 1;
        !           973:        if ((selEndX < xBound) && (count > 0)) {
        !           974:            TkDisplayChars(Tk_Display(tkwin), pixmap, entryPtr->textGC,
        !           975:                    entryPtr->fontPtr,
        !           976:                    entryPtr->string + entryPtr->selectLast + 1,
        !           977:                    count, selEndX, baseY, TK_NEWLINES_NOT_SPECIAL);
        !           978:        }
        !           979:     }
        !           980: 
        !           981:     /*
        !           982:      * Draw the border last, so it will overwrite any text that extends
        !           983:      * past the viewable part of the window.
        !           984:      */
        !           985: 
        !           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,
        !           990:                entryPtr->relief);
        !           991:     }
        !           992: 
        !           993:     /*
        !           994:      * Everything's been redisplayed;  now copy the pixmap onto the screen
        !           995:      * and free up the pixmap.
        !           996:      */
        !           997: 
        !           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;
        !          1002: }
        !          1003: 
        !          1004: /*
        !          1005:  *----------------------------------------------------------------------
        !          1006:  *
        !          1007:  * InsertChars --
        !          1008:  *
        !          1009:  *     Add new characters to an entry widget.
        !          1010:  *
        !          1011:  * Results:
        !          1012:  *     None.
        !          1013:  *
        !          1014:  * Side effects:
        !          1015:  *     New information gets added to entryPtr;  it will be redisplayed
        !          1016:  *     soon, but not necessarily immediately.
        !          1017:  *
        !          1018:  *----------------------------------------------------------------------
        !          1019:  */
        !          1020: 
        !          1021: static void
        !          1022: InsertChars(entryPtr, index, string)
        !          1023:     register Entry *entryPtr;  /* Entry that is to get the new
        !          1024:                                 * elements. */
        !          1025:     int index;                 /* Add the new elements before this
        !          1026:                                 * element. */
        !          1027:     char *string;              /* New characters to add (NULL-terminated
        !          1028:                                 * string). */
        !          1029: {
        !          1030:     int length;
        !          1031:     char *new;
        !          1032: 
        !          1033:     length = strlen(string);
        !          1034:     if (length == 0) {
        !          1035:        return;
        !          1036:     }
        !          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;
        !          1044: 
        !          1045:     /*
        !          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).
        !          1049:      */
        !          1050: 
        !          1051:     if (entryPtr->selectFirst >= index) {
        !          1052:        entryPtr->selectFirst += length;
        !          1053:     }
        !          1054:     if (entryPtr->selectLast >= index) {
        !          1055:        entryPtr->selectLast += length;
        !          1056:     }
        !          1057:     if (entryPtr->selectAnchor >= index) {
        !          1058:        entryPtr->selectAnchor += length;
        !          1059:     }
        !          1060:     if (entryPtr->leftIndex > index) {
        !          1061:        entryPtr->leftIndex += length;
        !          1062:     }
        !          1063:     if (entryPtr->cursorPos >= index) {
        !          1064:        entryPtr->cursorPos += length;
        !          1065:     }
        !          1066: 
        !          1067:     if (entryPtr->textVarName != NULL) {
        !          1068:        Tcl_SetVar(entryPtr->interp, entryPtr->textVarName, entryPtr->string,
        !          1069:                TCL_GLOBAL_ONLY);
        !          1070:     }
        !          1071:     EventuallyRedraw(entryPtr);
        !          1072:     EntryUpdateScrollbar(entryPtr);
        !          1073: }
        !          1074: 
        !          1075: /*
        !          1076:  *----------------------------------------------------------------------
        !          1077:  *
        !          1078:  * DeleteChars --
        !          1079:  *
        !          1080:  *     Remove one or more characters from an entry widget.
        !          1081:  *
        !          1082:  * Results:
        !          1083:  *     None.
        !          1084:  *
        !          1085:  * Side effects:
        !          1086:  *     Memory gets freed, the entry gets modified and (eventually)
        !          1087:  *     redisplayed.
        !          1088:  *
        !          1089:  *----------------------------------------------------------------------
        !          1090:  */
        !          1091: 
        !          1092: static void
        !          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. */
        !          1097: {
        !          1098:     char *new;
        !          1099: 
        !          1100:     if ((index + count) > entryPtr->numChars) {
        !          1101:        count = entryPtr->numChars - index;
        !          1102:     }
        !          1103:     if (count <= 0) {
        !          1104:        return;
        !          1105:     }
        !          1106: 
        !          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;
        !          1113: 
        !          1114:     /*
        !          1115:      * Deleting characters results in the remaining characters being
        !          1116:      * renumbered.  Update the various indexes into the string to reflect
        !          1117:      * this change.
        !          1118:      */
        !          1119:     if (entryPtr->selectFirst >= index) {
        !          1120:        if (entryPtr->selectFirst >= (index+count)) {
        !          1121:            entryPtr->selectFirst -= count;
        !          1122:        } else {
        !          1123:            entryPtr->selectFirst = index;
        !          1124:        }
        !          1125:     }
        !          1126:     if (entryPtr->selectLast >= index) {
        !          1127:        if (entryPtr->selectLast >= (index+count)) {
        !          1128:            entryPtr->selectLast -= count;
        !          1129:        } else {
        !          1130:            entryPtr->selectLast = index-1;
        !          1131:        }
        !          1132:     }
        !          1133:     if (entryPtr->selectLast < entryPtr->selectFirst) {
        !          1134:        entryPtr->selectFirst = entryPtr->selectLast = -1;
        !          1135:     }
        !          1136:     if (entryPtr->selectAnchor >= index) {
        !          1137:        if (entryPtr->selectAnchor >= (index+count)) {
        !          1138:            entryPtr->selectAnchor -= count;
        !          1139:        } else {
        !          1140:            entryPtr->selectAnchor = index;
        !          1141:        }
        !          1142:     }
        !          1143:     if (entryPtr->leftIndex > index) {
        !          1144:        if (entryPtr->leftIndex >= (index+count)) {
        !          1145:            entryPtr->leftIndex -= count;
        !          1146:        } else {
        !          1147:            entryPtr->leftIndex = index;
        !          1148:        }
        !          1149:     }
        !          1150:     if (entryPtr->cursorPos >= index) {
        !          1151:        if (entryPtr->cursorPos >= (index+count)) {
        !          1152:            entryPtr->cursorPos -= count;
        !          1153:        } else {
        !          1154:            entryPtr->cursorPos = index;
        !          1155:        }
        !          1156:     }
        !          1157: 
        !          1158:     if (entryPtr->textVarName != NULL) {
        !          1159:        Tcl_SetVar(entryPtr->interp, entryPtr->textVarName, entryPtr->string,
        !          1160:                TCL_GLOBAL_ONLY);
        !          1161:     }
        !          1162:     EventuallyRedraw(entryPtr);
        !          1163:     EntryUpdateScrollbar(entryPtr);
        !          1164: }
        !          1165: 
        !          1166: /*
        !          1167:  *----------------------------------------------------------------------
        !          1168:  *
        !          1169:  * EntrySetValue --
        !          1170:  *
        !          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.
        !          1174:  *
        !          1175:  * Results:
        !          1176:  *     None.
        !          1177:  *
        !          1178:  * Side effects:
        !          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
        !          1183:  *     infinite loop.
        !          1184:  *
        !          1185:  *----------------------------------------------------------------------
        !          1186:  */
        !          1187: 
        !          1188: static void
        !          1189: EntrySetValue(entryPtr, value)
        !          1190:     register Entry *entryPtr;          /* Entry whose value is to be
        !          1191:                                         * changed. */
        !          1192:     char *value;                       /* New text to display in entry. */
        !          1193: {
        !          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;
        !          1201: 
        !          1202:     EventuallyRedraw(entryPtr);
        !          1203:     EntryUpdateScrollbar(entryPtr);
        !          1204: }
        !          1205: 
        !          1206: /*
        !          1207:  *--------------------------------------------------------------
        !          1208:  *
        !          1209:  * EntryEventProc --
        !          1210:  *
        !          1211:  *     This procedure is invoked by the Tk dispatcher for various
        !          1212:  *     events on entryes.
        !          1213:  *
        !          1214:  * Results:
        !          1215:  *     None.
        !          1216:  *
        !          1217:  * Side effects:
        !          1218:  *     When the window gets deleted, internal structures get
        !          1219:  *     cleaned up.  When it gets exposed, it is redisplayed.
        !          1220:  *
        !          1221:  *--------------------------------------------------------------
        !          1222:  */
        !          1223: 
        !          1224: static void
        !          1225: EntryEventProc(clientData, eventPtr)
        !          1226:     ClientData clientData;     /* Information about window. */
        !          1227:     XEvent *eventPtr;          /* Information about event. */
        !          1228: {
        !          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);
        !          1238:        }
        !          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);
        !          1245:     }
        !          1246: }
        !          1247: 
        !          1248: /*
        !          1249:  *--------------------------------------------------------------
        !          1250:  *
        !          1251:  * GetEntryIndex --
        !          1252:  *
        !          1253:  *     Parse an index into an entry and return either its value
        !          1254:  *     or an error.
        !          1255:  *
        !          1256:  * Results:
        !          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.
        !          1262:  *
        !          1263:  * Side effects:
        !          1264:  *     None.
        !          1265:  *
        !          1266:  *--------------------------------------------------------------
        !          1267:  */
        !          1268: 
        !          1269: static int
        !          1270: GetEntryIndex(interp, entryPtr, string, indexPtr)
        !          1271:     Tcl_Interp *interp;                /* For error messages. */
        !          1272:     Entry *entryPtr;           /* Entry for which the index is being
        !          1273:                                 * specified. */
        !          1274:     char *string;              /* Specifies character in entryPtr. */
        !          1275:     int *indexPtr;             /* Where to store converted index. */
        !          1276: {
        !          1277:     int length;
        !          1278: 
        !          1279:     length = strlen(string);
        !          1280: 
        !          1281:     if (string[0] == 'e') {
        !          1282:        if (strncmp(string, "end", length) == 0) {
        !          1283:            *indexPtr = entryPtr->numChars;
        !          1284:        } else {
        !          1285:            badIndex:
        !          1286: 
        !          1287:            /*
        !          1288:             * Some of the paths here leave messages in interp->result,
        !          1289:             * so we have to clear it out before storing our own message.
        !          1290:             */
        !          1291: 
        !          1292:            Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
        !          1293:            Tcl_AppendResult(interp, "bad entry index \"", string,
        !          1294:                    "\"", (char *) NULL);
        !          1295:            return TCL_ERROR;
        !          1296:        }
        !          1297:     } else if (string[0] == 'c') {
        !          1298:        if (strncmp(string, "cursor", length) == 0) {
        !          1299:            *indexPtr = entryPtr->cursorPos;
        !          1300:        } else {
        !          1301:            goto badIndex;
        !          1302:        }
        !          1303:     } else if (string[0] == 's') {
        !          1304:        if (entryPtr->selectFirst == -1) {
        !          1305:            interp->result = "selection isn't in entry";
        !          1306:            return TCL_ERROR;
        !          1307:        }
        !          1308:        if (length < 5) {
        !          1309:            goto badIndex;
        !          1310:        }
        !          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;
        !          1315:        } else {
        !          1316:            goto badIndex;
        !          1317:        }
        !          1318:     } else if (string[0] == '@') {
        !          1319:        int x, dummy;
        !          1320: 
        !          1321:        if (Tcl_GetInt(interp, string+1, &x) != TCL_OK) {
        !          1322:            goto badIndex;
        !          1323:        }
        !          1324:        if (entryPtr->numChars == 0) {
        !          1325:            *indexPtr = 0;
        !          1326:        } else {
        !          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);
        !          1331:        }
        !          1332:     } else {
        !          1333:        if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
        !          1334:            goto badIndex;
        !          1335:        }
        !          1336:        if (*indexPtr < 0){
        !          1337:            *indexPtr = 0;
        !          1338:        } else if (*indexPtr > entryPtr->numChars) {
        !          1339:            *indexPtr = entryPtr->numChars;
        !          1340:        }
        !          1341:     }
        !          1342:     return TCL_OK;
        !          1343: }
        !          1344: 
        !          1345: /*
        !          1346:  *----------------------------------------------------------------------
        !          1347:  *
        !          1348:  * EntryScanTo --
        !          1349:  *
        !          1350:  *     Given a y-coordinate (presumably of the curent mouse location)
        !          1351:  *     drag the view in the window to implement the scan operation.
        !          1352:  *
        !          1353:  * Results:
        !          1354:  *     None.
        !          1355:  *
        !          1356:  * Side effects:
        !          1357:  *     The view in the window may change.
        !          1358:  *
        !          1359:  *----------------------------------------------------------------------
        !          1360:  */
        !          1361: 
        !          1362: static void
        !          1363: EntryScanTo(entryPtr, x)
        !          1364:     register Entry *entryPtr;          /* Information about widget. */
        !          1365:     int x;                             /* X-coordinate to use for scan
        !          1366:                                         * operation. */
        !          1367: {
        !          1368:     int newLeftIndex;
        !          1369: 
        !          1370:     /*
        !          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).
        !          1379:      */
        !          1380: 
        !          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;
        !          1386:     }
        !          1387:     if (newLeftIndex < 0) {
        !          1388:        newLeftIndex = entryPtr->scanMarkIndex = 0;
        !          1389:        entryPtr->scanMarkX = x;
        !          1390:     } 
        !          1391:     if (newLeftIndex != entryPtr->leftIndex) {
        !          1392:        entryPtr->leftIndex = newLeftIndex;
        !          1393:        EventuallyRedraw(entryPtr);
        !          1394:        EntryUpdateScrollbar(entryPtr);
        !          1395:     }
        !          1396: }
        !          1397: 
        !          1398: /*
        !          1399:  *----------------------------------------------------------------------
        !          1400:  *
        !          1401:  * EntrySelectTo --
        !          1402:  *
        !          1403:  *     Modify the selection by moving its un-anchored end.  This could
        !          1404:  *     make the selection either larger or smaller.
        !          1405:  *
        !          1406:  * Results:
        !          1407:  *     None.
        !          1408:  *
        !          1409:  * Side effects:
        !          1410:  *     The selection changes.
        !          1411:  *
        !          1412:  *----------------------------------------------------------------------
        !          1413:  */
        !          1414: 
        !          1415: static void
        !          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
        !          1420:                                         * selection. */
        !          1421: {
        !          1422:     int newFirst, newLast;
        !          1423: 
        !          1424:     /*
        !          1425:      * Grab the selection if we don't own it already.
        !          1426:      */
        !          1427: 
        !          1428:     if ((entryPtr->selectFirst == -1) && (entryPtr->exportSelection)) {
        !          1429:        Tk_OwnSelection(entryPtr->tkwin, EntryLostSelection,
        !          1430:                (ClientData) entryPtr);
        !          1431:     }
        !          1432: 
        !          1433:     if (index < 0) {
        !          1434:        index = 0;
        !          1435:     }
        !          1436:     if (index >= entryPtr->numChars) {
        !          1437:        index = entryPtr->numChars-1;
        !          1438:     }
        !          1439:     if (entryPtr->selectAnchor > entryPtr->numChars) {
        !          1440:        entryPtr->selectAnchor = entryPtr->numChars;
        !          1441:     }
        !          1442:     if (entryPtr->selectAnchor <= index) {
        !          1443:        newFirst = entryPtr->selectAnchor;
        !          1444:        newLast = index;
        !          1445:     } else {
        !          1446:        newFirst = index;
        !          1447:        newLast = entryPtr->selectAnchor - 1;
        !          1448:        if (newLast < 0) {
        !          1449:            newFirst = newLast = -1;
        !          1450:        }
        !          1451:     }
        !          1452:     if ((entryPtr->selectFirst == newFirst)
        !          1453:            && (entryPtr->selectLast == newLast)) {
        !          1454:        return;
        !          1455:     }
        !          1456:     entryPtr->selectFirst = newFirst;
        !          1457:     entryPtr->selectLast = newLast;
        !          1458:     EventuallyRedraw(entryPtr);
        !          1459: }
        !          1460: 
        !          1461: /*
        !          1462:  *----------------------------------------------------------------------
        !          1463:  *
        !          1464:  * EntryFetchSelection --
        !          1465:  *
        !          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.
        !          1469:  *
        !          1470:  * Results:
        !          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.
        !          1475:  *
        !          1476:  * Side effects:
        !          1477:  *     None.
        !          1478:  *
        !          1479:  *----------------------------------------------------------------------
        !          1480:  */
        !          1481: 
        !          1482: static int
        !          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
        !          1488:                                         * selection. */
        !          1489:     int maxBytes;                      /* Maximum number of bytes to place
        !          1490:                                         * at buffer, not including terminating
        !          1491:                                         * NULL character. */
        !          1492: {
        !          1493:     Entry *entryPtr = (Entry *) clientData;
        !          1494:     int count;
        !          1495: 
        !          1496:     if ((entryPtr->selectFirst < 0) || !(entryPtr->exportSelection)) {
        !          1497:        return -1;
        !          1498:     }
        !          1499:     count = entryPtr->selectLast + 1 - entryPtr->selectFirst - offset;
        !          1500:     if (count > maxBytes) {
        !          1501:        count = maxBytes;
        !          1502:     }
        !          1503:     if (count <= 0) {
        !          1504:        return 0;
        !          1505:     }
        !          1506:     strncpy(buffer, entryPtr->string + entryPtr->selectFirst + offset, count);
        !          1507:     buffer[count] = '\0';
        !          1508:     return count;
        !          1509: }
        !          1510: 
        !          1511: /*
        !          1512:  *----------------------------------------------------------------------
        !          1513:  *
        !          1514:  * EntryLostSelection --
        !          1515:  *
        !          1516:  *     This procedure is called back by Tk when the selection is
        !          1517:  *     grabbed away from an entry widget.
        !          1518:  *
        !          1519:  * Results:
        !          1520:  *     None.
        !          1521:  *
        !          1522:  * Side effects:
        !          1523:  *     The existing selection is unhighlighted, and the window is
        !          1524:  *     marked as not containing a selection.
        !          1525:  *
        !          1526:  *----------------------------------------------------------------------
        !          1527:  */
        !          1528: 
        !          1529: static void
        !          1530: EntryLostSelection(clientData)
        !          1531:     ClientData clientData;             /* Information about entry widget. */
        !          1532: {
        !          1533:     Entry *entryPtr = (Entry *) clientData;
        !          1534: 
        !          1535:     if ((entryPtr->selectFirst != -1) && entryPtr->exportSelection) {
        !          1536:        entryPtr->selectFirst = -1;
        !          1537:        entryPtr->selectLast = -1;
        !          1538:        EventuallyRedraw(entryPtr);
        !          1539:     }
        !          1540: }
        !          1541: 
        !          1542: /*
        !          1543:  *----------------------------------------------------------------------
        !          1544:  *
        !          1545:  * EventuallyRedraw --
        !          1546:  *
        !          1547:  *     Ensure that an entry is eventually redrawn on the display.
        !          1548:  *
        !          1549:  * Results:
        !          1550:  *     None.
        !          1551:  *
        !          1552:  * Side effects:
        !          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
        !          1556:  *     could be changed.
        !          1557:  *
        !          1558:  *----------------------------------------------------------------------
        !          1559:  */
        !          1560: 
        !          1561: static void
        !          1562: EventuallyRedraw(entryPtr)
        !          1563:     register Entry *entryPtr;          /* Information about widget. */
        !          1564: {
        !          1565:     if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) {
        !          1566:        return;
        !          1567:     }
        !          1568: 
        !          1569:     /*
        !          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.
        !          1573:      */
        !          1574: 
        !          1575:     if (!(entryPtr->flags & REDRAW_PENDING)) {
        !          1576:        entryPtr->flags |= REDRAW_PENDING;
        !          1577:        Tk_DoWhenIdle(DisplayEntry, (ClientData) entryPtr);
        !          1578:     }
        !          1579: }
        !          1580: 
        !          1581: /*
        !          1582:  *----------------------------------------------------------------------
        !          1583:  *
        !          1584:  * EntryUpdateScrollbar --
        !          1585:  *
        !          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.
        !          1590:  *
        !          1591:  * Results:
        !          1592:  *     None.
        !          1593:  *
        !          1594:  * Side effects:
        !          1595:  *     A Tcl command is invoked, and an additional command may be
        !          1596:  *     invoked to process errors in the command.
        !          1597:  *
        !          1598:  *----------------------------------------------------------------------
        !          1599:  */
        !          1600: 
        !          1601: static void
        !          1602: EntryUpdateScrollbar(entryPtr)
        !          1603:     register Entry *entryPtr;          /* Information about widget. */
        !          1604: {
        !          1605:     char args[100];
        !          1606:     int result, last, charsInWindow, endX;
        !          1607: 
        !          1608:     if (entryPtr->scrollCmd == NULL) {
        !          1609:        return;
        !          1610:     }
        !          1611: 
        !          1612:     /*
        !          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.
        !          1616:      */
        !          1617: 
        !          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;
        !          1625:     } else {
        !          1626:        last = entryPtr->leftIndex + charsInWindow - 1;
        !          1627:     }
        !          1628:     if (endX < Tk_Width(entryPtr->tkwin)) {
        !          1629:        charsInWindow += (Tk_Width(entryPtr->tkwin) - endX)/entryPtr->avgWidth;
        !          1630:     }
        !          1631:     sprintf(args, " %d %d %d %d", entryPtr->numChars, charsInWindow,
        !          1632:            entryPtr->leftIndex, last);
        !          1633:     result = Tcl_VarEval(entryPtr->interp, entryPtr->scrollCmd, args,
        !          1634:            (char *) NULL);
        !          1635:     if (result != TCL_OK) {
        !          1636:        TkBindError(entryPtr->interp);
        !          1637:     }
        !          1638:     Tcl_SetResult(entryPtr->interp, (char *) NULL, TCL_STATIC);
        !          1639: }
        !          1640: 
        !          1641: /*
        !          1642:  *----------------------------------------------------------------------
        !          1643:  *
        !          1644:  * EntryBlinkProc --
        !          1645:  *
        !          1646:  *     This procedure is called as a timer handler to blink the
        !          1647:  *     insertion cursor off and on.
        !          1648:  *
        !          1649:  * Results:
        !          1650:  *     None.
        !          1651:  *
        !          1652:  * Side effects:
        !          1653:  *     The cursor gets turned on or off, redisplay gets invoked,
        !          1654:  *     and this procedure reschedules itself.
        !          1655:  *
        !          1656:  *----------------------------------------------------------------------
        !          1657:  */
        !          1658: 
        !          1659: static void
        !          1660: EntryBlinkProc(clientData)
        !          1661:     ClientData clientData;     /* Pointer to record describing entry. */
        !          1662: {
        !          1663:     register Entry *entryPtr = (Entry *) clientData;
        !          1664: 
        !          1665:     if (!(entryPtr->flags & GOT_FOCUS) || (entryPtr->cursorOffTime == 0)) {
        !          1666:        return;
        !          1667:     }
        !          1668:     if (entryPtr->flags & CURSOR_ON) {
        !          1669:        entryPtr->flags &= ~CURSOR_ON;
        !          1670:        entryPtr->cursorBlinkHandler = Tk_CreateTimerHandler(
        !          1671:                entryPtr->cursorOffTime, EntryBlinkProc, (ClientData) entryPtr);
        !          1672:     } else {
        !          1673:        entryPtr->flags |= CURSOR_ON;
        !          1674:        entryPtr->cursorBlinkHandler = Tk_CreateTimerHandler(
        !          1675:                entryPtr->cursorOnTime, EntryBlinkProc, (ClientData) entryPtr);
        !          1676:     }
        !          1677:     EventuallyRedraw(entryPtr);
        !          1678: }
        !          1679: 
        !          1680: /*
        !          1681:  *----------------------------------------------------------------------
        !          1682:  *
        !          1683:  * EntryFocusProc --
        !          1684:  *
        !          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.
        !          1688:  *
        !          1689:  * Results:
        !          1690:  *     None.
        !          1691:  *
        !          1692:  * Side effects:
        !          1693:  *     The cursor gets turned on or off.
        !          1694:  *
        !          1695:  *----------------------------------------------------------------------
        !          1696:  */
        !          1697: 
        !          1698: static void
        !          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. */
        !          1703: {
        !          1704:     register Entry *entryPtr = (Entry *) clientData;
        !          1705: 
        !          1706:     if (entryPtr->cursorBlinkHandler != NULL) {
        !          1707:       Tk_DeleteTimerHandler(entryPtr->cursorBlinkHandler);
        !          1708:       entryPtr->cursorBlinkHandler = NULL;
        !          1709:     }
        !          1710:     if (gotFocus) {
        !          1711:        entryPtr->flags |= GOT_FOCUS | CURSOR_ON;
        !          1712:        if (entryPtr->cursorOffTime != 0) {
        !          1713:            entryPtr->cursorBlinkHandler = Tk_CreateTimerHandler(
        !          1714:                    entryPtr->cursorOnTime, EntryBlinkProc,
        !          1715:                    (ClientData) entryPtr);
        !          1716:        }
        !          1717:     } else {
        !          1718:        entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON);
        !          1719:        entryPtr->cursorBlinkHandler = (Tk_TimerToken) NULL;
        !          1720:     }
        !          1721:     EventuallyRedraw(entryPtr);
        !          1722: }
        !          1723: 
        !          1724: /*
        !          1725:  *--------------------------------------------------------------
        !          1726:  *
        !          1727:  * EntryTextVarProc --
        !          1728:  *
        !          1729:  *     This procedure is invoked when someone changes the variable
        !          1730:  *     whose contents are to be displayed in an entry.
        !          1731:  *
        !          1732:  * Results:
        !          1733:  *     NULL is always returned.
        !          1734:  *
        !          1735:  * Side effects:
        !          1736:  *     The text displayed in the entry will change to match the
        !          1737:  *     variable.
        !          1738:  *
        !          1739:  *--------------------------------------------------------------
        !          1740:  */
        !          1741: 
        !          1742:        /* ARGSUSED */
        !          1743: static char *
        !          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. */
        !          1750: {
        !          1751:     register Entry *entryPtr = (Entry *) clientData;
        !          1752:     char *value;
        !          1753: 
        !          1754:     /*
        !          1755:      * If the variable is unset, then immediately recreate it unless
        !          1756:      * the whole interpreter is going away.
        !          1757:      */
        !          1758: 
        !          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);
        !          1766:        }
        !          1767:        return (char *) NULL;
        !          1768:     }
        !          1769: 
        !          1770:     /*
        !          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
        !          1774:      * the entry).
        !          1775:      */
        !          1776: 
        !          1777:     value = Tcl_GetVar2(interp, name1, name2, flags & TCL_GLOBAL_ONLY);
        !          1778:     if (value == NULL) {
        !          1779:        value = "";
        !          1780:     }
        !          1781:     if (strcmp(value, entryPtr->string) != 0) {
        !          1782:        EntrySetValue(entryPtr, value);
        !          1783:     }
        !          1784:     return (char *) NULL;
        !          1785: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.