summaryrefslogtreecommitdiffstats
path: root/generic
diff options
context:
space:
mode:
Diffstat (limited to 'generic')
-rw-r--r--generic/tkBind.c50
-rw-r--r--generic/tkBitmap.c2
-rw-r--r--generic/tkEntry.c4
-rw-r--r--generic/tkFont.c2
-rw-r--r--generic/tkGrid.c4
-rw-r--r--generic/tkInt.decls3
-rw-r--r--generic/tkIntPlatDecls.h11
-rw-r--r--generic/tkStubInit.c1
-rw-r--r--generic/tkText.c53
-rw-r--r--generic/tkText.h3
-rw-r--r--generic/tkTextBTree.c17
-rw-r--r--generic/tkTextDisp.c586
-rw-r--r--generic/tkTextIndex.c91
-rw-r--r--generic/ttk/ttkLabel.c2
14 files changed, 583 insertions, 246 deletions
diff --git a/generic/tkBind.c b/generic/tkBind.c
index 8d20fa9..c4f8226 100644
--- a/generic/tkBind.c
+++ b/generic/tkBind.c
@@ -16,9 +16,9 @@
#ifdef __WIN32__
#include "tkWinInt.h"
-#endif
-
-#if !(defined(__WIN32__) || defined(MAC_OSX_TK)) /* UNIX */
+#elif defined(MAC_OSX_TK)
+#include "tkMacOSXInt.h"
+#else
#include "tkUnixInt.h"
#endif
@@ -156,7 +156,7 @@ typedef struct PatternTableKey {
* events as part of the process of converting X events into Tcl commands.
*/
-typedef struct Pattern {
+typedef struct TkPattern {
int eventType; /* Type of X event, e.g. ButtonPress. */
int needMods; /* Mask of modifiers that must be present (0
* means no modifiers are required). */
@@ -170,7 +170,7 @@ typedef struct Pattern {
* button (0 means any buttons are OK). For
* virtual events, specifies the Tk_Uid of the
* virtual event name (never 0). */
-} Pattern;
+} TkPattern;
/*
* The following structure defines a pattern sequence, which consists of one
@@ -223,7 +223,7 @@ typedef struct PatSeq {
* for end of list). Needed to implement
* Tk_DeleteAllBindings. In a virtual event
* table, always NULL. */
- Pattern pats[1]; /* Array of "numPats" patterns. Only one
+ TkPattern pats[1]; /* Array of "numPats" patterns. Only one
* element is declared here but in actuality
* enough space will be allocated for
* "numPats" patterns. To match, pats[0] must
@@ -660,7 +660,8 @@ static int DeleteVirtualEvent(Tcl_Interp *interp,
char *eventString);
static void DeleteVirtualEventTable(VirtualEventTable *vetPtr);
static void ExpandPercents(TkWindow *winPtr, const char *before,
- XEvent *eventPtr,KeySym keySym,Tcl_DString *dsPtr);
+ XEvent *eventPtr,KeySym keySym,
+ unsigned int scriptCount, Tcl_DString *dsPtr);
static void FreeTclBinding(ClientData clientData);
static PatSeq * FindSequence(Tcl_Interp *interp,
Tcl_HashTable *patternTablePtr, ClientData object,
@@ -684,7 +685,7 @@ static PatSeq * MatchPatterns(TkDisplay *dispPtr,
static int NameToWindow(Tcl_Interp *interp, Tk_Window main,
Tcl_Obj *objPtr, Tk_Window *tkwinPtr);
static int ParseEventDescription(Tcl_Interp *interp,
- const char **eventStringPtr, Pattern *patPtr,
+ const char **eventStringPtr, TkPattern *patPtr,
unsigned long *eventMaskPtr);
static void DoWarp(ClientData clientData);
@@ -1415,6 +1416,7 @@ Tk_BindEvent(
PatSeq *vMatchDetailList, *vMatchNoDetailList;
int flags, oldScreen, i, deferModal;
unsigned int matchCount, matchSpace;
+ unsigned int scriptCount;
Tcl_Interp *interp;
Tcl_DString scripts, savedResult;
Detail detail;
@@ -1571,6 +1573,7 @@ Tk_BindEvent(
pendingPtr = &staticPending;
matchCount = 0;
+ scriptCount = 0;
matchSpace = sizeof(staticPending.matchArray) / sizeof(PatSeq *);
Tcl_DStringInit(&scripts);
@@ -1628,7 +1631,7 @@ Tk_BindEvent(
}
if (sourcePtr->eventProc == EvalTclBinding) {
ExpandPercents(winPtr, (char *) sourcePtr->clientData,
- eventPtr, detail.keySym, &scripts);
+ eventPtr, detail.keySym, scriptCount++, &scripts);
} else {
if (matchCount >= matchSpace) {
PendingBinding *newPtr;
@@ -1957,7 +1960,7 @@ MatchPatterns(
for ( ; psPtr != NULL; psPtr = psPtr->nextSeqPtr) {
XEvent *eventPtr = &bindPtr->eventRing[bindPtr->curEvent];
Detail *detailPtr = &bindPtr->detailRing[bindPtr->curEvent];
- Pattern *patPtr = psPtr->pats;
+ TkPattern *patPtr = psPtr->pats;
Window window = eventPtr->xany.window;
int patCount, ringCount, flags, state, modMask, i;
@@ -2171,7 +2174,7 @@ MatchPatterns(
*/
if (bestPtr != NULL) {
- Pattern *patPtr2;
+ TkPattern *patPtr2;
if (matchPtr->numPats != bestPtr->numPats) {
if (bestPtr->numPats > matchPtr->numPats) {
@@ -2259,6 +2262,8 @@ ExpandPercents(
* in % replacements. */
KeySym keySym, /* KeySym: only relevant for KeyPress and
* KeyRelease events). */
+ unsigned int scriptCount, /* The number of script-based binding patterns
+ * matched so far for this event. */
Tcl_DString *dsPtr) /* Dynamic string in which to append new
* command. */
{
@@ -2540,6 +2545,9 @@ ExpandPercents(
}
}
goto doString;
+ case 'M':
+ number = scriptCount;
+ goto doNumber;
case 'N':
if ((flags & KEY) && (eventPtr->type != MouseWheelEvent)) {
number = (int) keySym;
@@ -3251,7 +3259,7 @@ HandleEventGenerate(
char *name, *windowName;
int count, flags, synch, i, number, warp;
Tcl_QueuePosition pos;
- Pattern pat;
+ TkPattern pat;
Tk_Window tkwin, tkwin2;
TkWindow *mainPtr;
unsigned long eventMask;
@@ -3953,10 +3961,10 @@ FindSequence(
unsigned long *maskPtr) /* *maskPtr is filled in with the event types
* on which this pattern sequence depends. */
{
- Pattern pats[EVENT_BUFFER_SIZE];
+ TkPattern pats[EVENT_BUFFER_SIZE];
int numPats, virtualFound;
const char *p;
- Pattern *patPtr;
+ TkPattern *patPtr;
PatSeq *psPtr;
Tcl_HashEntry *hPtr;
int flags, count, isNew;
@@ -4036,7 +4044,7 @@ FindSequence(
key.type = patPtr->eventType;
key.detail = patPtr->detail;
hPtr = Tcl_CreateHashEntry(patternTablePtr, (char *) &key, &isNew);
- sequenceSize = numPats*sizeof(Pattern);
+ sequenceSize = numPats*sizeof(TkPattern);
if (!isNew) {
for (psPtr = (PatSeq *) Tcl_GetHashValue(hPtr); psPtr != NULL;
psPtr = psPtr->nextSeqPtr) {
@@ -4064,7 +4072,7 @@ FindSequence(
return NULL;
}
psPtr = (PatSeq *) ckalloc((unsigned) (sizeof(PatSeq)
- + (numPats-1)*sizeof(Pattern)));
+ + (numPats-1)*sizeof(TkPattern)));
psPtr->numPats = numPats;
psPtr->eventProc = NULL;
psPtr->freeProc = NULL;
@@ -4111,7 +4119,7 @@ ParseEventDescription(
const char **eventStringPtr,/* On input, holds a pointer to start of event
* string. On exit, gets pointer to rest of
* string after parsed event. */
- Pattern *patPtr, /* Filled with the pattern parsed from the
+ TkPattern *patPtr, /* Filled with the pattern parsed from the
* event string. */
unsigned long *eventMaskPtr)/* Filled with event mask of matched event. */
{
@@ -4389,7 +4397,7 @@ GetPatternString(
PatSeq *psPtr,
Tcl_DString *dsPtr)
{
- Pattern *patPtr;
+ TkPattern *patPtr;
char c, buffer[TCL_INTEGER_SPACE];
int patsLeft, needMods;
ModInfo *modPtr;
@@ -4439,15 +4447,15 @@ GetPatternString(
if ((psPtr->flags & PAT_NEARBY) && (patsLeft > 1)
&& (memcmp((char *) patPtr, (char *) (patPtr-1),
- sizeof(Pattern)) == 0)) {
+ sizeof(TkPattern)) == 0)) {
patsLeft--;
patPtr--;
if ((patsLeft > 1) && (memcmp((char *) patPtr,
- (char *) (patPtr-1), sizeof(Pattern)) == 0)) {
+ (char *) (patPtr-1), sizeof(TkPattern)) == 0)) {
patsLeft--;
patPtr--;
if ((patsLeft > 1) && (memcmp((char *) patPtr,
- (char *) (patPtr-1), sizeof(Pattern)) == 0)) {
+ (char *) (patPtr-1), sizeof(TkPattern)) == 0)) {
patsLeft--;
patPtr--;
Tcl_DStringAppend(dsPtr, "Quadruple-", 10);
diff --git a/generic/tkBitmap.c b/generic/tkBitmap.c
index 09545d6..f7df546 100644
--- a/generic/tkBitmap.c
+++ b/generic/tkBitmap.c
@@ -304,7 +304,7 @@ GetBitmap(
TkBitmap *bitmapPtr, *existingBitmapPtr;
TkPredefBitmap *predefPtr;
Pixmap bitmap;
- int isNew, width, height, dummy2;
+ int isNew, width = 0, height = 0, dummy2;
TkDisplay *dispPtr = ((TkWindow *) tkwin)->dispPtr;
ThreadSpecificData *tsdPtr = (ThreadSpecificData *)
Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));
diff --git a/generic/tkEntry.c b/generic/tkEntry.c
index 816b7fa..6683cdc 100644
--- a/generic/tkEntry.c
+++ b/generic/tkEntry.c
@@ -1330,7 +1330,7 @@ ConfigureEntry(
double dvalue;
- if (sscanf(entryPtr->string, "%lf", &dvalue) == 0) {
+ if (sscanf(entryPtr->string, "%lf", &dvalue) <= 0) {
/* Scan failure */
dvalue = sbPtr->fromValue;
} else {
@@ -4231,7 +4231,7 @@ SpinboxInvoke(
} else if (!DOUBLES_EQ(sbPtr->fromValue, sbPtr->toValue)) {
double dvalue;
- if (sscanf(entryPtr->string, "%lf", &dvalue) == 0) {
+ if (sscanf(entryPtr->string, "%lf", &dvalue) <= 0) {
/*
* If the string doesn't scan as a double value, just
* use the -from value
diff --git a/generic/tkFont.c b/generic/tkFont.c
index 9eaaf94..5d2ad43 100644
--- a/generic/tkFont.c
+++ b/generic/tkFont.c
@@ -3015,7 +3015,6 @@ ConfigAttributesObj(
for (i = 0; i < objc; i += 2) {
optionPtr = objv[i];
- valuePtr = objv[i + 1];
if (Tcl_GetIndexFromObj(interp, optionPtr, fontOpt, "option", 1,
&index) != TCL_OK) {
@@ -3034,6 +3033,7 @@ ConfigAttributesObj(
}
return TCL_ERROR;
}
+ valuePtr = objv[i + 1];
switch (index) {
case FONT_FAMILY:
diff --git a/generic/tkGrid.c b/generic/tkGrid.c
index c6a00d5..ccdde19 100644
--- a/generic/tkGrid.c
+++ b/generic/tkGrid.c
@@ -1991,7 +1991,7 @@ ResolveConstraints(
if (slavePtr->numCols > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
- } else {
+ } else if (rightEdge >= 0) {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
@@ -2010,7 +2010,7 @@ ResolveConstraints(
if (slavePtr->numRows > 1) {
slavePtr->binNextPtr = layoutPtr[rightEdge].binNextPtr;
layoutPtr[rightEdge].binNextPtr = slavePtr;
- } else {
+ } else if (rightEdge >= 0) {
int size = slavePtr->size + layoutPtr[rightEdge].pad;
if (size > layoutPtr[rightEdge].minSize) {
diff --git a/generic/tkInt.decls b/generic/tkInt.decls
index 17f39ba..ab56bed 100644
--- a/generic/tkInt.decls
+++ b/generic/tkInt.decls
@@ -971,6 +971,9 @@ declare 53 aqua {
declare 54 aqua {
void *TkMacOSXDrawable(Drawable drawable)
}
+declare 55 aqua {
+ int TkpScanWindowId(Tcl_Interp *interp, const char *string, Window *idPtr)
+}
##############################################################################
diff --git a/generic/tkIntPlatDecls.h b/generic/tkIntPlatDecls.h
index 9b800f3..b377173 100644
--- a/generic/tkIntPlatDecls.h
+++ b/generic/tkIntPlatDecls.h
@@ -531,6 +531,12 @@ EXTERN unsigned long TkpGetMS(void);
/* 54 */
EXTERN VOID * TkMacOSXDrawable(Drawable drawable);
#endif
+#ifndef TkpScanWindowId_TCL_DECLARED
+#define TkpScanWindowId_TCL_DECLARED
+/* 55 */
+EXTERN int TkpScanWindowId(Tcl_Interp *interp,
+ CONST char *string, Window *idPtr);
+#endif
#endif /* AQUA */
#if !(defined(__WIN32__) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
#ifndef TkCreateXEventSource_TCL_DECLARED
@@ -716,6 +722,7 @@ typedef struct TkIntPlatStubs {
VOID *reserved52;
unsigned long (*tkpGetMS) (void); /* 53 */
VOID * (*tkMacOSXDrawable) (Drawable drawable); /* 54 */
+ int (*tkpScanWindowId) (Tcl_Interp *interp, CONST char *string, Window *idPtr); /* 55 */
#endif /* AQUA */
#if !(defined(__WIN32__) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
void (*tkCreateXEventSource) (void); /* 0 */
@@ -1127,6 +1134,10 @@ extern TkIntPlatStubs *tkIntPlatStubsPtr;
#define TkMacOSXDrawable \
(tkIntPlatStubsPtr->tkMacOSXDrawable) /* 54 */
#endif
+#ifndef TkpScanWindowId
+#define TkpScanWindowId \
+ (tkIntPlatStubsPtr->tkpScanWindowId) /* 55 */
+#endif
#endif /* AQUA */
#if !(defined(__WIN32__) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
#ifndef TkCreateXEventSource
diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c
index 79edc4d..3ee54dd 100644
--- a/generic/tkStubInit.c
+++ b/generic/tkStubInit.c
@@ -591,6 +591,7 @@ TkIntPlatStubs tkIntPlatStubs = {
NULL, /* 52 */
TkpGetMS, /* 53 */
TkMacOSXDrawable, /* 54 */
+ TkpScanWindowId, /* 55 */
#endif /* AQUA */
#if !(defined(__WIN32__) || defined(__CYGWIN__) || defined(MAC_OSX_TK)) /* X11 */
TkCreateXEventSource, /* 0 */
diff --git a/generic/tkText.c b/generic/tkText.c
index f3e1c26..139e71d 100644
--- a/generic/tkText.c
+++ b/generic/tkText.c
@@ -871,7 +871,7 @@ TextWidgetObjCmd(
} else if (c == 'd' && (length > 8)
&& !strncmp("-displaylines", option, (unsigned) length)) {
TkTextLine *fromPtr, *lastPtr;
- TkTextIndex index;
+ TkTextIndex index, index2;
int compare = TkTextIndexCmp(indexFromPtr, indexToPtr);
value = 0;
@@ -906,35 +906,44 @@ TextWidgetObjCmd(
/*
* We're going to count up all display lines in the logical
* line of 'indexFromPtr' up to, but not including the logical
- * line of 'indexToPtr', and then subtract off what we didn't
- * want from 'from' and add on what we didn't count from 'to.
+ * line of 'indexToPtr' (except if this line is elided), and
+ * then subtract off what came in too much from elided lines,
+ * also subtract off what we didn't want from 'from' and add
+ * on what we didn't count from 'to'.
*/
- while (index.linePtr != indexToPtr->linePtr) {
- value += TkTextUpdateOneLine(textPtr, fromPtr,0,&index,0);
-
- /*
- * We might have skipped past indexToPtr, if we have
- * multiple logical lines in a single display line.
- */
- if (TkTextIndexCmp(&index,indexToPtr) > 0) {
- break;
- }
+ while (TkTextIndexCmp(&index,indexToPtr) < 0) {
+ value += TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
}
- /*
- * Now we need to adjust the count to add on the number of
- * display lines in the last logical line, and subtract off
- * the number of display lines overcounted in the first
- * logical line. This logic is still ok if both indices are in
- * the same logical line.
- */
+ index2 = index;
+
+ /*
+ * Now we need to adjust the count to:
+ * - subtract off the number of display lines between
+ * indexToPtr and index2, since we might have skipped past
+ * indexToPtr, if we have several logical lines in a
+ * single display line
+ * - subtract off the number of display lines overcounted
+ * in the first logical line
+ * - add on the number of display lines in the last logical
+ * line
+ * This logic is still ok if both indexFromPtr and indexToPtr
+ * are in the same logical line.
+ */
+ index = *indexToPtr;
+ index.byteIndex = 0;
+ while (TkTextIndexCmp(&index,&index2) < 0) {
+ value -= TkTextUpdateOneLine(textPtr, index.linePtr,
+ 0, &index, 0);
+ }
index.linePtr = indexFromPtr->linePtr;
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (index.byteIndex >= indexFromPtr->byteIndex) {
+ if (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
@@ -946,7 +955,7 @@ TextWidgetObjCmd(
index.byteIndex = 0;
while (1) {
TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
- if (index.byteIndex >= indexToPtr->byteIndex) {
+ if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
break;
}
TkTextIndexForwBytes(textPtr, &index, 1, &index);
diff --git a/generic/tkText.h b/generic/tkText.h
index 4ffdc8a..6f5f153 100644
--- a/generic/tkText.h
+++ b/generic/tkText.h
@@ -1071,6 +1071,9 @@ MODULE_SCOPE void TkTextIndexBackChars(const TkText *textPtr,
TkTextIndex *dstPtr, TkTextCountType type);
MODULE_SCOPE int TkTextIndexCmp(const TkTextIndex *index1Ptr,
const TkTextIndex *index2Ptr);
+MODULE_SCOPE int TkTextIndexCountBytes(const TkText *textPtr,
+ const TkTextIndex *index1Ptr,
+ const TkTextIndex *index2Ptr);
MODULE_SCOPE int TkTextIndexCount(const TkText *textPtr,
const TkTextIndex *index1Ptr,
const TkTextIndex *index2Ptr,
diff --git a/generic/tkTextBTree.c b/generic/tkTextBTree.c
index 67ff79d..36f0ef3 100644
--- a/generic/tkTextBTree.c
+++ b/generic/tkTextBTree.c
@@ -1882,8 +1882,7 @@ TkBTreePreviousLine(
* number of pixels in the widget.
*
* Results:
- * The result is the index of linePtr within the tree, where 0
- * corresponds to the first line in the tree.
+ * The result is the pixel height of the top of the given line.
*
* Side effects:
* None.
@@ -3616,20 +3615,6 @@ TkTextIsElided(
infoPtr->elidePriority = -1;
for (i = infoPtr->numTags-1; i >=0; i--) {
if (infoPtr->tagCnts[i] & 1) {
- /*
- * Who would make the selection elided?
- */
-
- if ((tagPtr == textPtr->selTagPtr)
- && !(textPtr->flags & GOT_FOCUS)
- && (textPtr->inactiveSelBorder == NULL
-#ifdef MAC_OSX_TK
- /* Don't show inactive selection in disabled widgets. */
- || textPtr->state == TK_TEXT_STATE_DISABLED
-#endif
- )) {
- continue;
- }
infoPtr->elide = infoPtr->tagPtrs[i]->elide;
/*
diff --git a/generic/tkTextDisp.c b/generic/tkTextDisp.c
index 548e47e..3edd5dc 100644
--- a/generic/tkTextDisp.c
+++ b/generic/tkTextDisp.c
@@ -243,7 +243,8 @@ typedef struct DLine {
* top to bottom. Note: the next DLine doesn't
* always correspond to the next line of text:
* (a) can have multiple DLines for one text
- * line, and (b) can have gaps where DLine's
+ * line (wrapping), (b) can have elided newlines,
+ * and (c) can have gaps where DLine's
* have been deleted because they're out of
* date. */
int flags; /* Various flag bits: see below for values. */
@@ -542,7 +543,8 @@ static void DisplayDLine(TkText *textPtr, DLine *dlPtr,
static void DisplayLineBackground(TkText *textPtr, DLine *dlPtr,
DLine *prevPtr, Pixmap pixmap);
static void DisplayText(ClientData clientData);
-static DLine * FindDLine(DLine *dlPtr, CONST TkTextIndex *indexPtr);
+static DLine * FindDLine(TkText *textPtr, DLine *dlPtr,
+ CONST TkTextIndex *indexPtr);
static void FreeDLines(TkText *textPtr, DLine *firstPtr,
DLine *lastPtr, int action);
static void FreeStyle(TkText *textPtr, TextStyle *stylePtr);
@@ -589,6 +591,8 @@ static int TextGetScrollInfoObj(Tcl_Interp *interp,
int *intPtr);
static void AsyncUpdateLineMetrics(ClientData clientData);
static void AsyncUpdateYScrollbar(ClientData clientData);
+static int IsStartOfNotMergedLine(TkText *textPtr,
+ CONST TkTextIndex *indexPtr);
/*
* Result values returned by TextGetScrollInfoObj:
@@ -1758,7 +1762,7 @@ UpdateDisplayInfo(
*/
index = textPtr->topIndex;
- dlPtr = FindDLine(dInfoPtr->dLinePtr, &index);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
if ((dlPtr != NULL) && (dlPtr != dInfoPtr->dLinePtr)) {
FreeDLines(textPtr, dInfoPtr->dLinePtr, dlPtr, DLINE_UNLINK);
}
@@ -3381,7 +3385,7 @@ TkTextFindDisplayLineEnd(
* of the original index within its display
* line. */
{
- if (!end && indexPtr->byteIndex == 0) {
+ if (!end && IsStartOfNotMergedLine(textPtr, indexPtr)) {
/*
* Nothing to do.
*/
@@ -3460,8 +3464,9 @@ TkTextFindDisplayLineEnd(
* this now.
*/
- *xOffset = DlineXOfIndex(textPtr, dlPtr,
- indexPtr->byteIndex - dlPtr->index.byteIndex);
+ *xOffset = DlineXOfIndex(textPtr, dlPtr,
+ TkTextIndexCountBytes(textPtr, &dlPtr->index,
+ indexPtr));
}
if (end) {
/*
@@ -3531,6 +3536,27 @@ CalculateDisplayLineHeight(
DLine *dlPtr;
int pixelHeight;
+ if (tkTextDebug) {
+ int oldtkTextDebug = tkTextDebug;
+ /*
+ * Check that the indexPtr we are given really is at the start of a
+ * display line. The gymnastics with tkTextDebug is to prevent
+ * failure of a test suite test, that checks that lines are rendered
+ * exactly once. TkTextFindDisplayLineEnd is used here for checking
+ * indexPtr but it calls LayoutDLine/FreeDLine which makes the
+ * counting wrong. The debug mode shall therefore be switched off
+ * when calling TkTextFindDisplayLineEnd.
+ */
+
+ TkTextIndex indexPtr2 = *indexPtr;
+ tkTextDebug = 0;
+ TkTextFindDisplayLineEnd(textPtr, &indexPtr2, 0, NULL);
+ tkTextDebug = oldtkTextDebug;
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) != 0) {
+ Tcl_Panic("CalculateDisplayLineHeight called with bad indexPtr");
+ }
+ }
+
/*
* Special case for artificial last line. May be better to move this
* inside LayoutDLine.
@@ -3597,26 +3623,44 @@ TkTextIndexYPixels(
{
int pixelHeight;
TkTextIndex index;
+ int alreadyStartOfLine = 1;
- pixelHeight = TkBTreePixelsTo(textPtr, indexPtr->linePtr);
+ /*
+ * Find the index denoting the closest position being at the same time
+ * the start of a logical line above indexPtr and the start of a display
+ * line.
+ */
+
+ index = *indexPtr;
+ while (1) {
+ TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
+ if (index.byteIndex == 0) {
+ break;
+ }
+ TkTextIndexBackBytes(textPtr, &index, 1, &index);
+ alreadyStartOfLine = 0;
+ }
+
+ pixelHeight = TkBTreePixelsTo(textPtr, index.linePtr);
/*
- * Iterate through all display-lines corresponding to the single logical
- * line belonging to indexPtr, adding up the pixel height of each such
- * display line as we go along, until we go past 'indexPtr'.
+ * Shortcut to avoid layout of a superfluous display line. We know there
+ * is nothing more to add up to the height if the index we were given was
+ * already on the first display line of a logical line.
*/
- if (indexPtr->byteIndex == 0) {
- return pixelHeight;
+ if (alreadyStartOfLine) {
+ return pixelHeight;
}
- index.tree = textPtr->sharedTextPtr->tree;
- index.linePtr = indexPtr->linePtr;
- index.byteIndex = 0;
- index.textPtr = NULL;
+ /*
+ * Iterate through display lines, starting at the logical line belonging
+ * to index, adding up the pixel height of each such display line as we
+ * go along, until we go past 'indexPtr'.
+ */
while (1) {
- int bytes, height;
+ int bytes, height, compare;
/*
* Currently this call doesn't have many side-effects. However, if in
@@ -3628,9 +3672,10 @@ TkTextIndexYPixels(
height = CalculateDisplayLineHeight(textPtr, &index, &bytes, NULL);
- index.byteIndex += bytes;
+ TkTextIndexForwBytes(textPtr, &index, bytes, &index);
- if (index.byteIndex > indexPtr->byteIndex) {
+ compare = TkTextIndexCmp(&index,indexPtr);
+ if (compare > 0) {
return pixelHeight;
}
@@ -3638,7 +3683,7 @@ TkTextIndexYPixels(
pixelHeight += height;
}
- if (index.byteIndex == indexPtr->byteIndex) {
+ if (compare == 0) {
return pixelHeight;
}
}
@@ -3702,10 +3747,26 @@ TkTextUpdateOneLine(
}
/*
+ * CalculateDisplayLineHeight _must_ be called (below) with an index at
+ * the beginning of a display line. Force this to happen. This is needed
+ * when TkTextUpdateOneLine is called with a line that is merged with its
+ * previous line: the number of merged logical lines in a display line is
+ * calculated correctly only when CalculateDisplayLineHeight receives
+ * an index at the beginning of a display line. In turn this causes the
+ * merged lines to receive their correct zero pixel height in
+ * TkBTreeAdjustPixelHeight.
+ */
+
+ TkTextFindDisplayLineEnd(textPtr, indexPtr, 0, NULL);
+ linePtr = indexPtr->linePtr;
+
+ /*
* Iterate through all display-lines corresponding to the single logical
- * line 'linePtr', adding up the pixel height of each such display line as
- * we go along. The final total is, therefore, the height of the logical
- * line.
+ * line 'linePtr' (and lines merged into this line due to eol elision),
+ * adding up the pixel height of each such display line as we go along.
+ * The final total is, therefore, the total height of all display lines
+ * made up by the logical line 'linePtr' and subsequent logical lines
+ * merged into this line.
*/
displayLines = 0;
@@ -3722,7 +3783,7 @@ TkTextUpdateOneLine(
* test below this while loop.
*/
- height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
+ height = CalculateDisplayLineHeight(textPtr, indexPtr, &bytes,
&logicalLines);
if (height > 0) {
@@ -3736,44 +3797,31 @@ TkTextUpdateOneLine(
break;
}
- if (logicalLines == 0) {
- if (indexPtr->linePtr != linePtr) {
- /*
- * If we reached the end of the logical line, then either way
- * we don't have a partial calculation.
- */
+ if (mergedLines == 0) {
+ if (indexPtr->linePtr != linePtr) {
+ /*
+ * If we reached the end of the logical line, then either way
+ * we don't have a partial calculation.
+ */
- partialCalc = 0;
- break;
- }
- } else if (indexPtr->byteIndex != 0) {
- /*
- * We must still be on the same wrapped line.
- */
- } else {
- /*
- * Must check if indexPtr is really a new logical line which is
- * not merged with the previous line. The only code that would
- * really know this is LayoutDLine, which doesn't pass the
- * information on, so we have to check manually here.
- */
-
- TkTextIndex idx;
-
- TkTextIndexBackChars(textPtr, indexPtr, 1, &idx, COUNT_INDICES);
- if (!TkTextIsElided(textPtr, &idx, NULL)) {
- /*
- * We've ended a logical line.
- */
-
- partialCalc = 0;
- break;
- }
+ partialCalc = 0;
+ break;
+ }
+ } else {
+ if (IsStartOfNotMergedLine(textPtr, indexPtr)) {
+ /*
+ * We've ended a logical line.
+ */
+
+ partialCalc = 0;
+ break;
+ }
- /*
- * We must still be on the same wrapped line.
- */
- }
+ /*
+ * We must still be on the same wrapped line, on a new logical
+ * line merged with the logical line 'linePtr'.
+ */
+ }
if (partialCalc && displayLines > 50 && mergedLines == 0) {
/*
* Only calculate 50 display lines at a time, to avoid huge
@@ -3890,8 +3938,17 @@ RedisplayText(
{
register TkText *textPtr = (TkText *) clientData;
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
- TkRegion damageRegion = TkCreateRegion();
- XRectangle rectangle = {0, 0, dInfoPtr->maxX, dInfoPtr->maxY};
+ TkRegion damageRegion;
+ XRectangle rectangle;
+
+ if (dInfoPtr == NULL) {
+ return;
+ }
+ damageRegion = TkCreateRegion();
+ rectangle.x = 0;
+ rectangle.y = 0;
+ rectangle.width = dInfoPtr->maxX;
+ rectangle.height = dInfoPtr->maxY;
TkUnionRectWithRegion(&rectangle, damageRegion, damageRegion);
TextInvalidateRegion(textPtr, damageRegion);
@@ -4571,6 +4628,8 @@ TextChanged(
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
DLine *firstPtr, *lastPtr;
TkTextIndex rounded;
+ TkTextLine *linePtr;
+ int notBegin;
/*
* Schedule both a redisplay and a recomputation of display information.
@@ -4596,23 +4655,78 @@ TextChanged(
/*
* Find the DLines corresponding to index1Ptr and index2Ptr. There is one
* tricky thing here, which is that we have to relayout in units of whole
- * text lines: round index1Ptr back to the beginning of its text line, and
- * include all the display lines after index2, up to the end of its text
- * line. This is necessary because the indices stored in the display lines
- * will no longer be valid. It's also needed because any edit could change
- * the way lines wrap.
+ * text lines: This is necessary because the indices stored in the display
+ * lines will no longer be valid. It's also needed because any edit could
+ * change the way lines wrap.
+ * To relayout in units of whole text (logical) lines, round index1Ptr
+ * back to the beginning of its text line (or, if this line start is
+ * elided, to the beginning of the text line that starts the display line
+ * it is included in), and include all the display lines after index2Ptr,
+ * up to the end of its text line (or, if this line end is elided, up to
+ * the end of the first non elided text line after this line end).
*/
rounded = *index1Ptr;
rounded.byteIndex = 0;
- firstPtr = FindDLine(dInfoPtr->dLinePtr, &rounded);
+ notBegin = 0;
+ while (!IsStartOfNotMergedLine(textPtr, &rounded) && notBegin) {
+ notBegin = !TkTextIndexBackBytes(textPtr, &rounded, 1, &rounded);
+ rounded.byteIndex = 0;
+ }
+
+ /*
+ * 'rounded' now points to the start of a display line as well as the
+ * real (non elided) start of a logical line, and this index is the
+ * closest before index1Ptr.
+ */
+
+ firstPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
+
if (firstPtr == NULL) {
+ /*
+ * index1Ptr pertains to no display line, i.e this index is after
+ * the last display line. Since index2Ptr is after index1Ptr, there
+ * is no display line to free/redisplay and we can return early.
+ */
+
return;
}
- lastPtr = FindDLine(dInfoPtr->dLinePtr, index2Ptr);
- while ((lastPtr != NULL)
- && (lastPtr->index.linePtr == index2Ptr->linePtr)) {
- lastPtr = lastPtr->nextPtr;
+
+ rounded = *index2Ptr;
+ linePtr = index2Ptr->linePtr;
+ do {
+ linePtr = TkBTreeNextLine(textPtr, linePtr);
+ if (linePtr == NULL) {
+ break;
+ }
+ rounded.linePtr = linePtr;
+ rounded.byteIndex = 0;
+ } while (!IsStartOfNotMergedLine(textPtr, &rounded));
+
+ if (linePtr == NULL) {
+ lastPtr = NULL;
+ } else {
+ /*
+ * 'rounded' now points to the start of a display line as well as the
+ * start of a logical line not merged with its previous line, and
+ * this index is the closest after index2Ptr.
+ */
+
+ lastPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &rounded);
+
+ /*
+ * At least one display line is supposed to change. This makes the
+ * redisplay OK in case the display line we expect to get here was
+ * unlinked by a previous call to TkTextChanged and the text widget
+ * did not update before reaching this point. This happens for
+ * instance when moving the cursor up one line.
+ * Note that lastPtr != NULL here, otherwise we would have returned
+ * earlier when we tested for firstPtr being NULL.
+ */
+
+ if (lastPtr == firstPtr) {
+ lastPtr = lastPtr->nextPtr;
+ }
}
/*
@@ -4792,14 +4906,13 @@ TextRedrawTag(
* the line containing the previous character.
*/
- if (curIndexPtr->byteIndex == 0) {
- dlPtr = FindDLine(dlPtr, curIndexPtr);
+ if (IsStartOfNotMergedLine(textPtr, curIndexPtr)) {
+ dlPtr = FindDLine(textPtr, dlPtr, curIndexPtr);
} else {
- TkTextIndex tmp;
+ TkTextIndex tmp = *curIndexPtr;
- tmp = *curIndexPtr;
- tmp.byteIndex -= 1;
- dlPtr = FindDLine(dlPtr, &tmp);
+ TkTextIndexBackBytes(textPtr, &tmp, 1, &tmp);
+ dlPtr = FindDLine(textPtr, dlPtr, &tmp);
}
if (dlPtr == NULL) {
break;
@@ -4815,9 +4928,9 @@ TextRedrawTag(
curIndexPtr = &search.curIndex;
endIndexPtr = curIndexPtr;
}
- endPtr = FindDLine(dlPtr, endIndexPtr);
- if ((endPtr != NULL) && (endPtr->index.linePtr == endIndexPtr->linePtr)
- && (endPtr->index.byteIndex < endIndexPtr->byteIndex)) {
+ endPtr = FindDLine(textPtr, dlPtr, endIndexPtr);
+ if ((endPtr != NULL)
+ && (TkTextIndexCmp(&endPtr->index,endIndexPtr) < 0)) {
endPtr = endPtr->nextPtr;
}
@@ -4935,7 +5048,7 @@ TkTextRelayoutWindow(
* could change the way lines wrap.
*/
- if (textPtr->topIndex.byteIndex != 0) {
+ if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
}
@@ -5048,9 +5161,9 @@ TkTextSetYView(
*/
textPtr->topIndex = *indexPtr;
- if (indexPtr->byteIndex != 0) {
- TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
- }
+ if (!IsStartOfNotMergedLine(textPtr, indexPtr)) {
+ TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex, 0, NULL);
+ }
dInfoPtr->newTopPixelOffset = pickPlace;
goto scheduleUpdate;
}
@@ -5064,7 +5177,7 @@ TkTextSetYView(
if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
UpdateDisplayInfo(textPtr);
}
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, indexPtr);
if (dlPtr != NULL) {
if ((dlPtr->y + dlPtr->height) > dInfoPtr->maxY) {
/*
@@ -5073,19 +5186,20 @@ TkTextSetYView(
*/
dlPtr = NULL;
- } else if ((dlPtr->index.linePtr == indexPtr->linePtr)
- && (dlPtr->index.byteIndex <= indexPtr->byteIndex)) {
- if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
- /*
- * It is on the top line, but that line is hanging off the top
- * of the screen. Change the top overlap to zero and update.
- */
-
- dInfoPtr->newTopPixelOffset = 0;
- goto scheduleUpdate;
- }
- return;
- }
+ } else {
+ if (TkTextIndexCmp(&dlPtr->index, indexPtr) <= 0) {
+ if (dInfoPtr->dLinePtr == dlPtr && dInfoPtr->topPixelOffset != 0) {
+ /*
+ * It is on the top line, but that line is hanging off the top
+ * of the screen. Change the top overlap to zero and update.
+ */
+
+ dInfoPtr->newTopPixelOffset = 0;
+ goto scheduleUpdate;
+ }
+ return;
+ }
+ }
}
/*
@@ -5096,7 +5210,9 @@ TkTextSetYView(
* If the line is not close, place it in the center of the window.
*/
- lineHeight = CalculateDisplayLineHeight(textPtr, indexPtr, NULL, NULL);
+ tmpIndex = *indexPtr;
+ TkTextFindDisplayLineEnd(textPtr, &tmpIndex, 0, NULL);
+ lineHeight = CalculateDisplayLineHeight(textPtr, &tmpIndex, NULL, NULL);
/*
* It would be better if 'bottomY' were calculated using the actual height
@@ -5137,7 +5253,7 @@ TkTextSetYView(
MeasureUp(textPtr, indexPtr, close + lineHeight
- textPtr->charHeight/2, &tmpIndex, &overlap);
- if (FindDLine(dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
+ if (FindDLine(textPtr, dInfoPtr->dLinePtr, &tmpIndex) != NULL) {
bottomY = dInfoPtr->maxY - dInfoPtr->y;
}
}
@@ -5275,6 +5391,8 @@ MeasureUp(
index.linePtr = TkBTreeFindLine(srcPtr->tree, textPtr, lineNum);
index.byteIndex = 0;
+ TkTextFindDisplayLineEnd(textPtr, &index, 0, NULL);
+ lineNum = TkBTreeLinesTo(textPtr, index.linePtr);
lowestPtr = NULL;
do {
dlPtr = LayoutDLine(textPtr, &index);
@@ -5295,8 +5413,21 @@ MeasureUp(
for (dlPtr = lowestPtr; dlPtr != NULL; dlPtr = dlPtr->nextPtr) {
distance -= dlPtr->height;
if (distance <= 0) {
- *dstPtr = dlPtr->index;
- if (overlap != NULL) {
+ *dstPtr = dlPtr->index;
+
+ /*
+ * dstPtr is the start of a display line that is or is not
+ * the start of a logical line. If it is the start of a
+ * logical line, we must check whether this line is merged
+ * with the previous logical line, and if so we must adjust
+ * dstPtr to the start of the display line since a display
+ * line start needs to be returned.
+ */
+ if (!IsStartOfNotMergedLine(textPtr, dstPtr)) {
+ TkTextFindDisplayLineEnd(textPtr, dstPtr, 0, NULL);
+ }
+
+ if (overlap != NULL) {
*overlap = -distance;
}
break;
@@ -5396,16 +5527,24 @@ TkTextSeeCmd(
}
/*
- * Find the chunk that contains the desired index. dlPtr may be NULL if
- * the widget is not mapped. [Bug #641778]
+ * Find the display line containing the desired index. dlPtr may be NULL
+ * if the widget is not mapped. [Bug #641778]
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, &index);
+ dlPtr = FindDLine(textPtr, dInfoPtr->dLinePtr, &index);
if (dlPtr == NULL) {
return TCL_OK;
}
- byteCount = index.byteIndex - dlPtr->index.byteIndex;
+ /*
+ * Find the chunk within the display line that contains the desired
+ * index. The chunks making the display line are skipped up to but not
+ * including the one crossing index. Skipping is done based on a
+ * byteCount offset possibly spanning several logical lines in case
+ * they are elided.
+ */
+
+ byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, &index);
for (chunkPtr = dlPtr->chunkPtr; chunkPtr != NULL ;
chunkPtr = chunkPtr->nextPtr) {
if (byteCount < chunkPtr->numBytes) {
@@ -5421,31 +5560,31 @@ TkTextSeeCmd(
*/
if (chunkPtr != NULL) {
- (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount,
- dlPtr->y + dlPtr->spaceAbove,
- dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
- dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
- &height);
- delta = x - dInfoPtr->curXPixelOffset;
- oneThird = lineWidth/3;
- if (delta < 0) {
- if (delta < -oneThird) {
- dInfoPtr->newXPixelOffset = (x - lineWidth/2);
- } else {
- dInfoPtr->newXPixelOffset -= ((-delta) );
- }
- } else {
- delta -= (lineWidth - width);
- if (delta > 0) {
- if (delta > oneThird) {
- dInfoPtr->newXPixelOffset = (x - lineWidth/2);
- } else {
- dInfoPtr->newXPixelOffset += (delta );
- }
- } else {
- return TCL_OK;
- }
- }
+ (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount,
+ dlPtr->y + dlPtr->spaceAbove,
+ dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
+ dlPtr->baseline - dlPtr->spaceAbove, &x, &y, &width,
+ &height);
+ delta = x - dInfoPtr->curXPixelOffset;
+ oneThird = lineWidth/3;
+ if (delta < 0) {
+ if (delta < -oneThird) {
+ dInfoPtr->newXPixelOffset = (x - lineWidth/2);
+ } else {
+ dInfoPtr->newXPixelOffset -= ((-delta) );
+ }
+ } else {
+ delta -= (lineWidth - width);
+ if (delta > 0) {
+ if (delta > oneThird) {
+ dInfoPtr->newXPixelOffset = (x - lineWidth/2);
+ } else {
+ dInfoPtr->newXPixelOffset += (delta );
+ }
+ } else {
+ return TCL_OK;
+ }
+ }
}
dInfoPtr->flags |= DINFO_OUT_OF_DATE;
if (!(dInfoPtr->flags & REDRAW_PENDING)) {
@@ -5682,7 +5821,25 @@ YScrollByLines(
offset++;
if (offset == 0) {
textPtr->topIndex = dlPtr->index;
- break;
+
+ /*
+ * topIndex is the start of a logical line. However, if
+ * the eol of the previous logical line is elided, then
+ * topIndex may be elsewhere than the first character of
+ * a display line, which is unwanted. Adjust to the start
+ * of the display line, if needed.
+ * topIndex is the start of a display line that is or is
+ * not the start of a logical line. If it is the start of
+ * a logical line, we must check whether this line is
+ * merged with the previous logical line, and if so we
+ * must adjust topIndex to the start of the display line.
+ */
+ if (!IsStartOfNotMergedLine(textPtr, &textPtr->topIndex)) {
+ TkTextFindDisplayLineEnd(textPtr, &textPtr->topIndex,
+ 0, NULL);
+ }
+
+ break;
}
}
@@ -6160,13 +6317,10 @@ GetYPixelCount(
/*
* For the common case where this dlPtr is also the start of the logical
- * line, we can return right away. Note the implicit assumption here that
- * the start of a logical line is always the start of a display line (if
- * the 'elide won't elide first newline' bug is fixed, this will no longer
- * necessarily be true).
+ * line, we can return right away.
*/
- if (dlPtr->index.byteIndex == 0) {
+ if (IsStartOfNotMergedLine(textPtr, &dlPtr->index)) {
return count;
}
@@ -6448,11 +6602,12 @@ AsyncUpdateYScrollbar(
static DLine *
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. */
{
- TkTextLine *linePtr;
+ DLine *dlPtrPrev;
if (dlPtr == NULL) {
return NULL;
@@ -6467,43 +6622,89 @@ FindDLine(
}
/*
- * Find the first display line that covers the desired text line.
+ * The display line containing the desired index is such that the index
+ * of the first character of this display line is at or before the
+ * desired index, and the index of the first character of the next
+ * display line is after the desired index.
*/
- linePtr = dlPtr->index.linePtr;
- while (linePtr != indexPtr->linePtr) {
- while (dlPtr->index.linePtr == linePtr) {
- dlPtr = dlPtr->nextPtr;
- if (dlPtr == NULL) {
- return NULL;
- }
- }
+ while (TkTextIndexCmp(&dlPtr->index,indexPtr) < 0) {
+ dlPtrPrev = dlPtr;
+ dlPtr = dlPtr->nextPtr;
+ if (dlPtr == NULL) {
+ TkTextIndex indexPtr2;
+ /*
+ * We're past the last display line, either because the desired
+ * index lies past the visible text, or because the desired index
+ * is on the last display line showing the last logical line.
+ */
+ indexPtr2 = dlPtrPrev->index;
+ TkTextIndexForwBytes(textPtr, &indexPtr2, dlPtrPrev->byteCount,
+ &indexPtr2);
+ if (TkTextIndexCmp(&indexPtr2,indexPtr) > 0) {
+ dlPtr = dlPtrPrev;
+ break;
+ } else {
+ return NULL;
+ }
+ }
+ if (TkTextIndexCmp(&dlPtr->index,indexPtr) > 0) {
+ dlPtr = dlPtrPrev;
+ break;
+ }
+ }
- /*
- * VMD: some concern here as to whether this logic, or the caller's
- * logic will work well with partial peer widgets.
- */
+ return dlPtr;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * IsStartOfNotMergedLine --
+ *
+ * This function checks whether the given index is the start of a
+ * logical line that is not merged with the previous logical line
+ * (due to elision of the eol of the previous line).
+ *
+ * Results:
+ * Returns whether the given index denotes the first index of a
+* logical line not merged with its previous line.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
- linePtr = TkBTreeNextLine(NULL, linePtr);
- if (linePtr == NULL) {
- Tcl_Panic("FindDLine reached end of text");
- }
- }
- if (indexPtr->linePtr != dlPtr->index.linePtr) {
- return dlPtr;
+static int
+IsStartOfNotMergedLine(
+ TkText *textPtr, /* Widget record for text widget. */
+ CONST TkTextIndex *indexPtr) /* Index to check. */
+{
+ TkTextIndex indexPtr2;
+
+ if (indexPtr->byteIndex != 0) {
+ /*
+ * Not the start of a logical line.
+ */
+ return 0;
}
- /*
- * Now get to the right position within the text line.
- */
+ if (TkTextIndexBackBytes(textPtr, indexPtr, 1, &indexPtr2)) {
+ /*
+ * indexPtr is the first index of the text widget.
+ */
+ return 1;
+ }
- while (indexPtr->byteIndex >= (dlPtr->index.byteIndex+dlPtr->byteCount)) {
- dlPtr = dlPtr->nextPtr;
- if ((dlPtr == NULL) || (dlPtr->index.linePtr != indexPtr->linePtr)) {
- break;
- }
+ if (!TkTextIsElided(textPtr, &indexPtr2, NULL)) {
+ /*
+ * The eol of the line just before indexPtr is elided.
+ */
+ return 1;
}
- return dlPtr;
+
+ return 0;
}
/*
@@ -6673,10 +6874,15 @@ DlineIndexOfX(
* We've reached the end of the text.
*/
+ TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
return;
}
if (chunkPtr->nextPtr == NULL) {
- TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
+ /*
+ * We've reached the end of the display line.
+ */
+
+ TkTextIndexBackChars(NULL, indexPtr, 1, indexPtr, COUNT_INDICES);
return;
}
chunkPtr = chunkPtr->nextPtr;
@@ -6762,7 +6968,7 @@ DlineXOfIndex(
* coordinate. */
{
register TkTextDispChunk *chunkPtr = dlPtr->chunkPtr;
- int x;
+ int x = 0;
if (byteIndex == 0 || chunkPtr == NULL) {
return 0;
@@ -6833,7 +7039,7 @@ TkTextIndexBbox(
TextDInfo *dInfoPtr = textPtr->dInfoPtr;
DLine *dlPtr;
register TkTextDispChunk *chunkPtr;
- int byteIndex;
+ int byteCount;
/*
* Make sure that all of the screen layout information is up to date.
@@ -6847,24 +7053,37 @@ TkTextIndexBbox(
* Find the display line containing the desired index.
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ 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)
+ * 2. if indexPtr is before the first display line, in which case
+ * dlPtr currently points to the first display line
+ */
+
if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
return -1;
}
/*
- * Find the chunk within the line that contains the desired index.
+ * Find the chunk within the display line that contains the desired
+ * index. The chunks making the display line are skipped up to but not
+ * including the one crossing indexPtr. Skipping is done based on
+ * a byteCount offset possibly spanning several logical lines in case
+ * they are elided.
*/
- byteIndex = indexPtr->byteIndex - dlPtr->index.byteIndex;
+ byteCount = TkTextIndexCountBytes(textPtr, &dlPtr->index, indexPtr);
for (chunkPtr = dlPtr->chunkPtr; ; chunkPtr = chunkPtr->nextPtr) {
if (chunkPtr == NULL) {
return -1;
}
- if (byteIndex < chunkPtr->numBytes) {
+ if (byteCount < chunkPtr->numBytes) {
break;
}
- byteIndex -= chunkPtr->numBytes;
+ byteCount -= chunkPtr->numBytes;
}
/*
@@ -6874,13 +7093,13 @@ TkTextIndexBbox(
* coordinate on the screen. Translate it to reflect horizontal scrolling.
*/
- (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteIndex,
+ (*chunkPtr->bboxProc)(textPtr, chunkPtr, byteCount,
dlPtr->y + dlPtr->spaceAbove,
dlPtr->height - dlPtr->spaceAbove - dlPtr->spaceBelow,
dlPtr->baseline - dlPtr->spaceAbove, xPtr, yPtr, widthPtr,
heightPtr);
*xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curXPixelOffset;
- if ((byteIndex == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
+ if ((byteCount == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
/*
* Last character in display line. Give it all the space up to the
* line.
@@ -6978,7 +7197,16 @@ TkTextDLineInfo(
* Find the display line containing the desired index.
*/
- dlPtr = FindDLine(dInfoPtr->dLinePtr, indexPtr);
+ 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)
+ * 2. if indexPtr is before the first display line, in which case
+ * dlPtr currently points to the first display line
+ */
+
if ((dlPtr == NULL) || (TkTextIndexCmp(&dlPtr->index, indexPtr) > 0)) {
return -1;
}
diff --git a/generic/tkTextIndex.c b/generic/tkTextIndex.c
index 70c94db..13f3957 100644
--- a/generic/tkTextIndex.c
+++ b/generic/tkTextIndex.c
@@ -40,6 +40,9 @@ static CONST char * StartEnd(TkText *textPtr, CONST char *string,
static int GetIndex(Tcl_Interp *interp, TkSharedText *sharedPtr,
TkText *textPtr, CONST char *string,
TkTextIndex *indexPtr, int *canCachePtr);
+static int IndexCountBytesOrdered(CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1,
+ CONST TkTextIndex *indexPtr2);
/*
* The "textindex" Tcl_Obj definition:
@@ -771,11 +774,11 @@ GetIndex(
}
if (TkTextWindowIndex(textPtr, string, indexPtr) != 0) {
- return TCL_OK;
+ goto done;
}
if (TkTextImageIndex(textPtr, string, indexPtr) != 0) {
- return TCL_OK;
+ goto done;
}
/*
@@ -1628,6 +1631,90 @@ TkTextIndexForwChars(
/*
*---------------------------------------------------------------------------
*
+ * TkTextIndexCountBytes --
+ *
+ * Given a pair of indices in a text widget, this function counts how
+ * many bytes are between the two indices. The two indices do not need
+ * to be ordered.
+ *
+ * Results:
+ * The number of bytes in the given range.
+ *
+ * Side effects:
+ * None.
+ *
+ *---------------------------------------------------------------------------
+ */
+
+int
+TkTextIndexCountBytes(
+ CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1, /* Index describing one location. */
+ CONST TkTextIndex *indexPtr2) /* Index describing second location. */
+{
+ int compare = TkTextIndexCmp(indexPtr1, indexPtr2);
+
+ if (compare == 0) {
+ return 0;
+ } else if (compare > 0) {
+ return IndexCountBytesOrdered(textPtr, indexPtr2, indexPtr1);
+ } else {
+ return IndexCountBytesOrdered(textPtr, indexPtr1, indexPtr2);
+ }
+}
+
+static int
+IndexCountBytesOrdered(
+ CONST TkText *textPtr,
+ CONST TkTextIndex *indexPtr1,
+ /* Index describing location of character from
+ * which to count. */
+ CONST TkTextIndex *indexPtr2)
+ /* Index describing location of last character
+ * at which to stop the count. */
+{
+ int byteCount, offset;
+ TkTextSegment *segPtr, *segPtr1;
+ TkTextLine *linePtr;
+
+ if (indexPtr1->linePtr == indexPtr2->linePtr) {
+ return indexPtr2->byteIndex - indexPtr1->byteIndex;
+ }
+
+ /*
+ * indexPtr2 is on a line strictly after the line containing indexPtr1.
+ * Add up:
+ * bytes between indexPtr1 and end of its line
+ * bytes in lines strictly between indexPtr1 and indexPtr2
+ * bytes between start of the indexPtr2 line and indexPtr2
+ */
+
+ segPtr1 = TkTextIndexToSeg(indexPtr1, &offset);
+ byteCount = -offset;
+ for (segPtr = segPtr1; segPtr != NULL; segPtr = segPtr->nextPtr) {
+ byteCount += segPtr->size;
+ }
+
+ linePtr = indexPtr1->linePtr->nextPtr;
+ while (linePtr != indexPtr2->linePtr) {
+ for (segPtr = linePtr->segPtr; segPtr != NULL;
+ segPtr = segPtr->nextPtr) {
+ byteCount += segPtr->size;
+ }
+ linePtr = TkBTreeNextLine(textPtr, linePtr);
+ if (linePtr == NULL) {
+ Tcl_Panic("TextIndexCountBytesOrdered ran out of lines");
+ }
+ }
+
+ byteCount += indexPtr2->byteIndex;
+
+ return byteCount;
+}
+
+/*
+ *---------------------------------------------------------------------------
+ *
* TkTextIndexCount --
*
* Given an ordered pair of indices in a text widget, this function
diff --git a/generic/ttk/ttkLabel.c b/generic/ttk/ttkLabel.c
index d51388b..1037840 100644
--- a/generic/ttk/ttkLabel.c
+++ b/generic/ttk/ttkLabel.c
@@ -293,6 +293,7 @@ static void ImageCleanup(ImageElement *image)
TtkFreeImageSpec(image->imageSpec);
}
+#ifndef MAC_OSX_TK
/*
* StippleOver --
* Draw a stipple over the image area, to make it look "grayed-out"
@@ -317,6 +318,7 @@ static void StippleOver(
Tk_FreeBitmapFromObj(tkwin, image->stippleObj);
}
}
+#endif
static void ImageDraw(
ImageElement *image, Tk_Window tkwin,Drawable d,Ttk_Box b,Ttk_State state)