From 6368c8d4f3e6c11af0a65b3b61fc27ac24267c8d Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Tue, 10 Nov 2015 21:03:04 +0000 Subject: Implementation of TIP #438 - Solution using virtual events --- generic/tkTextDisp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 6036222..a275b28 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -590,6 +590,8 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp, Tcl_Obj *CONST objv[], double *dblPtr, int *intPtr); static void AsyncUpdateLineMetrics(ClientData clientData); +static void GenerateMetricsEvent(TkText *textPtr, + CONST char *eventname); static void AsyncUpdateYScrollbar(ClientData clientData); static int IsStartOfNotMergedLine(TkText *textPtr, CONST TkTextIndex *indexPtr); @@ -2944,6 +2946,7 @@ AsyncUpdateLineMetrics( if (textPtr->refCount == 0) { ckfree((char *) textPtr); } + GenerateMetricsEvent(textPtr, "MetricsDone"); return; } dInfoPtr->currentMetricUpdateLine = lineNum; @@ -2960,6 +2963,51 @@ AsyncUpdateLineMetrics( /* *---------------------------------------------------------------------- * + * GenerateMetricsEvent -- + * + * Send an event related to the text widget metrics asynchronous update + * Two events are used: + * - <>: the asynchronous update of line metrics is + * currently running + * - <> : the asynchronous update of line metrics is + * over + * This is equivalent to: + * event generate $textWidget <> + * or + * event generate $textWidget <> + * + * Results: + * None + * + * Side effects: + * May force the text window into existence. + * If corresponding bindings are present, they will trigger. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateMetricsEvent( + TkText *textPtr, /* Information about text widget. */ + CONST char *eventname) /* Name of the virtual event to send. */ +{ + union {XEvent general; XVirtualEvent virtual;} event; + + Tk_MakeWindowExist(textPtr->tkwin); + + memset(&event, 0, sizeof(event)); + event.general.xany.type = VirtualEvent; + event.general.xany.serial = NextRequest(Tk_Display(textPtr->tkwin)); + event.general.xany.send_event = False; + event.general.xany.window = Tk_WindowId(textPtr->tkwin); + event.general.xany.display = Tk_Display(textPtr->tkwin); + event.virtual.name = Tk_GetUid(eventname); + Tk_HandleEvent(&event.general); +} + +/* + *---------------------------------------------------------------------- + * * TkTextUpdateLineMetrics -- * * This function updates the pixel height calculations of a range of @@ -3336,6 +3384,7 @@ TextInvalidateLineMetrics( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, (ClientData) textPtr); + GenerateMetricsEvent(textPtr, "MetricsOutdated"); } } @@ -5040,6 +5089,7 @@ TkTextRelayoutWindow( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, (ClientData) textPtr); + GenerateMetricsEvent(textPtr, "MetricsOutdated"); } } } -- cgit v0.12 From 96dd743b8e2af0448cb41cb7cf856b9e875ab7f0 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 14 Nov 2015 00:02:49 +0000 Subject: TIP #438 - [.text yupdate] command added, with corresponding new tests --- generic/tkText.c | 14 ++++++++++++-- tests/text.test | 45 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index cb89218..4d2df7e 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -690,14 +690,14 @@ TextWidgetObjCmd( "bbox", "cget", "compare", "configure", "count", "debug", "delete", "dlineinfo", "dump", "edit", "get", "image", "index", "insert", "mark", "peer", "replace", "scan", "search", "see", "tag", "window", - "xview", "yview", NULL + "xview", "yupdate", "yview", NULL }; enum options { TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT, TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT, TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK, TEXT_PEER, TEXT_REPLACE, TEXT_SCAN, TEXT_SEARCH, TEXT_SEE, - TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, TEXT_YVIEW + TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, TEXT_YUPDATE, TEXT_YVIEW }; if (objc < 2) { @@ -1494,6 +1494,16 @@ TextWidgetObjCmd( case TEXT_XVIEW: result = TkTextXviewCmd(textPtr, interp, objc, objv); break; + case TEXT_YUPDATE: { + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + result = TCL_ERROR; + goto done; + } + TkTextUpdateLineMetrics(textPtr, 1, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); + break; + } case TEXT_YVIEW: result = TkTextYviewCmd(textPtr, interp, objc, objv); break; diff --git a/tests/text.test b/tests/text.test index 7c1731d..f08431d 100644 --- a/tests/text.test +++ b/tests/text.test @@ -153,7 +153,7 @@ test text-3.1 {TextWidgetCmd procedure, basics} { } {1 {wrong # args: should be ".t option ?arg arg ...?"}} test text-3.2 {TextWidgetCmd procedure} { list [catch {.t gorp 1.0 z 1.2} msg] $msg -} {1 {bad option "gorp": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, or yview}} +} {1 {bad option "gorp": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} test text-4.1 {TextWidgetCmd procedure, "bbox" option} { list [catch {.t bbox} msg] $msg @@ -221,7 +221,7 @@ test text-6.13 {TextWidgetCmd procedure, "compare" option} { } {1 {bad comparison operator "z": must be <, <=, ==, >=, >, or !=}} test text-6.14 {TextWidgetCmd procedure, "compare" option} { list [catch {.t co 1.0 z 1.2} msg] $msg -} {1 {ambiguous option "co": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, or yview}} +} {1 {ambiguous option "co": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} # "configure" option is already covered above @@ -230,7 +230,7 @@ test text-7.1 {TextWidgetCmd procedure, "debug" option} { } {1 {wrong # args: should be ".t debug boolean"}} test text-7.2 {TextWidgetCmd procedure, "debug" option} { list [catch {.t de 0 1} msg] $msg -} {1 {ambiguous option "de": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, or yview}} +} {1 {ambiguous option "de": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} test text-7.3 {TextWidgetCmd procedure, "debug" option} { .t debug true .t deb @@ -901,7 +901,7 @@ test text-10.2 {TextWidgetCmd procedure, "index" option} { } {1 {wrong # args: should be ".t index index"}} test text-10.3 {TextWidgetCmd procedure, "index" option} { list [catch {.t in a b} msg] $msg -} {1 {ambiguous option "in": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, or yview}} +} {1 {ambiguous option "in": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} test text-10.4 {TextWidgetCmd procedure, "index" option} { list [catch {.t index @xyz} msg] $msg } {1 {bad text index "@xyz"}} @@ -960,7 +960,42 @@ test text-11.10 {TextWidgetCmd procedure, "insert" option} { list [.t get 1.0 1.end] [.t tag ranges bold] [.t tag ranges silly] } {{First second} {1.0 1.5} {1.5 1.12}} -# Edit, mark, scan, search, see, tag, window, xview, and yview actions are tested elsewhere. +test text-11a.1 {TextWidgetCmd procedure, "yupdate" option} { + destroy .yt + text .yt + list [catch {.yt yupdate mytext} msg] $msg +} {1 {wrong # args: should be ".yt yupdate"}} +test text-11a.2 {TextWidgetCmd procedure, "yupdate" option} { + destroy .top.yt .top + toplevel .top + pack [text .top.yt] + set content {} + for {set i 1} {$i < 30} {incr i} { + append content [string repeat "$i " 15] \n + } + .top.yt insert 1.0 $content + # wait for end of line metrics calculation to get correct $fraction1 + # as a reference + .top.yt yupdate + .top.yt yview moveto 1 + set fraction1 [lindex [.top.yt yview] 0] + set res [expr {$fraction1 > 0}] + # first case: do not wait for completion of line metrics calculation + .top.yt delete 1.0 end + .top.yt insert 1.0 $content + .top.yt yview moveto $fraction1 + set fraction2 [lindex [.top.yt yview] 0] + lappend res [expr {$fraction1 == $fraction2}] + # second case: wait for completion of line metrics calculation + .top.yt delete 1.0 end + .top.yt insert 1.0 $content + .top.yt yupdate + .top.yt yview moveto $fraction1 + set fraction2 [lindex [.top.yt yview] 0] + lappend res [expr {$fraction1 == $fraction2}] +} {1 0 1} + +# edit, mark, scan, search, see, tag, window, xview and yview actions are tested elsewhere. test text-12.1 {ConfigureText procedure} { list [catch {.t2 configure -state foobar} msg] $msg -- cgit v0.12 From 2107e14c172630b3da7e26687ba2a1c82b3bcf09 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 14 Nov 2015 09:11:48 +0000 Subject: TIP #438 - [.text pendingyupdate] command added, with corresponding new tests --- generic/tkText.c | 21 +++++++++++++++++---- generic/tkText.h | 1 + generic/tkTextDisp.c | 30 +++++++++++++++++++++++++++++- tests/text.test | 41 ++++++++++++++++++++++++++++++++++++----- 4 files changed, 83 insertions(+), 10 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 4d2df7e..36bb4d4 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -689,15 +689,16 @@ TextWidgetObjCmd( static const char *optionStrings[] = { "bbox", "cget", "compare", "configure", "count", "debug", "delete", "dlineinfo", "dump", "edit", "get", "image", "index", "insert", - "mark", "peer", "replace", "scan", "search", "see", "tag", "window", - "xview", "yupdate", "yview", NULL + "mark", "peer", "pendingyupdate", "replace", "scan", "search", + "see", "tag", "window", "xview", "yupdate", "yview", NULL }; enum options { TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT, TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT, TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK, - TEXT_PEER, TEXT_REPLACE, TEXT_SCAN, TEXT_SEARCH, TEXT_SEE, - TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, TEXT_YUPDATE, TEXT_YVIEW + TEXT_PEER, TEXT_PENDINGYUPDATE, TEXT_REPLACE, TEXT_SCAN, + TEXT_SEARCH, TEXT_SEE, TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, + TEXT_YUPDATE, TEXT_YVIEW }; if (objc < 2) { @@ -1372,6 +1373,18 @@ TextWidgetObjCmd( case TEXT_PEER: result = TextPeerCmd(textPtr, interp, objc, objv); break; + case TEXT_PENDINGYUPDATE: { + int number; + + if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, NULL); + result = TCL_ERROR; + goto done; + } + number = TkTextPendingyupdate(textPtr); + Tcl_SetObjResult(interp, Tcl_NewIntObj(number)); + break; + } case TEXT_REPLACE: { const TkTextIndex *indexFromPtr, *indexToPtr; diff --git a/generic/tkText.h b/generic/tkText.h index 6f5f153..2d1bcaa 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -1124,6 +1124,7 @@ MODULE_SCOPE int TkTextMarkNameToIndex(TkText *textPtr, MODULE_SCOPE void TkTextMarkSegToIndex(TkText *textPtr, TkTextSegment *markPtr, TkTextIndex *indexPtr); MODULE_SCOPE void TkTextEventuallyRepick(TkText *textPtr); +MODULE_SCOPE int TkTextPendingyupdate(TkText *textPtr); MODULE_SCOPE void TkTextPickCurrent(TkText *textPtr, XEvent *eventPtr); MODULE_SCOPE void TkTextPixelIndex(TkText *textPtr, int x, int y, TkTextIndex *indexPtr, int *nearest); diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 6036222..d740181 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -2920,6 +2920,8 @@ AsyncUpdateLineMetrics( lineNum = TkTextUpdateLineMetrics(textPtr, lineNum, dInfoPtr->lastMetricUpdateLine, 256); + dInfoPtr->currentMetricUpdateLine = lineNum; + if (tkTextDebug) { char buffer[2 * TCL_INTEGER_SPACE + 1]; @@ -2946,7 +2948,6 @@ AsyncUpdateLineMetrics( } return; } - dInfoPtr->currentMetricUpdateLine = lineNum; /* * Re-arm the timer. We already have a refCount on the text widget so no @@ -6034,6 +6035,33 @@ TkTextYviewCmd( /* *-------------------------------------------------------------- * + * TkTextPendingyupdate -- + * + * This function computes how many lines are not up-to-date regarding + * asynchronous height calculations. + * + * Results: + * Returns a positive integer corresponding to the number of lines for + * which the height is outdated. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +int +TkTextPendingyupdate( + TkText *textPtr) /* Information about text widget. */ +{ + TextDInfo *dInfoPtr = textPtr->dInfoPtr; + + return (dInfoPtr->lastMetricUpdateLine - dInfoPtr->currentMetricUpdateLine); +} + +/* + *-------------------------------------------------------------- + * * TkTextScanCmd -- * * This function is invoked to process the "scan" option for the widget diff --git a/tests/text.test b/tests/text.test index f08431d..d8ed533 100644 --- a/tests/text.test +++ b/tests/text.test @@ -153,7 +153,7 @@ test text-3.1 {TextWidgetCmd procedure, basics} { } {1 {wrong # args: should be ".t option ?arg arg ...?"}} test text-3.2 {TextWidgetCmd procedure} { list [catch {.t gorp 1.0 z 1.2} msg] $msg -} {1 {bad option "gorp": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {bad option "gorp": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} test text-4.1 {TextWidgetCmd procedure, "bbox" option} { list [catch {.t bbox} msg] $msg @@ -221,7 +221,7 @@ test text-6.13 {TextWidgetCmd procedure, "compare" option} { } {1 {bad comparison operator "z": must be <, <=, ==, >=, >, or !=}} test text-6.14 {TextWidgetCmd procedure, "compare" option} { list [catch {.t co 1.0 z 1.2} msg] $msg -} {1 {ambiguous option "co": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {ambiguous option "co": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} # "configure" option is already covered above @@ -230,7 +230,7 @@ test text-7.1 {TextWidgetCmd procedure, "debug" option} { } {1 {wrong # args: should be ".t debug boolean"}} test text-7.2 {TextWidgetCmd procedure, "debug" option} { list [catch {.t de 0 1} msg] $msg -} {1 {ambiguous option "de": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {ambiguous option "de": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} test text-7.3 {TextWidgetCmd procedure, "debug" option} { .t debug true .t deb @@ -901,7 +901,7 @@ test text-10.2 {TextWidgetCmd procedure, "index" option} { } {1 {wrong # args: should be ".t index index"}} test text-10.3 {TextWidgetCmd procedure, "index" option} { list [catch {.t in a b} msg] $msg -} {1 {ambiguous option "in": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {ambiguous option "in": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} test text-10.4 {TextWidgetCmd procedure, "index" option} { list [catch {.t index @xyz} msg] $msg } {1 {bad text index "@xyz"}} @@ -994,6 +994,37 @@ test text-11a.2 {TextWidgetCmd procedure, "yupdate" option} { set fraction2 [lindex [.top.yt yview] 0] lappend res [expr {$fraction1 == $fraction2}] } {1 0 1} +test text-11a.11 {TextWidgetCmd procedure, "pendingyupdate" option} { + destroy .yt + text .yt + list [catch {.yt pendingyupdate mytext} msg] $msg +} {1 {wrong # args: should be ".yt pendingyupdate"}} +test text-11a.12 {TextWidgetCmd procedure, "pendingyupdate" option} { + destroy .top.yt .top + toplevel .top + pack [text .top.yt] + set content {} + for {set i 1} {$i < 300} {incr i} { + append content [string repeat "$i " 15] \n + } + .top.yt insert 1.0 $content + update + # wait for end of line metrics calculation to get correct $fraction1 + # as a reference + while {[.top.yt pendingyupdate]} {update} + .top.yt yview moveto 1 + set fraction1 [lindex [.top.yt yview] 0] + set res [expr {$fraction1 > 0}] + .top.yt delete 1.0 end + .top.yt insert 1.0 $content + # ensure the test is relevant + lappend res [expr {[.top.yt pendingyupdate] > 0}] + # asynchronously wait for completion of line metrics calculation + while {[.top.yt pendingyupdate]} {update} + .top.yt yview moveto $fraction1 + set fraction2 [lindex [.top.yt yview] 0] + lappend res [expr {$fraction1 == $fraction2}] +} {1 1 1} # edit, mark, scan, search, see, tag, window, xview and yview actions are tested elsewhere. @@ -3733,7 +3764,7 @@ test text-31.2 {TextWidgetCmd procedure, "peer" option} { list [catch {.t peer names foo} msg] $msg } {1 {wrong # args: should be ".t peer names"}} test text-31.3 {TextWidgetCmd procedure, "peer" option} { - list [catch {.t p names} msg] $msg + list [catch {.t pee names} msg] $msg } {0 {}} test text-31.4 {TextWidgetCmd procedure, "peer" option} { .t peer names -- cgit v0.12 From 2ed86ea1765109d17541c7108b0d50dd0f54bae9 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Mon, 16 Nov 2015 17:21:36 +0000 Subject: Better test for bug [2677890] since [19960bcef8] breaks relevance/efficiency of the previous version of textDisp-34.1 --- tests/textDisp.test | 41 +++++++++++++++++++++++------------------ 1 file changed, 23 insertions(+), 18 deletions(-) diff --git a/tests/textDisp.test b/tests/textDisp.test index 9c6af70..4c88b38 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -4162,29 +4162,34 @@ test textDisp-33.5 {bold or italic fonts} win { } {italic font measurement ok} destroy .tt -test textDisp-34.1 {Text widgets multi-scrolling problem: Bug 2677890} -setup { - pack [text .t1 -width 10 -yscrollcommand {.sy set}] \ - [ttk::scrollbar .sy -orient vertical -command {.t1 yview}] \ - -side left -fill both - bindtags .sy {}; # No clicky! +test textDisp-34.1 {Line heights recalculation problem: bug 2677890} -setup { + pack [text .t1] -expand 1 -fill both set txt "" - for {set i 0} {$i < 99} {incr i} { - lappend txt "$i" [list pc $i] "\n" "" + for {set i 1} {$i < 100} {incr i} { + append txt "Line $i\n" } set result {} } -body { - .t1 insert end {*}$txt - update - lappend result [.sy get] - .t1 replace 6.0 6.0+1c "*" - lappend result [.sy get] - after 0 {lappend result [.sy get]} - after 1000 {lappend result [.sy get]} - vwait result;vwait result - return $result + .t1 insert end $txt + .t1 debug 1 + set ge [winfo geometry .] + scan $ge "%dx%d+%d+%d" width height left top + update + .t1 yupdate + set negative 0 + bind .t1 <> { if {%d < 0} {set negative 1} } + # Without the fix for bug 2677890, changing the width of the toplevel + # will launch recomputation of the line heights, but will produce negative + # number of still remaining outdated lines, which is obviously wrong. + # Thus we use this way to check for regression regarding bug 2677890, + # i.e. to check that the fix for this bug really is still in. + wm geometry . "[expr {$width * 2}]x$height+$left+$top" + update + .t1 yupdate + set negative } -cleanup { - destroy .t1 .sy -} -result {{0.0 0.24} {0.0 0.24} {0.0 0.24} {0.0 0.24}} + destroy .t1 +} -result {0} deleteWindows option clear -- cgit v0.12 From 6ab92895455d58b56238f1662cc1a08ffbf52d80 Mon Sep 17 00:00:00 2001 From: "nijtmans@users.sourceforge.net" Date: Thu, 19 Nov 2015 20:46:40 +0000 Subject: First test-implementation of "$t yupdate -command ". TODO: more testcases and documentation --- generic/tkText.c | 37 +++++++++++++++++++++++++++++-------- generic/tkText.h | 1 + generic/tkTextDisp.c | 13 ++++++++++++- tests/textDisp.test | 18 ++++++++++++++++++ 4 files changed, 60 insertions(+), 9 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 5c7f187..2c4d54c 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1508,14 +1508,31 @@ TextWidgetObjCmd( result = TkTextXviewCmd(textPtr, interp, objc, objv); break; case TEXT_YUPDATE: { - if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, NULL); - result = TCL_ERROR; - goto done; - } - TkTextUpdateLineMetrics(textPtr, 1, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); - break; + if ((objc == 4) && !strncmp(Tcl_GetString(objv[2]), "-command", objv[3]->length)) { + Tcl_Obj *cmd = objv[3]; + Tcl_IncrRefCount(cmd); + if (TkTextPendingyupdate(textPtr)) { + if (textPtr->linesUpdatedCmd) { + Tcl_DecrRefCount(textPtr->linesUpdatedCmd); + } + textPtr->linesUpdatedCmd = cmd; + } else { + result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmd); + } + break; + } else if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); + result = TCL_ERROR; + goto done; + } + if (textPtr->linesUpdatedCmd) { + Tcl_DecrRefCount(textPtr->linesUpdatedCmd); + } + textPtr->linesUpdatedCmd = NULL; + TkTextUpdateLineMetrics(textPtr, 1, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); + break; } case TEXT_YVIEW: result = TkTextYviewCmd(textPtr, interp, objc, objv); @@ -1993,6 +2010,10 @@ DestroyText( textPtr->tkwin = NULL; textPtr->refCount--; Tcl_DeleteCommandFromToken(textPtr->interp, textPtr->widgetCmd); + if (textPtr->linesUpdatedCmd != 0){ + Tcl_DecrRefCount(textPtr->linesUpdatedCmd); + textPtr->linesUpdatedCmd = 0; + } if (textPtr->refCount == 0) { ckfree((char *) textPtr); } diff --git a/generic/tkText.h b/generic/tkText.h index 2d1bcaa..192ab12 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -782,6 +782,7 @@ typedef struct TkText { * statements. */ int autoSeparators; /* Non-zero means the separators will be * inserted automatically. */ + Tcl_Obj *linesUpdatedCmd; /* Command to be executed when lines are up to date */ } TkText; /* diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index ff90520..d31d2f3 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -2942,9 +2942,20 @@ AsyncUpdateLineMetrics( /* * We have looped over all lines, so we're done. We must release our * refCount on the widget (the timer token was already set to NULL - * above). + * above). If there is a registered command, run that first. */ + if (textPtr->linesUpdatedCmd != NULL) { + Tcl_Preserve((ClientData)textPtr->interp); + int code = Tcl_EvalObjEx(textPtr->interp, textPtr->linesUpdatedCmd, TCL_EVAL_GLOBAL); + if (code != TCL_OK && code != TCL_CONTINUE + && code != TCL_BREAK) { + Tcl_AddErrorInfo(textPtr->interp, "\n (text yupdate)"); + Tcl_BackgroundError(textPtr->interp); + } + Tcl_Release((ClientData)textPtr->interp); + } + textPtr->refCount--; if (textPtr->refCount == 0) { ckfree((char *) textPtr); diff --git a/tests/textDisp.test b/tests/textDisp.test index 4c88b38..f2b176c 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -4191,6 +4191,24 @@ test textDisp-34.1 {Line heights recalculation problem: bug 2677890} -setup { destroy .t1 } -result {0} +test textDisp-34.2 {text yupdate syntax} -body { +} -body { + pack [text .t1] -expand 1 -fill both + .t1 yupdate foo +} -cleanup { + destroy .t1 +} -returnCodes 1 -result {wrong # args: should be ".t1 yupdate ?-command command?"} + +test textDisp-34.3 {text yupdate syntax} -body { +} -body { + set ::x 0 + pack [text .t1] -expand 1 -fill both + .t1 yupdate -command [list set ::x 1] + set ::x +} -cleanup { + destroy .t1 +} -result {1} + deleteWindows option clear -- cgit v0.12 From ecde8b2c60ae6a039a5c517b119b67f5acad545d Mon Sep 17 00:00:00 2001 From: "nijtmans@users.sourceforge.net" Date: Thu, 19 Nov 2015 21:04:08 +0000 Subject: better argument checking --- generic/tkText.c | 8 +++++++- tests/textDisp.test | 10 +++++++++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 2c4d54c..9cae716 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1508,8 +1508,14 @@ TextWidgetObjCmd( result = TkTextXviewCmd(textPtr, interp, objc, objv); break; case TEXT_YUPDATE: { - if ((objc == 4) && !strncmp(Tcl_GetString(objv[2]), "-command", objv[3]->length)) { + if (objc == 4) { Tcl_Obj *cmd = objv[3]; + const char *option = Tcl_GetString(objv[2]); + if (strncmp(option, "-command", objv[2]->length)) { + Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL); + result = TCL_ERROR; + goto done; + } Tcl_IncrRefCount(cmd); if (TkTextPendingyupdate(textPtr)) { if (textPtr->linesUpdatedCmd) { diff --git a/tests/textDisp.test b/tests/textDisp.test index f2b176c..133fcf5 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -4201,9 +4201,17 @@ test textDisp-34.2 {text yupdate syntax} -body { test textDisp-34.3 {text yupdate syntax} -body { } -body { + pack [text .t1] -expand 1 -fill both + .t1 yupdate -comx foo +} -cleanup { + destroy .t1 +} -returnCodes 1 -result {wrong option "-comx": should be "-command"} + +test textDisp-34.4 {text yupdate syntax} -body { +} -body { set ::x 0 pack [text .t1] -expand 1 -fill both - .t1 yupdate -command [list set ::x 1] + .t1 yupdate -comm [list set ::x 1] set ::x } -cleanup { destroy .t1 -- cgit v0.12 From 77f0f954d26cd60d994bcf873533e8308f06bf27 Mon Sep 17 00:00:00 2001 From: "nijtmans@users.sourceforge.net" Date: Thu, 19 Nov 2015 21:41:31 +0000 Subject: Code Formatting --- generic/tkText.c | 54 ++++++++++++++++++++++++++-------------------------- generic/tkText.h | 2 +- generic/tkTextDisp.c | 14 ++++++++------ 3 files changed, 36 insertions(+), 34 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 9cae716..15c6e73 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1508,36 +1508,36 @@ TextWidgetObjCmd( result = TkTextXviewCmd(textPtr, interp, objc, objv); break; case TEXT_YUPDATE: { - if (objc == 4) { - Tcl_Obj *cmd = objv[3]; - const char *option = Tcl_GetString(objv[2]); - if (strncmp(option, "-command", objv[2]->length)) { - Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL); + if (objc == 4) { + Tcl_Obj *cmd = objv[3]; + const char *option = Tcl_GetString(objv[2]); + if (strncmp(option, "-command", objv[2]->length)) { + Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL); result = TCL_ERROR; goto done; + } + Tcl_IncrRefCount(cmd); + if (TkTextPendingyupdate(textPtr)) { + if (textPtr->afterSyncCmd) { + Tcl_DecrRefCount(textPtr->afterSyncCmd); } - Tcl_IncrRefCount(cmd); - if (TkTextPendingyupdate(textPtr)) { - if (textPtr->linesUpdatedCmd) { - Tcl_DecrRefCount(textPtr->linesUpdatedCmd); - } - textPtr->linesUpdatedCmd = cmd; - } else { + textPtr->afterSyncCmd = cmd; + } else { result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); Tcl_DecrRefCount(cmd); - } - break; - } else if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); - result = TCL_ERROR; - goto done; - } - if (textPtr->linesUpdatedCmd) { - Tcl_DecrRefCount(textPtr->linesUpdatedCmd); } - textPtr->linesUpdatedCmd = NULL; - TkTextUpdateLineMetrics(textPtr, 1, - TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); + break; + } else if (objc != 2) { + Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); + result = TCL_ERROR; + goto done; + } + if (textPtr->afterSyncCmd) { + Tcl_DecrRefCount(textPtr->afterSyncCmd); + } + textPtr->afterSyncCmd = NULL; + TkTextUpdateLineMetrics(textPtr, 1, + TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); break; } case TEXT_YVIEW: @@ -2016,9 +2016,9 @@ DestroyText( textPtr->tkwin = NULL; textPtr->refCount--; Tcl_DeleteCommandFromToken(textPtr->interp, textPtr->widgetCmd); - if (textPtr->linesUpdatedCmd != 0){ - Tcl_DecrRefCount(textPtr->linesUpdatedCmd); - textPtr->linesUpdatedCmd = 0; + if (textPtr->afterSyncCmd != 0){ + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = 0; } if (textPtr->refCount == 0) { ckfree((char *) textPtr); diff --git a/generic/tkText.h b/generic/tkText.h index 192ab12..2aa8d59 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -782,7 +782,7 @@ typedef struct TkText { * statements. */ int autoSeparators; /* Non-zero means the separators will be * inserted automatically. */ - Tcl_Obj *linesUpdatedCmd; /* Command to be executed when lines are up to date */ + Tcl_Obj *afterSyncCmd; /* Command to be executed when lines are up to date */ } TkText; /* diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index d31d2f3..a18e2b9 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -2945,15 +2945,17 @@ AsyncUpdateLineMetrics( * above). If there is a registered command, run that first. */ - if (textPtr->linesUpdatedCmd != NULL) { - Tcl_Preserve((ClientData)textPtr->interp); - int code = Tcl_EvalObjEx(textPtr->interp, textPtr->linesUpdatedCmd, TCL_EVAL_GLOBAL); - if (code != TCL_OK && code != TCL_CONTINUE + if (textPtr->afterSyncCmd != NULL) { + Tcl_Preserve((ClientData)textPtr->interp); + int code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); + if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { Tcl_AddErrorInfo(textPtr->interp, "\n (text yupdate)"); Tcl_BackgroundError(textPtr->interp); - } - Tcl_Release((ClientData)textPtr->interp); + } + Tcl_Release((ClientData)textPtr->interp); + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = 0; } textPtr->refCount--; -- cgit v0.12 From bf839722a8f45dc2dc77cda2f3af7b8b684ed564 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Thu, 19 Nov 2015 21:57:36 +0000 Subject: Make it compile with Visual 2008 --- generic/tkTextDisp.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index a18e2b9..8f72be0 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -2946,8 +2946,8 @@ AsyncUpdateLineMetrics( */ if (textPtr->afterSyncCmd != NULL) { - Tcl_Preserve((ClientData)textPtr->interp); int code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); + Tcl_Preserve((ClientData)textPtr->interp); if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { Tcl_AddErrorInfo(textPtr->interp, "\n (text yupdate)"); -- cgit v0.12 From 57c735023e6a78bdf82a0182e14208d1e8450b67 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Thu, 19 Nov 2015 21:59:11 +0000 Subject: Tcl_Preserve should be first I guess --- generic/tkTextDisp.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 8f72be0..a8a8f85 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -2946,8 +2946,9 @@ AsyncUpdateLineMetrics( */ if (textPtr->afterSyncCmd != NULL) { - int code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); + int code; Tcl_Preserve((ClientData)textPtr->interp); + code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { Tcl_AddErrorInfo(textPtr->interp, "\n (text yupdate)"); -- cgit v0.12 From b621ecad3a2d575d1407f92058057a6697db080a Mon Sep 17 00:00:00 2001 From: "nijtmans@users.sourceforge.net" Date: Thu, 19 Nov 2015 22:02:27 +0000 Subject: Rename "yupdate" to "sync" and fix various test-cases --- generic/tkText.c | 50 +++++++++++++++++++++++++------------------------- generic/tkText.h | 2 +- generic/tkTextDisp.c | 24 ++++++++++++------------ tests/text.test | 42 +++++++++++++++++++++--------------------- tests/textDisp.test | 20 ++++++++++---------- 5 files changed, 69 insertions(+), 69 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 15c6e73..9047911 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -689,16 +689,16 @@ TextWidgetObjCmd( static const char *optionStrings[] = { "bbox", "cget", "compare", "configure", "count", "debug", "delete", "dlineinfo", "dump", "edit", "get", "image", "index", "insert", - "mark", "peer", "pendingyupdate", "replace", "scan", "search", - "see", "tag", "window", "xview", "yupdate", "yview", NULL + "mark", "peer", "pendingsync", "replace", "scan", "search", + "see", "sync", "tag", "window", "xview", "yview", NULL }; enum options { TEXT_BBOX, TEXT_CGET, TEXT_COMPARE, TEXT_CONFIGURE, TEXT_COUNT, TEXT_DEBUG, TEXT_DELETE, TEXT_DLINEINFO, TEXT_DUMP, TEXT_EDIT, TEXT_GET, TEXT_IMAGE, TEXT_INDEX, TEXT_INSERT, TEXT_MARK, - TEXT_PEER, TEXT_PENDINGYUPDATE, TEXT_REPLACE, TEXT_SCAN, - TEXT_SEARCH, TEXT_SEE, TEXT_TAG, TEXT_WINDOW, TEXT_XVIEW, - TEXT_YUPDATE, TEXT_YVIEW + TEXT_PEER, TEXT_PENDINGSYNC, TEXT_REPLACE, TEXT_SCAN, + TEXT_SEARCH, TEXT_SEE, TEXT_SYNC, TEXT_TAG, TEXT_WINDOW, + TEXT_XVIEW, TEXT_YVIEW }; if (objc < 2) { @@ -1373,7 +1373,7 @@ TextWidgetObjCmd( case TEXT_PEER: result = TextPeerCmd(textPtr, interp, objc, objv); break; - case TEXT_PENDINGYUPDATE: { + case TEXT_PENDINGSYNC: { int number; if (objc != 2) { @@ -1381,7 +1381,7 @@ TextWidgetObjCmd( result = TCL_ERROR; goto done; } - number = TkTextPendingyupdate(textPtr); + number = TkTextPendingsync(textPtr); Tcl_SetObjResult(interp, Tcl_NewIntObj(number)); break; } @@ -1507,26 +1507,26 @@ TextWidgetObjCmd( case TEXT_XVIEW: result = TkTextXviewCmd(textPtr, interp, objc, objv); break; - case TEXT_YUPDATE: { + case TEXT_SYNC: { if (objc == 4) { - Tcl_Obj *cmd = objv[3]; - const char *option = Tcl_GetString(objv[2]); - if (strncmp(option, "-command", objv[2]->length)) { - Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL); - result = TCL_ERROR; - goto done; - } - Tcl_IncrRefCount(cmd); - if (TkTextPendingyupdate(textPtr)) { - if (textPtr->afterSyncCmd) { - Tcl_DecrRefCount(textPtr->afterSyncCmd); - } - textPtr->afterSyncCmd = cmd; - } else { - result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); - Tcl_DecrRefCount(cmd); + Tcl_Obj *cmd = objv[3]; + const char *option = Tcl_GetString(objv[2]); + if (strncmp(option, "-command", objv[2]->length)) { + Tcl_AppendResult(interp, "wrong option \"", option, "\": should be \"-command\"", NULL); + result = TCL_ERROR; + goto done; + } + Tcl_IncrRefCount(cmd); + if (TkTextPendingsync(textPtr)) { + if (textPtr->afterSyncCmd) { + Tcl_DecrRefCount(textPtr->afterSyncCmd); } - break; + textPtr->afterSyncCmd = cmd; + } else { + result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmd); + } + break; } else if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); result = TCL_ERROR; diff --git a/generic/tkText.h b/generic/tkText.h index 2aa8d59..1c4be68 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -1125,7 +1125,7 @@ MODULE_SCOPE int TkTextMarkNameToIndex(TkText *textPtr, MODULE_SCOPE void TkTextMarkSegToIndex(TkText *textPtr, TkTextSegment *markPtr, TkTextIndex *indexPtr); MODULE_SCOPE void TkTextEventuallyRepick(TkText *textPtr); -MODULE_SCOPE int TkTextPendingyupdate(TkText *textPtr); +MODULE_SCOPE int TkTextPendingsync(TkText *textPtr); MODULE_SCOPE void TkTextPickCurrent(TkText *textPtr, XEvent *eventPtr); MODULE_SCOPE void TkTextPixelIndex(TkText *textPtr, int x, int y, TkTextIndex *indexPtr, int *nearest); diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index a8a8f85..3cee288 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -590,7 +590,7 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp, Tcl_Obj *CONST objv[], double *dblPtr, int *intPtr); static void AsyncUpdateLineMetrics(ClientData clientData); -static void GenerateTextLineHeightsInvalidEvent(TkText *textPtr); +static void GenerateWidgetViewSyncEvent(TkText *textPtr); static void AsyncUpdateYScrollbar(ClientData clientData); static int IsStartOfNotMergedLine(TkText *textPtr, CONST TkTextIndex *indexPtr); @@ -2930,7 +2930,7 @@ AsyncUpdateLineMetrics( LOG("tk_textInvalidateLine", buffer); } - GenerateTextLineHeightsInvalidEvent(textPtr); + GenerateWidgetViewSyncEvent(textPtr); /* * If we're not in the middle of a long-line calculation (metricEpoch==-1) @@ -2942,7 +2942,7 @@ AsyncUpdateLineMetrics( /* * We have looped over all lines, so we're done. We must release our * refCount on the widget (the timer token was already set to NULL - * above). If there is a registered command, run that first. + * above). If there is a registered aftersync command, run that first. */ if (textPtr->afterSyncCmd != NULL) { @@ -2951,7 +2951,7 @@ AsyncUpdateLineMetrics( code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); if (code != TCL_OK && code != TCL_CONTINUE && code != TCL_BREAK) { - Tcl_AddErrorInfo(textPtr->interp, "\n (text yupdate)"); + Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); Tcl_BackgroundError(textPtr->interp); } Tcl_Release((ClientData)textPtr->interp); @@ -2978,12 +2978,12 @@ AsyncUpdateLineMetrics( /* *---------------------------------------------------------------------- * - * GenerateTextLineHeightsInvalidEvent -- + * GenerateWidgetViewSyncEvent -- * - * Send the <> event related to the text widget + * Send the <> event related to the text widget * line metrics asynchronous update. * This is equivalent to: - * event generate $textWidget <> -detail $N + * event generate $textWidget <> -detail $N * where $N is the number of lines for which the height is outdated. * * Results: @@ -2996,7 +2996,7 @@ AsyncUpdateLineMetrics( */ static void -GenerateTextLineHeightsInvalidEvent( +GenerateWidgetViewSyncEvent( TkText *textPtr) /* Information about text widget. */ { union {XEvent general; XVirtualEvent virtual;} event; @@ -3007,8 +3007,8 @@ GenerateTextLineHeightsInvalidEvent( event.general.xany.send_event = False; event.general.xany.window = Tk_WindowId(textPtr->tkwin); event.general.xany.display = Tk_Display(textPtr->tkwin); - event.virtual.name = Tk_GetUid("TextLineHeightsInvalid"); - event.virtual.user_data = Tcl_NewIntObj(TkTextPendingyupdate(textPtr)); + event.virtual.name = Tk_GetUid("WidgetViewSync"); + event.virtual.user_data = Tcl_NewIntObj(TkTextPendingsync(textPtr)); Tk_HandleEvent(&event.general); } @@ -6089,7 +6089,7 @@ TkTextYviewCmd( /* *-------------------------------------------------------------- * - * TkTextPendingyupdate -- + * TkTextPendingsync -- * * This function computes how many lines are not up-to-date regarding * asynchronous height calculations. @@ -6105,7 +6105,7 @@ TkTextYviewCmd( */ int -TkTextPendingyupdate( +TkTextPendingsync( TkText *textPtr) /* Information about text widget. */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; diff --git a/tests/text.test b/tests/text.test index 7e754e2..3532546 100644 --- a/tests/text.test +++ b/tests/text.test @@ -153,7 +153,7 @@ test text-3.1 {TextWidgetCmd procedure, basics} { } {1 {wrong # args: should be ".t option ?arg arg ...?"}} test text-3.2 {TextWidgetCmd procedure} { list [catch {.t gorp 1.0 z 1.2} msg] $msg -} {1 {bad option "gorp": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {bad option "gorp": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingsync, replace, scan, search, see, sync, tag, window, xview, or yview}} test text-4.1 {TextWidgetCmd procedure, "bbox" option} { list [catch {.t bbox} msg] $msg @@ -221,7 +221,7 @@ test text-6.13 {TextWidgetCmd procedure, "compare" option} { } {1 {bad comparison operator "z": must be <, <=, ==, >=, >, or !=}} test text-6.14 {TextWidgetCmd procedure, "compare" option} { list [catch {.t co 1.0 z 1.2} msg] $msg -} {1 {ambiguous option "co": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {ambiguous option "co": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingsync, replace, scan, search, see, sync, tag, window, xview, or yview}} # "configure" option is already covered above @@ -230,7 +230,7 @@ test text-7.1 {TextWidgetCmd procedure, "debug" option} { } {1 {wrong # args: should be ".t debug boolean"}} test text-7.2 {TextWidgetCmd procedure, "debug" option} { list [catch {.t de 0 1} msg] $msg -} {1 {ambiguous option "de": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {ambiguous option "de": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingsync, replace, scan, search, see, sync, tag, window, xview, or yview}} test text-7.3 {TextWidgetCmd procedure, "debug" option} { .t debug true .t deb @@ -901,7 +901,7 @@ test text-10.2 {TextWidgetCmd procedure, "index" option} { } {1 {wrong # args: should be ".t index index"}} test text-10.3 {TextWidgetCmd procedure, "index" option} { list [catch {.t in a b} msg] $msg -} {1 {ambiguous option "in": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingyupdate, replace, scan, search, see, tag, window, xview, yupdate, or yview}} +} {1 {ambiguous option "in": must be bbox, cget, compare, configure, count, debug, delete, dlineinfo, dump, edit, get, image, index, insert, mark, peer, pendingsync, replace, scan, search, see, sync, tag, window, xview, or yview}} test text-10.4 {TextWidgetCmd procedure, "index" option} { list [catch {.t index @xyz} msg] $msg } {1 {bad text index "@xyz"}} @@ -960,12 +960,12 @@ test text-11.10 {TextWidgetCmd procedure, "insert" option} { list [.t get 1.0 1.end] [.t tag ranges bold] [.t tag ranges silly] } {{First second} {1.0 1.5} {1.5 1.12}} -test text-11a.1 {TextWidgetCmd procedure, "yupdate" option} { +test text-11a.1 {TextWidgetCmd procedure, "sync" option} { destroy .yt text .yt - list [catch {.yt yupdate mytext} msg] $msg -} {1 {wrong # args: should be ".yt yupdate"}} -test text-11a.2 {TextWidgetCmd procedure, "yupdate" option} { + list [catch {.yt sync mytext} msg] $msg +} {1 {wrong # args: should be ".yt sync ?-command command?"}} +test text-11a.2 {TextWidgetCmd procedure, "sync" option} { destroy .top.yt .top toplevel .top pack [text .top.yt] @@ -976,7 +976,7 @@ test text-11a.2 {TextWidgetCmd procedure, "yupdate" option} { .top.yt insert 1.0 $content # wait for end of line metrics calculation to get correct $fraction1 # as a reference - .top.yt yupdate + .top.yt sync .top.yt yview moveto 1 set fraction1 [lindex [.top.yt yview] 0] set res [expr {$fraction1 > 0}] @@ -989,17 +989,17 @@ test text-11a.2 {TextWidgetCmd procedure, "yupdate" option} { # second case: wait for completion of line metrics calculation .top.yt delete 1.0 end .top.yt insert 1.0 $content - .top.yt yupdate + .top.yt sync .top.yt yview moveto $fraction1 set fraction2 [lindex [.top.yt yview] 0] lappend res [expr {$fraction1 == $fraction2}] } {1 0 1} -test text-11a.11 {TextWidgetCmd procedure, "pendingyupdate" option} { +test text-11a.11 {TextWidgetCmd procedure, "pendingsync" option} { destroy .yt text .yt - list [catch {.yt pendingyupdate mytext} msg] $msg -} {1 {wrong # args: should be ".yt pendingyupdate"}} -test text-11a.12 {TextWidgetCmd procedure, "pendingyupdate" option} { + list [catch {.yt pendingsync mytext} msg] $msg +} {1 {wrong # args: should be ".yt pendingsync"}} +test text-11a.12 {TextWidgetCmd procedure, "pendingsync" option} { destroy .top.yt .top toplevel .top pack [text .top.yt] @@ -1011,21 +1011,21 @@ test text-11a.12 {TextWidgetCmd procedure, "pendingyupdate" option} { update # wait for end of line metrics calculation to get correct $fraction1 # as a reference - while {[.top.yt pendingyupdate]} {update} + while {[.top.yt pendingsync]} {update} .top.yt yview moveto 1 set fraction1 [lindex [.top.yt yview] 0] set res [expr {$fraction1 > 0}] .top.yt delete 1.0 end .top.yt insert 1.0 $content # ensure the test is relevant - lappend res [expr {[.top.yt pendingyupdate] > 0}] + lappend res [expr {[.top.yt pendingsync] > 0}] # asynchronously wait for completion of line metrics calculation - while {[.top.yt pendingyupdate]} {update} + while {[.top.yt pendingsync]} {update} .top.yt yview moveto $fraction1 set fraction2 [lindex [.top.yt yview] 0] lappend res [expr {$fraction1 == $fraction2}] } {1 1 1} -test text-11a.21 {"<>" event} { +test text-11a.21 {"<>" event} { destroy .top.yt .top toplevel .top pack [text .top.yt] @@ -1035,10 +1035,10 @@ test text-11a.21 {"<>" event} { } .top.yt insert 1.0 $content update - bind .top.yt <> { if {%d == 0} {set yud(%W) 1} } + bind .top.yt <> { if {%d == 0} {set yud(%W) 1} } # wait for end of line metrics calculation to get correct $fraction1 # as a reference - if {[.top.yt pendingyupdate]} {vwait yud(.top.yt)} + if {[.top.yt pendingsync]} {vwait yud(.top.yt)} .top.yt yview moveto 1 set fraction1 [lindex [.top.yt yview] 0] set res [expr {$fraction1 > 0}] @@ -1047,7 +1047,7 @@ test text-11a.21 {"<>" event} { # synchronously wait for completion of line metrics calculation # and ensure the test is relevant set waited 0 - if {[.top.yt pendingyupdate]} {set waited 1 ; vwait yud(.top.yt)} + if {[.top.yt pendingsync]} {set waited 1 ; vwait yud(.top.yt)} lappend res $waited .top.yt yview moveto $fraction1 set fraction2 [lindex [.top.yt yview] 0] diff --git a/tests/textDisp.test b/tests/textDisp.test index 133fcf5..80bdb9d 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -4175,9 +4175,9 @@ test textDisp-34.1 {Line heights recalculation problem: bug 2677890} -setup { set ge [winfo geometry .] scan $ge "%dx%d+%d+%d" width height left top update - .t1 yupdate + .t1 sync set negative 0 - bind .t1 <> { if {%d < 0} {set negative 1} } + bind .t1 <> { if {%d < 0} {set negative 1} } # Without the fix for bug 2677890, changing the width of the toplevel # will launch recomputation of the line heights, but will produce negative # number of still remaining outdated lines, which is obviously wrong. @@ -4185,33 +4185,33 @@ test textDisp-34.1 {Line heights recalculation problem: bug 2677890} -setup { # i.e. to check that the fix for this bug really is still in. wm geometry . "[expr {$width * 2}]x$height+$left+$top" update - .t1 yupdate + .t1 sync set negative } -cleanup { destroy .t1 } -result {0} -test textDisp-34.2 {text yupdate syntax} -body { +test textDisp-34.2 {text sync syntax} -body { } -body { pack [text .t1] -expand 1 -fill both - .t1 yupdate foo + .t1 sync foo } -cleanup { destroy .t1 -} -returnCodes 1 -result {wrong # args: should be ".t1 yupdate ?-command command?"} +} -returnCodes 1 -result {wrong # args: should be ".t1 sync ?-command command?"} -test textDisp-34.3 {text yupdate syntax} -body { +test textDisp-34.3 {text sync syntax} -body { } -body { pack [text .t1] -expand 1 -fill both - .t1 yupdate -comx foo + .t1 sync -comx foo } -cleanup { destroy .t1 } -returnCodes 1 -result {wrong option "-comx": should be "-command"} -test textDisp-34.4 {text yupdate syntax} -body { +test textDisp-34.4 {text sync syntax} -body { } -body { set ::x 0 pack [text .t1] -expand 1 -fill both - .t1 yupdate -comm [list set ::x 1] + .t1 sync -comm [list set ::x 1] set ::x } -cleanup { destroy .t1 -- cgit v0.12 From eb5d769a8ee796d5a2d9aabeae8803c7f45c7b4d Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 21 Nov 2015 08:43:25 +0000 Subject: Adjusted when <> fires. Also %d now only has boolean value. Implementation in sync with TIP #438 rev. 1.10 --- generic/tkTextDisp.c | 24 +++++++++++++++++------- tests/text.test | 2 +- 2 files changed, 18 insertions(+), 8 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 3cee288..d8a17a9 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -590,7 +590,7 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp, Tcl_Obj *CONST objv[], double *dblPtr, int *intPtr); static void AsyncUpdateLineMetrics(ClientData clientData); -static void GenerateWidgetViewSyncEvent(TkText *textPtr); +static void GenerateWidgetViewSyncEvent(TkText *textPtr, Bool InSync); static void AsyncUpdateYScrollbar(ClientData clientData); static int IsStartOfNotMergedLine(TkText *textPtr, CONST TkTextIndex *indexPtr); @@ -2930,8 +2930,6 @@ AsyncUpdateLineMetrics( LOG("tk_textInvalidateLine", buffer); } - GenerateWidgetViewSyncEvent(textPtr); - /* * If we're not in the middle of a long-line calculation (metricEpoch==-1) * and we've reached the last line, then we're done. @@ -2959,6 +2957,14 @@ AsyncUpdateLineMetrics( textPtr->afterSyncCmd = 0; } + /* + * Fire the <> event since the widget view is in sync + * with its internal data (actually it will be after the next trip + * through the event loop, because the widget redraws at idle-time). + */ + + GenerateWidgetViewSyncEvent(textPtr, 1); + textPtr->refCount--; if (textPtr->refCount == 0) { ckfree((char *) textPtr); @@ -2983,8 +2989,9 @@ AsyncUpdateLineMetrics( * Send the <> event related to the text widget * line metrics asynchronous update. * This is equivalent to: - * event generate $textWidget <> -detail $N - * where $N is the number of lines for which the height is outdated. + * event generate $textWidget <> -detail $s + * where $s is the sync status: true (when the widget view is in + * sync with its internal data) or false (when it is not). * * Results: * None @@ -2997,7 +3004,8 @@ AsyncUpdateLineMetrics( static void GenerateWidgetViewSyncEvent( - TkText *textPtr) /* Information about text widget. */ + TkText *textPtr, /* Information about text widget. */ + Bool InSync) /* True if in sync, false otherwise */ { union {XEvent general; XVirtualEvent virtual;} event; @@ -3008,7 +3016,7 @@ GenerateWidgetViewSyncEvent( event.general.xany.window = Tk_WindowId(textPtr->tkwin); event.general.xany.display = Tk_Display(textPtr->tkwin); event.virtual.name = Tk_GetUid("WidgetViewSync"); - event.virtual.user_data = Tcl_NewIntObj(TkTextPendingsync(textPtr)); + event.virtual.user_data = Tcl_NewBooleanObj(InSync); Tk_HandleEvent(&event.general); } @@ -3391,6 +3399,7 @@ TextInvalidateLineMetrics( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, (ClientData) textPtr); + GenerateWidgetViewSyncEvent(textPtr, 0); } } @@ -5095,6 +5104,7 @@ TkTextRelayoutWindow( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, (ClientData) textPtr); + GenerateWidgetViewSyncEvent(textPtr, 0); } } } diff --git a/tests/text.test b/tests/text.test index 3532546..3ba85b7 100644 --- a/tests/text.test +++ b/tests/text.test @@ -1035,7 +1035,7 @@ test text-11a.21 {"<>" event} { } .top.yt insert 1.0 $content update - bind .top.yt <> { if {%d == 0} {set yud(%W) 1} } + bind .top.yt <> { if {%d} {set yud(%W) 1} } # wait for end of line metrics calculation to get correct $fraction1 # as a reference if {[.top.yt pendingsync]} {vwait yud(.top.yt)} -- cgit v0.12 From a98909d33d6264a4225d36d44e33c1117b790ca6 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 21 Nov 2015 09:08:52 +0000 Subject: Improved the tests a bit --- tests/text.test | 55 +++++++++++++++++++++++++++++++++++++++++++---------- tests/textDisp.test | 26 ------------------------- 2 files changed, 45 insertions(+), 36 deletions(-) diff --git a/tests/text.test b/tests/text.test index 3ba85b7..563f61b 100644 --- a/tests/text.test +++ b/tests/text.test @@ -960,13 +960,25 @@ test text-11.10 {TextWidgetCmd procedure, "insert" option} { list [.t get 1.0 1.end] [.t tag ranges bold] [.t tag ranges silly] } {{First second} {1.0 1.5} {1.5 1.12}} -test text-11a.1 {TextWidgetCmd procedure, "sync" option} { +test text-11a.1 {TextWidgetCmd procedure, "sync" option} -setup { destroy .yt +} -body { text .yt list [catch {.yt sync mytext} msg] $msg -} {1 {wrong # args: should be ".yt sync ?-command command?"}} -test text-11a.2 {TextWidgetCmd procedure, "sync" option} { +} -cleanup { + destroy .yt +} -result {1 {wrong # args: should be ".yt sync ?-command command?"}} +test text-11a.2 {TextWidgetCmd procedure, "sync" option with -command} -setup { + destroy .yt +} -body { + text .yt + list [catch {.yt sync -comx foo} msg] $msg +} -cleanup { + destroy .yt +} -result {1 {wrong option "-comx": should be "-command"}} +test text-11a.3 {TextWidgetCmd procedure, "sync" option} -setup { destroy .top.yt .top +} -body { toplevel .top pack [text .top.yt] set content {} @@ -993,14 +1005,31 @@ test text-11a.2 {TextWidgetCmd procedure, "sync" option} { .top.yt yview moveto $fraction1 set fraction2 [lindex [.top.yt yview] 0] lappend res [expr {$fraction1 == $fraction2}] -} {1 0 1} -test text-11a.11 {TextWidgetCmd procedure, "pendingsync" option} { +} -cleanup { + destroy .top.yt .top +} -result {1 0 1} +test text-11a.4 {TextWidgetCmd procedure, "sync" option with -command} -setup { + destroy .yt +} -body { + set ::x 0 + pack [text .yt] -expand 1 -fill both + .yt sync -command [list set ::x 1] + set ::x +} -cleanup { + destroy .yt +} -result {1} + +test text-11a.11 {TextWidgetCmd procedure, "pendingsync" option} -setup { destroy .yt +} -body { text .yt list [catch {.yt pendingsync mytext} msg] $msg -} {1 {wrong # args: should be ".yt pendingsync"}} -test text-11a.12 {TextWidgetCmd procedure, "pendingsync" option} { +} -cleanup { + destroy .yt +} -result {1 {wrong # args: should be ".yt pendingsync"}} +test text-11a.12 {TextWidgetCmd procedure, "pendingsync" option} -setup { destroy .top.yt .top +} -body { toplevel .top pack [text .top.yt] set content {} @@ -1024,9 +1053,13 @@ test text-11a.12 {TextWidgetCmd procedure, "pendingsync" option} { .top.yt yview moveto $fraction1 set fraction2 [lindex [.top.yt yview] 0] lappend res [expr {$fraction1 == $fraction2}] -} {1 1 1} -test text-11a.21 {"<>" event} { +} -cleanup { + destroy .top.yt .top +} -result {1 1 1} + +test text-11a.21 {"<>" event} -setup { destroy .top.yt .top +} -body { toplevel .top pack [text .top.yt] set content {} @@ -1052,7 +1085,9 @@ test text-11a.21 {"<>" event} { .top.yt yview moveto $fraction1 set fraction2 [lindex [.top.yt yview] 0] lappend res [expr {$fraction1 == $fraction2}] -} {1 1 1} +} -cleanup { + destroy .top.yt .top +} -result {1 1 1} # edit, mark, scan, search, see, tag, window, xview and yview actions are tested elsewhere. diff --git a/tests/textDisp.test b/tests/textDisp.test index 80bdb9d..c8264e6 100644 --- a/tests/textDisp.test +++ b/tests/textDisp.test @@ -4191,32 +4191,6 @@ test textDisp-34.1 {Line heights recalculation problem: bug 2677890} -setup { destroy .t1 } -result {0} -test textDisp-34.2 {text sync syntax} -body { -} -body { - pack [text .t1] -expand 1 -fill both - .t1 sync foo -} -cleanup { - destroy .t1 -} -returnCodes 1 -result {wrong # args: should be ".t1 sync ?-command command?"} - -test textDisp-34.3 {text sync syntax} -body { -} -body { - pack [text .t1] -expand 1 -fill both - .t1 sync -comx foo -} -cleanup { - destroy .t1 -} -returnCodes 1 -result {wrong option "-comx": should be "-command"} - -test textDisp-34.4 {text sync syntax} -body { -} -body { - set ::x 0 - pack [text .t1] -expand 1 -fill both - .t1 sync -comm [list set ::x 1] - set ::x -} -cleanup { - destroy .t1 -} -result {1} - deleteWindows option clear -- cgit v0.12 From 7230deb8239418e6270d55933673b70ef17d5ecf Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 21 Nov 2015 12:47:31 +0000 Subject: Respect alphabetical order --- generic/tkText.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 9047911..62de1af 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1498,15 +1498,6 @@ TextWidgetObjCmd( case TEXT_SEE: result = TkTextSeeCmd(textPtr, interp, objc, objv); break; - case TEXT_TAG: - result = TkTextTagCmd(textPtr, interp, objc, objv); - break; - case TEXT_WINDOW: - result = TkTextWindowCmd(textPtr, interp, objc, objv); - break; - case TEXT_XVIEW: - result = TkTextXviewCmd(textPtr, interp, objc, objv); - break; case TEXT_SYNC: { if (objc == 4) { Tcl_Obj *cmd = objv[3]; @@ -1540,6 +1531,15 @@ TextWidgetObjCmd( TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); break; } + case TEXT_TAG: + result = TkTextTagCmd(textPtr, interp, objc, objv); + break; + case TEXT_WINDOW: + result = TkTextWindowCmd(textPtr, interp, objc, objv); + break; + case TEXT_XVIEW: + result = TkTextXviewCmd(textPtr, interp, objc, objv); + break; case TEXT_YVIEW: result = TkTextYviewCmd(textPtr, interp, objc, objv); break; -- cgit v0.12 From c6fe822f77a06d384d16550f567d91ada8bdf8a6 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sun, 22 Nov 2015 20:11:32 +0000 Subject: Use the new sync command instead of the 'count -update' workaround --- tests/text.test | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/tests/text.test b/tests/text.test index 563f61b..dc44293 100644 --- a/tests/text.test +++ b/tests/text.test @@ -745,10 +745,7 @@ test text-9.2.47 {TextWidgetCmd procedure, "count" option} -setup { .t tag configure hidden -elide true .t tag add hidden 5.7 11.0 update - # next line to be fully sure that asynchronous line heights calculation is - # up-to-date otherwise this test may fail (depending on the computer - # performance), especially when the . toplevel has small height - .t count -update -ypixels 1.0 end + .t sync set y1 [lindex [.t yview] 1] .t count -displaylines 5.0 11.0 set y2 [lindex [.t yview] 1] -- cgit v0.12 From 343fa871d1921334fb7333133266a7d5633baa61 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 28 Nov 2015 19:45:01 +0000 Subject: [.text pendingsync] returns a boolean --- generic/tkText.c | 6 ++---- generic/tkText.h | 2 +- generic/tkTextDisp.c | 13 +++++++------ tests/text.test | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 62de1af..09e656f 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1374,15 +1374,13 @@ TextWidgetObjCmd( result = TextPeerCmd(textPtr, interp, objc, objv); break; case TEXT_PENDINGSYNC: { - int number; - if (objc != 2) { Tcl_WrongNumArgs(interp, 2, objv, NULL); result = TCL_ERROR; goto done; } - number = TkTextPendingsync(textPtr); - Tcl_SetObjResult(interp, Tcl_NewIntObj(number)); + Tcl_SetObjResult(interp, + Tcl_NewBooleanObj(TkTextPendingsync(textPtr))); break; } case TEXT_REPLACE: { diff --git a/generic/tkText.h b/generic/tkText.h index 1c4be68..49ee479 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -1125,7 +1125,7 @@ MODULE_SCOPE int TkTextMarkNameToIndex(TkText *textPtr, MODULE_SCOPE void TkTextMarkSegToIndex(TkText *textPtr, TkTextSegment *markPtr, TkTextIndex *indexPtr); MODULE_SCOPE void TkTextEventuallyRepick(TkText *textPtr); -MODULE_SCOPE int TkTextPendingsync(TkText *textPtr); +MODULE_SCOPE Bool TkTextPendingsync(TkText *textPtr); MODULE_SCOPE void TkTextPickCurrent(TkText *textPtr, XEvent *eventPtr); MODULE_SCOPE void TkTextPixelIndex(TkText *textPtr, int x, int y, TkTextIndex *indexPtr, int *nearest); diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index d8a17a9..d214fa7 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -6101,12 +6101,11 @@ TkTextYviewCmd( * * TkTextPendingsync -- * - * This function computes how many lines are not up-to-date regarding - * asynchronous height calculations. + * This function checks if any line heights are not up-to-date. * * Results: - * Returns a positive integer corresponding to the number of lines for - * which the height is outdated. + * Returns a boolean true if it is the case, or false if all line + * heights are up-to-date. * * Side effects: * None. @@ -6114,13 +6113,15 @@ TkTextYviewCmd( *-------------------------------------------------------------- */ -int +Bool TkTextPendingsync( TkText *textPtr) /* Information about text widget. */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - return (dInfoPtr->lastMetricUpdateLine - dInfoPtr->currentMetricUpdateLine); + return ( + (dInfoPtr->lastMetricUpdateLine - dInfoPtr->currentMetricUpdateLine) ? + 1 : 0); } /* diff --git a/tests/text.test b/tests/text.test index dc44293..89dd12c 100644 --- a/tests/text.test +++ b/tests/text.test @@ -1044,7 +1044,7 @@ test text-11a.12 {TextWidgetCmd procedure, "pendingsync" option} -setup { .top.yt delete 1.0 end .top.yt insert 1.0 $content # ensure the test is relevant - lappend res [expr {[.top.yt pendingsync] > 0}] + lappend res [.top.yt pendingsync] # asynchronously wait for completion of line metrics calculation while {[.top.yt pendingsync]} {update} .top.yt yview moveto $fraction1 -- cgit v0.12 From 1b232846d84e9f6789845731949006126ce046b4 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 28 Nov 2015 21:38:19 +0000 Subject: Text widget documentation updated according to TIP #438 --- doc/text.n | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 92 insertions(+), 1 deletion(-) diff --git a/doc/text.n b/doc/text.n index d2f0c82..f7cb143 100644 --- a/doc/text.n +++ b/doc/text.n @@ -1060,6 +1060,82 @@ affected. See below for the \fIpathName \fBpeer\fR widget command that controls the creation of peer widgets. .VE 8.5 +.SH "ASYNCHRONOUS UPDATE OF LINE HEIGHTS" +.PP +In order to maintain a responsive user-experience, the text widget calculates +lines metrics (line heights in pixels) asynchronously. Because of this, some +commands of the text widget may return wrong results if the asynchronous +calculations are not finished at the time of calling. This applies to +\fIpathName \fBcount -ypixels\fR and \fIpathName \fByview\fR. +.PP +Again for performance reasons, it would not be appropriate to let these +commands always wait for the end of the update calculation each time they are +called. In most use cases of these commands a more or less inaccurate result +does not really matter compared to execution speed. +.PP +In case accurate result is needed (and if the text widget is managed by a +geometry manager), one can resort to \fIpathName \fBsync\fR and \fIpathName +\fBpendingsync\fR to control the synchronization of the view of text widgets. +.PP +The \fB<>\fR virtual event fires when the line heights of the +text widget becomes obsolete (due to some editing command or configuration +change), and again when the internal data of the text widget are back in sync +with the widget view. The detail field (%d substitution) is either true (when +the widget is in sync) or false (when it is not). +.PP +\fIpathName \fBsync\fR, \fIpathName \fBpendingsync\fR and +\fB<>\fR apply to each text widget independently of its peers. +.PP +Examples of use: +.CS +## Example 1: +# runtime, immediately complete line metrics at any cost (GUI unresponsive) +$w sync +$w yview moveto $fraction + +## Example 2: +# runtime, synchronously wait for up-to-date line metrics (GUI responsive) +$w sync -command [list $w yview moveto $fraction] + +## Example 3: +# init +set yud($w) 0 +proc updateaction w { +\&set ::yud($w) 1 +\&# any other update action here... +} +# runtime, synchronously wait for up-to-date line metrics (GUI responsive) +$w sync -command [list updateaction $w] +vwait yud($w) +$w yview moveto $fraction + +## Example 4: +# init +set todo($w) {} +proc updateaction w { +\&foreach cmd $::todo($w) {uplevel #0 $cmd} +\&set todo($w) {} +} +# runtime +lappend todo($w) [list $w yview moveto $fraction] +$w sync -command [list updateaction $w] + +## Example 5: +# init +set todo($w) {} +bind $w <> { +\&if {%d} { +\&\&foreach cmd $todo(%W) {eval $cmd} +\&\&set todo(%W) {} +\&} +} +# runtime +if {![$w pendingsync]} { +\&$w yview moveto $fraction +} else { +\&lappend todo($w) [list $w yview moveto $fraction] +} +.CE .SH "WIDGET COMMAND" .PP The \fBtext\fR command creates a new Tcl command whose @@ -1132,7 +1208,9 @@ if the text widget is managed by a geometry manager), then all subsequent options ensure that any possible out of date information is recalculated. This currently only has any effect for the \fI\-ypixels\fR count (which, if \fB\-update\fR is not given, will use the text widget's current cached value -for each line). The count options are interpreted as follows: +for each line). This \fB\-update\fR option is obsoleted by \fIpathName +\fBsync\fR, \fIpathName \fBpendingsync\fR and \fB<>\fR. The +count options are interpreted as follows: .RS .IP \fB\-chars\fR count all characters, whether elided or not. Do not count @@ -1508,6 +1586,9 @@ Returns a list of peers of this widget (this does not include the widget itself). The order within this list is undefined. .RE .TP +\fIpathName \fBpendingsync\fR +Returns 1 if the line heights calculations are not up-to-date, 0 otherwise. +.TP \fIpathName \fBreplace\fR \fIindex1 index2 chars\fR ?\fItagList chars tagList ...\fR? Replaces the range of characters between \fIindex1\fR and \fIindex2\fR with the given characters and tags. See the section on \fIpathName @@ -1701,6 +1782,16 @@ edge of the window. If \fIindex\fR is far out of view, then the command centers \fIindex\fR in the window. .TP +\fIpathName \fBsync\fR ?\fB-command \fIcommand\fR? +Immediately brings the line metrics up-to-date by forcing computation of any +outdated line heights. The command returns immediately if there is no such +outdated line heights, otherwise it returns only at the end of the computation. +The command returns an empty string. If \fB-command \fIcommand\fR is specified, +schedule \fIcommand\fR to be executed exactly once as soon as all line +calculations are up-to-date. If there are no pending line metrics calculations, +\fIcommand\fR is executed immediately. \fIpathName \fBsync -command +\fIcommand\fR returns the return value of \fIcommand\fR. +.TP \fIpathName \fBtag \fIoption \fR?\fIarg arg ...\fR? This command is used to manipulate tags. The exact behavior of the command depends on the \fIoption\fR argument that follows the -- cgit v0.12 From 6073a4f2b76f804d103c87a1fe8e670cdd432b2b Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 28 Nov 2015 22:18:58 +0000 Subject: Fixed indentation --- generic/tkText.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 09e656f..a2b7dde 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -1510,19 +1510,19 @@ TextWidgetObjCmd( if (textPtr->afterSyncCmd) { Tcl_DecrRefCount(textPtr->afterSyncCmd); } - textPtr->afterSyncCmd = cmd; + textPtr->afterSyncCmd = cmd; } else { - result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); - Tcl_DecrRefCount(cmd); + result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); + Tcl_DecrRefCount(cmd); } - break; + break; } else if (objc != 2) { - Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); - result = TCL_ERROR; - goto done; + Tcl_WrongNumArgs(interp, 2, objv, "?-command command?"); + result = TCL_ERROR; + goto done; } if (textPtr->afterSyncCmd) { - Tcl_DecrRefCount(textPtr->afterSyncCmd); + Tcl_DecrRefCount(textPtr->afterSyncCmd); } textPtr->afterSyncCmd = NULL; TkTextUpdateLineMetrics(textPtr, 1, -- cgit v0.12 From 452517c0b7af4867700f545989c436dae97da21d Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 28 Nov 2015 22:35:18 +0000 Subject: Clearer separation between what [.text sync] and [.text sync -command] exactly perform --- doc/text.n | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/doc/text.n b/doc/text.n index f7cb143..1966882 100644 --- a/doc/text.n +++ b/doc/text.n @@ -1783,14 +1783,21 @@ If \fIindex\fR is far out of view, then the command centers \fIindex\fR in the window. .TP \fIpathName \fBsync\fR ?\fB-command \fIcommand\fR? +Control the synchronization of the view of text widget. +.RS +.TP +\fIpathName \fBsync\fR Immediately brings the line metrics up-to-date by forcing computation of any outdated line heights. The command returns immediately if there is no such outdated line heights, otherwise it returns only at the end of the computation. -The command returns an empty string. If \fB-command \fIcommand\fR is specified, -schedule \fIcommand\fR to be executed exactly once as soon as all line -calculations are up-to-date. If there are no pending line metrics calculations, -\fIcommand\fR is executed immediately. \fIpathName \fBsync -command -\fIcommand\fR returns the return value of \fIcommand\fR. +The command returns an empty string. +.TP +\fIpathName \fBsync -command \fIcommand\fR +Schedule \fIcommand\fR to be executed exactly once as soon as all line heights +are up-to-date. If there are no pending line metrics calculations, +\fIcommand\fR is executed immediately and the command returns the return value +of \fIcommand\fR. Otherwise the command returns an empty string. +.RE .TP \fIpathName \fBtag \fIoption \fR?\fIarg arg ...\fR? This command is used to manipulate tags. The exact behavior of the -- cgit v0.12 From 9ececb6eabce4f20485ba0f9a69cd069c456534e Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sun, 13 Dec 2015 20:58:26 +0000 Subject: Better (and more correct) description of what [.text sync -command $command] does --- doc/text.n | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/text.n b/doc/text.n index 1966882..c55b4cf 100644 --- a/doc/text.n +++ b/doc/text.n @@ -1794,9 +1794,9 @@ The command returns an empty string. .TP \fIpathName \fBsync -command \fIcommand\fR Schedule \fIcommand\fR to be executed exactly once as soon as all line heights -are up-to-date. If there are no pending line metrics calculations, -\fIcommand\fR is executed immediately and the command returns the return value -of \fIcommand\fR. Otherwise the command returns an empty string. +are up-to-date. If there are no pending line metrics calculations, the +scheduling is immediate. The command returns the empty string. \fBbgerror\fR is +called on \fIcommand\fR failure. .RE .TP \fIpathName \fBtag \fIoption \fR?\fIarg arg ...\fR? -- cgit v0.12 From 04d7a736ceccaf4d9cadfc0fb1513b99068a8bc9 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 19 Dec 2015 21:48:11 +0000 Subject: Tests reordered. Two issues currently: 1. text-11a.22 currently hangs but should pass once [.text sync -command $cmd] will be correctly implemented. 2. text-11a.41 fails (unsure why) --- tests/text.test | 118 ++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 80 insertions(+), 38 deletions(-) diff --git a/tests/text.test b/tests/text.test index 89dd12c..cdc14c0 100644 --- a/tests/text.test +++ b/tests/text.test @@ -957,23 +957,52 @@ test text-11.10 {TextWidgetCmd procedure, "insert" option} { list [.t get 1.0 1.end] [.t tag ranges bold] [.t tag ranges silly] } {{First second} {1.0 1.5} {1.5 1.12}} -test text-11a.1 {TextWidgetCmd procedure, "sync" option} -setup { +test text-11a.1 {TextWidgetCmd procedure, "pendingsync" option} -setup { destroy .yt } -body { text .yt - list [catch {.yt sync mytext} msg] $msg + list [catch {.yt pendingsync mytext} msg] $msg } -cleanup { destroy .yt -} -result {1 {wrong # args: should be ".yt sync ?-command command?"}} -test text-11a.2 {TextWidgetCmd procedure, "sync" option with -command} -setup { +} -result {1 {wrong # args: should be ".yt pendingsync"}} +test text-11a.2 {TextWidgetCmd procedure, "pendingsync" option} -setup { + destroy .top.yt .top +} -body { + toplevel .top + pack [text .top.yt] + set content {} + for {set i 1} {$i < 300} {incr i} { + append content [string repeat "$i " 15] \n + } + .top.yt insert 1.0 $content + # wait for end of line metrics calculation to get correct $fraction1 + # as a reference + while {[.top.yt pendingsync]} {update} + .top.yt yview moveto 1 + set fraction1 [lindex [.top.yt yview] 0] + set res [expr {$fraction1 > 0}] + .top.yt delete 1.0 end + .top.yt insert 1.0 $content + # ensure the test is relevant + lappend res [.top.yt pendingsync] + # asynchronously wait for completion of line metrics calculation + while {[.top.yt pendingsync]} {update} + .top.yt yview moveto $fraction1 + set fraction2 [lindex [.top.yt yview] 0] + lappend res [expr {$fraction1 == $fraction2}] +} -cleanup { + destroy .top.yt .top +} -result {1 1 1} + +test text-11a.11 {TextWidgetCmd procedure, "sync" option} -setup { destroy .yt } -body { text .yt - list [catch {.yt sync -comx foo} msg] $msg + list [catch {.yt sync mytext} msg] $msg } -cleanup { destroy .yt -} -result {1 {wrong option "-comx": should be "-command"}} -test text-11a.3 {TextWidgetCmd procedure, "sync" option} -setup { +} -result {1 {wrong # args: should be ".yt sync ?-command command?"}} +test text-11a.12 {TextWidgetCmd procedure, "sync" option} -setup { destroy .top.yt .top } -body { toplevel .top @@ -1005,56 +1034,44 @@ test text-11a.3 {TextWidgetCmd procedure, "sync" option} -setup { } -cleanup { destroy .top.yt .top } -result {1 0 1} -test text-11a.4 {TextWidgetCmd procedure, "sync" option with -command} -setup { - destroy .yt -} -body { - set ::x 0 - pack [text .yt] -expand 1 -fill both - .yt sync -command [list set ::x 1] - set ::x -} -cleanup { - destroy .yt -} -result {1} -test text-11a.11 {TextWidgetCmd procedure, "pendingsync" option} -setup { +test text-11a.21 {TextWidgetCmd procedure, "sync" option with -command} -setup { destroy .yt } -body { text .yt - list [catch {.yt pendingsync mytext} msg] $msg + list [catch {.yt sync -comx foo} msg] $msg } -cleanup { destroy .yt -} -result {1 {wrong # args: should be ".yt pendingsync"}} -test text-11a.12 {TextWidgetCmd procedure, "pendingsync" option} -setup { +} -result {1 {wrong option "-comx": should be "-command"}} +test text-11a.22 {TextWidgetCmd procedure, "sync" option with -command} -setup { destroy .top.yt .top } -body { + set res {} + set ::x 0 toplevel .top pack [text .top.yt] set content {} - for {set i 1} {$i < 300} {incr i} { + for {set i 1} {$i < 30} {incr i} { append content [string repeat "$i " 15] \n } .top.yt insert 1.0 $content - update - # wait for end of line metrics calculation to get correct $fraction1 - # as a reference - while {[.top.yt pendingsync]} {update} - .top.yt yview moveto 1 - set fraction1 [lindex [.top.yt yview] 0] - set res [expr {$fraction1 > 0}] - .top.yt delete 1.0 end - .top.yt insert 1.0 $content - # ensure the test is relevant + # first case: line metrics calculation still running when launching 'sync -command' lappend res [.top.yt pendingsync] - # asynchronously wait for completion of line metrics calculation + .top.yt sync -command [list set ::x 1] + lappend res $::x + # now finish line metrics calculations while {[.top.yt pendingsync]} {update} - .top.yt yview moveto $fraction1 - set fraction2 [lindex [.top.yt yview] 0] - lappend res [expr {$fraction1 == $fraction2}] + lappend res [.top.yt pendingsync] $::x + # second case: line metrics calculation completed when launching 'sync -command' + .top.yt sync -command [list set ::x 2] + lappend res $::x + vwait ::x + lappend res $::x } -cleanup { destroy .top.yt .top -} -result {1 1 1} +} -result {1 0 0 1 1 2} -test text-11a.21 {"<>" event} -setup { +test text-11a.31 {"<>" event} -setup { destroy .top.yt .top } -body { toplevel .top @@ -1086,6 +1103,31 @@ test text-11a.21 {"<>" event} -setup { destroy .top.yt .top } -result {1 1 1} +test text-11a.41 {"sync" "pendingsync" and <>} -setup { + destroy .top.yt .top +} -body { + set res {} + toplevel .top + pack [text .top.yt] + set content {} + for {set i 1} {$i < 300} {incr i} { + append content [string repeat "$i " 50] \n + } + bind .top.yt <> {lappend res Sync:%d} + .top.yt insert 1.0 $content + update + # ensure the test is relevant + lappend res [.top.yt pendingsync] + # - there is no more any pending sync after running 'sync' + # - <> fires when sync returns if there was pending syncs + .top.yt sync + lappend res [.top.yt pendingsync] + update + set res +} -cleanup { + destroy .top.yt .top +} -result {Sync:0 1 0 Sync:1} + # edit, mark, scan, search, see, tag, window, xview and yview actions are tested elsewhere. test text-12.1 {ConfigureText procedure} { -- cgit v0.12 From b94a6f1916a20ef6e8f2f67358b41ce290868a49 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sun, 20 Dec 2015 22:09:14 +0000 Subject: There could be false negatives with [.text pendingsync] when line metrics calculation is in the middle of a long line. --- generic/tkTextDisp.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 108cc4a..ba584ac 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -6144,8 +6144,9 @@ TkTextPendingsync( TextDInfo *dInfoPtr = textPtr->dInfoPtr; return ( - (dInfoPtr->lastMetricUpdateLine - dInfoPtr->currentMetricUpdateLine) ? - 1 : 0); + ((dInfoPtr->metricEpoch == -1) && + (dInfoPtr->lastMetricUpdateLine == dInfoPtr->currentMetricUpdateLine)) ? + 0 : 1); } /* -- cgit v0.12 From 13e6e328a24accea9268da09323fbaf15ff3c6ef Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sun, 20 Dec 2015 22:16:36 +0000 Subject: Test text-11a.41 now correctly written passes. --- tests/text.test | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/text.test b/tests/text.test index cdc14c0..2487df7 100644 --- a/tests/text.test +++ b/tests/text.test @@ -1115,18 +1115,18 @@ test text-11a.41 {"sync" "pendingsync" and <>} -setup { } bind .top.yt <> {lappend res Sync:%d} .top.yt insert 1.0 $content - update + vwait res ; # event dealt with by the event loop, with %d==0 i.e. we're out of sync # ensure the test is relevant - lappend res [.top.yt pendingsync] - # - there is no more any pending sync after running 'sync' + lappend res "Pending:[.top.yt pendingsync]" # - <> fires when sync returns if there was pending syncs + # - there is no more any pending sync after running 'sync' .top.yt sync - lappend res [.top.yt pendingsync] - update + vwait res ; # event dealt with by the event loop, with %d==1 i.e. we're in sync again + lappend res "Pending:[.top.yt pendingsync]" set res } -cleanup { destroy .top.yt .top -} -result {Sync:0 1 0 Sync:1} +} -result {Sync:0 Pending:1 Sync:1 Pending:0} # edit, mark, scan, search, see, tag, window, xview and yview actions are tested elsewhere. -- cgit v0.12 From 4eae3eafd8ade1f7d8ae787a253357f793333e70 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Sat, 26 Dec 2015 20:52:21 +0000 Subject: [.text sync -command $cmd] schedules execution of $cmd by the event loop at idle time --- generic/tkText.c | 51 +++++++++++++++++++++++++++++++++++++++++++++++++-- generic/tkText.h | 3 ++- generic/tkTextDisp.c | 22 +++++++++++----------- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index a2b7dde..0cb8431 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -397,6 +397,7 @@ static int TextSearchIndexInLine(const SearchSpec *searchSpecPtr, static int TextPeerCmd(TkText *textPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static TkUndoProc TextUndoRedoCallback; +static void RunAfterSyncCmd(ClientData clientData); /* * Declarations of the three search procs required by the multi-line search @@ -1512,8 +1513,8 @@ TextWidgetObjCmd( } textPtr->afterSyncCmd = cmd; } else { - result = Tcl_EvalObjEx(interp, cmd, TCL_EVAL_GLOBAL); - Tcl_DecrRefCount(cmd); + textPtr->afterSyncCmd = cmd; + Tcl_DoWhenIdle(RunAfterSyncCmd, (ClientData) textPtr); } break; } else if (objc != 2) { @@ -6747,6 +6748,52 @@ TkpTesttextCmd( } /* + *---------------------------------------------------------------------- + * + * RunAfterSyncCmd -- + * + * This function is called by the event loop and excutes the command + * scheduled by [.text sync -command $cmd]. + * + * Results: + * None. + * + * Side effects: + * Anything may happen, depending on $cmd contents. + * + *---------------------------------------------------------------------- + */ + +static void +RunAfterSyncCmd( + ClientData clientData) /* Information about text widget. */ +{ + register TkText *textPtr = (TkText *) clientData; + int code; + + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + /* + * The widget has been deleted. Don't do anything. + */ + + if (--textPtr->refCount == 0) { + ckfree((char *) textPtr); + } + return; + } + + Tcl_Preserve((ClientData) textPtr->interp); + code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); + if (code == TCL_ERROR) { + Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); + Tcl_BackgroundError(textPtr->interp); + } + Tcl_Release((ClientData) textPtr->interp); + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = NULL; +} + +/* * Local Variables: * mode: c * c-basic-offset: 4 diff --git a/generic/tkText.h b/generic/tkText.h index 49ee479..ea8ce07 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -782,7 +782,8 @@ typedef struct TkText { * statements. */ int autoSeparators; /* Non-zero means the separators will be * inserted automatically. */ - Tcl_Obj *afterSyncCmd; /* Command to be executed when lines are up to date */ + Tcl_Obj *afterSyncCmd; /* Command to be executed when lines are up to + * date */ } TkText; /* diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index ba584ac..39311a6 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -2958,18 +2958,18 @@ AsyncUpdateLineMetrics( * above). If there is a registered aftersync command, run that first. */ - if (textPtr->afterSyncCmd != NULL) { - int code; - Tcl_Preserve((ClientData)textPtr->interp); - code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); - if (code != TCL_OK && code != TCL_CONTINUE - && code != TCL_BREAK) { - Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); - Tcl_BackgroundError(textPtr->interp); + if (textPtr->afterSyncCmd) { + int code; + Tcl_Preserve((ClientData) textPtr->interp); + code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, + TCL_EVAL_GLOBAL); + if (code == TCL_ERROR) { + Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); + Tcl_BackgroundError(textPtr->interp); } - Tcl_Release((ClientData)textPtr->interp); - Tcl_DecrRefCount(textPtr->afterSyncCmd); - textPtr->afterSyncCmd = 0; + Tcl_Release((ClientData) textPtr->interp); + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = NULL; } /* -- cgit v0.12 From 9898632deaee50e7276c5e8e28cb20acc8824cd3 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Tue, 5 Jan 2016 16:12:39 +0000 Subject: Typo fixed in comment --- generic/tkText.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/generic/tkText.c b/generic/tkText.c index 0cb8431..c12c9a5 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -6752,7 +6752,7 @@ TkpTesttextCmd( * * RunAfterSyncCmd -- * - * This function is called by the event loop and excutes the command + * This function is called by the event loop and executes the command * scheduled by [.text sync -command $cmd]. * * Results: -- cgit v0.12 From 12dc2c5815c5d0ae8b4f4626ba98b0edda3fc60d Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Tue, 5 Jan 2016 16:25:50 +0000 Subject: Moved RunAfterSyncCmd procedure --- generic/tkText.c | 94 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 47 insertions(+), 47 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index c12c9a5..3389733 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -388,6 +388,7 @@ static Tcl_Obj * TextGetText(const TkText *textPtr, const TkTextIndex *index2, int visibleOnly); static void GenerateModifiedEvent(TkText *textPtr); static void UpdateDirtyFlag(TkSharedText *sharedPtr); +static void RunAfterSyncCmd(ClientData clientData); static void TextPushUndoAction(TkText *textPtr, Tcl_Obj *undoString, int insert, const TkTextIndex *index1Ptr, @@ -397,7 +398,6 @@ static int TextSearchIndexInLine(const SearchSpec *searchSpecPtr, static int TextPeerCmd(TkText *textPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); static TkUndoProc TextUndoRedoCallback; -static void RunAfterSyncCmd(ClientData clientData); /* * Declarations of the three search procs required by the multi-line search @@ -5377,6 +5377,52 @@ UpdateDirtyFlag( /* *---------------------------------------------------------------------- * + * RunAfterSyncCmd -- + * + * This function is called by the event loop and executes the command + * scheduled by [.text sync -command $cmd]. + * + * Results: + * None. + * + * Side effects: + * Anything may happen, depending on $cmd contents. + * + *---------------------------------------------------------------------- + */ + +static void +RunAfterSyncCmd( + ClientData clientData) /* Information about text widget. */ +{ + register TkText *textPtr = (TkText *) clientData; + int code; + + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { + /* + * The widget has been deleted. Don't do anything. + */ + + if (--textPtr->refCount == 0) { + ckfree((char *) textPtr); + } + return; + } + + Tcl_Preserve((ClientData) textPtr->interp); + code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); + if (code == TCL_ERROR) { + Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); + Tcl_BackgroundError(textPtr->interp); + } + Tcl_Release((ClientData) textPtr->interp); + Tcl_DecrRefCount(textPtr->afterSyncCmd); + textPtr->afterSyncCmd = NULL; +} + +/* + *---------------------------------------------------------------------- + * * SearchPerform -- * * Overall control of search process. Is given a pattern, a starting @@ -6748,52 +6794,6 @@ TkpTesttextCmd( } /* - *---------------------------------------------------------------------- - * - * RunAfterSyncCmd -- - * - * This function is called by the event loop and executes the command - * scheduled by [.text sync -command $cmd]. - * - * Results: - * None. - * - * Side effects: - * Anything may happen, depending on $cmd contents. - * - *---------------------------------------------------------------------- - */ - -static void -RunAfterSyncCmd( - ClientData clientData) /* Information about text widget. */ -{ - register TkText *textPtr = (TkText *) clientData; - int code; - - if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { - /* - * The widget has been deleted. Don't do anything. - */ - - if (--textPtr->refCount == 0) { - ckfree((char *) textPtr); - } - return; - } - - Tcl_Preserve((ClientData) textPtr->interp); - code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); - if (code == TCL_ERROR) { - Tcl_AddErrorInfo(textPtr->interp, "\n (text sync)"); - Tcl_BackgroundError(textPtr->interp); - } - Tcl_Release((ClientData) textPtr->interp); - Tcl_DecrRefCount(textPtr->afterSyncCmd); - textPtr->afterSyncCmd = NULL; -} - -/* * Local Variables: * mode: c * c-basic-offset: 4 -- cgit v0.12 From 6e1757de48dab079d8cf8cc4962e0639b755f4e4 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Tue, 5 Jan 2016 16:48:20 +0000 Subject: Polished documentation a bit --- doc/text.n | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/doc/text.n b/doc/text.n index c55b4cf..536a3a5 100644 --- a/doc/text.n +++ b/doc/text.n @@ -1089,12 +1089,13 @@ the widget is in sync) or false (when it is not). Examples of use: .CS ## Example 1: -# runtime, immediately complete line metrics at any cost (GUI unresponsive) +# immediately complete line metrics at any cost (GUI unresponsive) $w sync $w yview moveto $fraction ## Example 2: -# runtime, synchronously wait for up-to-date line metrics (GUI responsive) +# synchronously wait for up-to-date line metrics (GUI responsive) +# before executing the scheduled command, but don't block execution flow $w sync -command [list $w yview moveto $fraction] ## Example 3: @@ -1783,7 +1784,7 @@ If \fIindex\fR is far out of view, then the command centers \fIindex\fR in the window. .TP \fIpathName \fBsync\fR ?\fB-command \fIcommand\fR? -Control the synchronization of the view of text widget. +Controls the synchronization of the view of the text widget. .RS .TP \fIpathName \fBsync\fR @@ -1793,10 +1794,10 @@ outdated line heights, otherwise it returns only at the end of the computation. The command returns an empty string. .TP \fIpathName \fBsync -command \fIcommand\fR -Schedule \fIcommand\fR to be executed exactly once as soon as all line heights -are up-to-date. If there are no pending line metrics calculations, the -scheduling is immediate. The command returns the empty string. \fBbgerror\fR is -called on \fIcommand\fR failure. +Schedules \fIcommand\fR to be executed (by the event loop) exactly once as soon +as all line heights are up-to-date. If there are no pending line metrics +calculations, the scheduling is immediate. The command returns the empty +string. \fBbgerror\fR is called on \fIcommand\fR failure. .RE .TP \fIpathName \fBtag \fIoption \fR?\fIarg arg ...\fR? -- cgit v0.12 From 36242ad6ed63a032a19693cbbf7444f94a2ea035 Mon Sep 17 00:00:00 2001 From: "fvogelnew1@free.fr" Date: Tue, 5 Jan 2016 17:00:48 +0000 Subject: Harmonized use of NULL for textPtr->afterSyncCmd --- generic/tkText.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/generic/tkText.c b/generic/tkText.c index 3389733..8dbe13e 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -2015,9 +2015,9 @@ DestroyText( textPtr->tkwin = NULL; textPtr->refCount--; Tcl_DeleteCommandFromToken(textPtr->interp, textPtr->widgetCmd); - if (textPtr->afterSyncCmd != 0){ + if (textPtr->afterSyncCmd){ Tcl_DecrRefCount(textPtr->afterSyncCmd); - textPtr->afterSyncCmd = 0; + textPtr->afterSyncCmd = NULL; } if (textPtr->refCount == 0) { ckfree((char *) textPtr); -- cgit v0.12