Tk Source Code

Check-in [1cefcd34]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to tclconference@googlegroups.com
or submit via the online form by Sep 9.

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

Overview
Comment:Merged core-8-6-branch
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tip-449
Files: files | file ages | folders
SHA1:1cefcd34869c06cd34e1bd9f976e1e7a50669c0a
User & Date: fvogel 2016-06-28 18:41:36
Context
2016-07-04
21:26
Return indices making sense at undo/redo return time. The returned ranges are optimized (no duplicates, no overlapping ranges). Works but needs polishing. check-in: 6c03c35d user: fvogel tags: tip-449
2016-06-28
18:41
Merged core-8-6-branch check-in: 1cefcd34 user: fvogel tags: tip-449
2016-06-27
19:23
Fixed [4cb3dab4eb] - Improvements to the documentation of Tk_FindPhoto et al. Patch provided by Simon Bachmann. check-in: 16bb032e user: fvogel tags: core-8-6-branch
2016-06-11
15:12
Merged core-8-6-branch check-in: 32c88915 user: fvogel tags: tip-449
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to doc/FindPhoto.3.

95
96
97
98
99
100
101


102
103
104
105
106
107
108
...
177
178
179
180
181
182
183












184
185
186
187
188
189
190
.BE
.SH DESCRIPTION
.PP
\fBTk_FindPhoto\fR returns an opaque handle that is used to identify a
particular photo image to the other procedures.  The parameter is the
name of the image, that is, the name specified to the \fBimage create
photo\fR command, or assigned by that command if no name was specified.


.PP
\fBTk_PhotoPutBlock\fR is used to supply blocks of image data to be
displayed.  The call affects an area of the image of size
\fIwidth\fR x \fIheight\fR pixels, with its top-left corner at
coordinates (\fIx\fR,\fIy\fR).  All of \fIwidth\fR, \fIheight\fR,
\fIx\fR, and \fIy\fR must be non-negative.
If part of this area lies outside the
................................................................................
.PP
\fBTk_PhotoGetImage\fR can be used to retrieve image data from a photo
image.  \fBTk_PhotoGetImage\fR fills
in the structure pointed to by the \fIblockPtr\fR parameter with values
that describe the address and layout of the image data that the
photo image has stored internally.  The values are valid
until the image is destroyed or its size is changed.












\fBTk_PhotoGetImage\fR returns 1 for compatibility with the
corresponding procedure in the old photo widget.
.PP
\fBTk_PhotoBlank\fR blanks the entire area of the
photo image.  Blank areas of a photo image are transparent.
.PP
\fBTk_PhotoExpand\fR requests that the widget's image be expanded to be







>
>







 







>
>
>
>
>
>
>
>
>
>
>
>







95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
...
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
.BE
.SH DESCRIPTION
.PP
\fBTk_FindPhoto\fR returns an opaque handle that is used to identify a
particular photo image to the other procedures.  The parameter is the
name of the image, that is, the name specified to the \fBimage create
photo\fR command, or assigned by that command if no name was specified.
If \fIimageName\fR does not exist or is not a photo image, 
\fBTk_FindPhoto\fR returns NULL. 
.PP
\fBTk_PhotoPutBlock\fR is used to supply blocks of image data to be
displayed.  The call affects an area of the image of size
\fIwidth\fR x \fIheight\fR pixels, with its top-left corner at
coordinates (\fIx\fR,\fIy\fR).  All of \fIwidth\fR, \fIheight\fR,
\fIx\fR, and \fIy\fR must be non-negative.
If part of this area lies outside the
................................................................................
.PP
\fBTk_PhotoGetImage\fR can be used to retrieve image data from a photo
image.  \fBTk_PhotoGetImage\fR fills
in the structure pointed to by the \fIblockPtr\fR parameter with values
that describe the address and layout of the image data that the
photo image has stored internally.  The values are valid
until the image is destroyed or its size is changed.
.PP
It is possible to modify an image by writing directly to the data 
the \fIpixelPtr\fR field points to. The size of the image cannot be
changed this way, though.
Also, changes made by writing directly to \fIpixelPtr\fR will not be 
immediately visible, but only after a call to 
\fBTk_ImageChanged\fR or after an event that causes the interested 
widgets to redraw themselves.
For these reasons usually it is preferable to make changes to 
a copy of the image data and write it back with 
\fBTk_PhotoPutBlock\fR or \fBTk_PhotoPutZoomedBlock\fR. 
.PP
\fBTk_PhotoGetImage\fR returns 1 for compatibility with the
corresponding procedure in the old photo widget.
.PP
\fBTk_PhotoBlank\fR blanks the entire area of the
photo image.  Blank areas of a photo image are transparent.
.PP
\fBTk_PhotoExpand\fR requests that the widget's image be expanded to be

Changes to generic/tkFrame.c.

442
443
444
445
446
447
448
























449
450
451
452
453
454
455
	    toplevel ? TYPE_TOPLEVEL : TYPE_FRAME, appName);
    for (i=0; i<argc; i++) {
	Tcl_DecrRefCount(objv[i]);
    }
    ckfree(objv);
    return result;
}

























static int
CreateFrame(
    ClientData clientData,	/* NULL. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[],	/* Argument objects. */







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
	    toplevel ? TYPE_TOPLEVEL : TYPE_FRAME, appName);
    for (i=0; i<argc; i++) {
	Tcl_DecrRefCount(objv[i]);
    }
    ckfree(objv);
    return result;
}

int
TkListCreateFrame(
    ClientData clientData,	/* Either NULL or pointer to option table. */
    Tcl_Interp *interp,		/* Current interpreter. */
    Tcl_Obj *listObj,		/* List of arguments. */
    int toplevel,		/* Non-zero means create a toplevel window,
				 * zero means create a frame. */
    Tcl_Obj *nameObj)		/* Should only be non-NULL if there is no main
				 * window associated with the interpreter.
				 * Gives the base name to use for the new
				 * application. */
    
{
    int objc;
    Tcl_Obj **objv;

    if (TCL_OK != Tcl_ListObjGetElements(interp, listObj, &objc, &objv)) {
	return TCL_ERROR;
    }
    return CreateFrame(clientData, interp, objc, objv,
	    toplevel ? TYPE_TOPLEVEL : TYPE_FRAME,
	    nameObj ? Tcl_GetString(nameObj) : NULL);
}

static int
CreateFrame(
    ClientData clientData,	/* NULL. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[],	/* Argument objects. */

Changes to generic/tkInt.h.

1213
1214
1215
1216
1217
1218
1219



1220
1221
1222
1223
1224
1225
1226
			    const char *nsname, const char *name,
			    ClientData clientData, const TkEnsemble *map);
MODULE_SCOPE int	TkInitTkCmd(Tcl_Interp *interp,
			    ClientData clientData);
MODULE_SCOPE int	TkInitFontchooser(Tcl_Interp *interp,
			    ClientData clientData);
MODULE_SCOPE void	TkpWarpPointer(TkDisplay *dispPtr);




#ifdef _WIN32
#define TkParseColor XParseColor
#else
MODULE_SCOPE Status TkParseColor (Display * display,
				Colormap map, const char* spec,
				XColor * colorPtr);







>
>
>







1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
			    const char *nsname, const char *name,
			    ClientData clientData, const TkEnsemble *map);
MODULE_SCOPE int	TkInitTkCmd(Tcl_Interp *interp,
			    ClientData clientData);
MODULE_SCOPE int	TkInitFontchooser(Tcl_Interp *interp,
			    ClientData clientData);
MODULE_SCOPE void	TkpWarpPointer(TkDisplay *dispPtr);
MODULE_SCOPE int	TkListCreateFrame(ClientData clientData,
			    Tcl_Interp *interp, Tcl_Obj *listObj,
			    int toplevel, Tcl_Obj *nameObj);

#ifdef _WIN32
#define TkParseColor XParseColor
#else
MODULE_SCOPE Status TkParseColor (Display * display,
				Colormap map, const char* spec,
				XColor * colorPtr);

Changes to generic/tkText.c.

119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
....
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
....
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
....
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
....
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
....
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
....
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
....
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
....
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
....
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
....
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
....
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
....
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
....
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
....
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
....
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
....
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
....
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
....
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
 * Information used to parse text configuration options:
 */

static const Tk_OptionSpec optionSpecs[] = {
    {TK_OPTION_BOOLEAN, "-autoseparators", "autoSeparators",
	"AutoSeparators", DEF_TEXT_AUTO_SEPARATORS, -1,
	Tk_Offset(TkText, autoSeparators),
        TK_OPTION_DONT_SET_DEFAULT, 0, 0},
    {TK_OPTION_BORDER, "-background", "background", "Background",
	DEF_TEXT_BG_COLOR, -1, Tk_Offset(TkText, border),
	0, DEF_TEXT_BG_MONO, 0},
    {TK_OPTION_SYNONYM, "-bd", NULL, NULL,
	NULL, 0, -1, 0, "-borderwidth",
	TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_SYNONYM, "-bg", NULL, NULL,
................................................................................
	DEF_TEXT_INSERT_UNFOCUSSED, -1, Tk_Offset(TkText, insertUnfocussed),
	0, insertUnfocussedStrings, 0},
    {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
	DEF_TEXT_INSERT_WIDTH, -1, Tk_Offset(TkText, insertWidth),
	0, 0, 0},
    {TK_OPTION_INT, "-maxundo", "maxUndo", "MaxUndo",
	DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo),
        TK_OPTION_DONT_SET_DEFAULT, 0, 0},
    {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
	DEF_TEXT_PADX, -1, Tk_Offset(TkText, padX), 0, 0,
	TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
	DEF_TEXT_PADY, -1, Tk_Offset(TkText, padY), 0, 0, 0},
    {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
	DEF_TEXT_RELIEF, -1, Tk_Offset(TkText, relief), 0, 0, 0},
