8000 Add initial support for HiDPI in TkAgg on Windows. · matplotlib/matplotlib@c06cc86 · GitHub
[go: up one dir, main page]

Skip to content

Commit c06cc86

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 497fd23 commit c06cc86

File tree

2 files changed

+29
-1
lines changed

2 files changed

+29
-1
lines changed

lib/matplotlib/backends/_backend_tk.py

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ def __init__(self, figure=None, master=None, resize_callback=None):
167167
super().__init__(figure)
168168
self._idle_draw_id = None
169169
self._event_loop_id = None
170-
w, h = self.figure.bbox.size.astype(int)
170+
w, h = self.get_width_height(physical=True)
171171
self._tkcanvas = tk.Canvas(
172172
master=master, background="white",
173173
width=w, height=h, borderwidth=0, highlightthickness=0)
@@ -176,6 +176,7 @@ def __init__(self, figure=None, master=None, resize_callback=None):
176176
self._tkcanvas.create_image(w//2, h//2, image=self._tkphoto)
177177
self._resize_callback = resize_callback
178178
self._tkcanvas.bind("<Configure>", self.resize)
179+
self._tkcanvas.bind("<Map>", self._update_device_pixel_ratio)
179180
self._tkcanvas.bind("<Key>", self.key_press)
180181
self._tkcanvas.bind("<Motion>", self.motion_notify_event)
181182
self._tkcanvas.bind("<Enter>", self.enter_notify_event)
@@ -210,6 +211,18 @@ def filter_destroy(event):
210211
self._master = master
211212
self._tkcanvas.focus_set()
212213

214+
def _update_device_pixel_ratio(self, event=None):
215+
# Tk gives scaling with respect to 72 DPI, but most (all?) screens are
216+
# scaled vs 96 dpi, and pixel ratio settings are given in whole
217+
# percentages, so round to 2 digits.
218+
ratio = round(self._master.call('tk', 'scaling') / (96 / 72), 2)
219+
if self._set_device_pixel_ratio(ratio):
220+
# The easiest way to resize the canvas is to resize the canvas
221+
# widget itself, since we implement all the logic for resizing the
222+
# canvas backing store on that event.
223+
w, h = self.get_width_height(physical=True)
224+
self._tkcanvas.configure(width=w, height=h)
225+
213226
def resize(self, event):
214227
width, height = event.width, event.height
215228
if self._resize_callback is not None:
@@ -845,6 +858,7 @@ def new_figure_manager_given_figure(cls, num, figure):
845858
with _restore_foreground_window_at_end():
846859
if cbook._get_running_interactive_framework() is None:
847860
cbook._setup_new_guiapp()
861+
_c_internal_utils.Win32_SetDpiAwareness()
848862
window = tk.Tk(className="matplotlib")
849863
window.withdraw()
850864

src/_c_internal_utils.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,15 @@ mpl_SetForegroundWindow(PyObject* module, PyObject *arg)
124124
#endif
125125
}
126126

127+
static PyObject*
128+
mpl_SetDpiAwareness(PyObject* module)
129+
{
130+
#ifdef _WIN32
131+
SetProcessDPIAware();
132+
#endif
133+
Py_RETURN_NONE;
134+
}
135+
127136
static PyMethodDef functions[] = {
128137
{"display_is_valid", (PyCFunction)mpl_display_is_valid, METH_NOARGS,
129138
"display_is_valid()\n--\n\n"
@@ -151,6 +160,11 @@ static PyMethodDef functions[] = {
151160
"Win32_SetForegroundWindow(hwnd, /)\n--\n\n"
152161
"Wrapper for Windows' SetForegroundWindow. On non-Windows platforms, \n"
153162
"a no-op."},
163+
{"Win32_SetDpiAwareness",
164+
(PyCFunction)mpl_SetDpiAwareness, METH_NOARGS,
165+
"Win32_SetDpiAwareness()\n--\n\n"
166+
"Set Windows' process DPI awareness to be enabled. On non-Windows\n"
167+
"platforms, does nothing."},
154168
{NULL, NULL}}; // sentinel.
155169
static PyModuleDef util_module = {
156170
PyModuleDef_HEAD_INIT, "_c_internal_utils", "", 0, functions, NULL, NULL, NULL, NULL};

0 commit comments

Comments
 (0)
0