Check-in [e67daf4f5a]
Not logged in

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

Overview
Comment:add tk upstream changes
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e67daf4f5a5b497e3cfe015d6af44d274acb51a1
User & Date: chw 2019-09-03 06:51:10
Context
2019-09-03
07:25
update some undroid/vanillawish build scripts check-in: 6fc4944980 user: chw tags: trunk
06:51
merge with trunk check-in: f02026baf6 user: chw tags: wtf-8-experiment
06:51
add tk upstream changes check-in: e67daf4f5a user: chw tags: trunk
06:46
add tcl upstream changes check-in: 26903ebe4b user: chw tags: trunk
Changes

Changes to jni/sdl2tk/doc/tk_mac.n.

44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
The Aqua/Mac OS X application environment defines a number of additional
events that applications should respond to. These events are mapped by Tk to
calls to commands in the \fB::tk::mac\fR namespace; unless otherwise noted, if
the command is absent, no action will be taken.
.TP
\fB::tk::mac::DoScriptFile\fR
.
The default Apple Event handler for AEDoScriptHandler. This command,
if defined, executes a Tcl file when an AppleScript sends a
.QW "do script"
command to Wish with a file path as a parameter. 
.TP
\fB::tk::mac::DoScriptText\fR
.
The default Apple Event handler for AEDoScriptHandler. This command,
if defined, executes Tcl code when an AppleScript sends a
.QW "do script"
command to Wish with Tcl code or a Tcl procedure as a parameter.
.TP
\fB::tk::mac::ShowPreferences\fR
.
The default Apple Event handler for kAEShowPreferences,
.QW pref .
................................................................................
.PP
.CS
proc ::tk::mac::OpenDocument {args} {
    foreach f $args {my_open_document $f}
}
.CE
.RE
Note: the application must be running for this command to work. 
.TP
\fB::tk::mac::PrintDocument \fIfile...\fR
.
If a proc of this name is defined it is the default Apple Event handler for
kAEPrintDocuments,
.QW pdoc ,
the Apple Event sent when your application is asked to print a
document.  It takes a single absolute file path as an argument.
Note: the application must be running for this command to work. 
.TP
\fB::tk::mac::Quit\fR
.
If a proc of this name is defined it is the default Apple Event handler for
kAEQuitApplication,
.QW quit ,
the Apple Event sent when your application is asked to be quit, e.g. via the







|
|





|
|







 







<








<







44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
...
120
121
122
123
124
125
126

127
128
129
130
131
132
133
134

135
136
137
138
139
140
141
The Aqua/Mac OS X application environment defines a number of additional
events that applications should respond to. These events are mapped by Tk to
calls to commands in the \fB::tk::mac\fR namespace; unless otherwise noted, if
the command is absent, no action will be taken.
.TP
\fB::tk::mac::DoScriptFile\fR
.
The default Apple Event handler for AEDoScriptHandler. This command
executes a Tcl file when an AppleScript sends a
.QW "do script"
command to Wish with a file path as a parameter. 
.TP
\fB::tk::mac::DoScriptText\fR
.
The default Apple Event handler for AEDoScriptHandler. This command
executes Tcl code when an AppleScript sends a
.QW "do script"
command to Wish with Tcl code or a Tcl procedure as a parameter.
.TP
\fB::tk::mac::ShowPreferences\fR
.
The default Apple Event handler for kAEShowPreferences,
.QW pref .
................................................................................
.PP
.CS
proc ::tk::mac::OpenDocument {args} {
    foreach f $args {my_open_document $f}
}
.CE
.RE

.TP
\fB::tk::mac::PrintDocument \fIfile...\fR
.
If a proc of this name is defined it is the default Apple Event handler for
kAEPrintDocuments,
.QW pdoc ,
the Apple Event sent when your application is asked to print a
document.  It takes a single absolute file path as an argument.

.TP
\fB::tk::mac::Quit\fR
.
If a proc of this name is defined it is the default Apple Event handler for
kAEQuitApplication,
.QW quit ,
the Apple Event sent when your application is asked to be quit, e.g. via the

Changes to jni/sdl2tk/generic/tkCanvas.c.

2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916

