X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;ds=sidebyside;f=src%2Fplugins%2Fplatforms%2Fxcb%2Fqxcbwindow.cpp;h=7020e63b0efa70d07c4565dfeb3748dfcae05f24;hb=015a5e0dcad0bca55d10822f6300b77a95fb69d6;hp=c5aee5c81d6271788377af3f68571f1586774c0e;hpb=dea76f3496ee077e271b334c7e8101fed5119481;p=profile%2Fivi%2Fqtbase.git diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index c5aee5c..7020e63 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -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$ ** ****************************************************************************/ @@ -43,11 +43,17 @@ #include #include +#include +#include #include "qxcbconnection.h" #include "qxcbscreen.h" #include "qxcbdrag.h" +#include "qxcbkeyboard.h" #include "qxcbwmsupport.h" +#include "qxcbimage.h" + +#include #ifdef XCB_USE_DRI2 #include "qdri2context.h" @@ -58,11 +64,15 @@ #include #undef class #include +#ifndef QT_NO_SHAPE +# include +#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 @@ -74,15 +84,17 @@ #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 #endif #include #include -#include -#include +#include +#include #include @@ -91,6 +103,10 @@ #include #endif +#if defined(XCB_USE_XINPUT2_MAEMO) || defined(XCB_USE_XINPUT2) +#include +#endif + #if defined(XCB_USE_GLX) #include "qglxintegration.h" #include @@ -118,16 +134,35 @@ static inline bool isTransient(const QWindow *w) || w->windowType() == Qt::Popup; } +static inline QImage::Format imageFormatForDepth(int depth) +{ + switch (depth) { + case 32: return QImage::Format_ARGB32_Premultiplied; + case 24: return QImage::Format_RGB32; + case 16: return QImage::Format_RGB16; + default: 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(window->screen()->handle()); @@ -140,6 +175,8 @@ void QXcbWindow::create() { destroy(); + m_deferredExpose = false; + m_configureNotifyPending = true; m_windowState = Qt::WindowNoState; Qt::WindowType type = window()->windowType(); @@ -147,11 +184,16 @@ void QXcbWindow::create() if (type == Qt::Desktop) { m_window = m_screen->root(); m_depth = m_screen->screen()->root_depth; - m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + m_imageFormat = imageFormatForDepth(m_depth); connection()->addWindow(m_window, this); 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 @@ -175,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); @@ -185,18 +230,21 @@ void QXcbWindow::create() if (parent()) xcb_parent_id = static_cast(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; @@ -206,28 +254,36 @@ 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; - m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + m_imageFormat = imageFormatForDepth(m_depth); Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone); XSetWindowAttributes a; a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber()); a.colormap = cmap; + + m_visualId = visualInfo->visualid; + 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()); m_depth = m_screen->screen()->root_depth; - m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32; + m_imageFormat = imageFormatForDepth(m_depth); + m_visualId = m_screen->screen()->root_visual; Q_XCB_CALL(xcb_create_window(xcb_connection(), XCB_COPY_FROM_PARENT, // depth -- same as root @@ -239,7 +295,7 @@ void QXcbWindow::create() rect.height(), 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class - m_screen->screen()->root_visual, // visual + m_visualId, // visual 0, // value mask 0)); // value list } @@ -297,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(); @@ -304,6 +362,25 @@ void QXcbWindow::create() atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32, 1, &leader)); +#ifdef XCB_USE_XINPUT2_MAEMO + if (connection()->isUsingXInput2Maemo()) { + XIEventMask xieventmask; + uchar bitmask[2] = { 0, 0 }; + + xieventmask.deviceid = XIAllMasterDevices; + xieventmask.mask = bitmask; + xieventmask.mask_len = sizeof(bitmask); + + XISetMask(bitmask, XI_ButtonPress); + XISetMask(bitmask, XI_ButtonRelease); + XISetMask(bitmask, XI_Motion); + + XISelectEvents(DISPLAY_FROM_XCB(this), m_window, &xieventmask, 1); + } +#elif defined(XCB_USE_XINPUT2) + connection()->xi2Select(m_window); +#endif + setWindowFlags(window()->windowFlags()); setWindowTitle(window()->windowTitle()); setWindowState(window()->windowState()); @@ -311,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() @@ -324,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; @@ -340,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(-XCOORD_MAX, wmGeometry.x(), XCOORD_MAX), + qBound(-XCOORD_MAX, wmGeometry.y(), XCOORD_MAX), + qBound(1, wmGeometry.width(), XCOORD_MAX), + qBound(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(values))); xcb_flush(xcb_connection()); } @@ -364,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; @@ -378,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; @@ -391,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) { // -- @@ -429,8 +511,6 @@ QMargins QXcbWindow::frameMargins() const m_frameMargins = QMargins(left, top, right, bottom); free(geom); - } else if (error) { - free(error); } m_dirtyFrameMargins = false; @@ -450,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 @@ -493,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()); @@ -555,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; @@ -597,53 +670,37 @@ static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMoti } } -void QXcbWindow::printNetWmState(const QVector &state) +QXcbWindow::NetWmStates QXcbWindow::netWmStates() { - 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 QXcbWindow::getNetWmState() -{ - QVector 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(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); @@ -653,8 +710,26 @@ QVector QXcbWindow::getNetWmState() return result; } -void QXcbWindow::setNetWmState(const QVector &atoms) +void QXcbWindow::setNetWmStates(NetWmStates states) { + QVector 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 { @@ -665,7 +740,6 @@ void QXcbWindow::setNetWmState(const QVector &atoms) xcb_flush(xcb_connection()); } - Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) { Qt::WindowType type = static_cast(int(flags & Qt::WindowType_Mask)); @@ -676,7 +750,11 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) flags |= Qt::X11BypassWindowManagerHint; if (flags & Qt::WindowTransparentForInput) { - uint32_t mask = XCB_EVENT_MASK_NO_EVENT; + uint32_t mask = XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_VISIBILITY_CHANGE + | XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_RESIZE_REDIRECT + | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT + | XCB_EVENT_MASK_FOCUS_CHANGE | XCB_EVENT_MASK_PROPERTY_CHANGE + | XCB_EVENT_MASK_COLOR_MAP_CHANGE | XCB_EVENT_MASK_OWNER_GRAB_BUTTON; xcb_change_window_attributes(xcb_connection(), xcb_window(), XCB_CW_EVENT_MASK, &mask); } @@ -684,6 +762,7 @@ Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags) setMotifWindowFlags(flags); setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput); + updateDoesNotAcceptFocus(flags & Qt::WindowDoesNotAcceptFocus); return flags; } @@ -927,30 +1006,28 @@ void QXcbWindow::updateMotifWmHintsBeforeMap() void QXcbWindow::updateNetWmStateBeforeMap() { - QVector 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) @@ -968,7 +1045,7 @@ void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp) -1, -1, 1, 1, 0, // border width XCB_WINDOW_CLASS_INPUT_OUTPUT, // window class - m_screen->screen()->root_visual, // visual + m_visualId, // visual 0, // value mask 0)); // value list wid = m_netWmUserTimeWindow; @@ -1016,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 { @@ -1046,6 +1135,49 @@ void QXcbWindow::setWindowTitle(const QString &title) ba.constData())); } +void QXcbWindow::setWindowIcon(const QIcon &icon) +{ + QVector icon_data; + + if (!icon.isNull()) { + QList 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; @@ -1060,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(); @@ -1098,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) @@ -1116,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); @@ -1137,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(); } } @@ -1165,28 +1354,52 @@ 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); } } void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event) { - QRect rect(event->x, event->y, event->width, event->height); + bool fromSendEvent = (event->response_type & 0x80); + QPoint pos(event->x, event->y); + 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_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); + } + } + + QRect rect(pos, QSize(event->width, event->height)); 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 @@ -1195,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())); } } @@ -1207,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()); } } @@ -1226,14 +1449,35 @@ static Qt::MouseButtons translateMouseButtons(int s) static Qt::MouseButton translateMouseButton(xcb_button_t s) { switch (s) { - case 1: - return Qt::LeftButton; - case 2: - return Qt::MidButton; - case 3: - return Qt::RightButton; - default: - return Qt::NoButton; + case 1: return Qt::LeftButton; + case 2: return Qt::MidButton; + case 3: return Qt::RightButton; + // Button values 4-7 were already handled as Wheel events, and won't occur here. + case 8: return Qt::BackButton; // Also known as Qt::ExtraButton1 + case 9: return Qt::ForwardButton; // Also known as Qt::ExtraButton2 + case 10: return Qt::ExtraButton3; + case 11: return Qt::ExtraButton4; + case 12: return Qt::ExtraButton5; + case 13: return Qt::ExtraButton6; + case 14: return Qt::ExtraButton7; + case 15: return Qt::ExtraButton8; + case 16: return Qt::ExtraButton9; + case 17: return Qt::ExtraButton10; + case 18: return Qt::ExtraButton11; + case 19: return Qt::ExtraButton12; + case 20: return Qt::ExtraButton13; + case 21: return Qt::ExtraButton14; + case 22: return Qt::ExtraButton15; + case 23: return Qt::ExtraButton16; + case 24: return Qt::ExtraButton17; + case 25: return Qt::ExtraButton18; + case 26: return Qt::ExtraButton19; + case 27: return Qt::ExtraButton20; + case 28: return Qt::ExtraButton21; + case 29: return Qt::ExtraButton22; + case 30: return Qt::ExtraButton23; + case 31: return Qt::ExtraButton24; + default: return Qt::NoButton; } } @@ -1244,40 +1488,42 @@ void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) QPoint local(event->event_x, event->event_y); QPoint global(event->root_x, event->root_y); - Qt::KeyboardModifiers modifiers = Qt::NoModifier; + Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); if (event->detail >= 4 && event->detail <= 7) { - //logic borrowed from qapplication_x11.cpp + // Logic borrowed from qapplication_x11.cpp int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1); bool hor = (((event->detail == 4 || event->detail == 5) && (modifiers & Qt::AltModifier)) || (event->detail == 6 || event->detail == 7)); QWindowSystemInterface::handleWheelEvent(window(), event->time, - local, global, delta, hor ? Qt::Horizontal : Qt::Vertical); + local, global, delta, hor ? Qt::Horizontal : Qt::Vertical, modifiers); return; } - handleMouseEvent(event->detail, event->state, event->time, local, global); + handleMouseEvent(event->detail, event->state, event->time, local, global, modifiers); } void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event) { QPoint local(event->event_x, event->event_y); QPoint global(event->root_x, event->root_y); + Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); - handleMouseEvent(event->detail, event->state, event->time, local, global); + handleMouseEvent(event->detail, event->state, event->time, local, global, modifiers); } void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) { QPoint local(event->event_x, event->event_y); QPoint global(event->root_x, event->root_y); + Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); - handleMouseEvent(event->detail, event->state, event->time, local, global); + handleMouseEvent(event->detail, event->state, event->time, local, global, modifiers); } -void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global) +void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global, Qt::KeyboardModifiers modifiers) { connection()->setTime(time); @@ -1286,7 +1532,7 @@ void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_times buttons ^= button; // X event uses state *before*, Qt uses state *after* - QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons); + QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons, modifiers); } void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) @@ -1316,6 +1562,49 @@ void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event) QWindowSystemInterface::handleLeaveEvent(window()); } +void QXcbWindow::handlePropertyNotifyEvent(const xcb_property_notify_event_t *event) +{ + connection()->setTime(event->time); + + 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 == netWmStateAtom || event->atom == wmStateAtom) { + if (propertyDeleted) + return; + + 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_get_property_reply_t *reply = + xcb_get_property_reply(xcb_connection(), get_cookie, NULL); + + 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; + } + } +} + void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *) { QWindowSystemInterface::handleWindowActivated(window()); @@ -1361,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; } @@ -1382,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; } @@ -1396,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 ®ion) +{ + 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 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