Skip to content
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

[conhost] Fix WM_GETDPISCALEDSIZE handler, use provided size instead of current window size #18268

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

ekoschik
Copy link
Contributor

@ekoschik ekoschik commented Dec 2, 2024

Summary of the Pull Request

The conhost window uses the window message WM_GETDPISCALEDSIZE to scale its client rect non-linearly. This is done to keep the rows and columns from changing when the window changes (font sizes scale non-linearly). If you size the window such that the text perfectly fits the width (and cursor is on the first row of the next line), dragging the window between monitors with different DPIs should NOT change how much of the text fits on each line.

https://learn.microsoft.com/en-us/windows/win32/hidpi/wm-getdpiscaledsize

The current code is assuming that the size that should be scaled is the current window size. This is sometimes the case, for example when dragging a window between monitors, but it is not always the case. This message can sometimes contain a size that is different from the window's current size. For example, if the window is maximized, minimized, or snapped (the size in these cases is the normal rect, or restore rect).

The msdn page above does (now) call this out, though it is possible that this was added after this conhost code was added...

The LPARAM is an in/out pointer to a SIZE struct. The In value in the LPARAM is the pending size of the window after a user-initiated move or a call to SetWindowPos. If the window is being resized, this size is not necessarily the same as the window's current size at the time this message is received.

This incorrect assumption can cause the conhost window to be unexpectedly large/small in some cases. For example:

  1. Requires two monitors, set to different DPIs.
  2. Size window somewhat small, and type text to fit exactly the width of the window, putting cursor on first row of next line.
  3. Win+Left (or otherwise snap/arrange the window).
  4. Win+Shift+Left (migrates the window to the other monitor)
  5. Win+Shift+Down (restore window, can also click maximize caption button twice, maximizing then restoring)

Expected: The window should restore to the original logical size, with the text perfectly fitting one line.

Actual: The window restores to another size; it is the snapped size on the original monitor (the size of the window at the time it was changing DPI, in step 4 above).

References and Relevant Issues

This message (WM_GETDPISCALEDSIZE) is not widely used, but it is used by dialogs (user32!CreateDialog), since they also size their windows using font sizes. The code in this change borrows from the code in the dialog manager, user32!GetDialogDpiScaledSize.

Detailed Description of the Pull Request / Additional comments

The WM_GETDPISCALEDSIZE message contains the new DPI and the new size, which is an in/out parameter. It starts as the new window size, scaled to the window's current DPI, and is expected to be scaled to the new DPI.

The client area (the part with the text) is NOT scaled linearly. For example, if the font at 100% DPI has a height of 7, it could have a height of 15 at 200%. (And if it did have a height of 14, linearly scaled, it would surely not be linearly scaled at 150%, since fonts cannot have a height of 10.5.) To pick the right size, we need to resolve the font at the new DPI and use its actual size to scale the client area.

To keep the amount of text in the window the same, we need to remove the non-client area of the window (caption bars, resize borders, etc). The non-client area is outside the area with the text, and its size depends on the window's DPI and window styles. To remove it and add it back, we need to:

  • Reduce the provided window rect size by the non-client size at the current DPI.
  • Scale the client size using the new/old font sizes.
  • Expand the final size by the non-client size at the new DPI.

Validation Steps Performed

PR Checklist

  • Closes #xxx
  • Tests added/passed
  • Documentation updated
    • If checked, please file a pull request on our docs repo and link it here: #xxx
  • Schema updated (if necessary)

Comment on lines +870 to +875
if (!SUCCEEDED(ServiceLocator::LocateGlobals().pRender->GetProposedFont(
dpiNew, fontInfoDesired, fontInfoNew)))
{
return false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason you chose to replace the previous

const auto coordFontProposed = SUCCEEDED(hr) ? fiProposed.GetSize() : til::size{ 1, 1 };

?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the question about handling cases where getting the speculative font fails? If we cannot resolve the new font size, the new version will return false from WM_GETDPISCALEDSIZE, instead of filling in a size. This falls back to default processing, window size linearly scaled for dpi change.

@DHowett
Copy link
Member

DHowett commented Dec 3, 2024

(Marking this one blocked per e-mail)

Copy link
Member

@DHowett DHowett left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@microsoft-github-policy-service microsoft-github-policy-service bot added the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Dec 3, 2024
@microsoft-github-policy-service microsoft-github-policy-service bot added the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Dec 10, 2024
@DHowett DHowett reopened this Dec 18, 2024
@DHowett DHowett removed the No-Recent-Activity This issue/PR is going stale and may be auto-closed without further activity. label Dec 18, 2024
@ekoschik ekoschik force-pushed the user/evkoschi/getDpiScaledSize branch from 2bfd71c to f6093ec Compare December 20, 2024 00:05
@microsoft-github-policy-service microsoft-github-policy-service bot removed the Needs-Author-Feedback The original author of the issue/PR needs to come back and respond to something label Dec 20, 2024
@ekoschik
Copy link
Contributor Author

@microsoft-github-policy-service agree

@ekoschik please read the following Contributor License Agreement(CLA). If you agree with the CLA, please reply with the following information.

@microsoft-github-policy-service agree [company="{your company}"]

Options:

  • (default - no company specified) I have sole ownership of intellectual property rights to my Submissions and I am not making Submissions in the course of work for my employer.
@microsoft-github-policy-service agree
  • (when company given) I am making Submissions in the course of work for my employer (or my employer has intellectual property rights in my Submissions by contract or applicable law). I have permission from my employer to make Submissions and enter into this Agreement on behalf of my employer. By signing below, the defined term “You” includes me and my employer.
@microsoft-github-policy-service agree company="Microsoft"

Contributor License Agreement

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants