Fixed non-GL applications crashing when GLX/EGL initialization fails on xcb.
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbwindow.cpp
index 8e01c8e..7020e63 100644 (file)
@@ -1,8 +1,7 @@
 /****************************************************************************
 **
-** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
-** All rights reserved.
-** Contact: Nokia Corporation (qt-info@nokia.com)
+** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/
 **
 ** This file is part of the plugins of the Qt Toolkit.
 **
@@ -35,6 +34,7 @@
 **
 **
 **
+**
 ** $QT_END_LICENSE$
 **
 ****************************************************************************/
 
 #include <QtDebug>
 #include <QScreen>
+#include <QtGui/QIcon>
+#include <QtGui/QRegion>
 
 #include "qxcbconnection.h"
 #include "qxcbscreen.h"
 #include "qxcbdrag.h"
 #include "qxcbkeyboard.h"
 #include "qxcbwmsupport.h"
+#include "qxcbimage.h"
+
+#include <qpa/qplatformintegration.h>
 
 #ifdef XCB_USE_DRI2
 #include "qdri2context.h"
 #include <xcb/xcb_icccm.h>
 #undef class
 #include <xcb/xfixes.h>
+#ifndef QT_NO_SHAPE
+#  include <xcb/shape.h>
+#endif // QT_NO_SHAPE
 
 // xcb-icccm 3.8 support
 #ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
 #define xcb_get_wm_hints_reply xcb_icccm_get_wm_hints_reply
 #define xcb_get_wm_hints xcb_icccm_get_wm_hints
+#define xcb_get_wm_hints_unchecked xcb_icccm_get_wm_hints_unchecked
 #define xcb_set_wm_hints xcb_icccm_set_wm_hints
 #define xcb_set_wm_normal_hints xcb_icccm_set_wm_normal_hints
 #define xcb_size_hints_set_base_size xcb_icccm_size_hints_set_base_size
@@ -75,6 +84,7 @@
 #define xcb_size_hints_set_win_gravity xcb_icccm_size_hints_set_win_gravity
 #define xcb_wm_hints_set_iconic xcb_icccm_wm_hints_set_iconic
 #define xcb_wm_hints_set_normal xcb_icccm_wm_hints_set_normal
+#define xcb_wm_hints_set_input xcb_icccm_wm_hints_set_input
 #define xcb_wm_hints_t xcb_icccm_wm_hints_t
 #define XCB_WM_STATE_ICONIC XCB_ICCCM_WM_STATE_ICONIC
 #define XCB_WM_STATE_WITHDRAWN XCB_ICCCM_WM_STATE_WITHDRAWN
@@ -83,8 +93,8 @@
 #include <private/qguiapplication_p.h>
 #include <private/qwindow_p.h>
 
-#include <QtGui/QPlatformBackingStore>
-#include <QtGui/QWindowSystemInterface>
+#include <qpa/qplatformbackingstore.h>
+#include <qpa/qwindowsysteminterface.h>
 
 #include <stdio.h>
 
 #include <X11/Xutil.h>
 #endif
 
-#ifdef XCB_USE_XINPUT2_MAEMO
+#if defined(XCB_USE_XINPUT2_MAEMO) || defined(XCB_USE_XINPUT2)
 #include <X11/extensions/XInput2.h>
 #endif
 
@@ -130,22 +140,29 @@ static inline QImage::Format imageFormatForDepth(int depth)
         case 32: return QImage::Format_ARGB32_Premultiplied;
         case 24: return QImage::Format_RGB32;
         case 16: return QImage::Format_RGB16;
-        default: break;
+        default: return QImage::Format_Invalid;
     }
-    qFatal("Unsupported display depth %d", depth);
-    return QImage::Format_Invalid;
+}
+
+static inline bool positionIncludesFrame(QWindow *w)
+{
+    return qt_window_private(w)->positionPolicy == QWindowPrivate::WindowFrameInclusive;
 }
 
 QXcbWindow::QXcbWindow(QWindow *window)
     : QPlatformWindow(window)
     , m_window(0)
     , m_syncCounter(0)
+    , m_gravity(XCB_GRAVITY_STATIC)
     , m_mapped(false)
     , m_transparent(false)
+    , m_deferredActivation(false)
     , m_netWmUserTimeWindow(XCB_NONE)
+    , m_dirtyFrameMargins(false)
 #if defined(XCB_USE_EGL)
     , m_eglSurface(0)
 #endif
