Index: doc/colors.n
==================================================================
--- doc/colors.n
+++ doc/colors.n
@@ -25,11 +25,11 @@
AntiqueWhite 250 235 215
AntiqueWhite1 255 239 219
AntiqueWhite2 238 223 204
AntiqueWhite3 205 192 176
AntiqueWhite4 139 131 120
-agua 0 255 255
+aqua 0 255 255
aquamarine 127 255 212
aquamarine1 127 255 212
aquamarine2 118 238 198
aquamarine3 102 205 170
aquamarine4 69 139 116
@@ -90,11 +90,11 @@
cornsilk 255 248 220
cornsilk1 255 248 220
cornsilk2 238 232 205
cornsilk3 205 200 177
cornsilk4 139 136 120
-crymson 220 20 60
+crimson 220 20 60
cyan 0 255 255
cyan1 0 255 255
cyan2 0 238 238
cyan3 0 205 205
cyan4 0 139 139
Index: doc/text.n
==================================================================
--- doc/text.n
+++ doc/text.n
@@ -33,11 +33,12 @@
Specifies a boolean that says whether separators are automatically inserted in
the undo stack. Only meaningful when the \fB\-undo\fR option is true.
.OP \-blockcursor blockCursor BlockCursor
Specifies a boolean that says whether the blinking insertion cursor should be
drawn as a character-sized rectangular block. If false (the default) a thin
-vertical line is used for the insertion cursor.
+vertical line is used for the insertion cursor. For further discussion
+refer to section \fBTHE INSERTION CURSOR\fR below.
.OP \-endline endLine EndLine
Specifies an integer line index representing the line of the underlying
textual data store that should be just after the last line contained in
the widget. This allows a text widget to reflect only a portion of a
larger piece of text. Instead of an integer, the empty string can be
@@ -915,10 +916,17 @@
with the
.QW "\fIpathName \fBmark unset\fR"
widget command. The \fBinsert\fR mark represents the position of the insertion
cursor, and the insertion cursor will automatically be drawn at this point
whenever the text widget has the input focus.
+.PP
+The \fB\-blockcursor\fR widget option controls the drawing of the cursor.
+However, drawing the cursor as a solid blinking block is not exactly
+performed as in real or emulated terminals. The character at the cursor
+position is always drawn in it's foreground color, i.e. not in
+"reverse video", which can lead to unwanted visual effects and even
+hide the character entirely, when the cursor is in its on-state.
.SH "THE MODIFIED FLAG"
.PP
The text widget can keep track of changes to the content of the widget by
means of the modified flag. Inserting or deleting text will set this flag. The
flag can be queried, set and cleared programmatically as well. Whenever the
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));
@@ -3645,16 +3645,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
@@ -7355,19 +7355,28 @@
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 the same value as 'charWidthPtr'
+ * except when indexPtr points to a Tab. Then
+ * 'cursorWidthPtr' 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.
*/
@@ -7429,24 +7438,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.
@@ -7470,10 +7475,34 @@
*heightPtr = dInfoPtr->maxY - *yPtr;
if (*heightPtr <= 0) {
return -1;
}
}
+
+ /*
+ * For a block cursor on a tab, cursorWidthPtr is the 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) {
Index: generic/ttk/ttkState.c
==================================================================
--- generic/ttk/ttkState.c
+++ generic/ttk/ttkState.c
@@ -112,14 +112,17 @@
} else {
offbits |= stateNames[j].value;
}
}
- /* Invalidate old intrep:
+ /* Invalidate old intrep, but make sure there's a string rep, see [7231bf9941].
*/
- if (objPtr->typePtr && objPtr->typePtr->freeIntRepProc) {
- objPtr->typePtr->freeIntRepProc(objPtr);
+ if (objPtr->typePtr) {
+ (void)Tcl_GetString(objPtr);
+ if (objPtr->typePtr->freeIntRepProc) {
+ objPtr->typePtr->freeIntRepProc(objPtr);
+ }
}
objPtr->typePtr = &StateSpecObjType.objType;
objPtr->internalRep.wideValue = ((Tcl_WideInt)onbits << 32) | offbits;
Index: tests/entry.test
==================================================================
--- tests/entry.test
+++ tests/entry.test
@@ -3329,11 +3329,11 @@
} -cleanup {
destroy .e
} -result {focusout {.e -1 -1 newdata abcd {} focusout forced}}
-# proc doval changed - returns 0
+# Using validateCmd3, which returns 0
test entry-19.18 {entry widget validation} -setup {
unset -nocomplain textVar validationData
} -body {
entry .e -validate all \
-validatecommand $validateCmd3 \
@@ -3349,11 +3349,11 @@
destroy .e
} -result {none {.e -1 -1 nextdata newdata {} all forced}}
## This sets validate to none because it shows that we prevent a possible
## loop condition in the validation, when the entry textvar is also set
-# proc doval2 used
+# Using validateCmd2
test entry-19.19 {entry widget validation} -setup {
unset -nocomplain textVar validationData
} -body {
entry .e -validate all \
-validatecommand $validateCmd3 \
Index: tests/ttk/ttk.test
==================================================================
--- tests/ttk/ttk.test
+++ tests/ttk/ttk.test
@@ -204,11 +204,11 @@
set x 0
.t instate !disabled { set x 1 }
set x
} -result 1
-test ttk-2.8 "bug 3223850: button state disabled during click" -setup {
+test ttk-2.8 {Bug [3223850]: Button remains stuck when disabled as depressed on XP} -setup {
destroy .b
set ttk28 {}
pack [ttk::button .b -command {set ::ttk28 failed}]
update
} -body {
@@ -221,10 +221,20 @@
set ttk28
} -cleanup {
destroy .b
unset -nocomplain ttk28 aid
} -result 1
+
+test ttk-2.9 {Bug [7231bf99]: Setting ttk state may change the variable passed by value} -body {
+ pack [ttk::button .b1 -text Hi!]
+ set state [list invalid disabled]
+ .b1 state $state
+ set state
+} -cleanup {
+ unset state
+ destroy .b1
+} -result [list invalid disabled]
foreach wc $widgetClasses {
test ttk-coreoptions-$wc "$wc has all core options" -body {
ttk::$wc .w
foreach option {-class -style -cursor -takefocus} {
@@ -255,11 +265,11 @@
test ttk-3.3 "Constructor failure with cursor" -body {
ttk::button .b -cursor bottom_right_corner -style BadStyle
} -returnCodes error -result "Layout BadStyle not found"
-test ttk-3.4 "SF#2009213" -body {
+test ttk-3.4 {Bug [2009213]: Segfault after setting bad -sliderrelief and packing scale} -body {
ttk::style configure TScale -sliderrelief {}
pack [ttk::scale .s]
update
} -cleanup {
ttk::style configure TScale -sliderrelief raised
@@ -596,11 +606,11 @@
test ttk-14.3 "-textvariable in nonexistant namespace" -body {
ttk::entry .tw -textvariable ::nsn::foo
} -returnCodes error -result {can't trace *: parent namespace doesn't exist} \
-match glob -cleanup { destroy .tw }
-test ttk-15.1 {Bug 3062331} -setup {
+test ttk-15.1 {Tcl bug [3062331]: segfault in variable traces with ttk::* widgets} -setup {
destroy .b
} -body {
set Y {}
ttk::button .b -textvariable Y
trace add variable Y unset "destroy .b; #"
@@ -607,11 +617,11 @@
unset Y
} -cleanup {
destroy .b
} -result {}
-test ttk-15.2 {Bug 3341056} -setup {
+test ttk-15.2 {Bug [3341056]: Usage of recreated ttk::checkbutton causes crash} -setup {
proc foo {} {
destroy .lf
ttk::labelframe .lf
ttk::checkbutton .lf.cb -text xxx
}
Index: win/rules.vc
==================================================================
--- win/rules.vc
+++ win/rules.vc
@@ -22,11 +22,11 @@
# The following macros define the version of the rules.vc nmake build system
# For modifications that are not backward-compatible, you *must* change
# the major version.
RULES_VERSION_MAJOR = 1
-RULES_VERSION_MINOR = 14
+RULES_VERSION_MINOR = 15
# The PROJECT macro must be defined by parent makefile.
!if "$(PROJECT)" == ""
!error *** Error: Macro PROJECT not defined! Please define it before including rules.vc
!endif
@@ -1688,10 +1688,11 @@
# Alias for default-install-scripts
default-install-libraries: default-install-scripts
default-install-scripts: $(OUT_DIR)\pkgIndex.tcl
@echo Installing libraries to '$(SCRIPT_INSTALL_DIR)'
+ @if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
@if exist $(LIBDIR) $(CPY) $(LIBDIR)\*.tcl "$(SCRIPT_INSTALL_DIR)"
@echo Installing package index in '$(SCRIPT_INSTALL_DIR)'
@$(CPY) $(OUT_DIR)\pkgIndex.tcl $(SCRIPT_INSTALL_DIR)
default-install-stubs:
Index: win/targets.vc
==================================================================
--- win/targets.vc
+++ win/targets.vc
@@ -51,10 +51,11 @@
# that the parent makefile will not define until after including rules-ext.vc
!if "$(PRJ_HEADERS_PUBLIC)" != ""
default-install: default-install-headers
default-install-headers:
@echo Installing headers to '$(INCLUDE_INSTALL_DIR)'
+ @if not exist "$(INCLUDE_INSTALL_DIR)" $(MKDIR) "$(INCLUDE_INSTALL_DIR)"
@for %f in ($(PRJ_HEADERS_PUBLIC)) do @$(COPY) %f "$(INCLUDE_INSTALL_DIR)"
!endif
!if "$(DISABLE_STANDARD_TARGETS)" == ""
DISABLE_STANDARD_TARGETS = 0
Index: win/tkWinWm.c
==================================================================
--- win/tkWinWm.c
+++ win/tkWinWm.c
@@ -547,28 +547,20 @@
/*
* Let the OS do the real work :)
*/
- hIcon = (HICON) CreateIconFromResourceEx(lpIcon->lpBits,
- lpIcon->dwNumBytes, isIcon, 0x00030000,
- (*(LPBITMAPINFOHEADER) lpIcon->lpBits).biWidth,
- (*(LPBITMAPINFOHEADER) lpIcon->lpBits).biHeight/2, 0);
+ hIcon = (HICON)CreateIconFromResourceEx(lpIcon->lpBits,
+ lpIcon->dwNumBytes, isIcon, 0x00030000, 0, 0, 0);
/*
- * It failed, odds are good we're on NT so try the non-Ex way.
+ * It failed, the non-Ex way might work as a fallback.
*/
if (hIcon == NULL) {
- /*
- * We would break on NT if we try with a 16bpp image.
- */
-
- if (lpIcon->lpbi->bmiHeader.biBitCount != 16) {
- hIcon = CreateIconFromResource(lpIcon->lpBits, lpIcon->dwNumBytes,
- isIcon, 0x00030000);
- }
+ hIcon = CreateIconFromResource(lpIcon->lpBits, lpIcon->dwNumBytes,
+ isIcon, 0x00030000);
}
return hIcon;
}
/*
@@ -1101,10 +1093,54 @@
* Results:
* BOOL - TRUE for success, FALSE for failure
*
*----------------------------------------------------------------------
*/
+
+static BOOL
+SetSizeAndColorFromHICON( /* Helper for AdjustIconImagePointers */
+ HICON hicon,
+ LPICONIMAGE lpImage)
+{
+ ICONINFO info;
+ BOOL bRes;
+ BITMAP bmp;
+
+ memset(&info, 0, sizeof(info));
+
+ bRes = GetIconInfo(hicon, &info);
+ if (!bRes) {
+ return FALSE;
+ }
+
+ if (info.hbmColor) {
+ const int nWrittenBytes = GetObject(info.hbmColor, sizeof(bmp), &bmp);
+
+ if (nWrittenBytes > 0) {
+ lpImage->Width = bmp.bmWidth;
+ lpImage->Height = bmp.bmHeight;
+ lpImage->Colors = bmp.bmBitsPixel;
+ }
+ } else if (info.hbmMask) {
+ // Icon has no color plane, image data stored in mask
+ const int nWrittenBytes = GetObject(info.hbmMask, sizeof(bmp), &bmp);
+
+ if (nWrittenBytes > 0) {
+ lpImage->Width = bmp.bmWidth;
+ lpImage->Height = bmp.bmHeight / 2;
+ lpImage->Colors = 1;
+ }
+ }
+
+ if (info.hbmColor) {
+ DeleteObject(info.hbmColor);
+ }
+ if (info.hbmMask) {
+ DeleteObject(info.hbmMask);
+ }
+ return TRUE;
+}
static BOOL
AdjustIconImagePointers(
LPICONIMAGE lpImage)
{
@@ -1121,28 +1157,14 @@
*/
lpImage->lpbi = (LPBITMAPINFO) lpImage->lpBits;
/*
- * Width - simple enough.
- */
-
- lpImage->Width = lpImage->lpbi->bmiHeader.biWidth;
-
- /*
- * Icons are stored in funky format where height is doubled so account for
- * that.
- */
-
- lpImage->Height = (lpImage->lpbi->bmiHeader.biHeight)/2;
-
- /*
- * How many colors?
- */
-
- lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes
- * lpImage->lpbi->bmiHeader.biBitCount;
+ * Width, height, and number of colors.
+ */
+
+ SetSizeAndColorFromHICON(lpImage->hIcon, lpImage);
/*
* XOR bits follow the header and color table.
*/
@@ -1151,11 +1173,11 @@
/*
* AND bits follow the XOR bits.
*/
lpImage->lpAND = lpImage->lpXOR +
- lpImage->Height*BytesPerLine((LPBITMAPINFOHEADER) lpImage->lpbi);
+ lpImage->Height * BytesPerLine((LPBITMAPINFOHEADER) lpImage->lpbi);
return TRUE;
}
/*
*----------------------------------------------------------------------
@@ -1531,21 +1553,21 @@
"error reading file: %s", Tcl_PosixError(interp)));
goto readError;
}
/*
- * Set the internal pointers appropriately.
+ * Create the icon from the resource, and set the internal pointers appropriately.
*/
+ lpIR->IconImages[i].hIcon =
+ MakeIconOrCursorFromResource(&lpIR->IconImages[i], isIcon);
if (!AdjustIconImagePointers(&lpIR->IconImages[i])) {
Tcl_SetObjResult(interp, Tcl_NewStringObj(
"Error converting to internal format", TCL_INDEX_NONE));
Tcl_SetErrorCode(interp, "TK", "WM", "ICON", "FORMAT", NULL);
goto readError;
}
- lpIR->IconImages[i].hIcon =
- MakeIconOrCursorFromResource(&lpIR->IconImages[i], isIcon);
}
/*
* Clean up
*/
Index: win/wish.exe.manifest.in
==================================================================
--- win/wish.exe.manifest.in
+++ win/wish.exe.manifest.in
@@ -33,14 +33,10 @@
true
-
- UTF-8
-