beeware / beeware/toga

WinForms: position and size properties are inconsistent when different screens have different DPIs

Open
#2,947 1 comment 0 reactions 0 assignees View on GitHub
bug windows
Dominant language
Python
Stars
5.4k
Forks
827
Avg merge
9h 45m
Merged PRs (30d)
58

Description

The Toga interface layer currently assumes that all the following properties operate in a single CSS-pixel coordinate system:
* Window.position, Window.size
* Screen.origin, Screen.size

Window.screen_position is then simply defined as Window.position - Screen.origin.

However, it isn't possible to define a consistent CSS-pixel coordinate system that covers different screens with different DPIs. Imagine you have four screens laid out like this in WinForms's physical coordinate space:

```
-------
| 1 |
-------
------- -------
| 2 | | 3 |
------- -------
-------
| 4 |
-------
```

Screens 2 and 3 have the same physical resolution. But if they have different DPIs, then what is the distance between screens 1 and 4 in CSS pixels? There are two answers, both equally valid.

As discussed in https://github.com/beeware/toga/pull/2155#issuecomment-2466962577, our current workaround is:

* Scale all the position/origin properties by the DPI of the *primary* screen, so they're consistent with each other.
* Scale all the size properties by the DPI of the *current* screen, so they're consistent with the scaling of the window's content.

So on the primary screen, and any other screen with the same DPI, everything works correctly. But on a screen with a different DPI to the primary one, the position and size properties will be in different scales, so you won’t be able to position windows relative to the bottom or right edges of the screen (as examples/window does) or of other windows.

I doubt many people are doing things like this, so it's not urgent to fix, but in the future we can implement a proper solution, which I think would look like this:

* Window.position: define to be relative to the current screen's origin and DPI, and move the calculation of that to the backend. Although this is technically backward-incompatible, it’s unlikely that any app will care. Even the "move" commands in examples/window will continue to work; the coordinate system will just change when the window moves onto a different screen.
* Window.screen_position: deprecate, since it's now the same as Window.position.
* Screen.origin: Since there will be no other absolute coordinates in the public API, the only thing an app can do with this information is find out the relative direction of each screen. So the implementation of this property can continue to use the DPI of the primary screen, but the documentation should say that the scale is undefined.

The examples/window app can be used to test this area. Note that the "screen edge" commands are always slightly inaccurate because they don't take the thickness of the title bar and invisible borders into account, but that's not relevant to this issue.

Contributor guide

Open the contributing guide

Research direction

Start with the examples/window app and inspect the Window.position, Window.size, Window.screen_position, Screen.origin, and Screen.size entry points in the Toga interface and WinForms backend. Use the app with screens that have different DPIs to verify the coordinate behavior. Done means the revised coordinate semantics and undefined Screen.origin scale are implemented and documented without breaking the described window operations.

Written by the indexing model from the issue text.

Assessment

Tech stack
python
Domain
desktop
Issue type
Refactor
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.