classification
Title: IDLE: Turn on DPI awareness on Windows
Type: enhancement Stage: resolved
Components: IDLE Versions: Python 3.8, Python 3.7, Python 3.6
process
Status: closed Resolution: fixed
Dependencies: Superseder:
Assigned To: terry.reedy Nosy List: eric.fahlgren, miss-islington, paul.moore, ronaldoussoren, serhiy.storchaka, steve.dower, taleinat, terry.reedy, tim.golden, zach.ware
Priority: normal Keywords: patch

Created on 2018-05-26 23:14 by terry.reedy, last changed 2018-10-14 00:41 by terry.reedy. This issue is now closed.

Pull Requests
URL Status Linked Edit
PR 7137 closed terry.reedy, 2018-05-26 23:39
PR 7638 merged terry.reedy, 2018-06-11 17:57
PR 7639 merged miss-islington, 2018-06-11 18:16
PR 7640 merged miss-islington, 2018-06-11 18:16
PR 7641 merged miss-islington, 2018-06-11 18:17
PR 7642 merged terry.reedy, 2018-06-11 19:32
PR 7643 merged miss-islington, 2018-06-11 19:46
PR 7644 merged miss-islington, 2018-06-11 19:47
PR 7646 merged terry.reedy, 2018-06-11 20:39
PR 7647 merged miss-islington, 2018-06-11 20:55
PR 7648 merged miss-islington, 2018-06-11 20:55
PR 9858 merged terry.reedy, 2018-10-13 23:42
PR 9862 merged miss-islington, 2018-10-14 00:00
PR 9863 merged miss-islington, 2018-10-14 00:00
Messages (38)
msg317775 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-05-26 23:14
On IDLE-dev today, Elisha Paine, from Ranelagh School in England, wrote:
'''
I love IDLE (so simple and lightweight compared with other IDEs) and was just wondering if you could add the following code into pyshell.py (as I have done on mine) because, as you will be able to tell, it sets DPI awareness (and on my set-up makes the text a lot clearer)

import ctypes
try: ctypes.windll.shcore.SetProcessDpiAwareness (True)
except: pass
'''
On my Win 10 system with a 2560 x 1440 27" monitor, the text is noticeably sharper, some colors are brighter, and some characters are better formed.  The main effect seems to be from properly lining up vertical and horizontal lines with the pixels.  Lines that are supposed to be 1 or 2 pixels wide are just that, instead of bleeding over onto additional rows or columns.

By comparing IDLE's shell with Windows consoles with the same font and text, both for Command Prompt and Python x.y consoles, I determined that the Windows consoles have DPI awareness on.  The text is longer with it off and some character shapes, such as for 2 and 3, don't match, whereas text length and shape matches perfectly with it on.

At least some other apps also have DPO awareness on.  With the patch, the Open and Save As dialogs opened opened by from IDLE, via the tkinter/tk function, match those opened by Firefox.  Without the patch, not.

I like the improvement and with 3.7.0rc1 delayed, would like to get it in now.  My question for you Windows experts is 1. Is the above exactly the right thing? and 2. Should it be unconditional, or is there a possible downside?  Do consoles always have DPI awareness, or is it conditional on the monitor? 

I will make a PR as soon as I post this and get an issue number.
msg317776 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-05-26 23:41
I changed the bare except: to 'except AttributeError:'.  If ctypes.windll.shcore.SetProcessDpiAwareness exists, can calling it with True ever fail?
msg318040 - (view) Author: Ronald Oussoren (ronaldoussoren) * (Python committer) Date: 2018-05-29 15:01
I'm not a Windows expert, but looking that the API description [1] the patch is not entirely correct. 