................................................................................
	DEF_TEXT_TABSTYLE, -1, Tk_Offset(TkText, tabStyle),
	0, tabStyleStrings, TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
	DEF_TEXT_TAKE_FOCUS, -1, Tk_Offset(TkText, takeFocus),
	TK_OPTION_NULL_OK, 0, 0},
    {TK_OPTION_BOOLEAN, "-undo", "undo", "Undo",
	DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo),
        TK_OPTION_DONT_SET_DEFAULT, 0 , 0},
    {TK_OPTION_INT, "-width", "width", "Width",
	DEF_TEXT_WIDTH, -1, Tk_Offset(TkText, width), 0, 0,
	TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_STRING_TABLE, "-wrap", "wrap", "Wrap",
	DEF_TEXT_WRAP, -1, Tk_Offset(TkText, wrapMode),
	0, wrapStrings, TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
................................................................................
		index = *indexFromPtr;
		index.byteIndex = 0;

		/*
		 * 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' (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 (TkTextIndexCmp(&index,indexToPtr) < 0) {
		    value += TkTextUpdateOneLine(textPtr, index.linePtr,
                            0, &index, 0);
		}

                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 (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
			break;
		    }
		    TkTextIndexForwBytes(textPtr, &index, 1, &index);
		    value--;

		}
		if (indexToPtr->linePtr != lastPtr) {
		    index.linePtr = indexToPtr->linePtr;
		    index.byteIndex = 0;
		    while (1) {
			TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
                        if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
			    break;
			}
			TkTextIndexForwBytes(textPtr, &index, 1, &index);
			value++;
		    }
		}

................................................................................
    case TEXT_MARK:
	result = TkTextMarkCmd(textPtr, interp, objc, objv);
	break;
    case TEXT_PEER:
	result = TextPeerCmd(textPtr, interp, objc, objv);
	break;
    case TEXT_PENDINGSYNC: {
        if (objc != 2) {
            Tcl_WrongNumArgs(interp, 2, objv, NULL);
            result = TCL_ERROR;
            goto done;
        }
        Tcl_SetObjResult(interp,
                Tcl_NewBooleanObj(TkTextPendingsync(textPtr)));
        break;
    }
    case TEXT_REPLACE: {
	const TkTextIndex *indexFromPtr, *indexToPtr;

	if (objc < 5) {
	    Tcl_WrongNumArgs(interp, 2, objv,
		    "index1 index2 chars ?tagList chars tagList ...?");
................................................................................
	    if (TkTextPendingsync(textPtr)) {
		if (textPtr->afterSyncCmd) {
		    Tcl_DecrRefCount(textPtr->afterSyncCmd);
		}
		textPtr->afterSyncCmd = cmd;
	    } else {
		textPtr->afterSyncCmd = cmd;
                Tcl_DoWhenIdle(RunAfterSyncCmd, (ClientData) textPtr);
	    }
	    break;
	} else if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?-command command?");
	    result = TCL_ERROR;
	    goto done;
	}
................................................................................
	}

	/* Indices are potentially obsolete after changing -startline and/or
	 * -endline, therefore increase the epoch.
	 * Also, clamp the insert and current (unshared) marks to the new
	 * -startline/-endline range limits of the widget. All other (shared)
	 * marks are unchanged.
         * The return value of TkTextMarkNameToIndex does not need to be
         * checked: "insert" and "current" marks always exist, and the
         * purpose of the code below precisely is to move them inside the
         * -startline/-endline range.
	 */

	textPtr->sharedTextPtr->stateEpoch++;
	TkTextMarkNameToIndex(textPtr, "insert", &index3);
	if (TkTextIndexCmp(&index3, &index1) < 0) {
	    textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &index1);
	}
................................................................................
     * Make sure that configuration options are properly mirrored between the
     * widget record and the "sel" tags. NOTE: we don't have to free up
     * information during the mirroring; old information was freed when it was
     * replaced in the widget record.
     */

    if (textPtr->selTagPtr->selBorder == NULL) {
        textPtr->selTagPtr->border = textPtr->selBorder;
    } else {
        textPtr->selTagPtr->selBorder = textPtr->selBorder;
    }
    if (textPtr->selTagPtr->borderWidthPtr != textPtr->selBorderWidthPtr) {
	textPtr->selTagPtr->borderWidthPtr = textPtr->selBorderWidthPtr;
	textPtr->selTagPtr->borderWidth = textPtr->selBorderWidth;
    }
    if (textPtr->selTagPtr->selFgColor == NULL) {
        textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr;
    } else {
        textPtr->selTagPtr->selFgColor = textPtr->selFgColorPtr;
    }
    textPtr->selTagPtr->affectsDisplay = 0;
    textPtr->selTagPtr->affectsDisplayGeometry = 0;
    if ((textPtr->selTagPtr->elideString != NULL)
	    || (textPtr->selTagPtr->tkfont != None)
	    || (textPtr->selTagPtr->justifyString != NULL)
	    || (textPtr->selTagPtr->lMargin1String != NULL)
................................................................................
	    || (textPtr->selTagPtr->selBorder != NULL)
	    || (textPtr->selTagPtr->reliefString != NULL)
	    || (textPtr->selTagPtr->bgStipple != None)
	    || (textPtr->selTagPtr->fgColor != NULL)
	    || (textPtr->selTagPtr->selFgColor != NULL)
	    || (textPtr->selTagPtr->fgStipple != None)
	    || (textPtr->selTagPtr->overstrikeString != NULL)
            || (textPtr->selTagPtr->overstrikeColor != NULL)
	    || (textPtr->selTagPtr->underlineString != NULL)
	    || (textPtr->selTagPtr->underlineColor != NULL)
            || (textPtr->selTagPtr->lMarginColor != NULL)
            || (textPtr->selTagPtr->rMarginColor != NULL)) {
	textPtr->selTagPtr->affectsDisplay = 1;
    }
    TkTextRedrawTag(NULL, textPtr, NULL, NULL, textPtr->selTagPtr, 1);

    /*
     * Claim the selection if we've suddenly started exporting it and there
     * are tagged characters.
................................................................................
    Tk_GetFontMetrics(textPtr->tkfont, &fm);

    textPtr->charHeight = fm.linespace;
    if (textPtr->charHeight <= 0) {
	textPtr->charHeight = 1;
    }
    if (textPtr->charHeight != oldCharHeight) {
        TkBTreeClientRangeChanged(textPtr, textPtr->charHeight);
    }
    border = textPtr->borderWidth + textPtr->highlightWidth;
    Tk_GeometryRequest(textPtr->tkwin,
	    textPtr->width * textPtr->charWidth + 2*textPtr->padX + 2*border,
	    textPtr->height*(fm.linespace+textPtr->spacing1+textPtr->spacing3)
		    + 2*textPtr->padY + 2*border);

................................................................................
    if (insert) {
	TkUndoPushAction(textPtr->sharedTextPtr->undoStack, iAtom, dAtom);
    } else {
	TkUndoPushAction(textPtr->sharedTextPtr->undoStack, dAtom, iAtom);
    }

    if (!canUndo || canRedo) {
        GenerateUndoStackEvent(textPtr);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * TextUndoRedoCallback --
................................................................................
		 * Deletion range starts on top line but after topIndex. Use
		 * the current topIndex as the new one.
		 */

		resetView = 1;
		line = line1;
		byteIndex = tPtr->topIndex.byteIndex;
            } else {
                /*
                 * Deletion range starts after the top line. This peers's view
                 * will not need to be reset. Nothing to do.
                 */
	    }
	} else if (index2.linePtr == tPtr->topIndex.linePtr) {
	    /*
	     * Deletion range ends on top line but before topIndex. Figure out
	     * what will be the new character index for the character
	     * currently pointed to by topIndex.
	     */
................................................................................
	    line = line2;
	    byteIndex = tPtr->topIndex.byteIndex;
	    if (index1.linePtr != index2.linePtr) {
		byteIndex -= index2.byteIndex;
	    } else {
		byteIndex -= (index2.byteIndex - index1.byteIndex);
	    }
        } else {
            /*
             * Deletion range ends before the top line. This peers's view
             * will not need to be reset. Nothing to do.
             */
	}
	if (resetView) {
	    lineAndByteIndex[resetViewCount] = line;
	    lineAndByteIndex[resetViewCount+1] = byteIndex;
	} else {
	    lineAndByteIndex[resetViewCount] = -1;
	}
