From c99cffa817d24768f82f157cfe08df35925c7f37 Mon Sep 17 00:00:00 2001 From: hobbs Date: Thu, 13 Dec 2007 00:31:33 +0000 Subject: * 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 <> [Bug 1737288] --- ChangeLog | 8 ++++++ generic/tkText.c | 87 +++++++++++++++++++++++++++++++------------------------- tests/text.test | 37 +++++++++++++++++++++++- 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 + + * 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 <> [Bug 1737288] + 2007-12-05 Jeff Hobbs * 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 <>" + * 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 <> + * + * 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 <>" - */ - - 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 <> "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 {<> virtual event} { set ::retval unmodified @@ -1547,6 +1562,26 @@ test text-25.11 {<> virtual event} { .t insert end "nothing special\n" set ::retval } {modified} +test text-25.11.1 {<> virtual event - insert before Modified} { + set ::retval {} + destroy .t + pack [text .t -undo 1] + bind .t <> { set ::retval [.t get 1.0 end-1c] } + update idletasks + .t insert end "nothing special" + set ::retval +} {nothing special} +test text-25.11.2 {<> virtual event - delete before Modified} { + # Bug 1737288, make sure we delete chars before triggering <> + set ::retval {} + destroy .t + pack [text .t -undo 1] + bind .t <> { 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 {<> virtual event} { set ::retval no_selection -- cgit v0.12