Fix window positioning on Windows when the taskbar is on the top or left#12933
Conversation
Added code to wWinMain in main.cpp to position the window relative to the work area, which may not be at (0, 0) depending on the user's configuration.
There was a problem hiding this comment.
Pull Request Overview
This PR fixes window positioning on Windows when the taskbar is positioned on the top or left edges of the screen by dynamically querying the work area instead of using hardcoded coordinates.
- Replaces hardcoded window position (10, 10) with dynamic positioning based on the system work area
- Adds new Win32Desktop utility module to query the available work area using SystemParametersInfoA
- Calculates window size to ensure it fits within the available work area boundaries
Reviewed Changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| flutter/windows/runner/win32_desktop.h | Header file defining the GetWorkArea function interface |
| flutter/windows/runner/win32_desktop.cpp | Implementation of GetWorkArea to query system work area using Windows API |
| flutter/windows/runner/main.cpp | Updates window positioning logic to use work area-based coordinates |
| flutter/windows/runner/CMakeLists.txt | Adds the new win32_desktop.cpp source file to the build |
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
| { | ||
| RECT workAreaRect; | ||
|
|
||
| if (!SystemParametersInfoA(SPI_GETWORKAREA, 0, &workAreaRect, 0)) |
There was a problem hiding this comment.
Using SystemParametersInfoA (ANSI version) is unnecessary here since no string parameters are involved. Consider using SystemParametersInfo or SystemParametersInfoW for consistency with modern Windows development practices.
| if (!SystemParametersInfoA(SPI_GETWORKAREA, 0, &workAreaRect, 0)) | |
| if (!SystemParametersInfo(SPI_GETWORKAREA, 0, &workAreaRect, 0)) |
There was a problem hiding this comment.
There is no function SystemParametersInfo. It's just a macro that calls either SystemParametersInfoA or SystemParametersInfoW. The parameter in this instance doesn't involve any string values at all, so it is irrelevant which entrypoint is used. I noticed that other existing code uses the ANSI functions for Win32 API calls, such as:
LoadLibraryAinmain.cpp,win32_window.cppGetEnvironmentVariableAinwf_cliprdr.cLoadLibraryExA,GetModuleHandleExA,LoadCursorA,RegisterClassExA,CreateWindowExA,FindWindowExAinmag.rsFormatMessageAinlddController.cShellExecuteAinvirtual_display_manager.rs
These existing ANSI calls were what I immediately saw in the surrounding code, so I used SystemParametersInfoA to follow suit.
But, I do recognize that using the wide-character functions is generally preferable. It avoids an extra layer of indirection in the use of the thunk, and if actual character strings are involved, it also avoids issues where the ANSI code page might not support characters being used, making it impossible to access certain files, properly display messages, etc. Those concerns are irrelevant to a call to SystemParametersInfo with action SPI_GETWORKAREA.
Should I change this call to use the wide-character entrypoint, or leave it using the ANSI endpoint for consistency with adjacent code?
|
Maybe a better way would be to center the main window on the first run? Because the other windows are initially centered.
|
Property centering the window still requires calculations based on the work area. It's not a bad idea, but it does feel out-of-scope for this PR. |
For what it's worth, the The resulting offset is then passed to an API function that expects coordinates that are relative to the work area. The result depends, then, on whether the work area is offset or not. In the common case, where the work area is at (0, 0) and the task bar is at the bottom of the screen, the centring simply ignores the task bar. The space above the window is larger than the space below the window. If the task bar is moved to the top edge of the screen, then it computes an offset as though the work area is at (0, 0), and then passes it into a Win32 API function that treats the coordinates it gets as being relative to the work area, not the raw display bounds. The result is that, since the work area actually starts at e.g. (0, 40), the window is pushed down by 40 pixels (or whatever the task bar's encroachment is). Once again, the space above the window is larger than the space below it, because the window is much lower on the screen than it should be. If the task bar is on the left or right edge, then the same effects happen but along the X axis instead of the Y axis. This is, of course, not a bug in RustDesk. |
Yes. But maybe there is no need to calculate the work area. RustDesk will call If the patch is applied #12933 (comment) , then no need to do the calculation in |
|
Though, the user could reconfigure their desktop between runs. If they launch it with the taskbar on the bottom of the screen, then move the window near the top of the screen, then exit, then move the taskbar to the top of the screen, on the next launch, it will be behind the taskbar. Contrived, yes, but tangible proof of a flaw in the algorithm. |
I don't think there's any need to care about complex cases. RustDesk will save the position and size of the window, and it will restore the window on the next start. All that needs to be considered is:
|
|
The logic for saving and restoring the window position also needs to take the work area into account, because the meaningful numbers are relative to the work area, not relative to the monitor boundaries. If the window is at (10, 70) because the taskbar is using the first 60 pixels, then the saved origin should be (10, 10), and then when it's being restored, if the taskbar is still using the first 60 pixels, it gets added back in to produce (10, 70). If the taskbar has been changed in height or moved elsewhere, then the computed offset is different, but the window is still in the same place relative to the desktop. The desktop icons will also move around with the work area. |
|
This might be a bit of an overkill. I think we are currently just considering centering the window, just like the install window and remote window by default. |
|
From where I'm sitting, calling a 20-line function that calls a system API that only deals in numbers and (probably) can't fail "overkill" is a bit weird, but okay. :-) I am already pursuing correcting |
|
Win7, Win10, Win11 are tested, the work areas are correct. Please:
|
|
My feeling is that centering is outside of the scope of this PR. What I'll do is, I'll make a branch off of this branch and add centering to that, and then I'll make a PR based on that. Then, if you merge this PR, I can rebase that PR as needed, or if you just merge that PR it'll include the work area-related enhancements anyway, either way. |
There was a problem hiding this comment.
Pull Request Overview
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.
…n and size as containing an existing window rectangle, and to find the monitor that contains or is closest to that window. Added function FitToWorkArea to win32_desktop.cpp/.h. Updated main.cpp to use Win32Desktop::FitToWorkArea instead of explicitly constraining the size.
|
In consideration of the distinct possibility of adding code to persist the window bounds in the future, I've made some architectural changes. It's still within the bounds of scope for this PR, but there is now a function I will shortly rebase the |
In Windows versions prior to Windows 11, the Task Bar can be docked to any edge of the screen. Even with Windows 11, this can still be done with third-party tools such as "StartAllBack".
When RustDesk creates its main window, it (currently) supplies a hardcoded window position of (10, 10):
rustdesk/flutter/windows/runner/main.cpp
Line 129 in 3176391
If the Task Bar is on the top or left edge of the screen, the pixel offset (10, 10) might be covered by the task bar. Part of the RustDesk window is thus not visible and inaccessible:
With no visible title bar, the window cannot be dragged to reposition it, and window control widgets located in the title bar are inaccessible. (There is a non-obvious workaround; when a window resize operation completes, Windows automatically crops the resulting rectangle to the active work area, so using any of the visible edges to resize the window causes the top edge of the window to be moved down making the title bar visible.)
This PR addresses this by querying the work area. This indicates the exact coordinate range that is not covered by permanent fixtures such as the Task Bar. The
originandsizeare then computed based on this.The work area is in virtual pixels. If the system desktop scale is not 100%, then the work area is correspondingly scaled. For instance, I'm presently using a 50" TV as my display, native resolution 1920x1080, and if I run it at the standard assumed 96 dpi, the text is difficult to read. So, my desktop scale ("Make everything bigger" in Display settings) is set to 150%. As a result, the work area is returned as (0, 40)-(1280, 720), instead of the actual literal pixel area of (0, 60)-(1920, 1080).
But, this is okay, because the
Win32Windowabstraction being used has, in itsCreateAndShowmethod, code to find the monitor's DPI and scale the coordinates correspondingly. So, the coordinate system fororiginis the same as the scaled frame of reference used for the work area (*as long asoriginis on the primary monitor -- if not, they might be the same but they might not, but in any case the current hardcoded (10, 10) will always be on the primary monitor).I wasn't able to get a build environment set up. The
rustup_init.exetool created abinfolder with all the requisite.exefiles, except they're all 0-byte files. Not sure why. So, I tested this code piecemeal, by copy/pasting it into a smaller project that I can build. It worked there. But, it might require tweaks in situ. I know that's a pain in the butt, and if I figure out why Rust didn't install properly, I'll see if I can't build it locally. In the meantime, I'm hoping someone with a working build environment will take pity on me and do a local build and push any fixes. :-)