0

I've run into an issue when developing some software for windows, an issue related around moving windows on the screen.

Basically, I've found that specific windows will consitantly not follow the coordinate system. I have a function that takes a window and a ratio, then scales up the window to the max size it can be (in that ratio) and still be within the working area of the monitor (not going over the edges or the taskbar).

Example 1: The function works as intended, sizes the window (VSCode) to be the max size it can be in 4:3, and puts it in the corner of the screen (using SetWindowPos and passing in 0,0 for the coords).

Example 2: The exact same function is run on a different window (Firefox) and it is again resized to 4:3 and set to 0,0. However, this time you can see the window isn't quite in the corner, off by 8 pixels to be exact. If I fetch the window position with the api call for that, it returns 0,0, even though it clearly is not. If I manually snap it into the corner myself, then it returns -8,0.

I have no idea what's wrong or how to fix it. It always happens on the same windows, not exactly sure but I think it has something to do with the type of titlebar the window has.

The only other person I've ever seen with this problem is here: https://answers.microsoft.com/en-us/insider/forum/insider_wintp-insider_desktop/desktop-coordinate-system-is-broken/9e6fd9ab-6d27-45e0-bb55-4c868cd6ac45

Unfortunately, he never got a real answer, so I'm back to square one.

So, any ideas of some way to consistently set windows to actually be in the corner? I've come up with some janky solutions by like trying to dynamically find how much a window offsets from the corner but it's not really something I want to be relying on. Is this just a bug with windows and I'm stuck?

Thanks, let me know if you have any questions!

Jordan J
  • 28
  • 3
  • Put and icon in that area and try clicking the space you see between firefox left and monitor bezel. If you arent able to activate/select the icon by clicking there, that means Firefox might be having a transparent margin in that area. So your window is 0,0 at top left just that there may be a transparent margin left. – Prateek Shrivastava Mar 16 '20 at 04:01
  • @PrateekShrivastava That's a good idea! I just tried that, but I'm not exactly sure, because the window resizing cursor appears when I'm on the edge there and doesn't let me click, I'm not sure if that's because the window is bigger than it actually is, or because the cursor is just too close to the window and it gets activated. However, when I manually use the Win + Left to snap windows, it snaps into the corner fine so I feel like the issue lies somewhere else. – Jordan J Mar 16 '20 at 04:07
  • So what coordinates do you get after Win + Left snapping? is it 0,0 or in negatives? – Prateek Shrivastava Mar 16 '20 at 04:09
  • Just tested, it returns 0,0 when my program puts it at the supposed 0,0, then -8,0 when I win-left snap it in. Oof. – Jordan J Mar 16 '20 at 04:26
  • 1
    DwmGetWindowAttribute : DWMWA_EXTENDED_FRAME_BOUNDS – Jonathan Potter Mar 16 '20 at 04:41
  • May be you detect if users OS is >= Win 10 - then PInvoke Win + Left Api. Otherwise do SetWindowPos. – Prateek Shrivastava Mar 16 '20 at 04:42
  • @JonathanPotter That... Almost works! The Rect it returns has a Left value of 6, which is 2 off of the magic 8. Is there some sort of property I'm missing in the Rect that would give the full 8 pixels that it's off by? https://imgur.com/a/imEVFUL – Jordan J Mar 16 '20 at 06:44
  • What's your system's DPI setting? What's your application's DPI setting? – IInspectable Mar 16 '20 at 07:12

1 Answers1

1

This is the design of windows system.

I saw similar questions long ago.

Windows 10 has thin invisible borders on left, right, and bottom, it is used to grip the mouse for resizing. The borders might look like this: 7,0,7,7 (left, top, right, bottom).

The borders are invisible in Windows 10, so it appears that the window is in the wrong place. Visual Studio IDE has its own tool-windows, when tool-window is docked, it uses no borders or custom NC_PAINT; and when its tool-window is floating, it uses default borders.

A workaroud:

RECT rect, frame;
GetWindowRect(hwnd, &rect);
DwmGetWindowAttribute(hwnd, DWMWA_EXTENDED_FRAME_BOUNDS, &frame, sizeof(RECT));

//rect should be `0, 0, 1280, 1024`
//frame should be `7, 0, 1273, 1017`

RECT border;
border.left = frame.left - rect.left;
border.top = frame.top - rect.top;
border.right = rect.right - frame.right;
border.bottom = rect.bottom - frame.bottom;

//border should be `7, 0, 7, 7`

Then offset the rectangle like so:

rect.left -= border.left;
rect.top -= border.top;
rect.right += border.left + border.right;
rect.bottom += border.top + border.bottom;

//new rect should be `-7, 0, 1287, 1031`

For more information, please refer @Barmak Shemirani's answer.

Similar case:

Retrieve Window Size without Windows Shadows

GetWindowRect returns a size including “invisible” borders

Note: DwmGetWindowAttribute() returns physical coordinates, but GetWindowRect() returns logical coordinates. So the border width will be wrong for a non-DPI aware application on a screen scaled to anything other than 100%.

Strive Sun
  • 4,935
  • 1
  • 4
  • 19
  • This works! And yeah, for some reason I didn't find either of those other questions, I guess my google-fu isn't as good as I thought :/ For reference, I used the code you had, and beforehand doing `SetThreadDpiAwarenessContext(2)` to make the application take into account per-monitor DPI, and that returns the magic 8 pixel wide border I was looking for so I can offset the window. Thank you again! – Jordan J Mar 16 '20 at 17:43