static void
EventuallyRedrawItem(
    TkCanvas *canvasPtr,	/* Information about widget. */
    Tk_Item *itemPtr)		/* Item to be redrawn. May be NULL, in which
				 * case nothing happens. */
{
    if (itemPtr == NULL) {
	return;
    }
    if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) ||
 	    (itemPtr->x2 < canvasPtr->xOrigin) ||
	    (itemPtr->y2 < canvasPtr->yOrigin) ||
	    (itemPtr->x1 >= canvasPtr->xOrigin+Tk_Width(canvasPtr->tkwin)) ||
	    (itemPtr->y1 >= canvasPtr->yOrigin+Tk_Height(canvasPtr->tkwin))) {







|







2902
2903
2904
2905
2906
2907
2908
2909
2910
2911
2912
2913
2914
2915
2916

static void
EventuallyRedrawItem(
    TkCanvas *canvasPtr,	/* Information about widget. */
    Tk_Item *itemPtr)		/* Item to be redrawn. May be NULL, in which
				 * case nothing happens. */
{
    if (itemPtr == NULL || canvasPtr->tkwin == NULL) {
	return;
    }
    if ((itemPtr->x1 >= itemPtr->x2) || (itemPtr->y1 >= itemPtr->y2) ||
 	    (itemPtr->x2 < canvasPtr->xOrigin) ||
	    (itemPtr->y2 < canvasPtr->yOrigin) ||
	    (itemPtr->x1 >= canvasPtr->xOrigin+Tk_Width(canvasPtr->tkwin)) ||
	    (itemPtr->y1 >= canvasPtr->yOrigin+Tk_Height(canvasPtr->tkwin))) {

Changes to jni/sdl2tk/library/tk.tcl.

715
716
717
718
719
720
721
722

723

724
725
726








727
728
729
730
731
732
733

if {[tk windowingsystem] eq "aqua"} {
    namespace eval ::tk::mac {
	set useCustomMDEF 0
    }
}

# Register to send data to macOS Services

if {[tk windowingsystem] eq "aqua"} {

proc ::tk::RegisterServiceWidget {w} {
    ::tk::mac::registerServiceWidget $w
  }








}

if {$::tk::sdltk} {
    # Android hardware keyboard handling
    if {$::tk::android} {
	if {[package versions Borg] ne {}} {
	    package require Borg







<
>

>
|
|
|
>
>
>
>
>
>
>
>







715
716
717
718
719
720
721

722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742

if {[tk windowingsystem] eq "aqua"} {
    namespace eval ::tk::mac {
	set useCustomMDEF 0
    }
}



if {[tk windowingsystem] eq "aqua"} {
    # Register to send data to macOS Services
    proc ::tk::RegisterServiceWidget {w} {
	::tk::mac::registerServiceWidget $w
    }

    # Stub procedures to respond to "do script" Apple Events
    proc ::tk::mac::DoScriptFile {file} {
	source $file
    }
    proc ::tk::mac::DoScriptText {script} {
	eval $script
    }
}

if {$::tk::sdltk} {
    # Android hardware keyboard handling
    if {$::tk::android} {
	if {[package versions Borg] ne {}} {
	    package require Borg

Changes to jni/sdl2tk/macosx/tkMacOSXHLEvents.c.

1
2
3
4
5
6
7
8
9
10

11
12
13
14
15
16
17
..
25
26
27
28
29
30
31












32
33
34
35
36
37
38
39
40
41











42
43
44
45
46
47
48
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
...
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
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
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
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
283
284
285
286
287
288
289
290
291
292
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
332
333
334
335
...
355
356
357
358
359
360
361


362
363
364
365
366
367
368
369
370
...
373
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
/*
 * tkMacOSXHLEvents.c --
 *
 *	Implements high level event support for the Macintosh. Currently, the
 *	only event that really does anything is the Quit event.
 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright 2001-2009, Apple Inc.
 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
 * Copyright (c) 2015 Marc Culler

 *
 * 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/param.h>
................................................................................
typedef struct KillEvent {
    Tcl_Event header;		/* Information that is standard for all
				 * events. */
    Tcl_Interp *interp;		/* Interp that was passed to the Quit
				 * AppleEvent */
} KillEvent;













/*
 * Static functions used only in this file.
 */

static void tkMacOSXProcessFiles(NSAppleEventDescriptor* event,
				 NSAppleEventDescriptor* replyEvent,
				 Tcl_Interp *interp,
				 const char* procedure);
static int  MissedAnyParameters(const AppleEvent *theEvent);
static int  ReallyKillMe(Tcl_Event *eventPtr, int flags);












#pragma mark TKApplication(TKHLEvents)

@implementation TKApplication(TKHLEvents)
- (void) terminate: (id) sender
{
    [self handleQuitApplicationEvent:Nil withReplyEvent:Nil];
................................................................................
	Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD);
    }
}

- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event
    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
   Tcl_Interp *interp = _eventInterp;

    if (interp &&
	Tcl_FindCommand(_eventInterp, "::tk::mac::OpenApplication", NULL, 0)){
	int code = Tcl_EvalEx(_eventInterp, "::tk::mac::OpenApplication",
			      -1, TCL_EVAL_GLOBAL);
	if (code != TCL_OK) {
	    Tcl_BackgroundException(_eventInterp, code);
	}
    }
................................................................................
	}
    }
}

- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event
    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
    tkMacOSXProcessFiles(event, replyEvent, _eventInterp, "::tk::mac::OpenDocument");
}

- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{

    NSString* file = [[event paramDescriptorForKeyword:keyDirectObject]
			 stringValue];
    const char *printFile=[file UTF8String];
    Tcl_DString print;
    Tcl_DStringInit(&print);
    if (Tcl_FindCommand(_eventInterp, "::tk::mac::PrintDocument", NULL, 0)) {
	Tcl_DStringAppend(&print, "::tk::mac::PrintDocument", -1);
    }
    Tcl_DStringAppendElement(&print, printFile);
    int  tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&print),
			     Tcl_DStringLength(&print), TCL_EVAL_GLOBAL);
    if (tclErr!= TCL_OK) {
	Tcl_BackgroundException(_eventInterp, tclErr);
    }
}


- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
    OSStatus err;
    const AEDesc *theDesc = nil;
    DescType type = 0, initialType = 0;
    Size actual;
    int tclErr = -1;
    char URLBuffer[1 + URL_MAX_LENGTH];
    char errString[128];
    char typeString[5];

    /*
     * The DoScript event receives one parameter that should be text data or a
     * fileURL.
     */

    theDesc = [event aeDesc];
    if (theDesc == nil) {
	return;
    }

    err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType,
			NULL, 0, NULL);
    if (err != noErr) {
	sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err);
	AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
		      errString, strlen(errString));
	return;
    }

    if (MissedAnyParameters((AppleEvent*)theDesc)) {
    	sprintf(errString, "AEDoScriptHandler: extra parameters");
    	AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
    		      errString, strlen(errString));
    	return;
    }

    if (initialType == typeFileURL || initialType == typeAlias) {
	/*
	 * The descriptor can be coerced to a file url.  Source the file, or
	 * pass the path as a string argument to ::tk::mac::DoScriptFile if
	 * that procedure exists.
	 */
	err = AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
			    (Ptr) URLBuffer, URL_MAX_LENGTH, &actual);
	if (err == noErr && actual > 0){
	    URLBuffer[actual] = '\0';
	    NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
	    NSURL *fileURL = [NSURL URLWithString:urlString];
	    Tcl_DString command;
	    Tcl_DStringInit(&command);
	    if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptFile", NULL, 0)){
		Tcl_DStringAppend(&command, "::tk::mac::DoScriptFile", -1);
	    } else {
		Tcl_DStringAppend(&command, "source", -1);
	    }
	    Tcl_DStringAppendElement(&command, [[fileURL path] UTF8String]);
	    tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
				 Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
	}
    } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
			   NULL, 0, &actual)) {
	if (actual > 0) {
	    /*
	     * The descriptor can be coerced to UTF8 text.  Evaluate as Tcl, or
	     * or pass the text as a string argument to ::tk::mac::DoScriptText
	     * if that procedure exists.
	     */
	    char *data = ckalloc(actual + 1);
	    if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
			    data, actual, NULL)) {
		if (Tcl_FindCommand(_eventInterp, "::tk::mac::DoScriptText", NULL, 0)){
		    Tcl_DString command;
		    Tcl_DStringInit(&command);
		    Tcl_DStringAppend(&command, "::tk::mac::DoScriptText", -1);
		    Tcl_DStringAppendElement(&command, data);
		    tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&command),
				 Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
		} else {
		    tclErr = Tcl_EvalEx(_eventInterp, data, actual, TCL_EVAL_GLOBAL);
		}
	    }
	    ckfree(data);
	}
    } else {
	/*
	 * The descriptor can not be coerced to a fileURL or UTF8 text.
	 */
	for (int i = 0; i < 4; i++) {
	    typeString[i] = ((char*)&initialType)[3-i];
	}
	typeString[4] = '\0';
	sprintf(errString, "AEDoScriptHandler: invalid script type '%s', "
		"must be coercable to 'furl' or 'utf8'", typeString);
	AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar, errString,
		      strlen(errString));
    }
    /*
     * If we ran some Tcl code, put the result in the reply.
     */
    if (tclErr >= 0) {
	int reslen;
	const char *result =
	    Tcl_GetStringFromObj(Tcl_GetObjResult(_eventInterp), &reslen);
	if (tclErr == TCL_OK) {
	    AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyDirectObject, typeChar,
			  result, reslen);
	} else {
	    AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString, typeChar,
			  result, reslen);
	    AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorNumber, typeSInt32,
			  (Ptr) &tclErr,sizeof(int));
	}
    }
    return;
}

