diff options
Diffstat (limited to 'generic')
-rw-r--r-- | generic/tkText.c | 11 | ||||
-rw-r--r-- | generic/tkText.h | 4 | ||||
-rw-r--r-- | generic/tkTextDisp.c | 77 |
3 files changed, 64 insertions, 28 deletions
diff --git a/generic/tkText.c b/generic/tkText.c index 4c536a2..3d9977f 100644 --- a/generic/tkText.c +++ b/generic/tkText.c @@ -406,7 +406,6 @@ static Tcl_Obj * TextGetText(const TkText *textPtr, static void GenerateModifiedEvent(TkText *textPtr); static void GenerateUndoStackEvent(TkText *textPtr); static void UpdateDirtyFlag(TkSharedText *sharedPtr); -static void RunAfterSyncCmd(ClientData clientData); static void TextPushUndoAction(TkText *textPtr, Tcl_Obj *undoString, int insert, const TkTextIndex *index1Ptr, @@ -1547,7 +1546,7 @@ TextWidgetObjCmd( textPtr->afterSyncCmd = cmd; } else { textPtr->afterSyncCmd = cmd; - Tcl_DoWhenIdle(RunAfterSyncCmd, (ClientData) textPtr); + Tcl_DoWhenIdle(TkTextRunAfterSyncCmd, (ClientData) textPtr); } break; } else if (objc != 2) { @@ -1559,7 +1558,7 @@ TextWidgetObjCmd( Tcl_DecrRefCount(textPtr->afterSyncCmd); } textPtr->afterSyncCmd = NULL; - TkTextUpdateLineMetrics(textPtr, 1, + TkTextUpdateLineMetrics(textPtr, 0, TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr), -1); break; } @@ -5506,7 +5505,7 @@ UpdateDirtyFlag( /* *---------------------------------------------------------------------- * - * RunAfterSyncCmd -- + * TkTextRunAfterSyncCmd -- * * This function is called by the event loop and executes the command * scheduled by [.text sync -command $cmd]. @@ -5520,8 +5519,8 @@ UpdateDirtyFlag( *---------------------------------------------------------------------- */ -static void -RunAfterSyncCmd( +void +TkTextRunAfterSyncCmd( ClientData clientData) /* Information about text widget. */ { register TkText *textPtr = (TkText *) clientData; diff --git a/generic/tkText.h b/generic/tkText.h index 5d88784..4703703 100644 --- a/generic/tkText.h +++ b/generic/tkText.h @@ -1070,7 +1070,7 @@ MODULE_SCOPE int TkTextGetObjIndex(Tcl_Interp *interp, TkText *textPtr, MODULE_SCOPE int TkTextSharedGetObjIndex(Tcl_Interp *interp, TkSharedText *sharedTextPtr, Tcl_Obj *idxPtr, TkTextIndex *indexPtr); -MODULE_SCOPE const TkTextIndex *TkTextGetIndexFromObj(Tcl_Interp *interp, +MODULE_SCOPE const TkTextIndex *TkTextGetIndexFromObj(Tcl_Interp *interp, TkText *textPtr, Tcl_Obj *objPtr); MODULE_SCOPE TkTextTabArray *TkTextGetTabs(Tcl_Interp *interp, TkText *textPtr, Tcl_Obj *stringPtr); @@ -1159,7 +1159,7 @@ MODULE_SCOPE int TkTextYviewCmd(TkText *textPtr, Tcl_Interp *interp, int objc, Tcl_Obj *const objv[]); MODULE_SCOPE void TkTextWinFreeClient(Tcl_HashEntry *hPtr, TkTextEmbWindowClient *client); - +MODULE_SCOPE void TkTextRunAfterSyncCmd(ClientData clientData); #endif /* _TKTEXT */ /* diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 8d60754..5903dfb 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -497,13 +497,15 @@ static TkTextDispChunk *baseCharChunkPtr = NULL; * different character might be under the mouse * cursor now). Need to recompute the current * character before the next redisplay. + * OUT_OF_SYNC 1 means that the last <<WidgetViewSync>> event had + * value 0, indicating that the widget is out of sync. */ #define DINFO_OUT_OF_DATE 1 #define REDRAW_PENDING 2 #define REDRAW_BORDERS 4 #define REPICK_NEEDED 8 - +#define OUT_OF_SYNC 16 /* * Action values for FreeDLines: * @@ -681,7 +683,7 @@ TkTextCreateDInfo( dInfoPtr->scanTotalYScroll = 0; dInfoPtr->scanMarkY = 0; dInfoPtr->dLinesInvalidated = 0; - dInfoPtr->flags = DINFO_OUT_OF_DATE; + dInfoPtr->flags = 0; dInfoPtr->topPixelOffset = 0; dInfoPtr->newTopPixelOffset = 0; dInfoPtr->currentMetricUpdateLine = -1; @@ -3070,10 +3072,13 @@ 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 aftersync command, run that first. + * Cancel any pending idle task which would try to run the command + * after the afterSyncCmd pointer had been set to NULL. */ if (textPtr->afterSyncCmd) { int code; + Tcl_CancelIdleCall(TkTextRunAfterSyncCmd, textPtr); Tcl_Preserve((ClientData) textPtr->interp); code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL); @@ -3091,7 +3096,6 @@ AsyncUpdateLineMetrics( * 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); if (textPtr->refCount-- <= 1) { @@ -3115,8 +3119,14 @@ AsyncUpdateLineMetrics( * GenerateWidgetViewSyncEvent -- * * Send the <<WidgetViewSync>> event related to the text widget - * line metrics asynchronous update. - * This is equivalent to: + * line metrics asynchronous update. These events should only + * be sent when the sync status has changed. So this function + * compares the requested state with the state saved in the + * TkText structure, and only generates the event if they are + * different. This means that it is safe to call this function + * at any time when the state is known. + * + * If an event is sent, the effect is equivalent to: * event generate $textWidget <<WidgetViewSync>> -data $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). @@ -3132,9 +3142,12 @@ AsyncUpdateLineMetrics( static void GenerateWidgetViewSyncEvent( - TkText *textPtr, /* Information about text widget. */ - Bool InSync) /* true if in sync, false otherwise */ + TkText *textPtr, /* Information about text widget. */ + Bool InSync) /* true if becoming in sync, false otherwise */ { + Bool NewSyncState = (InSync != 0); /* ensure 0 or 1 value */ + Bool OldSyncState = !(textPtr->dInfoPtr->flags & OUT_OF_SYNC); + /* * OSX 10.14 needs to be told to display the window when the Text Widget * is in sync. (That is, to run DisplayText inside of the drawRect @@ -3147,8 +3160,15 @@ GenerateWidgetViewSyncEvent( FORCE_DISPLAY(textPtr->tkwin); } - TkSendVirtualEvent(textPtr->tkwin, "WidgetViewSync", - Tcl_NewBooleanObj(InSync)); + if (NewSyncState != OldSyncState) { + if (NewSyncState) { + textPtr->dInfoPtr->flags &= ~OUT_OF_SYNC; + } else { + textPtr->dInfoPtr->flags |= OUT_OF_SYNC; + } + TkSendVirtualEvent(textPtr->tkwin, "WidgetViewSync", + Tcl_NewBooleanObj(NewSyncState)); + } } /* @@ -3191,6 +3211,9 @@ TkTextUpdateLineMetrics( TkTextLine *linePtr = NULL; int count = 0; int totalLines = TkBTreeNumLines(textPtr->sharedTextPtr->tree, textPtr); + int fullUpdateRequested = (lineNum == 0 && + endLine == totalLines && + doThisMuch == -1); if (totalLines == 0) { /* @@ -3201,6 +3224,7 @@ TkTextUpdateLineMetrics( } while (1) { + /* * Get a suitable line. */ @@ -3227,6 +3251,7 @@ TkTextUpdateLineMetrics( */ if (textPtr->dInfoPtr->metricEpoch == -1 && lineNum == endLine) { + /* * We have looped over all lines, so we're done. */ @@ -3250,10 +3275,12 @@ TkTextUpdateLineMetrics( if (TkBTreeLinePixelEpoch(textPtr, linePtr) == textPtr->dInfoPtr->lineMetricUpdateEpoch) { + /* * This line is already up to date. That means there's nothing * to do here. */ + } else if (doThisMuch == -1) { count += 8 * TkTextUpdateOneLine(textPtr, linePtr, 0,NULL,0); } else { @@ -3275,6 +3302,7 @@ TkTextUpdateLineMetrics( indexPtr = &textPtr->dInfoPtr->metricIndex; pixelHeight = textPtr->dInfoPtr->metricPixelHeight; } else { + /* * We must reset the partial line height calculation data * here, so we don't use it when it is out of date. @@ -3298,6 +3326,7 @@ TkTextUpdateLineMetrics( pixelHeight, indexPtr, 1); if (indexPtr->linePtr == linePtr) { + /* * We didn't complete the logical line, because it * produced very many display lines, which must be because @@ -3306,6 +3335,7 @@ TkTextUpdateLineMetrics( */ if (pixelHeight == 0) { + /* * These have already been stored, unless we just * started the new line. @@ -3327,6 +3357,7 @@ TkTextUpdateLineMetrics( textPtr->dInfoPtr->metricEpoch = -1; } } else { + /* * We must never recalculate the height of the last artificial * line. It must stay at zero, and if we recalculate it, it will @@ -3351,13 +3382,21 @@ TkTextUpdateLineMetrics( } } if (doThisMuch == -1) { + /* - * If we were requested to provide a full update, then also update the - * scrollbar. + * If we were requested to update the entire range, then also update + * the scrollbar. */ GetYView(textPtr->interp, textPtr, 1); } + if (fullUpdateRequested) { + TextDInfo *dInfoPtr = textPtr->dInfoPtr; + + dInfoPtr->lastMetricUpdateLine = lineNum; + dInfoPtr->currentMetricUpdateLine = lineNum; + GenerateWidgetViewSyncEvent(textPtr, 1); + } return lineNum; } @@ -3526,8 +3565,12 @@ TextInvalidateLineMetrics( textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, AsyncUpdateLineMetrics, textPtr); - GenerateWidgetViewSyncEvent(textPtr, 0); } + + /* + * The widget is out of sync: send a <<WidgetViewSync>> event. + */ + GenerateWidgetViewSyncEvent(textPtr, 0); } /* @@ -5269,9 +5312,7 @@ TkTextRelayoutWindow( inSync = 0; } - if (!inSync) { - GenerateWidgetViewSyncEvent(textPtr, 0); - } + GenerateWidgetViewSyncEvent(textPtr, inSync); } } @@ -6296,11 +6337,7 @@ TkTextPendingsync( { TextDInfo *dInfoPtr = textPtr->dInfoPtr; - return ( - (!(dInfoPtr->flags & REDRAW_PENDING) && - (dInfoPtr->metricEpoch == -1) && - (dInfoPtr->lastMetricUpdateLine == dInfoPtr->currentMetricUpdateLine)) ? - 0 : 1); + return ((dInfoPtr->flags & OUT_OF_SYNC) != 0); } /* |