+    , m_lastWindowStateEvent(-1)
 {
     m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
 
@@ -158,6 +175,8 @@ void QXcbWindow::create()
 {
     destroy();
 
+    m_deferredExpose = false;
+    m_configureNotifyPending = true;
     m_windowState = Qt::WindowNoState;
 
     Qt::WindowType type = window()->windowType();
@@ -170,6 +189,11 @@ void QXcbWindow::create()
         return;
     }
 
+    // Determine gravity from initial position. Do not change
+    // later as it will cause the window to move uncontrollably.
+    m_gravity = positionIncludesFrame(window()) ?
+                XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC;
+
     const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK;
     const quint32 values[] = {
         // XCB_CW_BACK_PIXMAP
@@ -193,6 +217,9 @@ void QXcbWindow::create()
         | XCB_EVENT_MASK_FOCUS_CHANGE
     };
 
+    // Parameters to XCreateWindow() are frame corner + inner size.
+    // This fits in case position policy is frame inclusive. There is
+    // currently no way to implement it for frame-exclusive geometries.
     QRect rect = window()->geometry();
     QPlatformWindow::setGeometry(rect);
 
@@ -203,18 +230,21 @@ void QXcbWindow::create()
     if (parent())
         xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
 
-    m_requestedFormat = window()->format();
+    m_format = window()->requestedFormat();
 
 #if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB)
     if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
-        || window()->format().hasAlpha())
+        || m_format.hasAlpha())
     {
 #if defined(XCB_USE_GLX)
-        XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->format());
-
+        XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen), m_screen->screenNumber(), &m_format);
+        if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
+            qFatal("Could not initialize GLX");
 #elif defined(XCB_USE_EGL)
         EGLDisplay eglDisplay = connection()->egl_display();
-        EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, window()->format(), true);
+        EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, m_format, true);
+        m_format = q_glFormatFromConfig(eglDisplay, eglConfig);
+
         VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
 
         XVisualInfo visualInfoTemplate;
@@ -224,6 +254,8 @@ void QXcbWindow::create()
         XVisualInfo *visualInfo;
         int matchingCount = 0;
         visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
+        if (!visualInfo && window()->surfaceType() == QSurface::OpenGLSurface)
+            qFatal("Could not initialize EGL");
 #endif //XCB_USE_GLX
         if (visualInfo) {
             m_depth = visualInfo->depth;
@@ -240,10 +272,12 @@ void QXcbWindow::create()
             m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(),
                                       0, visualInfo->depth, InputOutput, visualInfo->visual,
                                       CWBackPixel|CWBorderPixel|CWColormap, &a);
-        } else {
-            qFatal("no window!");
+
+            XFree(visualInfo);
         }
-    } else
+    }
+
+    if (!m_window)
 #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
     {
         m_window = xcb_generate_id(xcb_connection());
@@ -319,6 +353,8 @@ void QXcbWindow::create()
     memset(&hints, 0, sizeof(hints));
     xcb_wm_hints_set_normal(&hints);
 
+    xcb_wm_hints_set_input(&hints, !(window()->windowFlags() & Qt::WindowDoesNotAcceptFocus));
+
     xcb_set_wm_hints(xcb_connection(), m_window, &hints);
 
     xcb_window_t leader = m_screen->clientLeader();
@@ -327,7 +363,7 @@ void QXcbWindow::create()
                                    1, &leader));
 
 #ifdef XCB_USE_XINPUT2_MAEMO
-    if (connection()->isUsingXInput2()) {
+    if (connection()->isUsingXInput2Maemo()) {
         XIEventMask xieventmask;
         uchar bitmask[2] = { 0, 0 };
 
@@ -341,6 +377,8 @@ void QXcbWindow::create()
 
         XISelectEvents(DISPLAY_FROM_XCB(this), m_window, &xieventmask, 1);
     }
+#elif defined(XCB_USE_XINPUT2)
+    connection()->xi2Select(m_window);
 #endif
 
     setWindowFlags(window()->windowFlags());
@@ -350,7 +388,9 @@ void QXcbWindow::create()
     if (window()->windowFlags() & Qt::WindowTransparentForInput)
         setTransparentForMouseEvents(true);
 
+#ifndef QT_NO_DRAGANDDROP
     connection()->drag()->dndEnable(this, true);
+#endif
 }
 
 QXcbWindow::~QXcbWindow()
@@ -363,8 +403,17 @@ void QXcbWindow::destroy()
     if (m_syncCounter && m_screen->syncRequestSupported())
         Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
     if (m_window) {
+        if (m_netWmUserTimeWindow) {
+            xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
+            // Some window managers, like metacity, do XSelectInput on the _NET_WM_USER_TIME_WINDOW window,
+            // without trapping BadWindow (which crashes when the user time window is destroyed).
+            connection()->sync();
+            xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
+            m_netWmUserTimeWindow = XCB_NONE;
+        }
         connection()->removeWindow(m_window);
         Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
+        m_window = 0;
     }
     m_mapped = false;
 
@@ -379,14 +428,17 @@ void QXcbWindow::setGeometry(const QRect &rect)
     QPlatformWindow::setGeometry(rect);
 
     propagateSizeHints();