................................................................................
	int line = lineAndByteIndex[resetViewCount];

	if (line != -1) {
	    int byteIndex = lineAndByteIndex[resetViewCount+1];
	    TkTextIndex indexTmp;

	    if (tPtr == textPtr) {
                if (viewUpdate) {
                    /*
                     * line cannot be before -startline of textPtr because
                     * this line corresponds to an index which is necessarily
                     * between "1.0" and "end" relative to textPtr.
                     * Therefore no need to clamp line to the -start/-end
                     * range.
                     */

		    TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, line,
			    byteIndex, &indexTmp);
		    TkTextSetYView(tPtr, &indexTmp, 0);
		}
	    } else {
                TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, line,
			byteIndex, &indexTmp);
                /*
                 * line may be before -startline of tPtr and must be
                 * clamped to -startline before providing it to
                 * TkTextSetYView otherwise lines before -startline
                 * would be displayed.
                 * There is no need to worry about -endline however,
                 * because the view will only be reset if the deletion
                 * involves the TOP line of the screen
                 */

                if (tPtr->start != NULL) {
                    int start;
                    TkTextIndex indexStart;

                    start = TkBTreeLinesTo(NULL, tPtr->start);
                    TkTextMakeByteIndex(sharedTextPtr->tree, NULL, start,
			    0, &indexStart);
                    if (TkTextIndexCmp(&indexTmp, &indexStart) < 0) {
                        indexTmp = indexStart;
                    }
                }
		TkTextSetYView(tPtr, &indexTmp, 0);
	    }
	}
	resetViewCount += 2;
    }
    if (sharedTextPtr->refCount > PIXEL_CLIENTS) {
	ckfree(lineAndByteIndex);
................................................................................
    int index, setModified, oldModified;
    int canRedo = 0;
    int canUndo = 0;
    Tcl_Obj *rangesObj = Tcl_NewObj();

    static const char *const editOptionStrings[] = {
	"canundo", "canredo", "modified", "redo", "reset", "separator",
        "undo", NULL
    };
    enum editOptions {
	EDIT_CANUNDO, EDIT_CANREDO, EDIT_MODIFIED, EDIT_REDO, EDIT_RESET,
	EDIT_SEPARATOR, EDIT_UNDO
    };

    if (objc < 3) {
................................................................................
    if (Tcl_GetIndexFromObjStruct(interp, objv[2], editOptionStrings,
	    sizeof(char *), "edit option", 0, &index) != TCL_OK) {
	return TCL_ERROR;
    }

    switch ((enum editOptions) index) {
    case EDIT_CANREDO:
        if (objc != 3) {
            Tcl_WrongNumArgs(interp, 3, objv, NULL);
             return TCL_ERROR;
        }
        if (textPtr->sharedTextPtr->undo) {
            canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
        }
        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canRedo));
        break;
    case EDIT_CANUNDO:
        if (objc != 3) {
            Tcl_WrongNumArgs(interp, 3, objv, NULL);
             return TCL_ERROR;
        }
        if (textPtr->sharedTextPtr->undo) {
            canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
        }
        Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canUndo));
        break;
    case EDIT_MODIFIED:
	if (objc == 3) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewBooleanObj(textPtr->sharedTextPtr->isDirty));
	    return TCL_OK;
	} else if (objc != 4) {
	    Tcl_WrongNumArgs(interp, 3, objv, "?boolean?");
................................................................................

	/*
	 * Only issue the <<Modified>> event if the flag actually changed.
	 * However, degree of modified-ness doesn't matter. [Bug 1799782]
	 */

	if ((!oldModified) != (!setModified)) {
            GenerateModifiedEvent(textPtr);
	}
	break;
    case EDIT_REDO:
        if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
        if (TextEditRedo(textPtr, rangesObj)) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to redo", -1));
	    Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_REDO", NULL);
	    return TCL_ERROR;
        } else {
            Tcl_SetObjResult(interp, rangesObj);
        }
        canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
        if (!canUndo || !canRedo) {
            GenerateUndoStackEvent(textPtr);
        }
	break;
    case EDIT_RESET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
        canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
        canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
	TkUndoClearStacks(textPtr->sharedTextPtr->undoStack);
        if (canUndo || canRedo) {
            GenerateUndoStackEvent(textPtr);
        }
	break;
    case EDIT_SEPARATOR:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	TkUndoInsertUndoSeparator(textPtr->sharedTextPtr->undoStack);
	break;
    case EDIT_UNDO:
        if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
        canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
	if (TextEditUndo(textPtr, rangesObj)) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to undo", -1));
	    Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_UNDO", NULL);
	    return TCL_ERROR;
        } else {
            Tcl_SetObjResult(interp, rangesObj);
        }
        canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
        if (!canRedo || !canUndo) {
            GenerateUndoStackEvent(textPtr);
        }
	break;
    }
    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
................................................................................
/*
 *----------------------------------------------------------------------
 *
 * GenerateModifiedEvent --
 *
 *	Send an event that the text was modified. This is equivalent to:
 *	   event generate $textWidget <<Modified>>
  *	for all peers of $textWidget.
*
 * Results:
 *	None
 *
 * Side effects:
 *	May force the text window into existence.
 *
 *----------------------------------------------------------------------
................................................................................
 */

