Author: Olivier Tilloy <olivier.tilloy@canonical.com>
Description: Do not rely on _NET_WORKAREA for availableGeometry(screen)
 _NET_WORKAREA is not reliable as it exposes only one rectangular area
 spanning all screens.
Bug: http://bugreports.qt.nokia.com/browse/QTBUG-18380

diff --git a/src/gui/kernel/qapplication_x11.cpp b/src/gui/kernel/qapplication_x11.cpp
index e0447cc..099c309 100644
--- a/src/gui/kernel/qapplication_x11.cpp
+++ b/src/gui/kernel/qapplication_x11.cpp
@@ -218,6 +218,7 @@ static const char * x11_atomnames = {
 
     // EWMH (aka NETWM)
     "_NET_SUPPORTED\0"
+    "_NET_CLIENT_LIST\0"
     "_NET_VIRTUAL_ROOTS\0"
     "_NET_WORKAREA\0"
 
@@ -242,6 +243,8 @@ static const char * x11_atomnames = {
     "_NET_WM_STATE_STAYS_ON_TOP\0"
     "_NET_WM_STATE_DEMANDS_ATTENTION\0"
 
+    "_NET_WM_STRUT_PARTIAL\0"
+
     "_NET_WM_USER_TIME\0"
     "_NET_WM_USER_TIME_WINDOW\0"
     "_NET_WM_FULL_PLACEMENT\0"
diff --git a/src/gui/kernel/qdesktopwidget_x11.cpp b/src/gui/kernel/qdesktopwidget_x11.cpp
index b0f1290..0f9c267 100644
--- a/src/gui/kernel/qdesktopwidget_x11.cpp
+++ b/src/gui/kernel/qdesktopwidget_x11.cpp
@@ -285,42 +285,83 @@ const QRect QDesktopWidget::availableGeometry(int screen) const
     if (d->workareas[screen].isValid())
         return d->workareas[screen];
 
-    if (X11->isSupportedByWM(ATOM(_NET_WORKAREA))) {
+    QRect available = screenGeometry(screen);
+
+    if (X11->isSupportedByWM(ATOM(_NET_CLIENT_LIST)) &&
+        X11->isSupportedByWM(ATOM(_NET_WM_STRUT_PARTIAL))) {
+        // Iterate over all the client windows and subtract from the available
+        // area the space they reserved on the edges (struts).
+        // Note: _NET_WORKAREA is not reliable as it exposes only one
+        // rectangular area spanning all screens.
+
         int x11Screen = isVirtualDesktop() ? DefaultScreen(X11->display) : screen;
 
         Atom ret;
-        int format, e;
-        unsigned char *data = 0;
-        unsigned long nitems, after;
-
-        e = XGetWindowProperty(X11->display,
-                               QX11Info::appRootWindow(x11Screen),
-                               ATOM(_NET_WORKAREA), 0, 4, False, XA_CARDINAL,
-                               &ret, &format, &nitems, &after, &data);
-
-        QRect workArea;
-        if (e == Success && ret == XA_CARDINAL &&
-            format == 32 && nitems == 4) {
-            long *workarea = (long *) data;
-            workArea = QRect(workarea[0], workarea[1], workarea[2], workarea[3]);
-        } else {
-            workArea = screenGeometry(screen);
-        }
-
-        if (isVirtualDesktop()) {
-            // intersect the workarea (which spawns all Xinerama screens) with the rect for the
-            // requested screen
-            workArea &= screenGeometry(screen);
+        int format, status;
+        uchar* data = 0;
+        ulong nitems, after;
+
+        status = XGetWindowProperty(X11->display, QX11Info::appRootWindow(x11Screen),
+                                    ATOM(_NET_CLIENT_LIST), 0L, ~0L, False, XA_WINDOW,
+                                    &ret, &format, &nitems, &after, &data);
+
+        if (status == Success && ret == XA_WINDOW && format == 32 && nitems) {
+            const QRect desktopGeometry = rect();
+
+            Window* xids = (Window*) data;
+            for (quint32 i = 0; i < nitems; ++i) {
+                ulong nitems2;
+                uchar* data2 = 0;
+                status = XGetWindowProperty(X11->display, xids[i],
+                                            ATOM(_NET_WM_STRUT_PARTIAL), 0, 12, False, XA_CARDINAL,
+                                            &ret, &format, &nitems2, &after, &data2);
+
+                if (status == Success && ret == XA_CARDINAL && format == 32 && nitems2 == 12) {
+                    ulong* struts = (ulong*) data2;
+
+                    QRect left(desktopGeometry.x(),
+                               desktopGeometry.y() + struts[4],
+                               struts[0],
+                               struts[5] - struts[4]);
+                    if (available.intersects(left)) {
+                        available.setX(left.width());
+                    }
+
+                    QRect right(desktopGeometry.x() + desktopGeometry.width() - struts[1],
+                                desktopGeometry.y() + struts[6],
+                                struts[1],
+                                struts[7] - struts[6]);
+                    if (available.intersects(right)) {
+                        available.setWidth(right.x() - available.x());
+                    }
+
+                    QRect top(desktopGeometry.x() + struts[8],
+                              desktopGeometry.y(),
+                              struts[9] - struts[8],
+                              struts[2]);
+                    if (available.intersects(top)) {
+                        available.setY(top.height());
+                    }
+
+                    QRect bottom(desktopGeometry.x() + struts[10],
+                                 desktopGeometry.y() + desktopGeometry.height() - struts[3],
+                                 struts[11] - struts[10],
+                                 struts[3]);
+                    if (available.intersects(bottom)) {
+                        available.setHeight(bottom.y() - available.y());
+                    }
+                }
+                if (data2) {
+                    XFree(data2);
+                }
+            }
         }
-
-        d->workareas[screen] = workArea;
-
-        if (data)
+        if (data) {
             XFree(data);
-    } else {
-        d->workareas[screen] = screenGeometry(screen);
+        }
     }
 
+    d->workareas[screen] = available;
     return d->workareas[screen];
 }
 
diff --git a/src/gui/kernel/qt_x11_p.h b/src/gui/kernel/qt_x11_p.h
index 8ab129c..602aced 100644
--- a/src/gui/kernel/qt_x11_p.h
+++ b/src/gui/kernel/qt_x11_p.h
@@ -577,6 +577,7 @@ struct QX11Data
 
         // EWMH (aka NETWM)
         _NET_SUPPORTED,
+        _NET_CLIENT_LIST,
         _NET_VIRTUAL_ROOTS,
         _NET_WORKAREA,
 
@@ -601,6 +602,8 @@ struct QX11Data
         _NET_WM_STATE_STAYS_ON_TOP,
         _NET_WM_STATE_DEMANDS_ATTENTION,
 
+        _NET_WM_STRUT_PARTIAL,
+
         _NET_WM_USER_TIME,
         _NET_WM_USER_TIME_WINDOW,
         _NET_WM_FULL_PLACEMENT,