+    const QRect wmGeometry = windowToWmGeometry(rect);
 
     const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
-    const quint32 values[] = { rect.x(),
-                               rect.y(),
-                               qBound(1, rect.width(), XCOORD_MAX),
-                               qBound(1, rect.height(), XCOORD_MAX) };
+    const qint32 values[] = {
+        qBound<qint32>(-XCOORD_MAX, wmGeometry.x(),      XCOORD_MAX),
+        qBound<qint32>(-XCOORD_MAX, wmGeometry.y(),      XCOORD_MAX),
+        qBound<qint32>(1,           wmGeometry.width(),  XCOORD_MAX),
+        qBound<qint32>(1,           wmGeometry.height(), XCOORD_MAX),
+    };
 
-    Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
+    Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, reinterpret_cast<const quint32*>(values)));
 
     xcb_flush(xcb_connection());
 }
@@ -403,10 +455,9 @@ QMargins QXcbWindow::frameMargins() const
             connection()->wmSupport()->virtualRoots();
 
         while (!foundRoot) {
-            xcb_query_tree_cookie_t cookie = xcb_query_tree(xcb_connection(), parent);
+            xcb_query_tree_cookie_t cookie = xcb_query_tree_unchecked(xcb_connection(), parent);
 
-            xcb_generic_error_t *error;
-            xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, &error);
+            xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, NULL);
             if (reply) {
                 if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1) {
                     foundRoot = true;
@@ -417,11 +468,6 @@ QMargins QXcbWindow::frameMargins() const
 
                 free(reply);
             } else {
-                if (error) {
-                    connection()->handleXcbError(error);
-                    free(error);
-                }
-
                 m_dirtyFrameMargins = false;
                 m_frameMargins = QMargins();
                 return m_frameMargins;
@@ -430,25 +476,22 @@ QMargins QXcbWindow::frameMargins() const
 
         QPoint offset;
 
-        xcb_generic_error_t *error;
         xcb_translate_coordinates_reply_t *reply =
             xcb_translate_coordinates_reply(
                 xcb_connection(),
                 xcb_translate_coordinates(xcb_connection(), window, parent, 0, 0),
-                &error);
+                NULL);
 
         if (reply) {
             offset = QPoint(reply->dst_x, reply->dst_y);
             free(reply);
-        } else if (error) {
-            free(error);
         }
 
         xcb_get_geometry_reply_t *geom =
             xcb_get_geometry_reply(
                 xcb_connection(),
                 xcb_get_geometry(xcb_connection(), parent),
-                &error);
+                NULL);
 
         if (geom) {
             // --
@@ -468,8 +511,6 @@ QMargins QXcbWindow::frameMargins() const
             m_frameMargins = QMargins(left, top, right, bottom);
 
             free(geom);
-        } else if (error) {
-            free(error);
         }
 
         m_dirtyFrameMargins = false;
@@ -489,23 +530,18 @@ void QXcbWindow::setVisible(bool visible)
 void QXcbWindow::show()
 {
     if (window()->isTopLevel()) {
-        xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window);
-
-        xcb_generic_error_t *error;
+        xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window);
 
         xcb_wm_hints_t hints;
-        xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error);
-
-        if (error) {
-            connection()->handleXcbError(error);
-            free(error);
-        }
+        xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL);
 
         if (window()->windowState() & Qt::WindowMinimized)
             xcb_wm_hints_set_iconic(&hints);
         else
             xcb_wm_hints_set_normal(&hints);
 
+        xcb_wm_hints_set_input(&hints, !(window()->windowFlags() & Qt::WindowDoesNotAcceptFocus));
+
         xcb_set_wm_hints(xcb_connection(), m_window, &hints);
 
         // update WM_NORMAL_HINTS
@@ -532,6 +568,9 @@ void QXcbWindow::show()
         updateNetWmStateBeforeMap();
     }
 
+    if (connection()->time() != XCB_TIME_CURRENT_TIME)
+        updateNetWmUserTime(connection()->time());
+
     Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
     xcb_flush(xcb_connection());
 
@@ -594,20 +633,15 @@ static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window)
     QtMotifWmHints hints;
 
     xcb_get_property_cookie_t get_cookie =
-        xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS),
+        xcb_get_property_unchecked(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS),
                          c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20);
 
-    xcb_generic_error_t *error;
-
     xcb_get_property_reply_t *reply =
-        xcb_get_property_reply(c->xcb_connection(), get_cookie, &error);
+        xcb_get_property_reply(c->xcb_connection(), get_cookie, NULL);
 
     if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) {
         hints = *((QtMotifWmHints *)xcb_get_property_value(reply));
-    } else if (error) {
-        c->handleXcbError(error);
-        free(error);
-
+    } else {
         hints.flags = 0L;
         hints.functions = MWM_FUNC_ALL;
         hints.decorations = MWM_DECOR_ALL;
@@ -636,53 +670,37 @@ static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMoti
     }
 }
 
