From: Christian W. <Chr...@t-...> - 2025-04-01 20:26:03
|
Dear fellow readers of the core mailing list, after some playing with the text widget's -blockcursor option my conclusion is unfortunately, that it is almost unusable when turned on, at least when the default options of the text widget are in place, which is a very common use case. Rationale: the block cursor in its active state (INSERT_ON) draws a rectangle in the text widget's foreground color. Following that drawing the text is drawn in the text widget's foreground color resulting in a rectangle in the text widget's foreground color, i.e. without any information which was in place when the widget/cursor was in inactive (INSERT_OFF) state. This makes the block cursor indefinitely hiding the character under the cursor when the -insertofftime option is set to zero. Bluntly, the "-blockcursor 1" option is not usable at all since it's invention, BTW this was in 2003. Here is a POC how it can be remedied: ---8><--- --- old/tkTextDisp.c +++ new/tkTextDisp.c @@ -15,6 +15,7 @@ #include "tkInt.h" #include "tkText.h" +#include "tk3d.h" #if defined(_WIN32) && !defined(PLATFORM_SDL) #include "tkWinInt.h" @@ -2444,10 +2445,13 @@ * 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; + CharInfo ci; #ifndef TK_NO_DOUBLE_BUFFERING const int y = 0; #else @@ -2539,6 +2543,38 @@ * 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. + */ + + otherChunkPtr = &tmpChunk; + *otherChunkPtr = *(chunkPtr->nextPtr); + otherChunkPtr->undisplayProc = NULL; + otherChunkPtr->numBytes = 1; + tmpStyle = *otherChunkPtr->stylePtr; + otherChunkPtr->stylePtr = &tmpStyle; + tmpStyle.bgGC = None; + borderPtr = (TkBorder *) textPtr->border; + tmpStyle.fgGC = borderPtr->bgGC; + ci = *((CharInfo *) (otherChunkPtr->clientData)); + otherChunkPtr->clientData = (ClientData) &ci; + ci.numBytes = 1; + if ((ci.chars[0] == '\n') || + (ci.chars[0] == ' ') || (ci.chars[0] == '\t')) { + /* + * Ignore newline and other whitespace. + */ + + otherChunkPtr = NULL; + } + } continue; } @@ -2569,6 +2605,28 @@ display, pixmap, dlPtr->y + dlPtr->spaceAbove); } + if ((otherChunkPtr != NULL) && (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); + otherChunkPtr = NULL; + } + if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) { /* * A displayProc called in the loop above invoked a binding ---8><--- I've tested it in an X11 environment. No idea if this works in Win32 or MacOS. Cheers, Christian |