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
4842/* Keep track of the current mouse up/down state for open/closed cursor hand*/
4943static bool leftMouseGrabbing =false ;
5044
51- /* -------------------------- Helper function ----------------------------*/
52-
53- static void
54- _stdin_callback (CFReadStreamRef stream, CFStreamEventType eventType,void * info)
55- {
56- CFRunLoopRef runloop = info;
57- CFRunLoopStop (runloop);
58- }
59-
60- static int sigint_fd = -1 ;
61-
62- static void _sigint_handler (int sig)
63- {
64- const char c =' i' ;
65- write (sigint_fd, &c,1 );
66- }
67-
68- static void _sigint_callback (CFSocketRef s,
69- CFSocketCallBackType type,
70- CFDataRef address,
71- const void * data,
72- void *info)
73- {
74- char c;
75- int * interrupted = info;
76- CFSocketNativeHandle handle =CFSocketGetNative (s);
77- CFRunLoopRef runloop =CFRunLoopGetCurrent ();
78- read (handle, &c,1 );
79- *interrupted =1 ;
80- CFRunLoopStop (runloop);
81- }
82-
83- static CGEventRef_eventtap_callback (
84- CGEventTapProxy proxy, CGEventType type, CGEventRef event,void *refcon)
85- {
86- CFRunLoopRef runloop = refcon;
87- CFRunLoopStop (runloop);
88- return event;
89- }
90-
91- static int wait_for_stdin (void )
92- {
93- int interrupted =0 ;
94- const UInt8 buffer[] =" /dev/fd/0" ;
95- const CFIndex n = (CFIndex)strlen ((char *)buffer);
96- CFRunLoopRef runloop =CFRunLoopGetCurrent ();
97- CFURLRef url =CFURLCreateFromFileSystemRepresentation (kCFAllocatorDefault ,
98- buffer,
99- n,
100- false );
101- CFReadStreamRef stream =CFReadStreamCreateWithFile (kCFAllocatorDefault ,
102- url);
103- CFRelease (url);
104-
105- CFReadStreamOpen (stream);
106- #ifdef PYOSINPUTHOOK_REPETITIVE
107- if (!CFReadStreamHasBytesAvailable (stream))
108- /* This is possible because of how PyOS_InputHook is called from Python*/
109- #endif
110- {
111- int error;
112- int channel[2 ];
113- CFSocketRef sigint_socket =NULL ;
114- PyOS_sighandler_t py_sigint_handler =NULL ;
115- CFStreamClientContext clientContext = {0 ,NULL ,NULL ,NULL ,NULL };
116- clientContext.info = runloop;
117- CFReadStreamSetClient (stream,
118- kCFStreamEventHasBytesAvailable ,
119- _stdin_callback,
120- &clientContext);
121- CFReadStreamScheduleWithRunLoop (stream, runloop,kCFRunLoopDefaultMode );
122- error =socketpair (AF_UNIX, SOCK_STREAM,0 , channel);
123- if (!error) {
124- CFSocketContext context;
125- context.version =0 ;
126- context.info = &interrupted;
127- context.retain =NULL ;
128- context.release =NULL ;
129- context.copyDescription =NULL ;
130- fcntl (channel[0 ], F_SETFL, O_WRONLY | O_NONBLOCK);
131- sigint_socket =CFSocketCreateWithNative (
132- kCFAllocatorDefault ,
133- channel[1 ],
134- kCFSocketReadCallBack ,
135- _sigint_callback,
136- &context);
137- if (sigint_socket) {
138- CFRunLoopSourceRef source =CFSocketCreateRunLoopSource (
139- kCFAllocatorDefault , sigint_socket,0 );
140- CFRelease (sigint_socket);
141- if (source) {
142- CFRunLoopAddSource (runloop, source,kCFRunLoopDefaultMode );
143- CFRelease (source);
144- sigint_fd = channel[0 ];
145- py_sigint_handler =PyOS_setsig (SIGINT, _sigint_handler);
146- }
147- }
148- }
149-
150- NSEvent * event;
151- while (true ) {
152- while (true ) {
153- event = [NSApp nextEventMatchingMask: NSEventMaskAny
154- untilDate: [NSDate distantPast ]
155- inMode: NSDefaultRunLoopMode
156- dequeue: YES ];
157- if (!event) {break ; }
158- [NSApp sendEvent: event];
159- }
160- CFRunLoopRun ();
161- if (interrupted ||CFReadStreamHasBytesAvailable (stream)) {break ; }
162- }
163-
164- if (py_sigint_handler) {PyOS_setsig (SIGINT, py_sigint_handler); }
165- CFReadStreamUnscheduleFromRunLoop (
166- stream, runloop,kCFRunLoopCommonModes );
167- if (sigint_socket) {CFSocketInvalidate (sigint_socket); }
168- if (!error) {
169- close (channel[0 ]);
170- close (channel[1 ]);
171- }
172- }
173- CFReadStreamClose (stream);
174- CFRelease (stream);
175- if (interrupted) {
176- errno = EINTR;
177- raise (SIGINT);
178- return -1 ;
179- }
180- return 1 ;
181- }
182-
18345/* ---------------------------- Cocoa classes ----------------------------*/
18446
185- @interface WindowServerConnectionManager :NSObject
186- {
187- }
188- + (WindowServerConnectionManager*)sharedManager ;
189- - (void )launch : (NSNotification *)notification ;
190- @end
191-
19247@interface Window :NSWindow
19348{ PyObject* manager;
19449}
@@ -284,15 +139,6 @@ static void lazy_init(void) {
284139NSApp = [NSApplication sharedApplication ];
285140 [NSApp setActivationPolicy: NSApplicationActivationPolicyRegular];
286141
287- PyOS_InputHook = wait_for_stdin;
288-
289- WindowServerConnectionManager* connectionManager = [WindowServerConnectionManagersharedManager ];
290- NSWorkspace * workspace = [NSWorkspace sharedWorkspace ];
291- NSNotificationCenter * notificationCenter = [workspacenotificationCenter ];
292- [notificationCenteraddObserver: connectionManager
293- selector: @selector (launch: )
294- name: NSWorkspaceDidLaunchApplicationNotification
295- object: nil ];
296142}
297143
298144static PyObject*
@@ -551,40 +397,6 @@ int mpl_check_modifier(
551397return NULL ;
552398 }
553399
554- int error;
555- int interrupted =0 ;
556- int channel[2 ];
557- CFSocketRef sigint_socket =NULL ;
558- PyOS_sighandler_t py_sigint_handler =NULL ;
559-
560- CFRunLoopRef runloop =CFRunLoopGetCurrent ();
561-
562- error =pipe (channel);
563- if (!error) {
564- CFSocketContext context = {0 ,NULL ,NULL ,NULL ,NULL };
565- fcntl (channel[1 ], F_SETFL, O_WRONLY | O_NONBLOCK);
566-
567- context.info = &interrupted;
568- sigint_socket =CFSocketCreateWithNative (kCFAllocatorDefault ,
569- channel[0 ],
570- kCFSocketReadCallBack ,
571- _sigint_callback,
572- &context);
573- if (sigint_socket) {
574- CFRunLoopSourceRef source =CFSocketCreateRunLoopSource (
575- kCFAllocatorDefault , sigint_socket,0 );
576- CFRelease (sigint_socket);
577- if (source) {
578- CFRunLoopAddSource (runloop, source,kCFRunLoopDefaultMode );
579- CFRelease (source);
580- sigint_fd = channel[1 ];
581- py_sigint_handler =PyOS_setsig (SIGINT, _sigint_handler);
582- }
583- }
584- else
585- close (channel[0 ]);
586- }
587-
588400NSDate * date =
589401 (timeout >0.0 ) ? [NSDate dateWithTimeIntervalSinceNow: timeout]
590402 : [NSDate distantFuture ];
@@ -597,11 +409,6 @@ int mpl_check_modifier(
597409 [NSApp sendEvent: event];
598410 }
599411
600- if (py_sigint_handler) {PyOS_setsig (SIGINT, py_sigint_handler); }
601- if (sigint_socket) {CFSocketInvalidate (sigint_socket); }
602- if (!error) {close (channel[1 ]); }
603- if (interrupted) {raise (SIGINT); }
604-
605412 Py_RETURN_NONE;
606413}
607414
@@ -1175,76 +982,6 @@ -(void)save_figure:(id)sender { gil_call_method(toolbar, "save_figure"); }
1175982 Py_RETURN_NONE;
1176983}
1177984
1178- @implementation WindowServerConnectionManager
1179- static WindowServerConnectionManager *sharedWindowServerConnectionManager =nil ;
1180-
1181- + (WindowServerConnectionManager *)sharedManager
1182- {
1183- if (sharedWindowServerConnectionManager ==nil ) {
1184- sharedWindowServerConnectionManager = [[super allocWithZone: NULL ]init ];
1185- }
1186- return sharedWindowServerConnectionManager;
1187- }
1188-
1189- + (id )allocWithZone : (NSZone *)zone
1190- {
1191- return [[self sharedManager ]retain ];
1192- }
1193-
1194- + (id )copyWithZone : (NSZone *)zone
1195- {
1196- return self;
1197- }
1198-
1199- + (id )retain
1200- {
1201- return self;
1202- }
1203-
1204- - (NSUInteger )retainCount
1205- {
1206- return NSUIntegerMax;// denotes an object that cannot be released
1207- }
1208-
1209- - (oneway void )release
1210- {
1211- // Don't release a singleton object
1212- }
1213-
1214- - (id )autorelease
1215- {
1216- return self;
1217- }
1218-
1219- - (void )launch : (NSNotification *)notification
1220- {
1221- CFRunLoopRef runloop;
1222- CFMachPortRef port;
1223- CFRunLoopSourceRef source;
1224- NSDictionary * dictionary = [notificationuserInfo ];
1225- if (![[dictionaryvalueForKey: @" NSApplicationName" ]
1226- localizedCaseInsensitiveContainsString: @" python" ])
1227- return ;
1228- NSNumber * psnLow = [dictionaryvalueForKey: @" NSApplicationProcessSerialNumberLow" ];
1229- NSNumber * psnHigh = [dictionaryvalueForKey: @" NSApplicationProcessSerialNumberHigh" ];
1230- ProcessSerialNumber psn;
1231- psn.highLongOfPSN = [psnHighintValue ];
1232- psn.lowLongOfPSN = [psnLowintValue ];
1233- runloop =CFRunLoopGetCurrent ();
1234- port =CGEventTapCreateForPSN (&psn,
1235- kCGHeadInsertEventTap ,
1236- kCGEventTapOptionListenOnly ,
1237- kCGEventMaskForAllEvents ,
1238- &_eventtap_callback,
1239- runloop);
1240- source =CFMachPortCreateRunLoopSource (kCFAllocatorDefault ,
1241- port,
1242- 0 );
1243- CFRunLoopAddSource (runloop, source,kCFRunLoopDefaultMode );
1244- CFRelease (port);
1245- }
1246- @end
1247-
1248985@implementation Window
1249986- (Window*)initWithContentRect : (NSRect )rect styleMask : (unsigned int )mask backing : (NSBackingStoreType )bufferingType defer : (BOOL )deferCreation withManager : (PyObject*)theManager
1250987{