static void
GenerateModifiedEvent(
    TkText *textPtr)	/* Information about text widget. */
{
    for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
            textPtr = textPtr->next) {
        Tk_MakeWindowExist(textPtr->tkwin);
        TkSendVirtualEvent(textPtr->tkwin, "Modified", NULL);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * GenerateUndoStackEvent --
................................................................................
 */

static void
GenerateUndoStackEvent(
    TkText *textPtr)	/* Information about text widget. */
{
    for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
            textPtr = textPtr->next) {
        Tk_MakeWindowExist(textPtr->tkwin);
        TkSendVirtualEvent(textPtr->tkwin, "UndoStack", NULL);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * UpdateDirtyFlag --
................................................................................
    if (sharedTextPtr->dirtyMode == TK_TEXT_DIRTY_UNDO) {
	sharedTextPtr->isDirty--;
    } else {
	sharedTextPtr->isDirty++;
    }

    if (sharedTextPtr->isDirty == 0 || oldDirtyFlag == 0) {
        GenerateModifiedEvent(sharedTextPtr->peers);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * RunAfterSyncCmd --
................................................................................
RunAfterSyncCmd(
    ClientData clientData)		/* Information about text widget. */
{
    register TkText *textPtr = (TkText *) clientData;
    int code;

    if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
        /*
        * The widget has been deleted. Don't do anything.
        */

        if (--textPtr->refCount == 0) {
            ckfree((char *) textPtr);
        }
        return;
    }

    Tcl_Preserve((ClientData) textPtr->interp);
    code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL);
    if (code == TCL_ERROR) {
        Tcl_AddErrorInfo(textPtr->interp, "\n    (text sync)");
        Tcl_BackgroundError(textPtr->interp);
    }
    Tcl_Release((ClientData) textPtr->interp);
    Tcl_DecrRefCount(textPtr->afterSyncCmd);
    textPtr->afterSyncCmd = NULL;
}
 
/*







|







 







|







 







|







 







|
|



|

|


|

|
|
|
|
|
|
|
|
|
|
|
|
|

|
|
|
|
|
|




|











|







 







|
|
|
|
|
|
|
|







 







|







 







|
|
|
|







 







|

|






|

|







 







|


|
|







 







|







 







|







 







|
|
|
|
|







 







|
|
|
|
|







 







|
|
|
|
|
|
|
|






|

|
|
|
|
|
|
|
|
|

|
|
|

|
|

|
|
|
|







 







|







 







|
|
|
|
|
|
|
|
|

|
|
|
|
|
|
|
|
|







 







|



|




|






|
|
|
|






|
|

|
|
|









|



|







|
|
|
|







 







|
|







 







|
|
|







 







|
|
|







 







|







 







|
|
|

|
|
|
|





|
|







119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
...
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
...
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
....
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
....
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
....
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
....
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
....
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
....
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
....
2880
2881
2882
2883
2884
2885
2886
2887
2888
2889
2890
2891
2892
2893
2894
....
3218
3219
3220
3221
3222
3223
3224
3225
3226
3227
3228
3229
3230
3231
3232
3233
3234
3235
3236
....
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250
3251
3252
3253
3254
3255
3256
3257
....
3288
3289
3290
3291
3292
3293
3294
3295
3296
3297
3298
3299
3300
3301
3302
3303
3304
3305
3306
3307
3308
3309
3310
3311
3312
3313
3314
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334
3335
3336
3337
3338
....
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
....
5198
5199
5200
5201
5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
....
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
5288
5289
5290
5291
5292
5293
5294
5295
5296
5297
5298
5299
5300
5301
5302
5303
5304
5305
5306
5307
5308
5309
5310
5311
5312
5313
5314
5315
5316
5317
5318
5319
5320
....
5401
5402
5403
5404
5405
5406
5407
5408
5409
5410
5411
5412
5413
5414
5415
5416
....
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
....
5447
5448
5449
5450
5451
5452
5453
5454
5455
5456
5457
5458
5459
5460
5461
5462
5463
....
5504
5505
5506
5507
5508
5509
5510
5511
5512
5513
5514
5515
5516
5517
5518
....
5533
5534
5535
5536
5537
5538
5539
5540
5541
5542
5543
5544
5545
5546
5547
5548
5549
5550
5551
5552
5553
5554
5555
5556
5557
5558
5559
5560
5561
 * Information used to parse text configuration options:
 */

static const Tk_OptionSpec optionSpecs[] = {
    {TK_OPTION_BOOLEAN, "-autoseparators", "autoSeparators",
	"AutoSeparators", DEF_TEXT_AUTO_SEPARATORS, -1,
	Tk_Offset(TkText, autoSeparators),
	TK_OPTION_DONT_SET_DEFAULT, 0, 0},
    {TK_OPTION_BORDER, "-background", "background", "Background",
	DEF_TEXT_BG_COLOR, -1, Tk_Offset(TkText, border),
	0, DEF_TEXT_BG_MONO, 0},
    {TK_OPTION_SYNONYM, "-bd", NULL, NULL,
	NULL, 0, -1, 0, "-borderwidth",
	TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_SYNONYM, "-bg", NULL, NULL,
................................................................................
	DEF_TEXT_INSERT_UNFOCUSSED, -1, Tk_Offset(TkText, insertUnfocussed),
	0, insertUnfocussedStrings, 0},
    {TK_OPTION_PIXELS, "-insertwidth", "insertWidth", "InsertWidth",
	DEF_TEXT_INSERT_WIDTH, -1, Tk_Offset(TkText, insertWidth),
	0, 0, 0},
    {TK_OPTION_INT, "-maxundo", "maxUndo", "MaxUndo",
	DEF_TEXT_MAX_UNDO, -1, Tk_Offset(TkText, maxUndo),
	TK_OPTION_DONT_SET_DEFAULT, 0, 0},
    {TK_OPTION_PIXELS, "-padx", "padX", "Pad",
	DEF_TEXT_PADX, -1, Tk_Offset(TkText, padX), 0, 0,
	TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_PIXELS, "-pady", "padY", "Pad",
	DEF_TEXT_PADY, -1, Tk_Offset(TkText, padY), 0, 0, 0},
    {TK_OPTION_RELIEF, "-relief", "relief", "Relief",
	DEF_TEXT_RELIEF, -1, Tk_Offset(TkText, relief), 0, 0, 0},
................................................................................
	DEF_TEXT_TABSTYLE, -1, Tk_Offset(TkText, tabStyle),
	0, tabStyleStrings, TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_STRING, "-takefocus", "takeFocus", "TakeFocus",
	DEF_TEXT_TAKE_FOCUS, -1, Tk_Offset(TkText, takeFocus),
	TK_OPTION_NULL_OK, 0, 0},
    {TK_OPTION_BOOLEAN, "-undo", "undo", "Undo",
	DEF_TEXT_UNDO, -1, Tk_Offset(TkText, undo),
	TK_OPTION_DONT_SET_DEFAULT, 0 , 0},
    {TK_OPTION_INT, "-width", "width", "Width",
	DEF_TEXT_WIDTH, -1, Tk_Offset(TkText, width), 0, 0,
	TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_STRING_TABLE, "-wrap", "wrap", "Wrap",
	DEF_TEXT_WRAP, -1, Tk_Offset(TkText, wrapMode),
	0, wrapStrings, TK_TEXT_LINE_GEOMETRY},
    {TK_OPTION_STRING, "-xscrollcommand", "xScrollCommand", "ScrollCommand",
................................................................................
		index = *indexFromPtr;
		index.byteIndex = 0;

		/*
		 * 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' (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 (TkTextIndexCmp(&index,indexToPtr) < 0) {
		    value += TkTextUpdateOneLine(textPtr, index.linePtr,
			    0, &index, 0);
		}

		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 (TkTextIndexCmp(&index,indexFromPtr) >= 0) {
			break;
		    }
		    TkTextIndexForwBytes(textPtr, &index, 1, &index);
		    value--;

		}
		if (indexToPtr->linePtr != lastPtr) {
		    index.linePtr = indexToPtr->linePtr;
		    index.byteIndex = 0;
		    while (1) {
			TkTextFindDisplayLineEnd(textPtr, &index, 1, NULL);
			if (TkTextIndexCmp(&index,indexToPtr) >= 0) {
			    break;
			}
			TkTextIndexForwBytes(textPtr, &index, 1, &index);
			value++;
		    }
		}

................................................................................
    case TEXT_MARK:
	result = TkTextMarkCmd(textPtr, interp, objc, objv);
	break;
    case TEXT_PEER:
	result = TextPeerCmd(textPtr, interp, objc, objv);
	break;
    case TEXT_PENDINGSYNC: {
	if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, NULL);
	    result = TCL_ERROR;
	    goto done;
	}
	Tcl_SetObjResult(interp,
		Tcl_NewBooleanObj(TkTextPendingsync(textPtr)));
	break;
    }
    case TEXT_REPLACE: {
	const TkTextIndex *indexFromPtr, *indexToPtr;

	if (objc < 5) {
	    Tcl_WrongNumArgs(interp, 2, objv,
		    "index1 index2 chars ?tagList chars tagList ...?");
................................................................................
	    if (TkTextPendingsync(textPtr)) {
		if (textPtr->afterSyncCmd) {
		    Tcl_DecrRefCount(textPtr->afterSyncCmd);
		}
		textPtr->afterSyncCmd = cmd;
	    } else {
		textPtr->afterSyncCmd = cmd;
		Tcl_DoWhenIdle(RunAfterSyncCmd, (ClientData) textPtr);
	    }
	    break;
	} else if (objc != 2) {
	    Tcl_WrongNumArgs(interp, 2, objv, "?-command command?");
	    result = TCL_ERROR;
	    goto done;
	}
................................................................................
	}

	/* Indices are potentially obsolete after changing -startline and/or
	 * -endline, therefore increase the epoch.
	 * Also, clamp the insert and current (unshared) marks to the new
	 * -startline/-endline range limits of the widget. All other (shared)
	 * marks are unchanged.
	 * The return value of TkTextMarkNameToIndex does not need to be
	 * checked: "insert" and "current" marks always exist, and the
	 * purpose of the code below precisely is to move them inside the
	 * -startline/-endline range.
	 */

	textPtr->sharedTextPtr->stateEpoch++;
	TkTextMarkNameToIndex(textPtr, "insert", &index3);
	if (TkTextIndexCmp(&index3, &index1) < 0) {
	    textPtr->insertMarkPtr = TkTextSetMark(textPtr, "insert", &index1);
	}
................................................................................
     * Make sure that configuration options are properly mirrored between the
     * widget record and the "sel" tags. NOTE: we don't have to free up
     * information during the mirroring; old information was freed when it was
     * replaced in the widget record.
     */

    if (textPtr->selTagPtr->selBorder == NULL) {
	textPtr->selTagPtr->border = textPtr->selBorder;
    } else {
	textPtr->selTagPtr->selBorder = textPtr->selBorder;
    }
    if (textPtr->selTagPtr->borderWidthPtr != textPtr->selBorderWidthPtr) {
	textPtr->selTagPtr->borderWidthPtr = textPtr->selBorderWidthPtr;
	textPtr->selTagPtr->borderWidth = textPtr->selBorderWidth;
    }
    if (textPtr->selTagPtr->selFgColor == NULL) {
	textPtr->selTagPtr->fgColor = textPtr->selFgColorPtr;
    } else {
	textPtr->selTagPtr->selFgColor = textPtr->selFgColorPtr;
    }
    textPtr->selTagPtr->affectsDisplay = 0;
    textPtr->selTagPtr->affectsDisplayGeometry = 0;
    if ((textPtr->selTagPtr->elideString != NULL)
	    || (textPtr->selTagPtr->tkfont != None)
	    || (textPtr->selTagPtr->justifyString != NULL)
	    || (textPtr->selTagPtr->lMargin1String != NULL)
................................................................................
	    || (textPtr->selTagPtr->selBorder != NULL)
	    || (textPtr->selTagPtr->reliefString != NULL)
	    || (textPtr->selTagPtr->bgStipple != None)
	    || (textPtr->selTagPtr->fgColor != NULL)
	    || (textPtr->selTagPtr->selFgColor != NULL)
	    || (textPtr->selTagPtr->fgStipple != None)
	    || (textPtr->selTagPtr->overstrikeString != NULL)
	    || (textPtr->selTagPtr->overstrikeColor != NULL)
	    || (textPtr->selTagPtr->underlineString != NULL)
	    || (textPtr->selTagPtr->underlineColor != NULL)
	    || (textPtr->selTagPtr->lMarginColor != NULL)
	    || (textPtr->selTagPtr->rMarginColor != NULL)) {
	textPtr->selTagPtr->affectsDisplay = 1;
    }
    TkTextRedrawTag(NULL, textPtr, NULL, NULL, textPtr->selTagPtr, 1);

    /*
     * Claim the selection if we've suddenly started exporting it and there
     * are tagged characters.
................................................................................
    Tk_GetFontMetrics(textPtr->tkfont, &fm);

    textPtr->charHeight = fm.linespace;
    if (textPtr->charHeight <= 0) {
	textPtr->charHeight = 1;
    }
    if (textPtr->charHeight != oldCharHeight) {
	TkBTreeClientRangeChanged(textPtr, textPtr->charHeight);
    }
    border = textPtr->borderWidth + textPtr->highlightWidth;
    Tk_GeometryRequest(textPtr->tkwin,
	    textPtr->width * textPtr->charWidth + 2*textPtr->padX + 2*border,
	    textPtr->height*(fm.linespace+textPtr->spacing1+textPtr->spacing3)
		    + 2*textPtr->padY + 2*border);

................................................................................
    if (insert) {
	TkUndoPushAction(textPtr->sharedTextPtr->undoStack, iAtom, dAtom);
    } else {
	TkUndoPushAction(textPtr->sharedTextPtr->undoStack, dAtom, iAtom);
    }

    if (!canUndo || canRedo) {
	GenerateUndoStackEvent(textPtr);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * TextUndoRedoCallback --
................................................................................
		 * Deletion range starts on top line but after topIndex. Use
		 * the current topIndex as the new one.
		 */

		resetView = 1;
		line = line1;
		byteIndex = tPtr->topIndex.byteIndex;
	    } else {
		/*
		 * Deletion range starts after the top line. This peers's view
		 * will not need to be reset. Nothing to do.
		 */
	    }
	} else if (index2.linePtr == tPtr->topIndex.linePtr) {
	    /*
	     * Deletion range ends on top line but before topIndex. Figure out
	     * what will be the new character index for the character
	     * currently pointed to by topIndex.
	     */
................................................................................
	    line = line2;
	    byteIndex = tPtr->topIndex.byteIndex;
	    if (index1.linePtr != index2.linePtr) {
		byteIndex -= index2.byteIndex;
	    } else {
		byteIndex -= (index2.byteIndex - index1.byteIndex);
	    }
	} else {
	    /*
	     * Deletion range ends before the top line. This peers's view
	     * will not need to be reset. Nothing to do.
	     */
	}
	if (resetView) {
	    lineAndByteIndex[resetViewCount] = line;
	    lineAndByteIndex[resetViewCount+1] = byteIndex;
	} else {
	    lineAndByteIndex[resetViewCount] = -1;
	}