-void QXcbWindow::printNetWmState(const QVector<xcb_atom_t> &state)
-{
-    printf("_NET_WM_STATE (%d): ", state.size());
-    for (int i = 0; i < state.size(); ++i) {
-#define CHECK_WM_STATE(state_atom) \
-        if (state.at(i) == atom(QXcbAtom::state_atom))\
-            printf(#state_atom " ");
-        CHECK_WM_STATE(_NET_WM_STATE_ABOVE)
-        CHECK_WM_STATE(_NET_WM_STATE_BELOW)
-        CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN)
-        CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ)
-        CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT)
-        CHECK_WM_STATE(_NET_WM_STATE_MODAL)
-        CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP)
-        CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION)
-#undef CHECK_WM_STATE
-    }
-    printf("\n");
-}
-
-QVector<xcb_atom_t> QXcbWindow::getNetWmState()
+QXcbWindow::NetWmStates QXcbWindow::netWmStates()
 {
-    QVector<xcb_atom_t> result;
+    NetWmStates result(0);
 
     xcb_get_property_cookie_t get_cookie =
-        xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
+        xcb_get_property_unchecked(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
                          XCB_ATOM_ATOM, 0, 1024);
 
-    xcb_generic_error_t *error;
-
     xcb_get_property_reply_t *reply =
-        xcb_get_property_reply(xcb_connection(), get_cookie, &error);
+        xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
 
     if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
-        result.resize(reply->length);
-
-        memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t));
-
-#ifdef NET_WM_STATE_DEBUG
-        printf("getting net wm state (%x)\n", m_window);
-        printNetWmState(result);
-#endif
-
+        const xcb_atom_t *states = static_cast<const xcb_atom_t *>(xcb_get_property_value(reply));
+        const xcb_atom_t *statesEnd = states + reply->length;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_ABOVE)))
+            result |= NetWmStateAbove;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_BELOW)))
+            result |= NetWmStateBelow;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN)))
+            result |= NetWmStateFullScreen;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ)))
+            result |= NetWmStateMaximizedHorz;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT)))
+            result |= NetWmStateMaximizedVert;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_MODAL)))
+            result |= NetWmStateModal;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP)))
+            result |= NetWmStateStaysOnTop;
+        if (statesEnd != qFind(states, statesEnd, atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION)))
+            result |= NetWmStateDemandsAttention;
         free(reply);
-    } else if (error) {
-        connection()->handleXcbError(error);
-        free(error);
     } else {
 #ifdef NET_WM_STATE_DEBUG
         printf("getting net wm state (%x), empty\n", m_window);
@@ -692,8 +710,26 @@ QVector<xcb_atom_t> QXcbWindow::getNetWmState()
     return result;
 }
 
-void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms)
+void QXcbWindow::setNetWmStates(NetWmStates states)
 {
+    QVector<xcb_atom_t> atoms;
+    if (states & NetWmStateAbove)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
+    if (states & NetWmStateBelow)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_BELOW));
+    if (states & NetWmStateFullScreen)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
+    if (states & NetWmStateMaximizedHorz)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
+    if (states & NetWmStateMaximizedVert)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+    if (states & NetWmStateModal)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_MODAL));
+    if (states & NetWmStateStaysOnTop)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
+    if (states & NetWmStateDemandsAttention)
+        atoms.push_back(atom(QXcbAtom::_NET_WM_STATE_DEMANDS_ATTENTION));
+
     if (atoms.isEmpty()) {
         Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)));
     } else {
@@ -704,7 +740,6 @@ void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms)
     xcb_flush(xcb_connection());
 }
 
-
 Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
 {
     Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
@@ -727,6 +762,7 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
     setMotifWindowFlags(flags);
 
     setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput);
+    updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus);
 
     return flags;
 }
@@ -970,30 +1006,28 @@ void QXcbWindow::updateMotifWmHintsBeforeMap()
 
 void QXcbWindow::updateNetWmStateBeforeMap()
 {
-    QVector<xcb_atom_t> netWmState;
+    NetWmStates states(0);
 
-    Qt::WindowFlags flags = window()->windowFlags();
+    const Qt::WindowFlags flags = window()->windowFlags();
     if (flags & Qt::WindowStaysOnTopHint) {
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
+        states |= NetWmStateAbove;
+        states |= NetWmStateStaysOnTop;
     } else if (flags & Qt::WindowStaysOnBottomHint) {
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW));
+        states |= NetWmStateBelow;
     }
 
