-
Notifications
You must be signed in to change notification settings - Fork 180
Use DwmGetWindowAttribute for Shell#getLocation to avoid shadow margins #2426
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
base: master
Are you sure you want to change the base?
Conversation
9395761
to
8a135d1
Compare
bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java
Outdated
Show resolved
Hide resolved
bundles/org.eclipse.swt/Eclipse SWT/win32/org/eclipse/swt/widgets/Shell.java
Outdated
Show resolved
Hide resolved
bundles/org.eclipse.swt/Eclipse SWT PI/win32/org/eclipse/swt/internal/win32/OS.java
Outdated
Show resolved
Hide resolved
8a135d1
to
a4ebaa5
Compare
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.
a4ebaa5
to
49cfcde
Compare
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.
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:
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:
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) { |
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.
To improve comprehensibility:
if (hr != 0) { | |
if (hr != OS.S_OK) { |
GetWindowRect
returns the bounding rectangle of the entire window including invisible shadows and glass margins. This leads toShell#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: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:
Steps to Reproduce
Ctrl + Shift + T
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.