Tk Source Code

Changes On Branch mojave-cleanup
Login

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

Changes In Branch mojave-cleanup Excluding Merge-Ins

This is equivalent to a diff from 5be31db0 to f0df87e1

2018-10-30
16:15
Many updates for macOS. Most, but not all, were triggered by changes between OSX 10.13 and 10.14. check-in: e972802e user: culler tags: core-8-6-branch
15:49
Edited comments in tkMacOSXScrlbr.c Closed-Leaf check-in: f0df87e1 user: culler tags: mojave-cleanup
03:56
Fixed scrollbar behavior. Added some padding in buttons for 10.6 only. check-in: d711e835 user: culler tags: mojave-cleanup
2018-10-22
20:42
Add test textDisp-24.25 exercising a basic testcase for Tablelist (see [1c8aad0efa] check-in: f6ab49c4 user: fvogel tags: core-8-6-branch
2018-10-21
21:41
Deal with Mojave deprecations and remove unneeded code. check-in: c5a4c766 user: culler tags: mojave-cleanup
16:23
Remove knownBug constraint on test scrollbar-6.27 as this test now passes (checked on Vista - comment there was for Win2K) check-in: 6fee05d9 user: fvogel tags: trunk
16:23
Remove knownBug constraint on test scrollbar-6.27 as this test now passes (checked on Vista - comment there was for Win2K) check-in: 5be31db0 user: fvogel tags: core-8-6-branch
2018-10-19
17:13
Remove 'knownBug' constraint on tests that do pass without it (text-22.199 and 22.200), and fix error in the regexp for other tests (text-22.202 and 22.203) that then pass (constraint 'knownBug' removed as well therefore). check-in: e8973162 user: fvogel tags: core-8-6-branch

Changes to generic/tkBind.c.
71
72
73
74
75
76
77











78



79
80
81
82
83
84
85
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88

89
90
91
92
93
94
95
96
97
98







+
+
+
+
+
+
+
+
+
+
+
-
+
+
+







 * down (and auto-repeating). There may be as many as 3 auto-repeat events
 * after each mouse button press or release (see the first large comment block
 * within Tk_BindEvent for more on this), for a total of 20 events to cover
 * the three button presses and two intervening releases. If you reduce
 * EVENT_BUFFER_SIZE too much, shift multi-clicks will be lost.
 */

/*
 * NOTE: The changes which were needed to make Tk work on OSX 10.14 (Mojave)
 * also demand that the event ring be a bit bigger.  It might be wise to
 * augment the current double-click pattern matching by adding a new
 * DoubleClick modifier bit which could be set based on the clickCount of the
 * Apple NSEvent object.
 */

#ifndef TK_MAC_OSX
  #define EVENT_BUFFER_SIZE 45
#else
#define EVENT_BUFFER_SIZE 30
  #define EVENT_BUFFER_SIZE 30
#endif

typedef struct Tk_BindingTable_ {
    XEvent eventRing[EVENT_BUFFER_SIZE];
				/* Circular queue of recent events (higher
				 * indices are for more recent events). */
    Detail detailRing[EVENT_BUFFER_SIZE];
				/* "Detail" information (keySym, button,
				 * Tk_Uid, or 0) for each entry in
Changes to generic/tkButton.c.
875
876
877
878
879
880
881





882

883
884
885
886
887
888
889
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895







+
+
+
+
+

+







		 * Special note: must cancel any existing idle handler for
		 * TkpDisplayButton; it's no longer needed, and
		 * TkpDisplayButton cleared the REDRAW_PENDING flag.
		 */

		Tcl_CancelIdleCall(TkpDisplayButton, butPtr);
		XFlush(butPtr->display);
		#ifndef MAC_OSX_TK
		/*
		 * On the mac you can not sleep in a display proc, and the
		 * flash command doesn't do anything anyway.
		 */
		Tcl_Sleep(50);
		#endif
	    }
	}
	break;

    case COMMAND_INVOKE:
	if (objc > 2) {
	    Tcl_WrongNumArgs(interp, 1, objv, "invoke");
Changes to generic/tkTextDisp.c.
20
21
22
23
24
25
26





27
28
29
30
31
32
33
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38







+
+
+
+
+







#include "tkWinInt.h"
#elif defined(__CYGWIN__)
#include "tkUnixInt.h"
#endif

#ifdef MAC_OSX_TK
#include "tkMacOSXInt.h"
#define OK_TO_LOG (!TkpAppIsDrawing())
#define FORCE_DISPLAY(winPtr) TkpDisplayWindow(winPtr)
#else
#define OK_TO_LOG 1
#define FORCE_DISPLAY(winPtr)
#endif

/*
 * "Calculations of line pixel heights and the size of the vertical
 * scrollbar."
 *
 * Given that tag, font and elide changes can happen to large numbers of
199
200
201
202
203
204
205
206






207
208
209
210
211







212
213
214
215
216
217
218
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







-
+
+
+
+
+
+


-
-
-
+
+
+
+
+
+
+







 * precision is different (e.g. Intel)
 */

#define FP_EQUAL_SCALE(double1, double2, scaleFactor) \
    (fabs((double1)-(double2))*((scaleFactor)+1.0) < 0.3)

/*
 * Macro to make debugging/testing logging a little easier.
 * Macros to make debugging/testing logging a little easier.
 *
 * On OSX 10.14 Drawing procedures are sometimes run because the system has
 * decided to redraw the window.  This can corrupt the data that a test is
 * trying to collect.  So we don't write to the logging variables when the
 * drawing procedure is being run that way.  Other systems can always log.
 */

#define LOG(toVar,what) \
    Tcl_SetVar2(textPtr->interp, toVar, NULL, (what), \
	    TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT)
#define LOG(toVar,what)							\
    if (OK_TO_LOG)							\
        Tcl_SetVar2(textPtr->interp, toVar, NULL, (what),		\
		    TCL_GLOBAL_ONLY|TCL_APPEND_VALUE|TCL_LIST_ELEMENT)	
#define CLEAR(var)							\
    if (OK_TO_LOG)							\
	Tcl_SetVar2(interp, var, NULL, "", TCL_GLOBAL_ONLY)

/*
 * The following structure describes one line of the display, which may be
 * either part or all of one line of the text.
 */

typedef struct DLine {
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







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







 */

static void
GenerateWidgetViewSyncEvent(
    TkText *textPtr,		/* Information about text widget. */
    Bool InSync)                /* true if in sync, false otherwise */
{
    /*
     * OSX 10.14 needs to be told to display the window when the Text Widget
     * is in sync.  (That is, to run DisplayText inside of the drawRect
     * method.)  Otherwise the screen might not get updated until an event
     * like a mouse click is received.  But that extra drawing corrupts the
     * data that the test suite is trying to collect.
     */
    
    if (!tkTextDebug) {
	FORCE_DISPLAY(textPtr->tkwin);
    }
    
    TkSendVirtualEvent(textPtr->tkwin, "WidgetViewSync",
        Tcl_NewBooleanObj(InSync));
}

/*
 *----------------------------------------------------------------------
 *
4132
4133
4134
4135
4136
4137
4138
4139

4140
4141
4142
4143
4144
4145
4146
4147
4148
4149
4150

4151
4152
4153
4154
4155
4156
4157
4158
4159
4160
4161
4162
4163
4164

4165
4166
4167
4168
4169
4170
4171
4172
4173
4174
4175

4176
4177
4178
4179
4180
4181
4182
4183







-
+










-
+







	return;
    }

    interp = textPtr->interp;
    Tcl_Preserve(interp);

    if (tkTextDebug) {
	Tcl_SetVar2(interp, "tk_textRelayout", NULL, "", TCL_GLOBAL_ONLY);
	CLEAR("tk_textRelayout");
    }

    if (!Tk_IsMapped(textPtr->tkwin) || (dInfoPtr->maxX <= dInfoPtr->x)
	    || (dInfoPtr->maxY <= dInfoPtr->y)) {
	UpdateDisplayInfo(textPtr);
	dInfoPtr->flags &= ~REDRAW_PENDING;
	goto doScrollbars;
    }
    numRedisplays++;
    if (tkTextDebug) {
	Tcl_SetVar2(interp, "tk_textRedraw", NULL, "", TCL_GLOBAL_ONLY);
	CLEAR("tk_textRedraw");
    }

    /*
     * Choose a new current item if that is needed (this could cause event
     * handlers to be invoked, hence the preserve/release calls and the loop,
     * since the handlers could conceivably necessitate yet another current
     * item calculation). The tkwin check is because the whole window could go
5130
5131
5132
5133
5134
5135
5136

5137
5138
5139
5140
5141
5142
5143
5144

5145
5146
5147
5148
5149
5150
5151
5156
5157
5158
5159
5160
5161
5162
5163
5164
5165
5166
5167
5168
5169
5170
5171
5172
5173
5174
5175
5176
5177
5178
5179







+








+







    TkText *textPtr,		/* Widget record for text widget. */
    int mask)			/* OR'd collection of bits showing what has
				 * changed. */
{
    TextDInfo *dInfoPtr = textPtr->dInfoPtr;
    GC newGC;
    XGCValues gcValues;
    Bool inSync = 1;

    /*
     * Schedule the window redisplay. See TkTextChanged for the reason why
     * this has to be done before any calls to FreeDLines.
     */

    if (!(dInfoPtr->flags & REDRAW_PENDING)) {
	Tcl_DoWhenIdle(DisplayText, textPtr);
	inSync = 0;
    }
    dInfoPtr->flags |= REDRAW_PENDING|REDRAW_BORDERS|DINFO_OUT_OF_DATE
	    |REPICK_NEEDED;

    /*
     * (Re-)create the graphics context for drawing the traversal highlight.
     */
5209
5210
5211
5212
5213
5214
5215

5216
5217
5218
5219
5220
5221
5222
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251







+







     * be udpated.
     */

    dInfoPtr->xScrollFirst = dInfoPtr->xScrollLast = -1;
    dInfoPtr->yScrollFirst = dInfoPtr->yScrollLast = -1;

    if (mask & TK_TEXT_LINE_GEOMETRY) {

	/*
	 * Set up line metric recalculation.
	 *
	 * Avoid the special zero value, since that is used to mark individual
	 * lines as being out of date.
	 */

5233
5234
5235
5236
5237
5238
5239




5240

5241
5242
5243
5244
5245
5246
5247
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272

5273
5274
5275
5276
5277
5278
5279
5280







+
+
+
+
-
+








	dInfoPtr->metricEpoch = -1;

	if (dInfoPtr->lineUpdateTimer == NULL) {
	    textPtr->refCount++;
	    dInfoPtr->lineUpdateTimer = Tcl_CreateTimerHandler(1,
		    AsyncUpdateLineMetrics, textPtr);
	    inSync = 0;
	}
	
	if (!inSync) {
            GenerateWidgetViewSyncEvent(textPtr, 0);
	    GenerateWidgetViewSyncEvent(textPtr, 0);
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
Changes to macosx/tkMacOSXButton.c.
416
417
418
419
420
421
422



423
424
425
426
427
428
429
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432







+
+
+







    } else {
        height += butPtr->borderWidth*2;
        width += butPtr->borderWidth*2;
    }

    width += butPtr->inset*2;
    height += butPtr->inset*2;
    if ([NSApp macMinorVersion] == 6) {
      width += 12;
    }

    Tk_GeometryRequest(butPtr->tkwin, width, height);
    Tk_SetInternalBorder(butPtr->tkwin, butPtr->inset);
}

/*
 *----------------------------------------------------------------------
Changes to macosx/tkMacOSXClipboard.c.
8
9
10
11
12
13
14

15
16
17
18
19
20
21
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22







+







 * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]>
 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXConstants.h"
#include "tkSelect.h"

static NSInteger changeCount = -1;
static Tk_Window clipboardOwner = NULL;

#pragma mark TKApplication(TKClipboard)

Changes to macosx/tkMacOSXConstants.h.
11
12
13
14
15
16
17




18
19
20
21
22





23
24
25
26




27
28
29
30
31
32
33
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46







+
+
+
+





+
+
+
+
+




+
+
+
+







 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#ifndef _TKMACCONSTANTS
#define _TKMACCONSTANTS

#if MAC_OS_X_VERSION_MAX_ALLOWED < 1070
#define NSFullScreenWindowMask (1 << 14)
#endif

/*
 * Let's raise a glass for the project manager who improves our lives by
 * generating deprecation warnings about pointless changes of the names
 * of constants.
 */

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
#define kCTFontDefaultOrientation kCTFontOrientationDefault
#define kCTFontVerticalOrientation kCTFontOrientationVertical
#endif

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101000
#define NSOKButton NSModalResponseOK
#endif

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101100
#define kCTFontUserFixedPitchFontType kCTFontUIFontUserFixedPitch
#endif

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101200
#define NSAppKitDefined NSEventTypeAppKitDefined
#define NSApplicationActivatedEventType NSEventSubtypeApplicationActivated
#define NSApplicationDeactivatedEventType NSEventSubtypeApplicationDeactivated
#define NSWindowExposedEventType NSEventSubtypeWindowExposed
#define NSScreenChangedEventType NSEventSubtypeScreenChanged
88
89
90
91
92
93
94
95






96




101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119








+
+
+
+
+
+

+
+
+
+
#define NSClosableWindowMask NSWindowStyleMaskClosable
#define NSResizableWindowMask NSWindowStyleMaskResizable
#define NSUnifiedTitleAndToolbarWindowMask NSWindowStyleMaskUnifiedTitleAndToolbar
#define NSMiniaturizableWindowMask NSWindowStyleMaskMiniaturizable
#define NSBorderlessWindowMask NSWindowStyleMaskBorderless
#define NSFullScreenWindowMask NSWindowStyleMaskFullScreen
#endif

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
#define NSStringPboardType NSPasteboardTypeString
#define NSOnState NSControlStateValueOn
#define NSOffState NSControlStateValueOff
// Now we are also changing names of methods!
#define graphicsContextWithGraphicsPort graphicsContextWithCGContext
#endif


#endif

Changes to macosx/tkMacOSXDraw.c.
14
15
16
17
18
19
20






21
22
23
24
25
26
27
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33







+
+
+
+
+
+







 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXDebug.h"
#include "tkButton.h"

#if MAC_OS_X_VERSION_MIN_REQUIRED >= 101400
#define GET_CGCONTEXT [[NSGraphicsContext currentContext] CGContext]
#else
#define GET_CGCONTEXT [[NSGraphicsContext currentContext] graphicsPort]
#endif

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_DRAWING
#define TK_MAC_DEBUG_IMAGE_DRAWING
#endif
*/

1485
1486
1487
1488
1489
1490
1491
1492

1493
1494
1495
1496
1497
1498
1499
1491
1492
1493
1494
1495
1496
1497

1498
1499
1500
1501
1502
1503
1504
1505







-
+







	    } else {
		dontDraw = ![view canDraw];
	    }
	    if (dontDraw) {
		goto end;
	    }
	    dc.view = view;
	    dc.context = [[NSGraphicsContext currentContext] graphicsPort];
	    dc.context = GET_CGCONTEXT;
	    dc.portBounds = NSRectToCGRect([view bounds]);
	    if (dc.clipRgn) {
		clipBounds = CGContextGetClipBoundingBox(dc.context);
	    }
	} else {
	    Tcl_Panic("TkMacOSXSetupDrawingContext(): "
		    "no NSView to draw into !");
1654
1655
1656
1657
1658
1659
1660
1661

1662
1663
1664
1665
1666
1667
1668
1660
1661
1662
1663
1664
1665
1666

1667
1668
1669
1670
1671
1672
1673
1674







-
+








    if (macDraw->winPtr && macDraw->flags & TK_CLIP_INVALID) {
	TkMacOSXUpdateClipRgn(macDraw->winPtr);
#ifdef TK_MAC_DEBUG_DRAWING
	TkMacOSXDbgMsg("%s", macDraw->winPtr->pathName);
	NSView *view = TkMacOSXDrawableView(macDraw);
	if ([view lockFocusIfCanDraw]) {
	    CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort];
	    CGContextRef context = GET_CGCONTEXT;
	    CGContextSaveGState(context);
	    CGContextConcatCTM(context, CGAffineTransformMake(1.0, 0.0, 0.0,
		    -1.0, 0.0, [view bounds].size.height));
	    ChkErr(HIShapeReplacePathInCGContext, macDraw->visRgn, context);
	    CGContextSetRGBFillColor(context, 0.0, 1.0, 0.0, 0.1);
	    CGContextEOFillPath(context);
	    CGContextRestoreGState(context);
Changes to macosx/tkMacOSXEvent.c.
108
109
110
111
112
113
114
115
116





117
118
119
120
121

122

123
124
125
126
127
128
129
130
131
132
133
134
135
136

137
138
139
140
141
142
143
144
145
146
147
108
109
110
111
112
113
114


115
116
117
118
119
120
121
122
123
124
125

126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152







-
-
+
+
+
+
+





+
-
+














+











#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * TkMacOSXFlushWindows --
 *
 *	This routine flushes all the visible windows of the application. It is
 *	called by XSync().
 *	This routine is a stub called by XSync, which is called during
 *      the Tk update command.  It calls displayIfNeeded on all visible
 *      windows.  This is necessary in order to insure that update will
 *      run all of the display procedures which have been registered as
 *      idle tasks.  The test suite assumes that this is the case.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Calls the drawRect method of the contentView of each visible
 *	Flushes all visible Cocoa windows
 *      window.
 *
 *----------------------------------------------------------------------
 */

MODULE_SCOPE void
TkMacOSXFlushWindows(void)
{
    NSArray *macWindows = [NSApp orderedWindows];

    for (NSWindow *w in macWindows) {
	if (TkMacOSXGetXWindow(w)) {
	    [w displayIfNeeded];
	}
    }

}


/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */
Changes to macosx/tkMacOSXFont.c.
10
11
12
13
14
15
16

17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
10
11
12
13
14
15
16
17
18

19
20





21



22
23
24
25
26
27
28







+

-


-
-
-
-
-

-
-
-







 *
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"
#include "tkMacOSXFont.h"
#include "tkMacOSXConstants.h"

#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#define defaultOrientation kCTFontDefaultOrientation
#define verticalOrientation kCTFontVerticalOrientation
#else
#define defaultOrientation kCTFontOrientationDefault
#define verticalOrientation kCTFontOrientationVertical
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101100
#define fixedPitch kCTFontUserFixedPitchFontType
#else
#define fixedPitch kCTFontUIFontUserFixedPitch
#endif

/*
#ifdef TK_MAC_DEBUG
#define TK_MAC_DEBUG_FONTS
#endif
*/

Changes to macosx/tkMacOSXInit.c.
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50


51
52
53
54
55
56
57
12
13
14
15
16
17
18

19
20
21
22
23
24
25
26
27
28
29
30


31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56







-












-
-

















+
+







 * See the file "license.terms" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkMacOSXPrivate.h"

#include <sys/stat.h>
#include <sys/utsname.h>
#include <dlfcn.h>
#include <objc/objc-auto.h>

static char tkLibPath[PATH_MAX + 1] = "";

/*
 * If the App is in an App package, then we want to add the Scripts directory
 * to the auto_path.
 */

static char scriptPath[PATH_MAX + 1] = "";

long tkMacOSXMacOSXVersion = 0;

#pragma mark TKApplication(TKInit)

@interface TKApplication(TKKeyboard)
- (void) keyboardChanged: (NSNotification *) notification;
@end

#define TKApplication_NSApplicationDelegate <NSApplicationDelegate>
@interface TKApplication(TKWindowEvent) TKApplication_NSApplicationDelegate
- (void) _setupWindowNotifications;
@end

@interface TKApplication(TKMenus)
- (void) _setupMenus;
@end

@implementation TKApplication
@synthesize poolLock = _poolLock;
@synthesize macMinorVersion = _macMinorVersion;
@synthesize isDrawing = _isDrawing;
@end

/*
 * #define this to see a message on stderr whenever _resetAutoreleasePool is
 * called while the pool is locked.
 */
#undef DEBUG_LOCK
148
149
150
151
152
153
154



















155
156
157
158
159
160
161
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179







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








    /*
     * Install the global autoreleasePool.
     */
    _mainPool = [NSAutoreleasePool new];
    [NSApp setPoolLock:0];

    /*
     * Record the OS version we are running on.
     */
    int minorVersion;
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
    Gestalt(gestaltSystemVersionMinor, (SInt32*)&minorVersion);
#else
    NSOperatingSystemVersion systemVersion;
    systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
    minorVersion = systemVersion.minorVersion;
#endif
    [NSApp setMacMinorVersion: minorVersion]; 

    /*
     * We are not drawing yet.
     */

    [NSApp setIsDrawing: NO];

    /*
     * Be our own delegate.
     */
    [self setDelegate:self];

    /*
     * Make sure we are allowed to open windows.
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
269
270
271
272
273
274
275

276
277
278
279
280
281
282
283
284
285
286














287
288
289
290
291
292
293







-











-
-
-
-
-
-
-
-
-
-
-
-
-
-







    /*
     * Since it is possible for TkInit to be called multiple times and we
     * don't want to do the following initialization multiple times we protect
     * against doing it more than once.
     */

    if (!initialized) {
	struct utsname name;
	struct stat st;

	initialized = 1;

	/*
	 * Initialize/check OS version variable for runtime checks.
	 */

#if MAC_OS_X_VERSION_MIN_REQUIRED < 1060
#   error Mac OS X 10.6 required
#endif

	if (!uname(&name)) {
	    tkMacOSXMacOSXVersion = (strtod(name.release, NULL) + 96) * 10;
	}
       /*Check for new versioning scheme on Yosemite (10.10) and later.*/
	if (MAC_OS_X_VERSION_MIN_REQUIRED > 100000) {
		tkMacOSXMacOSXVersion = MAC_OS_X_VERSION_MIN_REQUIRED/100;
	    }
	if (tkMacOSXMacOSXVersion && MAC_OS_X_VERSION_MIN_REQUIRED < 100000 &&
		tkMacOSXMacOSXVersion/10 < MAC_OS_X_VERSION_MIN_REQUIRED/10) {
	    Tcl_Panic("Mac OS X 10.%d or later required !",
		    (MAC_OS_X_VERSION_MIN_REQUIRED/10)-100);
	}


#ifdef TK_FRAMEWORK
	/*
	 * When Tk is in a framework, force tcl_findLibrary to look in the
	 * framework scripts directory.
	 * FIXME: Should we come up with a more generic way of doing this?
	 */
Changes to macosx/tkMacOSXInt.h.
195
196
197
198
199
200
201



202
203
204
205
206
207
208
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211







+
+
+







	int clip_y_origin, XRectangle* rectangles, int n, int ordering);
#endif
MODULE_SCOPE void TkpClipDrawableToRect(Display *display, Drawable d, int x,
	int y, int width, int height);
MODULE_SCOPE void TkpRetainRegion(TkRegion r);
MODULE_SCOPE void TkpReleaseRegion(TkRegion r);
MODULE_SCOPE void TkpShiftButton(NSButton *button, NSPoint delta);
MODULE_SCOPE Bool TkpAppIsDrawing(void);
MODULE_SCOPE void TkpDisplayWindow(Tk_Window tkwin);

/*
 * Include the stubbed internal platform-specific API.
 */

#include "tkIntPlatDecls.h"

#endif /* _TKMACINT */
Changes to macosx/tkMacOSXKeyEvent.c.
326
327
328
329
330
331
332
333

334
335
336
337
338
339
340
326
327
328
329
330
331
332

333
334
335
336
337
338
339
340







-
+







  NSRect rect;
  NSPoint pt;

  pt.x = caret_x;
  pt.y = caret_y;

  pt = [self convertPoint: pt toView: nil];
  pt = [[self window] convertPointToScreen: pt];
  pt = [[self window] tkConvertPointToScreen: pt];
  pt.y -= caret_height;

  rect.origin = pt;
  rect.size.width = caret_height;
  rect.size.height = caret_height;
  return rect;
}
Changes to macosx/tkMacOSXMenu.c.
781
782
783
784
785
786
787
788

789
790
791
792
793
794
795
781
782
783
784
785
786
787

788
789
790
791
792
793
794
795







-
+







    }

    int oldMode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
    NSView *view = [win contentView];
    NSRect frame = NSMakeRect(x + 9, tkMacOSXZeroScreenHeight - y - 9, 1, 1);

    frame.origin = [view convertPoint:
	    [win convertPointFromScreen:frame.origin] fromView:nil];
	    [win tkConvertPointFromScreen:frame.origin] fromView:nil];

    NSMenu *menu = (NSMenu *) menuPtr->platformData;
    NSPopUpButtonCell *popUpButtonCell = [[NSPopUpButtonCell alloc]
	    initTextCell:@"" pullsDown:NO];

    [popUpButtonCell setAltersStateOfSelectedItem:NO];
    [popUpButtonCell setMenu:menu];
