summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
authorfvogel <fvogelnew1@free.fr>2019-06-08 22:06:10 (GMT)
committerfvogel <fvogelnew1@free.fr>2019-06-08 22:06:10 (GMT)
commit0bd46f264389482ef6561255f041c3c15b7d0cc4 (patch)
tree1865df15c7d699e7cf5b09731c441e2fcb78289c /generic
parentd2d2d59c209cc6a7c8009dc44bd9a4a07aa04887 (diff)
parent1638e5363d36014e6b4d9c4127431be476def481 (diff)
downloadtk-0bd46f264389482ef6561255f041c3c15b7d0cc4.zip
tk-0bd46f264389482ef6561255f041c3c15b7d0cc4.tar.gz
tk-0bd46f264389482ef6561255f041c3c15b7d0cc4.tar.bz2
merge core-8-6-branch
Diffstat (limited to 'generic')
-rw-r--r--generic/tkButton.c81
-rw-r--r--generic/tkEntry.c41
-rw-r--r--generic/tkListbox.c40
-rw-r--r--generic/tkMenu.c43
-rw-r--r--generic/tkMenubutton.c35
-rw-r--r--generic/tkMessage.c35
-rw-r--r--generic/tkScale.c35
-rw-r--r--generic/tkTest.c47
-rw-r--r--generic/ttk/ttkEntry.c55
-rw-r--r--generic/ttk/ttkTrace.c17
-rw-r--r--generic/ttk/ttkTreeview.c56
11 files changed, 311 insertions, 174 deletions
diff --git a/generic/tkButton.c b/generic/tkButton.c
index 42d63a7..0d760b0 100644
--- a/generic/tkButton.c
+++ b/generic/tkButton.c
@@ -1617,26 +1617,33 @@ ButtonVarProc(
Tcl_Obj *valuePtr;
/*
- * See ticket [5d991b82].
- */
-
- if (butPtr->selVarNamePtr == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- ButtonVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* If the variable is being unset, then just re-establish the trace unless
* the whole interpreter is going away.
*/
if (flags & TCL_TRACE_UNSETS) {
butPtr->flags &= ~(SELECTED | TRISTATED);
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ if (!Tcl_InterpDeleted(interp)) {
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ Tcl_GetString(butPtr->selVarNamePtr),
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ ButtonVarProc, probe);
+ if (probe == (ClientData)butPtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * selVarNamePtr, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ goto redisplay;
+ }
Tcl_TraceVar2(interp, Tcl_GetString(butPtr->selVarNamePtr),
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
ButtonVarProc, clientData);
@@ -1711,8 +1718,8 @@ static char *
ButtonTextVarProc(
ClientData clientData, /* Information about button. */
Tcl_Interp *interp, /* Interpreter containing variable. */
- const char *name1, /* Name of variable. */
- const char *name2, /* Second part of variable name. */
+ const char *name1, /* Not used. */
+ const char *name2, /* Not used. */
int flags) /* Information about what happened. */
{
TkButton *butPtr = clientData;
@@ -1723,25 +1730,39 @@ ButtonTextVarProc(
}
/*
- * See ticket [5d991b82].
- */
-
- if (butPtr->textVarNamePtr == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- ButtonTextVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* If the variable is unset, then immediately recreate it unless the whole
* interpreter is going away.
*/
if (flags & TCL_TRACE_UNSETS) {
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ if (!Tcl_InterpDeleted(interp) && butPtr->textVarNamePtr != NULL) {
+
+ /*
+ * An unset trace on some variable brought us here, but is it
+ * the variable we have stored in butPtr->textVarNamePtr ?
+ */
+
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ Tcl_GetString(butPtr->textVarNamePtr),
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ ButtonTextVarProc, probe);
+ if (probe == (ClientData)butPtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * textVarNamePtr, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former textvariable must be, and we should ignore it.
+ */
+ return NULL;
+ }
+
Tcl_ObjSetVar2(interp, butPtr->textVarNamePtr, NULL,
butPtr->textPtr, TCL_GLOBAL_ONLY);
Tcl_TraceVar2(interp, Tcl_GetString(butPtr->textVarNamePtr),
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index 05a1a60..a7bc5a0 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -3135,8 +3135,8 @@ static char *
EntryTextVarProc(
ClientData clientData, /* Information about button. */
Tcl_Interp *interp, /* Interpreter containing variable. */
- const char *name1, /* Name of variable. */
- const char *name2, /* Second part of variable name. */
+ const char *name1, /* Not used. */
+ const char *name2, /* Not used. */
int flags) /* Information about what happened. */
{
Entry *entryPtr = clientData;
@@ -3150,32 +3150,39 @@ EntryTextVarProc(
}
/*
- * See ticket [5d991b82].
- */
-
- if (entryPtr->textVarName == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- EntryTextVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* If the variable is unset, then immediately recreate it unless the whole
* interpreter is going away.
*/
if (flags & TCL_TRACE_UNSETS) {
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ if (!Tcl_InterpDeleted(interp) && entryPtr->textVarName) {
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ entryPtr->textVarName,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ EntryTextVarProc, probe);
+ if (probe == (ClientData)entryPtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * textVarName, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ return NULL;
+ }
Tcl_SetVar2(interp, entryPtr->textVarName, NULL,
entryPtr->string, TCL_GLOBAL_ONLY);
Tcl_TraceVar2(interp, entryPtr->textVarName, NULL,
TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
EntryTextVarProc, clientData);
entryPtr->flags |= ENTRY_VAR_TRACED;
- }
+ }
return NULL;
}
diff --git a/generic/tkListbox.c b/generic/tkListbox.c
index b323845..d92325f 100644
--- a/generic/tkListbox.c
+++ b/generic/tkListbox.c
@@ -3431,8 +3431,8 @@ static char *
ListboxListVarProc(
ClientData clientData, /* Information about button. */
Tcl_Interp *interp, /* Interpreter containing variable. */
- const char *name1, /* Name of variable. */
- const char *name2, /* Second part of variable name. */
+ const char *name1, /* Not used. */
+ const char *name2, /* Not used. */
int flags) /* Information about what happened. */
{
Listbox *listPtr = clientData;
@@ -3441,24 +3441,32 @@ ListboxListVarProc(
Tcl_HashEntry *entry;
/*
- * See ticket [5d991b82].
- */
-
- if (listPtr->listVarName == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- ListboxListVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* Bwah hahahaha! Puny mortal, you can't unset a -listvar'd variable!
*/
if (flags & TCL_TRACE_UNSETS) {
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+
+ if (!Tcl_InterpDeleted(interp) && listPtr->listVarName) {
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ listPtr->listVarName,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ ListboxListVarProc, probe);
+ if (probe == (ClientData)listPtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * listVarName, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ return NULL;
+ }
Tcl_SetVar2Ex(interp, listPtr->listVarName, NULL,
listPtr->listObj, TCL_GLOBAL_ONLY);
Tcl_TraceVar2(interp, listPtr->listVarName,
diff --git a/generic/tkMenu.c b/generic/tkMenu.c
index 38e3bbd..3a2d987 100644
--- a/generic/tkMenu.c
+++ b/generic/tkMenu.c
@@ -2491,9 +2491,10 @@ MenuVarProc(
const char *value;
const char *name, *onValue;
- if (flags & TCL_INTERP_DESTROYED) {
+ if (Tcl_InterpDeleted(interp) || (mePtr->namePtr == NULL)) {
/*
- * Do nothing if the interpreter is going away.
+ * Do nothing if the interpreter is going away or we have
+ * no variable name.
*/
return NULL;
@@ -2505,17 +2506,6 @@ MenuVarProc(
return NULL;
}
- /*
- * See ticket [5d991b82].
- */
-
- if (mePtr->namePtr == NULL) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- MenuVarProc, clientData);
- return NULL;
- }
-
name = Tcl_GetString(mePtr->namePtr);
/*
@@ -2523,12 +2513,29 @@ MenuVarProc(
*/
if (flags & TCL_TRACE_UNSETS) {
+ ClientData probe = NULL;
mePtr->entryFlags &= ~ENTRY_SELECTED;
- if (flags & TCL_TRACE_DESTROYED) {
- Tcl_TraceVar2(interp, name, NULL,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- MenuVarProc, clientData);
- }
+
+ do {
+ probe = Tcl_VarTraceInfo(interp, name,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ MenuVarProc, probe);
+ if (probe == (ClientData)mePtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * namePtr, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ return NULL;
+ }
+ Tcl_TraceVar2(interp, name, NULL,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ MenuVarProc, clientData);
TkpConfigureMenuEntry(mePtr);
TkEventuallyRedrawMenu(menuPtr, NULL);
return NULL;
diff --git a/generic/tkMenubutton.c b/generic/tkMenubutton.c
index 21da0d3..2228a2e 100644
--- a/generic/tkMenubutton.c
+++ b/generic/tkMenubutton.c
@@ -882,25 +882,32 @@ MenuButtonTextVarProc(
unsigned len;
/*
- * See ticket [5d991b82].
- */
-
- if (mbPtr->textVarName == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- MenuButtonTextVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* If the variable is unset, then immediately recreate it unless the whole
* interpreter is going away.
*/
if (flags & TCL_TRACE_UNSETS) {
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ if (!Tcl_InterpDeleted(interp) && mbPtr->textVarName) {
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ mbPtr->textVarName,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ MenuButtonTextVarProc, probe);
+ if (probe == (ClientData)mbPtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * textVarName, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ return NULL;
+ }
Tcl_SetVar2(interp, mbPtr->textVarName, NULL, mbPtr->text,
TCL_GLOBAL_ONLY);
Tcl_TraceVar2(interp, mbPtr->textVarName, NULL,
diff --git a/generic/tkMessage.c b/generic/tkMessage.c
index 9d02346..1a3c6de 100644
--- a/generic/tkMessage.c
+++ b/generic/tkMessage.c
@@ -839,25 +839,32 @@ MessageTextVarProc(
const char *value;
/*
- * See ticket [5d991b82].
- */
-
- if (msgPtr->textVarName == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- MessageTextVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* If the variable is unset, then immediately recreate it unless the whole
* interpreter is going away.
*/
if (flags & TCL_TRACE_UNSETS) {
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ if (!Tcl_InterpDeleted(interp) && msgPtr->textVarName) {
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ msgPtr->textVarName,
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ MessageTextVarProc, probe);
+ if (probe == (ClientData)msgPtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * textVarName, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ return NULL;
+ }
Tcl_SetVar2(interp, msgPtr->textVarName, NULL, msgPtr->string,
TCL_GLOBAL_ONLY);
Tcl_TraceVar2(interp, msgPtr->textVarName, NULL,
diff --git a/generic/tkScale.c b/generic/tkScale.c
index c5cdaff..5957b00 100644
--- a/generic/tkScale.c
+++ b/generic/tkScale.c
@@ -1353,25 +1353,32 @@ ScaleVarProc(
int result;
/*
- * See ticket [5d991b82].
- */
-
- if (scalePtr->varNamePtr == NULL) {
- if (!(flags & TCL_INTERP_DESTROYED)) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- ScaleVarProc, clientData);
- }
- return NULL;
- }
-
- /*
* If the variable is unset, then immediately recreate it unless the whole
* interpreter is going away.
*/
if (flags & TCL_TRACE_UNSETS) {
- if ((flags & TCL_TRACE_DESTROYED) && !(flags & TCL_INTERP_DESTROYED)) {
+ if (!Tcl_InterpDeleted(interp) && scalePtr->varNamePtr) {
+ ClientData probe = NULL;
+
+ do {
+ probe = Tcl_VarTraceInfo(interp,
+ Tcl_GetString(scalePtr->varNamePtr),
+ TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
+ ScaleVarProc, probe);
+ if (probe == (ClientData)scalePtr) {
+ break;
+ }
+ } while (probe);
+ if (probe) {
+ /*
+ * We were able to fetch the unset trace for our
+ * varNamePtr, which means it is not unset and not
+ * the cause of this unset trace. Instead some outdated
+ * former variable must be, and we should ignore it.
+ */
+ return NULL;
+ }
Tcl_TraceVar2(interp, Tcl_GetString(scalePtr->varNamePtr),
NULL, TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
ScaleVarProc, clientData);
diff --git a/generic/tkTest.c b/generic/tkTest.c
index 6712017..44fec0d 100644
--- a/generic/tkTest.c
+++ b/generic/tkTest.c
@@ -31,9 +31,9 @@
#if defined(MAC_OSX_TK)
#include "tkMacOSXInt.h"
#include "tkScrollbar.h"
-#define APP_IS_DRAWING TkTestAppIsDrawing()
+#define LOG_DISPLAY TkTestLogDisplay()
#else
-#define APP_IS_DRAWING 0
+#define LOG_DISPLAY 1
#endif
#ifdef __UNIX__
@@ -1556,25 +1556,36 @@ ImageDisplay(
/*
* The purpose of the test image type is to track the calls to an image
* display proc and record the parameters passed in each call. On macOS
- * these tests will fail because of the asynchronous drawing. The low
- * level graphics calls below which are supposed to draw a rectangle will
- * not draw anything to the screen because the idle task will not be
- * processed inside of the drawRect method and hence will not be able to
- * obtain a valid graphics context. Instead, the window will be marked as
- * needing display, and will be redrawn during a future asynchronous call
- * to drawRect. This will generate an other call to this display proc,
- * and the recorded data will show extra calls, causing the test to fail.
- * To avoid this, we can set the [NSApp simulateDrawing] flag, which will
- * cause all low level drawing routines to return immediately and not
- * schedule the window for drawing later. This flag is cleared by the
- * next call to XSync, which is called by the update command.
+ * a display proc must be run inside of the drawRect method of an NSView
+ * in order for the graphics operations to have any effect. To deal with
+ * this, whenever a display proc is called outside of any drawRect method
+ * it schedules a redraw of the NSView by calling [view setNeedsDisplay:YES].
+ * This will trigger a later call to the view's drawRect method which will
+ * run the display proc a second time.
+ *
+ * This complicates testing, since it can result in more calls to the display
+ * proc than are expected by the test. It can also result in an inconsistent
+ * number of calls unless the test waits until the call to drawRect actually
+ * occurs before validating its results.
+ *
+ * In an attempt to work around this, this display proc only logs those
+ * calls which occur within a drawRect method. This means that tests must
+ * be written so as to ensure that the drawRect method is run before
+ * results are validated. In practice it usually suffices to run update
+ * idletasks (to run the display proc the first time) followed by update
+ * (to run the display proc in drawRect).
+ *
+ * This also has the consequence that the image changed command will log
+ * different results on Aqua than on other systems, because when the image
+ * is redisplayed in the drawRect method the entire image will be drawn,
+ * not just the changed portion. Tests must account for this.
*/
- sprintf(buffer, "%s display %d %d %d %d",
- instPtr->masterPtr->imageName, imageX, imageY, width, height);
- if (!APP_IS_DRAWING) {
+ if (LOG_DISPLAY) {
+ sprintf(buffer, "%s display %d %d %d %d",
+ instPtr->masterPtr->imageName, imageX, imageY, width, height);
Tcl_SetVar2(instPtr->masterPtr->interp, instPtr->masterPtr->varName,
- NULL, buffer, TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
+ NULL, buffer, TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT);
}
if (width > (instPtr->masterPtr->width - imageX)) {
width = instPtr->masterPtr->width - imageX;
diff --git a/generic/ttk/ttkEntry.c b/generic/ttk/ttkEntry.c
index 36edf38..1579a32 100644
--- a/generic/ttk/ttkEntry.c
+++ b/generic/ttk/ttkEntry.c
@@ -1701,6 +1701,16 @@ static WidgetSpec EntryWidgetSpec = {
};
/*------------------------------------------------------------------------
+ * Named indices for the combobox "current" command
+ */
+static const char *const comboboxCurrentIndexNames[] = {
+ "end", NULL
+};
+enum comboboxCurrentIndices {
+ INDEX_END
+};
+
+/*------------------------------------------------------------------------
* +++ Combobox widget record.
*/
@@ -1801,15 +1811,42 @@ static int ComboboxCurrentCommand(
Tcl_SetObjResult(interp, Tcl_NewIntObj(currentIndex));
return TCL_OK;
} else if (objc == 3) {
- if (Tcl_GetIntFromObj(interp, objv[2], &currentIndex) != TCL_OK) {
- return TCL_ERROR;
- }
- if (currentIndex < 0 || currentIndex >= nValues) {
- Tcl_SetObjResult(interp, Tcl_ObjPrintf(
- "Index %s out of range", Tcl_GetString(objv[2])));
- Tcl_SetErrorCode(interp, "TTK", "COMBOBOX", "IDX_RANGE", NULL);
- return TCL_ERROR;
- }
+ int result, index;
+
+ result = Tcl_GetIndexFromObj(NULL, objv[2], comboboxCurrentIndexNames,
+ "", 0, &index);
+ if (result == TCL_OK) {
+
+ /*
+ * The index is one of the named indices.
+ */
+
+ switch (index) {
+ case INDEX_END:
+ /* "end" index */
+ currentIndex = nValues - 1;
+ break;
+ }
+ } else {
+
+ /*
+ * The index should be just an integer.
+ */
+
+ if (Tcl_GetIntFromObj(NULL, objv[2], &currentIndex) != TCL_OK) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "Incorrect index %s", Tcl_GetString(objv[2])));
+ Tcl_SetErrorCode(interp, "TTK", "COMBOBOX", "IDX_VALUE", NULL);
+ return TCL_ERROR;
+ }
+
+ if (currentIndex < 0 || currentIndex >= nValues) {
+ Tcl_SetObjResult(interp, Tcl_ObjPrintf(
+ "Index %s out of range", Tcl_GetString(objv[2])));
+ Tcl_SetErrorCode(interp, "TTK", "COMBOBOX", "IDX_RANGE", NULL);
+ return TCL_ERROR;
+ }
+ }
cbPtr->combobox.currentIndex = currentIndex;
diff --git a/generic/ttk/ttkTrace.c b/generic/ttk/ttkTrace.c
index e6eead2..7c4345d 100644
--- a/generic/ttk/ttkTrace.c
+++ b/generic/ttk/ttkTrace.c
@@ -26,26 +26,15 @@ static char *
VarTraceProc(
ClientData clientData, /* Widget record pointer */
Tcl_Interp *interp, /* Interpreter containing variable. */
- const char *name1, /* Name of variable. */
- const char *name2, /* Second part of variable name. */
+ const char *name1, /* (unused) */
+ const char *name2, /* (unused) */
int flags) /* Information about what happened. */
{
Ttk_TraceHandle *tracePtr = clientData;
const char *name, *value;
Tcl_Obj *valuePtr;
- if (flags & TCL_INTERP_DESTROYED) {
- return NULL;
- }
-
- /*
- * See ticket [5d991b82].
- */
-
- if (tracePtr->varnameObj == NULL) {
- Tcl_UntraceVar2(interp, name1, name2,
- TCL_GLOBAL_ONLY|TCL_TRACE_WRITES|TCL_TRACE_UNSETS,
- VarTraceProc, clientData);
+ if (Tcl_InterpDeleted(interp)) {
return NULL;
}
diff --git a/generic/ttk/ttkTreeview.c b/generic/ttk/ttkTreeview.c
index d78df5f..b1739b6 100644
--- a/generic/ttk/ttkTreeview.c
+++ b/generic/ttk/ttkTreeview.c
@@ -282,7 +282,7 @@ static Tk_OptionSpec ColumnOptionSpecs[] = {
0,0,0 },
{TK_OPTION_BOOLEAN, "-stretch", "stretch", "Stretch",
"1", -1, Tk_Offset(TreeColumn,stretch),
- 0,0,0 },
+ 0,0,GEOMETRY_CHANGED },
{TK_OPTION_ANCHOR, "-anchor", "anchor", "Anchor",
"w", Tk_Offset(TreeColumn,anchorObj), -1, /* <<NOTE-ANCHOR>> */
0,0,0 },
@@ -1234,11 +1234,10 @@ static int ConfigureColumn(
TtkResizeWidget(&tv->core);
}
RecomputeSlack(tv);
+ ResizeColumns(tv, TreeWidth(tv));
}
TtkRedisplayWidget(&tv->core);
- /* ASSERT: SLACKINVARIANT */
-
Tk_FreeSavedOptions(&savedOptions);
return TCL_OK;
@@ -1615,13 +1614,10 @@ static void TreeviewDoLayout(void *clientData)
Treeview *tv = clientData;
int visibleRows;
- /* ASSERT: SLACKINVARIANT */
-
Ttk_PlaceLayout(tv->core.layout,tv->core.state,Ttk_WinBox(tv->core.tkwin));
tv->tree.treeArea = Ttk_ClientRegion(tv->core.layout, "treearea");
ResizeColumns(tv, tv->tree.treeArea.width);
- /* ASSERT: SLACKINVARIANT */
TtkScrolled(tv->tree.xscrollHandle,
tv->tree.xscroll.first,
@@ -2684,7 +2680,7 @@ static int TreeviewDeleteCommand(
{
Treeview *tv = recordPtr;
TreeItem **items, *delq;
- int i;
+ int i, selItemDeleted = 0;
if (objc != 3) {
Tcl_WrongNumArgs(interp, 2, objv, "items");
@@ -2711,6 +2707,9 @@ static int TreeviewDeleteCommand(
*/
delq = 0;
for (i=0; items[i]; ++i) {
+ if (items[i]->state & TTK_STATE_SELECTED) {
+ selItemDeleted = 1;
+ }
delq = DeleteItems(items[i], delq);
}
@@ -2727,6 +2726,9 @@ static int TreeviewDeleteCommand(
}
ckfree(items);
+ if (selItemDeleted) {
+ TtkSendVirtualEvent(tv->core.tkwin, "TreeviewSelect");
+ }
TtkRedisplayWidget(&tv->core);
return TCL_OK;
}
@@ -2885,9 +2887,28 @@ static int TreeviewDragCommand(
TreeColumn *c = tv->tree.displayColumns[i];
int right = left + c->width;
if (c == column) {
- DragColumn(tv, i, newx - right);
- /* ASSERT: SLACKINVARIANT */
- TtkRedisplayWidget(&tv->core);
+ /* The limit not to exceed at the right is given by the tree width
+ minus the sum of the min widths of the columns at the right of
+ the one being resized (and don't forget possible x scrolling!).
+ For stretchable columns, this min width really is the minWidth,
+ for non-stretchable columns, this is the column width.
+ */
+ int newxRightLimit = tv->tree.treeArea.x - tv->tree.xscroll.first
+ + tv->tree.treeArea.width;
+ int j = i + 1;
+ while (j < tv->tree.nDisplayColumns) {
+ TreeColumn *cr = tv->tree.displayColumns[j];
+ if (cr->stretch) {
+ newxRightLimit -= cr->minWidth;
+ } else {
+ newxRightLimit -= cr->width;
+ }
+ ++j;
+ }
+ if (newx <= newxRightLimit) {
+ DragColumn(tv, i, newx - right);
+ TtkRedisplayWidget(&tv->core);
+ }
return TCL_OK;
}
left = right;
@@ -2899,6 +2920,20 @@ static int TreeviewDragCommand(
return TCL_ERROR;
}
+static int TreeviewDropCommand(
+ void *recordPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[])
+{
+ Treeview *tv = recordPtr;
+
+ if (objc != 2) {
+ Tcl_WrongNumArgs(interp, 1, objv, "drop");
+ return TCL_ERROR;
+ }
+ ResizeColumns(tv, TreeWidth(tv));
+ TtkRedisplayWidget(&tv->core);
+ return TCL_OK;
+}
+
/*------------------------------------------------------------------------
* +++ Widget commands -- focus and selection
*/
@@ -3248,6 +3283,7 @@ static const Ttk_Ensemble TreeviewCommands[] = {
{ "delete", TreeviewDeleteCommand,0 },
{ "detach", TreeviewDetachCommand,0 },
{ "drag", TreeviewDragCommand,0 },
+ { "drop", TreeviewDropCommand,0 },
{ "exists", TreeviewExistsCommand,0 },
{ "focus", TreeviewFocusCommand,0 },
{ "heading", TreeviewHeadingCommand,0 },