File xcb-dont-rely-on-_NET_WORKAREA_for_available_geometry.patch of Package libqt5-qtbase.13634

From b021ce5cb3c135dc60a4155b8840d1d01e7f54fb Mon Sep 17 00:00:00 2001
From: Gatis Paeglis <gatis.paeglis@qt.io>
Date: Fri, 21 Jul 2017 14:01:56 +0200
Subject: [PATCH] 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>
---
 src/gui/kernel/qscreen.cpp               |  4 ++++
 src/plugins/platforms/xcb/qxcbscreen.cpp | 25 ++++++++++++++++++++++++
 src/plugins/platforms/xcb/qxcbscreen.h   |  2 +-
 src/widgets/kernel/qdesktopwidget.qdoc   |  2 +-
 4 files changed, 31 insertions(+), 2 deletions(-)

diff --git a/src/gui/kernel/qscreen.cpp b/src/gui/kernel/qscreen.cpp
index 96f75f3..479e228 100644
--- a/src/gui/kernel/qscreen.cpp
+++ b/src/gui/kernel/qscreen.cpp
@@ -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
 {
diff --git a/src/plugins/platforms/xcb/qxcbscreen.cpp b/src/plugins/platforms/xcb/qxcbscreen.cpp
index ce1d541..d59f8ec 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.cpp
+++ b/src/plugins/platforms/xcb/qxcbscreen.cpp
@@ -127,6 +127,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;
@@ -450,6 +467,14 @@ quint8 QXcbScreen::depthOfVisual(xcb_visualid_t visualid) const
     return *it;
 }
 
+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));
diff --git a/src/plugins/platforms/xcb/qxcbscreen.h b/src/plugins/platforms/xcb/qxcbscreen.h
index 4163be2..95fbb79 100644
--- a/src/plugins/platforms/xcb/qxcbscreen.h
+++ b/src/plugins/platforms/xcb/qxcbscreen.h
@@ -120,7 +120,7 @@ public:
     QWindow *topLevelAt(const QPoint &point) 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; }
diff --git a/src/widgets/kernel/qdesktopwidget.qdoc b/src/widgets/kernel/qdesktopwidget.qdoc
index 27d05ec..fdf6a27 100644
--- a/src/widgets/kernel/qdesktopwidget.qdoc
+++ b/src/widgets/kernel/qdesktopwidget.qdoc
@@ -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()
 */
 
 /*!
-- 
2.24.0

openSUSE Build Service is sponsored by