From b965bde49f462725f54d29e9e8b8008f79fe43b9 Mon Sep 17 00:00:00 2001 From: fvogel 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 c3b96f601ce76e221a2dbd8fe8d747834c4a48ec Mon Sep 17 00:00:00 2001 From: fvogel 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 4fe451bdce628ec817ecdebadbcd7f46dc967b41 Mon Sep 17 00:00:00 2001 From: fvogel 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 8c6ac85de70a9f2ce13eecd5605fb55cfde6d911 Mon Sep 17 00:00:00 2001 From: fvogel 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 f0e7b98adcaa0890c60fdf84c8e9753f8f903a53 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" 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 d7e64d08df9fe0539c308b04f9a33201faa188f5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" 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 ae5a551ea90e295489c9b93879ddd911615e0536 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" 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 811bb84daa1769e2840edf52bdc5922d8370d930 Mon Sep 17 00:00:00 2001 From: fvogel 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 450aa9743dee157400ca5b3227922914f1c434a0 Mon Sep 17 00:00:00 2001 From: fvogel 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 a2432ecdb54d15171a3f5f403048743e09305ea5 Mon Sep 17 00:00:00 2001 From: "jan.nijtmans" 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 1238f724da65d098cb652af93972b4d0ac6e8f72 Mon Sep 17 00:00:00 2001 From: fvogel 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 6da3f989a4249675d97ecad8989d070f87966068 Mon Sep 17 00:00:00 2001 From: fvogel 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 b8c501de57829ea58d14a2f24841dec61241230a Mon Sep 17 00:00:00 2001 From: fvogel 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 258c36047d8f5dfd175a0b2cbaab37c1d0406cec Mon Sep 17 00:00:00 2001 From: fvogel 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 492a37c09443c512e4054acff1bd206ae5d4d501 Mon Sep 17 00:00:00 2001 From: fvogel 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 c7c6352112248f90539ef01a9d921745572b5d6b Mon Sep 17 00:00:00 2001 From: fvogel 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 8fd7d7784f01c76fd4cb02b9a66cc435194a8bc4 Mon Sep 17 00:00:00 2001 From: fvogel 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 bba041fbdedf7358083ff0f2cc618a4990696bd0 Mon Sep 17 00:00:00 2001 From: fvogel 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 ff45ebd61fc2390dcfe72e451ddc579fe1bca4bc Mon Sep 17 00:00:00 2001 From: fvogel 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 816ab6c14bd318a6918e1cb3cd97e1de92419e1a Mon Sep 17 00:00:00 2001 From: fvogel 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 801439653efba1124e5dc705bdcd018062719562 Mon Sep 17 00:00:00 2001 From: fvogel 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 f3e4c6787e4309d230f3d102105b2ebedf2d12ca Mon Sep 17 00:00:00 2001 From: fvogel 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 7fba872bef36903476be033836a8394fd742a1c0 Mon Sep 17 00:00:00 2001 From: fvogel 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 d429b10b89cba5a8dd80ca4eb3874dea424e5fb7 Mon Sep 17 00:00:00 2001 From: fvogel 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 e4067df1777998f73378f3a6e18f372a985bad0c Mon Sep 17 00:00:00 2001 From: fvogel 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 2e67237b8b1fa6815d9e318f28d2f50674bafde6 Mon Sep 17 00:00:00 2001 From: fvogel 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 5faa9a11695c74d40ca830ee4dcd68cfc9011e89 Mon Sep 17 00:00:00 2001 From: fvogel 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