-    if (window()->windowState() & Qt::WindowFullScreen) {
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
-    }
+    if (window()->windowState() & Qt::WindowFullScreen)
+        states |= NetWmStateFullScreen;
 
     if (window()->windowState() & Qt::WindowMaximized) {
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
+        states |= NetWmStateMaximizedHorz;
+        states |= NetWmStateMaximizedVert;
     }
 
-    if (window()->windowModality() != Qt::NonModal) {
-        netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL));
-    }
+    if (window()->windowModality() != Qt::NonModal)
+        states |= NetWmStateModal;
 
-    setNetWmState(netWmState);
+    setNetWmStates(states);
 }
 
 void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
@@ -1059,6 +1093,18 @@ void QXcbWindow::setTransparentForMouseEvents(bool transparent)
     m_transparent = transparent;
 }
 
+void QXcbWindow::updateDoesNotAcceptFocus(bool doesNotAcceptFocus)
+{
+    xcb_get_property_cookie_t cookie = xcb_get_wm_hints_unchecked(xcb_connection(), m_window);
+
+    xcb_wm_hints_t hints;
+    if (!xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, NULL)) {
+        return;
+    }
+
+    xcb_wm_hints_set_input(&hints, !doesNotAcceptFocus);
+    xcb_set_wm_hints(xcb_connection(), m_window, &hints);
+}
 
 WId QXcbWindow::winId() const
 {
@@ -1089,6 +1135,49 @@ void QXcbWindow::setWindowTitle(const QString &title)
                                    ba.constData()));
 }
 
+void QXcbWindow::setWindowIcon(const QIcon &icon)
+{
+    QVector<quint32> icon_data;
+
+    if (!icon.isNull()) {
+        QList<QSize> availableSizes = icon.availableSizes();
+        if (availableSizes.isEmpty()) {
+            // try to use default sizes since the icon can be a scalable image like svg.
+            availableSizes.push_back(QSize(16,16));
+            availableSizes.push_back(QSize(32,32));
+            availableSizes.push_back(QSize(64,64));
+            availableSizes.push_back(QSize(128,128));
+        }
+        for (int i = 0; i < availableSizes.size(); ++i) {
+            QSize size = availableSizes.at(i);
+            QPixmap pixmap = icon.pixmap(size);
+            if (!pixmap.isNull()) {
+                QImage image = pixmap.toImage().convertToFormat(QImage::Format_ARGB32);
+                int pos = icon_data.size();
+                icon_data.resize(pos + 2 + image.width()*image.height());
+                icon_data[pos++] = image.width();
+                icon_data[pos++] = image.height();
+                memcpy(icon_data.data() + pos, image.bits(), image.width()*image.height()*4);
+            }
+        }
+    }
+
+    if (!icon_data.isEmpty()) {
+        Q_XCB_CALL(xcb_change_property(xcb_connection(),
+                                       XCB_PROP_MODE_REPLACE,
+                                       m_window,
+                                       atom(QXcbAtom::_NET_WM_ICON),
+                                       atom(QXcbAtom::CARDINAL),
+                                       32,
+                                       icon_data.size(),
+                                       (unsigned char *) icon_data.data()));
+    } else {
+        Q_XCB_CALL(xcb_delete_property(xcb_connection(),
+                                       m_window,
+                                       atom(QXcbAtom::_NET_WM_ICON)));
+    }
+}
+
 void QXcbWindow::raise()
 {
     const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE;
@@ -1103,20 +1192,36 @@ void QXcbWindow::lower()
     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
 }
 
