Skip to content
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
macosx: Cleaning up old sigint handling from objc
  • Loading branch information
greglucas authored and anntzer committed Aug 7, 2023
commit ec6717aa7ad66868a3dc6186af031b970bb21c8e
263 changes: 0 additions & 263 deletions src/_macosx.m
Original file line number Diff line number Diff line change
@@ -1,15 +1,9 @@
#define PY_SSIZE_T_CLEAN
#include <Cocoa/Cocoa.h>
#include <ApplicationServices/ApplicationServices.h>
#include <sys/socket.h>
#include <Python.h>
#include "mplutils.h"

#ifndef PYPY
/* Remove this once Python is fixed: https://bugs.python.org/issue23237 */
#define PYOSINPUTHOOK_REPETITIVE 1
#endif

/* Proper way to check for the OS X version we are compiling for, from
* https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/cross_development/Using/using.html

Expand Down Expand Up @@ -48,147 +42,8 @@
/* Keep track of the current mouse up/down state for open/closed cursor hand */
static bool leftMouseGrabbing = false;

/* -------------------------- Helper function ---------------------------- */

static void
_stdin_callback(CFReadStreamRef stream, CFStreamEventType eventType, void* info)
{
CFRunLoopRef runloop = info;
CFRunLoopStop(runloop);
}

static int sigint_fd = -1;

static void _sigint_handler(int sig)
{
const char c = 'i';
write(sigint_fd, &c, 1);
}

static void _sigint_callback(CFSocketRef s,
CFSocketCallBackType type,
CFDataRef address,
const void * data,
void *info)
{
char c;
int* interrupted = info;
CFSocketNativeHandle handle = CFSocketGetNative(s);
CFRunLoopRef runloop = CFRunLoopGetCurrent();
read(handle, &c, 1);
*interrupted = 1;
CFRunLoopStop(runloop);
}

static CGEventRef _eventtap_callback(
CGEventTapProxy proxy, CGEventType type, CGEventRef event, void *refcon)
{
CFRunLoopRef runloop = refcon;
CFRunLoopStop(runloop);
return event;
}

static int wait_for_stdin(void)
{
int interrupted = 0;
const UInt8 buffer[] = "/dev/fd/0";
const CFIndex n = (CFIndex)strlen((char*)buffer);
CFRunLoopRef runloop = CFRunLoopGetCurrent();
CFURLRef url = CFURLCreateFromFileSystemRepresentation(kCFAllocatorDefault,
buffer,
n,
false);
CFReadStreamRef stream = CFReadStreamCreateWithFile(kCFAllocatorDefault,
url);
CFRelease(url);

CFReadStreamOpen(stream);
#ifdef PYOSINPUTHOOK_REPETITIVE
if (!CFReadStreamHasBytesAvailable(stream))
/* This is possible because of how PyOS_InputHook is called from Python */
#endif
{
int error;
int channel[2];
CFSocketRef sigint_socket = NULL;
PyOS_sighandler_t py_sigint_handler = NULL;
CFStreamClientContext clientContext = {0, NULL, NULL, NULL, NULL};
clientContext.info = runloop;
CFReadStreamSetClient(stream,
kCFStreamEventHasBytesAvailable,
_stdin_callback,
&clientContext);
CFReadStreamScheduleWithRunLoop(stream, runloop, kCFRunLoopDefaultMode);
error = socketpair(AF_UNIX, SOCK_STREAM, 0, channel);
if (!error) {
CFSocketContext context;
context.version = 0;
context.info = &interrupted;
context.retain = NULL;
context.release = NULL;
context.copyDescription = NULL;
fcntl(channel[0], F_SETFL, O_WRONLY | O_NONBLOCK);
sigint_socket = CFSocketCreateWithNative(
kCFAllocatorDefault,
channel[1],
kCFSocketReadCallBack,
_sigint_callback,
&context);
if (sigint_socket) {
CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(
kCFAllocatorDefault, sigint_socket, 0);
CFRelease(sigint_socket);
if (source) {
CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
CFRelease(source);
sigint_fd = channel[0];
py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler);
}
}
}

NSEvent* event;
while (true) {
while (true) {
event = [NSApp nextEventMatchingMask: NSEventMaskAny
untilDate: [NSDate distantPast]
inMode: NSDefaultRunLoopMode
dequeue: YES];
if (!event) { break; }
[NSApp sendEvent: event];
}
CFRunLoopRun();
if (interrupted || CFReadStreamHasBytesAvailable(stream)) { break; }
}

if (py_sigint_handler) { PyOS_setsig(SIGINT, py_sigint_handler); }
CFReadStreamUnscheduleFromRunLoop(
stream, runloop, kCFRunLoopCommonModes);
if (sigint_socket) { CFSocketInvalidate(sigint_socket); }
if (!error) {
close(channel[0]);
close(channel[1]);
}
}
CFReadStreamClose(stream);
CFRelease(stream);
if (interrupted) {
errno = EINTR;
raise(SIGINT);
return -1;
}
return 1;
}

/* ---------------------------- Cocoa classes ---------------------------- */

@interface WindowServerConnectionManager : NSObject
{
}
+ (WindowServerConnectionManager*)sharedManager;
- (void)launch:(NSNotification*)notification;
@end

@interface Window : NSWindow
{ PyObject* manager;
}
Expand Down Expand Up @@ -284,15 +139,6 @@ static void lazy_init(void) {
NSApp = [NSApplication sharedApplication];
[NSApp setActivationPolicy:NSApplicationActivationPolicyRegular];

PyOS_InputHook = wait_for_stdin;

WindowServerConnectionManager* connectionManager = [WindowServerConnectionManager sharedManager];
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
NSNotificationCenter* notificationCenter = [workspace notificationCenter];
[notificationCenter addObserver: connectionManager
selector: @selector(launch:)
name: NSWorkspaceDidLaunchApplicationNotification
object: nil];
}

static PyObject*
Expand Down Expand Up @@ -551,40 +397,6 @@ int mpl_check_modifier(
return NULL;
}

int error;
int interrupted = 0;
int channel[2];
CFSocketRef sigint_socket = NULL;
PyOS_sighandler_t py_sigint_handler = NULL;

CFRunLoopRef runloop = CFRunLoopGetCurrent();

error = pipe(channel);
if (!error) {
CFSocketContext context = {0, NULL, NULL, NULL, NULL};
fcntl(channel[1], F_SETFL, O_WRONLY | O_NONBLOCK);

context.info = &interrupted;
sigint_socket = CFSocketCreateWithNative(kCFAllocatorDefault,
channel[0],
kCFSocketReadCallBack,
_sigint_callback,
&context);
if (sigint_socket) {
CFRunLoopSourceRef source = CFSocketCreateRunLoopSource(
kCFAllocatorDefault, sigint_socket, 0);
CFRelease(sigint_socket);
if (source) {
CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
CFRelease(source);
sigint_fd = channel[1];
py_sigint_handler = PyOS_setsig(SIGINT, _sigint_handler);
}
}
else
close(channel[0]);
}

NSDate* date =
(timeout > 0.0) ? [NSDate dateWithTimeIntervalSinceNow: timeout]
: [NSDate distantFuture];
Expand All @@ -597,11 +409,6 @@ int mpl_check_modifier(
[NSApp sendEvent: event];
}

if (py_sigint_handler) { PyOS_setsig(SIGINT, py_sigint_handler); }
if (sigint_socket) { CFSocketInvalidate(sigint_socket); }
if (!error) { close(channel[1]); }
if (interrupted) { raise(SIGINT); }

Py_RETURN_NONE;
}

Expand Down Expand Up @@ -1198,76 +1005,6 @@ -(void)save_figure:(id)sender { gil_call_method(toolbar, "save_figure"); }
Py_RETURN_NONE;
}

@implementation WindowServerConnectionManager
static WindowServerConnectionManager *sharedWindowServerConnectionManager = nil;

+ (WindowServerConnectionManager *)sharedManager
{
if (sharedWindowServerConnectionManager == nil) {
sharedWindowServerConnectionManager = [[super allocWithZone:NULL] init];
}
return sharedWindowServerConnectionManager;
}

+ (id)allocWithZone:(NSZone *)zone
{
return [[self sharedManager] retain];
}

+ (id)copyWithZone:(NSZone *)zone
{
return self;
}

+ (id)retain
{
return self;
}

- (NSUInteger)retainCount
{
return NSUIntegerMax; //denotes an object that cannot be released
}

- (oneway void)release
{
// Don't release a singleton object
}

- (id)autorelease
{
return self;
}

- (void)launch:(NSNotification*)notification
{
CFRunLoopRef runloop;
CFMachPortRef port;
CFRunLoopSourceRef source;
NSDictionary* dictionary = [notification userInfo];
if (![[dictionary valueForKey:@"NSApplicationName"]
localizedCaseInsensitiveContainsString:@"python"])
return;
NSNumber* psnLow = [dictionary valueForKey: @"NSApplicationProcessSerialNumberLow"];
NSNumber* psnHigh = [dictionary valueForKey: @"NSApplicationProcessSerialNumberHigh"];
ProcessSerialNumber psn;
psn.highLongOfPSN = [psnHigh intValue];
psn.lowLongOfPSN = [psnLow intValue];
runloop = CFRunLoopGetCurrent();
port = CGEventTapCreateForPSN(&psn,
kCGHeadInsertEventTap,
kCGEventTapOptionListenOnly,
kCGEventMaskForAllEvents,
&_eventtap_callback,
runloop);
source = CFMachPortCreateRunLoopSource(kCFAllocatorDefault,
port,
0);
CFRunLoopAddSource(runloop, source, kCFRunLoopDefaultMode);
CFRelease(port);
}
@end

@implementation Window
- (Window*)initWithContentRect:(NSRect)rect styleMask:(unsigned int)mask backing:(NSBackingStoreType)bufferingType defer:(BOOL)deferCreation withManager: (PyObject*)theManager
{
Expand Down