#include "tkInt.h"
#include "tkDefault.h"
typedef struct {
Tk_Window tkwin;
Display *display;
Tcl_Interp *interp;
Tcl_Command widgetCmd;
int numChars;
char *string;
char *textVarName;
Tk_Uid state;
Tk_3DBorder normalBorder;
int borderWidth;
int relief;
XFontStruct *fontPtr;
XColor *fgColorPtr;
GC textGC;
Tk_3DBorder selBorder;
int selBorderWidth;
XColor *selFgColorPtr;
GC selTextGC;
Tk_3DBorder insertBorder;
int insertWidth;
int insertBorderWidth;
int insertOnTime;
int insertOffTime;
Tcl_TimerToken insertBlinkHandler;
int highlightWidth;
XColor *highlightBgColorPtr;
XColor *highlightColorPtr;
GC highlightGC;
Tk_Justify justify;
int avgWidth;
int prefWidth;
int inset;
int leftIndex;
int leftX;
int tabOrigin;
int insertPos;
char *showChar;
char *displayString;
int selectFirst;
int selectLast;
int selectAnchor;
int exportSelection;
int scanMarkX;
int scanMarkIndex;
Tk_Cursor cursor;
char *takeFocus;
char *scrollCmd;
int flags;
} Entry;
#define REDRAW_PENDING 1
#define BORDER_NEEDED 2
#define CURSOR_ON 4
#define GOT_FOCUS 8
#define UPDATE_SCROLLBAR 16
#define XPAD 1
#define YPAD 1
static Tk_ConfigSpec configSpecs[] = {
{TK_CONFIG_BORDER, "-background", "background", "Background",
DEF_ENTRY_BG_COLOR, Tk_Offset(Entry, normalBorder),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-background", "background", "Background",
DEF_ENTRY_BG_MONO, Tk_Offset(Entry, normalBorder),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_SYNONYM, "-bd", "borderWidth", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_SYNONYM, "-bg", "background", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_PIXELS, "-borderwidth", "borderWidth", "BorderWidth",
DEF_ENTRY_BORDER_WIDTH, Tk_Offset(Entry, borderWidth), 0},
{TK_CONFIG_ACTIVE_CURSOR, "-cursor", "cursor", "Cursor",
DEF_ENTRY_CURSOR, Tk_Offset(Entry, cursor), TK_CONFIG_NULL_OK},
{TK_CONFIG_BOOLEAN, "-exportselection", "exportSelection",
"ExportSelection", DEF_ENTRY_EXPORT_SELECTION,
Tk_Offset(Entry, exportSelection), 0},
{TK_CONFIG_SYNONYM, "-fg", "foreground", (char *) NULL,
(char *) NULL, 0, 0},
{TK_CONFIG_FONT, "-font", "font", "Font",
DEF_ENTRY_FONT, Tk_Offset(Entry, fontPtr), 0},
{TK_CONFIG_COLOR, "-foreground", "foreground", "Foreground",
DEF_ENTRY_FG, Tk_Offset(Entry, fgColorPtr), 0},
{TK_CONFIG_COLOR, "-highlightbackground", "highlightBackground",
"HighlightBackground", DEF_ENTRY_HIGHLIGHT_BG,
Tk_Offset(Entry, highlightBgColorPtr), 0},
{TK_CONFIG_COLOR, "-highlightcolor", "highlightColor", "HighlightColor",
DEF_ENTRY_HIGHLIGHT, Tk_Offset(Entry, highlightColorPtr), 0},
{TK_CONFIG_PIXELS, "-highlightthickness", "highlightThickness",
"HighlightThickness",
DEF_ENTRY_HIGHLIGHT_WIDTH, Tk_Offset(Entry, highlightWidth), 0},
{TK_CONFIG_BORDER, "-insertbackground", "insertBackground", "Foreground",
DEF_ENTRY_INSERT_BG, Tk_Offset(Entry, insertBorder), 0},
{TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
DEF_ENTRY_INSERT_BD_COLOR, Tk_Offset(Entry, insertBorderWidth),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_PIXELS, "-insertborderwidth", "insertBorderWidth", "BorderWidth",
DEF_ENTRY_INSERT_BD_MONO, Tk_Offset(Entry, insertBorderWidth),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_INT, "-insertofftime", "insertOffTime", "OffTime",
DEF_ENTRY_INSERT_OFF_TIME, Tk_Offset(Entry, insertOffTime), 0},
{TK_CONFIG_INT, "-insertontime", "insertOnTime", "OnTime",
DEF_ENTRY_INSERT_ON_TIME, Tk_Offset(Entry, insertOnTime), 0},
{TK_CONFIG_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
DEF_ENTRY_INSERT_WIDTH, Tk_Offset(Entry, insertWidth), 0},
{TK_CONFIG_JUSTIFY, "-justify", "justify", "Justify",
DEF_ENTRY_JUSTIFY, Tk_Offset(Entry, justify), 0},
{TK_CONFIG_RELIEF, "-relief", "relief", "Relief",
DEF_ENTRY_RELIEF, Tk_Offset(Entry, relief), 0},
{TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
DEF_ENTRY_SELECT_COLOR, Tk_Offset(Entry, selBorder),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_BORDER, "-selectbackground", "selectBackground", "Foreground",
DEF_ENTRY_SELECT_MONO, Tk_Offset(Entry, selBorder),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
DEF_ENTRY_SELECT_BD_COLOR, Tk_Offset(Entry, selBorderWidth),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_PIXELS, "-selectborderwidth", "selectBorderWidth", "BorderWidth",
DEF_ENTRY_SELECT_BD_MONO, Tk_Offset(Entry, selBorderWidth),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_ENTRY_SELECT_FG_COLOR, Tk_Offset(Entry, selFgColorPtr),
TK_CONFIG_COLOR_ONLY},
{TK_CONFIG_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_ENTRY_SELECT_FG_MONO, Tk_Offset(Entry, selFgColorPtr),
TK_CONFIG_MONO_ONLY},
{TK_CONFIG_STRING, "-show", "show", "Show",
DEF_ENTRY_SHOW, Tk_Offset(Entry, showChar), TK_CONFIG_NULL_OK},
{TK_CONFIG_UID, "-state", "state", "State",
DEF_ENTRY_STATE, Tk_Offset(Entry, state), 0},
{TK_CONFIG_STRING, "-takefocus", "takeFocus", "TakeFocus",
DEF_ENTRY_TAKE_FOCUS, Tk_Offset(Entry, takeFocus), TK_CONFIG_NULL_OK},
{TK_CONFIG_STRING, "-textvariable", "textVariable", "Variable",
DEF_ENTRY_TEXT_VARIABLE, Tk_Offset(Entry, textVarName),
TK_CONFIG_NULL_OK},
{TK_CONFIG_INT, "-width", "width", "Width",
DEF_ENTRY_WIDTH, Tk_Offset(Entry, prefWidth), 0},
{TK_CONFIG_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
DEF_ENTRY_SCROLL_COMMAND, Tk_Offset(Entry, scrollCmd),
TK_CONFIG_NULL_OK},
{TK_CONFIG_END, (char *) NULL, (char *) NULL, (char *) NULL,
(char *) NULL, 0, 0}
};
#define ZERO_OK 1
#define LAST_PLUS_ONE_OK 2
static int ConfigureEntry _ANSI_ARGS_((Tcl_Interp *interp,
Entry *entryPtr, int argc, char **argv,
int flags));
static void DeleteChars _ANSI_ARGS_((Entry *entryPtr, int index,
int count));
static void DestroyEntry _ANSI_ARGS_((char *memPtr));
static void DisplayEntry _ANSI_ARGS_((ClientData clientData));
static void EntryBlinkProc _ANSI_ARGS_((ClientData clientData));
static void EntryCmdDeletedProc _ANSI_ARGS_((
ClientData clientData));
static void EntryComputeGeometry _ANSI_ARGS_((Entry *entryPtr));
static void EntryEventProc _ANSI_ARGS_((ClientData clientData,
XEvent *eventPtr));
static void EntryFocusProc _ANSI_ARGS_ ((Entry *entryPtr,
int gotFocus));
static int EntryFetchSelection _ANSI_ARGS_((ClientData clientData,
int offset, char *buffer, int maxBytes));
static void EntryLostSelection _ANSI_ARGS_((
ClientData clientData));
static void EventuallyRedraw _ANSI_ARGS_((Entry *entryPtr));
static void EntryScanTo _ANSI_ARGS_((Entry *entryPtr, int y));
static void EntrySetValue _ANSI_ARGS_((Entry *entryPtr,
char *value));
static void EntrySelectTo _ANSI_ARGS_((
Entry *entryPtr, int index));
static char * EntryTextVarProc _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, char *name1, char *name2,
int flags));
static void EntryUpdateScrollbar _ANSI_ARGS_((Entry *entryPtr));
static void EntryValueChanged _ANSI_ARGS_((Entry *entryPtr));
static void EntryVisibleRange _ANSI_ARGS_((Entry *entryPtr,
double *firstPtr, double *lastPtr));
static int EntryWidgetCmd _ANSI_ARGS_((ClientData clientData,
Tcl_Interp *interp, int argc, char **argv));
static int GetEntryIndex _ANSI_ARGS_((Tcl_Interp *interp,
Entry *entryPtr, char *string, int *indexPtr));
static void InsertChars _ANSI_ARGS_((Entry *entryPtr, int index,
char *string));
int
Tk_EntryCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
Tk_Window tkwin = (Tk_Window) clientData;
register Entry *entryPtr;
Tk_Window new;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " pathName ?options?\"", (char *) NULL);
return TCL_ERROR;
}
new = Tk_CreateWindowFromPath(interp, tkwin, argv[1], (char *) NULL);
if (new == NULL) {
return TCL_ERROR;
}
entryPtr = (Entry *) ckalloc(sizeof(Entry));
entryPtr->tkwin = new;
entryPtr->display = Tk_Display(new);
entryPtr->interp = interp;
entryPtr->widgetCmd = Tcl_CreateCommand(interp,
Tk_PathName(entryPtr->tkwin), EntryWidgetCmd,
(ClientData) entryPtr, EntryCmdDeletedProc);
entryPtr->numChars = 0;
entryPtr->string = (char *) ckalloc(1);
entryPtr->string[0] = '\0';
entryPtr->textVarName = NULL;
entryPtr->state = tkNormalUid;
entryPtr->normalBorder = NULL;
entryPtr->borderWidth = 0;
entryPtr->relief = TK_RELIEF_FLAT;
entryPtr->fontPtr = NULL;
entryPtr->fgColorPtr = NULL;
entryPtr->textGC = None;
entryPtr->selBorder = NULL;
entryPtr->selBorderWidth = 0;
entryPtr->selFgColorPtr = NULL;
entryPtr->selTextGC = None;
entryPtr->insertBorder = NULL;
entryPtr->insertWidth = 0;
entryPtr->insertBorderWidth = 0;
entryPtr->insertOnTime = 0;
entryPtr->insertOffTime = 0;
entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
entryPtr->highlightWidth = 0;
entryPtr->highlightBgColorPtr = NULL;
entryPtr->highlightColorPtr = NULL;
entryPtr->justify = TK_JUSTIFY_LEFT;
entryPtr->avgWidth = 1;
entryPtr->prefWidth = 0;
entryPtr->inset = XPAD;
entryPtr->leftIndex = 0;
entryPtr->leftX = 0;
entryPtr->tabOrigin = 0;
entryPtr->insertPos = 0;
entryPtr->showChar = NULL;
entryPtr->displayString = NULL;
entryPtr->selectFirst = -1;
entryPtr->selectLast = -1;
entryPtr->selectAnchor = 0;
entryPtr->exportSelection = 1;
entryPtr->scanMarkX = 0;
entryPtr->scanMarkIndex = 0;
entryPtr->cursor = None;
entryPtr->takeFocus = NULL;
entryPtr->scrollCmd = NULL;
entryPtr->flags = 0;
Tk_SetClass(entryPtr->tkwin, "Entry");
Tk_CreateEventHandler(entryPtr->tkwin,
ExposureMask|StructureNotifyMask|FocusChangeMask,
EntryEventProc, (ClientData) entryPtr);
Tk_CreateSelHandler(entryPtr->tkwin, XA_PRIMARY, XA_STRING,
EntryFetchSelection, (ClientData) entryPtr, XA_STRING);
if (ConfigureEntry(interp, entryPtr, argc-2, argv+2, 0) != TCL_OK) {
goto error;
}
interp->result = Tk_PathName(entryPtr->tkwin);
return TCL_OK;
error:
Tk_DestroyWindow(entryPtr->tkwin);
return TCL_ERROR;
}
static int
EntryWidgetCmd(clientData, interp, argc, argv)
ClientData clientData;
Tcl_Interp *interp;
int argc;
char **argv;
{
register Entry *entryPtr = (Entry *) clientData;
int result = TCL_OK;
size_t length;
int c, height;
if (argc < 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " option ?arg arg ...?\"", (char *) NULL);
return TCL_ERROR;
}
Tcl_Preserve((ClientData) entryPtr);
c = argv[1][0];
length = strlen(argv[1]);
if ((c == 'b') && (strncmp(argv[1], "bbox", length) == 0)) {
int index, x1, x2;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " bbox index\"",
(char *) NULL);
goto error;
}
if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
goto error;
}
if ((index == entryPtr->numChars) && (index > 0)) {
index--;
}
TkMeasureChars(entryPtr->fontPtr,
(entryPtr->displayString == NULL) ? entryPtr->string
: entryPtr->displayString, index, entryPtr->tabOrigin,
1000000, entryPtr->tabOrigin, TK_NEWLINES_NOT_SPECIAL,
&x1);
if (index < entryPtr->numChars) {
TkMeasureChars(entryPtr->fontPtr,
(entryPtr->displayString == NULL) ? entryPtr->string
: entryPtr->displayString, index+1, entryPtr->tabOrigin,
1000000, entryPtr->tabOrigin, TK_NEWLINES_NOT_SPECIAL,
&x2);
} else {
x2 = x1;
}
height = entryPtr->fontPtr->ascent + entryPtr->fontPtr->descent;
sprintf(interp->result, "%d %d %d %d", x1,
(Tk_Height(entryPtr->tkwin) - height)/2, x2-x1, height);
} else if ((c == 'c') && (strncmp(argv[1], "cget", length) == 0)
&& (length >= 2)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " cget option\"",
(char *) NULL);
goto error;
}
result = Tk_ConfigureValue(interp, entryPtr->tkwin, configSpecs,
(char *) entryPtr, argv[2], 0);
} else if ((c == 'c') && (strncmp(argv[1], "configure", length) == 0)
&& (length >= 2)) {
if (argc == 2) {
result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs,
(char *) entryPtr, (char *) NULL, 0);
} else if (argc == 3) {
result = Tk_ConfigureInfo(interp, entryPtr->tkwin, configSpecs,
(char *) entryPtr, argv[2], 0);
} else {
result = ConfigureEntry(interp, entryPtr, argc-2, argv+2,
TK_CONFIG_ARGV_ONLY);
}
} else if ((c == 'd') && (strncmp(argv[1], "delete", length) == 0)) {
int first, last;
if ((argc < 3) || (argc > 4)) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " delete firstIndex ?lastIndex?\"",
(char *) NULL);
goto error;
}
if (GetEntryIndex(interp, entryPtr, argv[2], &first) != TCL_OK) {
goto error;
}
if (argc == 3) {
last = first+1;
} else {
if (GetEntryIndex(interp, entryPtr, argv[3], &last) != TCL_OK) {
goto error;
}
}
if ((last >= first) && (entryPtr->state == tkNormalUid)) {
DeleteChars(entryPtr, first, last-first);
}
} else if ((c == 'g') && (strncmp(argv[1], "get", length) == 0)) {
if (argc != 2) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " get\"", (char *) NULL);
goto error;
}
interp->result = entryPtr->string;
} else if ((c == 'i') && (strncmp(argv[1], "icursor", length) == 0)
&& (length >= 2)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " icursor pos\"",
(char *) NULL);
goto error;
}
if (GetEntryIndex(interp, entryPtr, argv[2], &entryPtr->insertPos)
!= TCL_OK) {
goto error;
}
EventuallyRedraw(entryPtr);
} else if ((c == 'i') && (strncmp(argv[1], "index", length) == 0)
&& (length >= 3)) {
int index;
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " index string\"", (char *) NULL);
goto error;
}
if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
goto error;
}
sprintf(interp->result, "%d", index);
} else if ((c == 'i') && (strncmp(argv[1], "insert", length) == 0)
&& (length >= 3)) {
int index;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " insert index text\"",
(char *) NULL);
goto error;
}
if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
goto error;
}
if (entryPtr->state == tkNormalUid) {
InsertChars(entryPtr, index, argv[3]);
}
} else if ((c == 's') && (length >= 2)
&& (strncmp(argv[1], "scan", length) == 0)) {
int x;
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " scan mark|dragto x\"", (char *) NULL);
goto error;
}
if (Tcl_GetInt(interp, argv[3], &x) != TCL_OK) {
goto error;
}
if ((argv[2][0] == 'm')
&& (strncmp(argv[2], "mark", strlen(argv[2])) == 0)) {
entryPtr->scanMarkX = x;
entryPtr->scanMarkIndex = entryPtr->leftIndex;
} else if ((argv[2][0] == 'd')
&& (strncmp(argv[2], "dragto", strlen(argv[2])) == 0)) {
EntryScanTo(entryPtr, x);
} else {
Tcl_AppendResult(interp, "bad scan option \"", argv[2],
"\": must be mark or dragto", (char *) NULL);
goto error;
}
} else if ((c == 's') && (length >= 2)
&& (strncmp(argv[1], "selection", length) == 0)) {
int index, index2;
if (argc < 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " select option ?index?\"", (char *) NULL);
goto error;
}
length = strlen(argv[2]);
c = argv[2][0];
if ((c == 'c') && (strncmp(argv[2], "clear", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " selection clear\"", (char *) NULL);
goto error;
}
if (entryPtr->selectFirst != -1) {
entryPtr->selectFirst = entryPtr->selectLast = -1;
EventuallyRedraw(entryPtr);
}
goto done;
} else if ((c == 'p') && (strncmp(argv[2], "present", length) == 0)) {
if (argc != 3) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " selection present\"", (char *) NULL);
goto error;
}
if (entryPtr->selectFirst == -1) {
interp->result = "0";
} else {
interp->result = "1";
}
goto done;
}
if (argc >= 4) {
if (GetEntryIndex(interp, entryPtr, argv[3], &index) != TCL_OK) {
goto error;
}
}
if ((c == 'a') && (strncmp(argv[2], "adjust", length) == 0)) {
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " selection adjust index\"",
(char *) NULL);
goto error;
}
if (entryPtr->selectFirst >= 0) {
int half1, half2;
half1 = (entryPtr->selectFirst + entryPtr->selectLast)/2;
half2 = (entryPtr->selectFirst + entryPtr->selectLast + 1)/2;
if (index < half1) {
entryPtr->selectAnchor = entryPtr->selectLast;
} else if (index > half2) {
entryPtr->selectAnchor = entryPtr->selectFirst;
} else {
}
}
EntrySelectTo(entryPtr, index);
} else if ((c == 'f') && (strncmp(argv[2], "from", length) == 0)) {
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " selection from index\"",
(char *) NULL);
goto error;
}
entryPtr->selectAnchor = index;
} else if ((c == 'r') && (strncmp(argv[2], "range", length) == 0)) {
if (argc != 5) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " selection range start end\"",
(char *) NULL);
goto error;
}
if (GetEntryIndex(interp, entryPtr, argv[4], &index2) != TCL_OK) {
goto error;
}
if (index >= index2) {
entryPtr->selectFirst = entryPtr->selectLast = -1;
} else {
if ((entryPtr->selectFirst == -1)
&& (entryPtr->exportSelection)) {
Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
EntryLostSelection, (ClientData) entryPtr);
}
entryPtr->selectFirst = index;
entryPtr->selectLast = index2;
}
if ((entryPtr->selectFirst == -1) && (entryPtr->exportSelection)) {
Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY,
EntryLostSelection, (ClientData) entryPtr);
}
EventuallyRedraw(entryPtr);
} else if ((c == 't') && (strncmp(argv[2], "to", length) == 0)) {
if (argc != 4) {
Tcl_AppendResult(interp, "wrong # args: should be \"",
argv[0], " selection to index\"",
(char *) NULL);
goto error;
}
EntrySelectTo(entryPtr, index);
} else {
Tcl_AppendResult(interp, "bad selection option \"", argv[2],
"\": must be adjust, clear, from, present, range, or to",
(char *) NULL);
goto error;
}
} else if ((c == 'x') && (strncmp(argv[1], "xview", length) == 0)) {
int index, type, count, charsPerPage;
double fraction, first, last;
if (argc == 2) {
EntryVisibleRange(entryPtr, &first, &last);
sprintf(interp->result, "%g %g", first, last);
goto done;
} else if (argc == 3) {
if (GetEntryIndex(interp, entryPtr, argv[2], &index) != TCL_OK) {
goto error;
}
} else {
type = Tk_GetScrollInfo(interp, argc, argv, &fraction, &count);
index = entryPtr->leftIndex;
switch (type) {
case TK_SCROLL_ERROR:
goto error;
case TK_SCROLL_MOVETO:
index = (fraction * entryPtr->numChars) + 0.5;
break;
case TK_SCROLL_PAGES:
charsPerPage = ((Tk_Width(entryPtr->tkwin)
- 2*entryPtr->inset) / entryPtr->avgWidth) - 2;
if (charsPerPage < 1) {
charsPerPage = 1;
}
index += charsPerPage*count;
break;
case TK_SCROLL_UNITS:
index += count;
break;
}
}
if (index >= entryPtr->numChars) {
index = entryPtr->numChars-1;
}
if (index < 0) {
index = 0;
}
entryPtr->leftIndex = index;
entryPtr->flags |= UPDATE_SCROLLBAR;
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
} else {
Tcl_AppendResult(interp, "bad option \"", argv[1],
"\": must be bbox, cget, configure, delete, get, ",
"icursor, index, insert, scan, selection, or xview",
(char *) NULL);
goto error;
}
done:
Tcl_Release((ClientData) entryPtr);
return result;
error:
Tcl_Release((ClientData) entryPtr);
return TCL_ERROR;
}
static void
DestroyEntry(memPtr)
char *memPtr;
{
register Entry *entryPtr = (Entry *) memPtr;
ckfree(entryPtr->string);
if (entryPtr->textVarName != NULL) {
Tcl_UntraceVar(entryPtr->interp, entryPtr->textVarName,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, (ClientData) entryPtr);
}
if (entryPtr->textGC != None) {
Tk_FreeGC(entryPtr->display, entryPtr->textGC);
}
if (entryPtr->selTextGC != None) {
Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
}
Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler);
if (entryPtr->displayString != NULL) {
ckfree(entryPtr->displayString);
}
Tk_FreeOptions(configSpecs, (char *) entryPtr, entryPtr->display, 0);
ckfree((char *) entryPtr);
}
static int
ConfigureEntry(interp, entryPtr, argc, argv, flags)
Tcl_Interp *interp;
register Entry *entryPtr;
int argc;
char **argv;
int flags;
{
XGCValues gcValues;
GC new;
int oldExport;
if (entryPtr->textVarName != NULL) {
Tcl_UntraceVar(interp, entryPtr->textVarName,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, (ClientData) entryPtr);
}
oldExport = entryPtr->exportSelection;
if (Tk_ConfigureWidget(interp, entryPtr->tkwin, configSpecs,
argc, argv, (char *) entryPtr, flags) != TCL_OK) {
return TCL_ERROR;
}
if (entryPtr->textVarName != NULL) {
char *value;
value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
if (value == NULL) {
EntryValueChanged(entryPtr);
} else {
EntrySetValue(entryPtr, value);
}
Tcl_TraceVar(interp, entryPtr->textVarName,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, (ClientData) entryPtr);
}
if ((entryPtr->state != tkNormalUid)
&& (entryPtr->state != tkDisabledUid)) {
Tcl_AppendResult(interp, "bad state value \"", entryPtr->state,
"\": must be normal or disabled", (char *) NULL);
entryPtr->state = tkNormalUid;
return TCL_ERROR;
}
Tk_SetBackgroundFromBorder(entryPtr->tkwin, entryPtr->normalBorder);
gcValues.foreground = entryPtr->fgColorPtr->pixel;
gcValues.font = entryPtr->fontPtr->fid;
gcValues.graphics_exposures = False;
new = Tk_GetGC(entryPtr->tkwin, GCForeground|GCFont|GCGraphicsExposures,
&gcValues);
if (entryPtr->textGC != None) {
Tk_FreeGC(entryPtr->display, entryPtr->textGC);
}
entryPtr->textGC = new;
gcValues.foreground = entryPtr->selFgColorPtr->pixel;
gcValues.font = entryPtr->fontPtr->fid;
new = Tk_GetGC(entryPtr->tkwin, GCForeground|GCFont, &gcValues);
if (entryPtr->selTextGC != None) {
Tk_FreeGC(entryPtr->display, entryPtr->selTextGC);
}
entryPtr->selTextGC = new;
if (entryPtr->insertWidth <= 0) {
entryPtr->insertWidth = 2;
}
if (entryPtr->insertBorderWidth > entryPtr->insertWidth/2) {
entryPtr->insertBorderWidth = entryPtr->insertWidth/2;
}
if (entryPtr->flags & GOT_FOCUS) {
EntryFocusProc(entryPtr, 1);
}
if (entryPtr->exportSelection && (!oldExport)
&& (entryPtr->selectFirst != -1)) {
Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
(ClientData) entryPtr);
}
Tk_SetInternalBorder(entryPtr->tkwin,
entryPtr->borderWidth + entryPtr->highlightWidth);
if (entryPtr->highlightWidth <= 0) {
entryPtr->highlightWidth = 0;
}
entryPtr->inset = entryPtr->highlightWidth + entryPtr->borderWidth + XPAD;
entryPtr->avgWidth = XTextWidth(entryPtr->fontPtr, "0", 1);
EntryComputeGeometry(entryPtr);
entryPtr->flags |= UPDATE_SCROLLBAR;
EventuallyRedraw(entryPtr);
return TCL_OK;
}
static void
DisplayEntry(clientData)
ClientData clientData;
{
register Entry *entryPtr = (Entry *) clientData;
register Tk_Window tkwin = entryPtr->tkwin;
int baseY, selStartX, selEndX, index, cursorX;
int xBound, count;
Pixmap pixmap;
char *displayString;
entryPtr->flags &= ~REDRAW_PENDING;
if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
return;
}
if (entryPtr->flags & UPDATE_SCROLLBAR) {
entryPtr->flags &= ~UPDATE_SCROLLBAR;
EntryUpdateScrollbar(entryPtr);
}
pixmap = Tk_GetPixmap(entryPtr->display, Tk_WindowId(tkwin),
Tk_Width(tkwin), Tk_Height(tkwin), Tk_Depth(tkwin));
xBound = Tk_Width(tkwin) - entryPtr->inset;
baseY = (Tk_Height(tkwin) + entryPtr->fontPtr->ascent
- entryPtr->fontPtr->descent)/2;
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
0, 0, Tk_Width(tkwin), Tk_Height(tkwin), 0, TK_RELIEF_FLAT);
if (entryPtr->displayString == NULL) {
displayString = entryPtr->string;
} else {
displayString = entryPtr->displayString;
}
if (entryPtr->selectLast > entryPtr->leftIndex) {
if (entryPtr->selectFirst <= entryPtr->leftIndex) {
selStartX = entryPtr->leftX;
index = entryPtr->leftIndex;
} else {
(void) TkMeasureChars(entryPtr->fontPtr,
displayString + entryPtr->leftIndex,
entryPtr->selectFirst - entryPtr->leftIndex,
entryPtr->leftX, xBound, entryPtr->tabOrigin,
TK_PARTIAL_OK|TK_NEWLINES_NOT_SPECIAL, &selStartX);
index = entryPtr->selectFirst;
}
if ((selStartX - entryPtr->selBorderWidth) < xBound) {
(void) TkMeasureChars(entryPtr->fontPtr,
displayString + index, entryPtr->selectLast - index,
selStartX, xBound, entryPtr->tabOrigin,
TK_PARTIAL_OK|TK_NEWLINES_NOT_SPECIAL, &selEndX);
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->selBorder,
selStartX - entryPtr->selBorderWidth,
baseY - entryPtr->fontPtr->ascent
- entryPtr->selBorderWidth,
(selEndX - selStartX) + 2*entryPtr->selBorderWidth,
entryPtr->fontPtr->ascent + entryPtr->fontPtr->descent
+ 2*entryPtr->selBorderWidth,
entryPtr->selBorderWidth, TK_RELIEF_RAISED);
} else {
selEndX = xBound;
}
}
if ((entryPtr->insertPos >= entryPtr->leftIndex)
&& (entryPtr->state == tkNormalUid)
&& (entryPtr->flags & GOT_FOCUS)) {
(void) TkMeasureChars(entryPtr->fontPtr,
displayString + entryPtr->leftIndex,
entryPtr->insertPos - entryPtr->leftIndex, entryPtr->leftX,
xBound + entryPtr->insertWidth, entryPtr->tabOrigin,
TK_PARTIAL_OK|TK_NEWLINES_NOT_SPECIAL, &cursorX);
cursorX -= (entryPtr->insertWidth)/2;
if (cursorX < xBound) {
if (entryPtr->flags & CURSOR_ON) {
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->insertBorder,
cursorX, baseY - entryPtr->fontPtr->ascent,
entryPtr->insertWidth,
entryPtr->fontPtr->ascent + entryPtr->fontPtr->descent,
entryPtr->insertBorderWidth, TK_RELIEF_RAISED);
} else if (entryPtr->insertBorder == entryPtr->selBorder) {
Tk_Fill3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
cursorX, baseY - entryPtr->fontPtr->ascent,
entryPtr->insertWidth,
entryPtr->fontPtr->ascent + entryPtr->fontPtr->descent,
0, TK_RELIEF_FLAT);
}
}
}
if (entryPtr->selectLast <= entryPtr->leftIndex) {
TkDisplayChars(entryPtr->display, pixmap, entryPtr->textGC,
entryPtr->fontPtr, displayString + entryPtr->leftIndex,
entryPtr->numChars - entryPtr->leftIndex, entryPtr->leftX,
baseY, entryPtr->tabOrigin, TK_NEWLINES_NOT_SPECIAL);
} else {
count = entryPtr->selectFirst - entryPtr->leftIndex;
if (count > 0) {
TkDisplayChars(entryPtr->display, pixmap, entryPtr->textGC,
entryPtr->fontPtr, displayString + entryPtr->leftIndex,
count, entryPtr->leftX, baseY, entryPtr->tabOrigin,
TK_NEWLINES_NOT_SPECIAL);
index = entryPtr->selectFirst;
} else {
index = entryPtr->leftIndex;
}
count = entryPtr->selectLast - index;
if ((selStartX < xBound) && (count > 0)) {
TkDisplayChars(entryPtr->display, pixmap, entryPtr->selTextGC,
entryPtr->fontPtr, displayString + index, count,
selStartX, baseY, entryPtr->tabOrigin,
TK_NEWLINES_NOT_SPECIAL);
}
count = entryPtr->numChars - entryPtr->selectLast;
if ((selEndX < xBound) && (count > 0)) {
TkDisplayChars(entryPtr->display, pixmap, entryPtr->textGC,
entryPtr->fontPtr,
displayString + entryPtr->selectLast,
count, selEndX, baseY, entryPtr->tabOrigin,
TK_NEWLINES_NOT_SPECIAL);
}
}
if (entryPtr->relief != TK_RELIEF_FLAT) {
Tk_Draw3DRectangle(tkwin, pixmap, entryPtr->normalBorder,
entryPtr->highlightWidth, entryPtr->highlightWidth,
Tk_Width(tkwin) - 2*entryPtr->highlightWidth,
Tk_Height(tkwin) - 2*entryPtr->highlightWidth,
entryPtr->borderWidth, entryPtr->relief);
}
if (entryPtr->highlightWidth != 0) {
GC gc;
if (entryPtr->flags & GOT_FOCUS) {
gc = Tk_GCForColor(entryPtr->highlightColorPtr, pixmap);
} else {
gc = Tk_GCForColor(entryPtr->highlightBgColorPtr, pixmap);
}
Tk_DrawFocusHighlight(tkwin, gc, entryPtr->highlightWidth, pixmap);
}
XCopyArea(entryPtr->display, pixmap, Tk_WindowId(tkwin), entryPtr->textGC,
0, 0, (unsigned) Tk_Width(tkwin), (unsigned) Tk_Height(tkwin),
0, 0);
Tk_FreePixmap(entryPtr->display, pixmap);
entryPtr->flags &= ~BORDER_NEEDED;
}
static void
EntryComputeGeometry(entryPtr)
Entry *entryPtr;
{
int totalLength, overflow, maxOffScreen, rightX;
int fontHeight, height, width, i;
char *p, *displayString;
if (entryPtr->displayString != NULL) {
ckfree(entryPtr->displayString);
entryPtr->displayString = NULL;
}
if (entryPtr->showChar != NULL) {
entryPtr->displayString = (char *) ckalloc((unsigned)
(entryPtr->numChars + 1));
for (p = entryPtr->displayString, i = entryPtr->numChars; i > 0;
i--, p++) {
*p = entryPtr->showChar[0];
}
*p = 0;
displayString = entryPtr->displayString;
} else {
displayString = entryPtr->string;
}
TkMeasureChars(entryPtr->fontPtr, displayString, entryPtr->numChars,
0, INT_MAX, 0, TK_NEWLINES_NOT_SPECIAL, &totalLength);
overflow = totalLength - (Tk_Width(entryPtr->tkwin) - 2*entryPtr->inset);
if (overflow <= 0) {
entryPtr->leftIndex = 0;
if (entryPtr->justify == TK_JUSTIFY_LEFT) {
entryPtr->leftX = entryPtr->inset;
} else if (entryPtr->justify == TK_JUSTIFY_RIGHT) {
entryPtr->leftX = Tk_Width(entryPtr->tkwin) - entryPtr->inset
- totalLength;
} else {
entryPtr->leftX = (Tk_Width(entryPtr->tkwin) - totalLength)/2;
}
entryPtr->tabOrigin = entryPtr->leftX;
} else {
maxOffScreen = TkMeasureChars(entryPtr->fontPtr, displayString,
entryPtr->numChars, 0, overflow, 0,
TK_NEWLINES_NOT_SPECIAL|TK_PARTIAL_OK, &rightX);
if (rightX < overflow) {
maxOffScreen += 1;
}
if (entryPtr->leftIndex > maxOffScreen) {
entryPtr->leftIndex = maxOffScreen;
}
TkMeasureChars(entryPtr->fontPtr, displayString,
entryPtr->leftIndex, 0, INT_MAX, 0,
TK_NEWLINES_NOT_SPECIAL|TK_PARTIAL_OK, &rightX);
entryPtr->leftX = entryPtr->inset;
entryPtr->tabOrigin = entryPtr->leftX - rightX;
}
fontHeight = entryPtr->fontPtr->ascent + entryPtr->fontPtr->descent;
height = fontHeight + 2*entryPtr->inset + 2*(YPAD-XPAD);
if (entryPtr->prefWidth > 0) {
width = entryPtr->prefWidth*entryPtr->avgWidth + 2*entryPtr->inset;
} else {
if (totalLength == 0) {
width = entryPtr->avgWidth + 2*entryPtr->inset;
} else {
width = totalLength + 2*entryPtr->inset;
}
}
Tk_GeometryRequest(entryPtr->tkwin, width, height);
}
static void
InsertChars(entryPtr, index, string)
register Entry *entryPtr;
int index;
char *string;
{
int length;
char *new;
length = strlen(string);
if (length == 0) {
return;
}
new = (char *) ckalloc((unsigned) (entryPtr->numChars + length + 1));
strncpy(new, entryPtr->string, (size_t) index);
strcpy(new+index, string);
strcpy(new+index+length, entryPtr->string+index);
ckfree(entryPtr->string);
entryPtr->string = new;
entryPtr->numChars += length;
if (entryPtr->selectFirst >= index) {
entryPtr->selectFirst += length;
}
if (entryPtr->selectLast > index) {
entryPtr->selectLast += length;
}
if ((entryPtr->selectAnchor > index) || (entryPtr->selectFirst >= index)) {
entryPtr->selectAnchor += length;
}
if (entryPtr->leftIndex > index) {
entryPtr->leftIndex += length;
}
if (entryPtr->insertPos >= index) {
entryPtr->insertPos += length;
}
EntryValueChanged(entryPtr);
}
static void
DeleteChars(entryPtr, index, count)
register Entry *entryPtr;
int index;
int count;
{
char *new;
if ((index + count) > entryPtr->numChars) {
count = entryPtr->numChars - index;
}
if (count <= 0) {
return;
}
new = (char *) ckalloc((unsigned) (entryPtr->numChars + 1 - count));
strncpy(new, entryPtr->string, (size_t) index);
strcpy(new+index, entryPtr->string+index+count);
ckfree(entryPtr->string);
entryPtr->string = new;
entryPtr->numChars -= count;
if (entryPtr->selectFirst >= index) {
if (entryPtr->selectFirst >= (index+count)) {
entryPtr->selectFirst -= count;
} else {
entryPtr->selectFirst = index;
}
}
if (entryPtr->selectLast >= index) {
if (entryPtr->selectLast >= (index+count)) {
entryPtr->selectLast -= count;
} else {
entryPtr->selectLast = index;
}
}
if (entryPtr->selectLast <= entryPtr->selectFirst) {
entryPtr->selectFirst = entryPtr->selectLast = -1;
}
if (entryPtr->selectAnchor >= index) {
if (entryPtr->selectAnchor >= (index+count)) {
entryPtr->selectAnchor -= count;
} else {
entryPtr->selectAnchor = index;
}
}
if (entryPtr->leftIndex > index) {
if (entryPtr->leftIndex >= (index+count)) {
entryPtr->leftIndex -= count;
} else {
entryPtr->leftIndex = index;
}
}
if (entryPtr->insertPos >= index) {
if (entryPtr->insertPos >= (index+count)) {
entryPtr->insertPos -= count;
} else {
entryPtr->insertPos = index;
}
}
EntryValueChanged(entryPtr);
}
static void
EntryValueChanged(entryPtr)
Entry *entryPtr;
{
char *newValue;
if (entryPtr->textVarName == NULL) {
newValue = NULL;
} else {
newValue = Tcl_SetVar(entryPtr->interp, entryPtr->textVarName,
entryPtr->string, TCL_GLOBAL_ONLY);
}
if ((newValue != NULL) && (strcmp(newValue, entryPtr->string) != 0)) {
EntrySetValue(entryPtr, newValue);
} else {
entryPtr->flags |= UPDATE_SCROLLBAR;
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
}
}
static void
EntrySetValue(entryPtr, value)
register Entry *entryPtr;
char *value;
{
ckfree(entryPtr->string);
entryPtr->numChars = strlen(value);
entryPtr->string = (char *) ckalloc((unsigned) (entryPtr->numChars + 1));
strcpy(entryPtr->string, value);
if (entryPtr->selectFirst != -1) {
if (entryPtr->selectFirst >= entryPtr->numChars) {
entryPtr->selectFirst = entryPtr->selectLast = -1;
} else if (entryPtr->selectLast > entryPtr->numChars) {
entryPtr->selectLast = entryPtr->numChars;
}
}
if (entryPtr->leftIndex >= entryPtr->numChars) {
entryPtr->leftIndex = entryPtr->numChars-1;
}
if (entryPtr->insertPos > entryPtr->numChars) {
entryPtr->insertPos = entryPtr->numChars;
}
entryPtr->flags |= UPDATE_SCROLLBAR;
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
}
static void
EntryEventProc(clientData, eventPtr)
ClientData clientData;
XEvent *eventPtr;
{
Entry *entryPtr = (Entry *) clientData;
if (eventPtr->type == Expose) {
EventuallyRedraw(entryPtr);
entryPtr->flags |= BORDER_NEEDED;
} else if (eventPtr->type == DestroyNotify) {
if (entryPtr->tkwin != NULL) {
entryPtr->tkwin = NULL;
Tcl_DeleteCommand(entryPtr->interp,
Tcl_GetCommandName(entryPtr->interp, entryPtr->widgetCmd));
}
if (entryPtr->flags & REDRAW_PENDING) {
Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr);
}
Tcl_EventuallyFree((ClientData) entryPtr, DestroyEntry);
} else if (eventPtr->type == ConfigureNotify) {
Tcl_Preserve((ClientData) entryPtr);
entryPtr->flags |= UPDATE_SCROLLBAR;
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
Tcl_Release((ClientData) entryPtr);
} else if (eventPtr->type == FocusIn) {
if (eventPtr->xfocus.detail != NotifyInferior) {
EntryFocusProc(entryPtr, 1);
}
} else if (eventPtr->type == FocusOut) {
if (eventPtr->xfocus.detail != NotifyInferior) {
EntryFocusProc(entryPtr, 0);
}
}
}
static void
EntryCmdDeletedProc(clientData)
ClientData clientData;
{
Entry *entryPtr = (Entry *) clientData;
Tk_Window tkwin = entryPtr->tkwin;
if (tkwin != NULL) {
entryPtr->tkwin = NULL;
Tk_DestroyWindow(tkwin);
}
}
static int
GetEntryIndex(interp, entryPtr, string, indexPtr)
Tcl_Interp *interp;
Entry *entryPtr;
char *string;
int *indexPtr;
{
size_t length;
length = strlen(string);
if (string[0] == 'a') {
if (strncmp(string, "anchor", length) == 0) {
*indexPtr = entryPtr->selectAnchor;
} else {
badIndex:
Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
Tcl_AppendResult(interp, "bad entry index \"", string,
"\"", (char *) NULL);
return TCL_ERROR;
}
} else if (string[0] == 'e') {
if (strncmp(string, "end", length) == 0) {
*indexPtr = entryPtr->numChars;
} else {
goto badIndex;
}
} else if (string[0] == 'i') {
if (strncmp(string, "insert", length) == 0) {
*indexPtr = entryPtr->insertPos;
} else {
goto badIndex;
}
} else if (string[0] == 's') {
if (entryPtr->selectFirst == -1) {
interp->result = "selection isn't in entry";
return TCL_ERROR;
}
if (length < 5) {
goto badIndex;
}
if (strncmp(string, "sel.first", length) == 0) {
*indexPtr = entryPtr->selectFirst;
} else if (strncmp(string, "sel.last", length) == 0) {
*indexPtr = entryPtr->selectLast;
} else {
goto badIndex;
}
} else if (string[0] == '@') {
int x, dummy, roundUp;
if (Tcl_GetInt(interp, string+1, &x) != TCL_OK) {
goto badIndex;
}
if (x < entryPtr->inset) {
x = entryPtr->inset;
}
roundUp = 0;
if (x >= (Tk_Width(entryPtr->tkwin) - entryPtr->inset)) {
x = Tk_Width(entryPtr->tkwin) - entryPtr->inset - 1;
roundUp = 1;
}
if (entryPtr->numChars == 0) {
*indexPtr = 0;
} else {
*indexPtr = TkMeasureChars(entryPtr->fontPtr,
(entryPtr->displayString == NULL) ? entryPtr->string
: entryPtr->displayString,
entryPtr->numChars, entryPtr->tabOrigin, x,
entryPtr->tabOrigin, TK_NEWLINES_NOT_SPECIAL, &dummy);
}
if (roundUp && (*indexPtr < entryPtr->numChars)) {
*indexPtr += 1;
}
} else {
if (Tcl_GetInt(interp, string, indexPtr) != TCL_OK) {
goto badIndex;
}
if (*indexPtr < 0){
*indexPtr = 0;
} else if (*indexPtr > entryPtr->numChars) {
*indexPtr = entryPtr->numChars;
}
}
return TCL_OK;
}
static void
EntryScanTo(entryPtr, x)
register Entry *entryPtr;
int x;
{
int newLeftIndex;
newLeftIndex = entryPtr->scanMarkIndex
- (10*(x - entryPtr->scanMarkX))/entryPtr->avgWidth;
if (newLeftIndex >= entryPtr->numChars) {
newLeftIndex = entryPtr->scanMarkIndex = entryPtr->numChars-1;
entryPtr->scanMarkX = x;
}
if (newLeftIndex < 0) {
newLeftIndex = entryPtr->scanMarkIndex = 0;
entryPtr->scanMarkX = x;
}
if (newLeftIndex != entryPtr->leftIndex) {
entryPtr->leftIndex = newLeftIndex;
entryPtr->flags |= UPDATE_SCROLLBAR;
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
}
}
static void
EntrySelectTo(entryPtr, index)
register Entry *entryPtr;
int index;
{
int newFirst, newLast;
if ((entryPtr->selectFirst == -1) && (entryPtr->exportSelection)) {
Tk_OwnSelection(entryPtr->tkwin, XA_PRIMARY, EntryLostSelection,
(ClientData) entryPtr);
}
if (entryPtr->selectAnchor > entryPtr->numChars) {
entryPtr->selectAnchor = entryPtr->numChars;
}
if (entryPtr->selectAnchor <= index) {
newFirst = entryPtr->selectAnchor;
newLast = index;
} else {
newFirst = index;
newLast = entryPtr->selectAnchor;
if (newLast < 0) {
newFirst = newLast = -1;
}
}
if ((entryPtr->selectFirst == newFirst)
&& (entryPtr->selectLast == newLast)) {
return;
}
entryPtr->selectFirst = newFirst;
entryPtr->selectLast = newLast;
EventuallyRedraw(entryPtr);
}
static int
EntryFetchSelection(clientData, offset, buffer, maxBytes)
ClientData clientData;
int offset;
char *buffer;
int maxBytes;
{
Entry *entryPtr = (Entry *) clientData;
int count;
char *displayString;
if ((entryPtr->selectFirst < 0) || !(entryPtr->exportSelection)) {
return -1;
}
count = entryPtr->selectLast - entryPtr->selectFirst - offset;
if (count > maxBytes) {
count = maxBytes;
}
if (count <= 0) {
return 0;
}
if (entryPtr->displayString == NULL) {
displayString = entryPtr->string;
} else {
displayString = entryPtr->displayString;
}
strncpy(buffer, displayString + entryPtr->selectFirst + offset,
(size_t) count);
buffer[count] = '\0';
return count;
}
static void
EntryLostSelection(clientData)
ClientData clientData;
{
Entry *entryPtr = (Entry *) clientData;
if ((entryPtr->selectFirst != -1) && entryPtr->exportSelection) {
entryPtr->selectFirst = -1;
entryPtr->selectLast = -1;
EventuallyRedraw(entryPtr);
}
}
static void
EventuallyRedraw(entryPtr)
register Entry *entryPtr;
{
if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) {
return;
}
if (!(entryPtr->flags & REDRAW_PENDING)) {
entryPtr->flags |= REDRAW_PENDING;
Tcl_DoWhenIdle(DisplayEntry, (ClientData) entryPtr);
}
}
static void
EntryVisibleRange(entryPtr, firstPtr, lastPtr)
Entry *entryPtr;
double *firstPtr;
double *lastPtr;
{
char *displayString;
int charsInWindow, endX;
if (entryPtr->displayString == NULL) {
displayString = entryPtr->string;
} else {
displayString = entryPtr->displayString;
}
if (entryPtr->numChars == 0) {
*firstPtr = 0.0;
*lastPtr = 1.0;
} else {
charsInWindow = TkMeasureChars(entryPtr->fontPtr,
displayString + entryPtr->leftIndex,
entryPtr->numChars - entryPtr->leftIndex, entryPtr->inset,
Tk_Width(entryPtr->tkwin) - entryPtr->inset, entryPtr->inset,
TK_AT_LEAST_ONE|TK_NEWLINES_NOT_SPECIAL, &endX);
*firstPtr = ((double) entryPtr->leftIndex)/entryPtr->numChars;
*lastPtr = ((double) (entryPtr->leftIndex + charsInWindow))
/entryPtr->numChars;
}
}
static void
EntryUpdateScrollbar(entryPtr)
Entry *entryPtr;
{
char args[100];
int code;
double first, last;
Tcl_Interp *interp;
if (entryPtr->scrollCmd == NULL) {
return;
}
interp = entryPtr->interp;
Tcl_Preserve((ClientData) interp);
EntryVisibleRange(entryPtr, &first, &last);
sprintf(args, " %g %g", first, last);
code = Tcl_VarEval(interp, entryPtr->scrollCmd, args, (char *) NULL);
if (code != TCL_OK) {
Tcl_AddErrorInfo(interp,
"\n (horizontal scrolling command executed by entry)");
Tcl_BackgroundError(interp);
}
Tcl_SetResult(interp, (char *) NULL, TCL_STATIC);
Tcl_Release((ClientData) interp);
}
static void
EntryBlinkProc(clientData)
ClientData clientData;
{
register Entry *entryPtr = (Entry *) clientData;
if (!(entryPtr->flags & GOT_FOCUS) || (entryPtr->insertOffTime == 0)) {
return;
}
if (entryPtr->flags & CURSOR_ON) {
entryPtr->flags &= ~CURSOR_ON;
entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
entryPtr->insertOffTime, EntryBlinkProc, (ClientData) entryPtr);
} else {
entryPtr->flags |= CURSOR_ON;
entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
entryPtr->insertOnTime, EntryBlinkProc, (ClientData) entryPtr);
}
EventuallyRedraw(entryPtr);
}
static void
EntryFocusProc(entryPtr, gotFocus)
register Entry *entryPtr;
int gotFocus;
{
Tcl_DeleteTimerHandler(entryPtr->insertBlinkHandler);
if (gotFocus) {
entryPtr->flags |= GOT_FOCUS | CURSOR_ON;
if (entryPtr->insertOffTime != 0) {
entryPtr->insertBlinkHandler = Tcl_CreateTimerHandler(
entryPtr->insertOnTime, EntryBlinkProc,
(ClientData) entryPtr);
}
} else {
entryPtr->flags &= ~(GOT_FOCUS | CURSOR_ON);
entryPtr->insertBlinkHandler = (Tcl_TimerToken) NULL;
}
EventuallyRedraw(entryPtr);
}
static char *
EntryTextVarProc(clientData, interp, name1, name2, flags)
ClientData clientData;
Tcl_Interp *interp;
char *name1;
char *name2;
int flags;
{
register Entry *entryPtr = (Entry *) clientData;
char *value;
if (flags & TCL_TRACE_UNSETS) {
if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
Tcl_SetVar(interp, entryPtr->textVarName, entryPtr->string,
TCL_GLOBAL_ONLY);
Tcl_TraceVar(interp, entryPtr->textVarName,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, clientData);
}
return (char *) NULL;
}
value = Tcl_GetVar(interp, entryPtr->textVarName, TCL_GLOBAL_ONLY);
if (value == NULL) {
value = "";
}
if (strcmp(value, entryPtr->string) != 0) {
EntrySetValue(entryPtr, value);
}
return (char *) NULL;
}