diff --git a/lib/matplotlib/backend_bases.py b/lib/matplotlib/backend_bases.py index 527d8c010710..626852f2aa34 100644 --- a/lib/matplotlib/backend_bases.py +++ b/lib/matplotlib/backend_bases.py @@ -1619,7 +1619,8 @@ def _allow_interrupt(prepare_notifier, handle_sigint): If SIGINT was indeed caught, after exiting the on_signal() function the interpreter reacts to the signal according to the handler function which had been set up by a signal.signal() call; here, we arrange to call the - backend-specific *handle_sigint* function. Finally, we call the old SIGINT + backend-specific *handle_sigint* function, passing the notifier object + as returned by prepare_notifier(). Finally, we call the old SIGINT handler with the same arguments that were given to our custom handler. We do this only if the old handler for SIGINT was not None, which means @@ -1629,7 +1630,7 @@ def _allow_interrupt(prepare_notifier, handle_sigint): Parameters ---------- prepare_notifier : Callable[[socket.socket], object] - handle_sigint : Callable[[], object] + handle_sigint : Callable[[object], object] """ old_sigint_handler = signal.getsignal(signal.SIGINT) @@ -1645,9 +1646,10 @@ def _allow_interrupt(prepare_notifier, handle_sigint): notifier = prepare_notifier(rsock) def save_args_and_handle_sigint(*args): - nonlocal handler_args + nonlocal handler_args, notifier handler_args = args - handle_sigint() + handle_sigint(notifier) + notifier = None signal.signal(signal.SIGINT, save_args_and_handle_sigint) try: diff --git a/lib/matplotlib/backends/backend_qt.py b/lib/matplotlib/backends/backend_qt.py index 5cde4866cad7..9089e982cea6 100644 --- a/lib/matplotlib/backends/backend_qt.py +++ b/lib/matplotlib/backends/backend_qt.py @@ -169,9 +169,14 @@ def _may_clear_sock(): # be forgiving about reading an empty socket. pass - return sn # Actually keep the notifier alive. - - def handle_sigint(): + # We return the QSocketNotifier so that the caller holds a reference, and we + # also explicitly clean it up in handle_sigint(). Without doing both, deletion + # of the socket notifier can happen prematurely or not at all. + return sn + + def handle_sigint(sn): + sn.deleteLater() + QtCore.QCoreApplication.sendPostedEvents(sn, QtCore.QEvent.Type.DeferredDelete) if hasattr(qapp_or_eventloop, 'closeAllWindows'): qapp_or_eventloop.closeAllWindows() qapp_or_eventloop.quit() diff --git a/src/_macosx.m b/src/_macosx.m index aa2a6e68cda5..1372157bc80d 100755 --- a/src/_macosx.m +++ b/src/_macosx.m @@ -258,7 +258,7 @@ static void lazy_init(void) { } static PyObject* -stop(PyObject* self) +stop(PyObject* self, PyObject* _ /* ignored */) { stopWithEvent(); Py_RETURN_NONE; @@ -1863,7 +1863,7 @@ - (void)flagsChanged:(NSEvent *)event "written on the file descriptor given as argument.")}, {"stop", (PyCFunction)stop, - METH_NOARGS, + METH_VARARGS, PyDoc_STR("Stop the NSApp.")}, {"show", (PyCFunction)show,