Tk Source Code

View Ticket
EuroTcl/OpenACS 11 - 12 JULY 2024, VIENNA
Ticket UUID: a9ee44102be4b2849fab7388f53fc8adb553ca3a
Title: Windows 10 multi-screen dpi scaling problem
Type: Bug Version: 8.6.9
Submitter: cjmcdonald Created on: 2019-09-12 12:10:43
Subsystem: 68. Win Window Operations Assigned To: nobody
Priority: 5 Medium Severity: Severe
Status: Open Last Modified: 2020-08-22 06:42:24
Resolution: None Closed By: nobody
    Closed on:
The attached test script demonstrates a problem with Windows dpi scaling
on a Windows 10 (1803) system with screens with different dpi.  Wish is
built with a "system" dpiaware manifest, which means that Tk uses the
dpi of the primary screen, and Microsoft Windows should automatically
bitmap scale toplevels on any other screens to get the correct size.
But Windows sometimes appears to have the wrong screen dpi associated
with a toplevel, making it too big or too small or positioning it

Run the script on a Windows 10 system with multiple screens with
significantly different dpi, eg a laptop screen and an external monitor.
Move Toplevel 2 to a different screen from Toplevel 1.  Clicking on each
pop-up button should produce a pop-up marker over the button, but with
different dpi the marker is often sized and positioned incorrectly on
one or other screen.  If nothing appears to happen when clicking on a
button it may be that the pop-up has been positioned completely off the

The likelihood of seeing the problem appears to be affected by which
different "wm" subcommands are used for the pop-up window, and their
User Comments: chrstphrchvz added on 2020-08-22 06:42:24:

Possible duplicate: [dc18394b42]

chrstphrchvz added on 2020-06-24 20:19:12:

It must be emphasized that this issue is dealing with "logical" pixel density, i.e. the pretend DPI that the OS provides to software; and not the actual measured "physical" pixel density of some particular model display/monitor (I suggest completely ignoring physical pixel density for this discussion to avoid further confusion). Changing the screen resolution does not change the logical pixel density.

The reporter is referring to how Windows 10 1803 and later support multiple logical pixel densities for different connected monitors, whereas before only a single DPI setting across all monitors was supported. This DPI setting is located in the Settings App under System > Display: first click the number of a monitor in the "Rearrange your displays" diagram, then use the "Scale and layout" > "Change the size of text, apps, and other items" setting below. 100% corresponds to the traditional 96 DPI on Windows. However something higher like 125% (120 DPI) or 150% (144 DPI) might be the default/recommendation for newer devices with high (physical) pixel density monitors. Once the DPI is set differently between monitors, this issue is easily observed.

The issue seems to generally be that a toplevel with overrideredirect set might have its DPI scaling/virtualization state determined not by its position alone, but instead by the DPI scaling state for some other toplevel, i.e. that other toplevel's position; the toplevel whose state is followed appears to depend on stacking/Z ordering. (Toplevel transience does not seem to be relevant.) I am considering posting an example showing toplevels "crawling" between monitors and crossing between DPI scaling states: a normal toplevel's DPI scaling state will toggle based on its own position, while an overrideredirect toplevel will have its state be determined by where one of the normal toplevels is. Probably the only case I've observed where an overrideredirect toplevel has its DPI scaling state toggle correctly is when it is the only toplevel present (i.e. the root toplevel). I didn't determine if this is merely due to an oversight/outdated handling in Tk, or an actual Windows DPI virtualization bug.

Also, I don't think this issue is caused specifically by declaring "system" DPI awareness for wish, as this issue occurs even when declaring it as DPI-unaware. The issue may have more to do with not using per-monitor DPI awareness, though I don't think Tk can easily support using that: it would likely entail having per-toplevel values of tk scaling (i.e. DPI รท 72.0), and that updates to tk scaling (e.g. when moving a toplevel between monitors) be reflected by widgets (whereas their behavior is currently undefined if tk scaling changes).

fvogel added on 2019-11-05 08:30:38:

I have tried again but definitely I cannot reproduce on the Win 10 version 1803 I have here, running either 8.5.15 or a recent core-8-6-branch version (specifically [b127e6b08a]).

The setup I'm using is a laptop showing the primary screen featuring 1920x1080 pixels and a physical screen size of ~34.5cm x ~19.5cm, that is ~55 pixels/cm. On this laptop a secondary monitor is attached, having 1920x1200 pixels and a physical screen size of ~52cm x ~33cm, that is ~36 pixels/cm. The two screens therefore have really different dpi, and this setting is similar the the one the OP has described.

Running the provided 'test_scaling.tcl' script I cannot trigger any issue whatever screen I put whichever toplevel on. The red box always is exactly on top of the inside of the toplevel.

Changin screen resolution of the secondary monitor to 800x600 (thus an even more different dpi of ~18 pixels/cm) still does not allow me to reproduce.

cjmcdonald added on 2019-10-10 20:47:24:

On my system the test script exactly as attached always goes wrong when the toplevels are on different screens. Not just for the first invocation of the pop-ups, but repeatedly. However, any changes to the script produces different behaviour, eg changing the order of the "wm" commands, or adding extra ones - even just repeating a wm command or adding a diagnostic output can change the behaviour.

I agree that it's not clear whether this is a Tk bug or a Windows bug. My guess is that Windows is getting confused as to which screen a toplevel or pop-up will be associated with when realised, and then applying the wrong scaling. My hope is that if we leave this problem as a reminder then perhaps we will find a way of making Tk give Windows a hint as to which screen a toplevel is going to appear on.

bll added on 2019-10-10 18:34:58:
I am still not sure whether this is a Tk bug or a Windows bug.
I don't understand why my toplevel 2 never has an issue, but the OP's does.
I have no idea where to start looking for this bug.

If anyone has an idea of what to start looking at to debug this, please give me some pointers.

bll added on 2019-10-09 20:39:08:
Changed the code to do a
  wm withrdaw .
Added a toplevel 3.

No failures with either toplevel 2 or toplevel 3.

I am using a version of core-8-6-10-rc from a few days back.
On windows 10 1903 64-bit .

bll added on 2019-10-09 20:34:03:
Ok, found a DVI to HDMI adapter, there's a TV here i never use, and
the cables I have barely reach.

My desktop monitor is 72 dpi, no idea what the TV is.

The first time I ran the test program, the pop-up appeared up and left of
the window (as excpected).  After that, all pop-ups appeared in the proper
place, and I cannot get the condition to repeat.

Second test: move both topleves to the other monitor.  Top level 1 fails
more than once.  toplevel 2 works, and toplevel 1 works thereafter.

Third test: move both toplevels to the other monitor.  Top level 2 works,
top level 1 works.

fourth test: try topleve 1 and 2 on main monitor.  move both.  toplevel 1 
fails, toplevel 2 works, and toplevel 1 works thereafter.

bll added on 2019-10-09 19:12:49:
I have a 32-bit windows 10 VM handy, and can configure a second monitor on it,
but I can't reproduce the problem that way either.  Obviously the same DPI.

Both of my Windows 10 I have available are version 1903 now.

cjmcdonald added on 2019-10-09 17:04:26:

Thank you for taking the time to look at this.

I've been seeing the problem on systems running Windows 10 (1803). There have been several changes in Windows 10 to how Windows handles screens with different resolutions, so I'm not surprised you don't see the same behaviour in Vista.

I see the problem when I use Tcl/Tk on systems which have more than one screen, and the screens have different pixels/cm:

  • I have a laptop with a screen resolution of 1920 x 1080 pixels, physical size approximately 308x174 millimetres, giving approximately 62 pixels/cm.
  • Also attached is an external monitor with resolution 1920x1200 pixels, physical size approximately 592x372 millimetres, giving approximately 32 pixels/cm.

I think that it is this difference in pixels/cm which is the causing the problem to appear. In the wish.mainfest we declare wish to be a "system" dpiaware manifest, which means that Tk uses the dpi of the primary screen only, and according to the Microsoft documentation Windows should automatically bitmap scale toplevels on any other screens to get the correct size. It's probably that scaling process which is sometimes going wrong. Maybe a Windows problem, but it could be triggered by Tk "wm" interactions.

When I interrogate the wm geometry settings of each toplevel and the pop-ups, they all appear correct.

bll added on 2019-10-09 14:18:59:
Sorry, I was a bit terse there.

I would like to see the OP's [wm geometry $parent] output and compare
it to what he was generating for the positioning of the second window.

Try changing your second screen to 680x400 or 1024x768, and see if that
generates any difference in the test results.  I don't know how to re-create
this either.

I would use the output of [wm geometry $parent] to position the second 
window rather than generating a new geometry string and that brought to
my mind the issues I had with processing right side offsets, therefore the 
other odd statement.

fvogel added on 2019-10-09 06:20:37:
Sorry I don't really understand your answer.

What I'm observing is that, running the provided test script, after pushing the button, the location of the red toplevel is always (as far as I can tell) exactly matching the inside of the parent toplevel, and this remains true whichever screen is used to display the toplevels. In other words, what I'm seeing is as in "expected_behaviour.png" added by cjmcdonald in the present ticket.

I'm normally using a setup where the primary monitor is "physically on the left", and the secondary monitor is on its right (its upper left corner is (1920,0)), therefore coordinates are always positive in X and Y. I have tried (on the Vista PC) moving the secondary monitor around the primary monitor (in the windows display configuration), making it feature negative x and/or y coordinates but still the red thing is on top of the toplevel in which I pushed the button.

Could it be that by chance the dpi of my two screens are the same? The OP says the key is that the two screens have different dpi values. How can I set a specific dpi value for a given screen? I must be missing something.

bll added on 2019-10-08 23:44:06:
Compare 'wm geometry $parent' with what is being generated.

I also had issues with right edge offsets (negative x values) and my 
code converts those to positive numbers.

fvogel added on 2019-10-08 19:07:30:

I have tried the provided test script on:

- a Vista desktop PC with two monitors attached (similar resolution)
- a laptop running Win10 with an additional screen attached

but I couldn't reproduce.