Changes to macosx/tkMacOSXMouseEvent.c.
86
87
88
89
90
91
92
93

94
95
96
97
98
99
100

101
102
103
104
105
106
107
86
87
88
89
90
91
92

93
94
95
96
97
98
99

100
101
102
103
104
105
106
107







-
+






-
+







	_windowWithMouse = eventWindow;
	[_windowWithMouse retain];
    }

    /* Create an Xevent to add to the Tk queue. */
    NSPoint global, local = [theEvent locationInWindow];
    if (eventWindow) { /* local will be in window coordinates. */
	global = [eventWindow convertPointToScreen: local];
	global = [eventWindow tkConvertPointToScreen: local];
	local.y = [eventWindow frame].size.height - local.y;
	global.y = tkMacOSXZeroScreenHeight - global.y;
    } else { /* local will be in screen coordinates. */
	if (_windowWithMouse ) {
	    eventWindow = _windowWithMouse;
	    global = local;
	    local = [eventWindow convertPointFromScreen: local];
	    local = [eventWindow tkConvertPointFromScreen: local];
	    local.y = [eventWindow frame].size.height - local.y;
	    global.y = tkMacOSXZeroScreenHeight - global.y;
	} else { /* We have no window. Use the screen???*/
	    local.y = tkMacOSXZeroScreenHeight - local.y;
	    global = local;
	}
    }
369
370
371
372
373
374
375
376

377
378
379
380
381
382
383
369
370
371
372
373
374
375

376
377
378
379
380
381
382
383







-
+







	if (getLocal) {
	    MacDrawable *macWin = (MacDrawable *) w;
	    NSWindow *win = TkMacOSXDrawableWindow(w);

	    if (win) {
		NSPoint local;

		local = [win convertPointFromScreen:global];
		local = [win tkConvertPointFromScreen:global];
		local.y = [win frame].size.height - local.y;
		if (macWin->winPtr && macWin->winPtr->wmInfoPtr) {
		    local.x -= macWin->winPtr->wmInfoPtr->xInParent;
		    local.y -= macWin->winPtr->wmInfoPtr->yInParent;
		}
		*win_x_return = local.x;
		*win_y_return = local.y;
467
468
469
470
471
472
473
474

475
476
477
478
479
480
481
467
468
469
470
471
472
473

474
475
476
477
478
479
480
481







-
+







    med.global.h = x;
    med.global.v = y;
    med.local = med.global;

    if (win) {
	NSPoint local = NSMakePoint(x, tkMacOSXZeroScreenHeight - y);

	local = [win convertPointFromScreen:local];
	local = [win tkConvertPointFromScreen:local];
	local.y = [win frame].size.height - local.y;
	if (macWin->winPtr && macWin->winPtr->wmInfoPtr) {
	    local.x -= macWin->winPtr->wmInfoPtr->xInParent;
	    local.y -= macWin->winPtr->wmInfoPtr->yInParent;
	}
	med.local.h = local.x;
	med.local.v = tkMacOSXZeroScreenHeight - local.y;
Changes to macosx/tkMacOSXNotify.c.
27
28
29
30
31
32
33














































































34
35
36
37
38
39
40
41
42
43




44
45
46





47
48
49
50
51



52
53

54
55
56


57
58
59
60
61

62
63
64


65
66


67
68
69
70
71
72
73
74




75
76
77
78
79
80
81
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119


120
121
122
123



124
125
126
127
128





129
130
131


132



133
134





135



136
137


138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158







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








-
-
+
+
+
+
-
-
-
+
+
+
+
+
-
-
-
-
-
+
+
+
-
-
+
-
-
-
+
+
-
-
-
-
-
+
-
-
-
+
+
-
-
+
+








+
+
+
+








#define TSD_INIT() ThreadSpecificData *tsdPtr = \
	Tcl_GetThreadData(&dataKey, sizeof(ThreadSpecificData))

static void TkMacOSXNotifyExitHandler(ClientData clientData);
static void TkMacOSXEventsSetupProc(ClientData clientData, int flags);
static void TkMacOSXEventsCheckProc(ClientData clientData, int flags);

#ifdef TK_MAC_DEBUG_EVENTS
static char* Tk_EventName[39] = {
    "",
    "",
    "KeyPress",		/*2*/
    "KeyRelease",      	/*3*/
    "ButtonPress",     	/*4*/
    "ButtonRelease",	/*5*/
    "MotionNotify",    	/*6*/
    "EnterNotify",     	/*7*/
    "LeaveNotify",     	/*8*/
    "FocusIn",		/*9*/
    "FocusOut",		/*10*/
    "KeymapNotify",    	/*11*/
    "Expose",		/*12*/
    "GraphicsExpose",	/*13*/
    "NoExpose",		/*14*/
    "VisibilityNotify",	/*15*/
    "CreateNotify",    	/*16*/
    "DestroyNotify",	/*17*/
    "UnmapNotify",     	/*18*/
    "MapNotify",       	/*19*/
    "MapRequest",      	/*20*/
    "ReparentNotify",	/*21*/
    "ConfigureNotify",	/*22*/
    "ConfigureRequest",	/*23*/
    "GravityNotify",	/*24*/
    "ResizeRequest",	/*25*/
    "CirculateNotify",	/*26*/
    "CirculateRequest",	/*27*/
    "PropertyNotify",	/*28*/
    "SelectionClear",	/*29*/
    "SelectionRequest",	/*30*/
    "SelectionNotify",	/*31*/
    "ColormapNotify",	/*32*/
    "ClientMessage",	/*33*/
    "MappingNotify",	/*34*/
    "VirtualEvent",    	/*35*/
    "ActivateNotify",	/*36*/
    "DeactivateNotify",	/*37*/
    "MouseWheelEvent"	/*38*/
};

static Tk_RestrictAction
InspectQueueRestrictProc(
     ClientData arg,
     XEvent *eventPtr)
{
    XVirtualEvent* ve = (XVirtualEvent*) eventPtr;
    const char *name;
    long serial = ve->serial;
    long time = eventPtr->xkey.time;
    
    if (eventPtr->type == VirtualEvent) {
	name = ve->name;
    } else {
	name = Tk_EventName[eventPtr->type];
    }
    printf("    > %s;serial = %lu; time=%lu)\n", name, serial, time);
    return TK_DEFER_EVENT;
}

/*
 * Debugging tool which prints the current Tcl queue.
 */

void DebugPrintQueue(void)
{
    ClientData oldArg;
    Tk_RestrictProc *oldProc;

    oldProc = Tk_RestrictEvents(InspectQueueRestrictProc, NULL, &oldArg);
    printf("Current queue:\n");
    while (Tcl_DoOneEvent(TCL_ALL_EVENTS|TCL_DONT_WAIT)) {};
    Tk_RestrictEvents(oldProc, oldArg, &oldArg);
}
# endif

#pragma mark TKApplication(TKNotify)

@interface NSApplication(TKNotify)
/* We need to declare this hidden method. */
- (void) _modalSession: (NSModalSession) session sendEvent: (NSEvent *) event;
@end

@implementation NSWindow(TKNotify)
- (id) tkDisplayIfNeeded
@implementation TKApplication(TKNotify)
/*
 * Earlier versions of Tk would override nextEventMatchingMask here, adding a
 * call to displayIfNeeded on all windows after calling super. This would cause
{
    if (![self isAutodisplay]) {
	[self displayIfNeeded];
 * windows to be redisplayed (if necessary) each time that an event was
 * received.  This was intended to replace Apple's default autoDisplay
 * mechanism, which the earlier versions of Tk would disable.  When autoDisplay
 * is set to the default value of YES, the Apple event loop will call
 * displayIfNeeded on all windows at the beginning of each iteration of their
    }
    return nil;
}
@end

 * event loop.  Since Tk does not call the Apple event loop, it was thought
 * that the autoDisplay behavior needed to be replicated.
 *
@implementation TKApplication(TKNotify)
/* Display all windows each time an event is removed from the queue.*/
 * However, as of OSX 10.14 (Mojave) the autoDisplay property became
- (NSEvent *) nextEventMatchingMask: (NSUInteger) mask
	untilDate: (NSDate *) expiration inMode: (NSString *) mode
	dequeue: (BOOL) deqFlag
 * deprecated.  Luckily it turns out that, even though we don't ever start the
 * Apple event loop, the Apple window manager still calls displayIfNeeded on
{
    NSEvent *event = [super nextEventMatchingMask:mask
					untilDate:expiration
					   inMode:mode
					  dequeue:deqFlag];
 * all windows on a regular basis, perhaps each time the queue is empty.  So we
    /* Retain this event for later use. Must be released.*/
    [event retain];
    [NSApp makeWindowsPerform:@selector(tkDisplayIfNeeded) inOrder:NO];
 * no longer, and perhaps never did need to set autoDisplay to NO, nor call
 * displayIfNeeded on our windows.  We can just leave all of that to the window
    return event;
}
 * manager.
 */

/*
 * Call super then check the pasteboard.
 */
- (void) sendEvent: (NSEvent *) theEvent
{
    [super sendEvent:theEvent];
    [NSApp tkCheckPasteboard];
#ifdef TK_MAC_DEBUG_EVENTS
    printf("Sending event of type %d\n", (int)[theEvent type]); 
    DebugPrintQueue();
#endif
}
@end

#pragma mark -

/*
 *----------------------------------------------------------------------
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
302
303
304
305
306
307
308

309
310
311
312
313
314
315







-







				       untilDate:[NSDate distantPast]
				       inMode:GetRunLoopMode(TkMacOSXGetModalSession())
				       dequeue:NO];
	if (currentEvent) {
	    if (currentEvent.type > 0) {
		Tcl_SetMaxBlockTime(&zeroBlockTime);
	    }
	    [currentEvent release];
	}
    }
}

/*
 *----------------------------------------------------------------------
 *
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
370
371
372
373
374
375
376

377
378
379
380
381
382
383







-







#endif
		    if (modalSession) {
			[NSApp _modalSession:modalSession sendEvent:currentEvent];
		    } else {
			[NSApp sendEvent:currentEvent];
		    }
		}
		[currentEvent release];
	    } else {
		break;
	    }
	} while (1);
	/* Now we can unlock the pool. */
	[NSApp _unlockAutoreleasePool];
    }
Changes to macosx/tkMacOSXPrivate.h.
261
262
263
264
265
266
267


268
269
270


271
272
273
274
275
276
277
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281







+
+



+
+







    NSArray *_defaultApplicationMenuItems, *_defaultWindowsMenuItems;
    NSArray *_defaultHelpMenuItems;
    NSWindow *_windowWithMouse;
    NSAutoreleasePool *_mainPool;
#ifdef __i386__
    /* The Objective C runtime used on i386 requires this. */
    int _poolLock;
    int _macMinorVersion;
    Bool _isDrawing;
#endif
}
@property int poolLock;
@property int macMinorVersion;
@property Bool isDrawing;

@end
@interface TKApplication(TKInit)
- (NSString *)tkFrameworkImagePath:(NSString*)image;
- (void)_resetAutoreleasePool;
- (void)_lockAutoreleasePool;
- (void)_unlockAutoreleasePool;
340
341
342
343
344
345
346
347
348


349
350
351
352
353
354
355
344
345
346
347
348
349
350


351
352
353
354
355
356
357
358
359







-
-
+
+







@end

VISIBILITY_HIDDEN
@interface TKWindow : NSWindow
@end

@interface NSWindow(TKWm)
- (NSPoint) convertPointToScreen:(NSPoint)point;
- (NSPoint) convertPointFromScreen:(NSPoint)point;
- (NSPoint) tkConvertPointToScreen:(NSPoint)point;
- (NSPoint) tkConvertPointFromScreen:(NSPoint)point;
@end

#pragma mark NSMenu & NSMenuItem Utilities

@interface NSMenu(TKUtils)
+ (id)menuWithTitle:(NSString *)title;
+ (id)menuWithTitle:(NSString *)title menuItems:(NSArray *)items;
Changes to macosx/tkMacOSXScrlbr.c.
1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35




36

37
38
39

40
41
42
43

44
45



46








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

63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83

84
85
86
87

88
89
90
91
92
93
94
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

30
31
32
33
34
35
36
37
38
39
40

41
42
43

44
45
46
47

48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77

78
79
80
81
82
83
84
85
86
87
88
89






90

91

92
93
94
95

96
97
98
99
100
101
102
103










+


















-
+






+
+
+
+
-
+


-
+



-
+


+
+
+

+
+
+
+
+
+
+
+















-
+











-
-
-
-
-
-

-

-
+



-
+







/*
 * tkMacOSXScrollbar.c --
 *
 *	This file implements the Macintosh specific portion of the scrollbar
 *	widget.
 *
 * Copyright (c) 1996 by Sun Microsystems, Inc.
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2006-2009 Daniel A. Steffen <[email protected]>
 * Copyright (c) 2015 Kevin Walzer/WordTech Commununications LLC.
 * Copyright (c) 2018 Marc Culler
 * See the file "license.terms" for information on usage and redistribution
 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
 */

#include "tkInt.h"
#include "tkScrollbar.h"
#include "tkMacOSXPrivate.h"


#define MIN_SCROLLBAR_VALUE		0

/*
 * Minimum slider length, in pixels (designed to make sure that the slider is
 * always easy to grab with the mouse).
 */

#define MIN_SLIDER_LENGTH	5

/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling of scrollbar values.*/
/*Borrowed from ttkMacOSXTheme.c to provide appropriate scaling.*/
#ifdef __LP64__
#define RangeToFactor(maximum) (((double) (INT_MAX >> 1)) / (maximum))
#else
#define RangeToFactor(maximum) (((double) (LONG_MAX >> 1)) / (maximum))
#endif /* __LP64__ */

/*
 * Apple reversed the scroll direction with the release of OSX 10.7 Lion.
 */

#define MOUNTAIN_LION_STYLE (NSAppKitVersionNumber < 1138)
#define SNOW_LEOPARD_STYLE (NSAppKitVersionNumber < 1138)

/*
 * Declaration of Mac specific scrollbar structure.
 * Declaration of an extended scrollbar structure with Mac specific additions.
 */

typedef struct MacScrollbar {
    TkScrollbar information;	 /* Generic scrollbar info. */
    TkScrollbar information;	/* Generic scrollbar info. */
    GC troughGC;		/* For drawing trough. */
    GC copyGC;			/* Used for copying from pixmap onto screen. */
    Bool buttonDown;            /* Is the mouse button down? */  
    Bool mouseOver;             /* Is the pointer over the scrollbar. */
    HIThemeTrackDrawInfo info;  /* Controls how the scrollbar is drawn. */
} MacScrollbar;

/* Used to initialize a MacScrollbar's info field. */
HIThemeTrackDrawInfo defaultInfo = {
    .version = 0,
    .min = 0.0,
    .max = 100.0,
    .attributes = kThemeTrackShowThumb,
};

/*
 * The class procedure table for the scrollbar widget. All fields except size
 * are left initialized to NULL, which should happen automatically since the
 * variable is declared at this scope.
 */

const Tk_ClassProcs tkpScrollbarProcs = {
    sizeof(Tk_ClassProcs),	/* size */
    NULL,					/* worldChangedProc */
    NULL,					/* createProc */
    NULL					/* modalProc */
};


/*Information on scrollbar layout, metrics, and draw info.*/
/* Information on scrollbar layout, metrics, and draw info.*/
typedef struct ScrollbarMetrics {
    SInt32 width, minThumbHeight;
    int minHeight, topArrowHeight, bottomArrowHeight;
    NSControlSize controlSize;
} ScrollbarMetrics;


static ScrollbarMetrics metrics = {
  15, 54, 26, 14, 14, kControlSizeNormal /* kThemeScrollBarMedium */
};

HIThemeTrackDrawInfo info = {
    .version = 0,
    .min = 0.0,
    .max = 100.0,
    .attributes = kThemeTrackShowThumb,
};


/*
 * Forward declarations for procedures defined later in this file:
 * Declarations of static functions defined later in this file:
 */

static void ScrollbarEventProc(ClientData clientData, XEvent *eventPtr);
static int ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr);
static int ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr);
static void UpdateControlValues(TkScrollbar  *scrollPtr);