+// Adapt the geometry to match the WM expection with regards
+// to gravity.
+QRect QXcbWindow::windowToWmGeometry(QRect r) const
+{
+    if (m_dirtyFrameMargins || m_frameMargins.isNull())
+        return r;
+    const bool frameInclusive = positionIncludesFrame(window());
+    // XCB_GRAVITY_STATIC requires the inner geometry, whereas
+    // XCB_GRAVITY_NORTH_WEST requires the frame geometry
+    if (frameInclusive && m_gravity == XCB_GRAVITY_STATIC) {
+        r.translate(m_frameMargins.left(), m_frameMargins.top());
+    } else if (!frameInclusive && m_gravity == XCB_GRAVITY_NORTH_WEST) {
+        r.translate(-m_frameMargins.left(), -m_frameMargins.top());
+    }
+    return r;
+}
+
 void QXcbWindow::propagateSizeHints()
 {
     // update WM_NORMAL_HINTS
     xcb_size_hints_t hints;
     memset(&hints, 0, sizeof(hints));
 
-    QRect rect = geometry();
+    const QRect rect = windowToWmGeometry(geometry());
 
     QWindow *win = window();
 
     xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
     xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
-    xcb_size_hints_set_win_gravity(&hints, qt_window_private(win)->positionPolicy == QWindowPrivate::WindowFrameInclusive
-                                           ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC);
+    xcb_size_hints_set_win_gravity(&hints, m_gravity);
 
     QSize minimumSize = win->minimumSize();
     QSize maximumSize = win->maximumSize();
@@ -1141,17 +1246,58 @@ void QXcbWindow::propagateSizeHints()
 
 void QXcbWindow::requestActivateWindow()
 {
-    if (m_mapped){
-        updateNetWmUserTime(connection()->time());
+    if (!m_mapped) {
+        m_deferredActivation = true;
+        return;
+    }
+    m_deferredActivation = false;
+
+    updateNetWmUserTime(connection()->time());
+
+    if (window()->isTopLevel()
+        && connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_ACTIVE_WINDOW))) {
+        xcb_client_message_event_t event;
+
+        event.response_type = XCB_CLIENT_MESSAGE;
+        event.format = 32;
+        event.window = m_window;
+        event.type = atom(QXcbAtom::_NET_ACTIVE_WINDOW);
+        event.data.data32[0] = 1;
+        event.data.data32[1] = connection()->time();
+        QWindow *focusWindow = QGuiApplication::focusWindow();
+        event.data.data32[2] = focusWindow ? focusWindow->winId() : XCB_NONE;
+        event.data.data32[3] = 0;
+        event.data.data32[4] = 0;
+
+        Q_XCB_CALL(xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
+    } else {
         Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time()));
     }
+
     connection()->sync();
 }
 
+#if XCB_USE_MAEMO_WINDOW_PROPERTIES
+void QXcbWindow::handleContentOrientationChange(Qt::ScreenOrientation orientation)
+{
+    int angle = 0;
+    switch (orientation) {
+        case Qt::PortraitOrientation: angle = 270; break;
+        case Qt::LandscapeOrientation: angle = 0; break;
+        case Qt::InvertedPortraitOrientation: angle = 90; break;
+        case Qt::InvertedLandscapeOrientation: angle = 180; break;
+        case Qt::PrimaryOrientation: break;
+    }
+    Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
+                                   atom(QXcbAtom::MeegoTouchOrientationAngle), XCB_ATOM_CARDINAL, 32,
+                                   1, &angle));
+}
+#endif
+
 QSurfaceFormat QXcbWindow::format() const
 {
     // ### return actual format
-    return m_requestedFormat;
+    return m_format;
 }
 
 #if defined(XCB_USE_EGL)
@@ -1159,7 +1305,7 @@ QXcbEGLSurface *QXcbWindow::eglSurface() const
 {
     if (!m_eglSurface) {
         EGLDisplay display = connection()->egl_display();
-        EGLConfig config = q_configFromGLFormat(display, window()->format(), true);
+        EGLConfig config = q_configFromGLFormat(display, window()->requestedFormat(), true);
         EGLSurface surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_window, 0);
 
         m_eglSurface = new QXcbEGLSurface(display, surface);
@@ -1180,7 +1326,7 @@ void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
 
     // if count is non-zero there are more expose events pending
     if (event->count == 0) {
-        QWindowSystemInterface::handleSynchronousExposeEvent(window(), m_exposeRegion);
+        QWindowSystemInterface::handleExposeEvent(window(), m_exposeRegion);
         m_exposeRegion = QRegion();
     }
 }
@@ -1208,18 +1354,21 @@ void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *even
             m_syncValue.lo = event->data.data32[2];
             m_syncValue.hi = event->data.data32[3];
         } else {
-            qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
+            qWarning() << "QXcbWindow: Unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
         }
+#ifndef QT_NO_DRAGANDDROP
     } else if (event->type == atom(QXcbAtom::XdndEnter)) {
         connection()->drag()->handleEnter(window(), event);
     } else if (event->type == atom(QXcbAtom::XdndPosition)) {
-        connection()->drag()->handlePosition(window(), event, false);
+        connection()->drag()->handlePosition(window(), event);
     } else if (event->type == atom(QXcbAtom::XdndLeave)) {
-        connection()->drag()->handleLeave(window(), event, false);
+        connection()->drag()->handleLeave(window(), event);
     } else if (event->type == atom(QXcbAtom::XdndDrop)) {
-        connection()->drag()->handleDrop(window(), event, false);
+        connection()->drag()->handleDrop(window(), event);
+#endif
+    } else if (event->type == atom(QXcbAtom::_XEMBED)) { // QSystemTrayIcon
     } else {
-        qWarning() << "unhandled client message:" << connection()->atomName(event->type);
+        qWarning() << "QXcbWindow: Unhandled client message:" << connection()->atomName(event->type);
     }
 }
 
@@ -1227,18 +1376,15 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
 {
     bool fromSendEvent = (event->response_type & 0x80);
     QPoint pos(event->x, event->y);
-    if (!fromSendEvent) {
+    if (!parent() && !fromSendEvent) {
         // Do not trust the position, query it instead.
         xcb_translate_coordinates_cookie_t cookie = xcb_translate_coordinates(xcb_connection(), xcb_window(),
                                                                               m_screen->root(), 0, 0);
-        xcb_generic_error_t *error;
-        xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, &error);
+        xcb_translate_coordinates_reply_t *reply = xcb_translate_coordinates_reply(xcb_connection(), cookie, NULL);
         if (reply) {
             pos.setX(reply->dst_x);
             pos.setY(reply->dst_y);
             free(reply);
-        } else if (error) {
-            free(error);
         }
     }
 
@@ -1247,6 +1393,13 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
     QPlatformWindow::setGeometry(rect);
     QWindowSystemInterface::handleGeometryChange(window(), rect);
 
+    m_configureNotifyPending = false;
+
+    if (m_deferredExpose) {
+        m_deferredExpose = false;
+        QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
+    }
+
     m_dirtyFrameMargins = true;
 
 #if XCB_USE_DRI2
@@ -1255,11 +1408,21 @@ void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *
 #endif
 }
 
+bool QXcbWindow::isExposed() const
+{
+    return m_mapped;
+}
+
 void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
 {
     if (event->window == m_window) {
         m_mapped = true;
-        QWindowSystemInterface::handleMapEvent(window());
+        if (m_deferredActivation)
+            requestActivateWindow();
+        if (m_configureNotifyPending)
+            m_deferredExpose = true;
+        else
+            QWindowSystemInterface::handleExposeEvent(window(), QRect(QPoint(), geometry().size()));
     }
 }
 
@@ -1267,7 +1430,7 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
 {
     if (event->window == m_window) {
         m_mapped = false;
-        QWindowSystemInterface::handleUnmapEvent(window());
+        QWindowSystemInterface::handleExposeEvent(window(), QRegion());
     }
 }
 
@@ -1403,46 +1566,42 @@ void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *ev
 {
     connection()->setTime(event->time);
 
-    bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
+    const bool propertyDeleted = event->state == XCB_PROPERTY_DELETE;
+    const xcb_atom_t netWmStateAtom = atom(QXcbAtom::_NET_WM_STATE);
+    const xcb_atom_t wmStateAtom = atom(QXcbAtom::WM_STATE);
 
-    if (event->atom == atom(QXcbAtom::_NET_WM_STATE) || event->atom == atom(QXcbAtom::WM_STATE)) {
+    if (event->atom == netWmStateAtom || event->atom == wmStateAtom) {
         if (propertyDeleted)
             return;
 
-        xcb_get_property_cookie_t get_cookie =
-            xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::WM_STATE),
-                             XCB_ATOM_ANY, 0, 1024);
+        Qt::WindowState newState = Qt::WindowNoState;
+        if (event->atom == wmStateAtom) { // WM_STATE: Quick check for 'Minimize'.
+            const xcb_get_property_cookie_t get_cookie =
+                xcb_get_property(xcb_connection(), 0, m_window, wmStateAtom,
+                                 XCB_ATOM_ANY, 0, 1024);
 
-        xcb_generic_error_t *error;
+            xcb_get_property_reply_t *reply =
+                xcb_get_property_reply(xcb_connection(), get_cookie, NULL);
 
-        xcb_get_property_reply_t *reply =
-            xcb_get_property_reply(xcb_connection(), get_cookie, &error);
-
-        xcb_atom_t wm_state = XCB_WM_STATE_WITHDRAWN;
-        if (reply && reply->format == 32 && reply->type == atom(QXcbAtom::WM_STATE)) {
-            if (reply->length != 0)
-                wm_state = ((long *)xcb_get_property_value(reply))[0];
-            free(reply);
-        } else if (error) {
-            connection()->handleXcbError(error);
-            free(error);
+            if (reply && reply->format == 32 && reply->type == wmStateAtom) {
+                const long *data = (const long *)xcb_get_property_value(reply);
+                if (reply->length != 0 && XCB_WM_STATE_ICONIC == data[0])
+                    newState = Qt::WindowMinimized;
+                free(reply);
+            }
+        } // WM_STATE: Quick check for 'Minimize'.
+        if (newState != Qt::WindowMinimized) { // Something else changed, get _NET_WM_STATE.
+            const NetWmStates states = netWmStates();
+            if ((states & NetWmStateMaximizedHorz) && (states & NetWmStateMaximizedVert))
+                newState = Qt::WindowMaximized;
+            else if (states & NetWmStateFullScreen)
+                newState = Qt::WindowFullScreen;
+        }
+        // Send Window state, compress events in case other flags (modality, etc) are changed.
+        if (m_lastWindowStateEvent != newState) {
+            QWindowSystemInterface::handleWindowStateChanged(window(), newState);
+            m_lastWindowStateEvent = newState;
         }
-
-        QVector<xcb_atom_t> netWmState = getNetWmState();
-
-        bool maximized = netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ))
-            && netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
-        bool fullscreen = netWmState.contains(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
-
-        Qt::WindowState state = Qt::WindowNoState;
-        if (wm_state == XCB_WM_STATE_ICONIC)
-            state = Qt::WindowMinimized;
-        else if (maximized)
-            state = Qt::WindowMaximized;
-        else if (fullscreen)
-            state = Qt::WindowFullScreen;
-
-        QWindowSystemInterface::handleWindowStateChanged(window(), state);
     }
 }
 