- (void)handleURLEvent:(NSAppleEventDescriptor*)event
        withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
    NSString* url = [[event paramDescriptorForKeyword:keyDirectObject]
                        stringValue];
    const char *cURL=[url UTF8String];
    Tcl_DString launch;
    Tcl_DStringInit(&launch);
    if (Tcl_FindCommand(_eventInterp, "::tk::mac::LaunchURL", NULL, 0)) {
	Tcl_DStringAppend(&launch, "::tk::mac::LaunchURL", -1);
    }
    Tcl_DStringAppendElement(&launch, cURL);
    int  tclErr = Tcl_EvalEx(_eventInterp, Tcl_DStringValue(&launch),
			     Tcl_DStringLength(&launch), TCL_EVAL_GLOBAL);
    if (tclErr!= TCL_OK) {
	Tcl_BackgroundException(_eventInterp, tclErr);
         }
    }

@end

#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * TkMacOSXProcessFiles --
 *
 *	Extract a list of fileURLs from an AppleEvent and call the specified
 *      procedure with the file paths as arguments.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The event is handled by running the procedure.
 *
 *----------------------------------------------------------------------
 */

static void
tkMacOSXProcessFiles(
    NSAppleEventDescriptor* event,
    NSAppleEventDescriptor* replyEvent,
    Tcl_Interp *interp,
    const char* procedure)
{
    Tcl_Encoding utf8;
    const AEDesc *fileSpecDesc = nil;
    AEDesc contents;
    char URLString[1 + URL_MAX_LENGTH];
    NSURL *fileURL;
    DescType type;
    Size actual;
    long count, index;
    AEKeyword keyword;
    Tcl_DString command, pathName;
    int code;

    /*
     * Do nothing if we don't have an interpreter or the procedure doesn't exist.
     */

    if (!interp || !Tcl_FindCommand(interp, procedure, NULL, 0)) {
	return;
    }

    fileSpecDesc = [event aeDesc];
    if (fileSpecDesc == nil ) {
	return;
    }
................................................................................
    }

    /*
     * Construct a Tcl command which calls the procedure, passing the
     * paths contained in the AppleEvent as arguments.
     */



    Tcl_DStringInit(&command);
    Tcl_DStringAppend(&command, procedure, -1);
    utf8 = Tcl_GetEncoding(NULL, "utf-8");

    for (index = 1; index <= count; index++) {
	if (noErr != AEGetNthPtr(fileSpecDesc, index, typeFileURL, &keyword,
				 &type, (Ptr) URLString, URL_MAX_LENGTH, &actual)) {
	    continue;
	}
................................................................................
	}
	URLString[actual] = '\0';
	fileURL = [NSURL URLWithString:[NSString stringWithUTF8String:(char*)URLString]];
	if (fileURL == nil) {
	    continue;
	}
	Tcl_ExternalToUtfDString(utf8, [[fileURL path] UTF8String], -1, &pathName);
	Tcl_DStringAppendElement(&command, Tcl_DStringValue(&pathName));
	Tcl_DStringFree(&pathName);
    }

    Tcl_FreeEncoding(utf8);
    AEDisposeDesc(&contents);

































    /*
     * Handle the event by evaluating the Tcl expression we constructed.


     */




































































































































    code = Tcl_EvalEx(interp, Tcl_DStringValue(&command),
	    Tcl_DStringLength(&command), TCL_EVAL_GLOBAL);
    if (code != TCL_OK) {
	Tcl_BackgroundException(interp, code);
    }















    Tcl_DStringFree(&command);

}
 
/*
 *----------------------------------------------------------------------
 *
 * TkMacOSXInitAppleEvents --
 *



|
<


|

|
>







 







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




<
<
<
<


>
>
>
>
>
>
>
>
>
>
>







 







|
<
<







 







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









|



|


|







 







>
>
|
|







 







|





>
>
>
>
|
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

<
>
>


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
|

|

>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>







1
2
3
4

5
6
7
8
9
10
11
12
13
14
15
16
17
..
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
..
93
94
95
96
97
98
99
100


101
102
103
104
105
106
107
...
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
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
...
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
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
283
284
285
286
287
288
289
290
291
292
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
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
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
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
/*
 * tkMacOSXHLEvents.c --
 *
 *	Implements high level event support for the Macintosh.

 *
 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
 * Copyright (c) 2001-2009, Apple Inc.
 * Copyright (c) 2006-2009 Daniel A. Steffen <das@users.sourceforge.net>
 * Copyright (c) 2015-2019 Marc Culler
 * Copyright (c) 2019 Kevin Walzer/WordTech Communications LLC.
 *
 * 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/param.h>
................................................................................
typedef struct KillEvent {
    Tcl_Event header;		/* Information that is standard for all
				 * events. */
    Tcl_Interp *interp;		/* Interp that was passed to the Quit
				 * AppleEvent */
} KillEvent;

