Skip to content

Commit 52c07fe

Browse files
committed
Add initial support for HiDPI in TkAgg on Windows.
At the moment, Tk does not support updating the 'scaling' value when the monitor pixel ratio changes, or the window is moved to a different one.
1 parent 8d78315 commit 52c07fe

File tree

3 files changed

+19
-3
lines changed

3 files changed

+19
-3
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,7 +166,7 @@ class FigureCanvasTk(FigureCanvasBase):
166166
def __init__(self, figure, master=None, resize_callback=None):
167167
super().__init__(figure)
168168
self._idle_draw_id = None
169-
w, h = self.figure.bbox.size.astype(int)
169+
w, h = self.get_width_height(physical=True)
170170
self._tkcanvas = tk.Canvas(
171171
master=master, background="white",
172172
width=w, height=h, borderwidth=0, highlightthickness=0)
@@ -175,6 +175,7 @@ def __init__(self, figure, master=None, resize_callback=None):
175175
self._tkcanvas.create_image(w//2, h//2, image=self._tkphoto)
176176
self._resize_callback = resize_callback
177177
self._tkcanvas.bind("<Configure>", self.resize)
178+
self._tkcanvas.bind("<Map>", self._update_device_pixel_ratio)
178179
self._tkcanvas.bind("<Key>", self.key_press)
179180
self._tkcanvas.bind("<Motion>", self.motion_notify_event)
180181
self._tkcanvas.bind("<Enter>", self.enter_notify_event)
@@ -209,6 +210,18 @@ def filter_destroy(event):
209210
self._master = master
210211
self._tkcanvas.focus_set()
211212

213+
def _update_device_pixel_ratio(self, event=None):
214+
# Tk gives scaling with respect to 72 DPI, but most (all?) screens are
215+
# scaled vs 96 dpi, and pixel ratio settings are given in whole
216+
# percentages, so round to 2 digits.
217+
ratio = round(self._master.call('tk', 'scaling') / (96 / 72), 2)
218+
if self._set_device_pixel_ratio(ratio):
219+
# The easiest way to resize the canvas is to resize the canvas
220+
# widget itself, since we implement all the logic for resizing the
221+
# canvas backing store on that event.
222+
w, h = self.get_width_height(physical=True)
223+
self._tkcanvas.configure(width=w, height=h)
224+
212225
def resize(self, event):
213226
width, height = event.width, event.height
214227
if self._resize_callback is not None:

setupext.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -411,8 +411,8 @@ def get_extensions(self):
411411
],
412412
include_dirs=["src"],
413413
# psapi library needed for finding Tcl/Tk at run time.
414-
libraries=({"linux": ["dl"], "win32": ["psapi"],
415-
"cygwin": ["psapi"]}.get(sys.platform, [])),
414+
libraries=({"linux": ["dl"], "win32": ["psapi", "user32"],
415+
"cygwin": ["psapi", "user32"]}.get(sys.platform, [])),
416416
extra_link_args={"win32": ["-mwindows"]}.get(sys.platform, []))
417417
add_numpy_flags(ext)
418418
add_libagg_flags(ext)

src/_tkagg.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,9 @@ static PyModuleDef _tkagg_module = {
205205

206206
PyMODINIT_FUNC PyInit__tkagg(void)
207207
{
208+
#ifdef WIN32_DLL
209+
SetProcessDPIAware(); // Ignore errors in case we are embedded.
210+
#endif
208211
load_tkinter_funcs();
209212
if (PyErr_Occurred()) {
210213
return NULL;

0 commit comments

Comments
 (0)