/*
 *----------------------------------------------------------------------
 *
 * TkpCreateScrollbar --
 *
108
109
110
111
112
113
114


115
116











117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134

135
136
137
138
139
140
141
142
143

144
145
146
147
148
149
150
117
118
119
120
121
122
123
124
125


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153

154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171







+
+
-
-
+
+
+
+
+
+
+
+
+
+
+

















-
+









+







		   Tk_Window tkwin)
{

    MacScrollbar *scrollPtr = (MacScrollbar *)ckalloc(sizeof(MacScrollbar));

    scrollPtr->troughGC = None;
    scrollPtr->copyGC = None;
    scrollPtr->info = defaultInfo;
    scrollPtr->buttonDown = false;

    Tk_CreateEventHandler(tkwin,ExposureMask|StructureNotifyMask|FocusChangeMask|ButtonPressMask|ButtonReleaseMask|EnterWindowMask|LeaveWindowMask|VisibilityChangeMask, ScrollbarEventProc, scrollPtr);
    
    Tk_CreateEventHandler(tkwin,
			  ExposureMask        |
			  StructureNotifyMask |
			  FocusChangeMask     |
			  ButtonPressMask     |
			  ButtonReleaseMask   |
			  EnterWindowMask     |
			  LeaveWindowMask     |
			  VisibilityChangeMask,
			  ScrollbarEventProc, scrollPtr);

    return (TkScrollbar *) scrollPtr;
}

/*
 *--------------------------------------------------------------
 *
 * TkpDisplayScrollbar --
 *
 *	This procedure redraws the contents of a scrollbar window. It is
 *	invoked as a do-when-idle handler, so it only runs when there's
 *	nothing else for the application to do.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Information appears on the screen.
 *	Draws a scrollbar on the screen.
 *
 *--------------------------------------------------------------
 */

