summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog8
-rw-r--r--generic/tkText.c87
-rw-r--r--tests/text.test37
3 files changed, 92 insertions, 40 deletions
diff --git a/ChangeLog b/ChangeLog
index 8953f21..f9990e3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-12-12 Jeff Hobbs <jeffh@ActiveState.com>
+
+ * generic/tkText.c (DeleteChars, TextEditCmd, updateDirtyFlag):
+ * tests/text.test (text-25.10.1,25.11.[12]):
+ Don't require [update idle] to trigger Modified event [Bug 1809538]
+ Modified virtual event should only fire on state change [Bug 1799782]
+ Make sure we delete chars before triggering <<Modified>> [Bug 1737288]
+
2007-12-05 Jeff Hobbs <jeffh@ActiveState.com>
* win/tkWinInt.h: remove CS_CLASSDC (not recommended for any apps now)
diff --git a/generic/tkText.c b/generic/tkText.c
index b1be4ab..6e5cb83 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -14,7 +14,7 @@
* See the file "license.terms" for information on usage and redistribution
* of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*
- * RCS: @(#) $Id: tkText.c,v 1.33.2.6 2007/04/29 02:24:02 das Exp $
+ * RCS: @(#) $Id: tkText.c,v 1.33.2.7 2007/12/13 00:31:33 hobbs Exp $
*/
#include "default.h"
@@ -323,6 +323,7 @@ static int TextEditUndo _ANSI_ARGS_((TkText *textPtr));
static int TextEditRedo _ANSI_ARGS_((TkText *textPtr));
static void TextGetText _ANSI_ARGS_((TkTextIndex * index1,
TkTextIndex * index2, Tcl_DString *dsPtr));
+static void GenerateModifiedEvent(TkText *textPtr);
static void updateDirtyFlag _ANSI_ARGS_((TkText *textPtr));
/*
@@ -1721,9 +1722,10 @@ DeleteChars(textPtr, index1String, index2String, indexPtr1, indexPtr2)
Tcl_DStringFree(&actionCommand);
Tcl_DStringFree(&revertCommand);
}
+ TkBTreeDeleteChars(&index1, &index2);
+
updateDirtyFlag(textPtr);
- TkBTreeDeleteChars(&index1, &index2);
if (resetView) {
TkTextMakeByteIndex(textPtr->tree, line, byteIndex, &index1);
TkTextSetYView(textPtr, &index1, 0);
@@ -2871,7 +2873,7 @@ TextEditCmd(textPtr, interp, argc, argv)
int argc; /* Number of arguments. */
CONST char **argv; /* Argument strings. */
{
- int c, setModified;
+ int c;
size_t length;
if (argc < 3) {
@@ -2889,35 +2891,24 @@ TextEditCmd(textPtr, interp, argc, argv)
argv[0], " edit modified ?boolean?\"", (char *) NULL);
return TCL_ERROR;
} else {
- XEvent event;
+ int setModified;
+
if (Tcl_GetBoolean(interp, argv[3], &setModified) != TCL_OK) {
return TCL_ERROR;
- }
- /*
- * Set or reset the dirty info and trigger a Modified event.
- */
-
- if (setModified) {
- textPtr->isDirty = 1;
- textPtr->modifiedSet = 1;
- } else {
- textPtr->isDirty = 0;
- textPtr->modifiedSet = 0;
}
/*
- * Send an event that the text was modified. This is equivalent to
- * "event generate $textWidget <<Modified>>"
+ * Set or reset the dirty info, but trigger a Modified event only
+ * if it has changed. Ensure a rationalized value for the bit.
*/
- memset((VOID *) &event, 0, sizeof(event));
- event.xany.type = VirtualEvent;
- event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
- event.xany.send_event = False;
- event.xany.window = Tk_WindowId(textPtr->tkwin);
- event.xany.display = Tk_Display(textPtr->tkwin);
- ((XVirtualEvent *) &event)->name = Tk_GetUid("Modified");
- Tk_HandleEvent(&event);
+ setModified = setModified ? 1 : 0;
+
+ textPtr->isDirty = setModified;
+ if (textPtr->modifiedSet != setModified) {
+ textPtr->modifiedSet = setModified;
+ GenerateModifiedEvent(textPtr);
+ }
}
} else if ((c == 'r') && (strncmp(argv[2], "redo", length) == 0)
&& (length >= 3)) {
@@ -3018,6 +3009,37 @@ TextGetText(indexPtr1,indexPtr2, dsPtr)
}
/*
+ * GenerateModifiedEvent --
+ *
+ * Send an event that the text was modified. This is equivalent to
+ * event generate $textWidget <<Modified>>
+ *
+ * Results:
+ * None
+ *
+ * Side effects:
+ * May force the text window into existence.
+ */
+
+static void
+GenerateModifiedEvent(
+ TkText *textPtr) /* Information about text widget. */
+{
+ XEvent event;
+
+ Tk_MakeWindowExist(textPtr->tkwin);
+
+ memset(&event, 0, sizeof(event));
+ event.xany.type = VirtualEvent;
+ event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
+ event.xany.send_event = False;
+ event.xany.window = Tk_WindowId(textPtr->tkwin);
+ event.xany.display = Tk_Display(textPtr->tkwin);
+ ((XVirtualEvent *) &event)->name = Tk_GetUid("Modified");
+ Tk_HandleEvent(&event);
+}
+
+/*
* updateDirtyFlag --
* increases the dirtyness of the text widget
*
@@ -3039,19 +3061,6 @@ static void updateDirtyFlag (textPtr)
oldDirtyFlag = textPtr->isDirty;
textPtr->isDirty += textPtr->isDirtyIncrement;
if (textPtr->isDirty == 0 || oldDirtyFlag == 0) {
- XEvent event;
- /*
- * Send an event that the text was modified. This is equivalent to
- * "event generate $textWidget <<Modified>>"
- */
-
- memset((VOID *) &event, 0, sizeof(event));
- event.xany.type = VirtualEvent;
- event.xany.serial = NextRequest(Tk_Display(textPtr->tkwin));
- event.xany.send_event = False;
- event.xany.window = Tk_WindowId(textPtr->tkwin);
- event.xany.display = Tk_Display(textPtr->tkwin);
- ((XVirtualEvent *) &event)->name = Tk_GetUid("Modified");
- Tk_HandleEvent(&event);
+ GenerateModifiedEvent(textPtr);
}
}
diff --git a/tests/text.test b/tests/text.test
index a5cdfbe..0158389 100644
--- a/tests/text.test
+++ b/tests/text.test
@@ -6,7 +6,7 @@
# Copyright (c) 1998-1999 by Scriptics Corporation.
# All rights reserved.
#
-# RCS: @(#) $Id: text.test,v 1.19.2.1 2006/04/05 19:48:44 hobbs Exp $
+# RCS: @(#) $Id: text.test,v 1.19.2.2 2007/12/13 00:31:34 hobbs Exp $
package require tcltest 2.1
namespace import -force tcltest::configure
@@ -1536,6 +1536,21 @@ test text-25.10 {TextEditCmd procedure, set modified flag} {
.t edit modified 1
.t edit modified
} {1}
+test text-25.10.1 {TextEditCmd procedure, set modified flag repeat} {
+ catch {destroy .t}
+ text .t
+ pack .t
+ set ::retval {}
+ bind .t <<Modified>> "lappend ::retval modified"
+ # Shouldn't require [update idle] to trigger event [Bug 1809538]
+ lappend ::retval [.t edit modified]
+ .t edit modified 1
+ update idletasks
+ lappend ::retval [.t edit modified]
+ .t edit modified 1 ; # binding should only fire once [Bug 1799782]
+ update idletasks
+ lappend ::retval [.t edit modified]
+} {0 modified 1 1}
test text-25.11 {<<Modified>> virtual event} {
set ::retval unmodified
@@ -1547,6 +1562,26 @@ test text-25.11 {<<Modified>> virtual event} {
.t insert end "nothing special\n"
set ::retval
} {modified}
+test text-25.11.1 {<<Modified>> virtual event - insert before Modified} {
+ set ::retval {}
+ destroy .t
+ pack [text .t -undo 1]
+ bind .t <<Modified>> { set ::retval [.t get 1.0 end-1c] }
+ update idletasks
+ .t insert end "nothing special"
+ set ::retval
+} {nothing special}
+test text-25.11.2 {<<Modified>> virtual event - delete before Modified} {
+ # Bug 1737288, make sure we delete chars before triggering <<Modified>>
+ set ::retval {}
+ destroy .t
+ pack [text .t -undo 1]
+ bind .t <<Modified>> { set ::retval [.t get 1.0 end-1c] }
+ .t insert end "nothing special"
+ .t edit modified 0
+ .t delete 1.0 1.2
+ set ::retval
+} {thing special}
test text-25.12 {<<Selection>> virtual event} {
set ::retval no_selection