summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/tk.h4
-rw-r--r--generic/tkEntry.c158
-rw-r--r--generic/tkEvent.c6
-rw-r--r--generic/tkFont.c4
-rw-r--r--generic/tkListbox.c156
-rw-r--r--generic/tkMenu.c7
-rw-r--r--generic/tkOption.c31
-rw-r--r--generic/tkScrollbar.c2
-rw-r--r--generic/tkText.c131
-rw-r--r--generic/tkText.h5
-rw-r--r--generic/tkTextBTree.c2
-rw-r--r--generic/tkTextDisp.c250
-rw-r--r--generic/tkTextTag.c8
-rw-r--r--generic/ttk/ttkButton.c4
-rw-r--r--generic/ttk/ttkNotebook.c2
15 files changed, 594 insertions, 176 deletions
diff --git a/generic/tk.h b/generic/tk.h
index 4a655a4..75d82ba 100644
--- a/generic/tk.h
+++ b/generic/tk.h
@@ -75,10 +75,10 @@ extern "C" {
#define TK_MAJOR_VERSION 8
#define TK_MINOR_VERSION 6
#define TK_RELEASE_LEVEL TCL_FINAL_RELEASE
-#define TK_RELEASE_SERIAL 4
+#define TK_RELEASE_SERIAL 5
#define TK_VERSION "8.6"
-#define TK_PATCH_LEVEL "8.6.4"
+#define TK_PATCH_LEVEL "8.6.5"
/*
* A special definition used to allow this header file to be included from
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index 3ad9acd..ea8d7f1 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -133,7 +133,7 @@ static const Tk_OptionSpec entryOptSpec[] = {
0, DEF_ENTRY_SELECT_BD_MONO, 0},
{TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
- TK_CONFIG_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0},
+ TK_OPTION_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0},
{TK_OPTION_STRING, "-show", "show", "Show",
DEF_ENTRY_SHOW, -1, Tk_Offset(Entry, showChar),
TK_OPTION_NULL_OK, 0, 0},
@@ -279,23 +279,23 @@ static const Tk_OptionSpec sbOptSpec[] = {
0, DEF_ENTRY_SELECT_BD_MONO, 0},
{TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_ENTRY_SELECT_FG_COLOR, -1, Tk_Offset(Entry, selFgColorPtr),
- TK_CONFIG_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0},
+ TK_OPTION_NULL_OK, DEF_ENTRY_SELECT_FG_MONO, 0},
{TK_OPTION_STRING_TABLE, "-state", "state", "State",
DEF_ENTRY_STATE, -1, Tk_Offset(Entry, state),
0, stateStrings, 0},
{TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
DEF_ENTRY_TAKE_FOCUS, -1, Tk_Offset(Entry, takeFocus),
- TK_CONFIG_NULL_OK, 0, 0},
+ TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-textvariable", "textVariable", "Variable",
DEF_ENTRY_TEXT_VARIABLE, -1, Tk_Offset(Entry, textVarName),
- TK_CONFIG_NULL_OK, 0, 0},
+ TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_DOUBLE, "-to", "to", "To",
DEF_SPINBOX_TO, -1, Tk_Offset(Spinbox, toValue), 0, 0, 0},
{TK_OPTION_STRING_TABLE, "-validate", "validate", "Validate",
DEF_ENTRY_VALIDATE, -1, Tk_Offset(Entry, validate),
0, validateStrings, 0},
{TK_OPTION_STRING, "-validatecommand", "validateCommand","ValidateCommand",
- NULL, -1, Tk_Offset(Entry, validateCmd), TK_CONFIG_NULL_OK, 0, 0},
+ NULL, -1, Tk_Offset(Entry, validateCmd), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-values", "values", "Values",
DEF_SPINBOX_VALUES, -1, Tk_Offset(Spinbox, valueStr),
TK_OPTION_NULL_OK, 0, 0},
@@ -307,7 +307,7 @@ static const Tk_OptionSpec sbOptSpec[] = {
DEF_SPINBOX_WRAP, -1, Tk_Offset(Spinbox, wrap), 0, 0, 0},
{TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
DEF_ENTRY_SCROLL_COMMAND, -1, Tk_Offset(Entry, scrollCmd),
- TK_CONFIG_NULL_OK, 0, 0},
+ TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_END, NULL, NULL, NULL, NULL, 0, -1, 0, 0, 0}
};
@@ -390,8 +390,8 @@ static const char *const selElementNames[] = {
*/
static int ConfigureEntry(Tcl_Interp *interp, Entry *entryPtr,
- int objc, Tcl_Obj *const objv[], int flags);
-static void DeleteChars(Entry *entryPtr, int index, int count);
+ int objc, Tcl_Obj *const objv[]);
+static int DeleteChars(Entry *entryPtr, int index, int count);
static void DestroyEntry(void *memPtr);
static void DisplayEntry(ClientData clientData);
static void EntryBlinkProc(ClientData clientData);
@@ -417,7 +417,7 @@ static int EntryValidateChange(Entry *entryPtr, const char *change,
static void ExpandPercents(Entry *entryPtr, const char *before,
const char *change, const char *newStr, int index,
int type, Tcl_DString *dsPtr);
-static void EntryValueChanged(Entry *entryPtr,
+static int EntryValueChanged(Entry *entryPtr,
const char *newValue);
static void EntryVisibleRange(Entry *entryPtr,
double *firstPtr, double *lastPtr);
@@ -427,7 +427,7 @@ static int EntryWidgetObjCmd(ClientData clientData,
static void EntryWorldChanged(ClientData instanceData);
static int GetEntryIndex(Tcl_Interp *interp, Entry *entryPtr,
const char *string, int *indexPtr);
-static void InsertChars(Entry *entryPtr, int index, const char *string);
+static int InsertChars(Entry *entryPtr, int index, const char *string);
/*
* These forward declarations are the spinbox specific ones:
@@ -554,7 +554,7 @@ Tk_EntryObjCmd(
if ((Tk_InitOptions(interp, (char *) entryPtr, optionTable, tkwin)
!= TCL_OK) ||
- (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK)) {
+ (ConfigureEntry(interp, entryPtr, objc-2, objv+2) != TCL_OK)) {
Tk_DestroyWindow(entryPtr->tkwin);
return TCL_ERROR;
}
@@ -659,12 +659,12 @@ EntryWidgetObjCmd(
}
Tcl_SetObjResult(interp, objPtr);
} else {
- result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0);
+ result = ConfigureEntry(interp, entryPtr, objc-2, objv+2);
}
break;
case COMMAND_DELETE: {
- int first, last;
+ int first, last, code;
if ((objc < 3) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
@@ -681,7 +681,10 @@ EntryWidgetObjCmd(
goto error;
}
if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
- DeleteChars(entryPtr, first, last - first);
+ code = DeleteChars(entryPtr, first, last - first);
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -722,7 +725,7 @@ EntryWidgetObjCmd(
}
case COMMAND_INSERT: {
- int index;
+ int index, code;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "index text");
@@ -733,7 +736,10 @@ EntryWidgetObjCmd(
goto error;
}
if (entryPtr->state == STATE_NORMAL) {
- InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ code = InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -1082,8 +1088,7 @@ ConfigureEntry(
Entry *entryPtr, /* Information about widget; may or may not
* already have values for some fields. */
int objc, /* Number of valid entries in argv. */
- Tcl_Obj *const objv[], /* Argument objects. */
- int flags) /* Flags to pass to Tk_ConfigureWidget. */
+ Tcl_Obj *const objv[]) /* Argument objects. */
{
Tk_SavedOptions savedOptions;
Tk_3DBorder border;
@@ -1098,6 +1103,7 @@ ConfigureEntry(
int valuesChanged = 0; /* lint initialization */
double oldFrom = 0.0; /* lint initialization */
double oldTo = 0.0; /* lint initialization */
+ int code;
/*
* Eliminate any existing trace on a variable monitored by the entry.
@@ -1305,6 +1311,17 @@ ConfigureEntry(
value = Tcl_GetVar2(interp, entryPtr->textVarName, NULL, TCL_GLOBAL_ONLY);
if (value == NULL) {
+
+ /*
+ * Since any trace on the textvariable was eliminated above,
+ * the only possible reason for EntryValueChanged to return
+ * an error is that the textvariable lives in a namespace
+ * that does not (yet) exist. Indeed, namespaces are not
+ * automatically created as needed. Don't trap this error
+ * here, better do it below when attempting to trace the
+ * variable.
+ */
+
EntryValueChanged(entryPtr, NULL);
} else {
EntrySetValue(entryPtr, value);
@@ -1323,7 +1340,13 @@ ConfigureEntry(
*/
Tcl_ListObjIndex(interp, sbPtr->listObj, 0, &objPtr);
- EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
+
+ /*
+ * No check for error return here as well, because any possible
+ * error will be trapped below when attempting tracing.
+ */
+
+ EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
} else if ((sbPtr->valueStr == NULL)
&& !DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)
&& (!DOUBLES_EQ(sbPtr->fromValue, oldFrom)
@@ -1346,6 +1369,12 @@ ConfigureEntry(
dvalue = sbPtr->fromValue;
}
sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
+
+ /*
+ * No check for error return here as well, because any possible
+ * error will be trapped below when attempting tracing.
+ */
+
EntryValueChanged(entryPtr, sbPtr->formatBuf);
}
}
@@ -1357,10 +1386,13 @@ ConfigureEntry(
if ((entryPtr->textVarName != NULL)
&& !(entryPtr->flags & ENTRY_VAR_TRACED)) {
- Tcl_TraceVar2(interp, entryPtr->textVarName,
+ code = Tcl_TraceVar2(interp, entryPtr->textVarName,
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, entryPtr);
- entryPtr->flags |= ENTRY_VAR_TRACED;
+ if (code != TCL_OK) {
+ return TCL_ERROR;
+ }
+ entryPtr->flags |= ENTRY_VAR_TRACED;
}
EntryWorldChanged(entryPtr);
@@ -1680,7 +1712,7 @@ DisplayEntry(
Tk_CharBbox(entryPtr->textLayout, entryPtr->insertPos, &cursorX, NULL,
NULL, NULL);
cursorX += entryPtr->layoutX;
- cursorX -= (entryPtr->insertWidth)/2;
+ cursorX -= (entryPtr->insertWidth == 1) ? 1 : (entryPtr->insertWidth)/2;
Tk_SetCaretPos(entryPtr->tkwin, cursorX, baseY - fm.ascent,
fm.ascent + fm.descent);
if (entryPtr->insertPos >= entryPtr->leftIndex && cursorX < xBound) {
@@ -1993,7 +2025,8 @@ EntryComputeGeometry(
* Add new characters to an entry widget.
*
* Results:
- * None.
+ * A standard Tcl result. If an error occurred then an error message is
+ * left in the interp's result.
*
* Side effects:
* New information gets added to entryPtr; it will be redisplayed soon,
@@ -2002,12 +2035,12 @@ EntryComputeGeometry(
*----------------------------------------------------------------------
*/
-static void
+static int
InsertChars(
Entry *entryPtr, /* Entry that is to get the new elements. */
int index, /* Add the new elements before this character
* index. */
- const char *value) /* New characters to add (NULL-terminated
+ const char *value) /* New characters to add (NULL-terminated
* string). */
{
ptrdiff_t byteIndex;
@@ -2020,7 +2053,7 @@ InsertChars(
byteIndex = Tcl_UtfAtIndex(string, index) - string;
byteCount = strlen(value);
if (byteCount == 0) {
- return;
+ return TCL_OK;
}
newByteCount = entryPtr->numBytes + byteCount + 1;
@@ -2034,7 +2067,7 @@ InsertChars(
EntryValidateChange(entryPtr, value, newStr, index,
VALIDATE_INSERT) != TCL_OK) {
ckfree(newStr);
- return;
+ return TCL_OK;
}
ckfree((char *)string);
@@ -2082,7 +2115,7 @@ InsertChars(
if (entryPtr->insertPos >= index) {
entryPtr->insertPos += charsAdded;
}
- EntryValueChanged(entryPtr, NULL);
+ return EntryValueChanged(entryPtr, NULL);
}
/*
@@ -2093,7 +2126,8 @@ InsertChars(
* Remove one or more characters from an entry widget.
*
* Results:
- * None.
+ * A standard Tcl result. If an error occurred then an error message is
+ * left in the interp's result.
*
* Side effects:
* Memory gets freed, the entry gets modified and (eventually)
@@ -2102,7 +2136,7 @@ InsertChars(
*----------------------------------------------------------------------
*/
-static void
+static int
DeleteChars(
Entry *entryPtr, /* Entry widget to modify. */
int index, /* Index of first character to delete. */
@@ -2116,7 +2150,7 @@ DeleteChars(
count = entryPtr->numChars - index;
}
if (count <= 0) {
- return;
+ return TCL_OK;
}
string = entryPtr->string;
@@ -2138,7 +2172,7 @@ DeleteChars(
VALIDATE_DELETE) != TCL_OK) {
ckfree(newStr);
ckfree(toDelete);
- return;
+ return TCL_OK;
}
ckfree(toDelete);
@@ -2197,7 +2231,7 @@ DeleteChars(
entryPtr->insertPos = index;
}
}
- EntryValueChanged(entryPtr, NULL);
+ return EntryValueChanged(entryPtr, NULL);
}
/*
@@ -2210,7 +2244,8 @@ DeleteChars(
* is one, and does other bookkeeping such as arranging for redisplay.
*
* Results:
- * None.
+ * A standard Tcl result. If an error occurred then an error message is
+ * left in the interp's result.
*
* Side effects:
* None.
@@ -2218,7 +2253,7 @@ DeleteChars(
*----------------------------------------------------------------------
*/
-static void
+static int
EntryValueChanged(
Entry *entryPtr, /* Entry whose value just changed. */
const char *newValue) /* If this value is not NULL, we first force
@@ -2232,7 +2267,7 @@ EntryValueChanged(
newValue = NULL;
} else {
newValue = Tcl_SetVar2(entryPtr->interp, entryPtr->textVarName,
- NULL, entryPtr->string, TCL_GLOBAL_ONLY);
+ NULL, entryPtr->string, TCL_GLOBAL_ONLY|TCL_LEAVE_ERR_MSG);
}
if ((newValue != NULL) && (strcmp(newValue, entryPtr->string) != 0)) {
@@ -2254,6 +2289,19 @@ EntryValueChanged(
EntryComputeGeometry(entryPtr);
EventuallyRedraw(entryPtr);
}
+
+ /*
+ * An error may have happened when setting the textvariable in case there
+ * is a trace on that variable and the trace proc triggered an error.
+ * Another possibility is that the textvariable is in a namespace that
+ * does not (yet) exist.
+ * Signal this error.
+ */
+
+ if ((entryPtr->textVarName != NULL) && (newValue == NULL)) {
+ return TCL_ERROR;
+ }
+ return TCL_OK;
}
/*
@@ -3611,7 +3659,7 @@ Tk_SpinboxObjCmd(
Tk_DestroyWindow(entryPtr->tkwin);
return TCL_ERROR;
}
- if (ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0) != TCL_OK) {
+ if (ConfigureEntry(interp, entryPtr, objc-2, objv+2) != TCL_OK) {
goto error;
}
@@ -3719,12 +3767,12 @@ SpinboxWidgetObjCmd(
}
Tcl_SetObjResult(interp, objPtr);
} else {
- result = ConfigureEntry(interp, entryPtr, objc-2, objv+2, 0);
+ result = ConfigureEntry(interp, entryPtr, objc-2, objv+2);
}
break;
case SB_CMD_DELETE: {
- int first, last;
+ int first, last, code;
if ((objc < 3) || (objc > 4)) {
Tcl_WrongNumArgs(interp, 2, objv, "firstIndex ?lastIndex?");
@@ -3743,7 +3791,10 @@ SpinboxWidgetObjCmd(
}
}
if ((last >= first) && (entryPtr->state == STATE_NORMAL)) {
- DeleteChars(entryPtr, first, last - first);
+ code = DeleteChars(entryPtr, first, last - first);
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -3803,7 +3854,7 @@ SpinboxWidgetObjCmd(
}
case SB_CMD_INSERT: {
- int index;
+ int index, code;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "index text");
@@ -3814,7 +3865,10 @@ SpinboxWidgetObjCmd(
goto error;
}
if (entryPtr->state == STATE_NORMAL) {
- InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ code = InsertChars(entryPtr, index, Tcl_GetString(objv[3]));
+ if (code != TCL_OK) {
+ goto error;
+ }
}
break;
}
@@ -4024,16 +4078,22 @@ SpinboxWidgetObjCmd(
break;
}
- case SB_CMD_SET:
+ case SB_CMD_SET: {
+ int code = TCL_OK;
+
if (objc > 3) {
Tcl_WrongNumArgs(interp, 2, objv, "?string?");
goto error;
}
if (objc == 3) {
- EntryValueChanged(entryPtr, Tcl_GetString(objv[2]));
+ code = EntryValueChanged(entryPtr, Tcl_GetString(objv[2]));
+ if (code != TCL_OK) {
+ goto error;
+ }
}
Tcl_SetObjResult(interp, Tcl_NewStringObj(entryPtr->string, -1));
break;
+ }
case SB_CMD_VALIDATE: {
int code;
@@ -4174,7 +4234,7 @@ GetSpinboxElement(
* TCL_OK.
*
* Side effects:
- * An background error condition may arise when invoking the callback.
+ * A background error condition may arise when invoking the callback.
* The widget value may change.
*
*--------------------------------------------------------------
@@ -4205,6 +4265,7 @@ SpinboxInvoke(
return TCL_OK;
}
+ code = TCL_OK;
if (fabs(sbPtr->increment) > MIN_DBL_VAL) {
if (sbPtr->listObj != NULL) {
Tcl_Obj *objPtr;
@@ -4250,7 +4311,7 @@ SpinboxInvoke(
}
}
Tcl_ListObjIndex(interp, sbPtr->listObj, sbPtr->eIndex, &objPtr);
- EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
+ code = EntryValueChanged(entryPtr, Tcl_GetString(objPtr));
} else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) {
double dvalue;
@@ -4297,9 +4358,12 @@ SpinboxInvoke(
}
}
sprintf(sbPtr->formatBuf, sbPtr->valueFormat, dvalue);
- EntryValueChanged(entryPtr, sbPtr->formatBuf);
+ code = EntryValueChanged(entryPtr, sbPtr->formatBuf);
}
}
+ if (code != TCL_OK) {
+ return TCL_ERROR;
+ }
if (sbPtr->command != NULL) {
Tcl_DStringInit(&script);
diff --git a/generic/tkEvent.c b/generic/tkEvent.c
index bcc6d98..95aeda1 100644
--- a/generic/tkEvent.c
+++ b/generic/tkEvent.c
@@ -2039,6 +2039,12 @@ TkFinalize(
{
ExitHandler *exitPtr;
+#if defined(_WIN32) && !defined(STATIC_BUILD)
+ if (!tclStubsPtr) {
+ return;
+ }
+#endif
+
Tcl_DeleteExitHandler(TkFinalize, NULL);
Tcl_MutexLock(&exitMutex);
diff --git a/generic/tkFont.c b/generic/tkFont.c
index 447f9e1..102fc6e 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -2067,14 +2067,14 @@ Tk_ComputeTextLayout(
NewChunk(&layoutPtr, &maxChunks, start, 1, curX, newX,
baseline)->numDisplayChars = -1;
start++;
+ curX = newX;
+ flags &= ~TK_AT_LEAST_ONE;
if ((start < end) &&
((wrapLength <= 0) || (newX <= wrapLength))) {
/*
* More chars can still fit on this line.
*/
- curX = newX;
- flags &= ~TK_AT_LEAST_ONE;
continue;
}
} else {
diff --git a/generic/tkListbox.c b/generic/tkListbox.c
index 437973a..c7effdd 100644
--- a/generic/tkListbox.c
+++ b/generic/tkListbox.c
@@ -90,14 +90,14 @@ typedef struct {
* display. */
int topIndex; /* Index of top-most element visible in
* window. */
- int fullLines; /* Number of lines that fit are completely
+ int fullLines; /* Number of lines that are completely
* visible in window. There may be one
* additional line at the bottom that is
* partially visible. */
int partialLine; /* 0 means that the window holds exactly
* fullLines lines. 1 means that there is one
* additional line that is partially
- * visble. */
+ * visible. */
int setGrid; /* Non-zero means pass gridding information to
* window manager. */
@@ -114,7 +114,8 @@ typedef struct {
int xOffset; /* The left edge of each string in the listbox
* is offset to the left by this many pixels
* (0 means no offset, positive means there is
- * an offset). */
+ * an offset). This is x scrolling information
+ * is not linked to justification. */
/*
* Information about what's selected or active, if any.
@@ -131,7 +132,7 @@ typedef struct {
int active; /* Index of "active" element (the one that has
* been selected by keyboard traversal). -1
* means none. */
- int activeStyle; /* style in which to draw the active element.
+ int activeStyle; /* Style in which to draw the active element.
* One of: underline, none, dotbox */
/*
@@ -165,6 +166,7 @@ typedef struct {
Pixmap gray; /* Pixmap for displaying disabled text. */
int flags; /* Various flag bits: see below for
* definitions. */
+ Tk_Justify justify; /* Justification. */
} Listbox;
/*
@@ -197,7 +199,7 @@ typedef struct {
* be updated.
* GOT_FOCUS: Non-zero means this widget currently has the
* input focus.
- * MAXWIDTH_IS_STALE: Stored maxWidth may be out-of-date
+ * MAXWIDTH_IS_STALE: Stored maxWidth may be out-of-date.
* LISTBOX_DELETED: This listbox has been effectively destroyed.
*/
@@ -275,6 +277,8 @@ static const Tk_OptionSpec optionSpecs[] = {
{TK_OPTION_PIXELS, "-highlightthickness", "highlightThickness",
"HighlightThickness", DEF_LISTBOX_HIGHLIGHT_WIDTH, -1,
Tk_Offset(Listbox, highlightWidth), 0, 0, 0},
+ {TK_OPTION_JUSTIFY, "-justify", "justify", "Justify",
+ DEF_LISTBOX_JUSTIFY, -1, Tk_Offset(Listbox, justify), 0, 0, 0},
{TK_OPTION_RELIEF, "-relief", "relief", "Relief",
DEF_LISTBOX_RELIEF, -1, Tk_Offset(Listbox, relief), 0, 0, 0},
{TK_OPTION_BORDER, "-selectbackground", "selectBackground", "Foreground",
@@ -285,7 +289,7 @@ static const Tk_OptionSpec optionSpecs[] = {
Tk_Offset(Listbox, selBorderWidth), 0, 0, 0},
{TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_LISTBOX_SELECT_FG_COLOR, -1, Tk_Offset(Listbox, selFgColorPtr),
- TK_CONFIG_NULL_OK, DEF_LISTBOX_SELECT_FG_MONO, 0},
+ TK_OPTION_NULL_OK, DEF_LISTBOX_SELECT_FG_MONO, 0},
{TK_OPTION_STRING, "-selectmode", "selectMode", "SelectMode",
DEF_LISTBOX_SELECT_MODE, -1, Tk_Offset(Listbox, selectMode),
TK_OPTION_NULL_OK, 0, 0},
@@ -313,7 +317,7 @@ static const Tk_OptionSpec optionSpecs[] = {
/*
* The itemAttrOptionSpecs table defines the valid configuration options for
- * listbox items
+ * listbox items.
*/
static const Tk_OptionSpec itemAttrOptionSpecs[] = {
@@ -340,7 +344,7 @@ static const Tk_OptionSpec itemAttrOptionSpecs[] = {
};
/*
- * The following tables define the listbox widget commands (and sub- commands)
+ * The following tables define the listbox widget commands (and sub-commands)
* and map the indexes into the string tables into enumerated types used to
* dispatch the listbox widget command.
*/
@@ -386,7 +390,7 @@ enum indices {
static void ChangeListboxOffset(Listbox *listPtr, int offset);
static void ChangeListboxView(Listbox *listPtr, int index);
static int ConfigureListbox(Tcl_Interp *interp, Listbox *listPtr,
- int objc, Tcl_Obj *const objv[], int flags);
+ int objc, Tcl_Obj *const objv[]);
static int ConfigureListboxItem(Tcl_Interp *interp,
Listbox *listPtr, ItemAttr *attrs, int objc,
Tcl_Obj *const objv[], int index);
@@ -408,6 +412,7 @@ static void ListboxEventProc(ClientData clientData,
static int ListboxFetchSelection(ClientData clientData,
int offset, char *buffer, int maxBytes);
static void ListboxLostSelection(ClientData clientData);
+static void GenerateListboxSelectEvent(Listbox *listPtr);
static void EventuallyRedrawRange(Listbox *listPtr,
int first, int last);
static void ListboxScanTo(Listbox *listPtr, int x, int y);
@@ -435,6 +440,7 @@ static char * ListboxListVarProc(ClientData clientData,
const char *name2, int flags);
static void MigrateHashEntries(Tcl_HashTable *table,
int first, int last, int offset);
+static int GetMaxOffset(Listbox *listPtr);
/*
* The structure below defines button class behavior by means of procedures
@@ -545,6 +551,7 @@ Tk_ListboxObjCmd(
listPtr->cursor = None;
listPtr->state = STATE_NORMAL;
listPtr->gray = None;
+ listPtr->justify = TK_JUSTIFY_LEFT;
/*
* Keep a hold of the associated tkwin until we destroy the listbox,
@@ -566,7 +573,7 @@ Tk_ListboxObjCmd(
return TCL_ERROR;
}
- if (ConfigureListbox(interp, listPtr, objc-2, objv+2, 0) != TCL_OK) {
+ if (ConfigureListbox(interp, listPtr, objc-2, objv+2) != TCL_OK) {
Tk_DestroyWindow(listPtr->tkwin);
return TCL_ERROR;
}
@@ -612,7 +619,7 @@ ListboxWidgetObjCmd(
/*
* Parse the command by looking up the second argument in the list of
- * valid subcommand names
+ * valid subcommand names.
*/
result = Tcl_GetIndexFromObj(interp, objv[1], commandNames,
@@ -697,7 +704,7 @@ ListboxWidgetObjCmd(
Tcl_SetObjResult(interp, objPtr);
result = TCL_OK;
} else {
- result = ConfigureListbox(interp, listPtr, objc-2, objv+2, 0);
+ result = ConfigureListbox(interp, listPtr, objc-2, objv+2);
}
break;
@@ -1075,6 +1082,7 @@ ListboxBboxSubCmd(
Listbox *listPtr, /* Information about the listbox */
int index) /* Index of the element to get bbox info on */
{
+ register Tk_Window tkwin = listPtr->tkwin;
int lastVisibleIndex;
/*
@@ -1110,7 +1118,15 @@ ListboxBboxSubCmd(
Tk_GetFontMetrics(listPtr->tkfont, &fm);
pixelWidth = Tk_TextWidth(listPtr->tkfont, stringRep, stringLen);
- x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset;
+ if (listPtr->justify == TK_JUSTIFY_LEFT) {
+ x = (listPtr->inset + listPtr->selBorderWidth) - listPtr->xOffset;
+ } else if (listPtr->justify == TK_JUSTIFY_RIGHT) {
+ x = Tk_Width(tkwin) - (listPtr->inset + listPtr->selBorderWidth)
+ - pixelWidth - listPtr->xOffset + GetMaxOffset(listPtr);
+ } else {
+ x = (Tk_Width(tkwin) - pixelWidth)/2
+ - listPtr->xOffset + GetMaxOffset(listPtr)/2;
+ }
y = ((index - listPtr->topIndex)*listPtr->lineHeight)
+ listPtr->inset + listPtr->selBorderWidth;
results[0] = Tcl_NewIntObj(x);
@@ -1542,8 +1558,7 @@ ConfigureListbox(
register Listbox *listPtr, /* Information about widget; may or may not
* already have values for some fields. */
int objc, /* Number of valid entries in argv. */
- Tcl_Obj *const objv[], /* Arguments. */
- int flags) /* Flags to pass to Tk_ConfigureWidget. */
+ Tcl_Obj *const objv[]) /* Arguments. */
{
Tk_SavedOptions savedOptions;
Tcl_Obj *oldListObj = NULL;
@@ -1837,6 +1852,7 @@ DisplayListbox(
* or right edge of the listbox is
* off-screen. */
Pixmap pixmap;
+ int textWidth;
listPtr->flags &= ~REDRAW_PENDING;
if (listPtr->flags & LISTBOX_DELETED) {
@@ -2016,7 +2032,7 @@ DisplayListbox(
} else {
/*
* If there is an item attributes record for this item, draw
- * the background box and set the foreground color accordingly
+ * the background box and set the foreground color accordingly.
*/
if (entry != NULL) {
@@ -2056,12 +2072,24 @@ DisplayListbox(
* Draw the actual text of this item.
*/
+ Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement);
+ stringRep = Tcl_GetStringFromObj(curElement, &stringLen);
+ textWidth = Tk_TextWidth(listPtr->tkfont, stringRep, stringLen);
+
Tk_GetFontMetrics(listPtr->tkfont, &fm);
y += fm.ascent + listPtr->selBorderWidth;
- x = listPtr->inset + listPtr->selBorderWidth - listPtr->xOffset;
- Tcl_ListObjIndex(listPtr->interp, listPtr->listObj, i, &curElement);
- stringRep = Tcl_GetStringFromObj(curElement, &stringLen);
- Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont,
+
+ if (listPtr->justify == TK_JUSTIFY_LEFT) {
+ x = (listPtr->inset + listPtr->selBorderWidth) - listPtr->xOffset;
+ } else if (listPtr->justify == TK_JUSTIFY_RIGHT) {
+ x = Tk_Width(tkwin) - (listPtr->inset + listPtr->selBorderWidth)
+ - textWidth - listPtr->xOffset + GetMaxOffset(listPtr);
+ } else {
+ x = (Tk_Width(tkwin) - textWidth)/2
+ - listPtr->xOffset + GetMaxOffset(listPtr)/2;
+ }
+
+ Tk_DrawChars(listPtr->display, pixmap, gc, listPtr->tkfont,
stringRep, stringLen, x, y);
/*
@@ -2458,7 +2486,7 @@ ListboxDeleteSubCmd(
/*
* Check width of the element. We only have to check if widthChanged
* has not already been set to 1, because we only need one maxWidth
- * element to disappear for us to have to recompute the width
+ * element to disappear for us to have to recompute the width.
*/
if (widthChanged == 0) {
@@ -2735,7 +2763,11 @@ GetListboxIndex(
stringRep = Tcl_GetString(indexObj);
if (stringRep[0] == '@') {
- /* @x,y index */
+
+ /*
+ * @x,y index
+ */
+
int y;
const char *start;
char *end;
@@ -2844,9 +2876,7 @@ ChangeListboxOffset(
*/
offset += listPtr->xScrollUnit / 2;
- maxOffset = listPtr->maxWidth - (Tk_Width(listPtr->tkwin) -
- 2*listPtr->inset - 2*listPtr->selBorderWidth)
- + listPtr->xScrollUnit - 1;
+ maxOffset = GetMaxOffset(listPtr);
if (offset > maxOffset) {
offset = maxOffset;
}
@@ -2887,9 +2917,7 @@ ListboxScanTo(
int newTopIndex, newOffset, maxIndex, maxOffset;
maxIndex = listPtr->nElements - listPtr->fullLines;
- maxOffset = listPtr->maxWidth + (listPtr->xScrollUnit - 1)
- - (Tk_Width(listPtr->tkwin) - 2*listPtr->inset
- - 2*listPtr->selBorderWidth - listPtr->xScrollUnit);
+ maxOffset = GetMaxOffset(listPtr);
/*
* Compute new top line for screen by amplifying the difference between
@@ -3170,12 +3198,46 @@ ListboxLostSelection(
if ((listPtr->exportSelection) && (listPtr->nElements > 0)) {
ListboxSelect(listPtr, 0, listPtr->nElements-1, 0);
+ GenerateListboxSelectEvent(listPtr);
}
}
/*
*----------------------------------------------------------------------
*
+ * GenerateListboxSelectEvent --
+ *
+ * Send an event that the listbox selection was updated. This is
+ * equivalent to event generate $listboxWidget <<ListboxSelect>>
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * Any side effect possible, depending on bindings to this event.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GenerateListboxSelectEvent(
+ Listbox *listPtr) /* Information about widget. */
+{
+ union {XEvent general; XVirtualEvent virtual;} event;
+
+ memset(&event, 0, sizeof(event));
+ event.general.xany.type = VirtualEvent;
+ event.general.xany.serial = NextRequest(Tk_Display(listPtr->tkwin));
+ event.general.xany.send_event = False;
+ event.general.xany.window = Tk_WindowId(listPtr->tkwin);
+ event.general.xany.display = Tk_Display(listPtr->tkwin);
+ event.virtual.name = Tk_GetUid("ListboxSelect");
+ Tk_HandleEvent(&event.general);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* EventuallyRedrawRange --
*
* Ensure that a given range of elements is eventually redrawn on the
@@ -3431,7 +3493,7 @@ ListboxListVarProc(
/*
* If the list length has decreased, then we should clean up selection and
- * attributes information for elements past the end of the new list
+ * attributes information for elements past the end of the new list.
*/
oldLength = listPtr->nElements;
@@ -3549,6 +3611,42 @@ MigrateHashEntries(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * GetMaxOffset --
+ *
+ * Passing in a listbox pointer, returns the maximum offset for the box,
+ * i.e. the maximum possible horizontal scrolling value (in pixels).
+ *
+ * Results:
+ * Listbox's maxOffset.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+*/
+static int GetMaxOffset(
+ register Listbox *listPtr)
+{
+ int maxOffset;
+
+ maxOffset = listPtr->maxWidth -
+ (Tk_Width(listPtr->tkwin) - 2*listPtr->inset -
+ 2*listPtr->selBorderWidth) + listPtr->xScrollUnit - 1;
+ if (maxOffset < 0) {
+
+ /*
+ * Listbox is larger in width than its largest width item.
+ */
+
+ maxOffset = 0;
+ }
+ maxOffset -= maxOffset % listPtr->xScrollUnit;
+
+ return maxOffset;
+}
+/*
* Local Variables:
* mode: c
* c-basic-offset: 4
diff --git a/generic/tkMenu.c b/generic/tkMenu.c
index 354d329..d24516f 100644
--- a/generic/tkMenu.c
+++ b/generic/tkMenu.c
@@ -885,9 +885,14 @@ MenuWidgetObjCmd(
* Tearoff menus are posted differently on Mac and Windows than
* non-tearoffs. TkpPostMenu does not actually map the menu's window
* on those platforms, and popup menus have to be handled specially.
+ * Also, menubar menues are not intended to be posted (bug 1567681,
+ * 2160206).
*/
- if (menuPtr->menuType != TEAROFF_MENU) {
+ if (menuPtr->menuType == MENUBAR) {
+ Tcl_AppendResult(interp, "a menubar menu cannot be posted", NULL);
+ return TCL_ERROR;
+ } else if (menuPtr->menuType != TEAROFF_MENU) {
result = TkpPostMenu(interp, menuPtr, x, y);
} else {
result = TkPostTearoffMenu(interp, menuPtr, x, y);
diff --git a/generic/tkOption.c b/generic/tkOption.c
index 75dc3b9..24e7fb3 100644
--- a/generic/tkOption.c
+++ b/generic/tkOption.c
@@ -560,7 +560,7 @@ Tk_GetOption(
count -= levelPtr[-1].bases[currentStack];
}
- if (currentStack && CLASS) {
+ if (currentStack & CLASS) {
nodeId = winClassId;
} else {
nodeId = winNameId;
@@ -1080,7 +1080,7 @@ ReadOptionFile(
* TK_MAX_PRIO. */
{
const char *realName;
- char *buffer;
+ Tcl_Obj *buffer;
int result, bufferSize;
Tcl_Channel chan;
Tcl_DString newName;
@@ -1108,24 +1108,10 @@ ReadOptionFile(
return TCL_ERROR;
}
- /*
- * Compute size of file by seeking to the end of the file. This will
- * overallocate if we are performing CRLF translation.
- */
-
- bufferSize = (int) Tcl_Seek(chan, (Tcl_WideInt) 0, SEEK_END);
- Tcl_Seek(chan, (Tcl_WideInt) 0, SEEK_SET);
-
- if (bufferSize < 0) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "error seeking to end of file \"%s\": %s",
- fileName, Tcl_PosixError(interp)));
- Tcl_Close(NULL, chan);
- return TCL_ERROR;
- }
-
- buffer = ckalloc(bufferSize + 1);
- bufferSize = Tcl_Read(chan, buffer, bufferSize);
+ buffer = Tcl_NewObj();
+ Tcl_IncrRefCount(buffer);
+ Tcl_SetChannelOption(NULL, chan, "-encoding", "utf-8");
+ bufferSize = Tcl_ReadChars(chan, buffer, -1, 0);
if (bufferSize < 0) {
Tcl_SetObjResult(interp, Tcl_ObjPrintf(
"error reading file \"%s\": %s",
@@ -1134,9 +1120,8 @@ ReadOptionFile(
return TCL_ERROR;
}
Tcl_Close(NULL, chan);
- buffer[bufferSize] = 0;
- result = AddFromString(interp, tkwin, buffer, priority);
- ckfree(buffer);
+ result = AddFromString(interp, tkwin, Tcl_GetString(buffer), priority);
+ Tcl_DecrRefCount(buffer);
return result;
}
diff --git a/generic/tkScrollbar.c b/generic/tkScrollbar.c
index d453187..5017d30 100644
--- a/generic/tkScrollbar.c
+++ b/generic/tkScrollbar.c
@@ -622,6 +622,8 @@ TkScrollbarEventProc(
TkScrollbarEventuallyRedraw(scrollPtr);
}
}
+ } else if (eventPtr->type == MapNotify) {
+ TkScrollbarEventuallyRedraw(scrollPtr);
}
}
diff --git a/generic/tkText.c b/generic/tkText.c
index b002068..3079417 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -211,18 +211,18 @@ static const Tk_OptionSpec optionSpecs[] = {
TK_OPTION_NULL_OK, DEF_TEXT_SELECT_BD_MONO, 0},
{TK_OPTION_COLOR, "-selectforeground", "selectForeground", "Background",
DEF_TEXT_SELECT_FG_COLOR, -1, Tk_Offset(TkText, selFgColorPtr),
- TK_CONFIG_NULL_OK, DEF_TEXT_SELECT_FG_MONO, 0},
+ TK_OPTION_NULL_OK, DEF_TEXT_SELECT_FG_MONO, 0},
{TK_OPTION_BOOLEAN, "-setgrid", "setGrid", "SetGrid",
DEF_TEXT_SET_GRID, -1, Tk_Offset(TkText, setGrid), 0, 0, 0},
{TK_OPTION_PIXELS, "-spacing1", "spacing1", "Spacing",
DEF_TEXT_SPACING1, -1, Tk_Offset(TkText, spacing1),
- TK_OPTION_DONT_SET_DEFAULT, 0 , TK_TEXT_LINE_GEOMETRY },
+ 0, 0 , TK_TEXT_LINE_GEOMETRY },
{TK_OPTION_PIXELS, "-spacing2", "spacing2", "Spacing",
DEF_TEXT_SPACING2, -1, Tk_Offset(TkText, spacing2),
- TK_OPTION_DONT_SET_DEFAULT, 0 , TK_TEXT_LINE_GEOMETRY },
+ 0, 0 , TK_TEXT_LINE_GEOMETRY },
{TK_OPTION_PIXELS, "-spacing3", "spacing3", "Spacing",
DEF_TEXT_SPACING3, -1, Tk_Offset(TkText, spacing3),
- TK_OPTION_DONT_SET_DEFAULT, 0 , TK_TEXT_LINE_GEOMETRY },
+ 0, 0 , TK_TEXT_LINE_GEOMETRY },
{TK_OPTION_CUSTOM, "-startline", NULL, NULL,
NULL, -1, Tk_Offset(TkText, start), TK_OPTION_NULL_OK,
&lineOption, TK_TEXT_LINE_RANGE},
@@ -402,6 +402,7 @@ static Tcl_Obj * TextGetText(const TkText *textPtr,
const TkTextIndex *index2, int visibleOnly);
static void GenerateModifiedEvent(TkText *textPtr);
static void UpdateDirtyFlag(TkSharedText *sharedPtr);
+static void RunAfterSyncCmd(ClientData clientData);
static void TextPushUndoAction(TkText *textPtr,
Tcl_Obj *undoString, int insert,
const TkTextIndex *index1Ptr,
@@ -580,14 +581,6 @@ CreateWidget(
textPtr->end = NULL;
}
- /*
- * Register with the B-tree. In some sense it would be best if we could do
- * this later (after configuration options), so that any changes to
- * start,end do not require a total recalculation.
- */
-
- TkBTreeAddClient(sharedPtr->tree, textPtr, textPtr->charHeight);
-
textPtr->state = TK_TEXT_STATE_NORMAL;
textPtr->relief = TK_RELIEF_FLAT;
textPtr->cursor = None;
@@ -598,6 +591,14 @@ CreateWidget(
textPtr->prevHeight = Tk_Height(newWin);
/*
+ * Register with the B-tree. In some sense it would be best if we could do
+ * this later (after configuration options), so that any changes to
+ * start,end do not require a total recalculation.
+ */
+
+ TkBTreeAddClient(sharedPtr->tree, textPtr, textPtr->charHeight);
+
+ /*
* This will add refCounts to textPtr.
*/
@@ -702,15 +703,16 @@ TextWidgetObjCmd(
static const char *const optionStrings[] = {
"bbox", "cget", "compare", "configure", "count", "debug", "delete",
"dlineinfo", "dump", "edit", "get", "image", "index", "insert",
- "mark", "peer", "replace", "scan", "search", "see", "tag", "window",
- "xview", "yview", NULL
+ "mark", "peer", "pendingsync", "replace", "scan", "search",
+ "see", "sync", "tag", "window", "xview", "yview", NULL
};
enum options {
TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT,
TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT,
TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK,
- TEXT_PEER, TEXT_REPLACE, TEXT_SCAN, TEXT_SEARCH, TEXT_SEE,
- TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, TEXT_YVIEW
+ TEXT_PEER, TEXT_PENDINGSYNC, TEXT_REPLACE, TEXT_SCAN,
+ TEXT_SEARCH, TEXT_SEE, TEXT_SYNC, TEXT_TAG, TEXT_WINDOW,
+ TEXT_XVIEW, TEXT_YVIEW
};
if (objc < 2) {
@@ -1392,6 +1394,16 @@ TextWidgetObjCmd(
case TEXT_PEER:
result = TextPeerCmd(textPtr, interp, objc, objv);
break;
+ case TEXT_PENDINGSYNC: {
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ Tcl_SetObjResult(interp,
+ Tcl_NewBooleanObj(TkTextPendingsync(textPtr)));
+ break;
+ }
case TEXT_REPLACE: {
const TkTextIndex *indexFromPtr, *indexToPtr;
@@ -1506,6 +1518,39 @@ TextWidgetObjCmd(
case TEXT_SEE:
result = TkTextSeeCmd(textPtr, interp, objc, objv);
break;
+ case TEXT_SYNC: {
+ if (objc == 4) {
+ Tcl_Obj *cmd = objv[3];
+ const char *option = Tcl_GetString(objv[2]);
+ if (strncmp(option, "-command", objv[2]->length)) {
+ Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL);
+ result = TCL_ERROR;
+ goto done;
+ }
+ Tcl_IncrRefCount(cmd);
+ if (TkTextPendingsync(textPtr)) {
+ if (textPtr->afterSyncCmd) {
+ Tcl_DecrRefCount(textPtr->afterSyncCmd);
+ }
+ textPtr->afterSyncCmd = cmd;
+ } else {
+ textPtr->afterSyncCmd = cmd;
+ Tcl_DoWhenIdle(RunAfterSyncCmd, (ClientData) textPtr);
+ }
+ break;
+ } else if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 2, objv, "?-command command?");
+ result = TCL_ERROR;
+ goto done;
+ }
+ if (textPtr->afterSyncCmd) {
+ Tcl_DecrRefCount(textPtr->afterSyncCmd);
+ }
+ textPtr->afterSyncCmd = NULL;
+ TkTextUpdateLineMetrics(textPtr, 1,
+ TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1);
+ break;
+ }
case TEXT_TAG:
result = TkTextTagCmd(textPtr, interp, objc, objv);
break;
@@ -1995,6 +2040,10 @@ DestroyText(
textPtr->tkwin = NULL;
textPtr->refCount--;
Tcl_DeleteCommandFromToken(textPtr->interp, textPtr->widgetCmd);
+ if (textPtr->afterSyncCmd){
+ Tcl_DecrRefCount(textPtr->afterSyncCmd);
+ textPtr->afterSyncCmd = NULL;
+ }
if (textPtr->refCount == 0) {
ckfree(textPtr);
}
@@ -2344,6 +2393,7 @@ TextWorldChanged(
{
Tk_FontMetrics fm;
int border;
+ int oldCharHeight = textPtr->charHeight;
textPtr->charWidth = Tk_TextWidth(textPtr->tkfont, "0", 1);
if (textPtr->charWidth <= 0) {
@@ -2355,6 +2405,9 @@ TextWorldChanged(
if (textPtr->charHeight <= 0) {
textPtr->charHeight = 1;
}
+ if (textPtr->charHeight != oldCharHeight) {
+ TkBTreeClientRangeChanged(textPtr, textPtr->charHeight);
+ }
border = textPtr->borderWidth + textPtr->highlightWidth;
Tk_GeometryRequest(textPtr->tkwin,
textPtr->width * textPtr->charWidth + 2*textPtr->padX + 2*border,
@@ -5364,6 +5417,52 @@ UpdateDirtyFlag(
/*
*----------------------------------------------------------------------
*
+ * RunAfterSyncCmd --
+ *
+ * This function is called by the event loop and executes the command
+ * scheduled by [.text sync -command $cmd].
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Anything may happen, depending on $cmd contents.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+RunAfterSyncCmd(
+ ClientData clientData) /* Information about text widget. */
+{
+ register TkText *textPtr = (TkText *) clientData;
+ int code;
+
+ if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
+ /*
+ * The widget has been deleted. Don't do anything.
+ */
+
+ if (--textPtr->refCount == 0) {
+ ckfree((char *) textPtr);
+ }
+ return;
+ }
+
+ Tcl_Preserve((ClientData) textPtr->interp);
+ code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL);
+ if (code == TCL_ERROR) {
+ Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)");
+ Tcl_BackgroundError(textPtr->interp);
+ }
+ Tcl_Release((ClientData) textPtr->interp);
+ Tcl_DecrRefCount(textPtr->afterSyncCmd);
+ textPtr->afterSyncCmd = NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* SearchPerform --
*
* Overall control of search process. Is given a pattern, a starting
diff --git a/generic/tkText.h b/generic/tkText.h
index 99a4888..fc92644 100644
--- a/generic/tkText.h
+++ b/generic/tkText.h
@@ -168,7 +168,7 @@ typedef struct TkTextSegment {
int size; /* Size of this segment (# of bytes of index
* space it occupies). */
union {
- char chars[1]; /* Characters that make up character info.
+ char chars[2]; /* Characters that make up character info.
* Actual length varies to hold as many
* characters as needed.*/
TkTextToggle toggle; /* Information about tag toggle. */
@@ -785,6 +785,8 @@ typedef struct TkText {
* statements. */
int autoSeparators; /* Non-zero means the separators will be
* inserted automatically. */
+ Tcl_Obj *afterSyncCmd; /* Command to be executed when lines are up to
+ * date */
} TkText;
/*
@@ -1109,6 +1111,7 @@ MODULE_SCOPE int TkTextMarkNameToIndex(TkText *textPtr,
MODULE_SCOPE void TkTextMarkSegToIndex(TkText *textPtr,
TkTextSegment *markPtr, TkTextIndex *indexPtr);
MODULE_SCOPE void TkTextEventuallyRepick(TkText *textPtr);
+MODULE_SCOPE Bool TkTextPendingsync(TkText *textPtr);
MODULE_SCOPE void TkTextPickCurrent(TkText *textPtr, XEvent *eventPtr);
MODULE_SCOPE void TkTextPixelIndex(TkText *textPtr, int x, int y,
TkTextIndex *indexPtr, int *nearest);
diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c
index 7383d21..0fdc280 100644
--- a/generic/tkTextBTree.c
+++ b/generic/tkTextBTree.c
@@ -1112,7 +1112,7 @@ TkBTreeInsertChars(
/*
* I don't believe it's possible for either of the two lines passed to
* this function to be the last line of text, but the function is robust
- * to that case anyway. (We must never re-calculated the line height of
+ * to that case anyway. (We must never re-calculate the line height of
* the last line).
*/
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index a95bb91..1eea37d 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -591,6 +591,7 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp,
Tcl_Obj *const objv[], double *dblPtr,
int *intPtr);
static void AsyncUpdateLineMetrics(ClientData clientData);
+static void GenerateWidgetViewSyncEvent(TkText *textPtr, Bool InSync);
static void AsyncUpdateYScrollbar(ClientData clientData);
static int IsStartOfNotMergedLine(TkText *textPtr,
CONST TkTextIndex *indexPtr);
@@ -659,17 +660,8 @@ TkTextCreateDInfo(
dInfoPtr->metricEpoch = -1;
dInfoPtr->metricIndex.textPtr = NULL;
dInfoPtr->metricIndex.linePtr = NULL;
-
- /*
- * Add a refCount for each of the idle call-backs.
- */
-
- textPtr->refCount++;
- dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(0,
- AsyncUpdateLineMetrics, textPtr);
- textPtr->refCount++;
- dInfoPtr->scrollbarTimer = Tcl_CreateTimerHandler(200,
- AsyncUpdateYScrollbar, textPtr);
+ dInfoPtr->lineUpdateTimer = NULL;
+ dInfoPtr->scrollbarTimer = NULL;
textPtr->dInfoPtr = dInfoPtr;
}
@@ -1648,7 +1640,7 @@ LayoutDLine(
* Make one more pass over the line to recompute various things like its
* height, length, and total number of bytes. Also modify the x-locations
* of chunks to reflect justification. If we're not wrapping, I'm not sure
- * what is the best way to handle left and center justification: should
+ * what is the best way to handle right and center justification: should
* the total length, for purposes of justification, be (a) the window
* width, (b) the length of the longest line in the window, or (c) the
* length of the longest line in the text? (c) isn't available, (b) seems
@@ -2226,7 +2218,7 @@ UpdateDisplayInfo(
* Here's a problem: see the tests textDisp-29.2.1-4
*
* If the widget is being created, but has not yet been configured it will
- * have a maxY of 1 above, and we we won't have examined all the lines
+ * have a maxY of 1 above, and we won't have examined all the lines
* (just the first line, in fact), and so maxOffset will not be a true
* reflection of the widget's lines. Therefore we must not overwrite the
* original newXPixelOffset in this case.
@@ -2541,7 +2533,7 @@ DisplayLineBackground(
* current x coordinate? */
int matchRight; /* Does line's style match its neighbor just
* to the right of the current x-coord? */
- int minX, maxX, xOffset;
+ int minX, maxX, xOffset, bw;
StyleValues *sValuePtr;
Display *display;
#ifndef TK_NO_DOUBLE_BUFFERING
@@ -2612,16 +2604,25 @@ DisplayLineBackground(
rightX = leftX + 32767;
}
+ /*
+ * Prevent the borders from leaking on adjacent characters,
+ * which would happen for too large border width.
+ */
+
+ bw = sValuePtr->borderWidth;
+ if (leftX + sValuePtr->borderWidth > rightX) {
+ bw = rightX - leftX;
+ }
+
XFillRectangle(display, pixmap, chunkPtr->stylePtr->bgGC,
leftX + xOffset, y, (unsigned int) (rightX - leftX),
(unsigned int) dlPtr->height);
if (sValuePtr->relief != TK_RELIEF_FLAT) {
Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- leftX + xOffset, y, sValuePtr->borderWidth,
- dlPtr->height, 1, sValuePtr->relief);
+ leftX + xOffset, y, bw, dlPtr->height, 1,
+ sValuePtr->relief);
Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- rightX - sValuePtr->borderWidth + xOffset,
- y, sValuePtr->borderWidth, dlPtr->height, 0,
+ rightX - bw + xOffset, y, bw, dlPtr->height, 0,
sValuePtr->relief);
}
}
@@ -2718,22 +2719,29 @@ DisplayLineBackground(
matchRight = (nextPtr2 != NULL)
&& SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr);
if (matchLeft && !matchRight) {
+ bw = sValuePtr->borderWidth;
+ if (rightX2 - sValuePtr->borderWidth < leftX) {
+ bw = rightX2 - leftX;
+ }
if (sValuePtr->relief != TK_RELIEF_FLAT) {
Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- rightX2 - sValuePtr->borderWidth + xOffset, y,
- sValuePtr->borderWidth, sValuePtr->borderWidth, 0,
- sValuePtr->relief);
+ rightX2 - bw + xOffset, y, bw,
+ sValuePtr->borderWidth, 0, sValuePtr->relief);
}
- leftX = rightX2 - sValuePtr->borderWidth;
+ leftX = rightX2 - bw;
leftXIn = 0;
} else if (!matchLeft && matchRight
&& (sValuePtr->relief != TK_RELIEF_FLAT)) {
+ bw = sValuePtr->borderWidth;
+ if (rightX2 + sValuePtr->borderWidth > rightX) {
+ bw = rightX - rightX2;
+ }
Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- rightX2 + xOffset, y, sValuePtr->borderWidth,
- sValuePtr->borderWidth, 1, sValuePtr->relief);
+ rightX2 + xOffset, y, bw, sValuePtr->borderWidth,
+ 1, sValuePtr->relief);
Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- leftX + xOffset, y, rightX2 + sValuePtr->borderWidth -
- leftX, sValuePtr->borderWidth, leftXIn, 0, 1,
+ leftX + xOffset, y, rightX2 + bw - leftX,
+ sValuePtr->borderWidth, leftXIn, 0, 1,
sValuePtr->relief);
}
@@ -2765,7 +2773,7 @@ DisplayLineBackground(
chunkPtr2 = NULL;
if (dlPtr->nextPtr != NULL && dlPtr->nextPtr->chunkPtr != NULL) {
/*
- * Find the chunk in the previous line that covers leftX.
+ * Find the chunk in the next line that covers leftX.
*/
nextPtr2 = dlPtr->nextPtr->chunkPtr;
@@ -2821,26 +2829,33 @@ DisplayLineBackground(
matchRight = (nextPtr2 != NULL)
&& SAME_BACKGROUND(nextPtr2->stylePtr, chunkPtr->stylePtr);
if (matchLeft && !matchRight) {
+ bw = sValuePtr->borderWidth;
+ if (rightX2 - sValuePtr->borderWidth < leftX) {
+ bw = rightX2 - leftX;
+ }
if (sValuePtr->relief != TK_RELIEF_FLAT) {
Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- rightX2 - sValuePtr->borderWidth + xOffset,
+ rightX2 - bw + xOffset,
y + dlPtr->height - sValuePtr->borderWidth,
- sValuePtr->borderWidth, sValuePtr->borderWidth, 0,
- sValuePtr->relief);
+ bw, sValuePtr->borderWidth, 0, sValuePtr->relief);
}
- leftX = rightX2 - sValuePtr->borderWidth;
+ leftX = rightX2 - bw;
leftXIn = 1;
} else if (!matchLeft && matchRight
&& (sValuePtr->relief != TK_RELIEF_FLAT)) {
+ bw = sValuePtr->borderWidth;
+ if (rightX2 + sValuePtr->borderWidth > rightX) {
+ bw = rightX - rightX2;
+ }
Tk_3DVerticalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- rightX2 + xOffset, y + dlPtr->height -
- sValuePtr->borderWidth, sValuePtr->borderWidth,
+ rightX2 + xOffset,
+ y + dlPtr->height - sValuePtr->borderWidth, bw,
sValuePtr->borderWidth, 1, sValuePtr->relief);
Tk_3DHorizontalBevel(textPtr->tkwin, pixmap, sValuePtr->border,
- leftX + xOffset, y + dlPtr->height -
- sValuePtr->borderWidth, rightX2 + sValuePtr->borderWidth -
- leftX, sValuePtr->borderWidth, leftXIn, 1, 0,
- sValuePtr->relief);
+ leftX + xOffset,
+ y + dlPtr->height - sValuePtr->borderWidth,
+ rightX2 + bw - leftX, sValuePtr->borderWidth, leftXIn,
+ 1, 0, sValuePtr->relief);
}
nextChunk2b:
@@ -2890,9 +2905,10 @@ AsyncUpdateLineMetrics(
dInfoPtr->lineUpdateTimer = NULL;
- if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
+ if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)
+ || !Tk_IsMapped(textPtr->tkwin)) {
/*
- * The widget has been deleted. Don't do anything.
+ * The widget has been deleted, or is not mapped. Don't do anything.
*/
if (--textPtr->refCount == 0) {
@@ -2926,6 +2942,8 @@ AsyncUpdateLineMetrics(
lineNum = TkTextUpdateLineMetrics(textPtr, lineNum,
dInfoPtr->lastMetricUpdateLine, 256);
+ dInfoPtr->currentMetricUpdateLine = lineNum;
+
if (tkTextDebug) {
char buffer[2 * TCL_INTEGER_SPACE + 1];
@@ -2943,16 +2961,37 @@ AsyncUpdateLineMetrics(
/*
* We have looped over all lines, so we're done. We must release our
* refCount on the widget (the timer token was already set to NULL
- * above).
+ * above). If there is a registered aftersync command, run that first.
*/
+ if (textPtr->afterSyncCmd) {
+ int code;
+ Tcl_Preserve((ClientData) textPtr->interp);
+ code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd,
+ TCL_EVAL_GLOBAL);
+ if (code == TCL_ERROR) {
+ Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)");
+ Tcl_BackgroundError(textPtr->interp);
+ }
+ Tcl_Release((ClientData) textPtr->interp);
+ Tcl_DecrRefCount(textPtr->afterSyncCmd);
+ textPtr->afterSyncCmd = NULL;
+ }
+
+ /*
+ * Fire the <<WidgetViewSync>> event since the widget view is in sync
+ * with its internal data (actually it will be after the next trip
+ * through the event loop, because the widget redraws at idle-time).
+ */
+
+ GenerateWidgetViewSyncEvent(textPtr, 1);
+
textPtr->refCount--;
if (textPtr->refCount == 0) {
ckfree(textPtr);
}
return;
}
- dInfoPtr->currentMetricUpdateLine = lineNum;
/*
* Re-arm the timer. We already have a refCount on the text widget so no
@@ -2966,6 +3005,45 @@ AsyncUpdateLineMetrics(
/*
*----------------------------------------------------------------------
*
+ * GenerateWidgetViewSyncEvent --
+ *
+ * Send the <<WidgetViewSync>> event related to the text widget
+ * line metrics asynchronous update.
+ * This is equivalent to:
+ * event generate $textWidget <<WidgetViewSync>> -detail $s
+ * where $s is the sync status: true (when the widget view is in
+ * sync with its internal data) or false (when it is not).
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * If corresponding bindings are present, they will trigger.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GenerateWidgetViewSyncEvent(
+ TkText *textPtr, /* Information about text widget. */
+ Bool InSync) /* True if in sync, false otherwise */
+{
+ union {XEvent general; XVirtualEvent virtual;} event;
+
+ memset(&event, 0, sizeof(event));
+ event.general.xany.type = VirtualEvent;
+ event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
+ event.general.xany.send_event = False;
+ event.general.xany.window = Tk_WindowId(textPtr->tkwin);
+ event.general.xany.display = Tk_Display(textPtr->tkwin);
+ event.virtual.name = Tk_GetUid("WidgetViewSync");
+ event.virtual.user_data = Tcl_NewBooleanObj(InSync);
+ Tk_HandleEvent(&event.general);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkTextUpdateLineMetrics --
*
* This function updates the pixel height calculations of a range of
@@ -3338,6 +3416,7 @@ TextInvalidateLineMetrics(
textPtr->refCount++;
dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
AsyncUpdateLineMetrics, textPtr);
+ GenerateWidgetViewSyncEvent(textPtr, 0);
}
}
@@ -5042,6 +5121,7 @@ TkTextRelayoutWindow(
textPtr->refCount++;
dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
AsyncUpdateLineMetrics, textPtr);
+ GenerateWidgetViewSyncEvent(textPtr, 0);
}
}
}
@@ -5153,7 +5233,10 @@ TkTextSetYView(
dInfoPtr->newTopPixelOffset = 0;
goto scheduleUpdate;
- }
+ }
+ /*
+ * The line is already on screen, with no need to scroll.
+ */
return;
}
}
@@ -5216,6 +5299,15 @@ TkTextSetYView(
}
/*
+ * If the window height is smaller than the line height, prefer to make
+ * the top of the line visible.
+ */
+
+ if (dInfoPtr->maxY - dInfoPtr->y < lineHeight) {
+ bottomY = lineHeight;
+ }
+
+ /*
* Our job now is to arrange the display so that indexPtr appears as low
* on the screen as possible but with its bottom no lower than bottomY.
* BottomY is the bottom of the window if the desired line is just below
@@ -6035,6 +6127,35 @@ TkTextYviewCmd(
/*
*--------------------------------------------------------------
*
+ * TkTextPendingsync --
+ *
+ * This function checks if any line heights are not up-to-date.
+ *
+ * Results:
+ * Returns a boolean true if it is the case, or false if all line
+ * heights are up-to-date.
+ *
+ * Side effects:
+ * None.
+ *
+ *--------------------------------------------------------------
+ */
+
+Bool
+TkTextPendingsync(
+ TkText *textPtr) /* Information about text widget. */
+{
+ TextDInfo *dInfoPtr = textPtr->dInfoPtr;
+
+ return (
+ ((dInfoPtr->metricEpoch == -1) &&
+ (dInfoPtr->lastMetricUpdateLine == dInfoPtr->currentMetricUpdateLine)) ?
+ 0 : 1);
+}
+
+/*
+ *--------------------------------------------------------------
+ *
* TkTextScanCmd --
*
* This function is invoked to process the "scan" option for the widget
@@ -6578,6 +6699,7 @@ FindDLine(
const TkTextIndex *indexPtr)/* Index of desired character. */
{
DLine *dlPtrPrev;
+ TkTextIndex indexPtr2;
if (dlPtr == NULL) {
return NULL;
@@ -6602,24 +6724,58 @@ FindDLine(
dlPtrPrev = dlPtr;
dlPtr = dlPtr->nextPtr;
if (dlPtr == NULL) {
- TkTextIndex indexPtr2;
/*
* We're past the last display line, either because the desired
* index lies past the visible text, or because the desired index
- * is on the last display line showing the last logical line.
+ * is on the last display line.
*/
indexPtr2 = dlPtrPrev->index;
TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
&indexPtr2);
if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
+ /*
+ * The desired index is on the last display line.
+ * --> return this display line.
+ */
dlPtr = dlPtrPrev;
- break;
} else {
- return NULL;
+ /*
+ * The desired index is past the visible text. There is no
+ * display line displaying something at the desired index.
+ * --> return NULL.
+ */
}
+ break;
}
if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) {
- dlPtr = dlPtrPrev;
+ /*
+ * If we're here then we would normally expect that:
+ * dlPtrPrev->index <= indexPtr < dlPtr->index
+ * i.e. we have found the searched display line being dlPtr.
+ * However it is possible that some DLines were unlinked
+ * previously, leading to a situation where going through
+ * the list of display lines skips display lines that did
+ * exist just a moment ago.
+ */
+ indexPtr2 = dlPtrPrev->index;
+ TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
+ &indexPtr2);
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
+ /*
+ * Confirmed:
+ * dlPtrPrev->index <= indexPtr < dlPtr->index
+ * --> return dlPtrPrev.
+ */
+ dlPtr = dlPtrPrev;
+ } else {
+ /*
+ * The last (rightmost) index shown by dlPtrPrev is still
+ * before the desired index. This may be because there was
+ * previously a display line between dlPtrPrev and dlPtr
+ * and this display line has been unlinked.
+ * --> return dlPtr.
+ */
+ }
break;
}
}
diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c
index af3f235..3363d25 100644
--- a/generic/tkTextTag.c
+++ b/generic/tkTextTag.c
@@ -44,11 +44,11 @@ static const Tk_OptionSpec tagOptionSpecs[] = {
{TK_OPTION_BITMAP, "-bgstipple", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, bgStipple), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_PIXELS, "-borderwidth", NULL, NULL,
- "0", Tk_Offset(TkTextTag, borderWidthPtr), Tk_Offset(TkTextTag, borderWidth),
- TK_OPTION_DONT_SET_DEFAULT|TK_OPTION_NULL_OK, 0, 0},
+ NULL, Tk_Offset(TkTextTag, borderWidthPtr), Tk_Offset(TkTextTag, borderWidth),
+ TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0},
{TK_OPTION_STRING, "-elide", NULL, NULL,
- "0", -1, Tk_Offset(TkTextTag, elideString),
- TK_OPTION_DONT_SET_DEFAULT|TK_OPTION_NULL_OK, 0, 0},
+ NULL, -1, Tk_Offset(TkTextTag, elideString),
+ TK_OPTION_NULL_OK|TK_OPTION_DONT_SET_DEFAULT, 0, 0},
{TK_OPTION_BITMAP, "-fgstipple", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, fgStipple), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_FONT, "-font", NULL, NULL,
diff --git a/generic/ttk/ttkButton.c b/generic/ttk/ttkButton.c
index 2954184..bc44f25 100644
--- a/generic/ttk/ttkButton.c
+++ b/generic/ttk/ttkButton.c
@@ -413,8 +413,8 @@ typedef struct
static Tk_OptionSpec CheckbuttonOptionSpecs[] =
{
{TK_OPTION_STRING, "-variable", "variable", "Variable",
- "", Tk_Offset(Checkbutton, checkbutton.variableObj), -1,
- TK_OPTION_DONT_SET_DEFAULT,0,0},
+ NULL, Tk_Offset(Checkbutton, checkbutton.variableObj), -1,
+ TK_OPTION_NULL_OK,0,0},
{TK_OPTION_STRING, "-onvalue", "onValue", "OnValue",
"1", Tk_Offset(Checkbutton, checkbutton.onValueObj), -1,
0,0,0},
diff --git a/generic/ttk/ttkNotebook.c b/generic/ttk/ttkNotebook.c
index 16a8bfe..81a8b64 100644
--- a/generic/ttk/ttkNotebook.c
+++ b/generic/ttk/ttkNotebook.c
@@ -901,7 +901,7 @@ static int NotebookAddCommand(
if (tab->state == TAB_STATE_HIDDEN) {
tab->state = TAB_STATE_NORMAL;
}
- if (ConfigureTab(interp, nb, tab, slaveWindow, objc-4,objv+4) != TCL_OK) {
+ if (ConfigureTab(interp, nb, tab, slaveWindow, objc-3,objv+3) != TCL_OK) {
return TCL_ERROR;
}