................................................................................
	int line = lineAndByteIndex[resetViewCount];

	if (line != -1) {
	    int byteIndex = lineAndByteIndex[resetViewCount+1];
	    TkTextIndex indexTmp;

	    if (tPtr == textPtr) {
		if (viewUpdate) {
		    /*
		     * line cannot be before -startline of textPtr because
		     * this line corresponds to an index which is necessarily
		     * between "1.0" and "end" relative to textPtr.
		     * Therefore no need to clamp line to the -start/-end
		     * range.
		     */

		    TkTextMakeByteIndex(sharedTextPtr->tree, textPtr, line,
			    byteIndex, &indexTmp);
		    TkTextSetYView(tPtr, &indexTmp, 0);
		}
	    } else {
		TkTextMakeByteIndex(sharedTextPtr->tree, tPtr, line,
			byteIndex, &indexTmp);
		/*
		 * line may be before -startline of tPtr and must be
		 * clamped to -startline before providing it to
		 * TkTextSetYView otherwise lines before -startline
		 * would be displayed.
		 * There is no need to worry about -endline however,
		 * because the view will only be reset if the deletion
		 * involves the TOP line of the screen
		 */

		if (tPtr->start != NULL) {
		    int start;
		    TkTextIndex indexStart;

		    start = TkBTreeLinesTo(NULL, tPtr->start);
		    TkTextMakeByteIndex(sharedTextPtr->tree, NULL, start,
			    0, &indexStart);
		    if (TkTextIndexCmp(&indexTmp, &indexStart) < 0) {
			indexTmp = indexStart;
		    }
		}
		TkTextSetYView(tPtr, &indexTmp, 0);
	    }
	}
	resetViewCount += 2;
    }
    if (sharedTextPtr->refCount > PIXEL_CLIENTS) {
	ckfree(lineAndByteIndex);
................................................................................
    int index, setModified, oldModified;
    int canRedo = 0;
    int canUndo = 0;
    Tcl_Obj *rangesObj = Tcl_NewObj();

    static const char *const editOptionStrings[] = {
	"canundo", "canredo", "modified", "redo", "reset", "separator",
	"undo", NULL
    };
    enum editOptions {
	EDIT_CANUNDO, EDIT_CANREDO, EDIT_MODIFIED, EDIT_REDO, EDIT_RESET,
	EDIT_SEPARATOR, EDIT_UNDO
    };

    if (objc < 3) {
................................................................................
    if (Tcl_GetIndexFromObjStruct(interp, objv[2], editOptionStrings,
	    sizeof(char *), "edit option", 0, &index) != TCL_OK) {
	return TCL_ERROR;
    }

    switch ((enum editOptions) index) {
    case EDIT_CANREDO:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	     return TCL_ERROR;
	}
	if (textPtr->sharedTextPtr->undo) {
	    canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
	}
	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canRedo));
	break;
    case EDIT_CANUNDO:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	     return TCL_ERROR;
	}
	if (textPtr->sharedTextPtr->undo) {
	    canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
	}
	Tcl_SetObjResult(interp, Tcl_NewBooleanObj(canUndo));
	break;
    case EDIT_MODIFIED:
	if (objc == 3) {
	    Tcl_SetObjResult(interp,
		    Tcl_NewBooleanObj(textPtr->sharedTextPtr->isDirty));
	    return TCL_OK;
	} else if (objc != 4) {
	    Tcl_WrongNumArgs(interp, 3, objv, "?boolean?");
................................................................................

	/*
	 * Only issue the <<Modified>> event if the flag actually changed.
	 * However, degree of modified-ness doesn't matter. [Bug 1799782]
	 */

	if ((!oldModified) != (!setModified)) {
	    GenerateModifiedEvent(textPtr);
	}
	break;
    case EDIT_REDO:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
	if (TextEditRedo(textPtr, rangesObj)) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to redo", -1));
	    Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_REDO", NULL);
	    return TCL_ERROR;
        } else {
            Tcl_SetObjResult(interp, rangesObj);
        }
	canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
	if (!canUndo || !canRedo) {
	    GenerateUndoStackEvent(textPtr);
	}
	break;
    case EDIT_RESET:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
	canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
	TkUndoClearStacks(textPtr->sharedTextPtr->undoStack);
	if (canUndo || canRedo) {
	    GenerateUndoStackEvent(textPtr);
	}
	break;
    case EDIT_SEPARATOR:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	TkUndoInsertUndoSeparator(textPtr->sharedTextPtr->undoStack);
	break;
    case EDIT_UNDO:
	if (objc != 3) {
	    Tcl_WrongNumArgs(interp, 3, objv, NULL);
	    return TCL_ERROR;
	}
	canRedo = TkUndoCanRedo(textPtr->sharedTextPtr->undoStack);
	if (TextEditUndo(textPtr, rangesObj)) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj("nothing to undo", -1));
	    Tcl_SetErrorCode(interp, "TK", "TEXT", "NO_UNDO", NULL);
	    return TCL_ERROR;
        } else {
            Tcl_SetObjResult(interp, rangesObj);
        }
	canUndo = TkUndoCanUndo(textPtr->sharedTextPtr->undoStack);
	if (!canRedo || !canUndo) {
	    GenerateUndoStackEvent(textPtr);
	}
	break;
    }
    return TCL_OK;
}
 
/*
 *----------------------------------------------------------------------
................................................................................
/*
 *----------------------------------------------------------------------
 *
 * GenerateModifiedEvent --
 *
 *	Send an event that the text was modified. This is equivalent to:
 *	   event generate $textWidget <<Modified>>
 *	for all peers of $textWidget.
 *
 * Results:
 *	None
 *
 * Side effects:
 *	May force the text window into existence.
 *
 *----------------------------------------------------------------------
................................................................................
 */

static void
GenerateModifiedEvent(
    TkText *textPtr)	/* Information about text widget. */
{
    for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
	    textPtr = textPtr->next) {
	Tk_MakeWindowExist(textPtr->tkwin);
	TkSendVirtualEvent(textPtr->tkwin, "Modified", NULL);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * GenerateUndoStackEvent --
................................................................................
 */

static void
GenerateUndoStackEvent(
    TkText *textPtr)	/* Information about text widget. */
{
    for (textPtr = textPtr->sharedTextPtr->peers; textPtr != NULL;
	    textPtr = textPtr->next) {
	Tk_MakeWindowExist(textPtr->tkwin);
	TkSendVirtualEvent(textPtr->tkwin, "UndoStack", NULL);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * UpdateDirtyFlag --
................................................................................
    if (sharedTextPtr->dirtyMode == TK_TEXT_DIRTY_UNDO) {
	sharedTextPtr->isDirty--;
    } else {
	sharedTextPtr->isDirty++;
    }

    if (sharedTextPtr->isDirty == 0 || oldDirtyFlag == 0) {
	GenerateModifiedEvent(sharedTextPtr->peers);
    }
}
 
/*
 *----------------------------------------------------------------------
 *
 * RunAfterSyncCmd --
................................................................................
RunAfterSyncCmd(
    ClientData clientData)		/* Information about text widget. */
{
    register TkText *textPtr = (TkText *) clientData;
    int code;

    if ((textPtr->tkwin == NULL) || (textPtr->flags & DESTROYED)) {
	/*
	* The widget has been deleted. Don't do anything.
	*/

	if (--textPtr->refCount == 0) {
	    ckfree((char *) textPtr);
	}
	return;
    }

    Tcl_Preserve((ClientData) textPtr->interp);
    code = Tcl_EvalObjEx(textPtr->interp, textPtr->afterSyncCmd, TCL_EVAL_GLOBAL);
    if (code == TCL_ERROR) {
	Tcl_AddErrorInfo(textPtr->interp, "\n    (text sync)");
	Tcl_BackgroundError(textPtr->interp);
    }
    Tcl_Release((ClientData) textPtr->interp);
    Tcl_DecrRefCount(textPtr->afterSyncCmd);
    textPtr->afterSyncCmd = NULL;
}
 
/*

Changes to generic/tkWindow.c.

49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
...
201
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
243
244
245
246
247
248
....
3022
3023
3024
3025
3026
3027
3028










3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040






























3041
3042
3043
3044
3045
3046
3047
....
3051
3052
3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064
3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080
3081
3082
3083
3084
3085
3086
3087
3088
3089
3090
3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111
3112
3113
3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130
3131

3132
3133
3134
3135
3136
3137
3138



3139
3140
3141
3142
3143

3144
3145
3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157
3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169
3170
3171


3172
3173







3174
3175
3176
3177
3178

3179
3180





3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194





3195
3196
3197
3198

3199

3200
3201
3202
3203
3204
3205
3206
3207
3208
3209










3210

3211
3212
3213
3214
3215
3216
3217
3218
3219
3220
3221
3222





3223
3224
3225
3226


3227
3228
3229
3230
3231
3232
3233
3234
3235
3236

3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250

3251
3252
3253
3254
3255
3256

3257
3258
3259


3260
3261
3262
3263
3264
3265
3266
3267
3268
3269
3270
3271
3272
3273
3274
3275
3276

3277
3278
3279
3280
3281

3282
3283
3284
3285
3286
3287
3288
3289
3290
3291
3292
....
3315
3316
3317
3318
3319
3320
3321
3322
3323
3324
3325
3326
3327
3328
3329
3330
3331
3332
....
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
    TkDisplay *displayList;	/* List of all displays currently in use by
				 * the current thread. */
    int initialized;		/* 0 means the structures above need
				 * initializing. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;

/*
 * The Mutex below is used to lock access to the Tk_Uid structs above.
 */

TCL_DECLARE_MUTEX(windowMutex)

/*
 * Default values for "changes" and "atts" fields of TkWindows. Note that Tk
 * always requests all events for all windows, except StructureNotify events
 * on internal windows: these events are generated internally.
 */

static const XWindowChanges defChanges = {
................................................................................
#ifdef MAC_OSX_TK
    {"::tk::unsupported::MacWindowStyle",
			TkUnsupported1ObjCmd,	PASSMAINWINDOW|ISSAFE},
#endif
    {NULL,		NULL,			0}
};

/*
 * The variables and table below are used to parse arguments from the "argv"
 * variable in Tk_Init.
 */

static int synchronize = 0;
static char *name = NULL;
static char *display = NULL;
static char *geometry = NULL;
static char *colormap = NULL;
static char *use = NULL;
static char *visual = NULL;
static int rest = 0;

static const Tk_ArgvInfo argTable[] = {
    {"-colormap", TK_ARGV_STRING, NULL, (char *) &colormap,
	"Colormap for main window"},
    {"-display", TK_ARGV_STRING, NULL, (char *) &display,
	"Display to use"},
    {"-geometry", TK_ARGV_STRING, NULL, (char *) &geometry,
	"Initial geometry for window"},
    {"-name", TK_ARGV_STRING, NULL, (char *) &name,
	"Name to use for application"},
    {"-sync", TK_ARGV_CONSTANT, (char *) 1, (char *) &synchronize,
	"Use synchronous mode for display server"},
    {"-visual", TK_ARGV_STRING, NULL, (char *) &visual,
	"Visual for main window"},
    {"-use", TK_ARGV_STRING, NULL, (char *) &use,
	"Id of window in which to embed application"},
    {"--", TK_ARGV_REST, (char *) 1, (char *) &rest,
	"Pass all remaining arguments through to script"},
    {NULL, TK_ARGV_END, NULL, NULL, NULL}
};

/*
 * Forward declarations to functions defined later in this file:
 */

static Tk_Window	CreateTopLevelWindow(Tcl_Interp *interp,
			    Tk_Window parent, const char *name,
			    const char *screenName, unsigned int flags);
................................................................................
 *	result if there was an error.
 *
 * Side effects:
 *	Depends on the initialization scripts that are invoked.
 *
 *----------------------------------------------------------------------
 */











static int
Initialize(
    Tcl_Interp *interp)		/* Interpreter to initialize. */
{
    char *p;
    int argc, code;
    const char **argv;
    const char *args[20];
    const char *argString = NULL;
    Tcl_DString class;
    ThreadSpecificData *tsdPtr;































    /*
     * Ensure that we are getting a compatible version of Tcl.
     */

    if (Tcl_InitStubs(interp, "8.6", 0) == NULL) {
	return TCL_ERROR;
................................................................................
     * Ensure that our obj-types are registered with the Tcl runtime.
     */

    TkRegisterObjTypes();

    tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));

    /*
     * Start by initializing all the static variables to default acceptable
     * values so that no information is leaked from a previous run of this
     * code.
     */

    Tcl_MutexLock(&windowMutex);
    synchronize = 0;
    name = NULL;
    display = NULL;
    geometry = NULL;
    colormap = NULL;
    use = NULL;
    visual = NULL;
    rest = 0;
    argv = NULL;

    /*
     * We start by resetting the result because it might not be clean.
     */

    Tcl_ResetResult(interp);

    if (Tcl_IsSafe(interp)) {
	/*
	 * Get the clearance to start Tk and the "argv" parameters from the
	 * master.
	 */

	Tcl_DString ds;

	/*
	 * Step 1 : find the master and construct the interp name (could be a
	 * function if new APIs were ok). We could also construct the path
	 * while walking, but there is no API to get the name of an interp
	 * either.
	 */

	Tcl_Interp *master = interp;

	while (1) {
	    master = Tcl_GetMaster(master);
	    if (master == NULL) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"no controlling master interpreter", -1));
		Tcl_SetErrorCode(interp, "TK", "SAFE", "NO_MASTER", NULL);
		code = TCL_ERROR;
		goto done;
	    }
	    if (!Tcl_IsSafe(master)) {
		/* Found the trusted master. */
		break;
	    }
	}

	/*
	 * Construct the name (rewalk...)
	 */

	code = Tcl_GetInterpPath(master, interp);
	if (code != TCL_OK) {
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		    "error in Tcl_GetInterpPath", -1));
	    Tcl_SetErrorCode(interp, "TK", "SAFE", "FAILED", NULL);
	    goto done;
	}

	/*
	 * Build the string to eval.
	 */

	Tcl_DStringInit(&ds);
	Tcl_DStringAppendElement(&ds, "::safe::TkInit");
	Tcl_DStringAppendElement(&ds, Tcl_GetString(Tcl_GetObjResult(master)));


	/*
	 * Step 2 : Eval in the master. The argument is the *reversed* interp
	 * path of the slave.
	 */

	code = Tcl_EvalEx(master, Tcl_DStringValue(&ds), -1, 0);



	if (code != TCL_OK) {
	    /*
	     * We might want to transfer the error message or not. We don't.
	     * (No API to do it and maybe security reasons).
	     */


	    Tcl_DStringFree(&ds);
	    Tcl_SetObjResult(interp, Tcl_NewStringObj(
		    "not allowed to start Tk by master's safe::TkInit", -1));
	    Tcl_SetErrorCode(interp, "TK", "SAFE", "FAILED", NULL);
	    goto done;
	}
	Tcl_DStringFree(&ds);

	/*
	 * Use the master's result as argv. Note: We don't use the Obj
	 * interfaces to avoid dealing with cross interp refcounting and
	 * changing the code below.
	 */

	argString = Tcl_GetString(Tcl_GetObjResult(master));
    } else {
	/*
	 * If there is an "argv" variable, get its value, extract out relevant
	 * arguments from it, and rewrite the variable without the arguments
	 * that we used.
	 */

	argString = Tcl_GetVar2(interp, "argv", NULL, TCL_GLOBAL_ONLY);
    }
    if (argString != NULL) {
	char buffer[TCL_INTEGER_SPACE];



	if (Tcl_SplitList(interp, argString, &argc, &argv) != TCL_OK) {
	argError:







	    Tcl_AddErrorInfo(interp,
		    "\n    (processing arguments in argv variable)");
	    code = TCL_ERROR;
	    goto done;
	}

	if (Tk_ParseArgv(interp, (Tk_Window) NULL, &argc, argv,
		argTable, TK_ARGV_DONT_SKIP_FIRST_ARG|TK_ARGV_NO_DEFAULTS)





		!= TCL_OK) {
	    goto argError;
	}
	p = Tcl_Merge(argc, argv);
	Tcl_SetVar2(interp, "argv", NULL, p, TCL_GLOBAL_ONLY);
	sprintf(buffer, "%d", argc);
	Tcl_SetVar2(interp, "argc", NULL, buffer, TCL_GLOBAL_ONLY);
	ckfree(p);
    }

    /*
     * Figure out the application's name and class.
     */






    Tcl_DStringInit(&class);
    if (name == NULL) {
	int offset;


	TkpGetAppName(interp, &class);

	offset = Tcl_DStringLength(&class)+1;
	Tcl_DStringSetLength(&class, offset);
	Tcl_DStringAppend(&class, Tcl_DStringValue(&class), offset-1);
	name = Tcl_DStringValue(&class) + offset;
    } else {
	Tcl_DStringAppend(&class, name, -1);
    }

    p = Tcl_DStringValue(&class);
    if (*p) {










	Tcl_UtfToTitle(p);

    }

    /*
     * Create an argument list for creating the top-level window, using the
     * information parsed from argv, if any.
     */

    args[0] = "toplevel";
    args[1] = ".";
    args[2] = "-class";
    args[3] = Tcl_DStringValue(&class);
    argc = 4;





    if (display != NULL) {
	args[argc] = "-screen";
	args[argc+1] = display;
	argc += 2;



	/*
	 * If this is the first application for this process, save the display
	 * name in the DISPLAY environment variable so that it will be
	 * available to subprocesses created by us.
	 */

	if (tsdPtr->numMainWindows == 0) {
	    Tcl_SetVar2(interp, "env", "DISPLAY", display, TCL_GLOBAL_ONLY);
	}

    }
    if (colormap != NULL) {
	args[argc] = "-colormap";
	args[argc+1] = colormap;
	argc += 2;
	colormap = NULL;
    }
    if (use != NULL) {
	args[argc] = "-use";
	args[argc+1] = use;
	argc += 2;
	use = NULL;
    }
    if (visual != NULL) {

	args[argc] = "-visual";
	args[argc+1] = visual;
	argc += 2;
	visual = NULL;
    }
    args[argc] = NULL;

    code = TkCreateFrame(NULL, interp, argc, args, 1, name);

    Tcl_DStringFree(&class);


    if (code != TCL_OK) {
	goto done;
    }
    Tcl_ResetResult(interp);
    if (synchronize) {
	XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);
    }

    /*
     * Set the geometry of the main window, if requested. Put the requested
     * geometry into the "geometry" variable.
     */

    if (geometry != NULL) {
	Tcl_DString buf;

	Tcl_SetVar2(interp, "geometry", NULL, geometry, TCL_GLOBAL_ONLY);

	Tcl_DStringInit(&buf);
	Tcl_DStringAppend(&buf, "wm geometry . ", -1);
	Tcl_DStringAppend(&buf, geometry, -1);
	code = Tcl_EvalEx(interp, Tcl_DStringValue(&buf), -1, 0);
	Tcl_DStringFree(&buf);

	if (code != TCL_OK) {
	    goto done;
	}
	geometry = NULL;
    }

    /*
     * Provide Tk and its stub table.
     */

    code = Tcl_PkgProvideEx(interp, "Tk", TK_PATCH_LEVEL,
................................................................................

    /*
     * Invoke platform-specific initialization. Unlock mutex before entering
     * TkpInit, as that may run through the Tk_Init routine again for the
     * console window interpreter.
     */

    Tcl_MutexUnlock(&windowMutex);
    if (argv != NULL) {
	ckfree(argv);
    }
    code = TkpInit(interp);
    if (code == TCL_OK) {

	/*
	 * In order to find tk.tcl during initialization, we evaluate the
	 * following script.  It calls on the Tcl command [tcl_findLibrary]
	 * to perform the search.  See the docs for that command for details
................................................................................
	 * Create exit handlers to delete all windows when the application or
	 * thread exits. The handler need to be invoked before other platform
	 * specific cleanups take place to avoid panics in finalization.
	 */

	TkCreateThreadExitHandler(DeleteWindowsExitProc, tsdPtr);
    }
    return code;

  done:
    Tcl_MutexUnlock(&windowMutex);
    if (argv != NULL) {
	ckfree(argv);
    }
    return code;
}
 
