summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/event.n4
-rw-r--r--doc/text.n25
-rw-r--r--generic/tkText.c139
-rw-r--r--generic/tkUndo.c121
-rw-r--r--generic/tkUndo.h3
-rw-r--r--library/button.tcl19
-rw-r--r--tests/button.test34
-rw-r--r--tests/text.test63
-rw-r--r--win/tkWinDialog.c35
9 files changed, 290 insertions, 153 deletions
diff --git a/doc/event.n b/doc/event.n
index 045339e..54ad42e 100644
--- a/doc/event.n
+++ b/doc/event.n
@@ -352,6 +352,10 @@ user-driven
.QW "tab to widget"
action.
.TP
+\fB<<UndoStack>>\fR
+This is sent to a text widget when its undo stack or redo stack becomes
+empty or unempty.
+.TP
\fB<<WidgetViewSync>>\fR
This is sent to a text widget when its internal data become obsolete,
and again when these internal data are back in sync with the widget
diff --git a/doc/text.n b/doc/text.n
index cb08d2f..e2bb01f 100644
--- a/doc/text.n
+++ b/doc/text.n
@@ -897,6 +897,9 @@ separator is already present at the top of the undo stack no other will be
inserted. That means that two separators on the undo stack are always
separated by at least one insert or delete action.
.PP
+The \fB<<UndoStack>>\fR virtual event is generated every time the undo stack
+or the redo stack becomes empty or unempty.
+.PP
The undo mechanism is also linked to the modified flag. This means that
undoing or redoing changes can take a modified text widget back to the
unmodified state or vice versa. The modified flag will be set automatically to
@@ -1282,6 +1285,16 @@ behavior of the command depends on the \fIoption\fR argument that follows the
supported:
.RS
.TP
+\fIpathName \fBedit canredo\fR
+.
+Returns a boolean true if redo is possible, i.e. when the redo stack is not
+empty. Otherwise returns false.
+.TP
+\fIpathName \fBedit canundo\fR
+.
+Returns a boolean true if undo is possible, i.e. when the undo stack is not
+empty. Otherwise returns false.
+.TP
\fIpathName \fBedit modified \fR?\fIboolean\fR?
.
If \fIboolean\fR is not specified, returns the modified flag of the widget.
@@ -1295,12 +1308,6 @@ When the \fB\-undo\fR option is true, reapplies the last undone edits provided
no other edits were done since then. Generates an error when the redo stack is
empty. Does nothing when the \fB\-undo\fR option is false.
.TP
-\fIpathName \fBedit redodepth\fR
-.
-Returns the depth of the redo stack (number of redoable actions). When this is
-zero there is nothing to redo. When the \fB\-undo\fR option is false zero is
-returned.
-.TP
\fIpathName \fBedit reset\fR
.
Clears the undo and redo stacks.
@@ -1316,12 +1323,6 @@ Undoes the last edit action when the \fB\-undo\fR option is true. An edit
action is defined as all the insert and delete commands that are recorded on
the undo stack in between two separators. Generates an error when the undo
stack is empty. Does nothing when the \fB\-undo\fR option is false.
-.TP
-\fIpathName \fBedit undodepth\fR
-.
-Returns the depth of the undo stack (number of undoable actions). When this is
-zero there is nothing to undo. When the \fB\-undo\fR option is false zero is
-returned.
.RE
.TP
\fIpathName \fBget\fR ?\fB\-displaychars\fR? ?\fB\-\-\fR? \fIindex1\fR ?\fIindex2 ...\fR?
diff --git a/generic/tkText.c b/generic/tkText.c
index d611323..a9b7527 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -401,6 +401,7 @@ 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,
@@ -2769,6 +2770,7 @@ TextPushUndoAction(
/* Index describing second location. */
{
TkUndoSubAtom *iAtom, *dAtom;
+ TkUndoAtom *redoElem, *undoElem;
/*
* Create the helpers.
@@ -2855,6 +2857,9 @@ TextPushUndoAction(
Tcl_DecrRefCount(index1Obj);
Tcl_DecrRefCount(index2Obj);
+ undoElem = textPtr->sharedTextPtr->undoStack->undoStack;
+ redoElem = textPtr->sharedTextPtr->undoStack->redoStack;
+
/*
* Depending whether the action is to insert or delete, we provide the
* appropriate second and third arguments to TkUndoPushAction. (The first
@@ -2866,6 +2871,10 @@ TextPushUndoAction(
} else {
TkUndoPushAction(textPtr->sharedTextPtr->undoStack, dAtom, iAtom);
}
+
+ if (undoElem == NULL || redoElem != NULL) {
+ GenerateUndoStackEvent(textPtr);
+ }
}
/*
@@ -5155,13 +5164,17 @@ TextEditCmd(
Tcl_Obj *const objv[]) /* Argument objects. */
{
int index, setModified, oldModified;
+ int canRedo = 0;
+ int canUndo = 0;
+ TkUndoAtom *redoElem, *undoElem;
+
static const char *const editOptionStrings[] = {
- "modified", "redo", "redodepth", "reset", "separator", "undo",
- "undodepth", NULL
+ "canundo", "canredo", "modified", "redo", "reset", "separator",
+ "undo", NULL
};
enum editOptions {
- EDIT_MODIFIED, EDIT_REDO, EDIT_REDODEPTH, EDIT_RESET,
- EDIT_SEPARATOR, EDIT_UNDO, EDIT_UNDODEPTH
+ EDIT_CANUNDO, EDIT_CANREDO, EDIT_MODIFIED, EDIT_REDO, EDIT_RESET,
+ EDIT_SEPARATOR, EDIT_UNDO
};
if (objc < 3) {
@@ -5175,6 +5188,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,
@@ -5208,42 +5241,36 @@ TextEditCmd(
*/
if ((!oldModified) != (!setModified)) {
- for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
- textPtr = textPtr->next) {
- GenerateModifiedEvent(textPtr);
- }
+ GenerateModifiedEvent(textPtr);
}
break;
case EDIT_REDO:
- if (objc != 3) {
+ if (objc != 3) {
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return TCL_ERROR;
}
- if (TextEditRedo(textPtr)) {
+ undoElem = textPtr->sharedTextPtr->undoStack->undoStack;
+ if (TextEditRedo(textPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to redo", -1));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_REDO", NULL);
return TCL_ERROR;
}
- break;
- case EDIT_REDODEPTH: {
- int depth = 0;
-
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 3, objv, NULL);
- return TCL_ERROR;
- }
- if (textPtr->sharedTextPtr->undo) {
- depth = TkUndoGetDepth(textPtr->sharedTextPtr->undoStack, 1);
+ redoElem = textPtr->sharedTextPtr->undoStack->redoStack;
+ if (undoElem == NULL || redoElem == NULL) {
+ GenerateUndoStackEvent(textPtr);
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(depth));
- break;
- }
+ break;
case EDIT_RESET:
if (objc != 3) {
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return TCL_ERROR;
}
+ undoElem = textPtr->sharedTextPtr->undoStack->undoStack;
+ redoElem = textPtr->sharedTextPtr->undoStack->redoStack;
TkUndoClearStacks(textPtr->sharedTextPtr->undoStack);
+ if (undoElem != NULL || redoElem != NULL) {
+ GenerateUndoStackEvent(textPtr);
+ }
break;
case EDIT_SEPARATOR:
if (objc != 3) {
@@ -5253,29 +5280,21 @@ TextEditCmd(
TkUndoInsertUndoSeparator(textPtr->sharedTextPtr->undoStack);
break;
case EDIT_UNDO:
- if (objc != 3) {
+ if (objc != 3) {
Tcl_WrongNumArgs(interp, 3, objv, NULL);
return TCL_ERROR;
}
+ redoElem = textPtr->sharedTextPtr->undoStack->redoStack;
if (TextEditUndo(textPtr)) {
Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to undo", -1));
Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_UNDO", NULL);
return TCL_ERROR;
}
- break;
- case EDIT_UNDODEPTH: {
- int depth = 0;
-
- if (objc != 3) {
- Tcl_WrongNumArgs(interp, 3, objv, NULL);
- return TCL_ERROR;
- }
- if (textPtr->sharedTextPtr->undo) {
- depth = TkUndoGetDepth(textPtr->sharedTextPtr->undoStack, 0);
+ undoElem = textPtr->sharedTextPtr->undoStack->undoStack;
+ if (redoElem == NULL || undoElem == NULL) {
+ GenerateUndoStackEvent(textPtr);
}
- Tcl_SetObjResult(interp, Tcl_NewIntObj(depth));
- break;
- }
+ break;
}
return TCL_OK;
}
@@ -5369,7 +5388,8 @@ TextGetText(
*
* Send an event that the text was modified. This is equivalent to:
* event generate $textWidget <<Modified>>
- *
+ * for all peers of $textWidget.
+*
* Results:
* None
*
@@ -5383,8 +5403,41 @@ static void
GenerateModifiedEvent(
TkText *textPtr) /* Information about text widget. */
{
- Tk_MakeWindowExist(textPtr->tkwin);
- TkSendVirtualEvent(textPtr->tkwin, "Modified", NULL);
+ 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);
+ }
}
/*
@@ -5408,7 +5461,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
@@ -5439,10 +5491,7 @@ UpdateDirtyFlag(
}
if (sharedTextPtr->isDirty == 0 || oldDirtyFlag == 0) {
- for (textPtr = sharedTextPtr->peers; textPtr != NULL;
- textPtr = textPtr->next) {
- GenerateModifiedEvent(textPtr);
- }
+ GenerateModifiedEvent(sharedTextPtr->peers);
}
}
diff --git a/generic/tkUndo.c b/generic/tkUndo.c
index 3aa3ee2..5934154 100644
--- a/generic/tkUndo.c
+++ b/generic/tkUndo.c
@@ -428,12 +428,12 @@ TkUndoSetMaxDepth(
/*
*----------------------------------------------------------------------
*
- * TkUndoGetDepth
+ * TkUndoClearStacks --
*
- * Return the depth of the undo (or redo) stack.
+ * Clear both the undo and redo stack.
*
* Results:
- * An integer representing the number of undoable (or redoable) actions.
+ * None.
*
* Side effects:
* None.
@@ -441,57 +441,22 @@ TkUndoSetMaxDepth(
*----------------------------------------------------------------------
*/
-int
-TkUndoGetDepth(
- TkUndoRedoStack *stack, /* An Undo/Redo stack */
- int whichStack) /* 0 means the undo stack,
- * otherwise the redo stack */
+void
+TkUndoClearStacks(
+ TkUndoRedoStack *stack) /* An Undo/Redo stack */
{
- int depth = 0;
- TkUndoAtom *elem = NULL;
-
- if (stack != NULL) {
- if (whichStack) {
- elem = stack->redoStack;
- } else {
- elem = stack->undoStack;
- }
-
- if (elem != NULL) {
- /*
- * Skip the first (top) separator if there is one.
- */
-
- if (elem->type == TK_UNDO_SEPARATOR) {
- elem = elem->next;
- }
-
- /*
- * The number of compound actions in the stack is then
- * the number of separators plus one, except if there is
- * a separator at the bottom of the stack. This latter
- * case cannot however happen (TkUndoInsertSeparator
- * prevents from inserting a separator there).
- */
-
- while (elem != NULL) {
- if (elem->type == TK_UNDO_SEPARATOR) {
- depth++;
- }
- elem = elem->next;
- }
- depth++;
- }
- }
- return depth;
+ TkUndoClearStack(&stack->undoStack);
+ TkUndoClearStack(&stack->redoStack);
+ stack->depth = 0;
}
/*
*----------------------------------------------------------------------
*
- * TkUndoClearStacks --
+ * TkUndoFreeStack
*
- * Clear both the undo and redo stack.
+ * Clear both the undo and redo stack and free the memory allocated to
+ * the u/r stack pointer.
*
* Results:
* None.
@@ -503,37 +468,77 @@ TkUndoGetDepth(
*/
void
-TkUndoClearStacks(
+TkUndoFreeStack(
TkUndoRedoStack *stack) /* An Undo/Redo stack */
{
- TkUndoClearStack(&stack->undoStack);
- TkUndoClearStack(&stack->redoStack);
- stack->depth = 0;
+ TkUndoClearStacks(stack);
+ ckfree(stack);
}
/*
*----------------------------------------------------------------------
*
- * TkUndoFreeStack
+ * TkUndoCanRedo --
*
- * Clear both the undo and redo stack and free the memory allocated to
- * the u/r stack pointer.
+ * 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 */
+{
+ int canRedo = 0;
+ TkUndoAtom *elem = stack->redoStack;
+
+ while (elem != NULL) {
+ if (elem->type != TK_UNDO_SEPARATOR) {
+ canRedo = 1;
+ break;
+ }
+ elem = elem->next;
+ }
+ return canRedo;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkUndoCanUndo --
+ *
+ * Returns true if undo is possible, i.e. if the undo stack is not empty.
+ *
+ * Results:
+ * A boolean.
+ *
* Side effects:
* None.
*
*----------------------------------------------------------------------
*/
-void
-TkUndoFreeStack(
+int
+TkUndoCanUndo(
TkUndoRedoStack *stack) /* An Undo/Redo stack */
{
- TkUndoClearStacks(stack);
- ckfree(stack);
+ int canUndo = 0;
+ TkUndoAtom *elem = stack->undoStack;
+
+ while (elem != NULL) {
+ if (elem->type != TK_UNDO_SEPARATOR) {
+ canUndo = 1;
+ break;
+ }
+ elem = elem->next;
+ }
+ return canUndo;
}
/*
diff --git a/generic/tkUndo.h b/generic/tkUndo.h
index 883f6ee..490ede9 100644
--- a/generic/tkUndo.h
+++ b/generic/tkUndo.h
@@ -97,9 +97,10 @@ MODULE_SCOPE void TkUndoClearStack(TkUndoAtom **stack);
MODULE_SCOPE TkUndoRedoStack *TkUndoInitStack(Tcl_Interp *interp, int maxdepth);
MODULE_SCOPE void TkUndoSetMaxDepth(TkUndoRedoStack *stack, int maxdepth);
-MODULE_SCOPE int TkUndoGetDepth(TkUndoRedoStack *stack, int whichStack);
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/library/button.tcl b/library/button.tcl
index b2bafb2..80d8bf9 100644
--- a/library/button.tcl
+++ b/library/button.tcl
@@ -597,12 +597,25 @@ proc ::tk::ButtonUp w {
# w - The name of the widget.
proc ::tk::ButtonInvoke w {
- if {[$w cget -state] ne "disabled"} {
+ if {[winfo exists $w] && [$w cget -state] ne "disabled"} {
set oldRelief [$w cget -relief]
set oldState [$w cget -state]
$w configure -state active -relief sunken
- update idletasks
- after 100
+ after 100 [list ::tk::ButtonInvokeEnd $w $oldState $oldRelief]
+ }
+}
+
+# ::tk::ButtonInvokeEnd --
+# The procedure below is called after a button is invoked through
+# the keyboard. It simulate a release of the button via the mouse.
+#
+# Arguments:
+# w - The name of the widget.
+# oldState - Old state to be set back.
+# oldRelief - Old relief to be set back.
+
+proc ::tk::ButtonInvokeEnd {w oldState oldRelief} {
+ if {[winfo exists $w]} {
$w configure -state $oldState -relief $oldRelief
uplevel #0 [list $w invoke]
}
diff --git a/tests/button.test b/tests/button.test
index 984fd43..708fc30 100644
--- a/tests/button.test
+++ b/tests/button.test
@@ -3750,7 +3750,7 @@ test button-12.1 {button widget vs hidden commands} -body {
destroy .b
} -result {1}
-test button-13.1 {size behaviouor: label} -setup {
+test button-13.1 {size behavior: label} -setup {
label .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
label .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
label .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3769,7 +3769,7 @@ test button-13.1 {size behaviouor: label} -setup {
} -cleanup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.2 {size behaviouor: label} -setup {
+test button-13.2 {size behavior: label} -setup {
label .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
label .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
label .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3789,7 +3789,7 @@ test button-13.2 {size behaviouor: label} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.3 {size behaviouor: button} -setup {
+test button-13.3 {size behavior: button} -setup {
button .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
button .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
button .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3808,7 +3808,7 @@ test button-13.3 {size behaviouor: button} -setup {
} -cleanup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.4 {size behaviouor: button} -setup {
+test button-13.4 {size behavior: button} -setup {
button .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
button .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
button .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3828,7 +3828,7 @@ test button-13.4 {size behaviouor: button} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.5 {size behaviouor: radiobutton} -setup {
+test button-13.5 {size behavior: radiobutton} -setup {
radiobutton .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
radiobutton .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
radiobutton .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3848,7 +3848,7 @@ test button-13.5 {size behaviouor: radiobutton} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.6 {size behaviouor: radiobutton} -setup {
+test button-13.6 {size behavior: radiobutton} -setup {
radiobutton .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
radiobutton .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
radiobutton .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3868,7 +3868,7 @@ test button-13.6 {size behaviouor: radiobutton} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.7 {size behaviouor: checkbutton} -setup {
+test button-13.7 {size behavior: checkbutton} -setup {
checkbutton .a -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
checkbutton .b -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
checkbutton .c -borderwidth 2 -highlightthickness 2 -font {Helvetica -12 bold}
@@ -3888,7 +3888,7 @@ test button-13.7 {size behaviouor: checkbutton} -setup {
destroy .a .b .c
} -result {1 1 1}
-test button-13.8 {size behaviouor: checkbutton} -setup {
+test button-13.8 {size behavior: checkbutton} -setup {
checkbutton .a -borderwidth 2 -highlightthickness 2 -font {Arial 20}
checkbutton .b -borderwidth 2 -highlightthickness 2 -font {Arial 20}
checkbutton .c -borderwidth 2 -highlightthickness 2 -font {Arial 20}
@@ -3908,6 +3908,24 @@ test button-13.8 {size behaviouor: checkbutton} -setup {
destroy .a .b .c
} -result {1 1 1}
+test button-14.1 {bug fix: [011706ec42] tk::ButtonInvoke unsafe wrt widget destruction} -body {
+ proc destroy_button {} {
+ if {[winfo exists .top.b]} {
+ destroy .top.b
+ }
+ }
+ toplevel .top
+ button .top.b -text Foo -command destroy_button
+ bind .top.b <space> destroy_button
+ pack .top.b
+ focus -force .top.b
+ update
+ event generate .top.b <space>
+ update ; # shall not trigger error invalid command name ".top.b"
+} -cleanup {
+ destroy .top.b .top
+} -result {}
+
imageFinish
cleanupTests
return
diff --git a/tests/text.test b/tests/text.test
index 56e69c0..0ec69d0 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -6207,7 +6207,7 @@ test text-27.2 {TextEditCmd procedure, argument parsing} -body {
.t edit gorp
} -cleanup {
destroy .t
-} -returnCodes {error} -result {bad edit option "gorp": must be modified, redo, redodepth, reset, separator, undo, or undodepth}
+} -returnCodes {error} -result {bad edit option "gorp": must be canundo, canredo, modified, redo, reset, separator, or undo}
test text-27.3 {TextEditUndo procedure, undoing changes} -body {
text .t -undo 1
pack .t
@@ -6494,31 +6494,74 @@ test text-27.22 {patch 1669632 (v) - <<Clear>> is atomic} -setup {
} -cleanup {
destroy .top.t .top
} -result "This A an example text"
-test text-27.24 {TextEditCmd procedure, undo and redo stack depths} -setup {
+test text-27.24 {TextEditCmd procedure, canundo and canredo} -setup {
destroy .t
set res {}
} -body {
text .t -undo false -autoseparators false
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
.t configure -undo true
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
.t insert end "DO\n"
.t edit separator
.t insert end "IT\n"
.t insert end "YOURSELF\n"
.t edit separator
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
.t edit undo
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
.t configure -undo false
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
.t configure -undo true
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
.t edit redo
- lappend res [.t edit undodepth] [.t edit redodepth]
+ lappend res [.t edit canundo] [.t edit canredo]
} -cleanup {
destroy .t
-} -result {0 0 0 0 2 0 1 1 0 0 1 1 2 0}
+} -result {0 0 0 0 1 0 1 1 0 0 1 1 1 0}
+test text-27.25 {<<UndoStack>> virtual event} -setup {
+ destroy .t
+ set res {}
+ set nbUS 0
+} -body {
+ text .t -undo false -autoseparators false
+ bind .t <<UndoStack>> {incr nbUS}
+ update ; lappend res $nbUS
+ .t configure -undo true
+ update ; lappend res $nbUS
+ .t insert end "DO\n"
+ .t edit separator
+ .t insert end "IT\n"
+ .t insert end "YOURSELF\n"
+ .t edit separator
+ .t insert end "MAN\n"
+ .t edit separator
+ update ; lappend res $nbUS
+ .t edit undo
+ update ; lappend res $nbUS
+ .t edit redo
+ update ; lappend res $nbUS
+ .t edit undo
+ update ; lappend res $nbUS
+ .t edit undo
+ update ; lappend res $nbUS
+ .t edit undo
+ update ; lappend res $nbUS
+ .t edit redo
+ update ; lappend res $nbUS
+ .t edit redo
+ update ; lappend res $nbUS
+ .t edit redo
+ update ; lappend res $nbUS
+ .t edit undo
+ update ; lappend res $nbUS
+ .t edit undo
+ update ; lappend res $nbUS
+ .t edit reset
+ update ; lappend res $nbUS
+} -cleanup {
+ destroy .t
+} -result {0 0 1 2 3 4 4 5 6 6 7 8 8 9}
test text-28.1 {bug fix - 624372, ControlUtfProc long lines} -body {
diff --git a/win/tkWinDialog.c b/win/tkWinDialog.c
index d58bd52..a7d8c7d 100644
--- a/win/tkWinDialog.c
+++ b/win/tkWinDialog.c
@@ -674,19 +674,25 @@ static void LoadShellProcs()
* processing functions are used to cope with keyboard navigation of
* controls.)
*
- * Here is one solution. After returning, we poll the message queue for
- * 1/4s looking for WM_LBUTTON up messages. If we see one it's consumed.
- * If we get a WM_LBUTTONDOWN message, then we exit early, since the user
- * must be doing something new. This fix only works for the current
- * application, so the problem will still occur if the open dialog
- * happens to be over another applications button. However this is a
- * fairly rare occurrance.
+ * Here is one solution. After returning, we flush all mouse events
+ * for 1/4 second. In 8.6.5 and earlier, the code used to
+ * poll the message queue consuming WM_LBUTTONUP messages.
+ * On seeing a WM_LBUTTONDOWN message, it would exit early, since the user
+ * must be doing something new. However this early exit does not work
+ * on Vista and later because the Windows sends both BUTTONDOWN and
+ * BUTTONUP after the DBLCLICK instead of just BUTTONUP as on XP.
+ * Rather than try and figure out version specific sequences, we
+ * ignore all mouse events in that interval.
+ *
+ * This fix only works for the current application, so the problem will
+ * still occur if the open dialog happens to be over another applications
+ * button. However this is a fairly rare occurrance.
*
* Results:
* None.
*
* Side effects:
- * Consumes an unwanted BUTTON messages.
+ * Consumes unwanted mouse related messages.
*
*-------------------------------------------------------------------------
*/
@@ -698,10 +704,7 @@ EatSpuriousMessageBugFix(void)
DWORD nTime = GetTickCount() + 250;
while (GetTickCount() < nTime) {
- if (PeekMessageA(&msg, 0, WM_LBUTTONDOWN, WM_LBUTTONDOWN, PM_NOREMOVE)){
- break;
- }
- PeekMessageA(&msg, 0, WM_LBUTTONUP, WM_LBUTTONUP, PM_REMOVE);
+ PeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE);
}
}
@@ -1113,7 +1116,7 @@ ParseOFNOptions(
if (strcmp(Tcl_GetString(objv[i]), "-xpstyle"))
goto error_return;
if (i + 1 == objc) {
- Tcl_SetResult(interp, "value for \"-xpstyle\" missing", TCL_STATIC);
+ Tcl_SetObjResult(interp, Tcl_NewStringObj("value for \"-xpstyle\" missing", -1));
Tcl_SetErrorCode(interp, "TK", "FILEDIALOG", "VALUE", NULL);
goto error_return;
}
@@ -1281,9 +1284,8 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr,
int oldMode;
if (tsdPtr->newFileDialogsState != FDLG_STATE_USE_NEW) {
- /* XXX - should be an assert but Tcl does not seem to have one? */
- Tcl_SetResult(interp, "Internal error: GetFileNameVista: IFileDialog API not available", TCL_STATIC);
- return TCL_ERROR;
+ Tcl_Panic("Internal error: GetFileNameVista: IFileDialog API not available");
+ return TCL_ERROR;
}
/*
@@ -1425,6 +1427,7 @@ static int GetFileNameVista(Tcl_Interp *interp, OFNOpts *optsPtr,
oldMode = Tcl_SetServiceMode(TCL_SERVICE_ALL);
hr = fdlgIf->lpVtbl->Show(fdlgIf, hWnd);
Tcl_SetServiceMode(oldMode);
+ EatSpuriousMessageBugFix();
/*
* Ensure that hWnd is enabled, because it can happen that we have updated