void
TkpDisplayScrollbar(
		    ClientData clientData)	/* Information about window. */
{
    register TkScrollbar *scrollPtr = (TkScrollbar *) clientData;
    MacScrollbar *msPtr = (MacScrollbar *) scrollPtr;
    register Tk_Window tkwin = scrollPtr->tkwin;
    TkWindow *winPtr = (TkWindow *) tkwin;
    TkMacOSXDrawingContext dc;

    scrollPtr->flags &= ~REDRAW_PENDING;

    if (tkwin == NULL || !Tk_IsMapped(tkwin)) {
160
161
162
163
164
165
166
167

168
169
170
171
172
173
174
181
182
183
184
185
186
187

188
189
190
191
192
193
194
195







-
+







    }

    CGFloat viewHeight = [view bounds].size.height;
    CGAffineTransform t = { .a = 1, .b = 0, .c = 0, .d = -1, .tx = 0,
			    .ty = viewHeight};
    CGContextConcatCTM(dc.context, t);

    /*Draw Unix-style scroll trough to provide rect for native scrollbar.*/
    /*Draw a 3D rectangle to provide a base for the native scrollbar.*/
    if (scrollPtr->highlightWidth != 0) {
    	GC fgGC, bgGC;

    	bgGC = Tk_GCForColor(scrollPtr->highlightBgColorPtr, (Pixmap) macWin);
    	if (scrollPtr->flags & GOT_FOCUS) {
    	    fgGC = Tk_GCForColor(scrollPtr->highlightColorPtr, (Pixmap) macWin);
    	} else {
184
185
186
187
188
189
190
191

192
193
194



195
196

197
198
199
200
201
202
203
205
206
207
208
209
210
211

212
213


214
215
216
217

218
219
220
221
222
223
224
225







-
+

-
-
+
+
+

-
+







    		       Tk_Height(tkwin) - 2*scrollPtr->highlightWidth,
    		       scrollPtr->borderWidth, scrollPtr->relief);
    Tk_Fill3DRectangle(tkwin, (Pixmap) macWin, scrollPtr->bgBorder,
    		       scrollPtr->inset, scrollPtr->inset,
    		       Tk_Width(tkwin) - 2*scrollPtr->inset,
    		       Tk_Height(tkwin) - 2*scrollPtr->inset, 0, TK_RELIEF_FLAT);

    /*Update values and draw in native rect.*/
    /* Update values and then draw the native scrollbar over the rectangle.*/
    UpdateControlValues(scrollPtr);
    if (MOUNTAIN_LION_STYLE) {
      HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationInverted);

    if (SNOW_LEOPARD_STYLE) {
	HIThemeDrawTrack (&(msPtr->info), 0, dc.context, kHIThemeOrientationInverted);
    } else {
      HIThemeDrawTrack (&info, 0, dc.context, kHIThemeOrientationNormal);
	HIThemeDrawTrack (&(msPtr->info), 0, dc.context, kHIThemeOrientationNormal);
    }
    TkMacOSXRestoreDrawingContext(&dc);

    scrollPtr->flags &= ~REDRAW_PENDING;
}

/*
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
249
250
251
252
246
247
248
249
250
251
252






253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273

274
275
276
277
278
279
280
281
282







-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+








+
+
+
-
+
+







TkpComputeScrollbarGeometry(
    register TkScrollbar *scrollPtr)
                           /* Scrollbar whose geometry may have
                           * changed. */
{

   /*
    * Using code from tkUnixScrlbr.c because Unix scroll bindings are
    * driving the display at the script level. All the Mac scrollbar
    * has to do is re-draw itself.
    * There is a difference with Unix however: on macOS later than 10.6
    * (Snow Leopard) the scrollbars have no arrows at all. This is
    * handled by having scrollPtr->arrowLength set to zero.
    * The code below is borrowed from tkUnixScrlbr.c but has been adjusted to
    * account for some differences between macOS and X11. The Unix scrollbar
    * has an arrow button on each end.  On macOS 10.6 (Snow Leopard) the
    * scrollbars by default have both arrow buttons at the bottom or right.
    * (There is a preferences setting to use the Unix layout, but we are not
    * supporting that!)  On more recent versions of macOS there are no arrow
    * buttons at all. The case of no arrow buttons can be handled as a special
    * case of having both buttons at the end, but where scrollPtr->arrowLength
    * happens to be zero.  To adjust for having both arrows at the same end we
    * shift the scrollbar up by the arrowLength.
    */

    int fieldLength;

    if (scrollPtr->highlightWidth < 0) {
       scrollPtr->highlightWidth = 0;
    }
    scrollPtr->inset = scrollPtr->highlightWidth + scrollPtr->borderWidth;
    if ([NSApp macMinorVersion] == 6) {
      scrollPtr->arrowLength = scrollPtr->width;
    } else {
    scrollPtr->arrowLength = 0;
      scrollPtr->arrowLength = 0;
    }
    fieldLength = (scrollPtr->vertical ? Tk_Height(scrollPtr->tkwin)
           : Tk_Width(scrollPtr->tkwin))
           - 2*(scrollPtr->arrowLength + scrollPtr->inset);
    if (fieldLength < 0) {
       fieldLength = 0;
    }
    scrollPtr->sliderFirst = fieldLength*scrollPtr->firstFraction;
266
267
268
269
270
271
272
273
274


275
276
277
278
279




280
281
282
283
284
285
286
296
297
298
299
300
301
302


303
304
305
306



307
308
309
310
311
312
313
314
315
316
317







-
-
+
+


-
-
-
+
+
+
+







    }
    if (scrollPtr->sliderLast < scrollPtr->sliderFirst + MIN_SLIDER_LENGTH) {
       scrollPtr->sliderLast = scrollPtr->sliderFirst + MIN_SLIDER_LENGTH;
    }
    if (scrollPtr->sliderLast > fieldLength) {
       scrollPtr->sliderLast = fieldLength;
    }
    scrollPtr->sliderFirst += scrollPtr->arrowLength + scrollPtr->inset;
    scrollPtr->sliderLast += scrollPtr->arrowLength + scrollPtr->inset;
    scrollPtr->sliderFirst += -scrollPtr->arrowLength + scrollPtr->inset;
    scrollPtr->sliderLast += scrollPtr->inset;

    /*
     * Register the desired geometry for the window (leave enough space for
     * the two arrows plus a minimum-size slider, plus border around the whole
     * window, if any). Then arrange for the window to be redisplayed.
     * Register the desired geometry for the window. Leave enough space for the
     * two arrows, if there are any arrows, plus a minimum-size slider, plus
     * border around the whole window, if any. Then arrange for the window to
     * be redisplayed.
     */

      if (scrollPtr->vertical) {
       Tk_GeometryRequest(scrollPtr->tkwin,
              scrollPtr->width + 2*scrollPtr->inset,
              2*(scrollPtr->arrowLength + scrollPtr->borderWidth
              + scrollPtr->inset) + metrics.minThumbHeight);
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335

336
337
338
339
340
341

342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
348
349
350
351
352
353
354


355
356
357
358
359
360
361
362
363

364
365
366
367
368
369

370
371
372
373
374
375
376
377


378
379
380
381
382
383
384







-
-









-
+





-
+







-
-








    if (macScrollPtr->troughGC != None) {
	Tk_FreeGC(scrollPtr->display, macScrollPtr->troughGC);
    }
    if (macScrollPtr->copyGC != None) {
	Tk_FreeGC(scrollPtr->display, macScrollPtr->copyGC);
    }

    macScrollPtr=NULL;
}

/*
 *----------------------------------------------------------------------
 *
 * TkpConfigureScrollbar --
 *
 *	This procedure is called after the generic code has finished
 *	processing configuration options, in order to configure platform
 *	specific options.
 *	specific options.  There are no such option on the Mac, however.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	Configuration info may get changed.
 *	Currently, none.
 *
 *----------------------------------------------------------------------
 */

void
TkpConfigureScrollbar(
		      register TkScrollbar *scrollPtr)
/* Information about widget; may or may not
 * already have values for some fields. */
{

}

/*
 *--------------------------------------------------------------
 *
374
375
376
377
378
379
380
381
382


383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399

400

401
402
403
404
405
406




407
408
409
410
411
412

413
414
415


416
417
418
419
420
421
422









423
424
425
426
427
428
429
430
401
402
403
404
405
406
407


408
409

410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426

427
428
429
430
431


432
433
434
435
436
437




438
439


440
441
442






443
444
445
446
447
448
449
450
451

452
453
454
455
456
457
458







-
-
+
+
-
















+
-
+




-
-
+
+
+
+


-
-
-
-
+

-
-
+
+

-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-







TkpScrollbarPosition(
    register TkScrollbar *scrollPtr,
				/* Scrollbar widget record. */
    int x, int y)		/* Coordinates within scrollPtr's window. */
{

   /*
   * Using code from tkUnixScrlbr.c because Unix scroll bindings are
   * driving the display at the script level. All the Mac scrollbar
   * The code below is borrowed from tkUnixScrlbr.c and needs no adjustment
   * since it does not involve the arrow buttons.
   * has to do is re-draw itself.
   */

    int length, width, tmp;
    register const int inset = scrollPtr->inset;

    if (scrollPtr->vertical) {
  	length = Tk_Height(scrollPtr->tkwin);
  	width = Tk_Width(scrollPtr->tkwin);
    } else {
  	tmp = x;
  	x = y;
  	y = tmp;
  	length = Tk_Width(scrollPtr->tkwin);
  	width = Tk_Height(scrollPtr->tkwin);
    }

    if (x < inset || x >= width - inset ||
    if (x<inset || x>=width-inset || y<inset || y>=length-inset) {
	y < inset || y >= length - inset) {
  	return OUTSIDE;
    }

    /*
     * All of the calculations in this procedure mirror those in
     * TkpDisplayScrollbar. Be sure to keep the two consistent.
     * Here we assume that the scrollbar is layed out with both arrow buttons
     * at the bottom (or right).  Except on 10.6, however, the arrows do not
     * actually exist, i.e. the arrowLength is 0.  These are the same
     * assumptions which are being made in TkpComputeScrollbarGeometry.
     */

    if (y < inset + scrollPtr->arrowLength) {
  	return TOP_ARROW;
    }
    if (y < scrollPtr->sliderFirst) {
    if (y < scrollPtr->sliderFirst + scrollPtr->arrowLength) {
  	return TOP_GAP;
    }
    if (y < scrollPtr->sliderLast) {
      }
      if (y < scrollPtr->sliderLast) {
  	return SLIDER;
    }
    if (y >= length - (scrollPtr->arrowLength + inset)) {
  	return BOTTOM_ARROW;
    }

    return BOTTOM_GAP;
      }
      if (y < length - (2*scrollPtr->arrowLength + inset)) {
  	return BOTTOM_GAP;
      }
      /* On systems newer than 10.6 we have already returned. */
      if (y < length - (scrollPtr->arrowLength + inset)) {
  	return TOP_ARROW;
      }
      return BOTTOM_ARROW;

}

/*
 *--------------------------------------------------------------
 *
 * UpdateControlValues --
 *
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

480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496

497
498

499
500
501


502
503

504
505
506

507
508
509
510
511

512
513
514


515
516
517
518
519
520
521
522

523
524
525


526
527
528
529
530
531

532

533
534
535
536
537
538
539
540
541
542
543
544




























































545
546
547
548
549
550
551
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493

494
495
496
497
498
499
500
501
502
503

504
505

506
507

508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524

525
526

527
528


529
530
531

532
533
534

535
536
537
538
539

540
541


542
543
544
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
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
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
620
621
622
623
624
625
626
627
628
629
630







+















-
+









-
+

-
+

-
+
















-
+

-
+

-
-
+
+

-
+


-
+




-
+

-
-
+
+







-
+


-
+
+





-
+

+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+







 *--------------------------------------------------------------
 */

static void
UpdateControlValues(
		    TkScrollbar *scrollPtr)		/* Scrollbar data struct. */
{
    MacScrollbar *msPtr = (MacScrollbar *)scrollPtr;
    Tk_Window tkwin = scrollPtr->tkwin;
    MacDrawable *macWin = (MacDrawable *) Tk_WindowId(scrollPtr->tkwin);
    double dViewSize;
    HIRect  contrlRect;
    short width, height;

    NSView *view = TkMacOSXDrawableView(macWin);
    CGFloat viewHeight = [view bounds].size.height;
    NSRect frame;
    frame = NSMakeRect(macWin->xOff, macWin->yOff, Tk_Width(tkwin),
		       Tk_Height(tkwin));
    frame = NSInsetRect(frame, scrollPtr->inset, scrollPtr->inset);
    frame.origin.y = viewHeight - (frame.origin.y + frame.size.height);

    contrlRect = NSRectToCGRect(frame);
    info.bounds = contrlRect;
    msPtr->info.bounds = contrlRect;

    width = contrlRect.size.width;
    height = contrlRect.size.height;

    /*
     * Ensure we set scrollbar control bounds only once all size adjustments
     * have been computed.
     */

    info.bounds = contrlRect;
    msPtr->info.bounds = contrlRect;
    if (scrollPtr->vertical) {
      info.attributes &= ~kThemeTrackHorizontal;
      msPtr->info.attributes &= ~kThemeTrackHorizontal;
    } else {
      info.attributes |= kThemeTrackHorizontal;
      msPtr->info.attributes |= kThemeTrackHorizontal;
    }

    /*
     * Given the Tk parameters for the fractions of the start and end of the
     * thumb, the following calculation determines the location for the
     * Macintosh thumb. The Aqua scroll control works as follows. The
     * scrollbar's value is the position of the left (or top) side of the view
     * area in the content area being scrolled. The maximum value of the
     * control is therefore the dimension of the content area less the size of
     * the view area.
     */

    double maximum = 100,  factor;
    factor = RangeToFactor(maximum);
    dViewSize = (scrollPtr->lastFraction - scrollPtr->firstFraction)
	* factor;
    info.max =  MIN_SCROLLBAR_VALUE +
    msPtr->info.max =  MIN_SCROLLBAR_VALUE +
	factor - dViewSize;
    info.trackInfo.scrollbar.viewsize = dViewSize;
    msPtr->info.trackInfo.scrollbar.viewsize = dViewSize;
    if (scrollPtr->vertical) {
      if (MOUNTAIN_LION_STYLE) {
	info.value = factor * scrollPtr->firstFraction;
      if (SNOW_LEOPARD_STYLE) {
	msPtr->info.value = factor * scrollPtr->firstFraction;
      } else {
	info.value = info.max - factor * scrollPtr->firstFraction;
	msPtr->info.value = msPtr->info.max - factor * scrollPtr->firstFraction;
      }
    } else {
	 info.value =  MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
	 msPtr->info.value =  MIN_SCROLLBAR_VALUE + factor * scrollPtr->firstFraction;
    }

    if((scrollPtr->firstFraction <= 0.0 && scrollPtr->lastFraction >= 1.0)
       || height <= metrics.minHeight) {
    	info.enableState = kThemeTrackHideTrack;
    	msPtr->info.enableState = kThemeTrackHideTrack;
    } else {
    	info.enableState = kThemeTrackActive;
    	info.attributes = kThemeTrackShowThumb |  kThemeTrackThumbRgnIsNotGhost;
        msPtr->info.enableState = kThemeTrackActive;
    	msPtr->info.attributes = kThemeTrackShowThumb |  kThemeTrackThumbRgnIsNotGhost;
    }

}

/*
 *--------------------------------------------------------------
 *
 * ScrollbarPress --
 * ScrollbarEvent --
 *
 *	This procedure is invoked in response to <ButtonPress>, <ButtonRelease>,
 *      <EnterNotify>, and <LeaveNotify> events. Scrollbar appearance is modified.
 *      <EnterNotify>, and <LeaveNotify> events. The Scrollbar appearance is
 *      modified for each event.
 *
 *--------------------------------------------------------------
 */

static int
ScrollbarPress(TkScrollbar *scrollPtr, XEvent *eventPtr)
ScrollbarEvent(TkScrollbar *scrollPtr, XEvent *eventPtr)
{
    MacScrollbar *msPtr = (MacScrollbar *)scrollPtr;

  if (eventPtr->type == ButtonPress) {
    UpdateControlValues(scrollPtr);
    info.trackInfo.scrollbar.pressState = 1;
  }
   if (eventPtr->type == EnterNotify) {
    info.trackInfo.scrollbar.pressState = 1;
  }
  if (eventPtr->type == ButtonRelease || eventPtr->type == LeaveNotify) {
    info.trackInfo.scrollbar.pressState = 0;
  }
  return TCL_OK;
    
    /* The pressState does not indicate whether the moused button was
     * pressed at some location in the Scrollbar.  Rather, it indicates
     * that the scrollbar should appear as if it were pressed in that
     * location. The standard Mac behavior is that once the button is
     * pressed inside the Scrollbar the appearance should not change until
     * the button is released, even if the mouse moves outside of the
     * scrollbar.  However, if the mouse lies over the scrollbar but the
     * button is not pressed then the appearance should be the same as if
     * the button had been pressed on the slider, i.e. kThemeThumbPressed.
     * See the file Appearance.r, or HIToolbox.bridgesupport on 10.14.
     */

    if (eventPtr->type == ButtonPress) {
	msPtr->buttonDown = true;
	UpdateControlValues(scrollPtr);
	int where = TkpScrollbarPosition(scrollPtr,
					 eventPtr->xbutton.x,
					 eventPtr->xbutton.y);
	switch(where) {
	case OUTSIDE:
	    msPtr->info.trackInfo.scrollbar.pressState = 0;
	    break;
	case TOP_GAP:
	    msPtr->info.trackInfo.scrollbar.pressState = kThemeTopTrackPressed;
	    break;
	case SLIDER:
	    msPtr->info.trackInfo.scrollbar.pressState = kThemeThumbPressed;
	    break;
	case BOTTOM_GAP:
	    msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomTrackPressed;
	    break;
	case TOP_ARROW:
	    /* This looks wrong and the docs say it is wrong but it works. */
	    msPtr->info.trackInfo.scrollbar.pressState = kThemeTopInsideArrowPressed;
	    break;
	case BOTTOM_ARROW:
	    msPtr->info.trackInfo.scrollbar.pressState = kThemeBottomOutsideArrowPressed;
	    break;
	}
    }
    if (eventPtr->type == ButtonRelease) {
	msPtr->buttonDown = false;
	if (!msPtr->mouseOver) {
	    msPtr->info.trackInfo.scrollbar.pressState = 0;
	}
    }
    if (eventPtr->type == EnterNotify) {
	msPtr->mouseOver = true;
	if (!msPtr->buttonDown) {
	    msPtr->info.trackInfo.scrollbar.pressState = kThemeThumbPressed;
	}
    }
    if (eventPtr->type == LeaveNotify) {
	msPtr->mouseOver = false;
	if (!msPtr->buttonDown) {
	    msPtr->info.trackInfo.scrollbar.pressState = 0;
	}
    }
    return TCL_OK;
}



/*
 *--------------------------------------------------------------
 *
579
580
581
582
583
584
585
586

587
588
589
590
591









658
659
660
661
662
663
664

665
666
667
668
669
670
671
672
673
674
675
676
677
678
679







-
+





+
+
+
+
+
+
+
+
+
    case DeactivateNotify:
	TkScrollbarEventuallyRedraw(scrollPtr);
	break;
    case ButtonPress:
    case ButtonRelease:
    case EnterNotify:
    case LeaveNotify:
    	ScrollbarPress(clientData, eventPtr);
    	ScrollbarEvent(clientData, eventPtr);
	break;
    default:
	TkScrollbarEventProc(clientData, eventPtr);
    }
}

/*
 * Local Variables:
 * mode: objc
 * c-basic-offset: 4
 * fill-column: 79
 * coding: utf-8
 * End:
 */
Changes to macosx/tkMacOSXWindowEvent.c.
293
294
295
296
297
298
299

























300
301
302
303
304
305
306
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331







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







@end

#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * TkpAppIsDrawing --
 *
 *      A widget display procedure can call this to determine whether it
 *      is being run inside of the drawRect method.  This is needed for
 *      some tests, especially of the Text widget, which record data in
 *      a global Tcl variable and assume that display procedures will be
 *      run in a predictable sequence as Tcl idle tasks.
 *
 * Results:
 *	True only while running the drawRect method of a TKContentView;
 *
 * Side effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
MODULE_SCOPE Bool
TkpAppIsDrawing(void) {
    return [NSApp isDrawing];
}


/*
 *----------------------------------------------------------------------
 *
 * GenerateUpdates --
 *
 *	Given a Macintosh update region and a Tk window this function geneates
 *	an X Expose event for the window if it meets the update region. The
 *	function will then recursivly have each damaged window generate Expose
 *	events for its child windows.
 *
797
798
799
800
801
802
803
804
805
806
807
808
809
810


811
812



813
814
815
816
817






818
819
820
821
822






823
824
825
826
827
828
829
830
831




832
833
834
835
836
837
838
822
823
824
825
826
827
828


829




830
831
832

833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862




863
864
865
866
867
868
869
870
871
872
873







-
-

-
-
-
-
+
+

-
+
+
+





+
+
+
+
+
+





+
+
+
+
+
+





-
-
-
-
+
+
+
+







@implementation TKContentView(TKWindowEvent)

- (void) drawRect: (NSRect) rect
{
    const NSRect *rectsBeingDrawn;
    NSInteger rectsBeingDrawnCount;

    [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];

#ifdef TK_MAC_DEBUG_DRAWING
    TKLog(@"-[%@(%p) %s%@]", [self class], self, _cmd, NSStringFromRect(rect));
    [[NSColor colorWithDeviceRed:0.0 green:1.0 blue:0.0 alpha:.1] setFill];
    NSRectFillListUsingOperation(rectsBeingDrawn, rectsBeingDrawnCount,
	    NSCompositeSourceOver);
    TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);
    if (winPtr) printf("drawRect: drawing %s\n", Tk_PathName(winPtr));
#endif

    
    [NSApp setIsDrawing: YES];
    [self getRectsBeingDrawn:&rectsBeingDrawn count:&rectsBeingDrawnCount];
    CGFloat height = [self bounds].size.height;
    HIMutableShapeRef drawShape = HIShapeCreateMutable();

    while (rectsBeingDrawnCount--) {
	CGRect r = NSRectToCGRect(*rectsBeingDrawn++);

#ifdef TK_MAC_DEBUG_DRAWING
	printf("drawRect: %dx%d@(%d,%d)\n", (int)r.size.width,
	       (int)r.size.height, (int)r.origin.x, (int)r.origin.y);
#endif

	r.origin.y = height - (r.origin.y + r.size.height);
	HIShapeUnionWithRect(drawShape, &r);
    }
    [self generateExposeEvents:(HIShapeRef)drawShape];
    CFRelease(drawShape);
    [NSApp setIsDrawing: NO];

#ifdef TK_MAC_DEBUG_DRAWING
    printf("drawRect: done.\n");
#endif

}

-(void) setFrameSize: (NSSize)newsize
{
    [super setFrameSize: newsize];
    if ([self inLiveResize]) {
	NSWindow *w = [self window];
	TkWindow *winPtr = TkMacOSXGetTkWindow(w);
	Tk_Window tkwin = (Tk_Window) winPtr;
    NSWindow *w = [self window];
    TkWindow *winPtr = TkMacOSXGetTkWindow(w);
    Tk_Window tkwin = (Tk_Window) winPtr;
    if (winPtr) {
	unsigned int width = (unsigned int)newsize.width;
	unsigned int height=(unsigned int)newsize.height;
	ClientData oldArg;
    	Tk_RestrictProc *oldProc;

	/*
	 * This can be called from outside the Tk event loop.
886
887
888
889
890
891
892
893


894
895

896
897
898
899
900
901
902
921
922
923
924
925
926
927

928
929
930

931
932
933
934
935
936
937
938







-
+
+

-
+








- (void) generateExposeEvents: (HIShapeRef) shape
{
    unsigned long serial;
    CGRect updateBounds;
    int updatesNeeded;
    TkWindow *winPtr = TkMacOSXGetTkWindow([self window]);

    ClientData oldArg;
    Tk_RestrictProc *oldProc;
    if (!winPtr) {
		return;
	return;
    }

    /*
     * Generate Tk Expose events.
     */

    HIShapeGetBounds(shape, &updateBounds);
910
911
912
913
914
915
916
917
918

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
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







-
-
+
-













-
+
+

-
-
+
+
+








    if (updatesNeeded) {

	/*
	 * First process all of the Expose events.
	 */

	ClientData oldArg;
    	Tk_RestrictProc *oldProc = Tk_RestrictEvents(ExposeRestrictProc,
    	oldProc = Tk_RestrictEvents(ExposeRestrictProc, UINT2PTR(serial), &oldArg);
						     UINT2PTR(serial), &oldArg);
    	while (Tcl_ServiceEvent(TCL_WINDOW_EVENTS)) {};
    	Tk_RestrictEvents(oldProc, oldArg, &oldArg);

	/*
	 * Starting with OSX 10.14, which uses Core Animation to draw windows,
	 * all drawing must be done within the drawRect method.  (The CGContext
	 * which draws to the backing CALayer is created by the NSView before
	 * calling drawRect, and destroyed when drawRect returns.  Drawing done
	 * with the current CGContext outside of the drawRect method has no
	 * effect.)
	 *
	 * Fortunately, Tk schedules all drawing to be done while Tcl is idle.
	 * So we can do the drawing by processing all of the idle events that
	 * were created when the expose events were processed.
	 * were created when the expose events were processed. Unfortunately
	 * this does not work in macOS 10.13.
	 */

	while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
	if ([NSApp macMinorVersion] > 13 || [self inLiveResize]) {
	    while (Tcl_DoOneEvent(TCL_IDLE_EVENTS)) {}
	}
    }
}

 
/*
 * These two methods allow Tk to register a virtual event which fires when the
 * appearance changes on 10.14.
Changes to macosx/tkMacOSXWm.c.
200
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
200
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







-
+



-
+




-
+







-
+








/*
 * Conversion of coordinates between window and screen.
 */

@implementation NSWindow(TKWm)
#if MAC_OS_X_VERSION_MIN_REQUIRED < 1070
- (NSPoint) convertPointToScreen: (NSPoint) point
- (NSPoint) tkConvertPointToScreen: (NSPoint) point
{
    return [self convertBaseToScreen:point];
}
- (NSPoint) convertPointFromScreen: (NSPoint)point
- (NSPoint) tkConvertPointFromScreen: (NSPoint)point
{
    return [self convertScreenToBase:point];
}
#else
- (NSPoint) convertPointToScreen: (NSPoint) point
- (NSPoint) tkConvertPointToScreen: (NSPoint) point
{
    NSRect pointrect;
    pointrect.origin = point;
    pointrect.size.width = 0;
    pointrect.size.height = 0;
    return [self convertRectToScreen:pointrect].origin;
}
- (NSPoint) convertPointFromScreen: (NSPoint)point
- (NSPoint) tkConvertPointFromScreen: (NSPoint)point
{
    NSRect pointrect;
    pointrect.origin = point;
    pointrect.size.width = 0;
    pointrect.size.height = 0;
    return [self convertRectFromScreen:pointrect].origin;
}
383
384
385
386
387
388
389
390

391
392
393
394
395








396
397

398
399
400
401
402
403
404
405
406
407
408











409
410
411
412
413
414


415
416
417


418
419
420
421
422
423
424
425
426
427
383
384
385
386
387
388
389

390





391
392
393
394
395
396
397
398
399
400
401
402
403
404








405
406
407
408
409
410
411
412
413
414
415
416
417
418
419


420
421
422


423
424
425
426

427
428
429
430
431
432
433







-
+
-
-
-
-
-
+
+
+
+
+
+
+
+


+



-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+




-
-
+
+

-
-
+
+


-







{
    id _i1, _i2;
}
@end


@implementation TKWindow: NSWindow
#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_12

/*
 * Override automatic fullscreen button on >10.12 because system fullscreen API
 * confuses Tk window geometry. Custom implementation setting fullscreen status using
 * Tk API and NSStatusItem in menubar to exit fullscreen status.
 */
/* Custom fullscreen implementation on 10.13 and above. On older versions of
 * macOS dating back to 10.7, the NSWindow fullscreen API was opt-in, requiring
 * explicit calls to toggleFullScreen. On 10.13, the API became implicit,
 * applying to all NSWindows unless they were marked non-resizable; this caused
 * issues with Tk, which was not aware of changes in screen geometry. Here we
 * override the toggleFullScreen call to hook directly into Tk's own fullscreen
 * API, allowing Tk to function smoothly with the Mac's fullscreen button.
*/

NSStatusItem *exitFullScreen;


- (void)toggleFullScreen:(id)sender
{
    TkWindow *winPtr = TkMacOSXGetTkWindow(self);
    Tcl_Interp *interp = Tk_Interp((Tk_Window)winPtr);

    if (([self styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask) {
    	TkMacOSXMakeFullscreen(winPtr, self, 0, interp);
    } else {
    	TkMacOSXMakeFullscreen(winPtr, self, 1, interp);
    }
  TkWindow *winPtr = TkMacOSXGetTkWindow(self);
  Tcl_Interp *interp = Tk_Interp((Tk_Window)winPtr);
  if ([NSApp macMinorVersion] > 12) {
      if (([self styleMask] & NSFullScreenWindowMask) == NSFullScreenWindowMask) {
	  TkMacOSXMakeFullscreen(winPtr, self, 0, interp);
      } else {
	  TkMacOSXMakeFullscreen(winPtr, self, 1, interp);
      }
  } else {
      NSLog (@"toggleFullScreen is ignored by Tk on OSX versions < 10.13");
  }
}

-(void)restoreOldScreen:(id)sender {

    TkWindow *winPtr = TkMacOSXGetTkWindow(self);
    Tcl_Interp *interp = Tk_Interp((Tk_Window)winPtr);
  TkWindow *winPtr = TkMacOSXGetTkWindow(self);
  Tcl_Interp *interp = Tk_Interp((Tk_Window)winPtr);

    TkMacOSXMakeFullscreen(winPtr, self, 0, interp);
    [[NSStatusBar systemStatusBar] removeStatusItem: exitFullScreen];
  TkMacOSXMakeFullscreen(winPtr, self, 0, interp);
  [[NSStatusBar systemStatusBar] removeStatusItem: exitFullScreen];
}

#endif
@end

@implementation TKWindow(TKWm)

- (BOOL) canBecomeKeyWindow
{
    TkWindow *winPtr = TkMacOSXGetTkWindow(self);
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
808
809
810
811
812
813
814

815
816
817
818
819
820
821







-







     */

    XMapWindow(winPtr->display, winPtr->window);

    /*Add window to Window menu.*/
    NSWindow *win = TkMacOSXDrawableWindow(winPtr->window);
    [win setExcludedFromWindowsMenu:NO];

}

/*
 *----------------------------------------------------------------------
 *
 * TkWmUnmapWindow --
 *
5645
5646
5647
5648
5649
5650
5651
5652
5653
5654
5655
5656
5657
5658
5659
5650
5651
5652
5653
5654
5655
5656

5657
5658
5659
5660
5661
5662
5663







-







    TKContentView *contentView = [[TKContentView alloc]
				     initWithFrame:NSZeroRect];
    [window setContentView:contentView];
    [contentView release];
    [window setDelegate:NSApp];
    [window setAcceptsMouseMovedEvents:YES];
    [window setReleasedWhenClosed:NO];
    [window setAutodisplay:NO];
    if (styleMask & NSUtilityWindowMask) {
	[(NSPanel*)window setFloatingPanel:YES];
    }
    if ((styleMask & (NSTexturedBackgroundWindowMask|NSHUDWindowMask)) &&
	    !(styleMask & NSDocModalWindowMask)) {
        /*
	 * Workaround for [Bug 2824538]: Textured windows are draggable
5672
5673
5674
5675
5676
5677
5678



























5679
5680
5681
5682
5683
5684
5685
5676
5677
5678
5679
5680
5681
5682
5683
5684
5685
5686
5687
5688
5689
5690
5691
5692
5693
5694
5695
5696
5697
5698
5699
5700
5701
5702
5703
5704
5705
5706
5707
5708
5709
5710
5711
5712
5713
5714
5715
5716







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







    geometry.size.height += structureRect.size.height;
    geometry.origin.y = tkMacOSXZeroScreenHeight - (geometry.origin.y +
	    geometry.size.height);
    [window setFrame:geometry display:NO];
    TkMacOSXRegisterOffScreenWindow((Window) macWin, window);
    macWin->flags |= TK_HOST_EXISTS;
}

/*
 *----------------------------------------------------------------------
 *
 * TkpDisplayWindow --
 *
 *      Mark the contentView of this window as needing display so the
 *      window will be drawn by the window manager.  If this is called
 *      within the drawRect method, do nothing.
 *
 * Results:
 *      None.
 *
 * Side effects:
 *      The window's contentView is marked as needing display.
 *
 *----------------------------------------------------------------------
 */

MODULE_SCOPE void
TkpDisplayWindow(Tk_Window tkwin) {
    if (![NSApp isDrawing]) {
    	TkWindow *winPtr = (TkWindow*)tkwin;
    	NSWindow *w = TkMacOSXDrawableWindow(winPtr->window);
    	[[w contentView] setNeedsDisplay: YES];
    }
}

/*
 *----------------------------------------------------------------------
 *
 * TkMacOSXRegisterOffScreenWindow --
 *
 *	This function adds the passed in Off Screen Port to the hash table
6487
6488
6489
6490
6491
6492
6493
6494

6495
6496

6497
6498
6499
6500
6501
6502
6503
6504
6505
6506
6507
6508
6509
6510
6511
6512
6513
6514
6515
6516
6517
6518
6519
6520
6521
6522



6523
6524
6525
6526
6527
6528
6529
6530


6531
6532
6533
6534
6535









6536
6537
6538
6539

6540

6541
6542
6543
6544




6545
6546
6547
6548
6549
6550
6551
6552
6553
6554
6555
6556

















6557
6558
6559






6560
6561
6562


6563
6564
6565
6566
6567
6568

6569
6570
6571
6572





6573
6574

6575
6576
6577
6578

6579
6580
6581
6582
6583
6584
6585
6518
6519
6520
6521
6522
6523
6524

6525


6526
6527
6528


6529
6530
6531
6532
6533
6534
6535
6536
6537
6538
6539
6540
6541
6542

6543






6544
6545
6546








6547
6548





6549
6550
6551
6552
6553
6554
6555
6556
6557
6558


6559
6560

6561
6562



6563
6564
6565
6566
6567











6568
6569
6570
6571
6572
6573
6574
6575
6576
6577
6578
6579
6580
6581
6582
6583
6584



6585
6586
6587
6588
6589
6590
6591


6592
6593
6594





6595
6596
6597
6598
6599
6600
6601
6602
6603
6604
6605

6606
6607

6608

6609
6610
6611
6612
6613
6614
6615
6616







-
+
-
-
+


-
-














-

-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+

-
-

+
-
+

-
-
-
+
+
+
+

-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+

-
-
+
+

-
-
-
-
-
+




+
+
+
+
+

-
+

-

-
+







TkMacOSXMakeFullscreen(
    TkWindow *winPtr,
    NSWindow *window,
    int fullscreen,
    Tcl_Interp *interp)
{
    WmInfo *wmPtr = winPtr->wmInfoPtr;
    int result = TCL_OK, wasFullscreen = (wmPtr->flags & WM_FULLSCREEN);
    int screenWidth =  WidthOfScreen(Tk_Screen(winPtr));
    static unsigned long prevMask = 0, prevPres = 0;

    int screenHeight = HeightOfScreen(Tk_Screen(winPtr));

    if (fullscreen) {
	int screenWidth =  WidthOfScreen(Tk_Screen(winPtr));
	int screenHeight = HeightOfScreen(Tk_Screen(winPtr));

	/*
	 * Check max width and height if set by the user.
	 */

	if ((wmPtr->maxWidth > 0 && wmPtr->maxWidth < screenWidth)
		|| (wmPtr->maxHeight > 0 && wmPtr->maxHeight < screenHeight)) {
	    if (interp) {
		Tcl_SetObjResult(interp, Tcl_ObjPrintf(
			"can't set fullscreen attribute for \"%s\": max"
			" width/height is too small", winPtr->pathName));
		Tcl_SetErrorCode(interp, "TK", "FULLSCREEN",
			"CONSTRAINT_FAILURE", NULL);
	    }
	    result = TCL_ERROR;
	    wmPtr->flags &= ~WM_FULLSCREEN;
	} else {
	    Tk_UnmapWindow((Tk_Window) winPtr);
	    NSRect bounds = [window contentRectForFrameRect:[window frame]];
	    NSRect screenBounds = NSMakeRect(0, 0, screenWidth, screenHeight);

	    if (!NSEqualRects(bounds, screenBounds) && !wasFullscreen) {
	    return TCL_ERROR;
	}

		wmPtr->configX = wmPtr->x;
		wmPtr->configY = wmPtr->y;
		wmPtr->configAttributes = wmPtr->attributes;
		wmPtr->attributes &= ~kWindowResizableAttribute;
		ApplyWindowAttributeFlagChanges(winPtr, window,
			wmPtr->configAttributes, wmPtr->flags, 1, 0);
		wmPtr->flags |= WM_SYNC_PENDING;
		[window setFrame:[window frameRectForContentRect:
	/*
	 * Save the current window state.
					   screenBounds] display:YES];
		wmPtr->flags &= ~WM_SYNC_PENDING;
	    }
	    wmPtr->flags |= WM_FULLSCREEN;
	}
	 */

	wmPtr->cachedBounds = [window frame];
	wmPtr->cachedStyle = [window styleMask];
	wmPtr->cachedPresentation = [NSApp presentationOptions];

	/*
	 * Adjust the window style so it looks like a Fullscreen window.
	 */

	prevMask = [window styleMask];
	prevPres = [NSApp presentationOptions];
	[window setStyleMask: NSFullScreenWindowMask];
	[NSApp setPresentationOptions: (NSApplicationPresentationAutoHideDock |
	[NSApp setPresentationOptions: NSApplicationPresentationAutoHideDock | NSApplicationPresentationAutoHideMenuBar];
					NSApplicationPresentationAutoHideMenuBar)];

	/*Fullscreen implementation for 10.13 and later.*/
	#if MAC_OS_X_VERSION_MIN_REQUIRED > MAC_OS_X_VERSION_10_12
	exitFullScreen = [[[NSStatusBar systemStatusBar]
	/*For 10.13 and later add a button for exiting Fullscreen.*/
	if ([NSApp macMinorVersion] > 12) {
#if MAC_OS_X_VERSION_MAX_ALLOWED > 101200
	    exitFullScreen = [[[NSStatusBar systemStatusBar]
				   statusItemWithLength:NSVariableStatusItemLength] retain];
	NSImage *exitIcon = [NSImage imageNamed:@"NSExitFullScreenTemplate"];
	[exitFullScreen setImage:exitIcon];
	[exitFullScreen setHighlightMode:YES];
	[exitFullScreen setToolTip:@"Exit Full Screen"];
	[exitFullScreen setTarget:window];
	[exitFullScreen setAction:@selector(restoreOldScreen:)];
	#endif

	Tk_MapWindow((Tk_Window) winPtr);
    } else {
	wmPtr->flags &= ~WM_FULLSCREEN;
	    NSImage *exitIcon = [NSImage imageNamed:@"NSExitFullScreenTemplate"];
	    exitFullScreen.button.image = exitIcon;
	    exitFullScreen.button.cell.highlighted = NO;
	    exitFullScreen.button.toolTip = @"Exit Full Screen";
	    exitFullScreen.button.target = window;
	    exitFullScreen.button.action = @selector(restoreOldScreen:);
#endif
	}

	/*
	 * Resize the window to fill the screen. (After setting the style!)
	 */

	wmPtr->flags |= WM_SYNC_PENDING;
	NSRect screenBounds = NSMakeRect(0, 0, screenWidth, screenHeight);
	[window setFrame:screenBounds display:YES];
	wmPtr->flags &= ~WM_SYNC_PENDING;
	[NSApp setPresentationOptions: prevPres];
	[window setStyleMask: prevMask];
    }
	wmPtr->flags |= WM_FULLSCREEN;
    } else {

	/*
	 * Restore the previous styles and attributes.
	 */

    if (wasFullscreen && !(wmPtr->flags & WM_FULLSCREEN)) {
	Tk_UnmapWindow((Tk_Window) winPtr);
	[NSApp setPresentationOptions: wmPtr->cachedPresentation];
	[window setStyleMask: wmPtr->cachedStyle];
	UInt64 oldAttributes = wmPtr->attributes;
	NSRect bounds = NSMakeRect(wmPtr->configX, tkMacOSXZeroScreenHeight -
		(wmPtr->configY + wmPtr->yInParent + wmPtr->configHeight),
		wmPtr->xInParent + wmPtr->configWidth,
		wmPtr->yInParent + wmPtr->configHeight);

	wmPtr->flags &= ~WM_FULLSCREEN;
	wmPtr->attributes |= wmPtr->configAttributes &
		kWindowResizableAttribute;
	ApplyWindowAttributeFlagChanges(winPtr, window, oldAttributes,
		wmPtr->flags, 1, 0);

	/*
	 * Resize the window to its previous size.
	 */

	wmPtr->flags |= WM_SYNC_PENDING;
	[window setFrame:[window frameRectForContentRect:bounds] display:YES];
	[window setFrame:wmPtr->cachedBounds display:YES];
	wmPtr->flags &= ~WM_SYNC_PENDING;
       Tk_MapWindow((Tk_Window) winPtr);
    }
    return result;
    return TCL_OK;
}

/*
 *----------------------------------------------------------------------
 *
 * GetMinSize --
 *
Changes to macosx/tkMacOSXWm.h.
181
182
183
184
185
186
187









188
189
190
191
192
193
194
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203







+
+
+
+
+
+
+
+
+







     */

    WindowClass macClass;
    UInt64 attributes, configAttributes;
    TkWindow *scrollWinPtr;	/* Ptr to scrollbar handling grow widget. */
    TkMenu *menuPtr;
    NSWindow *window;

    /*
     * Space to cache current window state when window becomes Fullscreen.
     */

    unsigned long cachedStyle;
    unsigned long cachedPresentation;
    NSRect cachedBounds;

} WmInfo;

/*
 * Flag values for WmInfo structures:
 *
 * WM_NEVER_MAPPED -		non-zero means window has never been mapped;
 *				need to update all info when window is first
Changes to macosx/tkMacOSXXStubs.c.
174
175
176
177
178
179
180
181

182
183
184
185
186
187
188
174
175
176
177
178
179
180

181
182
183
184
185
186
187
188







-
+







	snprintf(vendor, sizeof(vendor), "Apple AppKit %g",
		NSAppKitVersionNumber);
    }
    display->vendor = vendor;
    {
	int major, minor, patch;

#if MAC_OS_X_VERSION_MIN_REQUIRED < 1080
#if MAC_OS_X_VERSION_MIN_REQUIRED < 101000
	Gestalt(gestaltSystemVersionMajor, (SInt32*)&major);
	Gestalt(gestaltSystemVersionMinor, (SInt32*)&minor);
	Gestalt(gestaltSystemVersionBugFix, (SInt32*)&patch);
#else
	NSOperatingSystemVersion systemVersion = [[NSProcessInfo processInfo] operatingSystemVersion];
	major = systemVersion.majorVersion;
	minor = systemVersion.minorVersion;
Changes to tests/bind.test.
35
36
37
38
39
40
41
42
43


44
45

46
47
48
49
50
51
52
35
36
37
38
39
40
41


42
43
44

45
46
47
48
49
50
51
52







-
-
+
+

-
+







}

# This function fills the pattern matcher's ring buffer with events of
# the specified type.  This can be used when testing with generated
# events to make sure that there are no stray events in the ring
# buffer which might cause the pattern matcher to find unintended
# matches.  The size of the ring buffer is EVENT_BUFFER_SIZE, which is
# currently set to 30.  If this changes, the code below will need to
# change.
# currently set to 30 (or 45 on macOS).  If this changes, the code
# below will need to change.
proc clearRingBuffer {{event}} {
    for {set i 0} {$i < 30} {incr i} {
    for {set i 0} {$i < 45} {incr i} {
	event generate . $event
    }
}

# move the mouse pointer away of the testing area
# otherwise some spurious events may pollute the tests
toplevel .top