Index: generic/tkText.c ================================================================== --- generic/tkText.c +++ generic/tkText.c @@ -718,11 +718,11 @@ if (indexPtr == NULL) { result = TCL_ERROR; goto done; } if (TkTextIndexBbox(textPtr, indexPtr, &x, &y, &width, &height, - NULL) == 0) { + NULL, NULL) == 0) { Tcl_Obj *listObj = Tcl_NewListObj(0, NULL); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(x)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(y)); Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(width)); @@ -3731,16 +3731,17 @@ textPtr->insertBlinkHandler = Tcl_CreateTimerHandler( textPtr->insertOnTime, TextBlinkProc, textPtr); } redrawInsert: TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - if (TkTextIndexBbox(textPtr, &index, &x, &y, &w, &h, &charWidth) == 0) { + if (TkTextIndexBbox(textPtr, &index, &x, &y, &w, &h, + &charWidth, NULL) == 0) { int insertWidth; Tk_GetPixelsFromObj(NULL, textPtr->tkwin, textPtr->insertWidthObj, &insertWidth); if (textPtr->insertCursorType) { /* Block cursor */ - TkTextRedrawRegion(textPtr, x - textPtr->width / 2, y, + TkTextRedrawRegion(textPtr, x - insertWidth / 2, y, charWidth + insertWidth / 2, h); } else { /* I-beam cursor */ TkTextRedrawRegion(textPtr, x - insertWidth / 2, y, insertWidth, h); Index: generic/tkText.h ================================================================== --- generic/tkText.h +++ generic/tkText.h @@ -1033,11 +1033,12 @@ MODULE_SCOPE void TkTextBindProc(void *clientData, XEvent *eventPtr); MODULE_SCOPE void TkTextSelectionEvent(TkText *textPtr); MODULE_SCOPE int TkTextIndexBbox(TkText *textPtr, const TkTextIndex *indexPtr, int *xPtr, int *yPtr, - int *widthPtr, int *heightPtr, int *charWidthPtr); + int *widthPtr, int *heightPtr, int *charWidthPtr, + int *cursorWidthPtr); MODULE_SCOPE int TkTextCharLayoutProc(TkText *textPtr, TkTextIndex *indexPtr, TkTextSegment *segPtr, Tcl_Size offset, int maxX, Tcl_Size maxChars, int noBreakYet, TkWrapMode wrapMode, TkTextDispChunk *chunkPtr); MODULE_SCOPE void TkTextCreateDInfo(TkText *textPtr); Index: generic/tkTextDisp.c ================================================================== --- generic/tkTextDisp.c +++ generic/tkTextDisp.c @@ -13,10 +13,11 @@ * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include "tkText.h" +#include "tk3d.h" #ifdef _WIN32 #include "tkWinInt.h" #elif defined(__CYGWIN__) #include "tkUnixInt.h" @@ -2429,19 +2430,26 @@ * dlPtr is the top line. */ Pixmap pixmap) /* Pixmap to use for double-buffering. Caller * must make sure it's large enough to hold * line. */ { - TkTextDispChunk *chunkPtr; + TkTextDispChunk *chunkPtr, tmpChunk, *otherChunkPtr = NULL; TextDInfo *dInfoPtr = textPtr->dInfoPtr; Display *display; int height, y_off; + struct TextStyle tmpStyle; + TkBorder *borderPtr; #ifndef TK_NO_DOUBLE_BUFFERING const int y = 0; #else const int y = dlPtr->y; #endif /* TK_NO_DOUBLE_BUFFERING */ +#ifdef TK_LAYOUT_WITH_BASE_CHUNKS + BaseCharInfo bci; +#else + CharInfo ci; +#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ if (dlPtr->chunkPtr == NULL) return; display = Tk_Display(textPtr->tkwin); @@ -2523,10 +2531,78 @@ /* * Already displayed the insertion cursor above. Don't do it again * here. */ + if (textPtr->insertCursorType && + ((textPtr->flags & (GOT_FOCUS | INSERT_ON)) == + (GOT_FOCUS | INSERT_ON)) && + (chunkPtr->nextPtr != NULL) && + (chunkPtr->nextPtr->displayProc == CharDisplayProc) && + (chunkPtr->nextPtr->numBytes > 0)) { + /* + * Make a temporary chunk for displaying the text + * within the block cursor later on. + */ + XGCValues gcValues; + unsigned long mask; + int endX, numBytes, ix, iy, iw, ih; + int charWidth = 0, cursorWidth = 0; + TkTextIndex index; + +#ifdef TK_LAYOUT_WITH_BASE_CHUNKS + CharInfo *ciPtr; + BaseCharInfo *bciPtr; + Tcl_UniChar ch; + int chnum; + char buf[16]; +#endif + + otherChunkPtr = &tmpChunk; + *otherChunkPtr = *(chunkPtr->nextPtr); + TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); + TkTextIndexBbox(textPtr, &index, &ix, &iy, &iw, &ih, + &charWidth, &cursorWidth); + numBytes = CharChunkMeasureChars(otherChunkPtr, NULL, 0, + 0, -1, otherChunkPtr->x, + otherChunkPtr->x + cursorWidth, 0, &endX); + if (numBytes > 0) { + otherChunkPtr->undisplayProc = NULL; + tmpStyle = *otherChunkPtr->stylePtr; + otherChunkPtr->stylePtr = &tmpStyle; + tmpStyle.bgGC = None; + mask = GCFont; + gcValues.font = Tk_FontId(tmpStyle.sValuePtr->tkfont); + mask |= GCForeground; + borderPtr = (TkBorder *) textPtr->border; + gcValues.foreground = borderPtr->bgColorPtr->pixel; + tmpStyle.fgGC = Tk_GetGC(textPtr->tkwin, mask, &gcValues); +#ifdef TK_LAYOUT_WITH_BASE_CHUNKS + ciPtr = (CharInfo *) otherChunkPtr->clientData; + bciPtr = (BaseCharInfo *) ciPtr->baseChunkPtr->clientData; + bci.ci = *ciPtr; + Tcl_DStringInit(&bci.baseChars); + bci.width = -1; + Tcl_DStringAppend(&bci.baseChars, + Tcl_DStringValue(&bciPtr->baseChars) + + bci.ci.baseOffset, numBytes); + bci.ci.baseOffset = 0; + bci.ci.numBytes = Tcl_DStringLength(&bci.baseChars); + bci.ci.chars = Tcl_DStringValue(&bci.baseChars); + bci.ci.baseChunkPtr = otherChunkPtr; + otherChunkPtr->clientData = (ClientData) &bci; + otherChunkPtr->numBytes = bci.ci.numBytes; +#else + ci = *((CharInfo *) (otherChunkPtr->clientData)); + otherChunkPtr->clientData = (ClientData) &ci; + ci.numBytes = numBytes; + otherChunkPtr->numBytes = ci.numBytes; +#endif /* TK_LAYOUT_WITH_BASE_CHUNKS */ + } else { + otherChunkPtr = NULL; + } + } continue; } /* * Don't call if elide. This tax OK since not very many visible DLines @@ -2552,10 +2628,41 @@ chunkPtr->displayProc(textPtr, chunkPtr, x, y + dlPtr->spaceAbove, dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow, dlPtr->baseline - dlPtr->spaceAbove, display, pixmap, dlPtr->y + dlPtr->spaceAbove); } + + if (otherChunkPtr != NULL) { + if ((textPtr->tkwin != NULL) && !(textPtr->flags & DESTROYED)) { + /* + * Draw text within the block cursor. + */ + + int x = otherChunkPtr->x + dInfoPtr->x - + dInfoPtr->curXPixelOffset; + + if ((x + otherChunkPtr->width <= 0) || (x >= dInfoPtr->maxX)) { + /* + * See note above. + */ + + x = -otherChunkPtr->width; + } + otherChunkPtr->displayProc(textPtr, otherChunkPtr, x, + y + dlPtr->spaceAbove, dlPtr->height - + dlPtr->spaceAbove - dlPtr->spaceBelow, + dlPtr->baseline - dlPtr->spaceAbove, + display, pixmap, dlPtr->y + dlPtr->spaceAbove); + } + if (otherChunkPtr->stylePtr->fgGC != NULL) { + Tk_FreeGC(textPtr->display, otherChunkPtr->stylePtr->fgGC); + } +#ifdef TK_LAYOUT_WITH_BASE_CHUNKS + Tcl_DStringFree(&bci.baseChars); +#endif + otherChunkPtr = NULL; + } if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* * A displayProc called in the loop above invoked a binding * that caused the widget to be deleted. Don't do anything. @@ -7361,20 +7468,29 @@ const TkTextIndex *indexPtr,/* Index whose bounding box is desired. */ int *xPtr, int *yPtr, /* Filled with index's upper-left * coordinate. */ int *widthPtr, int *heightPtr, /* Filled in with index's dimensions. */ - int *charWidthPtr) /* If the 'index' is at the end of a display + int *charWidthPtr, /* If the 'index' is at the end of a display * line and therefore takes up a very large * width, this is used to return the smaller * width actually desired by the index. */ + int *cursorWidthPtr) /* Receives same value as 'charWidthPtr' + * except for the text index pointing to + * a Tab which gets reduced to the width of + * a single space. */ { TextDInfo *dInfoPtr = textPtr->dInfoPtr; DLine *dlPtr; TkTextDispChunk *chunkPtr; Tcl_Size byteCount; + int dummy; + if (charWidthPtr == NULL) { + charWidthPtr = &dummy; + } + /* * Make sure that all of the screen layout information is up to date. */ if (dInfoPtr->flags & DINFO_OUT_OF_DATE) { @@ -7435,24 +7551,20 @@ /* * Last character in display line. Give it all the space up to the * line. */ - if (charWidthPtr != NULL) { - *charWidthPtr = dInfoPtr->maxX - *xPtr; - if (*charWidthPtr > textPtr->charWidth) { - *charWidthPtr = textPtr->charWidth; - } + *charWidthPtr = dInfoPtr->maxX - *xPtr; + if (*charWidthPtr > textPtr->charWidth) { + *charWidthPtr = textPtr->charWidth; } if (*xPtr > dInfoPtr->maxX) { *xPtr = dInfoPtr->maxX; } *widthPtr = dInfoPtr->maxX - *xPtr; } else { - if (charWidthPtr != NULL) { - *charWidthPtr = *widthPtr; - } + *charWidthPtr = *widthPtr; } if (*widthPtr == 0) { /* * With zero width (e.g. elided text) we just need to make sure it is * onscreen, where the '=' case here is ok. @@ -7475,10 +7587,33 @@ if ((*yPtr + *heightPtr) > dInfoPtr->maxY) { *heightPtr = dInfoPtr->maxY - *yPtr; if (*heightPtr <= 0) { return -1; } + } + /* + * Display a block cursor on a tab with whitespace width + */ + + if (cursorWidthPtr != NULL) { + *cursorWidthPtr = *charWidthPtr; + if (chunkPtr->bboxProc == CharBboxProc) { + CharInfo *ciPtr = (CharInfo *)chunkPtr->clientData; +#ifdef TK_LAYOUT_WITH_BASE_CHUNKS + BaseCharInfo *bciPtr = + (BaseCharInfo *)ciPtr->baseChunkPtr->clientData; + char *chars = Tcl_DStringValue(&bciPtr->baseChars); + + if (chars[ciPtr->baseOffset + byteCount] == '\t') +#else + if (ciPtr->chars[byteCount] == '\t') +#endif + { + CharChunkMeasureChars(chunkPtr, " ", 1, 0, 1, + 0, -1, 0, cursorWidthPtr); + } + } } return 0; } /* Index: generic/tkTextMark.c ================================================================== --- generic/tkTextMark.c +++ generic/tkTextMark.c @@ -623,19 +623,21 @@ /* TkText *textPtr = chunkPtr->clientData; */ TkTextIndex index; int halfWidth, insertWidth, insertBorderWidth; int rightSideWidth; - int ix = 0, iy = 0, iw = 0, ih = 0, charWidth = 0; + int ix = 0, iy = 0, iw = 0, ih = 0, charWidth = 0, cursorWidth = 0; Tk_GetPixelsFromObj(NULL, textPtr->tkwin, textPtr->insertWidthObj, &insertWidth); Tk_GetPixelsFromObj(NULL, textPtr->tkwin, textPtr->insertBorderWidthObj, &insertBorderWidth); halfWidth = insertWidth/2; if (textPtr->insertCursorType) { TkTextMarkSegToIndex(textPtr, textPtr->insertMarkPtr, &index); - TkTextIndexBbox(textPtr, &index, &ix, &iy, &iw, &ih, &charWidth); + TkTextIndexBbox(textPtr, &index, &ix, &iy, &iw, &ih, &charWidth, + &cursorWidth); rightSideWidth = charWidth + halfWidth; + charWidth = cursorWidth; } else { rightSideWidth = halfWidth; } if ((x + rightSideWidth) < 0) {