The API takes an integer with 3 valid values, the patch effectively passes the value 1 (which means the application claims to be DPI aware, but won't scale itself when the DPI changes for some reason).  

The API can fail, but that shouldn't cause an exception as ctypes won't automaticly convert error return values to exceptions.

P.S. The pull request seems to contain an unrelated change as well.

[1] https://msdn.microsoft.com/en-us/library/windows/desktop/dn302122(v=vs.85).aspx
msg318053 - (view) Author: Zachary Ware (zach.ware) * (Python committer) Date: 2018-05-29 16:03
Does Tcl/Tk have a function for this, and/or should we expose this as a function in Tkinter?  Do other platforms (macOS, X/Wayland) have similar functions?
msg318056 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-05-29 16:13
Perhaps the argument should be 2 for supporting multi-display configuration. Currently I can't do this, but will test this recipe with Hi-DPI monitor and multiple displays after 1-2 weeks.
msg318068 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-05-29 19:07
Thanks for the comments:

Ronald: I agree that an int should be passed.  I understand your ctype comment as saying that an attribute error before making the call should be the only possible exception.

I should have explained the 'unrelated change' to the one entry box.  With the default size of 20, it no longer fits properly after the change.  Adding an explicit size was the easiest fix for something that is only present for test and demonstration purposes.  A better fix, which is not needed for this issue, would probably be to add a 'expand=True' or something, somewhere else.

I checked all the other panes on the settings dialog and the other major dialog boxes and found no problems.

Zack: I had the same question.  Now that I know that IDLE as a tk app *can* look 'sharp', the current fuzzyness is annoying.  I would not be surprised if it contributes to some of the negative opinions about IDLE.
  
Tk tries to look 'native' and this seems to be the main thing missing.  To me, the only obvious reason for tk to not use this setting as default
is that is can mess up spacing on current windows.  But to me, it definitely should be available.

I don't know if other systems have such a setting, or any need for such.  I will ask an someone who uses IDLE both in Windows and Ubuntu on the same machine to compare.

Serhiy: I have a space monitor and I believe my graphics card will allow me to attach one, so I may give it a try.
--

The linked article recommends "that you set the process-default DPI awareness via application manifest."  I don't currently know what this 
means.  It appears that making one call before any tkinter calls is the right thing to do if any call is to be made.

The call does not appear to be available on Windows 7 or 8.0.
msg318069 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-05-29 19:09
Eryk Sun commented on the PR.
msg319130 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-09 02:19
Elisha wrote and I quoted: '[the call] sets DPI awareness'.  After reading https://msdn.microsoft.com/en-us/library/windows/desktop/dn280512(v=vs.85).aspx PROCESS_DPI_AWARENESS, what the call sets is the system's idea of what DPI awareness the app/process has. As I understand,
0 means 'App assumes DPI = 96, so if it is not, system must adjust.'
1 means 'App reads DPI at startup (somehow) and adjust to that value, but does not adapt to monitor change, so system must.'
2 means 'App reads DPI at startup and again after monitor change (somehow), so system should leave it alone.'
The correct value to pass is the one that best describes what the app does.  I believe that 0 is wrong and 1 more likely than 2.

My own experience and Elisha's report that IDLE looks better (at any resolution setting) matches others.  For instance,
https://stackoverflow.com/questions/41315873/attempting-to-resolve-blurred-tkinter-text-scaling-on-windows-10-high-dpi-disp
Three people describe fuzzy tk text as a well-known problem, fixed by SetProcessDpiAwareness(1).

https://wiki.tcl.tk/8484 tk has a scaling function that gets and sets a scaling factor, dpi/72 = pixels per printer point.  "The initial value for the scaling factor is set when the application starts, based on properties of the installed monitor."  This also suggests to me also that default 0 for awareness is wrong value.  Users (apps) can changes this, but I see no suggestion that monitor changes are tracked.
msg319148 - (view) Author: Eric Fahlgren (eric.fahlgren) * Date: 2018-06-09 16:04
https://msdn.microsoft.com/en-us/library/windows/desktop/mt748620(v=vs.85).aspx gives the syntax for adding dpiAwareness to the Windows manifest.
msg319150 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-09 16:16
As reported on #26698, which was originally opened as an IDLE issue, but which I turned into a tkinter issue, one can also sharpen text buy opening python(w).exe properties, Compatibility tab, clicking [Change high DPI settings], and then checking [] Override high DPI scaling behavior while leaving the default 'Application'.  The effect is the same as 'SetProcessDpiAwareness (1)' -- or (2) if monitor is not changed.
msg319152 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-09 16:27
Eric, thanks for the additional reference.  From Window's viewpoint, Python, not IDLE, is the application.  IDLE is just input data.  I should not touch Python's manifest, and changing it would have to consider other possible gui module input data.

This page says it applies only to Win10 desktop.  The page for SetProcessDpiAwareness says it applies to 8.1+.  That still excludes Vista and Win7, but is better than just Win10.
msg319159 - (view) Author: Eric Fahlgren (eric.fahlgren) * Date: 2018-06-09 16:57
So maybe add the dpiAware and dpiAwareness settings to the manifest for just Windows' pythonw.exe and leave the python.exe console interpreter alone?  I'm going to guess that the pythonw.exe manifest already has some settings related to its unique status that align with this.
msg319184 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2018-06-09 23:03
I'm okay to add it to the manifest for both in 3.8, along with a What's New entry.

High DPI screens are very common though, and adding it to existing releases won't allow existing apps or frameworks to account for the change. I don't want non-DPI aware apps to suddenly become unreadably small with a minor runtime update. Backporting Python-specific docs is fine.
msg319185 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-09 23:26
Steve, I would like to add the SetProcessDpiAwareness(1) call to IDLE tomorrow, for 3.7.0 and 3.6.6.  Do I need to make it an avoidable option? Can it hurt people on some machines?  It seems to me that if tk is doing dpi scaling, then it should always be correct to tell Windows that it is doing so.
msg319192 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2018-06-10 01:30
Yep, that should be fine.

If you want to add it to the winapi module rather than use ctypes that's fine too.
msg319326 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 18:14
New changeset 800415e3df69f494afe9f95a8563ce17609fe1da by Terry Jan Reedy in branch 'master':
bpo-33656: On Windows, add API call saying that tk scales for DPI (GH-7137)
https://github.com/python/cpython/commit/800415e3df69f494afe9f95a8563ce17609fe1da
msg319327 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 18:15
New changeset 8a05f559ce5064df68c8d4ebd7d4ed28381d9971 by Terry Jan Reedy in branch 'master':
bpo-33656: Add entry to What's New 3.7. (GH-7638)
https://github.com/python/cpython/commit/8a05f559ce5064df68c8d4ebd7d4ed28381d9971
msg319328 - (view) Author: miss-islington (miss-islington) Date: 2018-06-11 18:35
New changeset 144a8670f24a157642c5f7fbaf518e87c7c1b969 by Miss Islington (bot) in branch '3.7':
bpo-33656: On Windows, add API call saying that tk scales for DPI (GH-7137)
https://github.com/python/cpython/commit/144a8670f24a157642c5f7fbaf518e87c7c1b969
msg319329 - (view) Author: miss-islington (miss-islington) Date: 2018-06-11 18:39
New changeset 0404d35f9dc89748949935a9178d28bedde9d8c8 by Miss Islington (bot) in branch '3.6':
bpo-33656: On Windows, add API call saying that tk scales for DPI (GH-7137)
https://github.com/python/cpython/commit/0404d35f9dc89748949935a9178d28bedde9d8c8
msg319330 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 19:09
Thanks everyone for the help.  I think this is the right patch, but as with many IDLE patches, it is hard to be sure until it is in use.  At least there is no question here of tk Windows-Linux-MacOS differences.  I checked that the Win 7 buildbots are OK with the PR.

Serhiy: My interpretation of the tk scaling doc is that 1, not 2, is the right argument.  But we can test to be sure.  I meant 'spare monitor', not 'space monitor'.  But I need to find one with a substantially different DPI.

Steve: changing the binaries' manifests is a separate issue, not limited to IDLE or even tkinter.  And 3.8 enhancements do nothing for IDLE on 3.6 and 3.7.  Ditto for a new WinAPI.
msg319331 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 19:17
Reopening, temporarily, to add change requested by Eryk Sun after the merge.
msg319332 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 19:45
New changeset fd88f319a4f40682b989b63f0b6378d69465fda4 by Terry Jan Reedy in branch 'master':
bpo-33656: Add enum name for argument of Windows call. (GH-7642)
https://github.com/python/cpython/commit/fd88f319a4f40682b989b63f0b6378d69465fda4
msg319334 - (view) Author: miss-islington (miss-islington) Date: 2018-06-11 20:06
New changeset d26277a73b61277ad9568cff6503d55deef07223 by Miss Islington (bot) in branch '3.7':
bpo-33656: Add enum name for argument of Windows call. (GH-7642)
https://github.com/python/cpython/commit/d26277a73b61277ad9568cff6503d55deef07223
msg319336 - (view) Author: miss-islington (miss-islington) Date: 2018-06-11 20:08
New changeset afa1ea5bfd18947aa732a1ea09220aefbed81e1c by Miss Islington (bot) in branch '3.6':
bpo-33656: Add enum name for argument of Windows call. (GH-7642)
https://github.com/python/cpython/commit/afa1ea5bfd18947aa732a1ea09220aefbed81e1c
msg319340 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 20:42
Since there should be time before .rcs are cut, I changed the idlelib NEWS.txt entry to mention color changes, based on editing with the change in place.
msg319345 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 20:53
New changeset 4b704f29f5a0b6f6d7bd67468ed004bd3a96855d by Terry Jan Reedy in branch 'master':
bpo-33656: Mention color in idlelib/NEWS.txt entry. (#7646)
https://github.com/python/cpython/commit/4b704f29f5a0b6f6d7bd67468ed004bd3a96855d
msg319346 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-11 21:08
New changeset 6530577e29a9679c7e4c7ba7adf1c02393d2ad13 by Terry Jan Reedy (Miss Islington (bot)) in branch '3.7':
bpo-33656: Mention color in idlelib/NEWS.txt entry. (GH-7646) (GH-7647)
https://github.com/python/cpython/commit/6530577e29a9679c7e4c7ba7adf1c02393d2ad13
msg319348 - (view) Author: miss-islington (miss-islington) Date: 2018-06-11 21:19
New changeset 2023eafd9a0554823cab5adf5a1b116d7984db98 by Miss Islington (bot) in branch '3.6':
bpo-33656: Mention color in idlelib/NEWS.txt entry. (GH-7646)
https://github.com/python/cpython/commit/2023eafd9a0554823cab5adf5a1b116d7984db98
msg319362 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-06-12 05:05
I can't test on multiple monitors, but I tested on a single HiDPI monitor. With 1 it looks much better than with 0. With 2 it looks the same as with 1 on HiDPI, but doesn't scale well after changing the resolution of the display. I suppose there are the same problems on multi-monitor configuration. Thus the value 1 is the correct one.

ctypes is optional. It would be better to catch an ImportError from importing it.
msg319403 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-12 21:32
I confirmed that IDLE did not import ctypes before this issue.  Serhiy, I presume that the new code can be skipped, you are suggesting replacing

import ctypes
<use ctypes....>

with

try:
    import ctypes
except ImportError:
    pass  # The ctypes-using fix is not essential.
else:
    <use ctypes...>

But, in what sense is ctypes optional *on Windows* more than most other modules?  I don't see anything in the ctypes doc.  It is normal to depend on stdlib modules being present and not wrap imports.

Steve: does the Windows installer have an option to omit ctypes?  I don't remember one.  

Anyone: do you know of any CPython Windows distributions that we care about that omit ctypes?

Which of the following best describes the situation?
1. This is a theoretical concern that does not justify adding noise to the code.
2. This is a real concern, but so rare that the fix can be deferred to 3.6.7 and 3.7.1.
3. This is likely common enough that we should ask Ned to cherry-pick the patch into 3.6.6 and 3.7.1.
msg319407 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-06-12 21:53
I just ran the 3.7.0rc1 installer and here is no option to omit ctypes.
msg319411 - (view) Author: Steve Dower (steve.dower) * (Python committer) Date: 2018-06-12 23:31
There's no option to omit ctypes, though I am aware of some custom builds of Python that exclude it. I don't think you need to worry about those being used for IDLE (but of course the general policy of the stdlib not relying on ctypes remains).
msg319426 - (view) Author: Serhiy Storchaka (serhiy.storchaka) * (Python committer) Date: 2018-06-13 05:10
I don't know whether this is a theoretical or a real concern, but I think this fix can wait for 3.7.1.
msg327676 - (view) Author: Tal Einat (taleinat) * (Python committer) Date: 2018-10-13 22:02
Ping? Do we want to get this in for 3.7.1 and 3.6.7?
msg327680 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-10-13 23:47
There is still no rush as guarding the ctypes import on Windows builds that can run IDLE may never be needed.  But I grepped the stdlib .py code and uuid is the only .py module that imports ctypes, and all are directly or indirectly guarded in the code or test_uuid.  So I moved the import inside the existing try block and added ImportError to those caught.
msg327681 - (view) Author: Terry J. Reedy (terry.reedy) * (Python committer) Date: 2018-10-14 00:00
New changeset d274afb5e579a5d9d990f68f9af856cf4c918779 by Terry Jan Reedy in branch 'master':
bpo-33656: Move pyshell ctypes import inside try block. (GH-9858)
https://github.com/python/cpython/commit/d274afb5e579a5d9d990f68f9af856cf4c918779
msg327683 - (view) Author: miss-islington (miss-islington) Date: 2018-10-14 00:19
New changeset 77e0abe228564a5be23284bd8e963c11952eb55b by Miss Islington (bot) in branch '3.7':
bpo-33656: Move pyshell ctypes import inside try block. (GH-9858)
https://github.com/python/cpython/commit/77e0abe228564a5be23284bd8e963c11952eb55b
msg327685 - (view) Author: miss-islington (miss-islington) Date: 2018-10-14 00:28
New changeset 68299305c7898eb8eb0cea6cad19c299d0d1ba2d by Miss Islington (bot) in branch '3.6':
bpo-33656: Move pyshell ctypes import inside try block. (GH-9858)
https://github.com/python/cpython/commit/68299305c7898eb8eb0cea6cad19c299d0d1ba2d
History
Date User Action Args
2018-10-14 00:41:17terry.reedysetstatus: open -> closed
stage: patch review -> resolved
2018-10-14 00:28:08miss-islingtonsetmessages: + msg327685
2018-10-14 00:19:27miss-islingtonsetmessages: + msg327683
2018-10-14 00:00:52miss-islingtonsetpull_requests: + pull_request9232
2018-10-14 00:00:44miss-islingtonsetstage: resolved -> patch review
pull_requests: + pull_request9231
2018-10-14 00:00:35terry.reedysetmessages: + msg327681
2018-10-13 23:47:23terry.reedysetmessages: + msg327680
stage: patch review -> resolved
2018-10-13 23:42:04terry.reedysetstage: resolved -> patch review
pull_requests: + pull_request9226
2018-10-13 22:02:33taleinatsetnosy: + taleinat
messages: + msg327676
2018-06-13 05:10:31serhiy.storchakasetmessages: + msg319426
2018-06-13 04:12:13terry.reedylinkissue26698 superseder
2018-06-12 23:31:47steve.dowersetmessages: + msg319411
2018-06-12 21:53:17terry.reedysetmessages: + msg319407
2018-06-12 21:32:50terry.reedysetstatus: closed -> open
2018-06-12 21:32:30terry.reedysetmessages: + msg319403
2018-06-12 05:05:06serhiy.storchakasetmessages: + msg319362
2018-06-11 21:21:32terry.reedysetstatus: open -> closed
stage: patch review -> resolved
2018-06-11 21:19:26miss-islingtonsetmessages: + msg319348
2018-06-11 21:08:22terry.reedysetmessages: + msg319346
2018-06-11 20:55:55miss-islingtonsetpull_requests: + pull_request7267
2018-06-11 20:55:02miss-islingtonsetstage: resolved -> patch review
pull_requests: + pull_request7266
2018-06-11 20:53:51terry.reedysetmessages: + msg319345
2018-06-11 20:42:41terry.reedysetmessages: + msg319340
stage: patch review -> resolved
2018-06-11 20:39:58terry.reedysetpull_requests: + pull_request7265
2018-06-11 20:08:26miss-islingtonsetmessages: + msg319336
2018-06-11 20:06:38miss-islingtonsetmessages: + msg319334
2018-06-11 19:47:38miss-islingtonsetpull_requests: + pull_request7263
2018-06-11 19:46:47miss-islingtonsetpull_requests: + pull_request7262
2018-06-11 19:45:29terry.reedysetmessages: + msg319332
2018-06-11 19:32:50terry.reedysetstage: resolved -> patch review
pull_requests: + pull_request7261
2018-06-11 19:17:14terry.reedysetstatus: closed -> open

messages: + msg319331
2018-06-11 19:09:43terry.reedysetstatus: open -> closed
resolution: fixed
messages: + msg319330

stage: patch review -> resolved
2018-06-11 18:39:46miss-islingtonsetmessages: + msg319329
2018-06-11 18:35:17miss-islingtonsetnosy: + miss-islington
messages: + msg319328
2018-06-11 18:17:43miss-islingtonsetpull_requests: + pull_request7260
2018-06-11 18:16:45miss-islingtonsetpull_requests: + pull_request7259
2018-06-11 18:16:06miss-islingtonsetpull_requests: + pull_request7258
2018-06-11 18:15:40terry.reedysetmessages: + msg319327
2018-06-11 18:14:35terry.reedysetmessages: + msg319326
2018-06-11 17:57:14terry.reedysetpull_requests: + pull_request7257
2018-06-10 01:30:26steve.dowersetmessages: + msg319192
2018-06-09 23:26:22terry.reedysetmessages: + msg319185
2018-06-09 23:03:38steve.dowersetmessages: + msg319184
2018-06-09 16:57:02eric.fahlgrensetmessages: + msg319159
2018-06-09 16:27:03terry.reedysetmessages: + msg319152
2018-06-09 16:16:10terry.reedysetmessages: + msg319150
2018-06-09 16:04:02eric.fahlgrensetnosy: + eric.fahlgren
messages: + msg319148
2018-06-09 02:19:29terry.reedysetmessages: + msg319130
2018-05-29 19:09:20terry.reedysetmessages: + msg318069
2018-05-29 19:07:39terry.reedysetmessages: + msg318068
2018-05-29 16:13:12serhiy.storchakasetmessages: + msg318056
2018-05-29 16:03:40zach.waresetnosy: + serhiy.storchaka
messages: + msg318053
2018-05-29 15:01:58ronaldoussorensetnosy: + ronaldoussoren
messages: + msg318040
2018-05-26 23:41:13terry.reedysetmessages: + msg317776
2018-05-26 23:39:40terry.reedysetkeywords: + patch
pull_requests: + pull_request6771
2018-05-26 23:14:50terry.reedycreate