@@ -1491,11 +1650,9 @@ bool QXcbWindow::setKeyboardGrabEnabled(bool grab)
     xcb_grab_keyboard_cookie_t cookie = xcb_grab_keyboard(xcb_connection(), false,
                                                           m_window, XCB_TIME_CURRENT_TIME,
                                                           XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
-    xcb_generic_error_t *err;
-    xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, &err);
-    bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
+    xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, NULL);
+    bool result = !(!reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
     free(reply);
-    free(err);
     return result;
 }
 
@@ -1512,11 +1669,9 @@ bool QXcbWindow::setMouseGrabEnabled(bool grab)
                                                         XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
                                                         XCB_WINDOW_NONE, XCB_CURSOR_NONE,
                                                         XCB_TIME_CURRENT_TIME);
-    xcb_generic_error_t *err;
-    xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, &err);
-    bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
+    xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, NULL);
+    bool result = !(!reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
     free(reply);
-    free(err);
     return result;
 }
 
@@ -1526,4 +1681,63 @@ void QXcbWindow::setCursor(xcb_cursor_t cursor)
     xcb_flush(xcb_connection());
 }
 
+bool QXcbWindow::startSystemResize(const QPoint &pos, Qt::Corner corner)
+{
+    const xcb_atom_t moveResize = connection()->atom(QXcbAtom::_NET_WM_MOVERESIZE);
+    if (!connection()->wmSupport()->isSupportedByWM(moveResize))
+        return false;
+    xcb_client_message_event_t xev;
+    xev.response_type = XCB_CLIENT_MESSAGE;
+    xev.type = moveResize;
+    xev.window = xcb_window();
+    xev.format = 32;
+    const QPoint globalPos = window()->mapToGlobal(pos);
+    xev.data.data32[0] = globalPos.x();
+    xev.data.data32[1] = globalPos.y();
+    const bool bottom = corner == Qt::BottomRightCorner || corner == Qt::BottomLeftCorner;
+    const bool left = corner == Qt::BottomLeftCorner || corner == Qt::TopLeftCorner;
+    if (bottom)
+        xev.data.data32[2] = left ? 6 : 4; // bottomleft/bottomright
+    else
+        xev.data.data32[2] = left ? 0 : 2; // topleft/topright
+    xev.data.data32[3] = XCB_BUTTON_INDEX_1;
+    xev.data.data32[4] = 0;
+    xcb_ungrab_pointer(connection()->xcb_connection(), XCB_CURRENT_TIME);
+    xcb_send_event(connection()->xcb_connection(), false, m_screen->root(),
+                   XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY,
+                   (const char *)&xev);
+    return true;
+}
+
+#if !defined(QT_NO_SHAPE)
+
+static inline xcb_rectangle_t qRectToXCBRectangle(const QRect &r)
+{
+    xcb_rectangle_t result;
+    result.x = qMax(SHRT_MIN, r.x());
+    result.y = qMax(SHRT_MIN, r.y());
+    result.width = qMin((int)USHRT_MAX, r.width());
+    result.height = qMin((int)USHRT_MAX, r.height());
+    return result;
+}
+
+void QXcbWindow::setMask(const QRegion &region)
+{
+    if (!connection()->hasXShape())
+        return;
+    if (region.isEmpty()) {
+        xcb_shape_mask(connection()->xcb_connection(), XCB_SHAPE_SO_SET,
+                       XCB_SHAPE_SK_BOUNDING, xcb_window(), 0, 0, XCB_NONE);
+    } else {
+        QVector<xcb_rectangle_t> rects;
+        foreach (const QRect &r, region.rects())
+            rects.push_back(qRectToXCBRectangle(r));
+        xcb_shape_rectangles(connection()->xcb_connection(), XCB_SHAPE_SO_SET,
+                             XCB_SHAPE_SK_BOUNDING, XCB_CLIP_ORDERING_UNSORTED,
+                             xcb_window(), 0, 0, rects.size(), &rects[0]);
+    }
+}
+
+#endif // !QT_NO_SHAPE
+
 QT_END_NAMESPACE