|
|
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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.