Skip to content

Conversation

ShahzaibIbrahim
Copy link
Contributor

@ShahzaibIbrahim ShahzaibIbrahim commented Aug 18, 2025

GetWindowRect returns the bounding rectangle of the entire window including invisible shadows and glass margins. This leads to Shell#getLocation reporting coordinates that do not match the actual visible frame location. For example, when positioning a dialog close to the left edge of a monitor, the reported X coordinate can be shifted by ~9 pixels compared to the visible window frame. The same discrepancy appears when opening dialogs under a maximized parent shell.

This patch changes Shell#getLocation to use:

DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, ...)

This API returns the extended frame bounds rectangle in screen space, which corresponds to the true visible window frame and excludes the transparent shadow margins. This produces values that align with what the user sees on screen and avoids subtle layout issues in multi-monitor or mixed-DPI setups.

If DWM is not available (e.g., on older Windows versions or when composition is disabled), the implementation falls back to GetWindowRect, preserving backward compatibility.

Benefits:

  • Correct window coordinates near monitor edges.
  • No more shadow-margin offset (~9px) in reported locations.
  • Consistent behavior across normal, minimized, and maximized shells.

Steps to Reproduce

  • Run the runtime workspace with monitor specific scaling turned on.
  • Move the window to secondary monitor on the right (could be of any zoom)
  • Resize the window to smaller size
  • Open the "Open Type" window using Ctrl + Shift + T
  • Move the Open Type window towards very left of the screen.
  • Close Open Type window
  • Maximize the size of main window.
  • Open the Open Type dialog again
  • You will see the dialog appearing on the left monitor instead of where it was last closed (on the right monitor)

Expected result

The sub-shell or dialog should open where it was last closed. There should be no shadow margins that leads to change of coordinates and resulting in window opening in the other monitor.

Copy link
Contributor

github-actions bot commented Aug 18, 2025

Test Results

   546 files  ±0     546 suites  ±0   33m 44s ⏱️ + 4m 19s
 4 426 tests ±0   4 409 ✅ ±0   17 💤 ±0  0 ❌ ±0 
16 750 runs  ±0  16 623 ✅ ±0  127 💤 ±0  0 ❌ ±0 

Results for commit 49cfcde. ± Comparison against base commit d5dc661.

♻️ This comment has been updated with latest results.

GetWindowRect includes invisible shadow borders on Windows 10/11, causing Shell#getLocation to return coordinates offset by ~9px from the visible frame. Replaced with DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) to report the true window bounds in screen space, with GetWindowRect as a fallback if DWM is unavailable.
Copy link
Contributor

@HeikoKlare HeikoKlare left a comment

Choose a reason for hiding this comment

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

The change looks good when using monitor-specific UI scaling and significantly improves UX in that case: shells properly open on the correct monitor and not on the monitor to the left if the parent is maximized. The given reproducer is a good way to test it.

For testing I have added some logging of the new and old values to compare where one can see that the x values are off by some pixels:

old: 140, 127; new: 147, 127 old: 88, 67; new: 95, 67 old: -8, -8; new: 0, 0 old: -8, -8; new: 0, 0 old: 44, 52; new: 51, 52 old: 44, 52; new: 51, 52 old: 1501, 1292; new: 1501, 1292 old: 1501, 1292; new: 1501, 1292 old: 37, 52; new: 44, 52 old: 34, 52; new: 41, 52 old: 31, 52; new: 38, 52 old: 28, 52; new: 35, 52 old: 24, 52; new: 31, 52 old: 22, 52; new: 29, 52 old: 18, 53; new: 25, 53 old: 15, 54; new: 22, 54 old: 13, 54; new: 20, 54 old: 10, 54; new: 17, 54 old: 7, 54; new: 14, 54 old: 4, 55; new: 11, 55 old: 3, 55; new: 10, 55 old: 2, 55; new: 9, 55 old: 1, 55; new: 8, 55 old: -1, 55; new: 6, 55 old: -2, 55; new: 5, 55 old: -3, 55; new: 4, 55 old: -4, 55; new: 3, 55 old: -5, 55; new: 2, 55 old: -7, 55; new: 0, 55 old: -8, 54; new: -1, 54

However, the change is incompatible with monitor-specific scaling being disabled. In that case, the offset between the two values is incorporated when reopening a shell, leading it to slightly move to the right on every reopen. See this capture:
shell_reopen_offset

Some interesting information on the issue in general can also be found here: https://stackoverflow.com/questions/34139450/getwindowrect-returns-a-size-including-invisible-borders

return new Point (rect.left, rect.top);
RECT rect = new RECT();
int hr = OS.DwmGetWindowAttribute(handle, OS.DWMWA_EXTENDED_FRAME_BOUNDS, rect, RECT.sizeof);
if (hr != 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

To improve comprehensibility:

Suggested change
if (hr != 0) {
if (hr != OS.S_OK) {

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.

Improve Shell#getLocation OS calls
3 participants