summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorhypnotoad <yoda@etoyoc.com>2016-10-02 12:07:40 (GMT)
committerhypnotoad <yoda@etoyoc.com>2016-10-02 12:07:40 (GMT)
commit0c444bd87e7dc74b25427a5fccf08ddd8d565cd6 (patch)
tree3afc6c9d5e73e2e86de808ce98ce275312d3dc7e /generic
parent20c81b194394bb6ea16d1831f6f895b63477819c (diff)
parent6c0dafab46875ddb6dd0a91f5e056a8d87722ca6 (diff)
downloadtk-core_zip_vfs.zip
tk-core_zip_vfs.tar.gz
tk-core_zip_vfs.tar.bz2
Pulling changes from trunkcore_zip_vfs
Diffstat (limited to 'generic')
-rw-r--r--generic/tk.h18
-rw-r--r--generic/tkBind.c22
-rw-r--r--generic/tkBusy.c4
-rw-r--r--generic/tkCanvas.c13
-rw-r--r--generic/tkDecls.h3
-rw-r--r--generic/tkEntry.c193
-rw-r--r--generic/tkEvent.c6
-rw-r--r--generic/tkFont.c28
-rw-r--r--generic/tkFrame.c23
-rw-r--r--generic/tkGC.c7
-rw-r--r--generic/tkImgGIF.c22
-rw-r--r--generic/tkImgPNG.c19
-rw-r--r--generic/tkImgPhInstance.c25
-rw-r--r--generic/tkImgPhoto.c75
-rw-r--r--generic/tkInt.decls3
-rw-r--r--generic/tkInt.h15
-rw-r--r--generic/tkIntPlatDecls.h8
-rw-r--r--generic/tkListbox.c147
-rw-r--r--generic/tkMain.c15
-rw-r--r--generic/tkMenu.c9
-rw-r--r--generic/tkOldConfig.c6
-rw-r--r--generic/tkOption.c31
-rw-r--r--generic/tkPanedWindow.c111
-rw-r--r--generic/tkScale.c15
-rw-r--r--generic/tkScrollbar.c2
-rw-r--r--generic/tkSelect.c2
-rw-r--r--generic/tkStubInit.c11
-rw-r--r--generic/tkTest.c4
-rw-r--r--generic/tkText.c542
-rw-r--r--generic/tkText.h20
-rw-r--r--generic/tkTextBTree.c2
-rw-r--r--generic/tkTextDisp.c389
-rw-r--r--generic/tkTextIndex.c49
-rw-r--r--generic/tkTextTag.c50
-rw-r--r--generic/tkTextWind.c16
-rw-r--r--generic/tkUndo.c52
-rw-r--r--generic/tkUndo.h4
-rw-r--r--generic/tkUtil.c89
-rw-r--r--generic/tkWindow.c310
-rw-r--r--generic/ttk/ttkButton.c17
-rw-r--r--generic/ttk/ttkClamTheme.c20
-rw-r--r--generic/ttk/ttkClassicTheme.c32
-rw-r--r--generic/ttk/ttkEntry.c17
-rw-r--r--generic/ttk/ttkGenStubs.tcl2
-rw-r--r--generic/ttk/ttkImage.c34
-rw-r--r--generic/ttk/ttkLabel.c14
-rw-r--r--generic/ttk/ttkManager.c2
-rw-r--r--generic/ttk/ttkManager.h2
-rw-r--r--generic/ttk/ttkNotebook.c2
-rw-r--r--generic/ttk/ttkProgress.c6
-rw-r--r--generic/ttk/ttkScale.c14
-rw-r--r--generic/ttk/ttkScrollbar.c6
-rw-r--r--generic/ttk/ttkSquare.c28
-rw-r--r--generic/ttk/ttkStubLib.c2
-rw-r--r--generic/ttk/ttkTagSet.c2
-rw-r--r--generic/ttk/ttkTheme.h2
-rw-r--r--generic/ttk/ttkTrace.c2
-rw-r--r--generic/ttk/ttkWidget.h4
58 files changed, 1847 insertions, 721 deletions
diff --git a/generic/tk.h b/generic/tk.h
index 4a655a4..9403f31 100644
--- a/generic/tk.h
+++ b/generic/tk.h
@@ -17,8 +17,8 @@
#define _TK
#include <tcl.h>
-#if (TCL_MAJOR_VERSION != 8) || (TCL_MINOR_VERSION < 6)
-# error Tk 8.6 must be compiled with tcl.h from Tcl 8.6 or better
+#if (TCL_MAJOR_VERSION < 8) || (TCL_MAJOR_VERSION == 8) && (TCL_MINOR_VERSION < 6)
+# error Tk 8.7 must be compiled with tcl.h from Tcl 8.6 or better
#endif
#ifndef CONST84
@@ -59,8 +59,8 @@ extern "C" {
* and update the version numbers:
*
* library/tk.tcl (1 LOC patch)
- * unix/configure.in (2 LOC Major, 2 LOC minor, 1 LOC patch)
- * win/configure.in (as above)
+ * unix/configure.ac (2 LOC Major, 2 LOC minor, 1 LOC patch)
+ * win/configure.ac (as above)
* README (sections 0 and 1)
* macosx/Tk-Common.xcconfig (not patchlevel) 1 LOC
* win/README (not patchlevel)
@@ -73,12 +73,12 @@ 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_MINOR_VERSION 7
+#define TK_RELEASE_LEVEL TCL_ALPHA_RELEASE
+#define TK_RELEASE_SERIAL 0
-#define TK_VERSION "8.6"
-#define TK_PATCH_LEVEL "8.6.4"
+#define TK_VERSION "8.7"
+#define TK_PATCH_LEVEL "8.7a0"
/*
* A special definition used to allow this header file to be included from
diff --git a/generic/tkBind.c b/generic/tkBind.c
index 9cd3b7b..bb95fa9 100644
--- a/generic/tkBind.c
+++ b/generic/tkBind.c
@@ -2868,7 +2868,7 @@ GetAllVirtualEvents(
* Any other fields in eventPtr which are not specified by the pattern
* string or the optional arguments, are set to 0.
*
- * The event may be handled sychronously or asynchronously, depending on
+ * The event may be handled synchronously or asynchronously, depending on
* the value specified by the optional "-when" option. The default
* setting is synchronous.
*
@@ -3460,7 +3460,7 @@ HandleEventGenerate(
Tcl_DoWhenIdle(DoWarp, dispPtr);
dispPtr->flags |= TK_DISPLAY_IN_WARP;
}
- dispPtr->warpWindow = Tk_IdToWindow(Tk_Display(mainWin),
+ dispPtr->warpWindow = Tk_IdToWindow(dispPtr->display,
event.general.xmotion.window);
dispPtr->warpMainwin = mainWin;
dispPtr->warpX = event.general.xmotion.x;
@@ -3535,8 +3535,20 @@ DoWarp(
{
TkDisplay *dispPtr = clientData;
- TkpWarpPointer(dispPtr);
- XForceScreenSaver(dispPtr->display, ScreenSaverReset);
+ /*
+ * DoWarp was scheduled only if the window was mapped. It needs to be
+ * still mapped at the time the present idle callback is executed. Also
+ * one needs to guard against window destruction in the meantime.
+ * Finally, the case warpWindow == NULL is special in that it means
+ * the whole screen.
+ */
+
+ if ((dispPtr->warpWindow == NULL) ||
+ (Tk_IsMapped(dispPtr->warpWindow)
+ && (Tk_WindowId(dispPtr->warpWindow) != None))) {
+ TkpWarpPointer(dispPtr);
+ XForceScreenSaver(dispPtr->display, ScreenSaverReset);
+ }
dispPtr->flags &= ~TK_DISPLAY_IN_WARP;
}
@@ -3937,7 +3949,7 @@ ParseEventDescription(
p = GetField(p, field, FIELD_SIZE);
}
if (*field != '\0') {
- if ((*field >= '1') && (*field <= '5') && (field[1] == '\0')) {
+ if ((*field >= '1') && (*field <= '9') && (field[1] == '\0')) {
if (eventFlags == 0) {
patPtr->eventType = ButtonPress;
eventMask = ButtonPressMask;
diff --git a/generic/tkBusy.c b/generic/tkBusy.c
index 65248a2..b36d453 100644
--- a/generic/tkBusy.c
+++ b/generic/tkBusy.c
@@ -433,6 +433,10 @@ MakeTransparentWindowExist(
TkpMakeTransparentWindowExist(tkwin, parent);
+ if (winPtr->window == None) {
+ return; /* Platform didn't make Window. */
+ }
+
dispPtr = winPtr->dispPtr;
hPtr = Tcl_CreateHashEntry(&dispPtr->winTable, (char *) winPtr->window,
&notUsed);
diff --git a/generic/tkCanvas.c b/generic/tkCanvas.c
index 8e14852..9c4d60a 100644
--- a/generic/tkCanvas.c
+++ b/generic/tkCanvas.c
@@ -2447,6 +2447,19 @@ DisplayCanvas(
goto done;
}
+#ifdef MAC_OSX_TK
+ /*
+ * If drawing is disabled, all we need to do is
+ * clear the REDRAW_PENDING flag.
+ */
+ TkWindow *winPtr = (TkWindow *)(canvasPtr->tkwin);
+ MacDrawable *macWin = winPtr->privatePtr;
+ if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){
+ canvasPtr->flags &= ~REDRAW_PENDING;
+ return;
+ }
+#endif
+
/*
* Choose a new current item if that is needed (this could cause event
* handlers to be invoked).
diff --git a/generic/tkDecls.h b/generic/tkDecls.h
index 64c32cd..eaaaf6c 100644
--- a/generic/tkDecls.h
+++ b/generic/tkDecls.h
@@ -1721,6 +1721,9 @@ extern const TkStubs *tkStubsPtr;
#undef Tk_SafeInit
#undef Tk_CreateConsoleWindow
+#undef Tk_FreeXId
+#define Tk_FreeXId(display,xid)
+
#if defined(_WIN32) && defined(UNICODE)
# define Tk_MainEx Tk_MainExW
EXTERN void Tk_MainExW(int argc, wchar_t **argv,
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index 3ad9acd..acfdd31 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.
@@ -1170,13 +1176,15 @@ ConfigureEntry(
if (entryPtr->type == TK_SPINBOX) {
if (sbPtr->fromValue > sbPtr->toValue) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "-to value must be greater than -from value",
- -1));
- Tcl_SetErrorCode(interp, "TK", "SPINBOX", "RANGE_SANITY",
- NULL);
- continue;
- }
+ /*
+ * Swap -from and -to values.
+ */
+
+ double tmpFromTo = sbPtr->fromValue;
+
+ sbPtr->fromValue = sbPtr->toValue;
+ sbPtr->toValue = tmpFromTo;
+ }
if (sbPtr->reqFormat && (oldFormat != sbPtr->reqFormat)) {
/*
@@ -1305,6 +1313,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 +1342,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 +1371,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 +1388,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 +1714,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) {
@@ -1892,8 +1926,8 @@ EntryComputeGeometry(
*/
if (entryPtr->showChar != NULL) {
- Tcl_UniChar ch;
- char buf[TCL_UTF_MAX];
+ int ch;
+ char buf[6];
int size;
/*
@@ -1903,15 +1937,16 @@ EntryComputeGeometry(
* resulting string.
*/
- Tcl_UtfToUniChar(entryPtr->showChar, &ch);
- size = Tcl_UniCharToUtf(ch, buf);
+ TkUtfToUniChar(entryPtr->showChar, &ch);
+ size = TkUniCharToUtf(ch, buf);
entryPtr->numDisplayBytes = entryPtr->numChars * size;
p = ckalloc(entryPtr->numDisplayBytes + 1);
entryPtr->displayString = p;
for (i = entryPtr->numChars; --i >= 0; ) {
- p += Tcl_UniCharToUtf(ch, p);
+ memcpy(p, buf, size);
+ p += size;
}
*p = '\0';
}
@@ -1993,7 +2028,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 +2038,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 +2056,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 +2070,7 @@ InsertChars(
EntryValidateChange(entryPtr, value, newStr, index,
VALIDATE_INSERT) != TCL_OK) {
ckfree(newStr);
- return;
+ return TCL_OK;
}
ckfree((char *)string);
@@ -2082,7 +2118,7 @@ InsertChars(
if (entryPtr->insertPos >= index) {
entryPtr->insertPos += charsAdded;
}
- EntryValueChanged(entryPtr, NULL);
+ return EntryValueChanged(entryPtr, NULL);
}
/*
@@ -2093,7 +2129,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 +2139,7 @@ InsertChars(
*----------------------------------------------------------------------
*/
-static void
+static int
DeleteChars(
Entry *entryPtr, /* Entry widget to modify. */
int index, /* Index of first character to delete. */
@@ -2116,7 +2153,7 @@ DeleteChars(
count = entryPtr->numChars - index;
}
if (count <= 0) {
- return;
+ return TCL_OK;
}
string = entryPtr->string;
@@ -2138,7 +2175,7 @@ DeleteChars(
VALIDATE_DELETE) != TCL_OK) {
ckfree(newStr);
ckfree(toDelete);
- return;
+ return TCL_OK;
}
ckfree(toDelete);
@@ -2197,7 +2234,7 @@ DeleteChars(
entryPtr->insertPos = index;
}
}
- EntryValueChanged(entryPtr, NULL);
+ return EntryValueChanged(entryPtr, NULL);
}
/*
@@ -2210,7 +2247,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 +2256,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 +2270,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 +2292,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;
}
/*
@@ -3363,7 +3414,7 @@ ExpandPercents(
* list element. */
int number, length;
register const char *string;
- Tcl_UniChar ch;
+ int ch;
char numStorage[2*TCL_INTEGER_SPACE];
while (1) {
@@ -3396,7 +3447,7 @@ ExpandPercents(
before++; /* skip over % */
if (*before != '\0') {
- before += Tcl_UtfToUniChar(before, &ch);
+ before += TkUtfToUniChar(before, &ch);
} else {
ch = '%';
}
@@ -3416,7 +3467,7 @@ ExpandPercents(
string = Tk_PathName(entryPtr->tkwin);
break;
default:
- length = Tcl_UniCharToUtf(ch, numStorage);
+ length = TkUniCharToUtf(ch, numStorage);
numStorage[length] = '\0';
string = numStorage;
break;
@@ -3476,7 +3527,7 @@ ExpandPercents(
string = Tk_PathName(entryPtr->tkwin);
break;
default:
- length = Tcl_UniCharToUtf(ch, numStorage);
+ length = TkUniCharToUtf(ch, numStorage);
numStorage[length] = '\0';
string = numStorage;
break;
@@ -3611,7 +3662,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 +3770,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 +3794,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 +3857,7 @@ SpinboxWidgetObjCmd(
}
case SB_CMD_INSERT: {
- int index;
+ int index, code;
if (objc != 4) {
Tcl_WrongNumArgs(interp, 2, objv, "index text");
@@ -3814,7 +3868,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 +4081,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 +4237,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 +4268,7 @@ SpinboxInvoke(
return TCL_OK;
}
+ code = TCL_OK;
if (fabs(sbPtr->increment) > MIN_DBL_VAL) {
if (sbPtr->listObj != NULL) {
Tcl_Obj *objPtr;
@@ -4250,7 +4314,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 +4361,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..7f2715b 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -497,7 +497,7 @@ Tk_FontObjCmd(
const char *s;
Tk_Font tkfont;
Tcl_Obj *optPtr, *charPtr, *resultPtr;
- Tcl_UniChar uniChar = 0;
+ int uniChar = 0;
const TkFontAttributes *faPtr;
TkFontAttributes fa;
@@ -562,17 +562,19 @@ Tk_FontObjCmd(
*/
if (charPtr != NULL) {
- if (Tcl_GetCharLength(charPtr) != 1) {
+ const char *string = Tcl_GetString(charPtr);
+ int len = TkUtfToUniChar(string, &uniChar);
+
+ if (len != charPtr->length) {
resultPtr = Tcl_NewStringObj(
"expected a single character but got \"", -1);
- Tcl_AppendLimitedToObj(resultPtr, Tcl_GetString(charPtr),
+ Tcl_AppendLimitedToObj(resultPtr, string,
-1, 40, "...");
Tcl_AppendToObj(resultPtr, "\"", -1);
Tcl_SetObjResult(interp, resultPtr);
Tcl_SetErrorCode(interp, "TK", "VALUE", "FONT_SAMPLE", NULL);
return TCL_ERROR;
}
- uniChar = Tcl_GetUniChar(charPtr, 0);
}
/*
@@ -1694,7 +1696,7 @@ Tk_PostscriptFontName(
} else if (strcasecmp(family, "ZapfDingbats") == 0) {
family = "ZapfDingbats";
} else {
- Tcl_UniChar ch;
+ int ch;
/*
* Inline, capitalize the first letter of each word, lowercase the
@@ -1712,14 +1714,14 @@ Tk_PostscriptFontName(
src++;
upper = 1;
}
- src += Tcl_UtfToUniChar(src, &ch);
+ src += TkUtfToUniChar(src, &ch);
if (upper) {
ch = Tcl_UniCharToUpper(ch);
upper = 0;
} else {
ch = Tcl_UniCharToLower(ch);
}
- dest += Tcl_UniCharToUtf(ch, dest);
+ dest += TkUniCharToUtf(ch, dest);
}
*dest = '\0';
Tcl_DStringSetLength(dsPtr, dest - Tcl_DStringValue(dsPtr));
@@ -2067,14 +2069,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 {
@@ -3249,7 +3251,7 @@ Tk_TextLayoutToPostscript(
int i, j, len;
const char *p, *glyphname;
char uindex[5], c, *ps;
- Tcl_UniChar ch;
+ int ch;
Tcl_AppendToObj(psObj, "[(", -1);
for (i = 0; i < layoutPtr->numChunks; i++, chunkPtr++) {
@@ -3272,7 +3274,7 @@ Tk_TextLayoutToPostscript(
* international postscript fonts.
*/
- p += Tcl_UtfToUniChar(p, &ch);
+ p += TkUtfToUniChar(p, &ch);
if ((ch == '(') || (ch == ')') || (ch == '\\') || (ch < 0x20)) {
/*
* Tricky point: the "03" is necessary in the sprintf below,
@@ -3298,6 +3300,9 @@ Tk_TextLayoutToPostscript(
* use the full glyph name.
*/
+ if (ch > 0xffff) {
+ goto noMapping;
+ }
sprintf(uindex, "%04X", ch); /* endianness? */
glyphname = Tcl_GetVar2(interp, "::tk::psglyphs", uindex, 0);
if (glyphname) {
@@ -3318,6 +3323,7 @@ Tk_TextLayoutToPostscript(
* No known mapping for the character into the space of
* PostScript glyphs. Ignore it. :-(
*/
+noMapping: ;
#ifdef TK_DEBUG_POSTSCRIPT_OUTPUT
fprintf(stderr, "Warning: no mapping to PostScript "
diff --git a/generic/tkFrame.c b/generic/tkFrame.c
index 057b4b8..0f1a1b3 100644
--- a/generic/tkFrame.c
+++ b/generic/tkFrame.c
@@ -447,6 +447,29 @@ TkCreateFrame(
return result;
}
+int
+TkListCreateFrame(
+ ClientData clientData, /* Either NULL or pointer to option table. */
+ Tcl_Interp *interp, /* Current interpreter. */
+ Tcl_Obj *listObj, /* List of arguments. */
+ int toplevel, /* Non-zero means create a toplevel window,
+ * zero means create a frame. */
+ Tcl_Obj *nameObj) /* Should only be non-NULL if there is no main
+ * window associated with the interpreter.
+ * Gives the base name to use for the new
+ * application. */
+{
+ int objc;
+ Tcl_Obj **objv;
+
+ if (TCL_OK != Tcl_ListObjGetElements(interp, listObj, &objc, &objv)) {
+ return TCL_ERROR;
+ }
+ return CreateFrame(clientData, interp, objc, objv,
+ toplevel ? TYPE_TOPLEVEL : TYPE_FRAME,
+ nameObj ? Tcl_GetString(nameObj) : NULL);
+}
+
static int
CreateFrame(
ClientData clientData, /* NULL. */
diff --git a/generic/tkGC.c b/generic/tkGC.c
index 5663ede..c424e30 100644
--- a/generic/tkGC.c
+++ b/generic/tkGC.c
@@ -314,7 +314,6 @@ Tk_FreeGC(
gcPtr = Tcl_GetHashValue(idHashPtr);
gcPtr->refCount--;
if (gcPtr->refCount == 0) {
- Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc));
XFreeGC(gcPtr->display, gcPtr->gc);
Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
Tcl_DeleteHashEntry(idHashPtr);
@@ -351,12 +350,6 @@ TkGCCleanup(
entryPtr != NULL; entryPtr = Tcl_NextHashEntry(&search)) {
gcPtr = Tcl_GetHashValue(entryPtr);
- /*
- * This call is not needed, as it is only used on Unix to restore the
- * Id to the stack pool, and we don't want to use them anymore.
- * Tk_FreeXId(gcPtr->display, (XID) XGContextFromGC(gcPtr->gc));
- */
-
XFreeGC(gcPtr->display, gcPtr->gc);
Tcl_DeleteHashEntry(gcPtr->valueHashPtr);
Tcl_DeleteHashEntry(entryPtr);
diff --git a/generic/tkImgGIF.c b/generic/tkImgGIF.c
index 27de486..1c28b54 100644
--- a/generic/tkImgGIF.c
+++ b/generic/tkImgGIF.c
@@ -393,7 +393,8 @@ FileReadGIF(
* image being read. */
{
int fileWidth, fileHeight, imageWidth, imageHeight;
- int nBytes, index = 0, argc = 0, i, result = TCL_ERROR;
+ unsigned int nBytes;
+ int index = 0, argc = 0, i, result = TCL_ERROR;
Tcl_Obj **objv;
unsigned char buf[100];
unsigned char *trashBuffer = NULL;
@@ -410,6 +411,7 @@ FileReadGIF(
* source and not a file.
*/
+ memset(colorMap, 0, MAXCOLORMAPSIZE*4);
memset(gifConfPtr, 0, sizeof(GIFImageConfig));
if (fileName == INLINE_DATA_BINARY || fileName == INLINE_DATA_BASE64) {
gifConfPtr->fromData = fileName;
@@ -425,8 +427,9 @@ FileReadGIF(
return TCL_ERROR;
}
for (i = 1; i < argc; i++) {
+ int optionIdx;
if (Tcl_GetIndexFromObjStruct(interp, objv[i], optionStrings,
- sizeof(char *), "option name", 0, &nBytes) != TCL_OK) {
+ sizeof(char *), "option name", 0, &optionIdx) != TCL_OK) {
return TCL_ERROR;
}
if (i == (argc-1)) {
@@ -590,8 +593,14 @@ FileReadGIF(
*/
if (trashBuffer == NULL) {
+ if (fileWidth > (int)((UINT_MAX/3)/fileHeight)) {
+ goto error;
+ }
nBytes = fileWidth * fileHeight * 3;
trashBuffer = ckalloc(nBytes);
+ if (trashBuffer) {
+ memset(trashBuffer, 0, nBytes);
+ }
}
/*
@@ -675,9 +684,18 @@ FileReadGIF(
block.offset[1] = 1;
block.offset[2] = 2;
block.offset[3] = (transparent>=0) ? 3 : 0;
+ if (imageWidth > INT_MAX/block.pixelSize) {
+ goto error;
+ }
block.pitch = block.pixelSize * imageWidth;
+ if (imageHeight > (int)(UINT_MAX/block.pitch)) {
+ goto error;
+ }
nBytes = block.pitch * imageHeight;
block.pixelPtr = ckalloc(nBytes);
+ if (block.pixelPtr) {
+ memset(block.pixelPtr, 0, nBytes);
+ }
if (ReadImage(gifConfPtr, interp, block.pixelPtr, chan, imageWidth,
imageHeight, colorMap, srcX, srcY, BitSet(buf[8], INTERLACE),
diff --git a/generic/tkImgPNG.c b/generic/tkImgPNG.c
index 8a740d2..c6e3029 100644
--- a/generic/tkImgPNG.c
+++ b/generic/tkImgPNG.c
@@ -10,6 +10,7 @@
* this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
+#include "assert.h"
#include "tkInt.h"
#define PNG_INT32(a,b,c,d) \
@@ -334,7 +335,7 @@ InitPNGImage(
if (Tcl_ZlibStreamInit(NULL, dir, TCL_ZLIB_FORMAT_ZLIB,
TCL_ZLIB_COMPRESS_DEFAULT, NULL, &pngPtr->stream) != TCL_OK) {
- if (interp) {
+ if (interp) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"zlib initialization failed", -1));
Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "ZLIB_INIT", NULL);
@@ -1846,6 +1847,13 @@ DecodeLine(
if (UnfilterLine(interp, pngPtr) == TCL_ERROR) {
return TCL_ERROR;
}
+ if (pngPtr->currentLine >= pngPtr->block.height) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "PNG image data overflow"));
+ Tcl_SetErrorCode(interp, "TK", "IMAGE", "PNG", "DATA_OVERFLOW", NULL);
+ return TCL_ERROR;
+ }
+
if (pngPtr->interlace) {
switch (pngPtr->phase) {
@@ -2175,10 +2183,13 @@ ReadIDAT(
/*
* Try to read another line of pixels out of the buffer
- * immediately.
+ * immediately, but don't allow write past end of block.
*/
- goto getNextLine;
+ if (pngPtr->currentLine < pngPtr->block.height) {
+ goto getNextLine;
+ }
+
}
/*
@@ -3345,7 +3356,7 @@ EncodePNG(
pngPtr->colorType = PNG_COLOR_RGBA;
pngPtr->bytesPerPixel = 4;
} else {
- pngPtr->colorType = PNG_COLOR_RGBA;
+ pngPtr->colorType = PNG_COLOR_RGB;
pngPtr->bytesPerPixel = 3;
}
} else {
diff --git a/generic/tkImgPhInstance.c b/generic/tkImgPhInstance.c
index 666a9b0..bd152f2 100644
--- a/generic/tkImgPhInstance.c
+++ b/generic/tkImgPhInstance.c
@@ -404,6 +404,9 @@ TkImgPhotoGet(
*
* Note that Win32 pre-defines those operations that we really need.
*
+ * Note that on MacOS, if the background comes from a Retina display
+ * then it will be twice as wide and twice as high as the photoimage.
+ *
*----------------------------------------------------------------------
*/
@@ -433,7 +436,16 @@ BlendComplexAlpha(
unsigned long pixel;
unsigned char r, g, b, alpha, unalpha, *masterPtr;
unsigned char *alphaAr = iPtr->masterPtr->pix32;
-
+#if defined(MAC_OSX_TK)
+ /* Background "pixels" are actually 2^pp x 2^pp blocks of subpixels. Each
+ * block gets blended with the color of one image pixel. Since we iterate
+ * over the background subpixels, we reset the width and height to the
+ * subpixel dimensions of the background image we are using.
+ */
+ int pp = bgImg->pixelpower;
+ width = width << pp;
+ height = height << pp;
+#endif
/*
* This blending is an integer version of the Source-Over compositing rule
* (see Porter&Duff, "Compositing Digital Images", proceedings of SIGGRAPH
@@ -532,9 +544,16 @@ BlendComplexAlpha(
#endif /* !_WIN32 && !MAC_OSX_TK */
for (y = 0; y < height; y++) {
+# if !defined(MAC_OSX_TK)
line = (y + yOffset) * iPtr->masterPtr->width;
for (x = 0; x < width; x++) {
masterPtr = alphaAr + ((line + x + xOffset) * 4);
+#else
+ /* Repeat each image row and column 2^pp times. */
+ line = ((y>>pp) + yOffset) * iPtr->masterPtr->width;
+ for (x = 0; x < width; x++) {
+ masterPtr = alphaAr + ((line + (x>>pp) + xOffset) * 4);
+#endif
alpha = masterPtr[3];
/*
@@ -635,7 +654,9 @@ TkImgPhotoDisplay(
(unsigned int)width, (unsigned int)height, AllPlanes, ZPixmap);
if (bgImg == NULL) {
Tk_DeleteErrorHandler(handler);
- /* We failed to get the image so draw without blending alpha. It's the best we can do */
+ /* We failed to get the image, so draw without blending alpha.
+ * It's the best we can do.
+ */
goto fallBack;
}
diff --git a/generic/tkImgPhoto.c b/generic/tkImgPhoto.c
index 9527c93..3e03f3d 100644
--- a/generic/tkImgPhoto.c
+++ b/generic/tkImgPhoto.c
@@ -886,6 +886,19 @@ ImgPhotoCmd(
break;
}
dataWidth = listObjc;
+ /*
+ * Memory allocation overflow protection.
+ * May not be able to trigger/ demo / test this.
+ */
+
+ if (dataWidth > (int)((UINT_MAX/3) / dataHeight)) {
+ Tcl_SetObjResult(interp, Tcl_NewStringObj(
+ "photo image dimensions exceed Tcl memory limits", -1));
+ Tcl_SetErrorCode(interp, "TK", "IMAGE", "PHOTO",
+ "OVERFLOW", NULL);
+ break;
+ }
+
pixelPtr = ckalloc(dataWidth * dataHeight * 3);
block.pixelPtr = pixelPtr;
} else if (listObjc != dataWidth) {
@@ -2051,8 +2064,8 @@ static int
ToggleComplexAlphaIfNeeded(
PhotoMaster *mPtr)
{
- size_t len = MAX(mPtr->userWidth, mPtr->width) *
- MAX(mPtr->userHeight, mPtr->height) * 4;
+ size_t len = (size_t)MAX(mPtr->userWidth, mPtr->width) *
+ (size_t)MAX(mPtr->userHeight, mPtr->height) * 4;
unsigned char *c = mPtr->pix32;
unsigned char *end = c + len;
@@ -2062,6 +2075,9 @@ ToggleComplexAlphaIfNeeded(
*/
mPtr->flags &= ~COMPLEX_ALPHA;
+ if (c == NULL) {
+ return 0;
+ }
c += 3; /* Start at first alpha byte. */
for (; c < end; c += 4) {
if (*c && *c != 255) {
@@ -2192,6 +2208,10 @@ ImgPhotoSetSize(
height = masterPtr->userHeight;
}
+ if (width > INT_MAX / 4) {
+ /* Pitch overflows int */
+ return TCL_ERROR;
+ }
pitch = width * 4;
/*
@@ -2201,11 +2221,12 @@ ImgPhotoSetSize(
if ((width != masterPtr->width) || (height != masterPtr->height)
|| (masterPtr->pix32 == NULL)) {
- /*
- * Not a u-long, but should be one.
- */
+ unsigned newPixSize;
- unsigned /*long*/ newPixSize = (unsigned /*long*/) (height * pitch);
+ if (pitch && height > (int)(UINT_MAX / pitch)) {
+ return TCL_ERROR;
+ }
+ newPixSize = height * pitch;
/*
* Some mallocs() really hate allocating zero bytes. [Bug 619544]
@@ -2257,14 +2278,14 @@ ImgPhotoSetSize(
if ((masterPtr->pix32 != NULL)
&& ((width == masterPtr->width) || (width == validBox.width))) {
if (validBox.y > 0) {
- memset(newPix32, 0, (size_t) (validBox.y * pitch));
+ memset(newPix32, 0, ((size_t) validBox.y * pitch));
}
h = validBox.y + validBox.height;
if (h < height) {
- memset(newPix32 + h*pitch, 0, (size_t) ((height - h) * pitch));
+ memset(newPix32 + h*pitch, 0, ((size_t) (height - h) * pitch));
}
} else {
- memset(newPix32, 0, (size_t) (height * pitch));
+ memset(newPix32, 0, ((size_t)height * pitch));
}
if (masterPtr->pix32 != NULL) {
@@ -2281,7 +2302,7 @@ ImgPhotoSetSize(
offset = validBox.y * pitch;
memcpy(newPix32 + offset, masterPtr->pix32 + offset,
- (size_t) (validBox.height * pitch));
+ ((size_t)validBox.height * pitch));
} else if ((validBox.width > 0) && (validBox.height > 0)) {
/*
@@ -2292,7 +2313,7 @@ ImgPhotoSetSize(
srcPtr = masterPtr->pix32 + (validBox.y * masterPtr->width
+ validBox.x) * 4;
for (h = validBox.height; h > 0; h--) {
- memcpy(destPtr, srcPtr, (size_t) (validBox.width * 4));
+ memcpy(destPtr, srcPtr, ((size_t)validBox.width * 4));
destPtr += width * 4;
srcPtr += masterPtr->width * 4;
}
@@ -2772,7 +2793,7 @@ Tk_PhotoPutBlock(
&& (blockPtr->pitch == pitch)))
&& (compRule == TK_PHOTO_COMPOSITE_SET)) {
memmove(destLinePtr, blockPtr->pixelPtr + blockPtr->offset[0],
- (size_t) (height * width * 4));
+ ((size_t)height * width * 4));
/*
* We know there's an alpha offset and we're setting the data, so skip
@@ -2804,7 +2825,7 @@ Tk_PhotoPutBlock(
&& (blueOffset == 2) && (alphaOffset == 3)
&& (width <= blockPtr->width)
&& compRuleSet) {
- memcpy(destLinePtr, srcLinePtr, (size_t) (width * 4));
+ memcpy(destLinePtr, srcLinePtr, ((size_t)width * 4));
srcLinePtr += blockPtr->pitch;
destLinePtr += pitch;
continue;
@@ -3454,7 +3475,7 @@ Tk_PhotoBlank(
*/
memset(masterPtr->pix32, 0,
- (size_t) (masterPtr->width * masterPtr->height * 4));
+ ((size_t)masterPtr->width * masterPtr->height * 4));
for (instancePtr = masterPtr->instancePtr; instancePtr != NULL;
instancePtr = instancePtr->nextPtr) {
TkImgResetDither(instancePtr);
@@ -3683,6 +3704,9 @@ ImgGetPhoto(
break;
}
}
+ if (!alphaOffset) {
+ blockPtr->offset[3]= -1; /* Tell caller alpha need not be read */
+ }
greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
if (((optPtr->options & OPT_BACKGROUND) && alphaOffset) ||
@@ -3696,6 +3720,10 @@ ImgGetPhoto(
if ((greenOffset||blueOffset) && !(optPtr->options & OPT_GRAYSCALE)) {
newPixelSize += 2;
}
+
+ if (blockPtr->height > (int)((UINT_MAX/newPixelSize)/blockPtr->width)) {
+ return NULL;
+ }
data = attemptckalloc(newPixelSize*blockPtr->width*blockPtr->height);
if (data == NULL) {
return NULL;
@@ -3803,9 +3831,6 @@ ImgGetPhoto(
blockPtr->offset[2] = 0;
blockPtr->offset[3]= 1;
}
- if (!alphaOffset) {
- blockPtr->offset[3]= -1;
- }
return data;
}
return NULL;
@@ -3835,32 +3860,30 @@ ImgStringWrite(
Tk_PhotoImageBlock *blockPtr)
{
int greenOffset, blueOffset;
- Tcl_DString data;
+ Tcl_Obj *data;
greenOffset = blockPtr->offset[1] - blockPtr->offset[0];
blueOffset = blockPtr->offset[2] - blockPtr->offset[0];
- Tcl_DStringInit(&data);
+ data = Tcl_NewObj();
if ((blockPtr->width > 0) && (blockPtr->height > 0)) {
- char *line = ckalloc((8 * blockPtr->width) + 2);
int row, col;
for (row=0; row<blockPtr->height; row++) {
+ Tcl_Obj *line = Tcl_NewObj();
unsigned char *pixelPtr = blockPtr->pixelPtr + blockPtr->offset[0]
+ row * blockPtr->pitch;
- char *linePtr = line;
for (col=0; col<blockPtr->width; col++) {
- sprintf(linePtr, " #%02x%02x%02x", *pixelPtr,
+ Tcl_AppendPrintfToObj(line, "%s#%02x%02x%02x",
+ col ? " " : "", *pixelPtr,
pixelPtr[greenOffset], pixelPtr[blueOffset]);
pixelPtr += blockPtr->pixelSize;
- linePtr += 8;
}
- Tcl_DStringAppendElement(&data, line+1);
+ Tcl_ListObjAppendElement(NULL, data, line);
}
- ckfree(line);
}
- Tcl_DStringResult(interp, &data);
+ Tcl_SetObjResult(interp, data);
return TCL_OK;
}
diff --git a/generic/tkInt.decls b/generic/tkInt.decls
index ebbadba..586b407 100644
--- a/generic/tkInt.decls
+++ b/generic/tkInt.decls
@@ -1017,6 +1017,9 @@ declare 50 aqua {
declare 51 aqua {
void TkGenWMDestroyEvent(Tk_Window tkwin)
}
+declare 52 aqua {
+ void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag)
+}
# removed duplicate from tkPlat table (tk.decls)
#declare 52 aqua {
diff --git a/generic/tkInt.h b/generic/tkInt.h
index b644c5b..1615a81 100644
--- a/generic/tkInt.h
+++ b/generic/tkInt.h
@@ -1196,7 +1196,7 @@ MODULE_SCOPE void TkUnderlineCharsInContext(Display *display,
const char *string, int numBytes, int x, int y,
int firstByte, int lastByte);
MODULE_SCOPE void TkpGetFontAttrsForChar(Tk_Window tkwin, Tk_Font tkfont,
- Tcl_UniChar c, struct TkFontAttributes *faPtr);
+ int c, struct TkFontAttributes *faPtr);
MODULE_SCOPE Tcl_Obj * TkNewWindowObj(Tk_Window tkwin);
MODULE_SCOPE void TkpShowBusyWindow(TkBusy busy);
MODULE_SCOPE void TkpHideBusyWindow(TkBusy busy);
@@ -1208,7 +1208,7 @@ MODULE_SCOPE void TkpCreateBusy(Tk_FakeWin *winPtr, Tk_Window tkRef,
MODULE_SCOPE int TkBackgroundEvalObjv(Tcl_Interp *interp,
int objc, Tcl_Obj *const *objv, int flags);
MODULE_SCOPE void TkSendVirtualEvent(Tk_Window tgtWin,
- const char *eventName);
+ const char *eventName, Tcl_Obj *detail);
MODULE_SCOPE Tcl_Command TkMakeEnsemble(Tcl_Interp *interp,
const char *nsname, const char *name,
ClientData clientData, const TkEnsemble *map);
@@ -1217,6 +1217,9 @@ MODULE_SCOPE int TkInitTkCmd(Tcl_Interp *interp,
MODULE_SCOPE int TkInitFontchooser(Tcl_Interp *interp,
ClientData clientData);
MODULE_SCOPE void TkpWarpPointer(TkDisplay *dispPtr);
+MODULE_SCOPE int TkListCreateFrame(ClientData clientData,
+ Tcl_Interp *interp, Tcl_Obj *listObj,
+ int toplevel, Tcl_Obj *nameObj);
#ifdef _WIN32
#define TkParseColor XParseColor
@@ -1229,6 +1232,14 @@ MODULE_SCOPE Status TkParseColor (Display * display,
MODULE_SCOPE void TkUnixSetXftClipRegion(TkRegion clipRegion);
#endif
+#if TCL_UTF_MAX > 4
+# define TkUtfToUniChar Tcl_UtfToUniChar
+# define TkUniCharToUtf Tcl_UniCharToUtf
+#else
+ MODULE_SCOPE int TkUtfToUniChar(const char *, int *);
+ MODULE_SCOPE int TkUniCharToUtf(int, char *);
+#endif
+
/*
* Unsupported commands.
*/
diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h
index 3a2a8aa..e48e803 100644
--- a/generic/tkIntPlatDecls.h
+++ b/generic/tkIntPlatDecls.h
@@ -250,7 +250,8 @@ EXTERN int TkGenerateButtonEvent(int x, int y, Window window,
unsigned int state);
/* 51 */
EXTERN void TkGenWMDestroyEvent(Tk_Window tkwin);
-/* Slot 52 is reserved */
+/* 52 */
+EXTERN void TkMacOSXSetDrawingEnabled(TkWindow *winPtr, int flag);
/* 53 */
EXTERN unsigned long TkpGetMS(void);
/* 54 */
@@ -395,7 +396,7 @@ typedef struct TkIntPlatStubs {
Window (*tkGetTransientMaster) (TkWindow *winPtr); /* 49 */
int (*tkGenerateButtonEvent) (int x, int y, Window window, unsigned int state); /* 50 */
void (*tkGenWMDestroyEvent) (Tk_Window tkwin); /* 51 */
- void (*reserved52)(void);
+ void (*tkMacOSXSetDrawingEnabled) (TkWindow *winPtr, int flag); /* 52 */
unsigned long (*tkpGetMS) (void); /* 53 */
void * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */
int (*tkpScanWindowId) (Tcl_Interp *interp, const char *string, Window *idPtr); /* 55 */
@@ -621,7 +622,8 @@ extern const TkIntPlatStubs *tkIntPlatStubsPtr;
(tkIntPlatStubsPtr->tkGenerateButtonEvent) /* 50 */
#define TkGenWMDestroyEvent \
(tkIntPlatStubsPtr->tkGenWMDestroyEvent) /* 51 */
-/* Slot 52 is reserved */
+#define TkMacOSXSetDrawingEnabled \
+ (tkIntPlatStubsPtr->tkMacOSXSetDrawingEnabled) /* 52 */
#define TkpGetMS \
(tkIntPlatStubsPtr->tkpGetMS) /* 53 */
#define TkMacOSXDrawable \
diff --git a/generic/tkListbox.c b/generic/tkListbox.c
index 437973a..b059727 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,37 @@ 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. */
+{
+ TkSendVirtualEvent(listPtr->tkwin, "ListboxSelect", NULL);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* EventuallyRedrawRange --
*
* Ensure that a given range of elements is eventually redrawn on the
@@ -3431,7 +3484,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 +3602,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/tkMain.c b/generic/tkMain.c
index f6f4013..1b21223 100644
--- a/generic/tkMain.c
+++ b/generic/tkMain.c
@@ -55,7 +55,16 @@ extern int TkCygwinMainEx(int, char **, Tcl_AppInitProc *, Tcl_Interp *);
* to strcmp here.
*/
#ifdef _WIN32
-# include "tclInt.h"
+/* Little hack to eliminate the need for "tclInt.h" here:
+ Just copy a small portion of TclIntPlatStubs, just
+ enough to make it work. See [600b72bfbc] */
+typedef struct {
+ int magic;
+ void *hooks;
+ void (*dummy[16]) (void); /* dummy entries 0-15, not used */
+ int (*tclpIsAtty) (int fd); /* 16 */
+} TclIntPlatStubs;
+extern const TclIntPlatStubs *tclIntPlatStubsPtr;
# include "tkWinInt.h"
#else
# define TCHAR char
@@ -108,9 +117,9 @@ static int WinIsTty(int fd) {
*/
#if !defined(STATIC_BUILD)
- if (tclStubsPtr->reserved9 && TclpIsAtty) {
+ if (tclStubsPtr->reserved9 && tclIntPlatStubsPtr->tclpIsAtty) {
/* We are running on Cygwin */
- return TclpIsAtty(fd);
+ return tclIntPlatStubsPtr->tclpIsAtty(fd);
}
#endif
handle = GetStdHandle(STD_INPUT_HANDLE + fd);
diff --git a/generic/tkMenu.c b/generic/tkMenu.c
index 354d329..7f5389c 100644
--- a/generic/tkMenu.c
+++ b/generic/tkMenu.c
@@ -38,7 +38,7 @@
* implemented using menu clones. Menu clones are full menus in their own
* right; they have a Tk window and pathname associated with them; they have a
* TkMenu structure and array of entries. However, they are linked with the
- * original menu that they were cloned from. The reflect the attributes of the
+ * original menu that they were cloned from. They reflect the attributes of the
* original, or "master", menu. So if an item is added to a menu, and that
* menu has clones, then the item must be added to all of its clones also.
* Menus are cloned when a menu is torn-off or when a menu is assigned as a
@@ -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/tkOldConfig.c b/generic/tkOldConfig.c
index d2d864f..920d93e 100644
--- a/generic/tkOldConfig.c
+++ b/generic/tkOldConfig.c
@@ -113,6 +113,10 @@ Tk_ConfigureWidget(
staticSpecs = GetCachedSpecs(interp, specs);
+ for (specPtr = staticSpecs; specPtr->type != TK_CONFIG_END; specPtr++) {
+ specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
+ }
+
/*
* Pass one: scan through all of the arguments, processing those that
* match entries in the specs.
@@ -167,7 +171,6 @@ Tk_ConfigureWidget(
if ((specPtr->specFlags & TK_CONFIG_OPTION_SPECIFIED)
|| (specPtr->argvName == NULL)
|| (specPtr->type == TK_CONFIG_SYNONYM)) {
- specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
continue;
}
if (((specPtr->specFlags & needFlags) != needFlags)
@@ -1126,7 +1129,6 @@ GetCachedSpecs(
specPtr->defValue = Tk_GetUid(specPtr->defValue);
}
}
- specPtr->specFlags &= ~TK_CONFIG_OPTION_SPECIFIED;
}
} else {
cachedSpecs = Tcl_GetHashValue(entryPtr);
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/tkPanedWindow.c b/generic/tkPanedWindow.c
index 733610e..f350d0a 100644
--- a/generic/tkPanedWindow.c
+++ b/generic/tkPanedWindow.c
@@ -147,6 +147,10 @@ typedef struct PanedWindow {
GC gc; /* Graphics context for copying from
* off-screen pixmap onto screen. */
int proxyx, proxyy; /* Proxy x,y coordinates. */
+ Tk_3DBorder proxyBackground;/* Background color used to draw proxy. If NULL, use background. */
+ Tcl_Obj *proxyBorderWidthPtr; /* Tcl_Obj rep for proxyBorderWidth */
+ int proxyBorderWidth; /* Borderwidth used to draw proxy. */
+ int proxyRelief; /* Relief used to draw proxy, if TK_RELIEF_NULL then use relief. */
Slave **slaves; /* Pointer to array of Slaves. */
int numSlaves; /* Number of slaves. */
int sizeofSlaves; /* Number of elements in the slaves array. */
@@ -203,6 +207,8 @@ static void PanedWindowReqProc(ClientData clientData,
static void ArrangePanes(ClientData clientData);
static void Unlink(Slave *slavePtr);
static Slave * GetPane(PanedWindow *pwPtr, Tk_Window tkwin);
+static void GetFirstLastVisiblePane(PanedWindow *pwPtr,
+ int *firstPtr, int *lastPtr);
static void SlaveStructureProc(ClientData clientData,
XEvent *eventPtr);
static int PanedWindowSashCommand(PanedWindow *pwPtr,
@@ -296,6 +302,15 @@ static const Tk_OptionSpec optionSpecs[] = {
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient",
DEF_PANEDWINDOW_ORIENT, -1, Tk_Offset(PanedWindow, orient),
0, orientStrings, GEOMETRY},
+ {TK_OPTION_BORDER, "-proxybackground", "proxyBackground", "ProxyBackground",
+ 0, -1, Tk_Offset(PanedWindow, proxyBackground), TK_OPTION_NULL_OK,
+ (ClientData) DEF_PANEDWINDOW_BG_MONO},
+ {TK_OPTION_PIXELS, "-proxyborderwidth", "proxyBorderWidth", "ProxyBorderWidth",
+ DEF_PANEDWINDOW_PROXYBORDER, Tk_Offset(PanedWindow, proxyBorderWidthPtr),
+ Tk_Offset(PanedWindow, proxyBorderWidth), 0, 0, GEOMETRY},
+ {TK_OPTION_RELIEF, "-proxyrelief", "proxyRelief", "Relief",
+ 0, -1, Tk_Offset(PanedWindow, proxyRelief),
+ TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_RELIEF, "-relief", "relief", "Relief",
DEF_PANEDWINDOW_RELIEF, -1, Tk_Offset(PanedWindow, relief), 0, 0, 0},
{TK_OPTION_CURSOR, "-sashcursor", "sashCursor", "Cursor",
@@ -682,6 +697,15 @@ PanedWindowWidgetObjCmd(
if (objc <= 4) {
tkwin = Tk_NameToWindow(interp, Tcl_GetString(objv[2]),
pwPtr->tkwin);
+ if (tkwin == NULL) {
+ /*
+ * Just a plain old bad window; Tk_NameToWindow filled in an
+ * error message for us.
+ */
+
+ result = TCL_ERROR;
+ break;
+ }
for (i = 0; i < pwPtr->numSlaves; i++) {
if (pwPtr->slaves[i]->tkwin == tkwin) {
resultObj = Tk_GetOptionInfo(interp,
@@ -1329,6 +1353,7 @@ PanedWindowEventProc(
XEvent *eventPtr) /* Information about event. */
{
PanedWindow *pwPtr = clientData;
+ int i;
if (eventPtr->type == Expose) {
if (pwPtr->tkwin != NULL && !(pwPtr->flags & REDRAW_PENDING)) {
@@ -1343,6 +1368,18 @@ PanedWindowEventProc(
}
} else if (eventPtr->type == DestroyNotify) {
DestroyPanedWindow(pwPtr);
+ } else if (eventPtr->type == UnmapNotify) {
+ for (i = 0; i < pwPtr->numSlaves; i++) {
+ if (!pwPtr->slaves[i]->hide) {
+ Tk_UnmapWindow(pwPtr->slaves[i]->tkwin);
+ }
+ }
+ } else if (eventPtr->type == MapNotify) {
+ for (i = 0; i < pwPtr->numSlaves; i++) {
+ if (!pwPtr->slaves[i]->hide) {
+ Tk_MapWindow(pwPtr->slaves[i]->tkwin);
+ }
+ }
}
}
@@ -1411,6 +1448,7 @@ DisplayPanedWindow(
Tk_Window tkwin = pwPtr->tkwin;
int i, sashWidth, sashHeight;
const int horizontal = (pwPtr->orient == ORIENT_HORIZONTAL);
+ int first, last;
pwPtr->flags &= ~REDRAW_PENDING;
if ((pwPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) {
@@ -1457,9 +1495,10 @@ DisplayPanedWindow(
* Draw the sashes.
*/
+ GetFirstLastVisiblePane(pwPtr, &first, &last);
for (i = 0; i < pwPtr->numSlaves - 1; i++) {
slavePtr = pwPtr->slaves[i];
- if (slavePtr->hide) {
+ if (slavePtr->hide || i == last) {
continue;
}
if (sashWidth > 0 && sashHeight > 0) {
@@ -1705,17 +1744,10 @@ ArrangePanes(
Tcl_Preserve(pwPtr);
/*
- * Find index of last visible pane.
+ * Find index of first and last visible panes.
*/
- for (i = 0, last = 0, first = -1; i < pwPtr->numSlaves; i++) {
- if (pwPtr->slaves[i]->hide == 0) {
- if (first < 0) {
- first = i;
- }
- last = i;
- }
- }
+ GetFirstLastVisiblePane(pwPtr, &first, &last);
/*
* First pass; compute sizes
@@ -2053,6 +2085,41 @@ GetPane(
}
/*
+ *----------------------------------------------------------------------
+ *
+ * GetFirstLastVisiblePane --
+ *
+ * Given panedwindow, find the index of the first and last visible panes
+ * of that paned window.
+ *
+ * Results:
+ * Index of the first and last visible panes.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GetFirstLastVisiblePane(
+ PanedWindow *pwPtr, /* Pointer to the paned window info. */
+ int *firstPtr, /* Returned index for first. */
+ int *lastPtr) /* Returned index for last. */
+{
+ int i;
+
+ for (i = 0, *lastPtr = 0, *firstPtr = -1; i < pwPtr->numSlaves; i++) {
+ if (pwPtr->slaves[i]->hide == 0) {
+ if (*firstPtr < 0) {
+ *firstPtr = i;
+ }
+ *lastPtr = i;
+ }
+ }
+}
+
+/*
*--------------------------------------------------------------
*
* SlaveStructureProc --
@@ -2553,7 +2620,7 @@ MoveSash(
slavePtr->paneWidth = slavePtr->width = slavePtr->sashx
- sashOffset - slavePtr->x - (2 * slavePtr->padx);
} else {
- slavePtr->paneWidth = slavePtr->height = slavePtr->sashy
+ slavePtr->paneHeight = slavePtr->height = slavePtr->sashy
- sashOffset - slavePtr->y - (2 * slavePtr->pady);
}
}
@@ -2726,8 +2793,10 @@ DisplayProxyWindow(
* Redraw the widget's background and border.
*/
- Tk_Fill3DRectangle(tkwin, pixmap, pwPtr->background, 0, 0,
- Tk_Width(tkwin), Tk_Height(tkwin), 2, pwPtr->sashRelief);
+ Tk_Fill3DRectangle(tkwin, pixmap,
+ pwPtr->proxyBackground ? pwPtr->proxyBackground : pwPtr->background,
+ 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), pwPtr->proxyBorderWidth,
+ (pwPtr->proxyRelief != TK_RELIEF_NULL) ? pwPtr->proxyRelief : pwPtr->sashRelief);
#ifndef TK_NO_DOUBLE_BUFFERING
/*
@@ -2771,6 +2840,7 @@ PanedWindowProxyCommand(
PROXY_COORD, PROXY_FORGET, PROXY_PLACE
};
int index, x, y, sashWidth, sashHeight;
+ int internalBW, pwWidth, pwHeight;
Tcl_Obj *coords[2];
if (objc < 3) {
@@ -2820,11 +2890,16 @@ PanedWindowProxyCommand(
return TCL_ERROR;
}
+ internalBW = Tk_InternalBorderWidth(pwPtr->tkwin);
if (pwPtr->orient == ORIENT_HORIZONTAL) {
if (x < 0) {
x = 0;
}
- y = Tk_InternalBorderWidth(pwPtr->tkwin);
+ pwWidth = Tk_Width(pwPtr->tkwin) - (2 * internalBW);
+ if (x > pwWidth) {
+ x = pwWidth;
+ }
+ y = Tk_InternalBorderWidth(pwPtr->tkwin);
sashWidth = pwPtr->sashWidth;
sashHeight = Tk_Height(pwPtr->tkwin) -
(2 * Tk_InternalBorderWidth(pwPtr->tkwin));
@@ -2832,6 +2907,10 @@ PanedWindowProxyCommand(
if (y < 0) {
y = 0;
}
+ pwHeight = Tk_Height(pwPtr->tkwin) - (2 * internalBW);
+ if (y > pwHeight) {
+ y = pwHeight;
+ }
x = Tk_InternalBorderWidth(pwPtr->tkwin);
sashHeight = pwPtr->sashWidth;
sashWidth = Tk_Width(pwPtr->tkwin) -
@@ -2966,6 +3045,7 @@ PanedWindowIdentifyCoords(
{
int i, sashHeight, sashWidth, thisx, thisy;
int found, isHandle, lpad, rpad, tpad, bpad;
+ int first, last;
if (pwPtr->orient == ORIENT_HORIZONTAL) {
if (Tk_IsMapped(pwPtr->tkwin)) {
@@ -3005,10 +3085,11 @@ PanedWindowIdentifyCoords(
lpad = rpad = 0;
}
+ GetFirstLastVisiblePane(pwPtr, &first, &last);
isHandle = 0;
found = -1;
for (i = 0; i < pwPtr->numSlaves - 1; i++) {
- if (pwPtr->slaves[i]->hide) {
+ if (pwPtr->slaves[i]->hide || i == last) {
continue;
}
thisx = pwPtr->slaves[i]->sashx;
diff --git a/generic/tkScale.c b/generic/tkScale.c
index cc7c294..cbc5202 100644
--- a/generic/tkScale.c
+++ b/generic/tkScale.c
@@ -303,6 +303,12 @@ Tk_ScaleObjCmd(
return TCL_ERROR;
}
+ /*
+ * The widget was just created, no command callback must be invoked.
+ */
+
+ scalePtr->flags &= ~INVOKE_COMMAND;
+
Tcl_SetObjResult(interp, TkNewWindowObj(scalePtr->tkwin));
return TCL_OK;
}
@@ -1268,7 +1274,14 @@ TkScaleSetValue(
return;
}
scalePtr->value = value;
- if (invokeCommand) {
+
+ /*
+ * Schedule command callback invocation only if there is such a command
+ * already registered, otherwise the callback would trigger later when
+ * configuring the widget -command option even if the value did not change.
+ */
+
+ if ((invokeCommand) && (scalePtr->command != NULL)) {
scalePtr->flags |= INVOKE_COMMAND;
}
TkEventuallyRedrawScale(scalePtr, REDRAW_SLIDER);
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/tkSelect.c b/generic/tkSelect.c
index ab9018a..74b3964 100644
--- a/generic/tkSelect.c
+++ b/generic/tkSelect.c
@@ -26,7 +26,7 @@ typedef struct {
int charOffset; /* The offset of the next char to retrieve. */
int byteOffset; /* The expected byte offset of the next
* chunk. */
- char buffer[TCL_UTF_MAX]; /* A buffer to hold part of a UTF character
+ char buffer[4]; /* A buffer to hold part of a UTF character
* that is split across chunks. */
char command[1]; /* Command to invoke. Actual space is
* allocated as large as necessary. This must
diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c
index f621d82..21e6a68 100644
--- a/generic/tkStubInit.c
+++ b/generic/tkStubInit.c
@@ -38,6 +38,15 @@ MODULE_SCOPE const TkStubs tkStubs;
*/
#undef Tk_MainEx
+#undef Tk_FreeXId
+
+static void
+doNothing(void)
+{
+ /* dummy implementation, no need to do anything */
+}
+
+#define Tk_FreeXId ((void (*)(Display *, XID)) doNothing)
#ifdef _WIN32
@@ -556,7 +565,7 @@ static const TkIntPlatStubs tkIntPlatStubs = {
TkGetTransientMaster, /* 49 */
TkGenerateButtonEvent, /* 50 */
TkGenWMDestroyEvent, /* 51 */
- 0, /* 52 */
+ TkMacOSXSetDrawingEnabled, /* 52 */
TkpGetMS, /* 53 */
TkMacOSXDrawable, /* 54 */
TkpScanWindowId, /* 55 */
diff --git a/generic/tkTest.c b/generic/tkTest.c
index fa9e073..faba89d 100644
--- a/generic/tkTest.c
+++ b/generic/tkTest.c
@@ -227,7 +227,7 @@ Tktest_Init(
{
static int initialized = 0;
- if (Tcl_InitStubs(interp, "8.1", 0) == NULL) {
+ if (Tcl_InitStubs(interp, "8.6", 0) == NULL) {
return TCL_ERROR;
}
if (Tk_InitStubs(interp, TK_VERSION, 0) == NULL) {
@@ -239,7 +239,7 @@ Tktest_Init(
*/
if (Tcl_PkgProvideEx(interp, "Tktest", TK_PATCH_LEVEL, NULL) == TCL_ERROR) {
- return TCL_ERROR;
+ return TCL_ERROR;
}
Tcl_CreateObjCommand(interp, "square", SquareObjCmd, NULL, NULL);
diff --git a/generic/tkText.c b/generic/tkText.c
index 0d06233..8ae17a5 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -122,7 +122,8 @@ static const Tk_ObjCustomOption lineOption = {
static const Tk_OptionSpec optionSpecs[] = {
{TK_OPTION_BOOLEAN, "-autoseparators", "autoSeparators",
"AutoSeparators", DEF_TEXT_AUTO_SEPARATORS, -1,
- Tk_Offset(TkText, autoSeparators), 0, 0, 0},
+ Tk_Offset(TkText, autoSeparators),
+ TK_OPTION_DONT_SET_DEFAULT, 0, 0},
{TK_OPTION_BORDER, "-background", "background", "Background",
DEF_TEXT_BG_COLOR, -1, Tk_Offset(TkText, border),
0, DEF_TEXT_BG_MONO, 0},
@@ -193,7 +194,8 @@ static const Tk_OptionSpec optionSpecs[] = {
DEF_TEXT_INSERT_WIDTH, -1, Tk_Offset(TkText, insertWidth),
0, 0, 0},
{TK_OPTION_INT, "-maxundo", "maxUndo", "MaxUndo",
- DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo), 0, 0, 0},
+ DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo),
+ TK_OPTION_DONT_SET_DEFAULT, 0, 0},
{TK_OPTION_PIXELS, "-padx", "padX", "Pad",
DEF_TEXT_PADX, -1, Tk_Offset(TkText, padX), 0, 0,
TK_TEXT_LINE_GEOMETRY},
@@ -211,18 +213,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},
@@ -239,7 +241,8 @@ static const Tk_OptionSpec optionSpecs[] = {
DEF_TEXT_TAKE_FOCUS, -1, Tk_Offset(TkText, takeFocus),
TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_BOOLEAN, "-undo", "undo", "Undo",
- DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo), 0, 0 , 0},
+ DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo),
+ TK_OPTION_DONT_SET_DEFAULT, 0 , 0},
{TK_OPTION_INT, "-width", "width", "Width",
DEF_TEXT_WIDTH, -1, Tk_Offset(TkText, width), 0, 0,
TK_TEXT_LINE_GEOMETRY},
@@ -401,7 +404,9 @@ static Tcl_Obj * TextGetText(const TkText *textPtr,
const TkTextIndex *index1,
const TkTextIndex *index2, int visibleOnly);
static void GenerateModifiedEvent(TkText *textPtr);
+static void GenerateUndoStackEvent(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,
@@ -542,7 +547,7 @@ CreateWidget(
Tcl_InitHashTable(&sharedPtr->windowTable, TCL_STRING_KEYS);
Tcl_InitHashTable(&sharedPtr->imageTable, TCL_STRING_KEYS);
sharedPtr->undoStack = TkUndoInitStack(interp,0);
- sharedPtr->undo = 1;
+ sharedPtr->undo = 0;
sharedPtr->isDirty = 0;
sharedPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL;
sharedPtr->autoSeparators = 1;
@@ -580,14 +585,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 +595,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 +707,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) {
@@ -917,43 +923,43 @@ TextWidgetObjCmd(
* We're going to count up all display lines in the logical
* line of 'indexFromPtr' up to, but not including the logical
* line of 'indexToPtr' (except if this line is elided), and
- * then subtract off what came in too much from elided lines,
- * also subtract off what we didn't want from 'from' and add
+ * then subtract off what came in too much from elided lines,
+ * also subtract off what we didn't want from 'from' and add
* on what we didn't count from 'to'.
*/
- while (TkTextIndexCmp(&index,indexToPtr) < 0) {
+ while (TkTextIndexCmp(&index,indexToPtr) < 0) {
value += TkTextUpdateOneLine(textPtr, index.linePtr,
- 0, &index, 0);
+ 0, &index, 0);
}
- index2 = index;
-
- /*
- * Now we need to adjust the count to:
- * - subtract off the number of display lines between
- * indexToPtr and index2, since we might have skipped past
- * indexToPtr, if we have several logical lines in a
- * single display line
- * - subtract off the number of display lines overcounted
- * in the first logical line
- * - add on the number of display lines in the last logical
- * line
- * This logic is still ok if both indexFromPtr and indexToPtr
- * are in the same logical line.
- */
-
- index = *indexToPtr;
- index.byteIndex = 0;
- while (TkTextIndexCmp(&index,&index2) < 0) {
- value -= TkTextUpdateOneLine(textPtr, index.linePtr,
- 0, &index, 0);
- }
+ index2 = index;
+
+ /*
+ * Now we need to adjust the count to:
+ * - subtract off the number of display lines between
+ * indexToPtr and index2, since we might have skipped past
+ * indexToPtr, if we have several logical lines in a
+ * single display line
+ * - subtract off the number of display lines overcounted
+ * in the first logical line
+ * - add on the number of display lines in the last logical
+ * line
+ * This logic is still ok if both indexFromPtr and indexToPtr
+ * are in the same logical line.
+ */
+
+ index = *indexToPtr;
+ index.byteIndex = 0;
+ while (TkTextIndexCmp(&index,&index2) < 0) {
+ value -= TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
+ }
index.linePtr = indexFromPtr->linePtr;
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
+ if (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
@@ -965,7 +971,7 @@ TextWidgetObjCmd(
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
+ if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
@@ -1392,6 +1398,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 +1522,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 +2044,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);
}
@@ -2044,7 +2097,7 @@ ConfigureText(
textPtr->sharedTextPtr->maxUndo = textPtr->maxUndo;
textPtr->sharedTextPtr->autoSeparators = textPtr->autoSeparators;
- TkUndoSetDepth(textPtr->sharedTextPtr->undoStack,
+ TkUndoSetMaxDepth(textPtr->sharedTextPtr->undoStack,
textPtr->sharedTextPtr->maxUndo);
/*
@@ -2142,10 +2195,10 @@ ConfigureText(
* Also, clamp the insert and current (unshared) marks to the new
* -startline/-endline range limits of the widget. All other (shared)
* marks are unchanged.
- * The return value of TkTextMarkNameToIndex does not need to be
- * checked: "insert" and "current" marks always exist, and the
- * purpose of the code below precisely is to move them inside the
- * -startline/-endline range.
+ * The return value of TkTextMarkNameToIndex does not need to be
+ * checked: "insert" and "current" marks always exist, and the
+ * purpose of the code below precisely is to move them inside the
+ * -startline/-endline range.
*/
textPtr->sharedTextPtr->stateEpoch++;
@@ -2204,12 +2257,20 @@ ConfigureText(
* replaced in the widget record.
*/
- textPtr->selTagPtr->border = textPtr->selBorder;
+ if (textPtr->selTagPtr->selBorder == NULL) {
+ textPtr->selTagPtr->border = textPtr->selBorder;
+ } else {
+ textPtr->selTagPtr->selBorder = textPtr->selBorder;
+ }
if (textPtr->selTagPtr->borderWidthPtr != textPtr->selBorderWidthPtr) {
textPtr->selTagPtr->borderWidthPtr = textPtr->selBorderWidthPtr;
textPtr->selTagPtr->borderWidth = textPtr->selBorderWidth;
}
- textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr;
+ if (textPtr->selTagPtr->selFgColor == NULL) {
+ textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr;
+ } else {
+ textPtr->selTagPtr->selFgColor = textPtr->selFgColorPtr;
+ }
textPtr->selTagPtr->affectsDisplay = 0;
textPtr->selTagPtr->affectsDisplayGeometry = 0;
if ((textPtr->selTagPtr->elideString != NULL)
@@ -2228,12 +2289,18 @@ ConfigureText(
textPtr->selTagPtr->affectsDisplayGeometry = 1;
}
if ((textPtr->selTagPtr->border != NULL)
+ || (textPtr->selTagPtr->selBorder != NULL)
|| (textPtr->selTagPtr->reliefString != NULL)
|| (textPtr->selTagPtr->bgStipple != None)
|| (textPtr->selTagPtr->fgColor != NULL)
+ || (textPtr->selTagPtr->selFgColor != NULL)
|| (textPtr->selTagPtr->fgStipple != None)
|| (textPtr->selTagPtr->overstrikeString != NULL)
- || (textPtr->selTagPtr->underlineString != NULL)) {
+ || (textPtr->selTagPtr->overstrikeColor != NULL)
+ || (textPtr->selTagPtr->underlineString != NULL)
+ || (textPtr->selTagPtr->underlineColor != NULL)
+ || (textPtr->selTagPtr->lMarginColor != NULL)
+ || (textPtr->selTagPtr->rMarginColor != NULL)) {
textPtr->selTagPtr->affectsDisplay = 1;
}
TkTextRedrawTag(NULL, textPtr, NULL, NULL, textPtr->selTagPtr, 1);
@@ -2344,6 +2411,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 +2423,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,
@@ -2702,6 +2773,10 @@ TextPushUndoAction(
/* Index describing second location. */
{
TkUndoSubAtom *iAtom, *dAtom;
+ int canUndo, canRedo;
+ char lMarkName[20] = "tk::undoMarkL";
+ char rMarkName[20] = "tk::undoMarkR";
+ char stringUndoMarkId[7] = "";
/*
* Create the helpers.
@@ -2712,6 +2787,10 @@ TextPushUndoAction(
Tcl_Obj *markSet2InsertObj = NULL;
Tcl_Obj *insertCmdObj = Tcl_NewObj();
Tcl_Obj *deleteCmdObj = Tcl_NewObj();
+ Tcl_Obj *markSetLUndoMarkCmdObj = Tcl_NewObj();
+ Tcl_Obj *markSetRUndoMarkCmdObj = NULL;
+ Tcl_Obj *markGravityLUndoMarkCmdObj = Tcl_NewObj();
+ Tcl_Obj *markGravityRUndoMarkCmdObj = NULL;
/*
* Get the index positions.
@@ -2761,6 +2840,40 @@ TextPushUndoAction(
Tcl_ListObjAppendElement(NULL, deleteCmdObj, index1Obj);
Tcl_ListObjAppendElement(NULL, deleteCmdObj, index2Obj);
+ Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj,
+ Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1));
+ Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj,
+ Tcl_NewStringObj("mark", 4));
+ Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj,
+ Tcl_NewStringObj("set", 3));
+ markSetRUndoMarkCmdObj = Tcl_DuplicateObj(markSetLUndoMarkCmdObj);
+ textPtr->sharedTextPtr->undoMarkId++;
+ sprintf(stringUndoMarkId, "%d", textPtr->sharedTextPtr->undoMarkId);
+ strcat(lMarkName, stringUndoMarkId);
+ strcat(rMarkName, stringUndoMarkId);
+ Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj,
+ Tcl_NewStringObj(lMarkName, -1));
+ Tcl_ListObjAppendElement(NULL, markSetRUndoMarkCmdObj,
+ Tcl_NewStringObj(rMarkName, -1));
+ Tcl_ListObjAppendElement(NULL, markSetLUndoMarkCmdObj, index1Obj);
+ Tcl_ListObjAppendElement(NULL, markSetRUndoMarkCmdObj, index2Obj);
+
+ Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj,
+ Tcl_NewStringObj(Tk_PathName(textPtr->tkwin), -1));
+ Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj,
+ Tcl_NewStringObj("mark", 4));
+ Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj,
+ Tcl_NewStringObj("gravity", 7));
+ markGravityRUndoMarkCmdObj = Tcl_DuplicateObj(markGravityLUndoMarkCmdObj);
+ Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj,
+ Tcl_NewStringObj(lMarkName, -1));
+ Tcl_ListObjAppendElement(NULL, markGravityRUndoMarkCmdObj,
+ Tcl_NewStringObj(rMarkName, -1));
+ Tcl_ListObjAppendElement(NULL, markGravityLUndoMarkCmdObj,
+ Tcl_NewStringObj("left", 4));
+ Tcl_ListObjAppendElement(NULL, markGravityRUndoMarkCmdObj,
+ Tcl_NewStringObj("right", 5));
+
/*
* Note: we don't wish to use textPtr->widgetCmd in these callbacks
* because if we delete the textPtr, but peers still exist, we will then
@@ -2778,16 +2891,27 @@ TextPushUndoAction(
insertCmdObj, NULL);
TkUndoMakeCmdSubAtom(NULL, markSet2InsertObj, iAtom);
TkUndoMakeCmdSubAtom(NULL, seeInsertObj, iAtom);
+ TkUndoMakeCmdSubAtom(NULL, markSetLUndoMarkCmdObj, iAtom);
+ TkUndoMakeCmdSubAtom(NULL, markSetRUndoMarkCmdObj, iAtom);
+ TkUndoMakeCmdSubAtom(NULL, markGravityLUndoMarkCmdObj, iAtom);
+ TkUndoMakeCmdSubAtom(NULL, markGravityRUndoMarkCmdObj, iAtom);
dAtom = TkUndoMakeSubAtom(&TextUndoRedoCallback, textPtr->sharedTextPtr,
deleteCmdObj, NULL);
TkUndoMakeCmdSubAtom(NULL, markSet1InsertObj, dAtom);
TkUndoMakeCmdSubAtom(NULL, seeInsertObj, dAtom);
+ TkUndoMakeCmdSubAtom(NULL, markSetLUndoMarkCmdObj, dAtom);
+ TkUndoMakeCmdSubAtom(NULL, markSetRUndoMarkCmdObj, dAtom);
+ TkUndoMakeCmdSubAtom(NULL, markGravityLUndoMarkCmdObj, dAtom);
+ TkUndoMakeCmdSubAtom(NULL, markGravityRUndoMarkCmdObj, dAtom);
Tcl_DecrRefCount(seeInsertObj);
Tcl_DecrRefCount(index1Obj);
Tcl_DecrRefCount(index2Obj);
+ canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
+ canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
+
/*
* Depending whether the action is to insert or delete, we provide the
* appropriate second and third arguments to TkUndoPushAction. (The first
@@ -2799,6 +2923,10 @@ TextPushUndoAction(
} else {
TkUndoPushAction(textPtr->sharedTextPtr->undoStack, dAtom, iAtom);
}
+
+ if (!canUndo || canRedo) {
+ GenerateUndoStackEvent(textPtr);
+ }
}
/*
@@ -2963,7 +3091,7 @@ CountIndices(
* If 'viewUpdate' is true, we may adjust the window contents'
* y-position, and scrollbar setting.
*
- * If 'viewUpdate' is false, true we can guarantee that textPtr->topIndex
+ * If 'viewUpdate' is true we can guarantee that textPtr->topIndex
* points to a valid TkTextLine after this function returns. However, if
* 'viewUpdate' is false, then there is no such guarantee (since
* topIndex.linePtr can be garbage). The caller is expected to take
@@ -3023,12 +3151,15 @@ DeleteIndexRange(
* dummy empty line at the end of the text. If the final newline of the
* file (just before the dummy line) is being deleted, then back up index
* to just before the newline. If there is a newline just before the first
- * character being deleted, then back up the first index too, so that an
- * even number of lines gets deleted. Furthermore, remove any tags that
- * are present on the newline that isn't going to be deleted after all
- * (this simulates deleting the newline and then adding a "clean" one back
- * again). Note that index1 and index2 might now be equal again which
- * means that no text will be deleted but tags might be removed.
+ * character being deleted, then back up the first index too. The idea is
+ * that a deletion involving a range starting at a line start and
+ * including the final \n (i.e. index2 is "end") is an attempt to delete
+ * complete lines, so the \n before the deleted block shall become the new
+ * final \n. Furthermore, remove any tags that are present on the newline
+ * that isn't going to be deleted after all (this simulates deleting the
+ * newline and then adding a "clean" one back again). Note that index1 and
+ * index2 might now be equal again which means that no text will be
+ * deleted but tags might be removed.
*/
line1 = TkBTreeLinesTo(textPtr, index1.linePtr);
@@ -3132,11 +3263,11 @@ DeleteIndexRange(
resetView = 1;
line = line1;
byteIndex = tPtr->topIndex.byteIndex;
- } else {
- /*
- * Deletion range starts after the top line. This peers's view
- * will not need to be reset. Nothing to do.
- */
+ } else {
+ /*
+ * Deletion range starts after the top line. This peers's view
+ * will not need to be reset. Nothing to do.
+ */
}
} else if (index2.linePtr == tPtr->topIndex.linePtr) {
/*
@@ -3153,11 +3284,11 @@ DeleteIndexRange(
} else {
byteIndex -= (index2.byteIndex - index1.byteIndex);
}
- } else {
- /*
- * Deletion range ends before the top line. This peers's view
- * will not need to be reset. Nothing to do.
- */
+ } else {
+ /*
+ * Deletion range ends before the top line. This peers's view
+ * will not need to be reset. Nothing to do.
+ */
}
if (resetView) {
lineAndByteIndex[resetViewCount] = line;
@@ -3202,43 +3333,43 @@ DeleteIndexRange(
TkTextIndex indexTmp;
if (tPtr == textPtr) {
- if (viewUpdate) {
- /*
- * line cannot be before -startline of textPtr because
- * this line corresponds to an index which is necessarily
- * between "1.0" and "end" relative to textPtr.
- * Therefore no need to clamp line to the -start/-end
- * range.
- */
+ if (viewUpdate) {
+ /*
+ * line cannot be before -startline of textPtr because
+ * this line corresponds to an index which is necessarily
+ * between "1.0" and "end" relative to textPtr.
+ * Therefore no need to clamp line to the -start/-end
+ * range.
+ */
TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, line,
byteIndex, &indexTmp);
TkTextSetYView(tPtr, &indexTmp, 0);
}
} else {
- TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, line,
+ TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, line,
byteIndex, &indexTmp);
- /*
- * line may be before -startline of tPtr and must be
- * clamped to -startline before providing it to
- * TkTextSetYView otherwise lines before -startline
- * would be displayed.
- * There is no need to worry about -endline however,
- * because the view will only be reset if the deletion
- * involves the TOP line of the screen
- */
-
- if (tPtr->start != NULL) {
- int start;
- TkTextIndex indexStart;
-
- start = TkBTreeLinesTo(NULL, tPtr->start);
- TkTextMakeByteIndex(sharedTextPtr->tree, NULL, start,
+ /*
+ * line may be before -startline of tPtr and must be
+ * clamped to -startline before providing it to
+ * TkTextSetYView otherwise lines before -startline
+ * would be displayed.
+ * There is no need to worry about -endline however,
+ * because the view will only be reset if the deletion
+ * involves the TOP line of the screen
+ */
+
+ if (tPtr->start != NULL) {
+ int start;
+ TkTextIndex indexStart;
+
+ start = TkBTreeLinesTo(NULL, tPtr->start);
+ TkTextMakeByteIndex(sharedTextPtr->tree, NULL, start,
0, &indexStart);
- if (TkTextIndexCmp(&indexTmp, &indexStart) < 0) {
- indexTmp = indexStart;
- }
- }
+ if (TkTextIndexCmp(&indexTmp, &indexStart) < 0) {
+ indexTmp = indexStart;
+ }
+ }
TkTextSetYView(tPtr, &indexTmp, 0);
}
}
@@ -3484,16 +3615,7 @@ TkTextSelectionEvent(
* event generate $textWidget <<Selection>>
*/
- 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("Selection");
- Tk_HandleEvent(&event.general);
+ TkSendVirtualEvent(textPtr->tkwin, "Selection", NULL);
}
/*
@@ -4240,7 +4362,11 @@ TextSearchFoundMatch(
matchOffset += Tcl_NumUtfChars(segPtr->body.chars, -1);
}
} else {
- leftToScan -= segPtr->size;
+ if (searchSpecPtr->exact) {
+ leftToScan -= segPtr->size;
+ } else {
+ leftToScan -= Tcl_NumUtfChars(segPtr->body.chars, -1);
+ }
}
curIndex.byteIndex += segPtr->size;
}
@@ -4382,7 +4508,7 @@ TkTextGetTabs(
Tcl_Obj **objv;
TkTextTabArray *tabArrayPtr;
TkTextTab *tabPtr;
- Tcl_UniChar ch;
+ int ch;
double prevStop, lastStop;
/*
* Map these strings to TkTextTabAlign values.
@@ -4489,7 +4615,7 @@ TkTextGetTabs(
* There may be a more efficient way of getting this.
*/
- Tcl_UtfToUniChar(Tcl_GetString(objv[i+1]), &ch);
+ TkUtfToUniChar(Tcl_GetString(objv[i+1]), &ch);
if (!Tcl_UniCharIsAlpha(ch)) {
continue;
}
@@ -4992,6 +5118,8 @@ TextEditUndo(
TkText *textPtr) /* Overall information about text widget. */
{
int status;
+ Tcl_Obj *cmdObj;
+ int code;
if (!textPtr->sharedTextPtr->undo) {
return TCL_OK;
@@ -5015,6 +5143,22 @@ TextEditUndo(
}
textPtr->sharedTextPtr->undo = 1;
+ /*
+ * Convert undo/redo temporary marks set by TkUndoRevert() into
+ * indices left in the interp result.
+ */
+
+ cmdObj = Tcl_ObjPrintf("::tk::TextUndoRedoProcessMarks %s",
+ Tk_PathName(textPtr->tkwin));
+ Tcl_IncrRefCount(cmdObj);
+ code = Tcl_EvalObjEx(textPtr->interp, cmdObj, TCL_EVAL_GLOBAL);
+ if (code != TCL_OK) {
+ Tcl_AddErrorInfo(textPtr->interp,
+ "\n (on undoing)");
+ Tcl_BackgroundException(textPtr->interp, code);
+ }
+ Tcl_DecrRefCount(cmdObj);
+
return status;
}
@@ -5040,6 +5184,8 @@ TextEditRedo(
TkText *textPtr) /* Overall information about text widget. */
{
int status;
+ Tcl_Obj *cmdObj;
+ int code;
if (!textPtr->sharedTextPtr->undo) {
return TCL_OK;
@@ -5062,6 +5208,23 @@ TextEditRedo(
textPtr->sharedTextPtr->dirtyMode = TK_TEXT_DIRTY_NORMAL;
}
textPtr->sharedTextPtr->undo = 1;
+
+ /*
+ * Convert undo/redo temporary marks set by TkUndoApply() into
+ * indices left in the interp result.
+ */
+
+ cmdObj = Tcl_ObjPrintf("::tk::TextUndoRedoProcessMarks %s",
+ Tk_PathName(textPtr->tkwin));
+ Tcl_IncrRefCount(cmdObj);
+ code = Tcl_EvalObjEx(textPtr->interp, cmdObj, TCL_EVAL_GLOBAL);
+ if (code != TCL_OK) {
+ Tcl_AddErrorInfo(textPtr->interp,
+ "\n (on undoing)");
+ Tcl_BackgroundException(textPtr->interp, code);
+ }
+ Tcl_DecrRefCount(cmdObj);
+
return status;
}
@@ -5090,11 +5253,16 @@ TextEditCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
int index, setModified, oldModified;
+ int canRedo = 0;
+ int canUndo = 0;
+
static const char *const editOptionStrings[] = {
- "modified", "redo", "reset", "separator", "undo", NULL
+ "canundo", "canredo", "modified", "redo", "reset", "separator",
+ "undo", NULL
};
enum editOptions {
- EDIT_MODIFIED, EDIT_REDO, EDIT_RESET, EDIT_SEPARATOR, EDIT_UNDO
+ EDIT_CANUNDO, EDIT_CANREDO, EDIT_MODIFIED, EDIT_REDO, EDIT_RESET,
+ EDIT_SEPARATOR, EDIT_UNDO
};
if (objc < 3) {
@@ -5108,6 +5276,26 @@ TextEditCmd(
}
switch ((enum editOptions) index) {
+ case EDIT_CANREDO:
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 3, objv, NULL);
+ return TCL_ERROR;
+ }
+ if (textPtr->sharedTextPtr->undo) {
+ canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canRedo));
+ break;
+ case EDIT_CANUNDO:
+ if (objc != 3) {
+ Tcl_WrongNumArgs(interp, 3, objv, NULL);
+ return TCL_ERROR;
+ }
+ if (textPtr->sharedTextPtr->undo) {
+ canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
+ }
+ Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canUndo));
+ break;
case EDIT_MODIFIED:
if (objc == 3) {
Tcl_SetObjResult(interp,
@@ -5149,18 +5337,28 @@ TextEditCmd(
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return TCL_ERROR;
}
+ canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
if (TextEditRedo(textPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to redo", -1));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_REDO", NULL);
return TCL_ERROR;
}
+ canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
+ if (!canUndo || !canRedo) {
+ GenerateUndoStackEvent(textPtr);
+ }
break;
case EDIT_RESET:
if (objc != 3) {
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return TCL_ERROR;
}
+ canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
+ canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
TkUndoClearStacks(textPtr->sharedTextPtr->undoStack);
+ if (canUndo || canRedo) {
+ GenerateUndoStackEvent(textPtr);
+ }
break;
case EDIT_SEPARATOR:
if (objc != 3) {
@@ -5174,11 +5372,16 @@ TextEditCmd(
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return TCL_ERROR;
}
+ canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
if (TextEditUndo(textPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to undo", -1));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_UNDO", NULL);
return TCL_ERROR;
}
+ canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
+ if (!canRedo || !canUndo) {
+ GenerateUndoStackEvent(textPtr);
+ }
break;
}
return TCL_OK;
@@ -5273,6 +5476,7 @@ TextGetText(
*
* Send an event that the text was modified. This is equivalent to:
* event generate $textWidget <<Modified>>
+ * for all peers of $textWidget.
*
* Results:
* None
@@ -5287,21 +5491,41 @@ static void
GenerateModifiedEvent(
TkText *textPtr) /* Information about text widget. */
{
- union {
- XEvent general;
- XVirtualEvent virtual;
- } event;
-
- Tk_MakeWindowExist(textPtr->tkwin);
-
- 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("Modified");
- Tk_HandleEvent(&event.general);
+ for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
+ textPtr = textPtr->next) {
+ Tk_MakeWindowExist(textPtr->tkwin);
+ TkSendVirtualEvent(textPtr->tkwin, "Modified", NULL);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * GenerateUndoStackEvent --
+ *
+ * Send an event that the undo or redo stack became empty or unempty.
+ * This is equivalent to:
+ * event generate $textWidget <<UndoStack>>
+ * for all peers of $textWidget.
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * May force the text window (and all peers) into existence.
+ *
+ *----------------------------------------------------------------------
+ */
+
+static void
+GenerateUndoStackEvent(
+ TkText *textPtr) /* Information about text widget. */
+{
+ for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
+ textPtr = textPtr->next) {
+ Tk_MakeWindowExist(textPtr->tkwin);
+ TkSendVirtualEvent(textPtr->tkwin, "UndoStack", NULL);
+ }
}
/*
@@ -5325,7 +5549,6 @@ UpdateDirtyFlag(
TkSharedText *sharedTextPtr)/* Information about text widget. */
{
int oldDirtyFlag;
- TkText *textPtr;
/*
* If we've been forced to be dirty, we stay dirty (until explicitly
@@ -5356,11 +5579,54 @@ UpdateDirtyFlag(
}
if (sharedTextPtr->isDirty == 0 || oldDirtyFlag == 0) {
- for (textPtr = sharedTextPtr->peers; textPtr != NULL;
- textPtr = textPtr->next) {
- GenerateModifiedEvent(textPtr);
+ GenerateModifiedEvent(sharedTextPtr->peers);
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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;
}
/*
@@ -5700,7 +5966,7 @@ SearchCore(
CLANG_ASSERT(pattern);
do {
- Tcl_UniChar ch;
+ int ch;
const char *p;
int lastFullLine = lastOffset;
@@ -5930,7 +6196,7 @@ SearchCore(
}
} else {
firstOffset = p - startOfLine +
- Tcl_UtfToUniChar(startOfLine+matchOffset,&ch);
+ TkUtfToUniChar(startOfLine+matchOffset,&ch);
}
}
} while (searchSpecPtr->all);
diff --git a/generic/tkText.h b/generic/tkText.h
index 99a4888..430c96b 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. */
@@ -347,6 +347,9 @@ typedef struct TkTextTag {
int lMargin2; /* Left margin for second and later display
* lines of each text line, in pixels. Only
* valid if lMargin2String is non-NULL. */
+ Tk_3DBorder lMarginColor; /* Used for drawing background in left margins.
+ * This is used for both lmargin1 and lmargin2.
+ * NULL means no value specified here. */
char *offsetString; /* -offset option string (malloc-ed). NULL
* means option not specified. */
int offset; /* Vertical offset of text's baseline from
@@ -358,10 +361,18 @@ typedef struct TkTextTag {
int overstrike; /* Non-zero means draw horizontal line through
* middle of text. Only valid if
* overstrikeString is non-NULL. */
+ XColor *overstrikeColor; /* Color for the overstrike. NULL means same
+ * color as foreground. */
char *rMarginString; /* -rmargin option string (malloc-ed). NULL
* means option not specified. */
int rMargin; /* Right margin for text, in pixels. Only
* valid if rMarginString is non-NULL. */
+ Tk_3DBorder rMarginColor; /* Used for drawing background in right margin.
+ * NULL means no value specified here. */
+ Tk_3DBorder selBorder; /* Used for drawing background for selected text.
+ * NULL means no value specified here. */
+ XColor *selFgColor; /* Foreground color for selected text. NULL means
+ * no value specified here. */
char *spacing1String; /* -spacing1 option string (malloc-ed). NULL
* means option not specified. */
int spacing1; /* Extra spacing above first display line for
@@ -389,6 +400,8 @@ typedef struct TkTextTag {
int underline; /* Non-zero means draw underline underneath
* text. Only valid if underlineString is
* non-NULL. */
+ XColor *underlineColor; /* Color for the underline. NULL means same
+ * color as foreground. */
TkWrapMode wrapMode; /* How to handle wrap-around for this tag.
* Must be TEXT_WRAPMODE_CHAR,
* TEXT_WRAPMODE_NONE, TEXT_WRAPMODE_WORD, or
@@ -567,6 +580,8 @@ typedef struct TkSharedText {
* statements. */
int autoSeparators; /* Non-zero means the separators will be
* inserted automatically. */
+ int undoMarkId; /* Counts undo marks temporarily used during
+ undo and redo operations. */
int isDirty; /* Flag indicating the 'dirtyness' of the
* text widget. If the flag is not zero,
* unsaved modifications have been applied to
@@ -785,6 +800,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 +1126,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 01ec22d..eb917cf 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -136,11 +136,15 @@ typedef struct StyleValues {
* line of each text line. */
int lMargin2; /* Left margin, in pixels, for second and
* later display lines of each text line. */
+ Tk_3DBorder lMarginColor; /* Color of left margins (1 and 2). */
int offset; /* Offset in pixels of baseline, relative to
* baseline of line. */
int overstrike; /* Non-zero means draw overstrike through
* text. */
+ XColor *overstrikeColor; /* Foreground color for overstrike through
+ * text. */
int rMargin; /* Right margin, in pixels. */
+ Tk_3DBorder rMarginColor; /* Color of right margin. */
int spacing1; /* Spacing above first dline in text line. */
int spacing2; /* Spacing between lines of dline. */
int spacing3; /* Spacing below last dline in text line. */
@@ -149,6 +153,8 @@ typedef struct StyleValues {
int tabStyle; /* One of TABULAR or WORDPROCESSOR. */
int underline; /* Non-zero means draw underline underneath
* text. */
+ XColor *underlineColor; /* Foreground color for underline underneath
+ * text. */
int elide; /* Zero means draw text, otherwise not. */
TkWrapMode wrapMode; /* How to handle wrap-around for this tag.
* One of TEXT_WRAPMODE_CHAR,
@@ -167,6 +173,8 @@ typedef struct TextStyle {
GC bgGC; /* Graphics context for background. None means
* use widget background. */
GC fgGC; /* Graphics context for foreground. */
+ GC ulGC; /* Graphics context for underline. */
+ GC ovGC; /* Graphics context for overstrike. */
StyleValues *sValuePtr; /* Raw information from which GCs were
* derived. */
Tcl_HashEntry *hPtr; /* Pointer to entry in styleTable. Used to
@@ -234,6 +242,14 @@ typedef struct DLine {
int spaceBelow; /* How much extra space was added to the
* bottom of the line because of spacing
* options. This is included in height. */
+ Tk_3DBorder lMarginColor; /* Background color of the area corresponding
+ * to the left margin of the display line. */
+ int lMarginWidth; /* Pixel width of the area corresponding to
+ * the left margin. */
+ Tk_3DBorder rMarginColor; /* Background color of the area corresponding
+ * to the right margin of the display line. */
+ int rMarginWidth; /* Pixel width of the area corresponding to
+ * the right margin. */
int length; /* Total length of line, in pixels. */
TkTextDispChunk *chunkPtr; /* Pointer to first chunk in list of all of
* those that are displayed on this line of
@@ -591,9 +607,10 @@ 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);
+ const TkTextIndex *indexPtr);
/*
* Result values returned by TextGetScrollInfoObj:
@@ -659,17 +676,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;
}
@@ -756,6 +764,7 @@ GetStyle(
TextStyle *stylePtr;
Tcl_HashEntry *hPtr;
int numTags, isNew, i;
+ int isSelected;
XGCValues gcValues;
unsigned long mask;
/*
@@ -766,6 +775,7 @@ GetStyle(
int fgPrio, fontPrio, fgStipplePrio;
int underlinePrio, elidePrio, justifyPrio, offsetPrio;
int lMargin1Prio, lMargin2Prio, rMarginPrio;
+ int lMarginColorPrio, rMarginColorPrio;
int spacing1Prio, spacing2Prio, spacing3Prio;
int overstrikePrio, tabPrio, tabStylePrio, wrapPrio;
@@ -780,11 +790,14 @@ GetStyle(
fgPrio = fontPrio = fgStipplePrio = -1;
underlinePrio = elidePrio = justifyPrio = offsetPrio = -1;
lMargin1Prio = lMargin2Prio = rMarginPrio = -1;
+ lMarginColorPrio = rMarginColorPrio = -1;
spacing1Prio = spacing2Prio = spacing3Prio = -1;
overstrikePrio = tabPrio = tabStylePrio = wrapPrio = -1;
memset(&styleValues, 0, sizeof(StyleValues));
styleValues.relief = TK_RELIEF_FLAT;
styleValues.fgColor = textPtr->fgColor;
+ styleValues.underlineColor = textPtr->fgColor;
+ styleValues.overstrikeColor = textPtr->fgColor;
styleValues.tkfont = textPtr->tkfont;
styleValues.justify = TK_JUSTIFY_LEFT;
styleValues.spacing1 = textPtr->spacing1;
@@ -794,12 +807,22 @@ GetStyle(
styleValues.tabStyle = textPtr->tabStyle;
styleValues.wrapMode = textPtr->wrapMode;
styleValues.elide = 0;
+ isSelected = 0;
+
+ for (i = 0 ; i < numTags; i++) {
+ if (textPtr->selTagPtr == tagPtrs[i]) {
+ isSelected = 1;
+ break;
+ }
+ }
for (i = 0 ; i < numTags; i++) {
Tk_3DBorder border;
+ XColor *fgColor;
tagPtr = tagPtrs[i];
border = tagPtr->border;
+ fgColor = tagPtr->fgColor;
/*
* If this is the selection tag, and inactiveSelBorder is NULL (the
@@ -819,6 +842,14 @@ GetStyle(
border = textPtr->inactiveSelBorder;
}
+ if ((tagPtr->selBorder != NULL) && (isSelected)) {
+ border = tagPtr->selBorder;
+ }
+
+ if ((tagPtr->selFgColor != None) && (isSelected)) {
+ fgColor = tagPtr->selFgColor;
+ }
+
if ((border != NULL) && (tagPtr->priority > borderPrio)) {
styleValues.border = border;
borderPrio = tagPtr->priority;
@@ -842,8 +873,8 @@ GetStyle(
styleValues.bgStipple = tagPtr->bgStipple;
bgStipplePrio = tagPtr->priority;
}
- if ((tagPtr->fgColor != None) && (tagPtr->priority > fgPrio)) {
- styleValues.fgColor = tagPtr->fgColor;
+ if ((fgColor != None) && (tagPtr->priority > fgPrio)) {
+ styleValues.fgColor = fgColor;
fgPrio = tagPtr->priority;
}
if ((tagPtr->tkfont != None) && (tagPtr->priority > fontPrio)) {
@@ -870,6 +901,11 @@ GetStyle(
styleValues.lMargin2 = tagPtr->lMargin2;
lMargin2Prio = tagPtr->priority;
}
+ if ((tagPtr->lMarginColor != NULL)
+ && (tagPtr->priority > lMarginColorPrio)) {
+ styleValues.lMarginColor = tagPtr->lMarginColor;
+ lMarginColorPrio = tagPtr->priority;
+ }
if ((tagPtr->offsetString != NULL)
&& (tagPtr->priority > offsetPrio)) {
styleValues.offset = tagPtr->offset;
@@ -879,12 +915,22 @@ GetStyle(
&& (tagPtr->priority > overstrikePrio)) {
styleValues.overstrike = tagPtr->overstrike;
overstrikePrio = tagPtr->priority;
+ if (tagPtr->overstrikeColor != None) {
+ styleValues.overstrikeColor = tagPtr->overstrikeColor;
+ } else if (fgColor != None) {
+ styleValues.overstrikeColor = fgColor;
+ }
}
if ((tagPtr->rMarginString != NULL)
&& (tagPtr->priority > rMarginPrio)) {
styleValues.rMargin = tagPtr->rMargin;
rMarginPrio = tagPtr->priority;
}
+ if ((tagPtr->rMarginColor != NULL)
+ && (tagPtr->priority > rMarginColorPrio)) {
+ styleValues.rMarginColor = tagPtr->rMarginColor;
+ rMarginColorPrio = tagPtr->priority;
+ }
if ((tagPtr->spacing1String != NULL)
&& (tagPtr->priority > spacing1Prio)) {
styleValues.spacing1 = tagPtr->spacing1;
@@ -914,6 +960,11 @@ GetStyle(
&& (tagPtr->priority > underlinePrio)) {
styleValues.underline = tagPtr->underline;
underlinePrio = tagPtr->priority;
+ if (tagPtr->underlineColor != None) {
+ styleValues.underlineColor = tagPtr->underlineColor;
+ } else if (fgColor != None) {
+ styleValues.underlineColor = fgColor;
+ }
}
if ((tagPtr->elideString != NULL)
&& (tagPtr->priority > elidePrio)) {
@@ -970,6 +1021,11 @@ GetStyle(
mask |= GCStipple|GCFillStyle;
}
stylePtr->fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues);
+ mask = GCForeground;
+ gcValues.foreground = styleValues.underlineColor->pixel;
+ stylePtr->ulGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues);
+ gcValues.foreground = styleValues.overstrikeColor->pixel;
+ stylePtr->ovGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues);
stylePtr->sValuePtr = (StyleValues *)
Tcl_GetHashKey(&textPtr->dInfoPtr->styleTable, hPtr);
stylePtr->hPtr = hPtr;
@@ -1010,6 +1066,12 @@ FreeStyle(
if (stylePtr->fgGC != None) {
Tk_FreeGC(textPtr->display, stylePtr->fgGC);
}
+ if (stylePtr->ulGC != None) {
+ Tk_FreeGC(textPtr->display, stylePtr->ulGC);
+ }
+ if (stylePtr->ovGC != None) {
+ Tk_FreeGC(textPtr->display, stylePtr->ovGC);
+ }
Tcl_DeleteHashEntry(stylePtr->hPtr);
ckfree(stylePtr);
}
@@ -1121,6 +1183,10 @@ LayoutDLine(
dlPtr->nextPtr = NULL;
dlPtr->flags = NEW_LAYOUT | OLD_Y_INVALID;
dlPtr->logicalLinesMerged = 0;
+ dlPtr->lMarginColor = NULL;
+ dlPtr->lMarginWidth = 0;
+ dlPtr->rMarginColor = NULL;
+ dlPtr->rMarginWidth = 0;
/*
* This is not necessarily totally correct, where we have merged logical
@@ -1395,6 +1461,7 @@ LayoutDLine(
x = chunkPtr->stylePtr->sValuePtr->lMargin2;
}
+ dlPtr->lMarginWidth = x;
if (wrapMode == TEXT_WRAPMODE_NONE) {
maxX = -1;
} else {
@@ -1648,7 +1715,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
@@ -1706,6 +1773,11 @@ LayoutDLine(
}
dlPtr->height += dlPtr->spaceAbove + dlPtr->spaceBelow;
dlPtr->baseline += dlPtr->spaceAbove;
+ dlPtr->lMarginColor = sValuePtr->lMarginColor;
+ dlPtr->rMarginColor = sValuePtr->rMarginColor;
+ if (wrapMode != TEXT_WRAPMODE_NONE) {
+ dlPtr->rMarginWidth = rMargin;
+ }
/*
* Recompute line length: may have changed because of justification.
@@ -2226,7 +2298,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.
@@ -2392,12 +2464,26 @@ DisplayDLine(
Tk_Width(textPtr->tkwin), dlPtr->height, 0, TK_RELIEF_FLAT);
/*
- * Next, draw background information for the whole line.
+ * Second, draw background information for the whole line.
*/
DisplayLineBackground(textPtr, dlPtr, prevPtr, pixmap);
/*
+ * Third, draw the background color of the left and right margins.
+ */
+ if (dlPtr->lMarginColor != NULL) {
+ Tk_Fill3DRectangle(textPtr->tkwin, pixmap, dlPtr->lMarginColor, 0, y,
+ dlPtr->lMarginWidth + dInfoPtr->x - dInfoPtr->curXPixelOffset,
+ dlPtr->height, 0, TK_RELIEF_FLAT);
+ }
+ if (dlPtr->rMarginColor != NULL) {
+ Tk_Fill3DRectangle(textPtr->tkwin, pixmap, dlPtr->rMarginColor,
+ dInfoPtr->maxX - dlPtr->rMarginWidth + dInfoPtr->curXPixelOffset,
+ y, dlPtr->rMarginWidth, dlPtr->height, 0, TK_RELIEF_FLAT);
+ }
+
+ /*
* Make another pass through all of the chunks to redraw the insertion
* cursor, if it is visible on this line. Must do it here rather than in
* the foreground pass below because otherwise a wide insertion cursor
@@ -2541,7 +2627,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 +2698,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 +2813,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 +2867,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 +2923,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 +2999,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 +3036,8 @@ AsyncUpdateLineMetrics(
lineNum = TkTextUpdateLineMetrics(textPtr, lineNum,
dInfoPtr->lastMetricUpdateLine, 256);
+ dInfoPtr->currentMetricUpdateLine = lineNum;
+
if (tkTextDebug) {
char buffer[2 * TCL_INTEGER_SPACE + 1];
@@ -2943,16 +3055,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 +3099,36 @@ AsyncUpdateLineMetrics(
/*
*----------------------------------------------------------------------
*
+ * GenerateWidgetViewSyncEvent --
+ *
+ * Send the <<WidgetViewSync>> event related to the text widget
+ * line metrics asynchronous update.
+ * This is equivalent to:
+ * event generate $textWidget <<WidgetViewSync>> -data $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 */
+{
+ TkSendVirtualEvent(textPtr->tkwin, "WidgetViewSync",
+ Tcl_NewBooleanObj(InSync));
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkTextUpdateLineMetrics --
*
* This function updates the pixel height calculations of a range of
@@ -3338,6 +3501,7 @@ TextInvalidateLineMetrics(
textPtr->refCount++;
dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
AsyncUpdateLineMetrics, textPtr);
+ GenerateWidgetViewSyncEvent(textPtr, 0);
}
}
@@ -3948,6 +4112,18 @@ DisplayText(
* warnings. */
Tcl_Interp *interp;
+#ifdef MAC_OSX_TK
+ /*
+ * If drawing is disabled, all we need to do is
+ * clear the REDRAW_PENDING flag.
+ */
+ TkWindow *winPtr = (TkWindow *)(textPtr->tkwin);
+ MacDrawable *macWin = winPtr->privatePtr;
+ if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){
+ dInfoPtr->flags &= ~REDRAW_PENDING;
+ return;
+ }
+#endif
if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
/*
@@ -3964,14 +4140,6 @@ DisplayText(
Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY);
}
- if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
- /*
- * The widget has been deleted. Don't do anything.
- */
-
- goto end;
- }
-
if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x)
|| (dInfoPtr->maxY <= dInfoPtr->y)) {
UpdateDisplayInfo(textPtr);
@@ -3983,14 +4151,6 @@ DisplayText(
Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY);
}
- if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
- /*
- * The widget has been deleted. Don't do anything.
- */
-
- goto end;
- }
-
/*
* Choose a new current item if that is needed (this could cause event
* handlers to be invoked, hence the preserve/release calls and the loop,
@@ -5046,6 +5206,7 @@ TkTextRelayoutWindow(
textPtr->refCount++;
dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
AsyncUpdateLineMetrics, textPtr);
+ GenerateWidgetViewSyncEvent(textPtr, 0);
}
}
}
@@ -5157,7 +5318,10 @@ TkTextSetYView(
dInfoPtr->newTopPixelOffset = 0;
goto scheduleUpdate;
- }
+ }
+ /*
+ * The line is already on screen, with no need to scroll.
+ */
return;
}
}
@@ -5220,6 +5384,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
@@ -6039,6 +6212,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
@@ -6582,6 +6784,7 @@ FindDLine(
const TkTextIndex *indexPtr)/* Index of desired character. */
{
DLine *dlPtrPrev;
+ TkTextIndex indexPtr2;
if (dlPtr == NULL) {
return NULL;
@@ -6606,24 +6809,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;
}
}
@@ -6653,7 +6890,7 @@ FindDLine(
static int
IsStartOfNotMergedLine(
TkText *textPtr, /* Widget record for text widget. */
- CONST TkTextIndex *indexPtr) /* Index to check. */
+ const TkTextIndex *indexPtr) /* Index to check. */
{
TkTextIndex indexPtr2;
@@ -7029,7 +7266,7 @@ TkTextIndexBbox(
dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
- /*
+ /*
* Two cases shall be trapped here because the logic later really
* needs dlPtr to be the display line containing indexPtr:
* 1. if no display line contains the desired index (NULL dlPtr)
@@ -7173,7 +7410,7 @@ TkTextDLineInfo(
dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
- /*
+ /*
* Two cases shall be trapped here because the logic later really
* needs dlPtr to be the display line containing indexPtr:
* 1. if no display line contains the desired index (NULL dlPtr)
@@ -7344,8 +7581,8 @@ TkTextCharLayoutProc(
if (bytesThatFit < maxBytes) {
if ((bytesThatFit == 0) && noCharsYet) {
- Tcl_UniChar ch;
- int chLen = Tcl_UtfToUniChar(p, &ch);
+ int ch;
+ int chLen = TkUtfToUniChar(p, &ch);
#if TK_LAYOUT_WITH_BASE_CHUNKS
bytesThatFit = CharChunkMeasureChars(chunkPtr, line,
@@ -7693,7 +7930,7 @@ CharDisplayProc(
y + baseline - sValuePtr->offset);
if (sValuePtr->underline) {
- TkUnderlineCharsInContext(display, dst, stylePtr->fgGC,
+ TkUnderlineCharsInContext(display, dst, stylePtr->ulGC,
sValuePtr->tkfont, string, numBytes,
ciPtr->baseChunkPtr->x + xDisplacement,
y + baseline - sValuePtr->offset,
@@ -7703,7 +7940,7 @@ CharDisplayProc(
Tk_FontMetrics fm;
Tk_GetFontMetrics(sValuePtr->tkfont, &fm);
- TkUnderlineCharsInContext(display, dst, stylePtr->fgGC,
+ TkUnderlineCharsInContext(display, dst, stylePtr->ovGC,
sValuePtr->tkfont, string, numBytes,
ciPtr->baseChunkPtr->x + xDisplacement,
y + baseline - sValuePtr->offset
@@ -7720,7 +7957,7 @@ CharDisplayProc(
Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string,
numBytes, offsetX, y + baseline - sValuePtr->offset);
if (sValuePtr->underline) {
- Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
+ Tk_UnderlineChars(display, dst, stylePtr->ulGC, sValuePtr->tkfont,
string, offsetX,
y + baseline - sValuePtr->offset,
0, numBytes);
@@ -7730,7 +7967,7 @@ CharDisplayProc(
Tk_FontMetrics fm;
Tk_GetFontMetrics(sValuePtr->tkfont, &fm);
- Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont,
+ Tk_UnderlineChars(display, dst, stylePtr->ovGC, sValuePtr->tkfont,
string, offsetX,
y + baseline - sValuePtr->offset
- fm.descent - (fm.ascent * 3) / 10,
diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c
index 70f74fb..7aebc84 100644
--- a/generic/tkTextIndex.c
+++ b/generic/tkTextIndex.c
@@ -40,9 +40,9 @@ static const char * StartEnd(TkText *textPtr, const char *string,
static int GetIndex(Tcl_Interp *interp, TkSharedText *sharedPtr,
TkText *textPtr, const char *string,
TkTextIndex *indexPtr, int *canCachePtr);
-static int IndexCountBytesOrdered(CONST TkText *textPtr,
- CONST TkTextIndex *indexPtr1,
- CONST TkTextIndex *indexPtr2);
+static int IndexCountBytesOrdered(const TkText *textPtr,
+ const TkTextIndex *indexPtr1,
+ const TkTextIndex *indexPtr2);
/*
* The "textindex" Tcl_Obj definition:
@@ -1636,9 +1636,9 @@ TkTextIndexForwChars(
int
TkTextIndexCountBytes(
- CONST TkText *textPtr,
- CONST TkTextIndex *indexPtr1, /* Index describing one location. */
- CONST TkTextIndex *indexPtr2) /* Index describing second location. */
+ const TkText *textPtr,
+ const TkTextIndex *indexPtr1, /* Index describing one location. */
+ const TkTextIndex *indexPtr2) /* Index describing second location. */
{
int compare = TkTextIndexCmp(indexPtr1, indexPtr2);
@@ -1653,11 +1653,11 @@ TkTextIndexCountBytes(
static int
IndexCountBytesOrdered(
- CONST TkText *textPtr,
- CONST TkTextIndex *indexPtr1,
+ const TkText *textPtr,
+ const TkTextIndex *indexPtr1,
/* Index describing location of character from
* which to count. */
- CONST TkTextIndex *indexPtr2)
+ const TkTextIndex *indexPtr2)
/* Index describing location of last character
* at which to stop the count. */
{
@@ -1683,7 +1683,7 @@ IndexCountBytesOrdered(
byteCount += segPtr->size;
}
- linePtr = indexPtr1->linePtr->nextPtr;
+ linePtr = TkBTreeNextLine(textPtr, indexPtr1->linePtr);
while (linePtr != indexPtr2->linePtr) {
for (segPtr = linePtr->segPtr; segPtr != NULL;
segPtr = segPtr->nextPtr) {
@@ -2205,7 +2205,7 @@ StartEnd(
TkText *textPtr, /* Information about text widget. */
const char *string, /* String to parse for additional info about
* modifier (count and units). Points to first
- * character of modifer word. */
+ * character of modifier word. */
TkTextIndex *indexPtr) /* Index to modify based on string. */
{
const char *p;
@@ -2298,9 +2298,9 @@ StartEnd(
int chSize = 1;
if (segPtr->typePtr == &tkTextCharType) {
- Tcl_UniChar ch;
+ int ch;
- chSize = Tcl_UtfToUniChar(segPtr->body.chars + offset, &ch);
+ chSize = TkUtfToUniChar(segPtr->body.chars + offset, &ch);
if (!Tcl_UniCharIsWordChar(ch)) {
break;
}
@@ -2327,7 +2327,7 @@ StartEnd(
int offset;
if (modifier == TKINDEX_DISPLAY) {
- TkTextIndexForwChars(NULL, indexPtr, 0, indexPtr,
+ TkTextIndexForwChars(textPtr, indexPtr, 0, indexPtr,
COUNT_DISPLAY_INDICES);
}
@@ -2343,9 +2343,9 @@ StartEnd(
int chSize = 1;
if (segPtr->typePtr == &tkTextCharType) {
- Tcl_UniChar ch;
- Tcl_UtfToUniChar(segPtr->body.chars + offset, &ch);
+ int ch;
+ TkUtfToUniChar(segPtr->body.chars + offset, &ch);
if (!Tcl_UniCharIsWordChar(ch)) {
break;
}
@@ -2356,11 +2356,20 @@ StartEnd(
}
firstChar = 0;
}
- offset -= chSize;
- indexPtr->byteIndex -= chSize;
+ if (offset == 0) {
+ if (modifier == TKINDEX_DISPLAY) {
+ TkTextIndexBackChars(textPtr, indexPtr, 1, indexPtr,
+ COUNT_DISPLAY_INDICES);
+ } else {
+ TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr,
+ COUNT_INDICES);
+ }
+ } else {
+ indexPtr->byteIndex -= chSize;
+ }
+ offset -= chSize;
if (offset < 0) {
- if (indexPtr->byteIndex < 0) {
- indexPtr->byteIndex = 0;
+ if (indexPtr->byteIndex == 0) {
goto done;
}
segPtr = TkTextIndexToSeg(indexPtr, &offset);
diff --git a/generic/tkTextTag.c b/generic/tkTextTag.c
index af3f235..dd3127d 100644
--- a/generic/tkTextTag.c
+++ b/generic/tkTextTag.c
@@ -30,7 +30,7 @@ static const char *const wrapStrings[] = {
/*
* The 'TkTextTabStyle' enum in tkText.h is used to define a type for the
* -tabstyle option of the Text widget. These values are used as indices into
- * the string table below. Tags are allowed an empty wrap value, but the
+ * the string table below. Tags are allowed an empty tabstyle value, but the
* widget as a whole is not.
*/
@@ -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,
@@ -61,15 +61,26 @@ static const Tk_OptionSpec tagOptionSpecs[] = {
NULL, -1, Tk_Offset(TkTextTag, lMargin1String), TK_OPTION_NULL_OK,0,0},
{TK_OPTION_STRING, "-lmargin2", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, lMargin2String), TK_OPTION_NULL_OK,0,0},
+ {TK_OPTION_BORDER, "-lmargincolor", NULL, NULL,
+ NULL, -1, Tk_Offset(TkTextTag, lMarginColor), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-offset", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, offsetString), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-overstrike", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, overstrikeString),
TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_COLOR, "-overstrikefg", NULL, NULL,
+ NULL, -1, Tk_Offset(TkTextTag, overstrikeColor),
+ TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-relief", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, reliefString), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-rmargin", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, rMarginString), TK_OPTION_NULL_OK, 0,0},
+ {TK_OPTION_BORDER, "-rmargincolor", NULL, NULL,
+ NULL, -1, Tk_Offset(TkTextTag, rMarginColor), TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_BORDER, "-selectbackground", NULL, NULL,
+ NULL, -1, Tk_Offset(TkTextTag, selBorder), TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_COLOR, "-selectforeground", NULL, NULL,
+ NULL, -1, Tk_Offset(TkTextTag, selFgColor), TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING, "-spacing1", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, spacing1String), TK_OPTION_NULL_OK,0,0},
{TK_OPTION_STRING, "-spacing2", NULL, NULL,
@@ -84,6 +95,9 @@ static const Tk_OptionSpec tagOptionSpecs[] = {
{TK_OPTION_STRING, "-underline", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, underlineString),
TK_OPTION_NULL_OK, 0, 0},
+ {TK_OPTION_COLOR, "-underlinefg", NULL, NULL,
+ NULL, -1, Tk_Offset(TkTextTag, underlineColor),
+ TK_OPTION_NULL_OK, 0, 0},
{TK_OPTION_STRING_TABLE, "-wrap", NULL, NULL,
NULL, -1, Tk_Offset(TkTextTag, wrapMode),
TK_OPTION_NULL_OK, wrapStrings, 0},
@@ -484,10 +498,18 @@ TkTextTagCmd(
*/
if (tagPtr == textPtr->selTagPtr) {
- textPtr->selBorder = tagPtr->border;
+ if (tagPtr->selBorder == NULL) {
+ textPtr->selBorder = tagPtr->border;
+ } else {
+ textPtr->selBorder = tagPtr->selBorder;
+ }
textPtr->selBorderWidth = tagPtr->borderWidth;
textPtr->selBorderWidthPtr = tagPtr->borderWidthPtr;
- textPtr->selFgColorPtr = tagPtr->fgColor;
+ if (tagPtr->selFgColor == NULL) {
+ textPtr->selFgColorPtr = tagPtr->fgColor;
+ } else {
+ textPtr->selFgColorPtr = tagPtr->selFgColor;
+ }
}
tagPtr->affectsDisplay = 0;
@@ -509,12 +531,18 @@ TkTextTagCmd(
tagPtr->affectsDisplayGeometry = 1;
}
if ((tagPtr->border != NULL)
+ || (tagPtr->selBorder != NULL)
|| (tagPtr->reliefString != NULL)
|| (tagPtr->bgStipple != None)
|| (tagPtr->fgColor != NULL)
+ || (tagPtr->selFgColor != NULL)
|| (tagPtr->fgStipple != None)
|| (tagPtr->overstrikeString != NULL)
- || (tagPtr->underlineString != NULL)) {
+ || (tagPtr->overstrikeColor != NULL)
+ || (tagPtr->underlineString != NULL)
+ || (tagPtr->underlineColor != NULL)
+ || (tagPtr->lMarginColor != NULL)
+ || (tagPtr->rMarginColor != NULL)) {
tagPtr->affectsDisplay = 1;
}
if (!newTag) {
@@ -1011,12 +1039,17 @@ TkTextCreateTag(
tagPtr->lMargin1 = 0;
tagPtr->lMargin2String = NULL;
tagPtr->lMargin2 = 0;
+ tagPtr->lMarginColor = NULL;
tagPtr->offsetString = NULL;
tagPtr->offset = 0;
tagPtr->overstrikeString = NULL;
tagPtr->overstrike = 0;
+ tagPtr->overstrikeColor = NULL;
tagPtr->rMarginString = NULL;
tagPtr->rMargin = 0;
+ tagPtr->rMarginColor = NULL;
+ tagPtr->selBorder = NULL;
+ tagPtr->selFgColor = NULL;
tagPtr->spacing1String = NULL;
tagPtr->spacing1 = 0;
tagPtr->spacing2String = NULL;
@@ -1028,6 +1061,7 @@ TkTextCreateTag(
tagPtr->tabStyle = TK_TEXT_TABSTYLE_NONE;
tagPtr->underlineString = NULL;
tagPtr->underline = 0;
+ tagPtr->underlineColor = NULL;
tagPtr->elideString = NULL;
tagPtr->elide = 0;
tagPtr->wrapMode = TEXT_WRAPMODE_NULL;
diff --git a/generic/tkTextWind.c b/generic/tkTextWind.c
index bd61d75..c9fc20f 100644
--- a/generic/tkTextWind.c
+++ b/generic/tkTextWind.c
@@ -1134,6 +1134,16 @@ TkTextEmbWinDisplayProc(
&lineX, &windowY, &width, &height);
windowX = lineX - chunkPtr->x + x;
+ /*
+ * Mark the window as displayed so that it won't get unmapped.
+ * This needs to be done before the next instruction block because
+ * Tk_MaintainGeometry/Tk_MapWindow will run event handlers, in
+ * particular for the <Map> event, and if the bound script deletes
+ * the embedded window its clients will get freed.
+ */
+
+ client->displayed = 1;
+
if (textPtr->tkwin == Tk_Parent(tkwin)) {
if ((windowX != Tk_X(tkwin)) || (windowY != Tk_Y(tkwin))
|| (Tk_ReqWidth(tkwin) != Tk_Width(tkwin))
@@ -1145,12 +1155,6 @@ TkTextEmbWinDisplayProc(
Tk_MaintainGeometry(tkwin, textPtr->tkwin, windowX, windowY,
width, height);
}
-
- /*
- * Mark the window as displayed so that it won't get unmapped.
- */
-
- client->displayed = 1;
}
/*
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index 8359e0a..c66905d 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -353,7 +353,7 @@ TkUndoInitStack(
/*
*----------------------------------------------------------------------
*
- * TkUndoSetDepth --
+ * TkUndoSetMaxDepth --
*
* Set the maximum depth of stack.
*
@@ -368,7 +368,7 @@ TkUndoInitStack(
*/
void
-TkUndoSetDepth(
+TkUndoSetMaxDepth(
TkUndoRedoStack *stack, /* An Undo/Redo stack */
int maxdepth) /* The maximum stack depth */
{
@@ -478,6 +478,52 @@ TkUndoFreeStack(
/*
*----------------------------------------------------------------------
*
+ * TkUndoCanRedo --
+ *
+ * Returns true if redo is possible, i.e. if the redo stack is not empty.
+ *
+ * Results:
+ * A boolean.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkUndoCanRedo(
+ TkUndoRedoStack *stack) /* An Undo/Redo stack */
+{
+ return stack->redoStack != NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkUndoCanUndo --
+ *
+ * Returns true if undo is possible, i.e. if the undo stack is not empty.
+ *
+ * Results:
+ * A boolean.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+int
+TkUndoCanUndo(
+ TkUndoRedoStack *stack) /* An Undo/Redo stack */
+{
+ return stack->undoStack != NULL;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
* TkUndoInsertUndoSeparator --
*
* Insert a separator on the undo stack, indicating a border for an
@@ -498,7 +544,7 @@ TkUndoInsertUndoSeparator(
{
if (TkUndoInsertSeparator(&stack->undoStack)) {
stack->depth++;
- TkUndoSetDepth(stack, stack->maxdepth);
+ TkUndoSetMaxDepth(stack, stack->maxdepth);
}
}
diff --git a/generic/tkUndo.h b/generic/tkUndo.h
index e63aac4..490ede9 100644
--- a/generic/tkUndo.h
+++ b/generic/tkUndo.h
@@ -96,9 +96,11 @@ MODULE_SCOPE void TkUndoClearStack(TkUndoAtom **stack);
*/
MODULE_SCOPE TkUndoRedoStack *TkUndoInitStack(Tcl_Interp *interp, int maxdepth);
-MODULE_SCOPE void TkUndoSetDepth(TkUndoRedoStack *stack, int maxdepth);
+MODULE_SCOPE void TkUndoSetMaxDepth(TkUndoRedoStack *stack, int maxdepth);
MODULE_SCOPE void TkUndoClearStacks(TkUndoRedoStack *stack);
MODULE_SCOPE void TkUndoFreeStack(TkUndoRedoStack *stack);
+MODULE_SCOPE int TkUndoCanRedo(TkUndoRedoStack *stack);
+MODULE_SCOPE int TkUndoCanUndo(TkUndoRedoStack *stack);
MODULE_SCOPE void TkUndoInsertUndoSeparator(TkUndoRedoStack *stack);
MODULE_SCOPE TkUndoSubAtom *TkUndoMakeCmdSubAtom(Tcl_Command command,
Tcl_Obj *actionScript, TkUndoSubAtom *subAtomList);
diff --git a/generic/tkUtil.c b/generic/tkUtil.c
index 7ff9ecb..d89282f 100644
--- a/generic/tkUtil.c
+++ b/generic/tkUtil.c
@@ -1162,7 +1162,8 @@ TkMakeEnsemble(
* TkSendVirtualEvent --
*
* Send a virtual event notification to the specified target window.
- * Equivalent to "event generate $target <<$eventName>>"
+ * Equivalent to:
+ * "event generate $target <<$eventName>> -data $detail"
*
* Note that we use Tk_QueueWindowEvent, not Tk_HandleEvent, so this
* routine does not reenter the interpreter.
@@ -1173,7 +1174,8 @@ TkMakeEnsemble(
void
TkSendVirtualEvent(
Tk_Window target,
- const char *eventName)
+ const char *eventName,
+ Tcl_Obj *detail)
{
union {XEvent general; XVirtualEvent virtual;} event;
@@ -1184,9 +1186,92 @@ TkSendVirtualEvent(
event.general.xany.window = Tk_WindowId(target);
event.general.xany.display = Tk_Display(target);
event.virtual.name = Tk_GetUid(eventName);
+ if (detail != NULL) {
+ event.virtual.user_data = detail;
+ }
Tk_QueueWindowEvent(&event.general, TCL_QUEUE_TAIL);
}
+
+#if TCL_UTF_MAX <= 4
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkUtfToUniChar --
+ *
+ * Almost the same as Tcl_UtfToUniChar but using int instead of Tcl_UniChar.
+ * This function is capable of collapsing a upper/lower surrogate pair to a
+ * single unicode character. So, up to 6 bytes might be consumed.
+ *
+ * Results:
+ * *chPtr is filled with the Tcl_UniChar, and the return value is the
+ * number of bytes from the UTF-8 string that were consumed.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+TkUtfToUniChar(
+ const char *src, /* The UTF-8 string. */
+ int *chPtr) /* Filled with the Tcl_UniChar represented by
+ * the UTF-8 string. */
+{
+ Tcl_UniChar uniChar = 0;
+
+ int len = Tcl_UtfToUniChar(src, &uniChar);
+ if ((uniChar & 0xfc00) == 0xd800) {
+ Tcl_UniChar high = uniChar;
+ /* This can only happen if Tcl is compiled with TCL_UTF_MAX=4,
+ * or when a high surrogate character is detected in UTF-8 form */
+ int len2 = Tcl_UtfToUniChar(src+len, &uniChar);
+ if ((uniChar & 0xfc00) == 0xdc00) {
+ *chPtr = (((high & 0x3ff) << 10) | (uniChar & 0x3ff)) + 0x10000;
+ len += len2;
+ } else {
+ *chPtr = high;
+ }
+ } else {
+ *chPtr = uniChar;
+ }
+ return len;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
+ * TkUniCharToUtf --
+ *
+ * Almost the same as Tcl_UniCharToUtf but producing surrogates if
+ * TCL_UTF_MAX==3. So, up to 6 bytes might be produced.
+ *
+ * Results:
+ * *buf is filled with the UTF-8 string, and the return value is the
+ * number of bytes produced.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int TkUniCharToUtf(int ch, char *buf)
+{
+ int size = Tcl_UniCharToUtf(ch, buf);
+ if ((ch > 0xffff) && (ch <= 0x10ffff) && (size < 4)) {
+ /* Hey, this is wrong, we must be running TCL_UTF_MAX==3
+ * The best thing we can do is spit out 2 surrogates */
+ ch -= 0x10000;
+ size = Tcl_UniCharToUtf(((ch >> 10) | 0xd800), buf);
+ size += Tcl_UniCharToUtf(((ch & 0x3ff) | 0xdc00), buf+size);
+ }
+ return size;
+}
+
+
+#endif
/*
* Local Variables:
* mode: c
diff --git a/generic/tkWindow.c b/generic/tkWindow.c
index b5cbbab..5855b7c 100644
--- a/generic/tkWindow.c
+++ b/generic/tkWindow.c
@@ -54,12 +54,6 @@ typedef struct ThreadSpecificData {
static Tcl_ThreadDataKey dataKey;
/*
- * The Mutex below is used to lock access to the Tk_Uid structs above.
- */
-
-TCL_DECLARE_MUTEX(windowMutex)
-
-/*
* Default values for "changes" and "atts" fields of TkWindows. Note that Tk
* always requests all events for all windows, except StructureNotify events
* on internal windows: these events are generated internally.
@@ -206,40 +200,6 @@ static const TkCmd commands[] = {
};
/*
- * The variables and table below are used to parse arguments from the "argv"
- * variable in Tk_Init.
- */
-
-static int synchronize = 0;
-static char *name = NULL;
-static char *display = NULL;
-static char *geometry = NULL;
-static char *colormap = NULL;
-static char *use = NULL;
-static char *visual = NULL;
-static int rest = 0;
-
-static const Tk_ArgvInfo argTable[] = {
- {"-colormap", TK_ARGV_STRING, NULL, (char *) &colormap,
- "Colormap for main window"},
- {"-display", TK_ARGV_STRING, NULL, (char *) &display,
- "Display to use"},
- {"-geometry", TK_ARGV_STRING, NULL, (char *) &geometry,
- "Initial geometry for window"},
- {"-name", TK_ARGV_STRING, NULL, (char *) &name,
- "Name to use for application"},
- {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
- "Use synchronous mode for display server"},
- {"-visual", TK_ARGV_STRING, NULL, (char *) &visual,
- "Visual for main window"},
- {"-use", TK_ARGV_STRING, NULL, (char *) &use,
- "Id of window in which to embed application"},
- {"--", TK_ARGV_REST, (char *) 1, (char *) &rest,
- "Pass all remaining arguments through to script"},
- {NULL, TK_ARGV_END, NULL, NULL, NULL}
-};
-
-/*
* Forward declarations to functions defined later in this file:
*/
@@ -2391,6 +2351,9 @@ Tk_IdToWindow(
break;
}
}
+ if (window == None) {
+ return NULL;
+ }
hPtr = Tcl_FindHashEntry(&dispPtr->winTable, (char *) window);
if (hPtr == NULL) {
@@ -3028,16 +2991,51 @@ MODULE_SCOPE const TkStubs tkStubs;
*/
static int
+CopyValue(
+ ClientData dummy,
+ Tcl_Obj *objPtr,
+ void *dstPtr)
+{
+ *(Tcl_Obj **)dstPtr = objPtr;
+ return 1;
+}
+
+static int
Initialize(
Tcl_Interp *interp) /* Interpreter to initialize. */
{
- char *p;
- int argc, code;
- const char **argv;
- const char *args[20];
- const char *argString = NULL;
- Tcl_DString class;
+ int code = TCL_OK;
ThreadSpecificData *tsdPtr;
+ Tcl_Obj *value = NULL;
+ Tcl_Obj *cmd;
+
+ Tcl_Obj *nameObj = NULL;
+ Tcl_Obj *classObj = NULL;
+ Tcl_Obj *displayObj = NULL;
+ Tcl_Obj *colorMapObj = NULL;
+ Tcl_Obj *useObj = NULL;
+ Tcl_Obj *visualObj = NULL;
+ Tcl_Obj *geometryObj = NULL;
+
+ int sync = 0;
+
+ const Tcl_ArgvInfo table[] = {
+ {TCL_ARGV_CONSTANT, "-sync", INT2PTR(1), &sync,
+ "Use synchronous mode for display server", NULL},
+ {TCL_ARGV_FUNC, "-colormap", CopyValue, &colorMapObj,
+ "Colormap for main window", NULL},
+ {TCL_ARGV_FUNC, "-display", CopyValue, &displayObj,
+ "Display to use", NULL},
+ {TCL_ARGV_FUNC, "-geometry", CopyValue, &geometryObj,
+ "Initial geometry for window", NULL},
+ {TCL_ARGV_FUNC, "-name", CopyValue, &nameObj,
+ "Name to use for application", NULL},
+ {TCL_ARGV_FUNC, "-visual", CopyValue, &visualObj,
+ "Visual for main window", NULL},
+ {TCL_ARGV_FUNC, "-use", CopyValue, &useObj,
+ "Id of window in which to embed application", NULL},
+ TCL_ARGV_AUTO_REST, TCL_ARGV_AUTO_HELP, TCL_ARGV_TABLE_END
+ };
/*
* Ensure that we are getting a compatible version of Tcl.
@@ -3056,23 +3054,6 @@ Initialize(
tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
/*
- * Start by initializing all the static variables to default acceptable
- * values so that no information is leaked from a previous run of this
- * code.
- */
-
- Tcl_MutexLock(&windowMutex);
- synchronize = 0;
- name = NULL;
- display = NULL;
- geometry = NULL;
- colormap = NULL;
- use = NULL;
- visual = NULL;
- rest = 0;
- argv = NULL;
-
- /*
* We start by resetting the result because it might not be clean.
*/
@@ -3084,8 +3065,6 @@ Initialize(
* master.
*/
- Tcl_DString ds;
-
/*
* Step 1 : find the master and construct the interp name (could be a
* function if new APIs were ok). We could also construct the path
@@ -3095,18 +3074,13 @@ Initialize(
Tcl_Interp *master = interp;
- while (1) {
+ while (Tcl_IsSafe(master)) {
master = Tcl_GetMaster(master);
if (master == NULL) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"no controlling master interpreter", -1));
Tcl_SetErrorCode(interp, "TK", "SAFE", "NO_MASTER", NULL);
- code = TCL_ERROR;
- goto done;
- }
- if (!Tcl_IsSafe(master)) {
- /* Found the trusted master. */
- break;
+ return TCL_ERROR;
}
}
@@ -3116,39 +3090,30 @@ Initialize(
code = Tcl_GetInterpPath(master, interp);
if (code != TCL_OK) {
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "error in Tcl_GetInterpPath", -1));
- Tcl_SetErrorCode(interp, "TK", "SAFE", "FAILED", NULL);
- goto done;
+ Tcl_Panic("Tcl_GetInterpPath broken!");
}
/*
- * Build the string to eval.
+ * Build the command to eval in trusted master.
*/
- Tcl_DStringInit(&ds);
- Tcl_DStringAppendElement(&ds, "::safe::TkInit");
- Tcl_DStringAppendElement(&ds, Tcl_GetString(Tcl_GetObjResult(master)));
+ cmd = Tcl_NewListObj(2, NULL);
+ Tcl_ListObjAppendElement(NULL, cmd,
+ Tcl_NewStringObj("::safe::TkInit", -1));
+ Tcl_ListObjAppendElement(NULL, cmd, Tcl_GetObjResult(master));
/*
* Step 2 : Eval in the master. The argument is the *reversed* interp
* path of the slave.
*/
- code = Tcl_EvalEx(master, Tcl_DStringValue(&ds), -1, 0);
+ Tcl_IncrRefCount(cmd);
+ code = Tcl_EvalObjEx(master, cmd, 0);
+ Tcl_DecrRefCount(cmd);
+ Tcl_TransferResult(master, code, interp);
if (code != TCL_OK) {
- /*
- * We might want to transfer the error message or not. We don't.
- * (No API to do it and maybe security reasons).
- */
-
- Tcl_DStringFree(&ds);
- Tcl_SetObjResult(interp, Tcl_NewStringObj(
- "not allowed to start Tk by master's safe::TkInit", -1));
- Tcl_SetErrorCode(interp, "TK", "SAFE", "FAILED", NULL);
- goto done;
+ return code;
}
- Tcl_DStringFree(&ds);
/*
* Use the master's result as argv. Note: We don't use the Obj
@@ -3156,7 +3121,7 @@ Initialize(
* changing the code below.
*/
- argString = Tcl_GetString(Tcl_GetObjResult(master));
+ value = Tcl_GetObjResult(interp);
} else {
/*
* If there is an "argv" variable, get its value, extract out relevant
@@ -3164,50 +3129,67 @@ Initialize(
* that we used.
*/
- argString = Tcl_GetVar2(interp, "argv", NULL, TCL_GLOBAL_ONLY);
+ value = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY);
}
- if (argString != NULL) {
- char buffer[TCL_INTEGER_SPACE];
- if (Tcl_SplitList(interp, argString, &argc, &argv) != TCL_OK) {
- argError:
+ if (value) {
+ int objc;
+ Tcl_Obj **objv, **rest;
+ Tcl_Obj *parseList = Tcl_NewListObj(1, NULL);
+
+ Tcl_ListObjAppendElement(NULL, parseList, Tcl_NewObj());
+
+ Tcl_IncrRefCount(value);
+ if (TCL_OK != Tcl_ListObjAppendList(interp, parseList, value) ||
+ TCL_OK != Tcl_ListObjGetElements(NULL, parseList, &objc, &objv) ||
+ TCL_OK != Tcl_ParseArgsObjv(interp, table, &objc, objv, &rest)) {
Tcl_AddErrorInfo(interp,
"\n (processing arguments in argv variable)");
code = TCL_ERROR;
- goto done;
}
- if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,
- argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS)
- != TCL_OK) {
- goto argError;
+ if (code == TCL_OK) {
+ Tcl_SetVar2Ex(interp, "argv", NULL,
+ Tcl_NewListObj(objc-1, rest+1), TCL_GLOBAL_ONLY);
+ Tcl_SetVar2Ex(interp, "argc", NULL,
+ Tcl_NewIntObj(objc-1), TCL_GLOBAL_ONLY);
+ ckfree(rest);
+ }
+ Tcl_DecrRefCount(parseList);
+ if (code != TCL_OK) {
+ goto done;
}
- p = Tcl_Merge(argc, argv);
- Tcl_SetVar2(interp, "argv", NULL, p, TCL_GLOBAL_ONLY);
- sprintf(buffer, "%d", argc);
- Tcl_SetVar2(interp, "argc", NULL, buffer, TCL_GLOBAL_ONLY);
- ckfree(p);
}
/*
* Figure out the application's name and class.
*/
- Tcl_DStringInit(&class);
- if (name == NULL) {
- int offset;
+ /*
+ * If we got no -name argument, fetch from TkpGetAppName().
+ */
- TkpGetAppName(interp, &class);
- offset = Tcl_DStringLength(&class)+1;
- Tcl_DStringSetLength(&class, offset);
- Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1);
- name = Tcl_DStringValue(&class) + offset;
- } else {
- Tcl_DStringAppend(&class, name, -1);
+ if (nameObj == NULL) {
+ Tcl_DString nameDS;
+
+ Tcl_DStringInit(&nameDS);
+ TkpGetAppName(interp, &nameDS);
+ nameObj = Tcl_NewStringObj(Tcl_DStringValue(&nameDS),
+ Tcl_DStringLength(&nameDS));
+ Tcl_DStringFree(&nameDS);
}
- p = Tcl_DStringValue(&class);
- if (*p) {
- Tcl_UtfToTitle(p);
+ /*
+ * The -class argument is always the ToTitle of the -name
+ */
+
+ {
+ int numBytes;
+ const char *bytes = Tcl_GetStringFromObj(nameObj, &numBytes);
+
+ classObj = Tcl_NewStringObj(bytes, numBytes);
+
+ numBytes = Tcl_UtfToTitle(Tcl_GetString(classObj));
+ Tcl_SetObjLength(classObj, numBytes);
}
/*
@@ -3215,15 +3197,14 @@ Initialize(
* information parsed from argv, if any.
*/
- args[0] = "toplevel";
- args[1] = ".";
- args[2] = "-class";
- args[3] = Tcl_DStringValue(&class);
- argc = 4;
- if (display != NULL) {
- args[argc] = "-screen";
- args[argc+1] = display;
- argc += 2;
+ cmd = Tcl_NewStringObj("toplevel . -class", -1);
+
+ Tcl_ListObjAppendElement(NULL, cmd, classObj);
+ classObj = NULL;
+
+ if (displayObj) {
+ Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-screen", -1));
+ Tcl_ListObjAppendElement(NULL, cmd, displayObj);
/*
* If this is the first application for this process, save the display
@@ -3232,36 +3213,35 @@ Initialize(
*/
if (tsdPtr->numMainWindows == 0) {
- Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
+ Tcl_SetVar2Ex(interp, "env", "DISPLAY", displayObj, TCL_GLOBAL_ONLY);
}
+ displayObj = NULL;
}
- if (colormap != NULL) {
- args[argc] = "-colormap";
- args[argc+1] = colormap;
- argc += 2;
- colormap = NULL;
+ if (colorMapObj) {
+ Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-colormap", -1));
+ Tcl_ListObjAppendElement(NULL, cmd, colorMapObj);
+ colorMapObj = NULL;
}
- if (use != NULL) {
- args[argc] = "-use";
- args[argc+1] = use;
- argc += 2;
- use = NULL;
+ if (useObj) {
+ Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-use", -1));
+ Tcl_ListObjAppendElement(NULL, cmd, useObj);
+ useObj = NULL;
}
- if (visual != NULL) {
- args[argc] = "-visual";
- args[argc+1] = visual;
- argc += 2;
- visual = NULL;
+ if (visualObj) {
+ Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-visual", -1));
+ Tcl_ListObjAppendElement(NULL, cmd, visualObj);
+ visualObj = NULL;
}
- args[argc] = NULL;
- code = TkCreateFrame(NULL, interp, argc, args, 1, name);
- Tcl_DStringFree(&class);
+ code = TkListCreateFrame(NULL, interp, cmd, 1, nameObj);
+
+ Tcl_DecrRefCount(cmd);
+
if (code != TCL_OK) {
goto done;
}
Tcl_ResetResult(interp);
- if (synchronize) {
+ if (sync) {
XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);
}
@@ -3270,19 +3250,19 @@ Initialize(
* geometry into the "geometry" variable.
*/
- if (geometry != NULL) {
- Tcl_DString buf;
+ if (geometryObj) {
+
+ Tcl_SetVar2Ex(interp, "geometry", NULL, geometryObj, TCL_GLOBAL_ONLY);
- Tcl_SetVar2(interp, "geometry", NULL, geometry, TCL_GLOBAL_ONLY);
- Tcl_DStringInit(&buf);
- Tcl_DStringAppend(&buf, "wm geometry . ", -1);
- Tcl_DStringAppend(&buf, geometry, -1);
- code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0);
- Tcl_DStringFree(&buf);
+ cmd = Tcl_NewStringObj("wm geometry .", -1);
+ Tcl_ListObjAppendElement(NULL, cmd, geometryObj);
+ Tcl_IncrRefCount(cmd);
+ code = Tcl_EvalObjEx(interp, cmd, 0);
+ Tcl_DecrRefCount(cmd);
+ geometryObj = NULL;
if (code != TCL_OK) {
goto done;
}
- geometry = NULL;
}
/*
@@ -3319,10 +3299,6 @@ Initialize(
* console window interpreter.
*/
- Tcl_MutexUnlock(&windowMutex);
- if (argv != NULL) {
- ckfree(argv);
- }
code = TkpInit(interp);
if (code == TCL_OK) {
@@ -3355,12 +3331,10 @@ tkInit", -1, 0);
TkCreateThreadExitHandler(DeleteWindowsExitProc, tsdPtr);
}
- return code;
-
done:
- Tcl_MutexUnlock(&windowMutex);
- if (argv != NULL) {
- ckfree(argv);
+ if (value) {
+ Tcl_DecrRefCount(value);
+ value = NULL;
}
return code;
}
diff --git a/generic/ttk/ttkButton.c b/generic/ttk/ttkButton.c
index 2954184..c00754b 100644
--- a/generic/ttk/ttkButton.c
+++ b/generic/ttk/ttkButton.c
@@ -136,6 +136,15 @@ BaseCleanup(void *recordPtr)
TtkFreeImageSpec(basePtr->base.imageSpec);
}
+static void
+BaseImageChanged(
+ ClientData clientData, int x, int y, int width, int height,
+ int imageWidth, int imageHeight)
+{
+ Base *basePtr = (Base *)clientData;
+ TtkResizeWidget(&basePtr->core);
+}
+
static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
{
Base *basePtr = recordPtr;
@@ -149,8 +158,8 @@ static int BaseConfigure(Tcl_Interp *interp, void *recordPtr, int mask)
}
if (basePtr->base.imageObj) {
- imageSpec = TtkGetImageSpec(
- interp, basePtr->core.tkwin, basePtr->base.imageObj);
+ imageSpec = TtkGetImageSpecEx(
+ interp, basePtr->core.tkwin, basePtr->base.imageObj, BaseImageChanged, basePtr);
if (!imageSpec) {
goto error;
}
@@ -413,8 +422,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/ttkClamTheme.c b/generic/ttk/ttkClamTheme.c
index 15ebcb7..b44eeb5 100644
--- a/generic/ttk/ttkClamTheme.c
+++ b/generic/ttk/ttkClamTheme.c
@@ -7,8 +7,8 @@
#include <tk.h>
#include "ttkTheme.h"
-/*
- * Under windows, the Tk-provided XDrawLine and XDrawArc have an
+/*
+ * Under windows, the Tk-provided XDrawLine and XDrawArc have an
* off-by-one error in the end point. This is especially apparent with this
* theme. Defining this macro as true handles this case.
*/
@@ -123,8 +123,8 @@ static Ttk_ElementOptionSpec BorderElementOptions[] = {
/*
* <<NOTE-BORDERWIDTH>>: -borderwidth is only partially supported:
* in this theme, borders are always exactly 2 pixels thick.
- * With -borderwidth 0, border is not drawn at all;
- * otherwise a 2-pixel border is used. For -borderwidth > 2,
+ * With -borderwidth 0, border is not drawn at all;
+ * otherwise a 2-pixel border is used. For -borderwidth > 2,
* the excess is used as padding.
*/
@@ -402,7 +402,7 @@ typedef struct {
static Ttk_ElementOptionSpec MenuIndicatorElementOptions[] =
{
{ "-arrowsize", TK_OPTION_PIXELS,
- Tk_Offset(MenuIndicatorElement,sizeObj),
+ Tk_Offset(MenuIndicatorElement,sizeObj),
STR(MENUBUTTON_ARROW_SIZE)},
{ "-arrowcolor",TK_OPTION_COLOR,
Tk_Offset(MenuIndicatorElement,colorObj),
@@ -630,7 +630,7 @@ static void ThumbElementDraw(
Tcl_GetIntFromObj(NULL, sb->gripCountObj, &gripCount);
lightGC = Ttk_GCForColor(tkwin,sb->lightColorObj,d);
darkGC = Ttk_GCForColor(tkwin,sb->borderColorObj,d);
-
+
if (orient == TTK_ORIENT_HORIZONTAL) {
dx = 1; dy = 0;
x1 = x2 = b.x + b.width / 2 - gripCount;
@@ -710,12 +710,12 @@ static void PbarElementDraw(
Drawable d, Ttk_Box b, unsigned state)
{
ScrollbarElement *sb = elementRecord;
-
+
b = Ttk_PadBox(b, Ttk_UniformPadding(2));
if (b.width > 4 && b.height > 4) {
DrawSmoothBorder(tkwin, d, b,
sb->borderColorObj, sb->lightColorObj, sb->darkColorObj);
- XFillRectangle(Tk_Display(tkwin), d,
+ XFillRectangle(Tk_Display(tkwin), d,
BackgroundGC(tkwin, sb->backgroundObj),
b.x+2, b.y+2, b.width-4, b.height-4);
}
@@ -780,8 +780,8 @@ static Ttk_ElementSpec ArrowElementSpec = {
/*------------------------------------------------------------------------
* +++ Notebook elements.
- *
- * Note: Tabs, except for the rightmost, overlap the neighbor to
+ *
+ * Note: Tabs, except for the rightmost, overlap the neighbor to
* their right by one pixel.
*/
diff --git a/generic/ttk/ttkClassicTheme.c b/generic/ttk/ttkClassicTheme.c
index 2fbcd76..d16cb85 100644
--- a/generic/ttk/ttkClassicTheme.c
+++ b/generic/ttk/ttkClassicTheme.c
@@ -68,7 +68,7 @@ static Ttk_ElementSpec HighlightElementSpec =
/*------------------------------------------------------------------------
* +++ Button Border element:
- *
+ *
* The Motif-style button border on X11 consists of (from outside-in):
*
* + focus indicator (controlled by -highlightcolor and -highlightthickness),
@@ -85,13 +85,13 @@ typedef struct {
static Ttk_ElementOptionSpec ButtonBorderElementOptions[] =
{
- { "-background", TK_OPTION_BORDER,
+ { "-background", TK_OPTION_BORDER,
Tk_Offset(ButtonBorderElement,borderObj), DEFAULT_BACKGROUND },
- { "-borderwidth", TK_OPTION_PIXELS,
+ { "-borderwidth", TK_OPTION_PIXELS,
Tk_Offset(ButtonBorderElement,borderWidthObj), DEFAULT_BORDERWIDTH },
- { "-relief", TK_OPTION_RELIEF,
+ { "-relief", TK_OPTION_RELIEF,
Tk_Offset(ButtonBorderElement,reliefObj), "flat" },
- { "-default", TK_OPTION_ANY,
+ { "-default", TK_OPTION_ANY,
Tk_Offset(ButtonBorderElement,defaultStateObj), "disabled" },
{ NULL, 0, 0, NULL }
};
@@ -115,7 +115,7 @@ static void ButtonBorderElementSize(
/*
* (@@@ Note: ButtonBorderElement still still still buggy:
- * padding for default ring is drawn in the wrong color
+ * padding for default ring is drawn in the wrong color
* when the button is active.)
*/
static void ButtonBorderElementDraw(
@@ -281,19 +281,19 @@ static Ttk_ElementSpec ArrowElementSpec =
/*------------------------------------------------------------------------
* +++ Sash element (for ttk::panedwindow)
*
- * NOTES:
+ * NOTES:
*
* panedwindows with -orient horizontal use vertical sashes, and vice versa.
*
* Interpretation of -sashrelief 'groove' and 'ridge' are
* swapped wrt. the core panedwindow, which (I think) has them backwards.
*
- * Default -sashrelief is sunken; the core panedwindow has default
+ * Default -sashrelief is sunken; the core panedwindow has default
* -sashrelief raised, but that looks wrong to me.
*/
static Ttk_Orient SashClientData[] = {
- TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL
+ TTK_ORIENT_HORIZONTAL, TTK_ORIENT_VERTICAL
};
typedef struct {
@@ -306,13 +306,13 @@ typedef struct {
} SashElement;
static Ttk_ElementOptionSpec SashOptions[] = {
- { "-background", TK_OPTION_BORDER,
+ { "-background", TK_OPTION_BORDER,
Tk_Offset(SashElement,borderObj), DEFAULT_BACKGROUND },
- { "-sashrelief", TK_OPTION_RELIEF,
+ { "-sashrelief", TK_OPTION_RELIEF,
Tk_Offset(SashElement,sashReliefObj), "sunken" },
{ "-sashthickness", TK_OPTION_PIXELS,
Tk_Offset(SashElement,sashThicknessObj), "6" },
- { "-sashpad", TK_OPTION_PIXELS,
+ { "-sashpad", TK_OPTION_PIXELS,
Tk_Offset(SashElement,sashPadObj), "2" },
{ "-handlesize", TK_OPTION_PIXELS,
Tk_Offset(SashElement,handleSizeObj), "8" },
@@ -367,10 +367,10 @@ static void SashElementDraw(
gc1 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_LIGHT_GC);
break;
- case TK_RELIEF_SOLID:
+ case TK_RELIEF_SOLID:
gc1 = gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_DARK_GC);
break;
- case TK_RELIEF_FLAT:
+ case TK_RELIEF_FLAT:
default:
gc1 = gc2 = Tk_3DBorderGC(tkwin, border, TK_3D_FLAT_GC);
break;
@@ -398,7 +398,7 @@ static void SashElementDraw(
hb = Ttk_StickBox(b, handleSize, handleSize, TTK_STICK_N);
hb.y += handlePad;
}
- Tk_Fill3DRectangle(tkwin, d, border,
+ Tk_Fill3DRectangle(tkwin, d, border,
hb.x, hb.y, hb.width, hb.height, 1, TK_RELIEF_RAISED);
}
}
@@ -495,7 +495,7 @@ MODULE_SCOPE int TtkClassicTheme_Init(Tcl_Interp *interp)
Ttk_RegisterElement(interp, theme, "arrow",
&ArrowElementSpec, &ArrowElements[0]);
- Ttk_RegisterElement(interp, theme, "hsash",
+ Ttk_RegisterElement(interp, theme, "hsash",
&SashElementSpec, &SashClientData[0]);
Ttk_RegisterElement(interp, theme, "vsash",
&SashElementSpec, &SashClientData[1]);
diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c
index f395649..a25574a 100644
--- a/generic/ttk/ttkEntry.c
+++ b/generic/ttk/ttkEntry.c
@@ -282,15 +282,16 @@ static char *EntryDisplayString(const char *showChar, int numChars)
{
char *displayString, *p;
int size;
- Tcl_UniChar ch;
- char buf[TCL_UTF_MAX];
+ int ch;
+ char buf[6];
- Tcl_UtfToUniChar(showChar, &ch);
- size = Tcl_UniCharToUtf(ch, buf);
+ TkUtfToUniChar(showChar, &ch);
+ size = TkUniCharToUtf(ch, buf);
p = displayString = ckalloc(numChars * size + 1);
while (numChars--) {
- p += Tcl_UniCharToUtf(ch, p);
+ memcpy(p, buf, size);
+ p += size;
}
*p = '\0';
@@ -405,7 +406,7 @@ ExpandPercents(
int number, length;
const char *string;
int stringLength;
- Tcl_UniChar ch;
+ int ch;
char numStorage[2*TCL_INTEGER_SPACE];
while (*template) {
@@ -429,7 +430,7 @@ ExpandPercents(
*/
++template; /* skip over % */
if (*template != '\0') {
- template += Tcl_UtfToUniChar(template, &ch);
+ template += TkUtfToUniChar(template, &ch);
} else {
ch = '%';
}
@@ -479,7 +480,7 @@ ExpandPercents(
string = Tk_PathName(entryPtr->core.tkwin);
break;
default:
- length = Tcl_UniCharToUtf(ch, numStorage);
+ length = TkUniCharToUtf(ch, numStorage);
numStorage[length] = '\0';
string = numStorage;
break;
diff --git a/generic/ttk/ttkGenStubs.tcl b/generic/ttk/ttkGenStubs.tcl
index 56ba2fa..8047e3f 100644
--- a/generic/ttk/ttkGenStubs.tcl
+++ b/generic/ttk/ttkGenStubs.tcl
@@ -18,8 +18,6 @@
# + Allow trailing semicolon in function declarations
#
-package require Tcl 8.4
-
namespace eval genStubs {
# libraryName --
#
diff --git a/generic/ttk/ttkImage.c b/generic/ttk/ttkImage.c
index a5a3a52..e403e2d 100644
--- a/generic/ttk/ttkImage.c
+++ b/generic/ttk/ttkImage.c
@@ -25,6 +25,8 @@ struct TtkImageSpec {
int mapCount; /* #state-specific overrides */
Ttk_StateSpec *states; /* array[mapCount] of states ... */
Tk_Image *images; /* ... per-state images to use */
+ Tk_ImageChangedProc *imageChanged;
+ ClientData imageChangedClientData;
};
/* NullImageChanged --
@@ -34,15 +36,41 @@ static void NullImageChanged(ClientData clientData,
int x, int y, int width, int height, int imageWidth, int imageHeight)
{ /* No-op */ }
+/* ImageSpecImageChanged --
+ * Image changes should trigger a repaint.
+ */
+static void ImageSpecImageChanged(ClientData clientData,
+ int x, int y, int width, int height, int imageWidth, int imageHeight)
+{
+ Ttk_ImageSpec *imageSpec = (Ttk_ImageSpec *)clientData;
+ if (imageSpec->imageChanged != NULL) {
+ imageSpec->imageChanged(imageSpec->imageChangedClientData,
+ x, y, width, height,
+ imageWidth, imageHeight);
+ }
+}
+
/* TtkGetImageSpec --
* Constructs a Ttk_ImageSpec * from a Tcl_Obj *.
* Result must be released using TtkFreeImageSpec.
*
- * TODO: Need a variant of this that takes a user-specified ImageChanged proc
*/
Ttk_ImageSpec *
TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
{
+ return TtkGetImageSpecEx(interp, tkwin, objPtr, NULL, NULL);
+}
+
+/* TtkGetImageSpecEx --
+ * Constructs a Ttk_ImageSpec * from a Tcl_Obj *.
+ * Result must be released using TtkFreeImageSpec.
+ * imageChangedProc will be called when not NULL when
+ * the image changes to allow widgets to repaint.
+ */
+Ttk_ImageSpec *
+TtkGetImageSpecEx(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr,
+ Tk_ImageChangedProc *imageChangedProc, ClientData imageChangedClientData)
+{
Ttk_ImageSpec *imageSpec = 0;
int i = 0, n = 0, objc;
Tcl_Obj **objv;
@@ -52,6 +80,8 @@ TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
imageSpec->mapCount = 0;
imageSpec->states = 0;
imageSpec->images = 0;
+ imageSpec->imageChanged = imageChangedProc;
+ imageSpec->imageChangedClientData = imageChangedClientData;
if (Tcl_ListObjGetElements(interp, objPtr, &objc, &objv) != TCL_OK) {
goto error;
@@ -74,7 +104,7 @@ TtkGetImageSpec(Tcl_Interp *interp, Tk_Window tkwin, Tcl_Obj *objPtr)
/* Get base image:
*/
imageSpec->baseImage = Tk_GetImage(
- interp, tkwin, Tcl_GetString(objv[0]), NullImageChanged, NULL);
+ interp, tkwin, Tcl_GetString(objv[0]), ImageSpecImageChanged, imageSpec);
if (!imageSpec->baseImage) {
goto error;
}
diff --git a/generic/ttk/ttkLabel.c b/generic/ttk/ttkLabel.c
index 1037840..b8b7f29 100644
--- a/generic/ttk/ttkLabel.c
+++ b/generic/ttk/ttkLabel.c
@@ -139,7 +139,7 @@ static void TextDraw(TextElement *text, Tk_Window tkwin, Drawable d, Ttk_Box b)
gcValues.foreground = WhitePixelOfScreen(Tk_Screen(tkwin));
gc2 = Tk_GetGC(tkwin, GCFont | GCForeground, &gcValues);
- /*
+ /*
* Place text according to -anchor:
*/
Tk_GetAnchorFromObj(NULL, text->anchorObj, &anchor);
@@ -342,15 +342,15 @@ static void ImageDraw(
Tk_RedrawImage(image->tkimg, 0,0, width, height, d, b.x, b.y);
- /* If we're disabled there's no state-specific 'disabled' image,
+ /* If we're disabled there's no state-specific 'disabled' image,
* stipple the image.
* @@@ Possibly: Don't do disabled-stippling at all;
* @@@ it's ugly and out of fashion.
- * Do not stipple at all under Aqua, just draw the image: it shows up
+ * Do not stipple at all under Aqua, just draw the image: it shows up
* as a white rectangle otherwise.
*/
-
+
if (state & TTK_STATE_DISABLED) {
if (TtkSelectImage(image->imageSpec, 0ul) == image->tkimg) {
#ifndef MAC_OSX_TK
@@ -577,7 +577,7 @@ static void LabelElementSize(
if (label->compound != TTK_COMPOUND_IMAGE)
textReqWidth = TextReqWidth(&label->text);
- switch (label->compound)
+ switch (label->compound)
{
case TTK_COMPOUND_TEXT:
*widthPtr = textReqWidth;
@@ -588,11 +588,11 @@ static void LabelElementSize(
case TTK_COMPOUND_TOP:
case TTK_COMPOUND_BOTTOM:
case TTK_COMPOUND_CENTER:
- *widthPtr = MAX(label->image.width, textReqWidth);
+ *widthPtr = MAX(label->image.width, textReqWidth);
break;
case TTK_COMPOUND_LEFT:
case TTK_COMPOUND_RIGHT:
- *widthPtr = label->image.width + textReqWidth + label->space;
+ *widthPtr = label->image.width + textReqWidth + label->space;
break;
case TTK_COMPOUND_NONE:
break; /* Can't happen */
diff --git a/generic/ttk/ttkManager.c b/generic/ttk/ttkManager.c
index 24a0fb1..031fdec 100644
--- a/generic/ttk/ttkManager.c
+++ b/generic/ttk/ttkManager.c
@@ -320,7 +320,7 @@ void Ttk_GeometryRequestProc(ClientData clientData, Tk_Window slaveWindow)
int reqHeight= Tk_ReqHeight(slaveWindow);
if (mgr->managerSpec->SlaveRequest(
- mgr->managerData, slaveIndex, reqWidth, reqHeight))
+ mgr->managerData, slaveIndex, reqWidth, reqHeight))
{
ScheduleUpdate(mgr, MGR_RESIZE_REQUIRED);
}
diff --git a/generic/ttk/ttkManager.h b/generic/ttk/ttkManager.h
index d22ff98..07fcea1 100644
--- a/generic/ttk/ttkManager.h
+++ b/generic/ttk/ttkManager.h
@@ -22,7 +22,7 @@ typedef struct TtkManager_ Ttk_Manager;
* SlaveRemoved() is called immediately before a slave is removed.
* NB: the associated slave window may have been destroyed when this
* routine is called.
- *
+ *
* SlaveRequest() is called when a slave requests a size change.
* It should return 1 if the request should propagate, 0 otherwise.
*/
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;
}
diff --git a/generic/ttk/ttkProgress.c b/generic/ttk/ttkProgress.c
index 4dc50a2..eed90ec 100644
--- a/generic/ttk/ttkProgress.c
+++ b/generic/ttk/ttkProgress.c
@@ -398,7 +398,7 @@ static int ProgressbarStepCommand(
{
Progressbar *pb = recordPtr;
double value = 0.0, stepAmount = 1.0;
- Tcl_Obj *newValueObj;
+ Tcl_Obj *newValueObj;
if (objc == 3) {
if (Tcl_GetDoubleFromObj(interp, objv[2], &stepAmount) != TCL_OK) {
@@ -424,7 +424,7 @@ static int ProgressbarStepCommand(
TtkRedisplayWidget(&pb->core);
- /* Update value by setting the linked -variable, if there is one:
+ /* Update value by setting the linked -variable, if there is one:
*/
if (pb->progress.variableTrace) {
return Tcl_ObjSetVar2(
@@ -444,7 +444,7 @@ static int ProgressbarStepCommand(
}
/* $sb start|stop ?args? --
- * Change [$sb $cmd ...] to [ttk::progressbar::$cmd ...]
+ * Change [$sb $cmd ...] to [ttk::progressbar::$cmd ...]
* and pass to interpreter.
*/
static int ProgressbarStartStopCommand(
diff --git a/generic/ttk/ttkScale.c b/generic/ttk/ttkScale.c
index 69753d1..95824af 100644
--- a/generic/ttk/ttkScale.c
+++ b/generic/ttk/ttkScale.c
@@ -46,14 +46,14 @@ typedef struct
static Tk_OptionSpec ScaleOptionSpecs[] =
{
{TK_OPTION_STRING, "-command", "command", "Command", "",
- Tk_Offset(Scale,scale.commandObj), -1,
+ Tk_Offset(Scale,scale.commandObj), -1,
TK_OPTION_NULL_OK,0,0},
{TK_OPTION_STRING, "-variable", "variable", "Variable", "",
- Tk_Offset(Scale,scale.variableObj), -1,
+ Tk_Offset(Scale,scale.variableObj), -1,
0,0,0},
{TK_OPTION_STRING_TABLE, "-orient", "orient", "Orient", "horizontal",
Tk_Offset(Scale,scale.orientObj),
- Tk_Offset(Scale,scale.orient), 0,
+ Tk_Offset(Scale,scale.orient), 0,
(ClientData)ttkOrientStrings, STYLE_CHANGED },
{TK_OPTION_DOUBLE, "-from", "from", "From", "0",
@@ -63,7 +63,7 @@ static Tk_OptionSpec ScaleOptionSpecs[] =
{TK_OPTION_DOUBLE, "-value", "value", "Value", "0",
Tk_Offset(Scale,scale.valueObj), -1, 0, 0, 0},
{TK_OPTION_PIXELS, "-length", "length", "Length",
- DEF_SCALE_LENGTH, Tk_Offset(Scale,scale.lengthObj), -1, 0, 0,
+ DEF_SCALE_LENGTH, Tk_Offset(Scale,scale.lengthObj), -1, 0, 0,
GEOMETRY_CHANGED},
WIDGET_TAKEFOCUS_TRUE,
@@ -76,7 +76,7 @@ static double PointToValue(Scale *scalePtr, int x, int y);
/* ScaleVariableChanged --
* Variable trace procedure for scale -variable;
* Updates the scale's value.
- * If the linked variable is not a valid double,
+ * If the linked variable is not a valid double,
* sets the 'invalid' state.
*/
static void ScaleVariableChanged(void *recordPtr, const char *value)
@@ -172,7 +172,7 @@ static int ScalePostConfigure(
/* ScaleGetLayout --
* getLayout hook.
*/
-static Ttk_Layout
+static Ttk_Layout
ScaleGetLayout(Tcl_Interp *interp, Ttk_Theme theme, void *recordPtr)
{
Scale *scalePtr = recordPtr;
@@ -236,7 +236,7 @@ static double ScaleFraction(Scale *scalePtr, double value)
}
/* $scale get ?x y? --
- * Returns the current value of the scale widget, or if $x and
+ * Returns the current value of the scale widget, or if $x and
* $y are specified, the value represented by point @x,y.
*/
static int
diff --git a/generic/ttk/ttkScrollbar.c b/generic/ttk/ttkScrollbar.c
index 5b0c212..9d99ea5 100644
--- a/generic/ttk/ttkScrollbar.c
+++ b/generic/ttk/ttkScrollbar.c
@@ -22,7 +22,7 @@ typedef struct
double first; /* top fraction */
double last; /* bottom fraction */
- Ttk_Box troughBox; /* trough parcel */
+ Ttk_Box troughBox; /* trough parcel */
int minSize; /* minimum size of thumb */
} ScrollbarPart;
@@ -50,7 +50,7 @@ static Tk_OptionSpec ScrollbarOptionSpecs[] =
* +++ Widget hooks.
*/
-static void
+static void
ScrollbarInitialize(Tcl_Interp *interp, void *recordPtr)
{
Scrollbar *sb = recordPtr;
@@ -241,7 +241,7 @@ ScrollbarDeltaCommand(
/* $sb fraction $x $y --
* Returns a real number between 0 and 1 indicating where the
- * point given by x and y lies in the trough area of the scrollbar.
+ * point given by x and y lies in the trough area of the scrollbar.
*/
static int
ScrollbarFractionCommand(
diff --git a/generic/ttk/ttkSquare.c b/generic/ttk/ttkSquare.c
index d002f2f..7837310 100644
--- a/generic/ttk/ttkSquare.c
+++ b/generic/ttk/ttkSquare.c
@@ -56,24 +56,24 @@ static Tk_OptionSpec SquareOptionSpecs[] =
{TK_OPTION_BORDER, "-foreground", "foreground", "Foreground",
DEFAULT_BACKGROUND, Tk_Offset(Square,square.foregroundObj),
-1, 0, 0, 0},
-
+
{TK_OPTION_PIXELS, "-width", "width", "Width",
"50", Tk_Offset(Square,square.widthObj), -1, 0, 0,
GEOMETRY_CHANGED},
{TK_OPTION_PIXELS, "-height", "height", "Height",
"50", Tk_Offset(Square,square.heightObj), -1, 0, 0,
GEOMETRY_CHANGED},
-
+
{TK_OPTION_STRING, "-padding", "padding", "Pad", NULL,
- Tk_Offset(Square,square.paddingObj), -1,
+ Tk_Offset(Square,square.paddingObj), -1,
TK_OPTION_NULL_OK,0,GEOMETRY_CHANGED },
-
+
{TK_OPTION_RELIEF, "-relief", "relief", "Relief",
NULL, Tk_Offset(Square,square.reliefObj), -1, TK_OPTION_NULL_OK, 0, 0},
-
+
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
NULL, Tk_Offset(Square,square.anchorObj), -1, TK_OPTION_NULL_OK, 0, 0},
-
+
WIDGET_TAKEFOCUS_TRUE,
WIDGET_INHERIT_OPTIONS(ttkCoreOptionSpecs)
};
@@ -138,7 +138,7 @@ static const Ttk_Ensemble SquareCommands[] = {
};
/*
- * The Widget specification structure holds all the implementation
+ * The Widget specification structure holds all the implementation
* information about this widget and this is what must be registered
* with Tk in the package initialization code (see bottom).
*/
@@ -159,7 +159,7 @@ static WidgetSpec SquareWidgetSpec =
TtkWidgetDisplay /* displayProc */
};
-/* ----------------------------------------------------------------------
+/* ----------------------------------------------------------------------
* Square element
*
* In this section we demonstrate what is required to create a new themed
@@ -176,7 +176,7 @@ typedef struct
Tcl_Obj *heightObj;
} SquareElement;
-static Ttk_ElementOptionSpec SquareElementOptions[] =
+static Ttk_ElementOptionSpec SquareElementOptions[] =
{
{ "-background", TK_OPTION_BORDER, Tk_Offset(SquareElement,borderObj),
DEFAULT_BACKGROUND },
@@ -248,7 +248,7 @@ static Ttk_ElementSpec SquareElementSpec =
* engine is similar to the Tk pack geometry manager. Read the documentation
* for the details. In this example we just need to have the square element
* that has been defined for this widget placed on a background. We will
- * also need some padding to keep it away from the edges.
+ * also need some padding to keep it away from the edges.
*/
TTK_BEGIN_LAYOUT(SquareLayout)
@@ -257,12 +257,12 @@ TTK_BEGIN_LAYOUT(SquareLayout)
TTK_NODE("Square.square", 0))
TTK_END_LAYOUT
-/* ----------------------------------------------------------------------
+/* ----------------------------------------------------------------------
*
* Widget initialization.
*
* This file defines a new element and a new widget. We need to register
- * the element with the themes that will need it. In this case we will
+ * the element with the themes that will need it. In this case we will
* register with the default theme that is the root of the theme inheritance
* tree. This means all themes will find this element.
* We then need to register the widget class style. This is the layout
@@ -287,10 +287,10 @@ TtkSquareWidget_Init(Tcl_Interp *interp)
/* register the new elements for this theme engine */
Ttk_RegisterElement(interp, theme, "square", &SquareElementSpec, NULL);
-
+
/* register the layout for this theme */
Ttk_RegisterLayout(theme, "TSquare", SquareLayout);
-
+
/* register the widget */
RegisterWidget(interp, "ttk::square", &SquareWidgetSpec);
diff --git a/generic/ttk/ttkStubLib.c b/generic/ttk/ttkStubLib.c
index 2c07b9d..c17f1e9 100644
--- a/generic/ttk/ttkStubLib.c
+++ b/generic/ttk/ttkStubLib.c
@@ -67,7 +67,7 @@ error:
"Error loading ", packageName, " package",
" (requested version '", version,
"', loaded version '", actualVersion, "'): ",
- errMsg,
+ errMsg,
NULL);
return NULL;
}
diff --git a/generic/ttk/ttkTagSet.c b/generic/ttk/ttkTagSet.c
index f2108b9..31798ea 100644
--- a/generic/ttk/ttkTagSet.c
+++ b/generic/ttk/ttkTagSet.c
@@ -188,7 +188,7 @@ int Ttk_TagSetAdd(Ttk_TagSet tagset, Ttk_Tag tag)
return 0;
}
}
- tagset->tags = ckrealloc(tagset->tags,
+ tagset->tags = ckrealloc(tagset->tags,
(tagset->nTags+1)*sizeof(tagset->tags[0]));
tagset->tags[tagset->nTags++] = tag;
return 1;
diff --git a/generic/ttk/ttkTheme.h b/generic/ttk/ttkTheme.h
index 7bf2a7f..9251dea 100644
--- a/generic/ttk/ttkTheme.h
+++ b/generic/ttk/ttkTheme.h
@@ -372,6 +372,8 @@ MODULE_SCOPE void Ttk_RegisterNamedColor(Ttk_ResourceCache, const char *, XColor
typedef struct TtkImageSpec Ttk_ImageSpec;
TTKAPI Ttk_ImageSpec *TtkGetImageSpec(Tcl_Interp *, Tk_Window, Tcl_Obj *);
+TTKAPI Ttk_ImageSpec *TtkGetImageSpecEx(Tcl_Interp *, Tk_Window, Tcl_Obj *,
+ Tk_ImageChangedProc *, ClientData);
TTKAPI void TtkFreeImageSpec(Ttk_ImageSpec *);
TTKAPI Tk_Image TtkSelectImage(Ttk_ImageSpec *, Ttk_State);
diff --git a/generic/ttk/ttkTrace.c b/generic/ttk/ttkTrace.c
index ba66db4..c0f17cf 100644
--- a/generic/ttk/ttkTrace.c
+++ b/generic/ttk/ttkTrace.c
@@ -3,7 +3,7 @@
*
* Simplified interface to Tcl_TraceVariable.
*
- * PROBLEM: Can't distinguish "variable does not exist" (which is OK)
+ * PROBLEM: Can't distinguish "variable does not exist" (which is OK)
* from other errors (which are not).
*/
diff --git a/generic/ttk/ttkWidget.h b/generic/ttk/ttkWidget.h
index e4dd712..798bcce 100644
--- a/generic/ttk/ttkWidget.h
+++ b/generic/ttk/ttkWidget.h
@@ -111,8 +111,8 @@ MODULE_SCOPE int TtkWidgetConstructorObjCmd(
/* WIDGET_TAKEFOCUS_TRUE --
* WIDGET_TAKEFOCUS_FALSE --
- * Add one or the other of these to each OptionSpecs table
- * to indicate whether the widget should take focus
+ * Add one or the other of these to each OptionSpecs table
+ * to indicate whether the widget should take focus
* during keyboard traversal.
*/
#define WIDGET_TAKEFOCUS_TRUE \