/*
 * When processing an AppleEvent as an idle task, a pointer to one
 * of these structs is passed as the clientData.
 */

typedef struct AppleEventInfo {
    Tcl_Interp *interp;
    const char *procedure;
    Tcl_DString command;
    NSAppleEventDescriptor *replyEvent; /* Only used for DoScriptText. */
} AppleEventInfo;

/*
 * Static functions used only in this file.
 */





static int  MissedAnyParameters(const AppleEvent *theEvent);
static int  ReallyKillMe(Tcl_Event *eventPtr, int flags);
static void ProcessAppleEvent(ClientData clientData);

/*
 * Names of the procedures which can be used to process AppleEvents.
 */

static char* openDocumentProc = "::tk::mac::OpenDocument";
static char* launchURLProc = "::tk::mac::LaunchURL";
static char* printDocProc = "::tk::mac::PrintDocument";
static char* scriptFileProc = "::tk::mac::DoScriptFile";
static char* scriptTextProc = "::tk::mac::DoScriptText";

#pragma mark TKApplication(TKHLEvents)

@implementation TKApplication(TKHLEvents)
- (void) terminate: (id) sender
{
    [self handleQuitApplicationEvent:Nil withReplyEvent:Nil];
................................................................................
	Tcl_QueueEvent((Tcl_Event *) eventPtr, TCL_QUEUE_HEAD);
    }
}

- (void) handleOpenApplicationEvent: (NSAppleEventDescriptor *)event
    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
    if (_eventInterp &&


	Tcl_FindCommand(_eventInterp, "::tk::mac::OpenApplication", NULL, 0)){
	int code = Tcl_EvalEx(_eventInterp, "::tk::mac::OpenApplication",
			      -1, TCL_EVAL_GLOBAL);
	if (code != TCL_OK) {
	    Tcl_BackgroundException(_eventInterp, code);
	}
    }
................................................................................
	}
    }
}

- (void) handleOpenDocumentsEvent: (NSAppleEventDescriptor *)event
    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{





























































































































































































    Tcl_Encoding utf8;
    const AEDesc *fileSpecDesc = nil;
    AEDesc contents;
    char URLString[1 + URL_MAX_LENGTH];
    NSURL *fileURL;
    DescType type;
    Size actual;
    long count, index;
    AEKeyword keyword;
    Tcl_DString pathName;
    int code;

    /*
     * Do nothing if we don't have an interpreter.
     */

    if (!_eventInterp) {
	return;
    }

    fileSpecDesc = [event aeDesc];
    if (fileSpecDesc == nil ) {
	return;
    }
................................................................................
    }

    /*
     * Construct a Tcl command which calls the procedure, passing the
     * paths contained in the AppleEvent as arguments.
     */

    AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
    Tcl_DString *openCommand = &AEInfo->command;
    Tcl_DStringInit(openCommand);
    Tcl_DStringAppend(openCommand, openDocumentProc, -1);
    utf8 = Tcl_GetEncoding(NULL, "utf-8");

    for (index = 1; index <= count; index++) {
	if (noErr != AEGetNthPtr(fileSpecDesc, index, typeFileURL, &keyword,
				 &type, (Ptr) URLString, URL_MAX_LENGTH, &actual)) {
	    continue;
	}
................................................................................
	}
	URLString[actual] = '\0';
	fileURL = [NSURL URLWithString:[NSString stringWithUTF8String:(char*)URLString]];
	if (fileURL == nil) {
	    continue;
	}
	Tcl_ExternalToUtfDString(utf8, [[fileURL path] UTF8String], -1, &pathName);
	Tcl_DStringAppendElement(openCommand, Tcl_DStringValue(&pathName));
	Tcl_DStringFree(&pathName);
    }

    Tcl_FreeEncoding(utf8);
    AEDisposeDesc(&contents);
    AEInfo->interp = _eventInterp;
    AEInfo->procedure = openDocumentProc;
    AEInfo->replyEvent = nil;
    Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}

- (void) handlePrintDocumentsEvent: (NSAppleEventDescriptor *)event
		    withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
    NSString* file = [[event paramDescriptorForKeyword:keyDirectObject]
			 stringValue];
    const char *printFile = [file UTF8String];
    AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
    Tcl_DString *printCommand = &AEInfo->command;
    Tcl_DStringInit(printCommand);
    Tcl_DStringAppend(printCommand, printDocProc, -1);
    Tcl_DStringAppendElement(printCommand, printFile);
    AEInfo->interp = _eventInterp;
    AEInfo->procedure = printDocProc;
    AEInfo->replyEvent = nil;
    Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}

