-
-
Notifications
You must be signed in to change notification settings - Fork 671
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improved DPI Scaling on Windows and Fixed related Bugs #2155
base: main
Are you sure you want to change the base?
Conversation
I have added an event handler to detect DPI changes while the app is running. I have also modified Scalable class to:
The latest commit detects the DPI changes of the Primary Screen only. But this will be fixed in #1930, where the DPI scale factor of each screen will be detected individually and will be used to do the scaling. I have tested the latest commit and it correctly detects new DPI change and scales the elements accordingly. However, the fonts' don't seem to be using the latest DPI value and as such they are not being scaled when a new DPI change is detected while the app is running. This needs to be fixed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for looking into this, I think you're on the right track.
The latest commit detects the DPI changes of the Primary Screen only. But this will be fixed in #1930, where the DPI scale factor of each screen will be detected individually and will be used to do the scaling.
WinForms has some per-window events for detecting DPI changes, which I think would allow this to be fixed without requiring Toga to be aware of multiple screens. That would allow us to fix all the DPI issues together in this PR, so I've added a "fixes" link to the top comment.
A few more comments:
I have tested them previously and was thinking about using DpiChanged event & DeviceDpiNew: https://learn.microsoft.com/en-us/dotnet/api/system.windows.forms.dpichangedeventargs.devicedpinew?view=windowsdesktop-7.0#system-windows-forms-dpichangedeventargs-devicedpinew But, none of these events trigger when the system DPI changes. Only the SystemEvents.DisplaySettingsChanged event is triggered consistently when system DPI changes. I am searching for a proper way to address this and will let you know as soon as I find a viable solution. |
I have added support so that the font scales when the DPI changes while the app is running. I have also added Screen as an optional dependency to Scalable class, so that the DPI can be found for the current screen, without the need for the API in #1930, while still allowing other APIs to use scale_in and scale_out methods. The following is the same run of the test script with the latest commit: The fonts scale correctly and detect the DPI changes while the app is running. |
Nevermind. The bug was caused due to the faulty implementation of WeakRef introduced in #2066 and reported in #2163. toga/winforms/src/toga_winforms/window.py Line 36 in 7a46d41
After removing the WeakRef wrapping, the resizing event handler appears to fire consistently when the DPI scale is changed. Here is the app after fixing the bug: So, this bug will be resolved automatically when #2163 is addressed. Looks like the weakref calls in different places are causing problems. I wonder if this is also leading to failing of the tests on windows testbed. |
To be clear - the tests are not failing on main at present. If they're failing in this PR, it's either an unintended side effect of something in this PR, or an error that isn't 100% reproducible. The latter does happen sometimes - it's the nature of running a GUI test that sometimes, the GUI doesn't respond quite quickly enough, which results in a test failure. Re-running the test will (usually) fix these problems; however, I've just re-run the tests, and the same problem is occurring, which suggests it likely isn't a transient problem - it's an unintended side effect. From a quick inspection, I can't see any obvious connection between this PR's changes and OptionContainer. However, I can confirm that when I run the optioncontainer tests, I see the problem locally, and if I remove the Weakref usage from OptionContainer, the problem remains. |
In that case, I'll search further and report back what is causing the tests to fail. |
Turns out the bugs were related to Hwnds being created at inappropriate times. As discussed in #2155 (comment), the Hwnds are being created even before the Application instance is created. I have fixed the current bug by initializing and disposing a graphics context at the time of widget Hwnd creation. But, I recon more bugs related to Hwnd will be encountered in the future due to the way toga app execution flow works. But that's for the future. |
I have updated to latest main branch. The dpi scaling is working properly. But between the last time I had updated to the latest main branch and now, something has changed in the main branch due to which it reports wrong
P.S. If you suspect anything that might be causing these bugs, then please let me know. |
On doing a deeper inspection, I have found that when dpi awareness is enabled, the following things happen:
This complicates things, since earlier, to move a window to the right side of the screen, we could do: self.main_window.screen_position = (
(self.main_window.screen.size.width - self.main_window.size.width),
self.main_window.position.y,
) But now, we need to do: self.main_window.screen_position = (
(self.main_window.screen.size.width - self.main_window.size.width*(dpi_scale)),
self.main_window.position.y,
) |
@mhsmith I would greatly appreciate your feedback regarding this new issue. |
@mhsmith friendly reminder to take a look look at this, as soon as you are free. |
@mhsmith Just a gentle nudge to take a look at this whenever you are free. |
This was a bad idea, because it assumes that the window's physical size remains unchanged, which we've already found wasn't happening on @proneon267's machine. But the tests still passed for him because they didn't actually contain any assertions, only comparisons with no I'll replace this with a different approach. |
Actually, disregard my previous comment (apart from the tests having no assertions) -- the window's physical size will always remain unchanged, because it's only a mock DPI change, not a real one. |
I'm working on the tests at the moment, so you don't need to push any more changes. |
Thanks for helping :) and apologies for causing any trouble. |
|
I think all these newer DPI related events will not be triggered unless DPI awareness is specified in a manifest file, which I haven't been able to figure out. Btw, the new test looks great :) |
While investigating the scaling problems encountered in #1930, I found that the call to
SetProcessDpiAwarenessContext
is erroneous. Hence, all the toga apps are always running in the DPI Unaware mode.This PR fixes the call and also checks if it was successful or not.
Note that this PR only has changes that fix the call to
SetProcessDpiAwarenessContext
, so that the call works. It doesn't fix any of the scaling issues currently present in toga. In particular, the test script from #1930, still shows the scaling bugs:At 125% scaling:
As you can see, the
DpiX
anddpi_scale
will always be 96 and 1.0 respectively. Furthermore, in the DPI Aware mode, the app menu has a disproportionately larger size compared to the rest of the window elements.Both of these bugs, indicate that there are problems in the scaling on windows. But those are for separate PRs.
Also, if required, I can add the code to correctly detect the actual system dpi.
PR Checklist: