Tk Source Code

Changes On Branch tk_collect_test_utils
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Changes In Branch addendum3 Excluding Merge-Ins

This is equivalent to a diff from cfcd3e7d to fdde2c69

2025-06-10
11:38
Addendum to project "Collect utility procs for the Tk test suite", correcting two proc names in comments in entry.test. check-in: 7c346303 user: erikleunissen tags: trunk, main
11:34
Remove Github CI scheduling instructions Closed-Leaf check-in: fdde2c69 user: erikleunissen tags: tk_collect_test_utils, addendum3
2025-06-06
12:20
Merge trunk check-in: 7ea63eb0 user: erikleunissen tags: tk_collect_test_utils, addendum3
12:02
Addendum 3 to tk_collect_test_utils: correct usage of name "doval" in comments in entry.test, proc was renamed previously check-in: a5562c58 user: erikleunissen tags: tk_collect_test_utils, addendum3
2025-05-19
19:21
Addendum to project "Collect utility procs for the Tk test suite" for proc "childTkInterp". check-in: fbd5f2c0 user: erikleunissen tags: trunk, main
19:12
Remove Github CI scheduling instructions Closed-Leaf check-in: cfcd3e7d user: erikleunissen tags: tk_collect_test_utils, addendum2
2025-05-18
19:42
Remove comments that sow confusion check-in: f747565a user: erikleunissen tags: tk_collect_test_utils, addendum2
2025-05-17
15:27
Let this branch test at Github CI. check-in: 959d2eec user: erikleunissen tags: tk_collect_test_utils, addendum2

Changes to doc/colors.n.
23
24
25
26
27
28
29
30

31
32
33
34
35
36
37
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37







-
+







AliceBlue	240	248 	255
antique white	250	235 	215
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
azure	240	255 	255
azure1	240	255 	255
88
89
90
91
92
93
94
95

96
97
98
99
100
101
102
88
89
90
91
92
93
94

95
96
97
98
99
100
101
102







-
+







cornflower blue	100	149 	237
CornflowerBlue	100	149 	237
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
dark blue	0	0 	139
dark cyan	0	139 	139
Changes to doc/text.n.
31
32
33
34
35
36
37
38


39
40
41
42
43
44
45
31
32
33
34
35
36
37

38
39
40
41
42
43
44
45
46







-
+
+







.SH "WIDGET-SPECIFIC OPTIONS"
.OP \-autoseparators autoSeparators AutoSeparators
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
provided to this configuration option, which will configure the widget
to end at the very last line in the textual data store.
913
914
915
916
917
918
919







920
921
922
923
924
925
926
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934







+
+
+
+
+
+
+







The mark named \fBinsert\fR has special significance in text widgets. It is
defined automatically when a text widget is created and it may not be unset
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
flag changes state a \fB<<Modified>>\fR virtual event is generated. See the
\fIpathName \fBedit modified\fR widget command for more details.
Changes to generic/tkText.c.
716
717
718
719
720
721
722
723

724
725
726
727
728
729
730
716
717
718
719
720
721
722

723
724
725
726
727
728
729
730







-
+







	}
	indexPtr = TkTextGetIndexFromObj(interp, textPtr, objv[2]);
	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));
	    Tcl_ListObjAppendElement(interp, listObj, Tcl_NewWideIntObj(height));

3643
3644
3645
3646
3647
3648
3649
3650


3651
3652
3653
3654
3655

3656
3657
3658
3659
3660
3661
3662
3643
3644
3645
3646
3647
3648
3649

3650
3651
3652
3653
3654
3655

3656
3657
3658
3659
3660
3661
3662
3663







-
+
+




-
+







    } else {
	textPtr->flags |= INSERT_ON;
	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);
	}
    }
Changes to generic/tkText.h.
1031
1032
1033
1034
1035
1036
1037
1038


1039
1040
1041
1042
1043
1044
1045
1031
1032
1033
1034
1035
1036
1037

1038
1039
1040
1041
1042
1043
1044
1045
1046







-
+
+







MODULE_SCOPE void	TkBTreeUnlinkSegment(TkTextSegment *segPtr,
			    TkTextLine *linePtr);
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);
MODULE_SCOPE int	TkTextDLineInfo(TkText *textPtr,
			    const TkTextIndex *indexPtr, int *xPtr, int *yPtr,
Changes to generic/tkTextDisp.c.
7353
7354
7355
7356
7357
7358
7359
7360

7361
7362
7363




7364
7365
7366
7367
7368





7369
7370
7371
7372
7373
7374
7375
7353
7354
7355
7356
7357
7358
7359

7360
7361
7362
7363
7364
7365
7366
7367
7368
7369
7370
7371
7372
7373
7374
7375
7376
7377
7378
7379
7380
7381
7382
7383
7384







-
+



+
+
+
+





+
+
+
+
+







TkTextIndexBbox(
    TkText *textPtr,		/* Widget record for text widget. */
    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.
     */

    if (dInfoPtr->flags & DINFO_OUT_OF_DATE) {
	UpdateDisplayInfo(textPtr);
7427
7428
7429
7430
7431
7432
7433
7434
7435
7436
7437
7438




7439
7440
7441
7442
7443
7444
7445
7446

7447
7448
7449
7450
7451
7452
7453
7454
7436
7437
7438
7439
7440
7441
7442





7443
7444
7445
7446

7447
7448
7449
7450
7451


7452

7453
7454
7455
7456
7457
7458
7459







-
-
-
-
-
+
+
+
+
-





-
-
+
-







    *xPtr = *xPtr + dInfoPtr->x - dInfoPtr->curXPixelOffset;
    if ((byteCount == chunkPtr->numBytes-1) && (chunkPtr->nextPtr == NULL)) {
	/*
	 * 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.
	 */

7468
7469
7470
7471
7472
7473
7474
























7475
7476
7477
7478
7479
7480
7481
7473
7474
7475
7476
7477
7478
7479
7480
7481
7482
7483
7484
7485
7486
7487
7488
7489
7490
7491
7492
7493
7494
7495
7496
7497
7498
7499
7500
7501
7502
7503
7504
7505
7506
7507
7508
7509
7510







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







    }
    if ((*yPtr + *heightPtr) > dInfoPtr->maxY) {
	*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;
}

/*
 *----------------------------------------------------------------------
 *
 * TkTextDLineInfo --
Changes to generic/tkTextMark.c.
621
622
623
624
625
626
627
628

629
630
631
632
633
634
635


636

637
638
639
640
641
642
643
621
622
623
624
625
626
627

628
629
630
631
632
633
634

635
636
637
638
639
640
641
642
643
644
645







-
+






-
+
+

+







     * We have no need for the clientData.
     */

    /* 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) {
	/*
	 * The insertion cursor is off-screen. Indicate caret at 0,0 and
Changes to generic/ttk/ttkState.c.
110
111
112
113
114
115
116
117

118
119
120





121
122
123
124
125
126
127
110
111
112
113
114
115
116

117
118


119
120
121
122
123
124
125
126
127
128
129
130







-
+

-
-
+
+
+
+
+







	if (on) {
	    onbits |= stateNames[j].value;
	} 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;

    return TCL_OK;
}
Changes to tests/entry.test.
3327
3328
3329
3330
3331
3332
3333
3334

3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353
3354

3355
3356
3357
3358
3359
3360
3361
3327
3328
3329
3330
3331
3332
3333

3334
3335
3336
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348
3349
3350
3351
3352
3353

3354
3355
3356
3357
3358
3359
3360
3361







-
+



















-
+







    set textVar newdata
    list [.e cget -validate] $validationData
} -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 \
	-invalidcommand bell \
	-textvariable textVar \
	-background red -foreground white
    pack .e ; update idletasks
    set textVar newdata                 ;# previous settings
    .e configure -validate all
    set textVar nextdata
    list [.e cget -validate] $validationData
} -cleanup {
    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 \
	-invalidcommand bell \
	-textvariable textVar \
Changes to tests/ttk/ttk.test.
202
203
204
205
206
207
208
209

210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225










226
227
228
229
230
231
232
202
203
204
205
206
207
208

209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242







-
+
















+
+
+
+
+
+
+
+
+
+








test ttk-2.7 "instate scripts, true" -body {
    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 {
    bind .b <Button-1> {after 0 {.b configure -state disabled}}
    after 1 {event generate .b <Button-1>}
    after 50 {event generate .b <ButtonRelease-1>}
    set aid [after 100 {set ::ttk28 [.b instate {disabled !pressed}]}]
    vwait ::ttk28
    after cancel $aid
    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} {
	    .w cget $option
	}
253
254
255
256
257
258
259
260

261
262
263
264
265
266
267
263
264
265
266
267
268
269

270
271
272
273
274
275
276
277







-
+







    unset ::A ; destroy .cb
} -returnCodes error -result {can't set "A": failure}

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
    destroy .s
}
594
595
596
597
598
599
600
601

602
603
604
605
606
607
608
609
610
611
612

613
614
615
616
617
618
619
604
605
606
607
608
609
610

611
612
613
614
615
616
617
618
619
620
621

622
623
624
625
626
627
628
629







-
+










-
+







  -match glob -cleanup { destroy .tw }

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; #"
    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
    }
} -body {
    ttk::button .b -text xxx -command foo
Changes to win/rules.vc.
20
21
22
23
24
25
26
27

28
29
30
31
32
33
34
20
21
22
23
24
25
26

27
28
29
30
31
32
33
34







-
+







!ifndef _RULES_VC
_RULES_VC = 1

# 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

!if "$(PRJ_PACKAGE_TCLNAME)" == ""
1686
1687
1688
1689
1690
1691
1692

1693
1694
1695
1696
1697
1698
1699
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700







+







	@$(CPY) $(PRJLIB) "$(LIB_INSTALL_DIR)" >NUL

# 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:
	@echo Installing stubs library to '$(SCRIPT_INSTALL_DIR)'
	@if not exist "$(SCRIPT_INSTALL_DIR)" mkdir "$(SCRIPT_INSTALL_DIR)"
Changes to win/targets.vc.
49
50
51
52
53
54
55

56
57
58
59
60
61
62
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63







+







# Unlike the other default targets, these cannot be in rules.vc because
# the executed command depends on existence of macro PRJ_HEADERS_PUBLIC
# 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
!endif

Changes to win/tkWinWm.c.
545
546
547
548
549
550
551
552
553


554
555
556
557
558

559
560
561
562
563
564
565
566
567
568


569
570
571
572
573
574
575
576
545
546
547
548
549
550
551


552
553


554
555

556
557
558
559







560
561

562
563
564
565
566
567
568







-
-
+
+
-
-


-
+



-
-
-
-
-
-
-
+
+
-







	return NULL;
    }

    /*
     * Let the OS do the real work :)
     */

    hIcon = (HICON) CreateIconFromResourceEx(lpIcon->lpBits,
	    lpIcon->dwNumBytes, isIcon, 0x00030000,
    hIcon = (HICON)CreateIconFromResourceEx(lpIcon->lpBits,
	    lpIcon->dwNumBytes, isIcon, 0x00030000, 0, 0, 0);
	    (*(LPBITMAPINFOHEADER) lpIcon->lpBits).biWidth,
	    (*(LPBITMAPINFOHEADER) lpIcon->lpBits).biHeight/2, 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;
}

/*
 *----------------------------------------------------------------------
 *
1099
1100
1101
1102
1103
1104
1105












































1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128

1129
1130
1131
1132
1133
1134
1135
1136
1137

1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156

1157
1158
1159
1160
1161
1162
1163
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161



1162





1163
1164


1165






1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177

1178
1179
1180
1181
1182
1183
1184
1185







+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+




















-
-
-
+
-
-
-
-
-


-
-
+
-
-
-
-
-
-












-
+







 *	code.
 *
 * 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)
{
    /*
     * Sanity check.
     */

    if (lpImage == NULL) {
	return FALSE;
    }

    /*
     * BITMAPINFO is at beginning of bits.
     */

    lpImage->lpbi = (LPBITMAPINFO) lpImage->lpBits;

    /*
     * Width - simple enough.
     */

     * Width, height, and number of colors.
    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;

    SetSizeAndColorFromHICON(lpImage->hIcon, lpImage);
    /*
     * How many colors?
     */

    lpImage->Colors = lpImage->lpbi->bmiHeader.biPlanes
	    * lpImage->lpbi->bmiHeader.biBitCount;

    /*
     * XOR bits follow the header and color table.
     */

    lpImage->lpXOR = (LPBYTE) FindDIBBits((LPSTR) lpImage->lpbi);

    /*
     * AND bits follow the XOR bits.
     */

    lpImage->lpAND = lpImage->lpXOR +
	    lpImage->Height*BytesPerLine((LPBITMAPINFOHEADER) lpImage->lpbi);
	    lpImage->Height * BytesPerLine((LPBITMAPINFOHEADER) lpImage->lpbi);
    return TRUE;
}

/*
 *----------------------------------------------------------------------
 *
 * GetIconFromPixmap --
1529
1530
1531
1532
1533
1534
1535
1536

1537
1538


1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1551
1552
1553
1554
1555
1556
1557

1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568


1569
1570
1571
1572
1573
1574
1575







-
+


+
+






-
-







	if (dwBytesRead != lpIDE[i].dwBytesInRes) {
	    Tcl_SetObjResult(interp, Tcl_ObjPrintf(
		    "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
     */

    ckfree(lpIDE);
Changes to win/wish.exe.manifest.in.
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
31
32
33
34
35
36
37




38
39
40
41
42
43
44







-
-
-
-







	</application>
    </compatibility>
    <asmv3:application>
	<asmv3:windowsSettings
		xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">
	    <dpiAware>true</dpiAware>
	</asmv3:windowsSettings>
	<asmv3:windowsSettings
		xmlns="http://schemas.microsoft.com/SMI/2019/WindowsSettings">
	    <activeCodePage>UTF-8</activeCodePage>
	</asmv3:windowsSettings>
    </asmv3:application>
    <dependency>
	<dependentAssembly>
	    <assemblyIdentity
		    type="win32"
		    name="Microsoft.Windows.Common-Controls"
		    version="6.0.0.0"