/*
 *----------------------------------------------------------------------
 *







<
<
<
<
<
<







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<







 







>
>
>
>
>
>
>
>
>
>





|
<
<
<
<
<

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<
<












<
<









|





|
<
<
<
<
<









<
|
<
<



|


|
|
|
>
|





|
>
>
>

<
<
<
<
>
|
<
<
<
<
<
<
<







|







|

<
<

>
>
|
|
>
>
>
>
>
>
>



<

>
|
|
>
>
>
>
>
|
|

<
<
<
<
<






>
>
>
>
>
|
<
<

>
|
>
|
<
<
<
<
|


<
<
>
>
>
>
>
>
>
>
>
>
|
>







<
<
<
<
<
>
>
>
>
>
|
<
<
<
>
>








|

>

|
<
|
|
|

|
|
|
<
|

|
>
|
<
<
|

<
>
|

<
>
>




|








|
<

|
>
|
|
|
|
|
>



<







 







<
<
<
<







 







|
|
|
|
<
<







49
50
51
52
53
54
55






56
57
58
59
60
61
62
...
195
196
197
198
199
200
201


































202
203
204
205
206
207
208
....
2982
2983
2984
2985
2986
2987
2988
2989
2990
2991
2992
2993
2994
2995
2996
2997
2998
2999
3000
3001
3002
3003
3004





3005
3006
3007
3008
3009
3010
3011
3012
3013
3014
3015
3016
3017
3018
3019
3020
3021
3022
3023
3024
3025
3026
3027
3028
3029
3030
3031
3032
3033
3034
3035
3036
3037
3038
3039
3040
3041
3042
....
3046
3047
3048
3049
3050
3051
3052

















3053
3054
3055
3056
3057
3058
3059
3060
3061
3062
3063
3064


3065
3066
3067
3068
3069
3070
3071
3072
3073
3074
3075
3076
3077
3078
3079
3080





3081
3082
3083
3084
3085
3086
3087
3088
3089

3090


3091
3092
3093
3094
3095
3096
3097
3098
3099
3100
3101
3102
3103
3104
3105
3106
3107
3108
3109
3110
3111




3112
3113







3114
3115
3116
3117
3118
3119
3120
3121
3122
3123
3124
3125
3126
3127
3128
3129
3130


3131
3132
3133
3134
3135
3136
3137
3138
3139
3140
3141
3142
3143
3144
3145

3146
3147
3148
3149
3150
3151
3152
3153
3154
3155
3156
3157





3158
3159
3160
3161
3162
3163
3164
3165
3166
3167
3168
3169


3170
3171
3172
3173
3174




3175
3176
3177


3178
3179
3180
3181
3182
3183
3184
3185
3186
3187
3188
3189
3190
3191
3192
3193
3194
3195
3196





3197
3198
3199
3200
3201
3202



3203
3204
3205
3206
3207
3208
3209
3210
3211
3212
3213
3214
3215
3216
3217

3218
3219
3220
3221
3222
3223
3224

3225
3226
3227
3228
3229


3230
3231

3232
3233
3234

3235
3236
3237
3238
3239
3240
3241
3242
3243
3244
3245
3246
3247
3248
3249
3250

3251
3252
3253
3254
3255
3256
3257
3258
3259
3260
3261
3262

3263
3264
3265
3266
3267
3268
3269
....
3292
3293
3294
3295
3296
3297
3298




3299
3300
3301
3302
3303
3304
3305
....
3324
3325
3326
3327
3328
3329
3330
3331
3332
3333
3334


3335
3336
3337
3338
3339
3340
3341
    TkDisplay *displayList;	/* List of all displays currently in use by
				 * the current thread. */
    int initialized;		/* 0 means the structures above need
				 * initializing. */
} ThreadSpecificData;
static Tcl_ThreadDataKey dataKey;







/*
 * Default values for "changes" and "atts" fields of TkWindows. Note that Tk
 * always requests all events for all windows, except StructureNotify events
 * on internal windows: these events are generated internally.
 */

static const XWindowChanges defChanges = {
................................................................................
#ifdef MAC_OSX_TK
    {"::tk::unsupported::MacWindowStyle",
			TkUnsupported1ObjCmd,	PASSMAINWINDOW|ISSAFE},
#endif
    {NULL,		NULL,			0}
};



































/*
 * Forward declarations to functions defined later in this file:
 */

static Tk_Window	CreateTopLevelWindow(Tcl_Interp *interp,
			    Tk_Window parent, const char *name,
			    const char *screenName, unsigned int flags);
................................................................................
 *	result if there was an error.
 *
 * Side effects:
 *	Depends on the initialization scripts that are invoked.
 *
 *----------------------------------------------------------------------
 */

static int
CopyValue(
    ClientData dummy,
    Tcl_Obj *objPtr,
    void *dstPtr)
{
    *(Tcl_Obj **)dstPtr = objPtr;
    return 1;
}

