diff options
Diffstat (limited to 'generic/tkTextDisp.c')
-rw-r--r-- | generic/tkTextDisp.c | 845 |
1 files changed, 529 insertions, 316 deletions
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c index 1f39112..0849307 100644 --- a/generic/tkTextDisp.c +++ b/generic/tkTextDisp.c @@ -16,7 +16,7 @@ #include "tkInt.h" #include "tkText.h" -#ifdef __WIN32__ +#ifdef _WIN32 #include "tkWinInt.h" #elif defined(__CYGWIN__) #include "tkUnixInt.h" @@ -136,11 +136,15 @@ typedef struct StyleValues { * line of each text line. */ int lMargin2; /* Left margin, in pixels, for second and * later display lines of each text line. */ + Tk_3DBorder lMarginColor; /* Color of left margins (1 and 2). */ int offset; /* Offset in pixels of baseline, relative to * baseline of line. */ int overstrike; /* Non-zero means draw overstrike through * text. */ + XColor *overstrikeColor; /* Foreground color for overstrike through + * text. */ int rMargin; /* Right margin, in pixels. */ + Tk_3DBorder rMarginColor; /* Color of right margin. */ int spacing1; /* Spacing above first dline in text line. */ int spacing2; /* Spacing between lines of dline. */ int spacing3; /* Spacing below last dline in text line. */ @@ -149,6 +153,8 @@ typedef struct StyleValues { int tabStyle; /* One of TABULAR or WORDPROCESSOR. */ int underline; /* Non-zero means draw underline underneath * text. */ + XColor *underlineColor; /* Foreground color for underline underneath + * text. */ int elide; /* Zero means draw text, otherwise not. */ TkWrapMode wrapMode; /* How to handle wrap-around for this tag. * One of TEXT_WRAPMODE_CHAR, @@ -167,6 +173,8 @@ typedef struct TextStyle { GC bgGC; /* Graphics context for background. None means * use widget background. */ GC fgGC; /* Graphics context for foreground. */ + GC ulGC; /* Graphics context for underline. */ + GC ovGC; /* Graphics context for overstrike. */ StyleValues *sValuePtr; /* Raw information from which GCs were * derived. */ Tcl_HashEntry *hPtr; /* Pointer to entry in styleTable. Used to @@ -234,6 +242,14 @@ typedef struct DLine { int spaceBelow; /* How much extra space was added to the * bottom of the line because of spacing * options. This is included in height. */ + Tk_3DBorder lMarginColor; /* Background color of the area corresponding + * to the left margin of the display line. */ + int lMarginWidth; /* Pixel width of the area corresponding to + * the left margin. */ + Tk_3DBorder rMarginColor; /* Background color of the area corresponding + * to the right margin of the display line. */ + int rMarginWidth; /* Pixel width of the area corresponding to + * the right margin. */ int length; /* Total length of line, in pixels. */ TkTextDispChunk *chunkPtr; /* Pointer to first chunk in list of all of * those that are displayed on this line of @@ -416,8 +432,8 @@ typedef struct TextDInfo { typedef struct CharInfo { int numBytes; /* Number of bytes to display. */ - char chars[4]; /* UTF characters to display. Actual size will - * be numBytes, not 4. THIS MUST BE THE LAST + char chars[1]; /* UTF characters to display. Actual size will + * be numBytes, not 1. THIS MUST BE THE LAST * FIELD IN THE STRUCTURE. */ } CharInfo; @@ -447,6 +463,7 @@ typedef struct BaseCharInfo { * LayoutDLine(). */ } BaseCharInfo; +/* TODO: Thread safety */ static TkTextDispChunk *baseCharChunkPtr = NULL; #endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ @@ -544,23 +561,23 @@ static void DisplayLineBackground(TkText *textPtr, DLine *dlPtr, DLine *prevPtr, Pixmap pixmap); static void DisplayText(ClientData clientData); static DLine * FindDLine(TkText *textPtr, DLine *dlPtr, - CONST TkTextIndex *indexPtr); + const TkTextIndex *indexPtr); static void FreeDLines(TkText *textPtr, DLine *firstPtr, DLine *lastPtr, int action); static void FreeStyle(TkText *textPtr, TextStyle *stylePtr); -static TextStyle * GetStyle(TkText *textPtr, CONST TkTextIndex *indexPtr); +static TextStyle * GetStyle(TkText *textPtr, const TkTextIndex *indexPtr); static void GetXView(Tcl_Interp *interp, TkText *textPtr, int report); static void GetYView(Tcl_Interp *interp, TkText *textPtr, int report); static int GetYPixelCount(TkText *textPtr, DLine *dlPtr); static DLine * LayoutDLine(TkText *textPtr, - CONST TkTextIndex *indexPtr); -static int MeasureChars(Tk_Font tkfont, CONST char *source, + const TkTextIndex *indexPtr); +static int MeasureChars(Tk_Font tkfont, const char *source, int maxBytes, int rangeStart, int rangeLength, int startX, int maxX, int flags, int *nextXPtr); static void MeasureUp(TkText *textPtr, - CONST TkTextIndex *srcPtr, int distance, + const TkTextIndex *srcPtr, int distance, TkTextIndex *dstPtr, int *overlap); static int NextTabStop(Tk_Font tkfont, int x, int tabOrigin); static void UpdateDisplayInfo(TkText *textPtr); @@ -570,8 +587,8 @@ static int SizeOfTab(TkText *textPtr, int tabStyle, TkTextTabArray *tabArrayPtr, int *indexPtr, int x, int maxX); static void TextChanged(TkText *textPtr, - CONST TkTextIndex *index1Ptr, - CONST TkTextIndex *index2Ptr); + const TkTextIndex *index1Ptr, + const TkTextIndex *index2Ptr); static void TextInvalidateRegion(TkText *textPtr, TkRegion region); static void TextRedrawTag(TkText *textPtr, TkTextIndex *index1Ptr, TkTextIndex *index2Ptr, @@ -579,7 +596,7 @@ static void TextRedrawTag(TkText *textPtr, static void TextInvalidateLineMetrics(TkText *textPtr, TkTextLine *linePtr, int lineCount, int action); static int CalculateDisplayLineHeight(TkText *textPtr, - CONST TkTextIndex *indexPtr, int *byteCountPtr, + const TkTextIndex *indexPtr, int *byteCountPtr, int *mergedLinePtr); static void DlineIndexOfX(TkText *textPtr, DLine *dlPtr, int x, TkTextIndex *indexPtr); @@ -587,9 +604,10 @@ static int DlineXOfIndex(TkText *textPtr, DLine *dlPtr, int byteIndex); static int TextGetScrollInfoObj(Tcl_Interp *interp, TkText *textPtr, int objc, - Tcl_Obj *CONST objv[], double *dblPtr, + Tcl_Obj *const objv[], double *dblPtr, int *intPtr); static void AsyncUpdateLineMetrics(ClientData clientData); +static void GenerateWidgetViewSyncEvent(TkText *textPtr, Bool InSync); static void AsyncUpdateYScrollbar(ClientData clientData); static int IsStartOfNotMergedLine(TkText *textPtr, CONST TkTextIndex *indexPtr); @@ -629,7 +647,7 @@ TkTextCreateDInfo( register TextDInfo *dInfoPtr; XGCValues gcValues; - dInfoPtr = (TextDInfo *) ckalloc(sizeof(TextDInfo)); + dInfoPtr = ckalloc(sizeof(TextDInfo)); Tcl_InitHashTable(&dInfoPtr->styleTable, sizeof(StyleValues)/sizeof(int)); dInfoPtr->dLinePtr = NULL; dInfoPtr->copyGC = None; @@ -701,7 +719,7 @@ TkTextFreeDInfo( } Tk_FreeGC(textPtr->display, dInfoPtr->scrollGC); if (dInfoPtr->flags & REDRAW_PENDING) { - Tcl_CancelIdleCall(DisplayText, (ClientData) textPtr); + Tcl_CancelIdleCall(DisplayText, textPtr); } if (dInfoPtr->lineUpdateTimer != NULL) { Tcl_DeleteTimerHandler(dInfoPtr->lineUpdateTimer); @@ -713,7 +731,7 @@ TkTextFreeDInfo( textPtr->refCount--; dInfoPtr->scrollbarTimer = NULL; } - ckfree((char *) dInfoPtr); + ckfree(dInfoPtr); } /* @@ -737,7 +755,7 @@ TkTextFreeDInfo( static TextStyle * GetStyle( TkText *textPtr, /* Overall information about text widget. */ - CONST TkTextIndex *indexPtr)/* The character in the text for which display + const TkTextIndex *indexPtr)/* The character in the text for which display * information is wanted. */ { TkTextTag **tagPtrs; @@ -746,6 +764,7 @@ GetStyle( TextStyle *stylePtr; Tcl_HashEntry *hPtr; int numTags, isNew, i; + int isSelected; XGCValues gcValues; unsigned long mask; /* @@ -756,6 +775,7 @@ GetStyle( int fgPrio, fontPrio, fgStipplePrio; int underlinePrio, elidePrio, justifyPrio, offsetPrio; int lMargin1Prio, lMargin2Prio, rMarginPrio; + int lMarginColorPrio, rMarginColorPrio; int spacing1Prio, spacing2Prio, spacing3Prio; int overstrikePrio, tabPrio, tabStylePrio, wrapPrio; @@ -770,11 +790,14 @@ GetStyle( fgPrio = fontPrio = fgStipplePrio = -1; underlinePrio = elidePrio = justifyPrio = offsetPrio = -1; lMargin1Prio = lMargin2Prio = rMarginPrio = -1; + lMarginColorPrio = rMarginColorPrio = -1; spacing1Prio = spacing2Prio = spacing3Prio = -1; overstrikePrio = tabPrio = tabStylePrio = wrapPrio = -1; memset(&styleValues, 0, sizeof(StyleValues)); styleValues.relief = TK_RELIEF_FLAT; styleValues.fgColor = textPtr->fgColor; + styleValues.underlineColor = textPtr->fgColor; + styleValues.overstrikeColor = textPtr->fgColor; styleValues.tkfont = textPtr->tkfont; styleValues.justify = TK_JUSTIFY_LEFT; styleValues.spacing1 = textPtr->spacing1; @@ -784,12 +807,22 @@ GetStyle( styleValues.tabStyle = textPtr->tabStyle; styleValues.wrapMode = textPtr->wrapMode; styleValues.elide = 0; + isSelected = 0; + + for (i = 0 ; i < numTags; i++) { + if (textPtr->selTagPtr == tagPtrs[i]) { + isSelected = 1; + break; + } + } for (i = 0 ; i < numTags; i++) { Tk_3DBorder border; + XColor *fgColor; tagPtr = tagPtrs[i]; border = tagPtr->border; + fgColor = tagPtr->fgColor; /* * If this is the selection tag, and inactiveSelBorder is NULL (the @@ -809,6 +842,14 @@ GetStyle( border = textPtr->inactiveSelBorder; } + if ((tagPtr->selBorder != NULL) && (isSelected)) { + border = tagPtr->selBorder; + } + + if ((tagPtr->selFgColor != None) && (isSelected)) { + fgColor = tagPtr->selFgColor; + } + if ((border != NULL) && (tagPtr->priority > borderPrio)) { styleValues.border = border; borderPrio = tagPtr->priority; @@ -832,8 +873,8 @@ GetStyle( styleValues.bgStipple = tagPtr->bgStipple; bgStipplePrio = tagPtr->priority; } - if ((tagPtr->fgColor != None) && (tagPtr->priority > fgPrio)) { - styleValues.fgColor = tagPtr->fgColor; + if ((fgColor != None) && (tagPtr->priority > fgPrio)) { + styleValues.fgColor = fgColor; fgPrio = tagPtr->priority; } if ((tagPtr->tkfont != None) && (tagPtr->priority > fontPrio)) { @@ -860,6 +901,11 @@ GetStyle( styleValues.lMargin2 = tagPtr->lMargin2; lMargin2Prio = tagPtr->priority; } + if ((tagPtr->lMarginColor != NULL) + && (tagPtr->priority > lMarginColorPrio)) { + styleValues.lMarginColor = tagPtr->lMarginColor; + lMarginColorPrio = tagPtr->priority; + } if ((tagPtr->offsetString != NULL) && (tagPtr->priority > offsetPrio)) { styleValues.offset = tagPtr->offset; @@ -869,12 +915,22 @@ GetStyle( && (tagPtr->priority > overstrikePrio)) { styleValues.overstrike = tagPtr->overstrike; overstrikePrio = tagPtr->priority; + if (tagPtr->overstrikeColor != None) { + styleValues.overstrikeColor = tagPtr->overstrikeColor; + } else if (fgColor != None) { + styleValues.overstrikeColor = fgColor; + } } if ((tagPtr->rMarginString != NULL) && (tagPtr->priority > rMarginPrio)) { styleValues.rMargin = tagPtr->rMargin; rMarginPrio = tagPtr->priority; } + if ((tagPtr->rMarginColor != NULL) + && (tagPtr->priority > rMarginColorPrio)) { + styleValues.rMarginColor = tagPtr->rMarginColor; + rMarginColorPrio = tagPtr->priority; + } if ((tagPtr->spacing1String != NULL) && (tagPtr->priority > spacing1Prio)) { styleValues.spacing1 = tagPtr->spacing1; @@ -904,6 +960,11 @@ GetStyle( && (tagPtr->priority > underlinePrio)) { styleValues.underline = tagPtr->underline; underlinePrio = tagPtr->priority; + if (tagPtr->underlineColor != None) { + styleValues.underlineColor = tagPtr->underlineColor; + } else if (fgColor != None) { + styleValues.underlineColor = fgColor; + } } if ((tagPtr->elideString != NULL) && (tagPtr->priority > elidePrio)) { @@ -917,7 +978,7 @@ GetStyle( } } if (tagPtrs != NULL) { - ckfree((char *) tagPtrs); + ckfree(tagPtrs); } /* @@ -927,7 +988,7 @@ GetStyle( hPtr = Tcl_CreateHashEntry(&textPtr->dInfoPtr->styleTable, (char *) &styleValues, &isNew); if (!isNew) { - stylePtr = (TextStyle *) Tcl_GetHashValue(hPtr); + stylePtr = Tcl_GetHashValue(hPtr); stylePtr->refCount++; return stylePtr; } @@ -936,7 +997,7 @@ GetStyle( * No existing style matched. Make a new one. */ - stylePtr = (TextStyle *) ckalloc(sizeof(TextStyle)); + stylePtr = ckalloc(sizeof(TextStyle)); stylePtr->refCount = 1; if (styleValues.border != NULL) { gcValues.foreground = Tk_3DBorderColor(styleValues.border)->pixel; @@ -960,6 +1021,11 @@ GetStyle( mask |= GCStipple|GCFillStyle; } stylePtr->fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); + mask = GCForeground; + gcValues.foreground = styleValues.underlineColor->pixel; + stylePtr->ulGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); + gcValues.foreground = styleValues.overstrikeColor->pixel; + stylePtr->ovGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); stylePtr->sValuePtr = (StyleValues *) Tcl_GetHashKey(&textPtr->dInfoPtr->styleTable, hPtr); stylePtr->hPtr = hPtr; @@ -1000,8 +1066,14 @@ FreeStyle( if (stylePtr->fgGC != None) { Tk_FreeGC(textPtr->display, stylePtr->fgGC); } + if (stylePtr->ulGC != None) { + Tk_FreeGC(textPtr->display, stylePtr->ulGC); + } + if (stylePtr->ovGC != None) { + Tk_FreeGC(textPtr->display, stylePtr->ovGC); + } Tcl_DeleteHashEntry(stylePtr->hPtr); - ckfree((char *) stylePtr); + ckfree(stylePtr); } } @@ -1042,7 +1114,7 @@ FreeStyle( static DLine * LayoutDLine( TkText *textPtr, /* Overall information about text widget. */ - CONST TkTextIndex *indexPtr)/* Beginning of display line. May not + const TkTextIndex *indexPtr)/* Beginning of display line. May not * necessarily point to a character * segment. */ { @@ -1100,7 +1172,7 @@ LayoutDLine( * Create and initialize a new DLine structure. */ - dlPtr = (DLine *) ckalloc(sizeof(DLine)); + dlPtr = ckalloc(sizeof(DLine)); dlPtr->index = *indexPtr; dlPtr->byteCount = 0; dlPtr->y = 0; @@ -1111,6 +1183,10 @@ LayoutDLine( dlPtr->nextPtr = NULL; dlPtr->flags = NEW_LAYOUT | OLD_Y_INVALID; dlPtr->logicalLinesMerged = 0; + dlPtr->lMarginColor = NULL; + dlPtr->lMarginWidth = 0; + dlPtr->rMarginColor = NULL; + dlPtr->rMarginWidth = 0; /* * This is not necessarily totally correct, where we have merged logical @@ -1260,14 +1336,14 @@ LayoutDLine( */ TkTextLine *linePtr = TkBTreeNextLine(NULL, curIndex.linePtr); - if (linePtr != NULL) { - dlPtr->logicalLinesMerged++; - curIndex.byteIndex = 0; - curIndex.linePtr = linePtr; - segPtr = curIndex.linePtr->segPtr; - } else { + if (linePtr == NULL) { break; } + + dlPtr->logicalLinesMerged++; + curIndex.byteIndex = 0; + curIndex.linePtr = linePtr; + segPtr = curIndex.linePtr->segPtr; } } @@ -1331,7 +1407,7 @@ LayoutDLine( * into a single display line. * if (segPtr == NULL && chunkPtr != NULL) { - ckfree((char *) chunkPtr); + ckfree(chunkPtr); chunkPtr = NULL; } */ @@ -1345,7 +1421,7 @@ LayoutDLine( continue; } if (chunkPtr == NULL) { - chunkPtr = (TkTextDispChunk *) ckalloc(sizeof(TkTextDispChunk)); + chunkPtr = ckalloc(sizeof(TkTextDispChunk)); chunkPtr->nextPtr = NULL; chunkPtr->clientData = NULL; } @@ -1385,6 +1461,7 @@ LayoutDLine( x = chunkPtr->stylePtr->sValuePtr->lMargin2; } + dlPtr->lMarginWidth = x; if (wrapMode == TEXT_WRAPMODE_NONE) { maxX = -1; } else { @@ -1454,7 +1531,7 @@ LayoutDLine( code = 1; } else { - code = (*segPtr->typePtr->layoutProc)(textPtr, &curIndex, segPtr, + code = segPtr->typePtr->layoutProc(textPtr, &curIndex, segPtr, byteOffset, maxX-tabSize, maxBytes, noCharsYet, wrapMode, chunkPtr); } @@ -1477,7 +1554,7 @@ LayoutDLine( */ if (chunkPtr != NULL) { - ckfree((char *) chunkPtr); + ckfree(chunkPtr); } break; } @@ -1606,18 +1683,18 @@ LayoutDLine( FreeStyle(textPtr, chunkPtr->stylePtr); breakChunkPtr->nextPtr = chunkPtr->nextPtr; if (chunkPtr->undisplayProc != NULL) { - (*chunkPtr->undisplayProc)(textPtr, chunkPtr); + chunkPtr->undisplayProc(textPtr, chunkPtr); } - ckfree((char *) chunkPtr); + ckfree(chunkPtr); } if (breakByteOffset != breakChunkPtr->numBytes) { if (breakChunkPtr->undisplayProc != NULL) { - (*breakChunkPtr->undisplayProc)(textPtr, breakChunkPtr); + breakChunkPtr->undisplayProc(textPtr, breakChunkPtr); } segPtr = TkTextIndexToSeg(&breakIndex, &byteOffset); - (*segPtr->typePtr->layoutProc)(textPtr, &breakIndex, - segPtr, byteOffset, maxX, breakByteOffset, 0, - wrapMode, breakChunkPtr); + segPtr->typePtr->layoutProc(textPtr, &breakIndex, segPtr, + byteOffset, maxX, breakByteOffset, 0, wrapMode, + breakChunkPtr); #if TK_LAYOUT_WITH_BASE_CHUNKS FinalizeBaseChunk(NULL); #endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ @@ -1696,6 +1773,11 @@ LayoutDLine( } dlPtr->height += dlPtr->spaceAbove + dlPtr->spaceBelow; dlPtr->baseline += dlPtr->spaceAbove; + dlPtr->lMarginColor = sValuePtr->lMarginColor; + dlPtr->rMarginColor = sValuePtr->rMarginColor; + if (wrapMode != TEXT_WRAPMODE_NONE) { + dlPtr->rMarginWidth = rMargin; + } /* * Recompute line length: may have changed because of justification. @@ -2302,13 +2384,13 @@ FreeDLines( for (chunkPtr = firstPtr->chunkPtr; chunkPtr != NULL; chunkPtr = nextChunkPtr) { if (chunkPtr->undisplayProc != NULL) { - (*chunkPtr->undisplayProc)(textPtr, chunkPtr); + chunkPtr->undisplayProc(textPtr, chunkPtr); } FreeStyle(textPtr, chunkPtr->stylePtr); nextChunkPtr = chunkPtr->nextPtr; - ckfree((char *) chunkPtr); + ckfree(chunkPtr); } - ckfree((char *) firstPtr); + ckfree(firstPtr); firstPtr = nextDLinePtr; } if (action != DLINE_FREE_TEMP) { @@ -2382,6 +2464,20 @@ DisplayDLine( Tk_Width(textPtr->tkwin), dlPtr->height, 0, TK_RELIEF_FLAT); /* + * Second, draw the background color of the left and right margins. + */ + if (dlPtr->lMarginColor != NULL) { + Tk_Fill3DRectangle(textPtr->tkwin, pixmap, dlPtr->lMarginColor, 0, y, + dlPtr->lMarginWidth + dInfoPtr->x - dInfoPtr->curXPixelOffset, + dlPtr->height, 0, TK_RELIEF_FLAT); + } + if (dlPtr->rMarginColor != NULL) { + Tk_Fill3DRectangle(textPtr->tkwin, pixmap, dlPtr->rMarginColor, + dInfoPtr->maxX - dlPtr->rMarginWidth + dInfoPtr->curXPixelOffset, + y, dlPtr->rMarginWidth, dlPtr->height, 0, TK_RELIEF_FLAT); + } + + /* * Next, draw background information for the whole line. */ @@ -2400,7 +2496,7 @@ DisplayDLine( if (chunkPtr->displayProc == TkTextInsertDisplayProc) { int x = chunkPtr->x + dInfoPtr->x - dInfoPtr->curXPixelOffset; - (*chunkPtr->displayProc)(textPtr, chunkPtr, x, + chunkPtr->displayProc(textPtr, chunkPtr, x, y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, @@ -2448,7 +2544,7 @@ DisplayDLine( x = -chunkPtr->width; } - (*chunkPtr->displayProc)(textPtr, chunkPtr, x, + chunkPtr->displayProc(textPtr, chunkPtr, x, y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, dlPtr->y + dlPtr->spaceAbove); @@ -2897,7 +2993,7 @@ static void AsyncUpdateLineMetrics( ClientData clientData) /* Information about widget. */ { - register TkText *textPtr = (TkText *) clientData; + register TkText *textPtr = clientData; TextDInfo *dInfoPtr = textPtr->dInfoPtr; int lineNum; @@ -2910,7 +3006,7 @@ AsyncUpdateLineMetrics( */ if (--textPtr->refCount == 0) { - ckfree((char *) textPtr); + ckfree(textPtr); } return; } @@ -2921,6 +3017,11 @@ AsyncUpdateLineMetrics( return; } + /* + * Reify where we end or all hell breaks loose with the calculations when + * we try to update. [Bug 2677890] + */ + lineNum = dInfoPtr->currentMetricUpdateLine; if (dInfoPtr->lastMetricUpdateLine == -1) { dInfoPtr->lastMetricUpdateLine = @@ -2935,6 +3036,8 @@ AsyncUpdateLineMetrics( lineNum = TkTextUpdateLineMetrics(textPtr, lineNum, dInfoPtr->lastMetricUpdateLine, 256); + dInfoPtr->currentMetricUpdateLine = lineNum; + if (tkTextDebug) { char buffer[2 * TCL_INTEGER_SPACE + 1]; @@ -2952,16 +3055,37 @@ 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 aftersync command, run that first. */ + 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 = NULL; + } + + /* + * Fire the <<WidgetViewSync>> 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); + ckfree(textPtr); } return; } - dInfoPtr->currentMetricUpdateLine = lineNum; /* * Re-arm the timer. We already have a refCount on the text widget so no @@ -2969,7 +3093,46 @@ AsyncUpdateLineMetrics( */ dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, - AsyncUpdateLineMetrics, (ClientData) textPtr); + AsyncUpdateLineMetrics, textPtr); +} + +/* + *---------------------------------------------------------------------- + * + * GenerateWidgetViewSyncEvent -- + * + * Send the <<WidgetViewSync>> event related to the text widget + * line metrics asynchronous update. + * This is equivalent to: + * event generate $textWidget <<WidgetViewSync>> -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 + * + * Side effects: + * If corresponding bindings are present, they will trigger. + * + *---------------------------------------------------------------------- + */ + +static void +GenerateWidgetViewSyncEvent( + TkText *textPtr, /* Information about text widget. */ + Bool InSync) /* True if in sync, false otherwise */ +{ + union {XEvent general; XVirtualEvent virtual;} event; + + 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("WidgetViewSync"); + event.virtual.user_data = Tcl_NewBooleanObj(InSync); + Tk_HandleEvent(&event.general); } /* @@ -3070,86 +3233,82 @@ TkTextUpdateLineMetrics( */ if (TkBTreeLinePixelEpoch(textPtr, linePtr) - != textPtr->dInfoPtr->lineMetricUpdateEpoch) { - if (doThisMuch == -1) { - count += 8 * TkTextUpdateOneLine(textPtr, linePtr, 0, - NULL, 0); - } else { - TkTextIndex index; - TkTextIndex *indexPtr; - int pixelHeight; + == 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 { + TkTextIndex index; + TkTextIndex *indexPtr; + int pixelHeight; + + /* + * If the metric epoch is the same as the widget's epoch, then + * we know that indexPtrs are still valid, and if the cached + * metricIndex (if any) is for the same line as we wish to + * examine, then we are looking at a long line wrapped many + * times, which we will examine in pieces. + */ + if (textPtr->dInfoPtr->metricEpoch == + textPtr->sharedTextPtr->stateEpoch && + textPtr->dInfoPtr->metricIndex.linePtr==linePtr) { + indexPtr = &textPtr->dInfoPtr->metricIndex; + pixelHeight = textPtr->dInfoPtr->metricPixelHeight; + } else { /* - * If the metric epoch is the same as the widget's epoch, - * then we know that indexPtrs are still valid, and if the - * cached metricIndex (if any) is for the same line as we - * wish to examine, then we are looking at a long line - * wrapped many times, which we will examine in pieces. + * We must reset the partial line height calculation data + * here, so we don't use it when it is out of date. */ - if (textPtr->dInfoPtr->metricEpoch == - textPtr->sharedTextPtr->stateEpoch && - textPtr->dInfoPtr->metricIndex.linePtr==linePtr) { - 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. - */ + textPtr->dInfoPtr->metricEpoch = -1; + index.tree = textPtr->sharedTextPtr->tree; + index.linePtr = linePtr; + index.byteIndex = 0; + index.textPtr = NULL; + indexPtr = &index; + pixelHeight = 0; + } - textPtr->dInfoPtr->metricEpoch = -1; - index.tree = textPtr->sharedTextPtr->tree; - index.linePtr = linePtr; - index.byteIndex = 0; - index.textPtr = NULL; - indexPtr = &index; - pixelHeight = 0; - } + /* + * Update the line and update the counter, counting 8 for each + * display line we actually re-layout. + */ + count += 8 * TkTextUpdateOneLine(textPtr, linePtr, + pixelHeight, indexPtr, 1); + + if (indexPtr->linePtr == linePtr) { /* - * Update the line and update the counter, counting 8 for - * each display line we actually re-layout. + * We didn't complete the logical line, because it + * produced very many display lines, which must be because + * it must be a long line wrapped many times. So we must + * cache as far as we got for next time around. */ - count += 8 * TkTextUpdateOneLine(textPtr, linePtr, - pixelHeight, indexPtr, 1); - - if (indexPtr->linePtr == linePtr) { + if (pixelHeight == 0) { /* - * We didn't complete the logical line, because it - * produced very many display lines - it must be a - * long line wrapped many times. So we must cache as - * far as we got for next time around. + * These have already been stored, unless we just + * started the new line. */ - if (pixelHeight == 0) { - /* - * These have already been stored, unless we just - * started the new line. - */ - - textPtr->dInfoPtr->metricIndex = index; - textPtr->dInfoPtr->metricEpoch = - textPtr->sharedTextPtr->stateEpoch; - } - textPtr->dInfoPtr->metricPixelHeight = - TkBTreeLinePixelCount(textPtr, linePtr); - break; - } else { - /* - * We're done with this long line. - */ - - textPtr->dInfoPtr->metricEpoch = -1; + textPtr->dInfoPtr->metricIndex = index; + textPtr->dInfoPtr->metricEpoch = + textPtr->sharedTextPtr->stateEpoch; } + textPtr->dInfoPtr->metricPixelHeight = + TkBTreeLinePixelCount(textPtr, linePtr); + break; } - } else { + /* - * This line is already up to date. That means there's nothing - * to do here. + * We're done with this long line. */ + + textPtr->dInfoPtr->metricEpoch = -1; } } else { /* @@ -3350,7 +3509,8 @@ TextInvalidateLineMetrics( if (dInfoPtr->lineUpdateTimer == NULL) { textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, - AsyncUpdateLineMetrics, (ClientData) textPtr); + AsyncUpdateLineMetrics, textPtr); + GenerateWidgetViewSyncEvent(textPtr, 0); } } @@ -3400,6 +3560,8 @@ TkTextFindDisplayLineEnd( * of the original index within its display * line. */ { + TkTextIndex index; + if (!end && IsStartOfNotMergedLine(textPtr, indexPtr)) { /* * Nothing to do. @@ -3409,96 +3571,94 @@ TkTextFindDisplayLineEnd( *xOffset = 0; } return; - } else { - TkTextIndex index = *indexPtr; - - index.byteIndex = 0; - index.textPtr = NULL; - - while (1) { - TkTextIndex endOfLastLine; + } - if (TkTextIndexBackBytes(textPtr, &index, 1, &endOfLastLine)) { - /* - * Reached beginning of text. - */ + index = *indexPtr; + index.byteIndex = 0; + index.textPtr = NULL; - break; - } + while (1) { + TkTextIndex endOfLastLine; - if (!TkTextIsElided(textPtr, &endOfLastLine, NULL)) { - /* - * The eol is not elided, so 'index' points to the start of a - * display line (as well as logical line). - */ + if (TkTextIndexBackBytes(textPtr, &index, 1, &endOfLastLine)) { + /* + * Reached beginning of text. + */ - break; - } + break; + } + if (!TkTextIsElided(textPtr, &endOfLastLine, NULL)) { /* - * indexPtr's logical line is actually merged with the previous - * logical line whose eol is elided. Continue searching back to - * get a real line start. + * The eol is not elided, so 'index' points to the start of a + * display line (as well as logical line). */ - index = endOfLastLine; - index.byteIndex = 0; + break; } - while (1) { - DLine *dlPtr; - int byteCount; - TkTextIndex nextLineStart; + /* + * indexPtr's logical line is actually merged with the previous + * logical line whose eol is elided. Continue searching back to get a + * real line start. + */ - dlPtr = LayoutDLine(textPtr, &index); - byteCount = dlPtr->byteCount; + index = endOfLastLine; + index.byteIndex = 0; + } - TkTextIndexForwBytes(textPtr, &index, byteCount, &nextLineStart); + while (1) { + DLine *dlPtr; + int byteCount; + TkTextIndex nextLineStart; + dlPtr = LayoutDLine(textPtr, &index); + byteCount = dlPtr->byteCount; + + TkTextIndexForwBytes(textPtr, &index, byteCount, &nextLineStart); + + /* + * 'byteCount' goes up to the beginning of the next display line, so + * equality here says we need one more line. We try to perform a quick + * comparison which is valid for the case where the logical line is + * the same, but otherwise fall back on a full TkTextIndexCmp. + */ + + if (((index.linePtr == indexPtr->linePtr) + && (index.byteIndex + byteCount > indexPtr->byteIndex)) + || (dlPtr->logicalLinesMerged > 0 + && TkTextIndexCmp(&nextLineStart, indexPtr) > 0)) { /* - * 'byteCount' goes up to the beginning of the next display line, - * so equality here says we need one more line. We try to perform - * a quick comparison which is valid for the case where the - * logical line is the same, but otherwise fall back on a full - * TkTextIndexCmp. + * It's on this display line. */ - if (((index.linePtr == indexPtr->linePtr) - && (index.byteIndex + byteCount > indexPtr->byteIndex)) - || (dlPtr->logicalLinesMerged > 0 - && TkTextIndexCmp(&nextLineStart, indexPtr) > 0)) { + if (xOffset != NULL) { /* - * It's on this display line. + * This call takes a byte index relative to the start of the + * current _display_ line, not logical line. We are about to + * overwrite indexPtr->byteIndex, so we must do this now. */ - if (xOffset != NULL) { - /* - * This call takes a byte index relative to the start of - * the current _display_ line, not logical line. We are - * about to overwrite indexPtr->byteIndex, so we must do - * this now. - */ - - *xOffset = DlineXOfIndex(textPtr, dlPtr, - TkTextIndexCountBytes(textPtr, &dlPtr->index, - indexPtr)); - } - if (end) { - /* - * The index we want is one less than the number of bytes - * in the display line. - */ + *xOffset = DlineXOfIndex(textPtr, dlPtr, + TkTextIndexCountBytes(textPtr, &dlPtr->index, + indexPtr)); + } + if (end) { + /* + * The index we want is one less than the number of bytes in + * the display line. + */ - TkTextIndexBackBytes(textPtr, &nextLineStart, 1, indexPtr); - } else { - *indexPtr = index; - } - FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP); - return; + TkTextIndexBackBytes(textPtr, &nextLineStart, 1, indexPtr); + } else { + *indexPtr = index; } FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP); - index = nextLineStart; + return; } + + FreeDLines(textPtr, dlPtr, NULL, DLINE_FREE_TEMP); + index = nextLineStart; } } @@ -3540,7 +3700,7 @@ TkTextFindDisplayLineEnd( static int CalculateDisplayLineHeight( TkText *textPtr, /* Widget record for text widget. */ - CONST TkTextIndex *indexPtr,/* The index at the beginning of the display + const TkTextIndex *indexPtr,/* The index at the beginning of the display * line of interest. */ int *byteCountPtr, /* NULL or used to return the number of byte * indices on the given display line. */ @@ -3632,7 +3792,7 @@ CalculateDisplayLineHeight( int TkTextIndexYPixels( TkText *textPtr, /* Widget record for text widget. */ - CONST TkTextIndex *indexPtr)/* The index of which we want the pixel + const TkTextIndex *indexPtr)/* The index of which we want the pixel * distance from top of logical line to top of * index. */ { @@ -3925,7 +4085,7 @@ TkTextUpdateOneLine( if (textPtr->dInfoPtr->scrollbarTimer == NULL) { textPtr->refCount++; textPtr->dInfoPtr->scrollbarTimer = Tcl_CreateTimerHandler(200, - AsyncUpdateYScrollbar, (ClientData) textPtr); + AsyncUpdateYScrollbar, textPtr); } return displayLines; } @@ -3951,7 +4111,7 @@ static void DisplayText( ClientData clientData) /* Information about widget. */ { - register TkText *textPtr = (TkText *) clientData; + register TkText *textPtr = clientData; TextDInfo *dInfoPtr = textPtr->dInfoPtr; register DLine *dlPtr; DLine *prevPtr; @@ -3969,8 +4129,8 @@ DisplayText( TkWindow *winPtr = (TkWindow *)(textPtr->tkwin); MacDrawable *macWin = winPtr->privatePtr; if (macWin && (macWin->flags & TK_DO_NOT_DRAW)){ - dInfoPtr->flags &= ~REDRAW_PENDING; - return; + dInfoPtr->flags &= ~REDRAW_PENDING; + return; } #endif @@ -3983,7 +4143,7 @@ DisplayText( } interp = textPtr->interp; - Tcl_Preserve((ClientData) interp); + Tcl_Preserve(interp); if (tkTextDebug) { Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY); @@ -4013,7 +4173,7 @@ DisplayText( dInfoPtr->flags &= ~REPICK_NEEDED; TkTextPickCurrent(textPtr, &textPtr->pickEvent); if (--textPtr->refCount == 0) { - ckfree((char *) textPtr); + ckfree(textPtr); goto end; } if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { @@ -4093,7 +4253,7 @@ DisplayText( */ if ((y + height) > dInfoPtr->maxY) { - height = dInfoPtr->maxY -y; + height = dInfoPtr->maxY - y; } oldY = dlPtr->oldY; if (y < dInfoPtr->y) { @@ -4406,7 +4566,7 @@ DisplayText( } end: - Tcl_Release((ClientData) interp); + Tcl_Release(interp); } /* @@ -4435,7 +4595,7 @@ TkTextEventuallyRepick( dInfoPtr->flags |= REPICK_NEEDED; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } } @@ -4479,7 +4639,7 @@ TkTextRedrawRegion( if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } TkDestroyRegion(damageRgn); } @@ -4573,8 +4733,8 @@ void TkTextChanged( TkSharedText *sharedTextPtr,/* Shared widget section, or NULL. */ TkText *textPtr, /* Widget record for text widget, or NULL. */ - CONST TkTextIndex*index1Ptr,/* Index of first character to redisplay. */ - CONST TkTextIndex*index2Ptr)/* Index of character just after last one to + const TkTextIndex*index1Ptr,/* Index of first character to redisplay. */ + const TkTextIndex*index2Ptr)/* Index of character just after last one to * redisplay. */ { if (sharedTextPtr == NULL) { @@ -4591,8 +4751,8 @@ TkTextChanged( static void TextChanged( TkText *textPtr, /* Widget record for text widget, or NULL. */ - CONST TkTextIndex*index1Ptr,/* Index of first character to redisplay. */ - CONST TkTextIndex*index2Ptr)/* Index of character just after last one to + const TkTextIndex*index1Ptr,/* Index of first character to redisplay. */ + const TkTextIndex*index2Ptr)/* Index of character just after last one to * redisplay. */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; @@ -4618,7 +4778,7 @@ TextChanged( */ if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; @@ -4855,7 +5015,7 @@ TextRedrawTag( */ if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; @@ -4959,7 +5119,7 @@ TkTextRelayoutWindow( */ if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } dInfoPtr->flags |= REDRAW_PENDING|REDRAW_BORDERS|DINFO_OUT_OF_DATE |REPICK_NEEDED; @@ -5054,7 +5214,8 @@ TkTextRelayoutWindow( if (dInfoPtr->lineUpdateTimer == NULL) { textPtr->refCount++; dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1, - AsyncUpdateLineMetrics, (ClientData) textPtr); + AsyncUpdateLineMetrics, textPtr); + GenerateWidgetViewSyncEvent(textPtr, 0); } } } @@ -5253,7 +5414,7 @@ TkTextSetYView( scheduleUpdate: if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; } @@ -5343,7 +5504,7 @@ TkTextMeasureDown( static void MeasureUp( TkText *textPtr, /* Text widget in which to measure. */ - CONST TkTextIndex *srcPtr, /* Index of character from which to start + const TkTextIndex *srcPtr, /* Index of character from which to start * measuring. */ int distance, /* Vertical distance in pixels measured from * the pixel just below the lowest one in @@ -5462,7 +5623,7 @@ TkTextSeeCmd( TkText *textPtr, /* Information about text widget. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. Someone else has already + Tcl_Obj *const objv[]) /* Argument objects. Someone else has already * parsed this command enough to know that * objv[1] is "see". */ { @@ -5542,7 +5703,7 @@ TkTextSeeCmd( */ if (chunkPtr != NULL) { - (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount, + chunkPtr->bboxProc(textPtr, chunkPtr, byteCount, dlPtr->y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width, @@ -5551,27 +5712,26 @@ TkTextSeeCmd( oneThird = lineWidth/3; if (delta < 0) { if (delta < -oneThird) { - dInfoPtr->newXPixelOffset = (x - lineWidth/2); + dInfoPtr->newXPixelOffset = x - lineWidth/2; } else { - dInfoPtr->newXPixelOffset -= ((-delta) ); + dInfoPtr->newXPixelOffset += delta; } } else { - delta -= (lineWidth - width); - if (delta > 0) { - if (delta > oneThird) { - dInfoPtr->newXPixelOffset = (x - lineWidth/2); - } else { - dInfoPtr->newXPixelOffset += (delta ); - } - } else { + delta -= lineWidth - width; + if (delta <= 0) { return TCL_OK; } + if (delta > oneThird) { + dInfoPtr->newXPixelOffset = x - lineWidth/2; + } else { + dInfoPtr->newXPixelOffset += delta; + } } } dInfoPtr->flags |= DINFO_OUT_OF_DATE; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } return TCL_OK; } @@ -5599,7 +5759,7 @@ TkTextXviewCmd( TkText *textPtr, /* Information about text widget. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. Someone else has already + Tcl_Obj *const objv[]) /* Argument objects. Someone else has already * parsed this command enough to know that * objv[1] is "xview". */ { @@ -5652,7 +5812,7 @@ TkTextXviewCmd( dInfoPtr->flags |= DINFO_OUT_OF_DATE; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } return TCL_OK; } @@ -5737,7 +5897,7 @@ YScrollByPixels( return; } if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; } @@ -5872,7 +6032,7 @@ YScrollByLines( scheduleUpdate: if (!(dInfoPtr->flags & REDRAW_PENDING)) { - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } dInfoPtr->flags |= REDRAW_PENDING|DINFO_OUT_OF_DATE|REPICK_NEEDED; } @@ -5900,7 +6060,7 @@ TkTextYviewCmd( TkText *textPtr, /* Information about text widget. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. Someone else has already + Tcl_Obj *const objv[]) /* Argument objects. Someone else has already * parsed this command enough to know that * objv[1] is "yview". */ { @@ -5926,7 +6086,7 @@ TkTextYviewCmd( pickPlace = 0; if (Tcl_GetString(objv[2])[0] == '-') { - register CONST char *switchStr = + register const char *switchStr = Tcl_GetStringFromObj(objv[2], &switchLength); if ((switchLength >= 2) && (strncmp(switchStr, "-pickplace", @@ -6061,6 +6221,35 @@ TkTextYviewCmd( /* *-------------------------------------------------------------- * + * TkTextPendingsync -- + * + * This function checks if any line heights are not up-to-date. + * + * Results: + * Returns a boolean true if it is the case, or false if all line + * heights are up-to-date. + * + * Side effects: + * None. + * + *-------------------------------------------------------------- + */ + +Bool +TkTextPendingsync( + TkText *textPtr) /* Information about text widget. */ +{ + TextDInfo *dInfoPtr = textPtr->dInfoPtr; + + return ( + ((dInfoPtr->metricEpoch == -1) && + (dInfoPtr->lastMetricUpdateLine == dInfoPtr->currentMetricUpdateLine)) ? + 0 : 1); +} + +/* + *-------------------------------------------------------------- + * * TkTextScanCmd -- * * This function is invoked to process the "scan" option for the widget @@ -6081,7 +6270,7 @@ TkTextScanCmd( register TkText *textPtr, /* Information about text widget. */ Tcl_Interp *interp, /* Current interpreter. */ int objc, /* Number of arguments. */ - Tcl_Obj *CONST objv[]) /* Argument objects. Someone else has already + Tcl_Obj *const objv[]) /* Argument objects. Someone else has already * parsed this command enough to know that * objv[1] is "scan". */ { @@ -6152,7 +6341,7 @@ TkTextScanCmd( dInfoPtr->flags |= DINFO_OUT_OF_DATE; if (!(dInfoPtr->flags & REDRAW_PENDING)) { dInfoPtr->flags |= REDRAW_PENDING; - Tcl_DoWhenIdle(DisplayText, (ClientData) textPtr); + Tcl_DoWhenIdle(DisplayText, textPtr); } } else if (c=='m' && strncmp(Tcl_GetString(objv[2]), "mark", length)==0) { dInfoPtr->scanMarkXPixel = dInfoPtr->newXPixelOffset; @@ -6160,8 +6349,11 @@ TkTextScanCmd( dInfoPtr->scanTotalYScroll = 0; dInfoPtr->scanMarkY = y; } else { - Tcl_AppendResult(interp, "bad scan option \"", Tcl_GetString(objv[2]), - "\": must be mark or dragto", NULL); + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "bad scan option \"%s\": must be mark or dragto", + Tcl_GetString(objv[2]))); + Tcl_SetErrorCode(interp, "TCL", "LOOKUP", "INDEX", "scan option", + Tcl_GetString(objv[2]), NULL); return TCL_ERROR; } return TCL_OK; @@ -6234,16 +6426,22 @@ GetXView( if (textPtr->xScrollCmd != NULL) { char buf1[TCL_DOUBLE_SPACE+1]; char buf2[TCL_DOUBLE_SPACE+1]; + Tcl_DString buf; buf1[0] = ' '; buf2[0] = ' '; Tcl_PrintDouble(NULL, first, buf1+1); Tcl_PrintDouble(NULL, last, buf2+1); - code = Tcl_VarEval(interp, textPtr->xScrollCmd, buf1, buf2, NULL); + Tcl_DStringInit(&buf); + Tcl_DStringAppend(&buf, textPtr->xScrollCmd, -1); + Tcl_DStringAppend(&buf, buf1, -1); + Tcl_DStringAppend(&buf, buf2, -1); + code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + Tcl_DStringFree(&buf); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (horizontal scrolling command executed by text)"); - Tcl_BackgroundError(interp); + Tcl_BackgroundException(interp, code); } } } @@ -6362,9 +6560,8 @@ GetYPixelCount( notFirst = 1; } break; - } else { - dlPtr = dlPtr->nextPtr; } + dlPtr = dlPtr->nextPtr; } while (dlPtr->index.linePtr == linePtr); return count; @@ -6514,16 +6711,22 @@ GetYView( if (textPtr->yScrollCmd != NULL) { char buf1[TCL_DOUBLE_SPACE+1]; char buf2[TCL_DOUBLE_SPACE+1]; + Tcl_DString buf; buf1[0] = ' '; buf2[0] = ' '; Tcl_PrintDouble(NULL, first, buf1+1); Tcl_PrintDouble(NULL, last, buf2+1); - code = Tcl_VarEval(interp, textPtr->yScrollCmd, buf1, buf2, NULL); + Tcl_DStringInit(&buf); + Tcl_DStringAppend(&buf, textPtr->yScrollCmd, -1); + Tcl_DStringAppend(&buf, buf1, -1); + Tcl_DStringAppend(&buf, buf2, -1); + code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0); + Tcl_DStringFree(&buf); if (code != TCL_OK) { Tcl_AddErrorInfo(interp, "\n (vertical scrolling command executed by text)"); - Tcl_BackgroundError(interp); + Tcl_BackgroundException(interp, code); } } } @@ -6550,7 +6753,7 @@ static void AsyncUpdateYScrollbar( ClientData clientData) /* Information about widget. */ { - register TkText *textPtr = (TkText *) clientData; + register TkText *textPtr = clientData; textPtr->dInfoPtr->scrollbarTimer = NULL; @@ -6559,7 +6762,7 @@ AsyncUpdateYScrollbar( } if (--textPtr->refCount == 0) { - ckfree((char *) textPtr); + ckfree(textPtr); } } @@ -6587,7 +6790,7 @@ FindDLine( TkText *textPtr, /* Widget record for text widget. */ register DLine *dlPtr, /* Pointer to first in list of DLines to * search. */ - CONST TkTextIndex *indexPtr)/* Index of desired character. */ + const TkTextIndex *indexPtr)/* Index of desired character. */ { DLine *dlPtrPrev; TkTextIndex indexPtr2; @@ -6797,25 +7000,26 @@ TkTextPixelIndex( } *indexPtr = textPtr->topIndex; return; - } else { - for (dlPtr = validDlPtr = dInfoPtr->dLinePtr; - y >= (dlPtr->y + dlPtr->height); - dlPtr = dlPtr->nextPtr) { - if (dlPtr->chunkPtr != NULL) { - validDlPtr = dlPtr; - } - if (dlPtr->nextPtr == NULL) { - /* - * Y-coordinate is off the bottom of the displayed text. Use - * the last character on the last line. - */ + } + for (dlPtr = validDlPtr = dInfoPtr->dLinePtr; + y >= (dlPtr->y + dlPtr->height); + dlPtr = dlPtr->nextPtr) { + if (dlPtr->chunkPtr != NULL) { + validDlPtr = dlPtr; + } + if (dlPtr->nextPtr == NULL) { + /* + * Y-coordinate is off the bottom of the displayed text. Use the + * last character on the last line. + */ - x = dInfoPtr->maxX - 1; - nearby = 1; - break; - } + x = dInfoPtr->maxX - 1; + nearby = 1; + break; } - if (dlPtr->chunkPtr == NULL) dlPtr = validDlPtr; + } + if (dlPtr->chunkPtr == NULL) { + dlPtr = validDlPtr; } if (nearest != NULL) { @@ -6913,7 +7117,7 @@ DlineIndexOfX( */ if (chunkPtr->numBytes > 1) { - indexPtr->byteIndex += (*chunkPtr->measureProc)(chunkPtr, x); + indexPtr->byteIndex += chunkPtr->measureProc(chunkPtr, x); } } @@ -6988,7 +7192,7 @@ DlineXOfIndex( int x = 0; if (byteIndex == 0 || chunkPtr == NULL) { - return 0; + return x; } /* @@ -7001,15 +7205,14 @@ DlineXOfIndex( if (byteIndex < chunkPtr->numBytes) { int y, width, height; - (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteIndex, + chunkPtr->bboxProc(textPtr, chunkPtr, byteIndex, dlPtr->y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width, &height); break; - } else { - byteIndex -= chunkPtr->numBytes; } + byteIndex -= chunkPtr->numBytes; if (chunkPtr->nextPtr == NULL || byteIndex == 0) { x = chunkPtr->x + chunkPtr->width; break; @@ -7043,7 +7246,7 @@ DlineXOfIndex( int TkTextIndexBbox( TkText *textPtr, /* Widget record for text widget. */ - CONST TkTextIndex *indexPtr,/* Index whose bounding box is desired. */ + const TkTextIndex *indexPtr,/* Index whose bounding box is desired. */ int *xPtr, int *yPtr, /* Filled with index's upper-left * coordinate. */ int *widthPtr, int *heightPtr, @@ -7072,7 +7275,7 @@ TkTextIndexBbox( dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr); - /* + /* * Two cases shall be trapped here because the logic later really * needs dlPtr to be the display line containing indexPtr: * 1. if no display line contains the desired index (NULL dlPtr) @@ -7110,7 +7313,7 @@ TkTextIndexBbox( * coordinate on the screen. Translate it to reflect horizontal scrolling. */ - (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount, + chunkPtr->bboxProc(textPtr, chunkPtr, byteCount, dlPtr->y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr, @@ -7189,7 +7392,7 @@ TkTextIndexBbox( int TkTextDLineInfo( TkText *textPtr, /* Widget record for text widget. */ - CONST TkTextIndex *indexPtr,/* Index of character whose bounding box is + const TkTextIndex *indexPtr,/* Index of character whose bounding box is * desired. */ int *xPtr, int *yPtr, /* Filled with line's upper-left * coordinate. */ @@ -7216,7 +7419,7 @@ TkTextDLineInfo( dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr); - /* + /* * Two cases shall be trapped here because the logic later really * needs dlPtr to be the display line containing indexPtr: * 1. if no display line contains the desired index (NULL dlPtr) @@ -7356,22 +7559,22 @@ TkTextCharLayoutProc( #if TK_LAYOUT_WITH_BASE_CHUNKS if (baseCharChunkPtr == NULL) { baseCharChunkPtr = chunkPtr; - bciPtr = (BaseCharInfo *) ckalloc(sizeof(BaseCharInfo)); + bciPtr = ckalloc(sizeof(BaseCharInfo)); baseString = &bciPtr->baseChars; Tcl_DStringInit(baseString); bciPtr->width = 0; ciPtr = &bciPtr->ci; } else { - bciPtr = (BaseCharInfo *) baseCharChunkPtr->clientData; - ciPtr = (CharInfo *) ckalloc(sizeof(CharInfo)); + bciPtr = baseCharChunkPtr->clientData; + ciPtr = ckalloc(sizeof(CharInfo)); baseString = &bciPtr->baseChars; } lineOffset = Tcl_DStringLength(baseString); line = Tcl_DStringAppend(baseString,p,maxBytes); - chunkPtr->clientData = (ClientData) ciPtr; + chunkPtr->clientData = ciPtr; ciPtr->baseChunkPtr = baseCharChunkPtr; ciPtr->baseOffset = lineOffset; ciPtr->chars = NULL; @@ -7427,7 +7630,7 @@ TkTextCharLayoutProc( } else { Tcl_DStringSetLength(baseString,lineOffset); } - ckfree((char *) ciPtr); + ckfree(ciPtr); #endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ return 0; } @@ -7453,9 +7656,8 @@ TkTextCharLayoutProc( chunkPtr->breakIndex = -1; #if !TK_LAYOUT_WITH_BASE_CHUNKS - ciPtr = (CharInfo *) - ckalloc((unsigned) bytesThatFit + Tk_Offset(CharInfo, chars) + 1); - chunkPtr->clientData = (ClientData) ciPtr; + ciPtr = ckalloc((Tk_Offset(CharInfo, chars) + 1) + bytesThatFit); + chunkPtr->clientData = ciPtr; memcpy(ciPtr->chars, p, (unsigned) bytesThatFit); #endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ @@ -7493,11 +7695,21 @@ TkTextCharLayoutProc( } else { for (count = bytesThatFit, p += bytesThatFit - 1; count > 0; count--, p--) { - if (UCHAR(*p) < 0x80 && isspace(UCHAR(*p))) { + /* + * Don't use isspace(); effects are unpredictable and can lead to + * odd word-wrapping problems on some platforms. Also don't use + * Tcl_UniCharIsSpace here either, as it identifies non-breaking + * spaces as places to break. What we actually want is only the + * ASCII space characters, so use them explicitly... + */ + + switch (*p) { + case '\t': case '\n': case '\v': case '\f': case '\r': case ' ': chunkPtr->breakIndex = count; - break; + goto checkForNextChunk; } } + checkForNextChunk: if ((bytesThatFit + byteOffset) == segPtr->size) { for (nextPtr = segPtr->nextPtr; nextPtr != NULL; nextPtr = nextPtr->nextPtr) { @@ -7557,7 +7769,7 @@ CharChunkMeasureChars( * here. */ { Tk_Font tkfont = chunkPtr->stylePtr->sValuePtr->tkfont; - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; + CharInfo *ciPtr = chunkPtr->clientData; #if !TK_LAYOUT_WITH_BASE_CHUNKS if (chars == NULL) { @@ -7570,7 +7782,7 @@ CharChunkMeasureChars( return MeasureChars(tkfont, chars, charsLen, start, end-start, startX, maxX, flags, nextXPtr); -#else +#else /* TK_LAYOUT_WITH_BASE_CHUNKS */ { int xDisplacement; int fit, bstart = start, bend = end; @@ -7610,7 +7822,7 @@ CharChunkMeasureChars( return fit - bstart; } } -#endif +#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ } /* @@ -7646,7 +7858,7 @@ CharDisplayProc( int screenY) /* Y-coordinate in text window that * corresponds to y. */ { - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; + CharInfo *ciPtr = chunkPtr->clientData; const char *string; TextStyle *stylePtr; StyleValues *sValuePtr; @@ -7664,7 +7876,7 @@ CharDisplayProc( } #if TK_DRAW_IN_CONTEXT - bciPtr = (BaseCharInfo *) ciPtr->baseChunkPtr->clientData; + bciPtr = ciPtr->baseChunkPtr->clientData; numBytes = Tcl_DStringLength(&bciPtr->baseChars); string = Tcl_DStringValue(&bciPtr->baseChars); @@ -7727,7 +7939,7 @@ CharDisplayProc( y + baseline - sValuePtr->offset); if (sValuePtr->underline) { - TkUnderlineCharsInContext(display, dst, stylePtr->fgGC, + TkUnderlineCharsInContext(display, dst, stylePtr->ulGC, sValuePtr->tkfont, string, numBytes, ciPtr->baseChunkPtr->x + xDisplacement, y + baseline - sValuePtr->offset, @@ -7737,7 +7949,7 @@ CharDisplayProc( Tk_FontMetrics fm; Tk_GetFontMetrics(sValuePtr->tkfont, &fm); - TkUnderlineCharsInContext(display, dst, stylePtr->fgGC, + TkUnderlineCharsInContext(display, dst, stylePtr->ovGC, sValuePtr->tkfont, string, numBytes, ciPtr->baseChunkPtr->x + xDisplacement, y + baseline - sValuePtr->offset @@ -7754,7 +7966,7 @@ CharDisplayProc( Tk_DrawChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, string, numBytes, offsetX, y + baseline - sValuePtr->offset); if (sValuePtr->underline) { - Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, + Tk_UnderlineChars(display, dst, stylePtr->ulGC, sValuePtr->tkfont, string, offsetX, y + baseline - sValuePtr->offset, 0, numBytes); @@ -7764,7 +7976,7 @@ CharDisplayProc( Tk_FontMetrics fm; Tk_GetFontMetrics(sValuePtr->tkfont, &fm); - Tk_UnderlineChars(display, dst, stylePtr->fgGC, sValuePtr->tkfont, + Tk_UnderlineChars(display, dst, stylePtr->ovGC, sValuePtr->tkfont, string, offsetX, y + baseline - sValuePtr->offset - fm.descent - (fm.ascent * 3) / 10, @@ -7797,7 +8009,7 @@ CharUndisplayProc( TkText *textPtr, /* Overall information about text widget. */ TkTextDispChunk *chunkPtr) /* Chunk that is about to be freed. */ { - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; + CharInfo *ciPtr = chunkPtr->clientData; if (ciPtr) { #if TK_LAYOUT_WITH_BASE_CHUNKS @@ -7824,7 +8036,7 @@ CharUndisplayProc( ciPtr->numBytes = 0; #endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ - ckfree((char *) ciPtr); + ckfree(ciPtr); chunkPtr->clientData = NULL; } } @@ -7900,7 +8112,7 @@ CharBboxProc( int *heightPtr) /* Gets filled in with height of character, in * pixels. */ { - CharInfo *ciPtr = (CharInfo *) chunkPtr->clientData; + CharInfo *ciPtr = chunkPtr->clientData; int maxX; maxX = chunkPtr->width + chunkPtr->x; @@ -8063,7 +8275,7 @@ AdjustForTab( if (chunkPtr2->displayProc != CharDisplayProc) { continue; } - ciPtr = (CharInfo *) chunkPtr2->clientData; + ciPtr = chunkPtr2->clientData; for (p = ciPtr->chars, i = 0; i < ciPtr->numBytes; p++, i++) { if (isdigit(UCHAR(*p))) { gotDigit = 1; @@ -8084,23 +8296,23 @@ AdjustForTab( if (decimalChunkPtr != NULL) { int curX; - ciPtr = (CharInfo *) decimalChunkPtr->clientData; + ciPtr = decimalChunkPtr->clientData; CharChunkMeasureChars(decimalChunkPtr, NULL, 0, 0, decimal, decimalChunkPtr->x, -1, 0, &curX); desired = tabX - (curX - x); goto update; - } else { - /* - * There wasn't a decimal point. Right justify the text. - */ + } - width = 0; - for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL; - chunkPtr2 = chunkPtr2->nextPtr) { - width += chunkPtr2->width; - } - desired = tabX - width; + /* + * There wasn't a decimal point. Right justify the text. + */ + + width = 0; + for (chunkPtr2 = chunkPtr->nextPtr; chunkPtr2 != NULL; + chunkPtr2 = chunkPtr2->nextPtr) { + width += chunkPtr2->width; } + desired = tabX - width; /* * Shift all of the chunks to the right so that the left edge is at the @@ -8338,7 +8550,7 @@ NextTabStop( static int MeasureChars( Tk_Font tkfont, /* Font in which to draw characters. */ - CONST char *source, /* Characters to be displayed. Need not be + const char *source, /* Characters to be displayed. Need not be * NULL-terminated. */ int maxBytes, /* Maximum # of bytes to consider from * source. */ @@ -8353,7 +8565,7 @@ MeasureChars( * here. */ { int curX, width, ch; - CONST char *special, *end, *start; + const char *special, *end, *start; ch = 0; /* lint. */ curX = startX; @@ -8400,11 +8612,10 @@ MeasureChars( break; } if (special < end) { - if (ch == '\t') { - start++; - } else { + if (ch != '\t') { break; } + start++; } } @@ -8445,19 +8656,19 @@ TextGetScrollInfoObj( Tcl_Interp *interp, /* Used for error reporting. */ TkText *textPtr, /* Information about the text widget. */ int objc, /* # arguments for command. */ - Tcl_Obj *CONST objv[], /* Arguments for command. */ + Tcl_Obj *const objv[], /* Arguments for command. */ double *dblPtr, /* Filled in with argument "moveto" option, if * any. */ int *intPtr) /* Filled in with number of pages or lines or * pixels to scroll, if any. */ { - static CONST char *subcommands[] = { + static const char *const subcommands[] = { "moveto", "scroll", NULL }; enum viewSubcmds { VIEW_MOVETO, VIEW_SCROLL }; - static CONST char *units[] = { + static const char *const units[] = { "units", "pages", "pixels", NULL }; enum viewUnits { @@ -8465,8 +8676,8 @@ TextGetScrollInfoObj( }; int index; - if (Tcl_GetIndexFromObj(interp, objv[2], subcommands, "option", 0, - &index) != TCL_OK) { + if (Tcl_GetIndexFromObjStruct(interp, objv[2], subcommands, + sizeof(char *), "option", 0, &index) != TCL_OK) { return TKTEXT_SCROLL_ERROR; } @@ -8485,8 +8696,8 @@ TextGetScrollInfoObj( Tcl_WrongNumArgs(interp, 3, objv, "number units|pages|pixels"); return TKTEXT_SCROLL_ERROR; } - if (Tcl_GetIndexFromObj(interp, objv[4], units, "argument", 0, - &index) != TCL_OK) { + if (Tcl_GetIndexFromObjStruct(interp, objv[4], units, + sizeof(char *), "argument", 0, &index) != TCL_OK) { return TKTEXT_SCROLL_ERROR; } switch ((enum viewUnits) index) { @@ -8564,7 +8775,7 @@ FinalizeBaseChunk( if (chunkPtr->displayProc != CharDisplayProc) { continue; } - ciPtr = (CharInfo *)chunkPtr->clientData; + ciPtr = chunkPtr->clientData; if (ciPtr->baseChunkPtr != baseCharChunkPtr) { break; } @@ -8581,7 +8792,7 @@ FinalizeBaseChunk( } if (addChunkPtr != NULL) { - ciPtr = (CharInfo *)addChunkPtr->clientData; + ciPtr = addChunkPtr->clientData; ciPtr->chars = baseChars + ciPtr->baseOffset; #if TK_DRAW_IN_CONTEXT @@ -8632,7 +8843,7 @@ FreeBaseChunk( if (chunkPtr->undisplayProc != CharUndisplayProc) { continue; } - ciPtr = (CharInfo *) chunkPtr->clientData; + ciPtr = chunkPtr->clientData; if (ciPtr->baseChunkPtr != baseChunkPtr) { break; } @@ -8641,7 +8852,9 @@ FreeBaseChunk( ciPtr->chars = NULL; } - Tcl_DStringFree(&((BaseCharInfo *) baseChunkPtr->clientData)->baseChars); + if (baseChunkPtr) { + Tcl_DStringFree(&((BaseCharInfo *) baseChunkPtr->clientData)->baseChars); + } } /* @@ -8750,14 +8963,14 @@ RemoveFromBaseChunk( * Reinstitute this base chunk for re-layout. */ - ciPtr = (CharInfo *) chunkPtr->clientData; + ciPtr = chunkPtr->clientData; baseCharChunkPtr = ciPtr->baseChunkPtr; /* * Remove the chunk data from the base chunk data. */ - bciPtr = (BaseCharInfo *) baseCharChunkPtr->clientData; + bciPtr = baseCharChunkPtr->clientData; if ((ciPtr->baseOffset + ciPtr->numBytes) != Tcl_DStringLength(&bciPtr->baseChars)) { |