xcb: don't rely on _NET_WORKAREA for available geometry on multi-head systems
On X11, QScreen::availableGeometry() is broken with multi-head systems, and there doesn't seem to be a real fix for this due to limitation in the protocol and therefore support in WMs (more details in the patch). In Gnome this issue is more visible because on this DE the _NET_WORKAREA rectangle represents the intersection of the available geometries on all monitors. This results in a big area of "dead space" on the secondary screen, when primary screen is positioned lower in the virtual space. If menu is opened by clicking in this dead space, the menu is awfully misplaced (qmenu uses availableGeometry() to calculate the position of menu). On Ubuntu with Unity (same is true for KDE Neon+Kwin and LUbuntu+Openbox), _NET_WORKAREA returns a bounding rectangle containing all monitors. Which does not cause the menu misplacement as "dead space" is outside clickable area. But this does not mean that the QScreen::availableGeometry() reported values are correct. With the same setup as described above, QScreen::availableGeometry() thinks that we have a tool panel on the right screen, when in reality it is on the left screen. AwesomeWM for example does not set _NET_WORKAREA at all, which means QScreen::availableGeometry() == QScreen::geometry(). I am not aware that it would cause any issues for popup/menu window positioning in Qt (Qt positions these windows manually by bypassing WM (via Qt::BypassWindowManagerHint) and using availableGeometry for calculations. With this patch, we would take the same code path as if _NET_WORKAREA was not set (where we know that_NET_WORKAREA is cleary wrong). The solution here is to recognize _NET_WORKAREA as true available geometry only in specific cases (cases where the meaning is cleary defined by the specification) and adjust the documentation accordingly. Not knowing the true available geometry on X11 is mitigated by WMs. Window manager can position windows as it wants. WMs are smart enough not to place windows on top of reserved areas at edges (even if user has explicitly requested this via setGeometry based on inaccurate information from availableGeometry()). [ChangeLog][Platform Specific Changes][Linux] The _NET_WORKAREA atom is used for calculating QScreen::availableGeometry() only on systems with one monitor. In all other cases QScreen::availableGeometry() is equal to QScreen::geometry(). To restore the legacy behavior with untrustworthy values in QScreen::availableGeometry() set QT_RELY_ON_NET_WORKAREA_ATOM=1 environment variable. Task-number: QTBUG-60513 Task-number: QTBUG-29278 Task-number: QTBUG-43768 Task-number: QTBUG-18380 Change-Id: I7e0f62f81d1444991b8a6c007c2527d8f96088c2 Reviewed-by: Uli Schlachter <psychon@znc.in> Reviewed-by: Lars Knoll <lars.knoll@qt.io>
This commit is contained in:
parent
6c2bfbf88e
commit
5a1f1345aa
@ -384,6 +384,10 @@ QRect QScreen::geometry() const
|
||||
|
||||
The available geometry is the geometry excluding window manager reserved areas
|
||||
such as task bars and system menus.
|
||||
|
||||
Note, on X11 this will return the true available geometry only on systems with one monitor and
|
||||
if window manager has set _NET_WORKAREA atom. In all other cases this is equal to geometry().
|
||||
This is a limitation in X11 window manager specification.
|
||||
*/
|
||||
QRect QScreen::availableGeometry() const
|
||||
{
|
||||
|
@ -188,6 +188,23 @@ void QXcbVirtualDesktop::subscribeToXFixesSelectionNotify()
|
||||
}
|
||||
}
|
||||
|
||||
/*! \internal
|
||||
|
||||
Using _NET_WORKAREA to calculate the available desktop geometry on multi-head systems (systems
|
||||
with more than one monitor) is unreliable. Different WMs have different interpretations of what
|
||||
_NET_WORKAREA means with multiple attached monitors. This gets worse when monitors have
|
||||
different dimensions and/or screens are not virtually aligned. In Qt we want the available
|
||||
geometry per monitor (QScreen), not desktop (represented by _NET_WORKAREA). WM specification
|
||||
does not have an atom for this. Thus, QScreen is limted by the lack of support from the
|
||||
underlying system.
|
||||
|
||||
One option could be that Qt does WM's job of calculating this by subtracting geometries of
|
||||
_NET_WM_STRUT_PARTIAL and windows where _NET_WM_WINDOW_TYPE(ATOM) = _NET_WM_WINDOW_TYPE_DOCK.
|
||||
But this won't work on Gnome 3 shell as it seems that on this desktop environment the tool panel
|
||||
is painted directly on the root window. Maybe there is some Gnome/GTK API that could be used
|
||||
to get height of the panel, but I did not find one. Maybe other WMs have their own tricks, so
|
||||
the reliability of this approach is questionable.
|
||||
*/
|
||||
QRect QXcbVirtualDesktop::getWorkArea() const
|
||||
{
|
||||
QRect r;
|
||||
@ -556,6 +573,14 @@ void QXcbScreen::sendStartupMessage(const QByteArray &message) const
|
||||
} while (sent < length);
|
||||
}
|
||||
|
||||
QRect QXcbScreen::availableGeometry() const
|
||||
{
|
||||
static bool enforceNetWorkarea = !qEnvironmentVariableIsEmpty("QT_RELY_ON_NET_WORKAREA_ATOM");
|
||||
bool isMultiHeadSystem = virtualSiblings().length() > 1;
|
||||
bool useScreenGeometry = isMultiHeadSystem && !enforceNetWorkarea;
|
||||
return useScreenGeometry ? m_geometry : m_availableGeometry;
|
||||
}
|
||||
|
||||
QImage::Format QXcbScreen::format() const
|
||||
{
|
||||
return qt_xcb_imageFormatForVisual(connection(), screen()->root_depth, visualForId(screen()->root_visual));
|
||||
|
@ -154,7 +154,7 @@ public:
|
||||
QString serialNumber() const override;
|
||||
|
||||
QRect geometry() const override { return m_geometry; }
|
||||
QRect availableGeometry() const override {return m_availableGeometry;}
|
||||
QRect availableGeometry() const override;
|
||||
int depth() const override { return screen()->root_depth; }
|
||||
QImage::Format format() const override;
|
||||
QSizeF physicalSize() const override { return m_sizeMillimeters; }
|
||||
|
@ -152,7 +152,7 @@
|
||||
on \macos, or the task bar on Windows). The default screen is used if
|
||||
\a screen is -1.
|
||||
|
||||
\sa screenNumber(), screenGeometry()
|
||||
\sa screenNumber(), screenGeometry(), QScreen::availableGeometry()
|
||||
*/
|
||||
|
||||
/*!
|
||||
|
Loading…
Reference in New Issue
Block a user