- (void) handleDoScriptEvent: (NSAppleEventDescriptor *)event
	      withReplyEvent: (NSAppleEventDescriptor *)replyEvent
{
    OSStatus err;
    const AEDesc *theDesc = nil;
    DescType type = 0, initialType = 0;
    Size actual;
    char URLBuffer[1 + URL_MAX_LENGTH];
    char errString[128];

    /*

     * The DoScript event receives one parameter that should be text data or a
     * fileURL.
     */

    theDesc = [event aeDesc];
    if (theDesc == nil) {
	return;
    }

    err = AEGetParamPtr(theDesc, keyDirectObject, typeWildCard, &initialType,
			NULL, 0, NULL);
    if (err != noErr) {
	sprintf(errString, "AEDoScriptHandler: GetParamDesc error %d", (int)err);
	AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString,
		      typeChar, errString, strlen(errString));
	return;
    }

    if (MissedAnyParameters((AppleEvent*)theDesc)) {
    	sprintf(errString, "AEDoScriptHandler: extra parameters");
    	AEPutParamPtr((AppleEvent*)[replyEvent aeDesc], keyErrorString,
		      typeChar,errString, strlen(errString));
    	return;
    }

    if (initialType == typeFileURL || initialType == typeAlias) {

	/*
	 * This descriptor can be coerced to a file url.  Construct a Tcl
	 * expression which passes the file path as a string argument to
         * ::tk::mac::DoScriptFile.
	 */

	if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeFileURL, &type,
                                  (Ptr) URLBuffer, URL_MAX_LENGTH, &actual)) {
            if (actual > 0) {
                URLBuffer[actual] = '\0';
                NSString *urlString = [NSString stringWithUTF8String:(char*)URLBuffer];
                NSURL *fileURL = [NSURL URLWithString:urlString];
                AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
                Tcl_DString *scriptFileCommand = &AEInfo->command;
                Tcl_DStringInit(scriptFileCommand);
                Tcl_DStringAppend(scriptFileCommand, scriptFileProc, -1);
                Tcl_DStringAppendElement(scriptFileCommand, [[fileURL path] UTF8String]);
                AEInfo->interp = _eventInterp;
                AEInfo->procedure = scriptFileProc;
                AEInfo->replyEvent = nil;
                Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
            }
        }
    } else if (noErr == AEGetParamPtr(theDesc, keyDirectObject, typeUTF8Text, &type,
			       NULL, 0, &actual)) {
        /*
         * The descriptor cannot be coerced to a file URL but can be coerced to
         * text.  Construct a Tcl expression which passes the text as a string
         * argument to ::tk::mac::DoScriptText.
         */

	if (actual > 0) {
	    char *data = ckalloc(actual + 1);
	    if (noErr == AEGetParamPtr(theDesc, keyDirectObject,
				       typeUTF8Text, &type,
				       data, actual, NULL)) {
                AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
                Tcl_DString *scriptTextCommand = &AEInfo->command;
                Tcl_DStringInit(scriptTextCommand);
                Tcl_DStringAppend(scriptTextCommand, scriptTextProc, -1);
		Tcl_DStringAppendElement(scriptTextCommand, data);
		AEInfo->interp = _eventInterp;
		AEInfo->procedure = scriptTextProc;
                if (Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
                    AEInfo->replyEvent = replyEvent;
                    ProcessAppleEvent((ClientData)AEInfo);
                } else {
                    AEInfo->replyEvent = nil;
                    Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
                }
	    }
	}
    }
}
   
- (void)handleURLEvent:(NSAppleEventDescriptor*)event
        withReplyEvent:(NSAppleEventDescriptor*)replyEvent
{
    NSString* url = [[event paramDescriptorForKeyword:keyDirectObject]
                        stringValue];
    const char *cURL=[url UTF8String];
    AppleEventInfo *AEInfo = ckalloc(sizeof(AppleEventInfo));
    Tcl_DString *launchCommand = &AEInfo->command;
    Tcl_DStringInit(launchCommand);
    Tcl_DStringAppend(launchCommand, launchURLProc, -1);
    Tcl_DStringAppendElement(launchCommand, cURL);
    AEInfo->interp = _eventInterp;
    AEInfo->procedure = launchURLProc;
    AEInfo->replyEvent = nil;
    Tcl_DoWhenIdle(ProcessAppleEvent, (ClientData)AEInfo);
}

@end

#pragma mark -

