Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit c0df144

Browse files
committed
Use context manager instead of FocusManager class
Because relying on garbage collection of unused variables for correctness is crazy, and could easily give implementation-specific behaviour (eg broken on PyPy) or outright break if collection is delayed substantially after the variable goes out of scope.
1 parent bdeb21e commit c0df144

File tree

2 files changed

+60
-41
lines changed

2 files changed

+60
-41
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 55 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,11 @@
66
import sys
77
import tkinter as Tk
88
from tkinter.simpledialog import SimpleDialog
9+
from contextlib import contextmanager
910

1011
import numpy as np
1112

1213
from . import _tkagg
13-
from matplotlib.backends.backend_agg import FigureCanvasAgg
14-
import matplotlib.backends.windowing as windowing
1514

1615
import matplotlib
1716
from matplotlib import backend_tools, rcParams
@@ -23,6 +22,22 @@
2322
from matplotlib.figure import Figure
2423
from matplotlib.widgets import SubplotTool
2524

25+
try:
26+
from matplotlib._windowing import GetForegroundWindow, SetForegroundWindow
27+
except ImportError:
28+
@contextmanager
29+
def _restore_foreground_window_at_end():
30+
yield
31+
else:
32+
@contextmanager
33+
def _restore_foreground_window_at_end():
34+
foreground = GetForegroundWindow()
35+
try:
36+
yield
37+
finally:
38+
if rcParams['tk.window_focus']:
39+
SetForegroundWindow(foreground)
40+
2641

2742
_log = logging.getLogger(__name__)
2843

@@ -540,19 +555,19 @@ def show(self):
540555
this function doesn't segfault but causes the
541556
PyEval_RestoreThread: NULL state bug on win32
542557
"""
543-
_focus = windowing.FocusManager()
544-
if not self._shown:
545-
def destroy(*args):
546-
self.window = None
547-
Gcf.destroy(self._num)
548-
self.canvas._tkcanvas.bind("<Destroy>", destroy)
549-
self.window.deiconify()
550-
else:
551-
self.canvas.draw_idle()
552-
# Raise the new window.
553-
self.canvas.manager.window.attributes('-topmost', 1)
554-
self.canvas.manager.window.attributes('-topmost', 0)
555-
self._shown = True
558+
with _restore_foreground_window_at_end():
559+
if not self._shown:
560+
def destroy(*args):
561+
self.window = None
562+
Gcf.destroy(self._num)
563+
self.canvas._tkcanvas.bind("<Destroy>", destroy)
564+
self.window.deiconify()
565+
else:
566+
self.canvas.draw_idle()
567+
# Raise the new window.
568+
self.canvas.manager.window.attributes('-topmost', 1)
569+
self.canvas.manager.window.attributes('-topmost', 0)
570+
self._shown = True
556571

557572
def destroy(self, *args):
558573
if self.window is not None:
@@ -716,9 +731,9 @@ def set_active(self, ind):
716731
self._active = [self._axes[i] for i in self._ind]
717732

718733
def update(self):
719-
_focus = windowing.FocusManager()
720734
self._axes = self.canvas.figure.axes
721-
NavigationToolbar2.update(self)
735+
with _restore_foreground_window_at_end():
736+
NavigationToolbar2.update(self)
722737

723738

724739
class ToolTip(object):
@@ -989,29 +1004,29 @@ def new_figure_manager_given_figure(cls, num, figure):
9891004
"""
9901005
Create a new figure manager instance for the given figure.
9911006
"""
992-
_focus = windowing.FocusManager()
993-
window = Tk.Tk(className="matplotlib")
994-
window.withdraw()
995-
996-
# Put a mpl icon on the window rather than the default tk icon.
997-
# Tkinter doesn't allow colour icons on linux systems, but tk>=8.5 has
998-
# a iconphoto command which we call directly. Source:
999-
# http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html
1000-
icon_fname = os.path.join(
1001-
rcParams['datapath'], 'images', 'matplotlib.ppm')
1002-
icon_img = Tk.PhotoImage(file=icon_fname)
1003-
try:
1004-
window.tk.call('wm', 'iconphoto', window._w, icon_img)
1005-
except Exception as exc:
1006-
# log the failure (due e.g. to Tk version), but carry on
1007-
_log.info('Could not load matplotlib icon: %s', exc)
1008-
1009-
canvas = cls.FigureCanvas(figure, master=window)
1010-
manager = cls.FigureManager(canvas, num, window)
1011-
if matplotlib.is_interactive():
1012-
manager.show()
1013-
canvas.draw_idle()
1014-
return manager
1007+
with _restore_foreground_window_at_end():
1008+
window = Tk.Tk(className="matplotlib")
1009+
window.withdraw()
1010+
1011+
# Put a mpl icon on the window rather than the default tk icon.
1012+
# Tkinter doesn't allow colour icons on linux systems, but tk>=8.5 has
1013+
# a iconphoto command which we call directly. Source:
1014+
# http://mail.python.org/pipermail/tkinter-discuss/2006-November/000954.html
1015+
icon_fname = os.path.join(
1016+
rcParams['datapath'], 'images', 'matplotlib.ppm')
1017+
icon_img = Tk.PhotoImage(file=icon_fname)
1018+
try:
1019+
window.tk.call('wm', 'iconphoto', window._w, icon_img)
1020+
except Exception as exc:
1021+
# log the failure (due e.g. to Tk version), but carry on
1022+
_log.info('Could not load matplotlib icon: %s', exc)
1023+
1024+
canvas = cls.FigureCanvas(figure, master=window)
1025+
manager = cls.FigureManager(canvas, num, window)
1026+
if matplotlib.is_interactive():
1027+
manager.show()
1028+
canvas.draw_idle()
1029+
return manager
10151030

10161031
@staticmethod
10171032
def trigger_manager_draw(manager):

lib/matplotlib/backends/windowing.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,13 @@
55
effectively disabled.
66
77
It uses a tiny C++ extension module to access MS Win functions.
8+
9+
This module is deprecated and will be removed in version 3.2
810
"""
911

10-
from matplotlib import rcParams
12+
from matplotlib import rcParams, cbook
13+
14+
cbook.warn_deprecated('3.0', obj_type='module', name='backends.windowing')
1115

1216
try:
1317
if not rcParams['tk.window_focus']:

0 commit comments

Comments
 (0)