static int
Initialize(
    Tcl_Interp *interp)		/* Interpreter to initialize. */
{
    int code = TCL_OK;





    ThreadSpecificData *tsdPtr;
    Tcl_Obj *value = NULL;
    Tcl_Obj *cmd;

    Tcl_Obj *nameObj = NULL;
    Tcl_Obj *classObj = NULL;
    Tcl_Obj *displayObj = NULL;
    Tcl_Obj *colorMapObj = NULL;
    Tcl_Obj *useObj = NULL;
    Tcl_Obj *visualObj = NULL;
    Tcl_Obj *geometryObj = NULL;

    int sync = 0;

    const Tcl_ArgvInfo table[] = {
	{TCL_ARGV_CONSTANT, "-sync", INT2PTR(1), &sync,
		"Use synchronous mode for display server", NULL},
	{TCL_ARGV_FUNC, "-colormap", CopyValue, &colorMapObj,
		"Colormap for main window", NULL},
	{TCL_ARGV_FUNC, "-display", CopyValue, &displayObj,
		"Display to use", NULL},
	{TCL_ARGV_FUNC, "-geometry", CopyValue, &geometryObj,
		"Initial geometry for window", NULL},
	{TCL_ARGV_FUNC, "-name", CopyValue, &nameObj,
		"Name to use for application", NULL},
	{TCL_ARGV_FUNC, "-visual", CopyValue, &visualObj,
		"Visual for main window", NULL},
	{TCL_ARGV_FUNC, "-use", CopyValue, &useObj,
		"Id of window in which to embed application", NULL},
	TCL_ARGV_AUTO_REST, TCL_ARGV_AUTO_HELP, TCL_ARGV_TABLE_END
    };

    /*
     * Ensure that we are getting a compatible version of Tcl.
     */

    if (Tcl_InitStubs(interp, "8.6", 0) == NULL) {
	return TCL_ERROR;
................................................................................
     * Ensure that our obj-types are registered with the Tcl runtime.
     */

    TkRegisterObjTypes();

    tsdPtr = Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData));


















    /*
     * We start by resetting the result because it might not be clean.
     */

    Tcl_ResetResult(interp);

    if (Tcl_IsSafe(interp)) {
	/*
	 * Get the clearance to start Tk and the "argv" parameters from the
	 * master.
	 */



	/*
	 * Step 1 : find the master and construct the interp name (could be a
	 * function if new APIs were ok). We could also construct the path
	 * while walking, but there is no API to get the name of an interp
	 * either.
	 */

	Tcl_Interp *master = interp;

	while (Tcl_IsSafe(master)) {
	    master = Tcl_GetMaster(master);
	    if (master == NULL) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"no controlling master interpreter", -1));
		Tcl_SetErrorCode(interp, "TK", "SAFE", "NO_MASTER", NULL);
		return TCL_ERROR;





	    }
	}

	/*
	 * Construct the name (rewalk...)
	 */

	code = Tcl_GetInterpPath(master, interp);
	if (code != TCL_OK) {

	    Tcl_Panic("Tcl_GetInterpPath broken!");


	}

	/*
	 * Build the command to eval in trusted master.
	 */

	cmd = Tcl_NewListObj(2, NULL);
	Tcl_ListObjAppendElement(NULL, cmd,
		Tcl_NewStringObj("::safe::TkInit", -1));
	Tcl_ListObjAppendElement(NULL, cmd, Tcl_GetObjResult(master));
	
	/*
	 * Step 2 : Eval in the master. The argument is the *reversed* interp
	 * path of the slave.
	 */

	Tcl_IncrRefCount(cmd);
	code = Tcl_EvalObjEx(master, cmd, 0);
	Tcl_DecrRefCount(cmd);
	Tcl_TransferResult(master, code, interp);
	if (code != TCL_OK) {




	    return code;
	}








	/*
	 * Use the master's result as argv. Note: We don't use the Obj
	 * interfaces to avoid dealing with cross interp refcounting and
	 * changing the code below.
	 */

	value = Tcl_GetObjResult(interp);
    } else {
	/*
	 * If there is an "argv" variable, get its value, extract out relevant
	 * arguments from it, and rewrite the variable without the arguments
	 * that we used.
	 */

	value = Tcl_GetVar2Ex(interp, "argv", NULL, TCL_GLOBAL_ONLY);
    }



    if (value) {
	int objc;
	Tcl_Obj **objv, **rest;
	Tcl_Obj *parseList = Tcl_NewListObj(1, NULL);

	Tcl_ListObjAppendElement(NULL, parseList, Tcl_NewObj());

	Tcl_IncrRefCount(value);
	if (TCL_OK != Tcl_ListObjAppendList(interp, parseList, value) ||
	    TCL_OK != Tcl_ListObjGetElements(NULL, parseList, &objc, &objv) ||
	    TCL_OK != Tcl_ParseArgsObjv(interp, table, &objc, objv, &rest)) {
	    Tcl_AddErrorInfo(interp,
		    "\n    (processing arguments in argv variable)");
	    code = TCL_ERROR;

	}
	if (code == TCL_OK) {
	    Tcl_SetVar2Ex(interp, "argv", NULL,
		    Tcl_NewListObj(objc-1, rest+1), TCL_GLOBAL_ONLY);
	    Tcl_SetVar2Ex(interp, "argc", NULL,
		    Tcl_NewIntObj(objc-1), TCL_GLOBAL_ONLY);
	    ckfree(rest);
	}
	Tcl_DecrRefCount(parseList);
	if (code != TCL_OK) {
	    goto done;
	}





    }

    /*
     * Figure out the application's name and class.
     */

    /*
     * If we got no -name argument, fetch from TkpGetAppName().
     */

    if (nameObj == NULL) {
	Tcl_DString nameDS;



	Tcl_DStringInit(&nameDS);
	TkpGetAppName(interp, &nameDS);
	nameObj = Tcl_NewStringObj(Tcl_DStringValue(&nameDS),
		Tcl_DStringLength(&nameDS));




	Tcl_DStringFree(&nameDS);
    }



    /*
     * The -class argument is always the ToTitle of the -name
     */

    {
	int numBytes;
	const char *bytes = Tcl_GetStringFromObj(nameObj, &numBytes);

	classObj = Tcl_NewStringObj(bytes, numBytes);

	numBytes = Tcl_UtfToTitle(Tcl_GetString(classObj));
	Tcl_SetObjLength(classObj, numBytes);
    }

    /*
     * Create an argument list for creating the top-level window, using the
     * information parsed from argv, if any.
     */






    cmd = Tcl_NewStringObj("toplevel . -class", -1);

    Tcl_ListObjAppendElement(NULL, cmd, classObj);
    classObj = NULL;

    if (displayObj) {



	Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-screen", -1));
	Tcl_ListObjAppendElement(NULL, cmd, displayObj);

	/*
	 * If this is the first application for this process, save the display
	 * name in the DISPLAY environment variable so that it will be
	 * available to subprocesses created by us.
	 */

	if (tsdPtr->numMainWindows == 0) {
	    Tcl_SetVar2Ex(interp, "env", "DISPLAY", displayObj, TCL_GLOBAL_ONLY);
	}
	displayObj = NULL;
    }
    if (colorMapObj) {

	Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-colormap", -1));
	Tcl_ListObjAppendElement(NULL, cmd, colorMapObj);
	colorMapObj = NULL;
    }
    if (useObj) {
	Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-use", -1));
	Tcl_ListObjAppendElement(NULL, cmd, useObj);

	useObj = NULL;
    }
    if (visualObj) {
	Tcl_ListObjAppendElement(NULL, cmd, Tcl_NewStringObj("-visual", -1));
	Tcl_ListObjAppendElement(NULL, cmd, visualObj);


	visualObj = NULL;
    }


    code = TkListCreateFrame(NULL, interp, cmd, 1, nameObj);


    Tcl_DecrRefCount(cmd);

    if (code != TCL_OK) {
	goto done;
    }
    Tcl_ResetResult(interp);
    if (sync) {
	XSynchronize(Tk_Display(Tk_MainWindow(interp)), True);
    }

    /*
     * Set the geometry of the main window, if requested. Put the requested
     * geometry into the "geometry" variable.
     */

    if (geometryObj) {


	Tcl_SetVar2Ex(interp, "geometry", NULL, geometryObj, TCL_GLOBAL_ONLY);

	cmd = Tcl_NewStringObj("wm geometry .", -1);
	Tcl_ListObjAppendElement(NULL, cmd, geometryObj);
	Tcl_IncrRefCount(cmd);
	code = Tcl_EvalObjEx(interp, cmd, 0);
	Tcl_DecrRefCount(cmd);
	geometryObj = NULL;
	if (code != TCL_OK) {
	    goto done;
	}

    }

    /*
     * Provide Tk and its stub table.
     */

    code = Tcl_PkgProvideEx(interp, "Tk", TK_PATCH_LEVEL,
................................................................................

    /*
     * Invoke platform-specific initialization. Unlock mutex before entering
     * TkpInit, as that may run through the Tk_Init routine again for the
     * console window interpreter.
     */





    code = TkpInit(interp);
    if (code == TCL_OK) {

	/*
	 * In order to find tk.tcl during initialization, we evaluate the
	 * following script.  It calls on the Tcl command [tcl_findLibrary]
	 * to perform the search.  See the docs for that command for details
................................................................................
	 * Create exit handlers to delete all windows when the application or
	 * thread exits. The handler need to be invoked before other platform
	 * specific cleanups take place to avoid panics in finalization.
	 */

	TkCreateThreadExitHandler(DeleteWindowsExitProc, tsdPtr);
    }
  done:
    if (value) {
	Tcl_DecrRefCount(value);
	value = NULL;


    }
    return code;
}
 
/*
 *----------------------------------------------------------------------
 *

Changes to tests/safe.test.

183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
} -result {}

test safe-5.1 {loading Tk in safe interps without master's clearance} -body {
    set i [safe::interpCreate]
    interp eval $i {load {} Tk}
} -cleanup {
    safe::interpDelete $i
} -returnCodes error -result {not allowed to start Tk by master's safe::TkInit}
test safe-5.2 {multi-level Tk loading with clearance} -setup {
    set safeParent [safe::interpCreate]
} -body {
    # No error shall occur in that test and no window shall remain at the end.
    set i [safe::interpCreate [list $safeParent x]]
    safe::loadTk $i
    interp eval $i {







|







183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
} -result {}

test safe-5.1 {loading Tk in safe interps without master's clearance} -body {
    set i [safe::interpCreate]
    interp eval $i {load {} Tk}
} -cleanup {
    safe::interpDelete $i
} -returnCodes error -result {not allowed}
test safe-5.2 {multi-level Tk loading with clearance} -setup {
    set safeParent [safe::interpCreate]
} -body {
    # No error shall occur in that test and no window shall remain at the end.
    set i [safe::interpCreate [list $safeParent x]]
    safe::loadTk $i
    interp eval $i {