diff options
author | hobbs <hobbs> | 2001-04-03 04:40:50 (GMT) |
---|---|---|
committer | hobbs <hobbs> | 2001-04-03 04:40:50 (GMT) |
commit | 5c2ad0a34a4a78a7879cd6dc7e4523f789aa3d0e (patch) | |
tree | a525aba7f40d33313e28afdfe008bcd9322aae02 /generic | |
parent | 9eb72b9d79626c34c27d968c36568bce309c741f (diff) | |
download | tk-5c2ad0a34a4a78a7879cd6dc7e4523f789aa3d0e.zip tk-5c2ad0a34a4a78a7879cd6dc7e4523f789aa3d0e.tar.gz tk-5c2ad0a34a4a78a7879cd6dc7e4523f789aa3d0e.tar.bz2 |
* tests/entry.test: added tests entry-20.*, delete during widget
activity
* generic/tkEntry.c (DestroyEntry, EntryEventProc): fixed the
entry widget to survive deletion while processing scrollbar
updates and validation.
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkEntry.c | 64 |
1 files changed, 53 insertions, 11 deletions
diff --git a/generic/tkEntry.c b/generic/tkEntry.c index 4a01d12..5555b64 100644 --- a/generic/tkEntry.c +++ b/generic/tkEntry.c @@ -12,7 +12,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkEntry.c,v 1.18 2000/11/22 01:49:37 ericm Exp $ + * RCS: @(#) $Id: tkEntry.c,v 1.19 2001/04/03 04:40:50 hobbs Exp $ */ #include "tkInt.h" @@ -851,7 +851,7 @@ Tk_EntryObjCmd(clientData, interp, objc, objv) Tk_DestroyWindow(entryPtr->tkwin); return TCL_ERROR; } - + Tcl_SetResult(interp, Tk_PathName(entryPtr->tkwin), TCL_STATIC); return TCL_OK; } @@ -1323,12 +1323,6 @@ DestroyEntry(memPtr) char *memPtr; /* Info about entry widget. */ { Entry *entryPtr = (Entry *) memPtr; - entryPtr->flags |= ENTRY_DELETED; - - Tcl_DeleteCommandFromToken(entryPtr->interp, entryPtr->widgetCmd); - if (entryPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayEntry, (ClientData) entryPtr); - } /* * Free up all the stuff that requires special handling, then @@ -1367,6 +1361,14 @@ DestroyEntry(memPtr) Tk_FreeConfigOptions((char *) entryPtr, entryPtr->optionTable, entryPtr->tkwin); entryPtr->tkwin = NULL; + + /* + * Tcl_EventuallyFree should be used here or better yet in the + * DestroyNotify branch of EntryEventProc. However, that can lead + * complications in Tk_FreeConfigOptions where the display for the + * entry has been deleted by Tk_DestroyWindow, which is needed + * when freeing the cursor option. + */ ckfree((char *) entryPtr); } @@ -1794,7 +1796,7 @@ DisplayEntry(clientData) Tk_3DBorder border; entryPtr->flags &= ~REDRAW_PENDING; - if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(tkwin)) { + if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(tkwin)) { return; } @@ -1810,6 +1812,15 @@ DisplayEntry(clientData) } /* + * We do this check twice because updating the scrollbar can have + * the side-effect of destroying or unmapping the entry widget. + */ + + if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(tkwin)) { + return; + } + + /* * In order to avoid screen flashes, this procedure redraws the * textual area of the entry into off-screen memory, then copies * it back on-screen in a single operation. This means there's @@ -2606,6 +2617,7 @@ EntryEventProc(clientData, eventPtr) Tk_UndefineCursor(entryPtr->tkwin); } } + return; } switch (eventPtr->type) { @@ -2614,7 +2626,15 @@ EntryEventProc(clientData, eventPtr) entryPtr->flags |= BORDER_NEEDED; break; case DestroyNotify: - DestroyEntry((char *) clientData); + if (!(entryPtr->flags & ENTRY_DELETED)) { + entryPtr->flags |= (ENTRY_DELETED | VALIDATE_ABORT); + Tcl_DeleteCommandFromToken(entryPtr->interp, + entryPtr->widgetCmd); + if (entryPtr->flags & REDRAW_PENDING) { + Tcl_CancelIdleCall(DisplayEntry, clientData); + } + DestroyEntry((char *) entryPtr); + } break; case ConfigureNotify: Tcl_Preserve((ClientData) entryPtr); @@ -3027,7 +3047,7 @@ static void EventuallyRedraw(entryPtr) Entry *entryPtr; /* Information about widget. */ { - if ((entryPtr->tkwin == NULL) || !Tk_IsMapped(entryPtr->tkwin)) { + if ((entryPtr->flags & ENTRY_DELETED) || !Tk_IsMapped(entryPtr->tkwin)) { return; } @@ -3424,15 +3444,27 @@ EntryValidateChange(entryPtr, change, new, index, type) * it means that a loop condition almost occured. Do not allow * this validation result to finish. */ + if (entryPtr->validate == VALIDATE_NONE || (!varValidate && (entryPtr->flags & VALIDATE_VAR))) { code = TCL_ERROR; } + + /* + * It's possible that the user deleted the entry during validation. + * In that case, abort future validation and return an error. + */ + + if (entryPtr->flags & ENTRY_DELETED) { + return TCL_ERROR; + } + /* * If validate will return ERROR, then disallow further validations * Otherwise, if it didn't accept the new string (returned TCL_BREAK) * then eval the invalidCmd (if it's set) */ + if (code == TCL_ERROR) { entryPtr->validate = VALIDATE_NONE; } else if (code == TCL_BREAK) { @@ -3444,6 +3476,7 @@ EntryValidateChange(entryPtr, change, new, index, type) * may want to do entry manipulation which the setting of the * var will later wipe anyway. */ + if (varValidate) { entryPtr->validate = VALIDATE_NONE; } else if (entryPtr->invalidCmd != NULL) { @@ -3461,6 +3494,15 @@ EntryValidateChange(entryPtr, change, new, index, type) entryPtr->validate = VALIDATE_NONE; } Tcl_DStringFree(&script); + + /* + * It's possible that the user deleted the entry during validation. + * In that case, abort future validation and return an error. + */ + + if (entryPtr->flags & ENTRY_DELETED) { + return TCL_ERROR; + } } } |