I have an app that makes use of several JUCE components that are added to the desktop as native windows (as children of the main window). After changing the Windows display scale back and forth while the app is running, it’s possible for the JUCE desktop windows to end up in a buggy state where their position is correct but their size is incorrect.
The easiest way to reproduce this is to start at a higher scale like 125%, drop to 100%, and go back up to 125%. This reliably breaks the window size (they stay the same physical size that they were at with 100% scaling even after the rest of the desktop is back to 125% scaling).
The bug has two moving parts:
- WM_DPICHANGED is invoked only for top-level windows, not child windows. So the child windows are not resized as a result of the DPI change in handleDPIChanging().
- In HWNDComponentPeer::setBounds(), the hasResized flag compares oldBounds with bounds, but I think it should instead be comparing it with newBounds, which is the DPI-scaled version of the bounds.
What’s happening is that when my app calls setBounds() on the child HWND after the DPI change, the logical size has not changed, and thus hasResized=false, resulting in SWP_NOSIZE and therefore SetWindowPos() does not update the size of the window.
Changing HWNDComponentPeer::setBounds() to compare oldBounds with newBounds solves the problem completely. But also… is it even really necessary to mess with SWP_NOMOVE and SWP_NOSIZE? It seems like it would be simpler and more robust to just unconditionally set the position and size and not even worry about hasMoved/hasResized.