/*
 *----------------------------------------------------------------------
 *
 * ProcessAppleEvent --
 *
 *      Usually used as an idle task which evaluates a Tcl expression generated
 *      from an AppleEvent.  If the AppleEventInfo passed as the client data
 *      has a non-null replyEvent, the result of evaluating the expression will
 *      be added to the reply.  This must not be done when this function is
 *      called as an idle task, but is done when handling DoScriptText events
 *      when this function is called directly.
 *
 * Results:
 *	None.
 *
 * Side effects:
 *	The expression will be evaluated and the clientData will be freed.
 *      The replyEvent may be modified to contain the result of evaluating
 *      a Tcl expression.
 *
 *----------------------------------------------------------------------
 */

static void ProcessAppleEvent(
    ClientData clientData)
{
    int code;
    AppleEventInfo *AEInfo = (AppleEventInfo*) clientData;
    if (!AEInfo->interp ||
        !Tcl_FindCommand(AEInfo->interp, AEInfo->procedure, NULL, 0)) {
	return;
    }
    code = Tcl_EvalEx(AEInfo->interp, Tcl_DStringValue(&AEInfo->command),
	    Tcl_DStringLength(&AEInfo->command), TCL_EVAL_GLOBAL);
    if (code != TCL_OK) {
	Tcl_BackgroundException(AEInfo->interp, code);
    }

    if (AEInfo->replyEvent && code >= 0) {
        int reslen;
        const char *result = Tcl_GetStringFromObj(Tcl_GetObjResult(AEInfo->interp),
                                                  &reslen);
        if (code == TCL_OK) {
            AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
                          keyDirectObject, typeChar, result, reslen);
        } else {
            AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
                          keyErrorString, typeChar, result, reslen);
            AEPutParamPtr((AppleEvent*)[AEInfo->replyEvent aeDesc],
                          keyErrorNumber, typeSInt32, (Ptr) &code, sizeof(int));
        }
    }
    Tcl_DStringFree(&AEInfo->command);
    ckfree(clientData);
}
 
