|
@@ -1,3 +1,4 @@
|
|
|
+import contextlib
|
|
|
import os
|
|
|
import signal
|
|
|
import socket
|
|
@@ -106,6 +107,13 @@ class FigureCanvasMac(FigureCanvasAgg, _macosx.FigureCanvas, FigureCanvasBase):
|
|
|
ResizeEvent("resize_event", self)._process()
|
|
|
self.draw_idle()
|
|
|
|
|
|
+ def start_event_loop(self, timeout=0):
|
|
|
+ # docstring inherited
|
|
|
+ with _maybe_allow_interrupt():
|
|
|
+ # Call the objc implementation of the event loop after
|
|
|
+ # setting up the interrupt handling
|
|
|
+ self._start_event_loop(timeout=timeout)
|
|
|
+
|
|
|
|
|
|
class NavigationToolbar2Mac(_macosx.NavigationToolbar2, NavigationToolbar2):
|
|
|
|
|
@@ -147,7 +155,7 @@ class FigureManagerMac(_macosx.FigureManager, FigureManagerBase):
|
|
|
icon_path = str(cbook._get_data_path('images/matplotlib.pdf'))
|
|
|
_macosx.FigureManager.set_icon(icon_path)
|
|
|
FigureManagerBase.__init__(self, canvas, num)
|
|
|
- self._set_window_mode(mpl.rcParams.get("macosx.window_mode", "system"))
|
|
|
+ self._set_window_mode(mpl.rcParams["macosx.window_mode"])
|
|
|
if self.toolbar is not None:
|
|
|
self.toolbar.update()
|
|
|
if mpl.is_interactive():
|
|
@@ -171,34 +179,8 @@ class FigureManagerMac(_macosx.FigureManager, FigureManagerBase):
|
|
|
# Set up a SIGINT handler to allow terminating a plot via CTRL-C.
|
|
|
# The logic is largely copied from qt_compat._maybe_allow_interrupt; see its
|
|
|
# docstring for details. Parts are implemented by wake_on_fd_write in ObjC.
|
|
|
-
|
|
|
- old_sigint_handler = signal.getsignal(signal.SIGINT)
|
|
|
- if old_sigint_handler in (None, signal.SIG_IGN, signal.SIG_DFL):
|
|
|
- _macosx.show()
|
|
|
- return
|
|
|
-
|
|
|
- handler_args = None
|
|
|
- wsock, rsock = socket.socketpair()
|
|
|
- wsock.setblocking(False)
|
|
|
- rsock.setblocking(False)
|
|
|
- old_wakeup_fd = signal.set_wakeup_fd(wsock.fileno())
|
|
|
- _macosx.wake_on_fd_write(rsock.fileno())
|
|
|
-
|
|
|
- def handle(*args):
|
|
|
- nonlocal handler_args
|
|
|
- handler_args = args
|
|
|
- _macosx.stop()
|
|
|
-
|
|
|
- signal.signal(signal.SIGINT, handle)
|
|
|
- try:
|
|
|
+ with _maybe_allow_interrupt():
|
|
|
_macosx.show()
|
|
|
- finally:
|
|
|
- wsock.close()
|
|
|
- rsock.close()
|
|
|
- signal.set_wakeup_fd(old_wakeup_fd)
|
|
|
- signal.signal(signal.SIGINT, old_sigint_handler)
|
|
|
- if handler_args is not None:
|
|
|
- old_sigint_handler(*handler_args)
|
|
|
|
|
|
def show(self):
|
|
|
if not self._shown:
|
|
@@ -208,6 +190,45 @@ class FigureManagerMac(_macosx.FigureManager, FigureManagerBase):
|
|
|
self._raise()
|
|
|
|
|
|
|
|
|
+@contextlib.contextmanager
|
|
|
+def _maybe_allow_interrupt():
|
|
|
+ """
|
|
|
+ This manager allows to terminate a plot by sending a SIGINT. It is
|
|
|
+ necessary because the running backend prevents Python interpreter to
|
|
|
+ run and process signals (i.e., to raise KeyboardInterrupt exception). To
|
|
|
+ solve this one needs to somehow wake up the interpreter and make it close
|
|
|
+ the plot window. The implementation is taken from qt_compat, see that
|
|
|
+ docstring for a more detailed description.
|
|
|
+ """
|
|
|
+ old_sigint_handler = signal.getsignal(signal.SIGINT)
|
|
|
+ if old_sigint_handler in (None, signal.SIG_IGN, signal.SIG_DFL):
|
|
|
+ yield
|
|
|
+ return
|
|
|
+
|
|
|
+ handler_args = None
|
|
|
+ wsock, rsock = socket.socketpair()
|
|
|
+ wsock.setblocking(False)
|
|
|
+ rsock.setblocking(False)
|
|
|
+ old_wakeup_fd = signal.set_wakeup_fd(wsock.fileno())
|
|
|
+ _macosx.wake_on_fd_write(rsock.fileno())
|
|
|
+
|
|
|
+ def handle(*args):
|
|
|
+ nonlocal handler_args
|
|
|
+ handler_args = args
|
|
|
+ _macosx.stop()
|
|
|
+
|
|
|
+ signal.signal(signal.SIGINT, handle)
|
|
|
+ try:
|
|
|
+ yield
|
|
|
+ finally:
|
|
|
+ wsock.close()
|
|
|
+ rsock.close()
|
|
|
+ signal.set_wakeup_fd(old_wakeup_fd)
|
|
|
+ signal.signal(signal.SIGINT, old_sigint_handler)
|
|
|
+ if handler_args is not None:
|
|
|
+ old_sigint_handler(*handler_args)
|
|
|
+
|
|
|
+
|
|
|
@_Backend.export
|
|
|
class _BackendMac(_Backend):
|
|
|
FigureCanvas = FigureCanvasMac
|