diff --git a/lib/matplotlib/backends/backend_gtk3.py b/lib/matplotlib/backends/backend_gtk3.py index 1f9408b0668a..2f34248837dc 100644 --- a/lib/matplotlib/backends/backend_gtk3.py +++ b/lib/matplotlib/backends/backend_gtk3.py @@ -367,6 +367,7 @@ def add_widget(child): self.window.set_default_size(w, h) + self._destroying = False self.window.connect("destroy", lambda *args: Gcf.destroy(self)) self.window.connect("delete_event", lambda *args: Gcf.destroy(self)) if mpl.is_interactive(): @@ -376,6 +377,13 @@ def add_widget(child): self.canvas.grab_focus() def destroy(self, *args): + if self._destroying: + # Otherwise, this can be called twice when the user presses 'q', + # which calls Gcf.destroy(self), then this destroy(), then triggers + # Gcf.destroy(self) once again via + # `connect("destroy", lambda *args: Gcf.destroy(self))`. + return + self._destroying = True self.vbox.destroy() self.window.destroy() self.canvas.destroy() diff --git a/lib/matplotlib/backends/backend_wx.py b/lib/matplotlib/backends/backend_wx.py index 7adc47e0de16..b8b6034d11bd 100644 --- a/lib/matplotlib/backends/backend_wx.py +++ b/lib/matplotlib/backends/backend_wx.py @@ -1008,7 +1008,8 @@ def _onClose(self, event): self.canvas.close_event() self.canvas.stop_event_loop() Gcf.destroy(self) - # self.Destroy() + if self: + self.Destroy() def GetToolBar(self): """Override wxFrame::GetToolBar as we don't have managed toolbar""" @@ -1066,7 +1067,7 @@ def show(self): def destroy(self, *args): _log.debug("%s - destroy()", type(self)) - self.frame.Destroy() + self.frame.Close() wxapp = wx.GetApp() if wxapp: wxapp.Yield() diff --git a/lib/matplotlib/tests/test_backends_interactive.py b/lib/matplotlib/tests/test_backends_interactive.py index e53aa646484d..af8cbd2febf4 100644 --- a/lib/matplotlib/tests/test_backends_interactive.py +++ b/lib/matplotlib/tests/test_backends_interactive.py @@ -111,6 +111,7 @@ def check_alt_backend(alt_backend): timer.add_callback(FigureCanvasBase.key_press_event, fig.canvas, "q") # Trigger quitting upon draw. fig.canvas.mpl_connect("draw_event", lambda event: timer.start()) +fig.canvas.mpl_connect("close_event", print) plt.show() """ @@ -120,12 +121,14 @@ def check_alt_backend(alt_backend): @pytest.mark.parametrize("backend", _get_testable_interactive_backends()) @pytest.mark.flaky(reruns=3) def test_interactive_backend(backend): - proc = subprocess.run([sys.executable, "-c", _test_script], - env={**os.environ, "MPLBACKEND": backend}, - timeout=_test_timeout) + proc = subprocess.run( + [sys.executable, "-c", _test_script], + env={**os.environ, "MPLBACKEND": backend}, timeout=_test_timeout, + stdout=subprocess.PIPE, universal_newlines=True) if proc.returncode: pytest.fail("The subprocess returned with non-zero exit status " f"{proc.returncode}.") + assert proc.stdout.count("CloseEvent") == 1 @pytest.mark.skipif('SYSTEM_TEAMFOUNDATIONCOLLECTIONURI' in os.environ,