@@ -59,21 +59,47 @@ static void stop_with_event() {
59
59
atStart: YES ];
60
60
}
61
61
62
- // Signal handler for SIGINT, only sets a flag to exit the run loop
62
+ // Signal handler for SIGINT, only argument matching for stop_with_event
63
63
static void handleSigint (int signal) {
64
- stop_with_event ();
64
+ stop_with_event ();
65
+ }
66
+
67
+ // Helper function to flush all events.
68
+ // This is needed in some instances to ensure e.g. that windows are properly closed.
69
+ // It is used in the input hook as well as wrapped in a version callable from Python.
70
+ static void flushEvents () {
71
+ while (true ) {
72
+ NSEvent * event = [NSApp nextEventMatchingMask: NSEventMaskAny
73
+ untilDate: [NSDate distantPast ]
74
+ inMode: NSDefaultRunLoopMode
75
+ dequeue: YES ];
76
+ if (!event) {
77
+ break ;
78
+ }
79
+ [NSApp sendEvent: event];
80
+ }
65
81
}
66
82
67
83
static int wait_for_stdin () {
84
+ // Short circuit if no windows are active
85
+ // Rely on Python's input handling to manage CPU usage
86
+ // This queries the NSApp, rather than using our FigureWindowCount because that is decremented when events still
87
+ // need to be processed to properly close the windows.
88
+ if (![[NSApp windows ] count ]) {
89
+ flushEvents ();
90
+ return 1 ;
91
+ }
92
+
68
93
@autoreleasepool {
69
94
// Set up a SIGINT handler to interrupt the event loop if ctrl+c comes in too
70
95
originalSigintAction = PyOS_setsig (SIGINT, handleSigint);
71
96
72
97
// Create an NSFileHandle for standard input
73
98
NSFileHandle *stdinHandle = [NSFileHandle fileHandleWithStandardInput ];
74
99
100
+
75
101
// Register for data available notifications on standard input
76
- [[NSNotificationCenter defaultCenter ] addObserverForName: NSFileHandleDataAvailableNotification
102
+ id notificationID = [[NSNotificationCenter defaultCenter ] addObserverForName: NSFileHandleDataAvailableNotification
77
103
object: stdinHandle
78
104
queue: [NSOperationQueue mainQueue ] // Use the main queue
79
105
usingBlock: ^(NSNotification *notification) {stop_with_event ();}
@@ -82,13 +108,16 @@ static int wait_for_stdin() {
82
108
// Wait in the background for anything that happens to stdin
83
109
[stdinHandle waitForDataInBackgroundAndNotify ];
84
110
111
+ // Run the application's event loop, which will be interrupted on stdin or SIGINT
85
112
[NSApp run ];
86
113
87
114
// Remove the input handler as an observer
88
- [[NSNotificationCenter defaultCenter ] removeObserver: stdinHandle];
115
+ [[NSNotificationCenter defaultCenter ] removeObserver: notificationID];
116
+
89
117
90
118
// Restore the original SIGINT handler upon exiting the function
91
119
PyOS_setsig (SIGINT, originalSigintAction);
120
+
92
121
return 1 ;
93
122
}
94
123
}
@@ -366,20 +395,9 @@ static CGFloat _get_device_scale(CGContextRef cr)
366
395
// We run the app, matching any events that are waiting in the queue
367
396
// to process, breaking out of the loop when no events remain and
368
397
// displaying the canvas if needed.
369
- NSEvent *event;
370
-
371
398
Py_BEGIN_ALLOW_THREADS
372
399
373
- while (true ) {
374
- event = [NSApp nextEventMatchingMask: NSEventMaskAny
375
- untilDate: [NSDate distantPast ]
376
- inMode: NSDefaultRunLoopMode
377
- dequeue: YES ];
378
- if (!event) {
379
- break ;
380
- }
381
- [NSApp sendEvent: event];
382
- }
400
+ flushEvents ();
383
401
384
402
Py_END_ALLOW_THREADS
385
403
@@ -1106,13 +1124,10 @@ - (void)close
1106
1124
{
1107
1125
[super close ];
1108
1126
--FigureWindowCount;
1109
- if (!FigureWindowCount) {
1110
- /* This is needed for show(), which should exit from [NSApp run]
1111
- * after all windows are closed.
1112
- */
1113
- PyObject* x = stop (NULL );
1114
- Py_DECREF (x);
1115
- }
1127
+ if (!FigureWindowCount) [NSApp stop: self ];
1128
+ /* This is needed for show(), which should exit from [NSApp run]
1129
+ * after all windows are closed.
1130
+ */
1116
1131
// For each new window, we have incremented the manager reference, so
1117
1132
// we need to bring that down during close and not just dealloc.
1118
1133
Py_DECREF (manager);
0 commit comments