diff options
author | fvogel <fvogelnew1@free.fr> | 2019-06-08 22:06:10 (GMT) |
---|---|---|
committer | fvogel <fvogelnew1@free.fr> | 2019-06-08 22:06:10 (GMT) |
commit | 0bd46f264389482ef6561255f041c3c15b7d0cc4 (patch) | |
tree | 1865df15c7d699e7cf5b09731c441e2fcb78289c /generic | |
parent | d2d2d59c209cc6a7c8009dc44bd9a4a07aa04887 (diff) | |
parent | 1638e5363d36014e6b4d9c4127431be476def481 (diff) | |
download | tk-0bd46f264389482ef6561255f041c3c15b7d0cc4.zip tk-0bd46f264389482ef6561255f041c3c15b7d0cc4.tar.gz tk-0bd46f264389482ef6561255f041c3c15b7d0cc4.tar.bz2 |
merge core-8-6-branch
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkButton.c | 81 | ||||
-rw-r--r-- | generic/tkEntry.c | 41 | ||||
-rw-r--r-- | generic/tkListbox.c | 40 | ||||
-rw-r--r-- | generic/tkMenu.c | 43 | ||||
-rw-r--r-- | generic/tkMenubutton.c | 35 | ||||
-rw-r--r-- | generic/tkMessage.c | 35 | ||||
-rw-r--r-- | generic/tkScale.c | 35 | ||||
-rw-r--r-- | generic/tkTest.c | 47 | ||||
-rw-r--r-- | generic/ttk/ttkEntry.c | 55 | ||||
-rw-r--r-- | generic/ttk/ttkTrace.c | 17 | ||||
-rw-r--r-- | generic/ttk/ttkTreeview.c | 56 |
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], ¤tIndex) != 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], ¤tIndex) != 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 }, |