於 13 月 前 建立
#22001 new defect
Linux hosts with HiDPI: whenever guest windows on a 2nd screen are auto-resized, they also change position
回報者: | javispedro | 負責人: | |
---|---|---|---|
元件: | GUI | 版本: | VirtualBox-7.0.14 |
關鍵字: | qt | 副本: | |
Guest type: | all | Host type: | Linux |
描述
I have a Linux host with Xorg, KDE, Qt 5.11 (but any 5.x version will do), and 2 identical 4k monitors configured with 2x automatic HiDPI scaling (each monitor is 3840x2160, total desktop resolution is 7680x 2160). The 2nd monitor is logically on the right of the 1st one.
The HiDPI scaling is setup using QT_SCREEN_SCALE_FACTORS (which is what KDE sets when you configure it using the Display preferences applet).
When using this configuration, and if the VBox guest window is on the _2nd_ monitor, whenever I either:
1 ) Select the view -> Adjust Window Size menu action,
2 ) Or the guest changes resolution, and with the "Auto-resize Guest Display" option enabled, VirtualBox tries to resize the guest window in the host...
Then the window will successfully resize, but it will also inadvertently move to the right edge of the 2nd monitor.
This does not happen if the window was placed in the 1st monitor. The window will resize and stay in its position correctly.
I have diagnosed this down to the X11-specific "workaround" on UIDesktopWidgetWatchdog::setTopLevelGeometry . Disabling the workaround there (i.e., calling QWidget::setGeometry directly as in the other platforms) fixes the issue.
The explanation boils down to HiDPI scaling. When using Qt's DPI scaling, coordinates are scaled down so that each monitor appears to be 1920x1080 instead of 4k. However, this does not mean that the total multi-monitor logical desktop size is 3840x1080, as you'd expect from having 2x 1920 monitors side-by-side, and as the setTopLevelGeometry function is assuming. Rather, Qt still places the top-left logical coordinate of the second monitor at the unscaled position: +3840+0 .
This means that Qt pretends the geometry for a full-screen window in the second monitor is 1920x1080 at position +3840+0 , and not at position +1920+0.
If Qt's setGeometry function is called, this trickery is handled correctly, however the "workaround" at UIDesktopWidgetWatchdog::setTopLevelGeometry does not: it will just divide the coordinates by the current scale factor. It will use Qt to get the geometry (+3840), but then call xcb directly with the coordinates divided by two. The window will be placed in an "impossible" location according to the above Qt logic and it will appear to "jump" around.
I am not sure how to fix the issue myself, as I can see the utility of the workaround in UIDesktopWidgetWatchdog::setTopLevelGeometry (I guess tiling window managers can refuse ConfigureRequests?) , so writing this down here in case anyone has any ideas.