11#define PY_SSIZE_T_CLEAN
22#include < Cocoa/Cocoa.h>
33#include < ApplicationServices/ApplicationServices.h>
4- #include < sys/socket.h>
54#include < Python.h>
65#include " mplutils.h"
76
8- #ifndef PYPY
9- /* Remove this once Python is fixed: https://bugs.python.org/issue23237 */
10- #define PYOSINPUTHOOK_REPETITIVE 1
11- #endif
12-
137/* Proper way to check for the OS X version we are compiling for, from
148 * https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html
159
4640static bool keyChangeOption = false ;
4741static bool keyChangeCapsLock = false ;
4842
49- /* -------------------------- Helper function ---------------------------- */
50-
51- static void
52- _stdin_callback (CFReadStreamRef stream, CFStreamEventType eventType, void * info)
53- {
54- CFRunLoopRef runloop = info;
55- CFRunLoopStop (runloop);
56- }
57-
58- static int sigint_fd = -1 ;
59-
60- static void _sigint_handler (int sig)
61- {
62- const char c = ' i' ;
63- write (sigint_fd, &c, 1 );
64- }
65-
66- static void _sigint_callback (CFSocketRef s,
67- CFSocketCallBackType type,
68- CFDataRef address,
69- const void * data,
70- void *info)
71- {
72- char c;
73- int * interrupted = info;
74- CFSocketNativeHandle handle = CFSocketGetNative (s);
75- CFRunLoopRef runloop = CFRunLoopGetCurrent ();
76- read (handle, &c, 1 );
77- *interrupted = 1 ;
78- CFRunLoopStop (runloop);
79- }
80-
81- static CGEventRef _eventtap_callback (
82- CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
83- {
84- CFRunLoopRef runloop = refcon;
85- CFRunLoopStop (runloop);
86- return event;
87- }
88-
89- static int wait_for_stdin (void )
90- {
91- int interrupted = 0 ;
92- const UInt8 buffer[] = " /dev/fd/0" ;
93- const CFIndex n = (CFIndex)strlen ((char *)buffer);
94- CFRunLoopRef runloop = CFRunLoopGetCurrent ();
95- CFURLRef url = CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault ,
96- buffer,
97- n,
98- false );
99- CFReadStreamRef stream = CFReadStreamCreateWithFile (kCFAllocatorDefault ,
100- url);
101- CFRelease (url);
102-
103- CFReadStreamOpen (stream);
104- #ifdef PYOSINPUTHOOK_REPETITIVE
105- if (!CFReadStreamHasBytesAvailable (stream))
106- /* This is possible because of how PyOS_InputHook is called from Python */
107- #endif
108- {
109- int error;
110- int channel[2 ];
111- CFSocketRef sigint_socket = NULL ;
112- PyOS_sighandler_t py_sigint_handler = NULL ;
113- CFStreamClientContext clientContext = {0 , NULL , NULL , NULL , NULL };
114- clientContext.info = runloop;
115- CFReadStreamSetClient (stream,
116- kCFStreamEventHasBytesAvailable ,
117- _stdin_callback,
118- &clientContext);
119- CFReadStreamScheduleWithRunLoop (stream, runloop, kCFRunLoopDefaultMode );
120- error = socketpair (AF_UNIX , SOCK_STREAM , 0 , channel);
121- if (!error) {
122- CFSocketContext context;
123- context.version = 0 ;
124- context.info = &interrupted;
125- context.retain = NULL ;
126- context.release = NULL ;
127- context.copyDescription = NULL ;
128- fcntl (channel[0 ], F_SETFL , O_WRONLY | O_NONBLOCK );
129- sigint_socket = CFSocketCreateWithNative (
130- kCFAllocatorDefault ,
131- channel[1 ],
132- kCFSocketReadCallBack ,
133- _sigint_callback,
134- &context);
135- if (sigint_socket) {
136- CFRunLoopSourceRef source = CFSocketCreateRunLoopSource (
137- kCFAllocatorDefault , sigint_socket, 0 );
138- CFRelease (sigint_socket);
139- if (source) {
140- CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode );
141- CFRelease (source);
142- sigint_fd = channel[0 ];
143- py_sigint_handler = PyOS_setsig (SIGINT , _sigint_handler);
144- }
145- }
146- }
147-
148- NSEvent * event;
149- while (true ) {
150- while (true ) {
151- event = [NSApp nextEventMatchingMask: NSEventMaskAny
152- untilDate: [NSDate distantPast ]
153- inMode: NSDefaultRunLoopMode
154- dequeue: YES ];
155- if (!event) { break ; }
156- [NSApp sendEvent: event];
157- }
158- CFRunLoopRun ();
159- if (interrupted || CFReadStreamHasBytesAvailable (stream)) { break ; }
160- }
161-
162- if (py_sigint_handler) { PyOS_setsig (SIGINT , py_sigint_handler); }
163- CFReadStreamUnscheduleFromRunLoop (
164- stream, runloop, kCFRunLoopCommonModes );
165- if (sigint_socket) { CFSocketInvalidate (sigint_socket); }
166- if (!error) {
167- close (channel[0 ]);
168- close (channel[1 ]);
169- }
170- }
171- CFReadStreamClose (stream);
172- CFRelease (stream);
173- if (interrupted) {
174- errno = EINTR ;
175- raise (SIGINT );
176- return -1 ;
177- }
178- return 1 ;
179- }
180-
18143/* ---------------------------- Cocoa classes ---------------------------- */
18244
18345@interface WindowServerConnectionManager : NSObject
18446{
18547}
18648+ (WindowServerConnectionManager*)sharedManager ;
187- - (void )launch : (NSNotification *)notification ;
18849- (void )receivedData : (NSNotification *)notification ;
18950@end
19051
@@ -285,15 +146,6 @@ static void lazy_init(void) {
285146 NSApp = [NSApplication sharedApplication ];
286147 [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
287148
288- PyOS_InputHook = wait_for_stdin;
289-
290- WindowServerConnectionManager* connectionManager = [WindowServerConnectionManager sharedManager ];
291- NSWorkspace * workspace = [NSWorkspace sharedWorkspace ];
292- NSNotificationCenter * notificationCenter = [workspace notificationCenter ];
293- [notificationCenter addObserver: connectionManager
294- selector: @selector (launch: )
295- name: NSWorkspaceDidLaunchApplicationNotification
296- object: nil ];
297149}
298150
299151static PyObject*
@@ -327,7 +179,7 @@ static void lazy_init(void) {
327179 [NSApp stop: nil ];
328180 // Post an event to trigger the actual stopping.
329181 [NSApp postEvent: [NSEvent otherEventWithType: NSEventTypeApplicationDefined
330- location: NSMakePoint ( 0 , 0 )
182+ location: NSZeroPoint
331183 modifierFlags: 0
332184 timestamp: 0
333185 windowNumber: 0
@@ -542,40 +394,6 @@ int mpl_check_modifier(
542394 return NULL ;
543395 }
544396
545- int error;
546- int interrupted = 0 ;
547- int channel[2 ];
548- CFSocketRef sigint_socket = NULL ;
549- PyOS_sighandler_t py_sigint_handler = NULL ;
550-
551- CFRunLoopRef runloop = CFRunLoopGetCurrent ();
552-
553- error = pipe (channel);
554- if (!error) {
555- CFSocketContext context = {0 , NULL , NULL , NULL , NULL };
556- fcntl (channel[1 ], F_SETFL , O_WRONLY | O_NONBLOCK );
557-
558- context.info = &interrupted;
559- sigint_socket = CFSocketCreateWithNative (kCFAllocatorDefault ,
560- channel[0 ],
561- kCFSocketReadCallBack ,
562- _sigint_callback,
563- &context);
564- if (sigint_socket) {
565- CFRunLoopSourceRef source = CFSocketCreateRunLoopSource (
566- kCFAllocatorDefault , sigint_socket, 0 );
567- CFRelease (sigint_socket);
568- if (source) {
569- CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode );
570- CFRelease (source);
571- sigint_fd = channel[1 ];
572- py_sigint_handler = PyOS_setsig (SIGINT , _sigint_handler);
573- }
574- }
575- else
576- close (channel[0 ]);
577- }
578-
579397 NSDate * date =
580398 (timeout > 0.0 ) ? [NSDate dateWithTimeIntervalSinceNow: timeout]
581399 : [NSDate distantFuture ];
@@ -588,11 +406,6 @@ int mpl_check_modifier(
588406 [NSApp sendEvent: event];
589407 }
590408
591- if (py_sigint_handler) { PyOS_setsig (SIGINT , py_sigint_handler); }
592- if (sigint_socket) { CFSocketInvalidate (sigint_socket); }
593- if (!error) { close (channel[1 ]); }
594- if (interrupted) { raise (SIGINT ); }
595-
596409 Py_RETURN_NONE;
597410}
598411
@@ -1207,34 +1020,6 @@ - (id)autorelease
12071020 return self;
12081021}
12091022
1210- - (void )launch : (NSNotification *)notification
1211- {
1212- CFRunLoopRef runloop;
1213- CFMachPortRef port;
1214- CFRunLoopSourceRef source;
1215- NSDictionary * dictionary = [notification userInfo ];
1216- if (![[dictionary valueForKey: @" NSApplicationName" ]
1217- localizedCaseInsensitiveContainsString: @" python" ])
1218- return ;
1219- NSNumber * psnLow = [dictionary valueForKey: @" NSApplicationProcessSerialNumberLow" ];
1220- NSNumber * psnHigh = [dictionary valueForKey: @" NSApplicationProcessSerialNumberHigh" ];
1221- ProcessSerialNumber psn;
1222- psn.highLongOfPSN = [psnHigh intValue ];
1223- psn.lowLongOfPSN = [psnLow intValue ];
1224- runloop = CFRunLoopGetCurrent ();
1225- port = CGEventTapCreateForPSN (&psn,
1226- kCGHeadInsertEventTap ,
1227- kCGEventTapOptionListenOnly ,
1228- kCGEventMaskForAllEvents ,
1229- &_eventtap_callback,
1230- runloop);
1231- source = CFMachPortCreateRunLoopSource (kCFAllocatorDefault ,
1232- port,
1233- 0 );
1234- CFRunLoopAddSource (runloop, source, kCFRunLoopDefaultMode );
1235- CFRelease (port);
1236- }
1237-
12381023- (void )receivedData : (NSNotification *)notification
12391024{
12401025 PyGILState_STATE gstate = PyGILState_Ensure ();
0 commit comments