/*
 *----------------------------------------------------------------------
 *
 * TkMacOSXInitAppleEvents --
 *

Changes to jni/sdl2tk/macosx/tkMacOSXInit.c.

321
322
323
324
325
326
327













328





329
330
331
332
333
334
335
336







337
338
339
340
341
342
343
			      @"_NSCanWrapButtonTitles",
				   [NSNumber numberWithInt:-1],
			      @"NSStringDrawingTypesetterBehavior",
			      nil]];
	[TKApplication sharedApplication];
	[pool drain];
	[NSApp _setup:interp];













	[NSApp finishLaunching];





	Tk_MacOSXSetupTkNotifier();

	/*
	 * If the root window is mapped before the App has finished launching
	 * it will open off screen (see ticket 56a1823c73).  To avoid this we
	 * ask Tk to process an event with no wait.  We expect Tcl_DoOneEvent
	 * to wait until the Mac event loop has been created and then return
	 * immediately since the queue is empty.







	 */

	Tcl_DoOneEvent(TCL_WINDOW_EVENTS | TCL_DONT_WAIT);

	/*
	 * If we don't have a TTY and stdin is a special character file of
	 * length 0, (e.g. /dev/null, which is what Finder sets when double







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

>
>
>
>
>



|
|
|
|
|
>
>
>
>
>
>
>







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
358
359
360
361
362
363
364
365
366
367
368
			      @"_NSCanWrapButtonTitles",
				   [NSNumber numberWithInt:-1],
			      @"NSStringDrawingTypesetterBehavior",
			      nil]];
	[TKApplication sharedApplication];
	[pool drain];
	[NSApp _setup:interp];

        /*
         * WARNING: The finishLaunching method runs asynchronously, apparently
         * in a separate thread.  This creates a race between the
         * initialization of the NSApplication and the initialization of Tk.
         * If Tk wins the race bad things happen with the root window (see
         * below).  If the NSApplication wins then an AppleEvent created during
         * launch, e.g. by dropping a file icon on the application icon, will
         * be delivered before the procedure meant to to handle the AppleEvent
         * has been defined.  This is now handled by processing the AppleEvent
         * as an idle task.  See tkMacOSXHLEvents.c.
         */

	[NSApp finishLaunching];

        /*
         * Create a Tk event source based on the Appkit event queue.
         */

	Tk_MacOSXSetupTkNotifier();

	/*
	 * If Tk initialization wins the race, the root window is mapped before
         * the NSApplication is initialized.  This can cause bad things to
         * happen.  The root window can open off screen with no way to make it
         * appear on screen until the app icon is clicked.  This will happen if
         * a Tk application opens a modal window in its startup script (see
         * ticket 56a1823c73).  In other cases, an empty root window can open
         * on screen and remain visible for a noticeable amount of time while
         * the Tk initialization finishes (see ticket d1989fb7cf).  The call
         * below forces Tk to block until the Appkit event queue has been
         * created.  This seems to be sufficient to ensure that the
         * NSApplication initialization wins the race, avoiding these bad
         * window behaviors.
	 */

	Tcl_DoOneEvent(TCL_WINDOW_EVENTS | TCL_DONT_WAIT);

	/*
	 * If we don't have a TTY and stdin is a special character file of
	 * length 0, (e.g. /dev/null, which is what Finder sets when double

Changes to jni/sdl2tk/macosx/ttkMacOSXTheme.c.

241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
275
276
277
278
279
280
281

282
283
284

285
286
287
288
289
290
291
....
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
    Tk_Window tkwin,
    int contrast,
    CGFloat *rgba)
{
    TkWindow *winPtr = (TkWindow *) tkwin;
    TkWindow *masterPtr = (TkWindow *) TkGetGeomMaster(tkwin);

    while (masterPtr != NULL) {
	if (masterPtr->privatePtr->flags & TTK_HAS_CONTRASTING_BG) {
	    break;
	}
	masterPtr = (TkWindow *) TkGetGeomMaster(masterPtr);
    }
    if (masterPtr) {
	for (int i = 0; i < 4; i++) {
	    rgba[i] = masterPtr->privatePtr->fillRGBA[i];
	}
    } else {
	if ([NSApp macMinorVersion] > 13) {
	    NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace];
	    NSColor *windowColor = [[NSColor windowBackgroundColor]
................................................................................
		rgba[i] += 8.0 / 255.0;
	    }
	} else {
	    for (int i = 0; i < 3; i++) {
		rgba[i] -= 8.0 / 255.0;
	    }
	}

	winPtr->privatePtr->flags |= TTK_HAS_CONTRASTING_BG;
	for (int i = 0; i < 4; i++) {
	    winPtr->privatePtr->fillRGBA[i] = rgba[i];

	}
    }
}


/*----------------------------------------------------------------------
 * +++ Single Arrow Buttons --
................................................................................
	GetBackgroundColor(dc.context, tkwin, 1, fill);

	/*
	 * Lighten the background to provide contrast.
	 */

	for (int i = 0; i < 3; i++) {
		fill[i] += 9.0 / 255.0;
	}
	background = [NSColor colorWithColorSpace: deviceRGB
	    components: fill
	    count: 4];
	CGContextSetFillColorWithColor(dc.context, CGCOLOR(background));
	CGContextFillRect(dc.context, bounds);
	if (state & TTK_STATE_FOCUS) {







|





|







 







>
|
|
|
>







 







|







241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
...
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
....
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
    Tk_Window tkwin,
    int contrast,
    CGFloat *rgba)
{
    TkWindow *winPtr = (TkWindow *) tkwin;
    TkWindow *masterPtr = (TkWindow *) TkGetGeomMaster(tkwin);

    while (masterPtr && masterPtr->privatePtr) {
	if (masterPtr->privatePtr->flags & TTK_HAS_CONTRASTING_BG) {
	    break;
	}
	masterPtr = (TkWindow *) TkGetGeomMaster(masterPtr);
    }
    if (masterPtr && masterPtr->privatePtr) {
	for (int i = 0; i < 4; i++) {
	    rgba[i] = masterPtr->privatePtr->fillRGBA[i];
	}
    } else {
	if ([NSApp macMinorVersion] > 13) {
	    NSColorSpace *deviceRGB = [NSColorSpace deviceRGBColorSpace];
	    NSColor *windowColor = [[NSColor windowBackgroundColor]
................................................................................
		rgba[i] += 8.0 / 255.0;
	    }
	} else {
	    for (int i = 0; i < 3; i++) {
		rgba[i] -= 8.0 / 255.0;
	    }
	}
        if (winPtr->privatePtr) {
	    winPtr->privatePtr->flags |= TTK_HAS_CONTRASTING_BG;
	    for (int i = 0; i < 4; i++) {
		winPtr->privatePtr->fillRGBA[i] = rgba[i];
	    }
	}
    }
}


/*----------------------------------------------------------------------
 * +++ Single Arrow Buttons --
................................................................................
	GetBackgroundColor(dc.context, tkwin, 1, fill);

	/*
	 * Lighten the background to provide contrast.
	 */

	for (int i = 0; i < 3; i++) {
	    fill[i] += 9.0 / 255.0;
	}
	background = [NSColor colorWithColorSpace: deviceRGB
	    components: fill
	    count: 4];
	CGContextSetFillColorWithColor(dc.context, CGCOLOR(background));
	CGContextFillRect(dc.context, bounds);
	if (state & TTK_STATE_FOCUS) {