Solved Windows: Mixed DPI screens and moving a window with move() vs dragging doesn't rescale
-
Qt 5.12.4 on Windows 10
My app stores the locations of its windows so when the user re-opens them they get moved to the last screen that the window was on. The location is sanity checked to make sure it is still valid in case the screens were rearranged or removed. I'm using move() to move the window location as it is created. I don't resize the window and just leave the default size that it had when created. That all worked fine until I HighDPIScaling-enabled my app.
The problem I'm having now is when there are two or more screens that have different font scaling settings in Windows. Normally when you drag a window between screens in this scenario the window size changes automatically just as it pops onto the new screen. However if you move() the window programmatically this doesn't occur and the window size ends up being crazy.
Example:
Screen #1 is set to 200% font scaling
Screen #2 is set to 100% font scalingI create a window and it gets positioned by default on screen #1. However let's say it was previously located on screen #2, so my code move()s it to screen #2. In this case the window stays the same pixel size HxW and now appears twice as large on the screen #2.
However if you manually dragged the window between screen #1 and screen #2, the size would have automatically been taken care of.
The opposite is also true if the font scaling is reversed. Now the window appears on the 200% screen at 1/2 size (but the same pixel size).
On Mac this isn't an issue since macOS handles the HighDPI stuff really well compared to Windows.
I thought about using QScreen and comparing the screen pixel ratios of the screen I'm moving from and the screen I'm moving to, then multiplying the current window size by that ratio and resizing it as I move it.
But that seems like a lot of effort and possibly risk (what happens for 150% font scaling?) for something that is already handled somewhere else (by Qt or Windows?).
Any suggestions on how best to handle this?
-
I found a workable solution. The trick is to use QWindow::setScreen() which redraws the window at the screens scaling.
So I ended up with something like this:
QScreen *m_screen=QGuiApplication::screenAt(position); QWindow *m_handle=this->windowHandle(); if (m_handle && m_screen) { m_handle->setPosition(position); m_handle->setScreen(m_screen); }