Skip to content

Commit 18909c7

Browse files
committed
Rework stdin handling on macos objective C
1 parent b1822cf commit 18909c7

File tree

1 file changed

+21
-43
lines changed

1 file changed

+21
-43
lines changed

src/_macosx.m

Lines changed: 21 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -40,22 +40,32 @@
4040
static bool keyChangeCapsLock = false;
4141
/* Keep track of the current mouse up/down state for open/closed cursor hand */
4242
static bool leftMouseGrabbing = false;
43-
/* Keep track of whether stdin has been received */
44-
static bool stdin_received = false;
45-
static bool stdin_sigint = false;
4643
// Global variable to store the original SIGINT handler
4744
static PyOS_sighandler_t originalSigintAction = NULL;
4845

46+
// Stop the current app's run loop, sending an event to ensure it actually stops
47+
static void stop_with_event() {
48+
[NSApp stop: nil];
49+
// Post an event to trigger the actual stopping.
50+
[NSApp postEvent: [NSEvent otherEventWithType: NSEventTypeApplicationDefined
51+
location: NSZeroPoint
52+
modifierFlags: 0
53+
timestamp: 0
54+
windowNumber: 0
55+
context: nil
56+
subtype: 0
57+
data1: 0
58+
data2: 0]
59+
atStart: YES];
60+
}
61+
4962
// Signal handler for SIGINT, only sets a flag to exit the run loop
5063
static void handleSigint(int signal) {
51-
stdin_sigint = true;
64+
stop_with_event();
5265
}
5366

5467
static int wait_for_stdin() {
5568
@autoreleasepool {
56-
stdin_received = false;
57-
stdin_sigint = false;
58-
5969
// Set up a SIGINT handler to interrupt the event loop if ctrl+c comes in too
6070
originalSigintAction = PyOS_setsig(SIGINT, handleSigint);
6171

@@ -66,33 +76,14 @@ static int wait_for_stdin() {
6676
[[NSNotificationCenter defaultCenter] addObserverForName: NSFileHandleDataAvailableNotification
6777
object: stdinHandle
6878
queue: [NSOperationQueue mainQueue] // Use the main queue
69-
usingBlock: ^(NSNotification *notification) {
70-
// Mark that input has been received
71-
stdin_received = true;
72-
}
79+
usingBlock: ^(NSNotification *notification) {stop_with_event();}
7380
];
7481

7582
// Wait in the background for anything that happens to stdin
7683
[stdinHandle waitForDataInBackgroundAndNotify];
7784

78-
// continuously run an event loop until the stdin_received flag is set to exit
79-
while (!stdin_received && !stdin_sigint) {
80-
// This loop is similar to the main event loop and flush_events which have
81-
// Py_[BEGIN|END]_ALLOW_THREADS surrounding the loop.
82-
// This should not be necessary here because PyOS_InputHook releases the GIL for us.
83-
while (true) {
84-
NSEvent *event = [NSApp nextEventMatchingMask: NSEventMaskAny
85-
untilDate: [NSDate distantPast]
86-
inMode: NSDefaultRunLoopMode
87-
dequeue: YES];
88-
if (!event) { break; }
89-
[NSApp sendEvent: event];
90-
}
91-
// We need to run the run loop for a short time to allow the
92-
// events to be processed and keep flushing them while we wait for stdin
93-
// without this, the CPU usage will be very high constantly polling this loop
94-
[[NSRunLoop currentRunLoop] runUntilDate: [NSDate dateWithTimeIntervalSinceNow: 0.01]];
95-
}
85+
[NSApp run];
86+
9687
// Remove the input handler as an observer
9788
[[NSNotificationCenter defaultCenter] removeObserver: stdinHandle];
9889

@@ -240,20 +231,7 @@ static void lazy_init(void) {
240231
static PyObject*
241232
stop(PyObject* self)
242233
{
243-
// Remove our input hook and stop the event loop.
244-
PyOS_InputHook = NULL;
245-
[NSApp stop: nil];
246-
// Post an event to trigger the actual stopping.
247-
[NSApp postEvent: [NSEvent otherEventWithType: NSEventTypeApplicationDefined
248-
location: NSZeroPoint
249-
modifierFlags: 0
250-
timestamp: 0
251-
windowNumber: 0
252-
context: nil
253-
subtype: 0
254-
data1: 0
255-
data2: 0]
256-
atStart: YES];
234+
stop_with_event();
257235
Py_RETURN_NONE;
258236
}
259237

0 commit comments

Comments
 (0)