Make qtbase build with Qt-in-namespace again
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbwindow.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2011 Nokia Corporation and/or its subsidiary(-ies).
4 ** All rights reserved.
5 ** Contact: Nokia Corporation (qt-info@nokia.com)
6 **
7 ** This file is part of the plugins of the Qt Toolkit.
8 **
9 ** $QT_BEGIN_LICENSE:LGPL$
10 ** GNU Lesser General Public License Usage
11 ** This file may be used under the terms of the GNU Lesser General Public
12 ** License version 2.1 as published by the Free Software Foundation and
13 ** appearing in the file LICENSE.LGPL included in the packaging of this
14 ** file. Please review the following information to ensure the GNU Lesser
15 ** General Public License version 2.1 requirements will be met:
16 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 **
18 ** In addition, as a special exception, Nokia gives you certain additional
19 ** rights. These rights are described in the Nokia Qt LGPL Exception
20 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 **
22 ** GNU General Public License Usage
23 ** Alternatively, this file may be used under the terms of the GNU General
24 ** Public License version 3.0 as published by the Free Software Foundation
25 ** and appearing in the file LICENSE.GPL included in the packaging of this
26 ** file. Please review the following information to ensure the GNU General
27 ** Public License version 3.0 requirements will be met:
28 ** http://www.gnu.org/copyleft/gpl.html.
29 **
30 ** Other Usage
31 ** Alternatively, this file may be used in accordance with the terms and
32 ** conditions contained in a signed written agreement between you and Nokia.
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qxcbwindow.h"
43
44 #include <QtDebug>
45 #include <QScreen>
46
47 #include "qxcbconnection.h"
48 #include "qxcbscreen.h"
49 #include "qxcbdrag.h"
50 #include "qxcbwmsupport.h"
51
52 #ifdef XCB_USE_DRI2
53 #include "qdri2context.h"
54 #endif
55
56 // FIXME This workaround can be removed for xcb-icccm > 3.8
57 #define class class_name
58 #include <xcb/xcb_icccm.h>
59 #undef class
60 #include <xcb/xfixes.h>
61
62 // xcb-icccm 3.8 support
63 #ifdef XCB_ICCCM_NUM_WM_SIZE_HINTS_ELEMENTS
64 #define xcb_get_wm_hints_reply xcb_icccm_get_wm_hints_reply
65 #define xcb_get_wm_hints xcb_icccm_get_wm_hints
66 #define xcb_set_wm_hints xcb_icccm_set_wm_hints
67 #define xcb_set_wm_normal_hints xcb_icccm_set_wm_normal_hints
68 #define xcb_size_hints_set_base_size xcb_icccm_size_hints_set_base_size
69 #define xcb_size_hints_set_max_size xcb_icccm_size_hints_set_max_size
70 #define xcb_size_hints_set_min_size xcb_icccm_size_hints_set_min_size
71 #define xcb_size_hints_set_position xcb_icccm_size_hints_set_position
72 #define xcb_size_hints_set_resize_inc xcb_icccm_size_hints_set_resize_inc
73 #define xcb_size_hints_set_size xcb_icccm_size_hints_set_size
74 #define xcb_size_hints_set_win_gravity xcb_icccm_size_hints_set_win_gravity
75 #define xcb_wm_hints_set_iconic xcb_icccm_wm_hints_set_iconic
76 #define xcb_wm_hints_set_normal xcb_icccm_wm_hints_set_normal
77 #define xcb_wm_hints_t xcb_icccm_wm_hints_t
78 #define XCB_WM_STATE_ICONIC XCB_ICCCM_WM_STATE_ICONIC
79 #endif
80
81 #include <private/qguiapplication_p.h>
82 #include <private/qwindow_p.h>
83
84 #include <QtGui/QPlatformBackingStore>
85 #include <QtGui/QWindowSystemInterface>
86
87 #include <stdio.h>
88
89 #ifdef XCB_USE_XLIB
90 #include <X11/Xlib.h>
91 #include <X11/Xutil.h>
92 #endif
93
94 #if defined(XCB_USE_GLX)
95 #include "qglxintegration.h"
96 #include <QtPlatformSupport/private/qglxconvenience_p.h>
97 #elif defined(XCB_USE_EGL)
98 #include "qxcbeglsurface.h"
99 #include <QtPlatformSupport/private/qeglconvenience_p.h>
100 #include <QtPlatformSupport/private/qxlibeglintegration_p.h>
101 #endif
102
103 #define XCOORD_MAX 16383
104
105 //#ifdef NET_WM_STATE_DEBUG
106
107 QT_BEGIN_NAMESPACE
108
109 // Returns true if we should set WM_TRANSIENT_FOR on \a w
110 static inline bool isTransient(const QWindow *w)
111 {
112     return w->windowType() == Qt::Dialog
113            || w->windowType() == Qt::Sheet
114            || w->windowType() == Qt::Tool
115            || w->windowType() == Qt::SplashScreen
116            || w->windowType() == Qt::ToolTip
117            || w->windowType() == Qt::Drawer
118            || w->windowType() == Qt::Popup;
119 }
120
121 QXcbWindow::QXcbWindow(QWindow *window)
122     : QPlatformWindow(window)
123     , m_window(0)
124     , m_syncCounter(0)
125     , m_mapped(false)
126     , m_transparent(false)
127     , m_netWmUserTimeWindow(XCB_NONE)
128 #if defined(XCB_USE_EGL)
129     , m_eglSurface(0)
130 #endif
131 {
132     m_screen = static_cast<QXcbScreen *>(window->screen()->handle());
133
134     setConnection(m_screen->connection());
135
136     create();
137 }
138
139 void QXcbWindow::create()
140 {
141     destroy();
142
143     m_windowState = Qt::WindowNoState;
144
145     Qt::WindowType type = window()->windowType();
146
147     if (type == Qt::Desktop) {
148         m_window = m_screen->root();
149         m_depth = m_screen->screen()->root_depth;
150         m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
151         connection()->addWindow(m_window, this);
152         return;
153     }
154
155     const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER | XCB_CW_EVENT_MASK;
156     const quint32 values[] = {
157         // XCB_CW_BACK_PIXMAP
158         XCB_NONE,
159         // XCB_CW_OVERRIDE_REDIRECT
160         type == Qt::Popup || type == Qt::ToolTip,
161         // XCB_CW_SAVE_UNDER
162         type == Qt::Popup || type == Qt::Tool || type == Qt::SplashScreen || type == Qt::ToolTip || type == Qt::Drawer,
163         // XCB_CW_EVENT_MASK
164         XCB_EVENT_MASK_EXPOSURE
165         | XCB_EVENT_MASK_STRUCTURE_NOTIFY
166         | XCB_EVENT_MASK_KEY_PRESS
167         | XCB_EVENT_MASK_KEY_RELEASE
168         | XCB_EVENT_MASK_BUTTON_PRESS
169         | XCB_EVENT_MASK_BUTTON_RELEASE
170         | XCB_EVENT_MASK_BUTTON_MOTION
171         | XCB_EVENT_MASK_ENTER_WINDOW
172         | XCB_EVENT_MASK_LEAVE_WINDOW
173         | XCB_EVENT_MASK_POINTER_MOTION
174         | XCB_EVENT_MASK_PROPERTY_CHANGE
175         | XCB_EVENT_MASK_FOCUS_CHANGE
176     };
177
178     QRect rect = window()->geometry();
179     QPlatformWindow::setGeometry(rect);
180
181     rect.setWidth(qBound(1, rect.width(), XCOORD_MAX));
182     rect.setHeight(qBound(1, rect.height(), XCOORD_MAX));
183
184     xcb_window_t xcb_parent_id = m_screen->root();
185     if (parent())
186         xcb_parent_id = static_cast<QXcbWindow *>(parent())->xcb_window();
187
188     m_requestedFormat = window()->format();
189
190 #if (defined(XCB_USE_GLX) || defined(XCB_USE_EGL)) && defined(XCB_USE_XLIB)
191     if (QGuiApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)
192         || window()->format().hasAlpha())
193     {
194 #if defined(XCB_USE_GLX)
195         XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), window()->format());
196
197 #elif defined(XCB_USE_EGL)
198         EGLDisplay eglDisplay = connection()->egl_display();
199         EGLConfig eglConfig = q_configFromGLFormat(eglDisplay, window()->format(), true);
200         VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
201
202         XVisualInfo visualInfoTemplate;
203         memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
204         visualInfoTemplate.visualid = id;
205
206         XVisualInfo *visualInfo;
207         int matchingCount = 0;
208         visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
209 #endif //XCB_USE_GLX
210         if (visualInfo) {
211             m_depth = visualInfo->depth;
212             m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
213             Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), xcb_parent_id, visualInfo->visual, AllocNone);
214
215             XSetWindowAttributes a;
216             a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
217             a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
218             a.colormap = cmap;
219             m_window = XCreateWindow(DISPLAY_FROM_XCB(this), xcb_parent_id, rect.x(), rect.y(), rect.width(), rect.height(),
220                                       0, visualInfo->depth, InputOutput, visualInfo->visual,
221                                       CWBackPixel|CWBorderPixel|CWColormap, &a);
222         } else {
223             qFatal("no window!");
224         }
225     } else
226 #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
227     {
228         m_window = xcb_generate_id(xcb_connection());
229         m_depth = m_screen->screen()->root_depth;
230         m_imageFormat = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
231
232         Q_XCB_CALL(xcb_create_window(xcb_connection(),
233                                      XCB_COPY_FROM_PARENT,            // depth -- same as root
234                                      m_window,                        // window id
235                                      xcb_parent_id,                   // parent window id
236                                      rect.x(),
237                                      rect.y(),
238                                      rect.width(),
239                                      rect.height(),
240                                      0,                               // border width
241                                      XCB_WINDOW_CLASS_INPUT_OUTPUT,   // window class
242                                      m_screen->screen()->root_visual, // visual
243                                      0,                               // value mask
244                                      0));                             // value list
245     }
246
247     connection()->addWindow(m_window, this);
248
249     Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
250
251     propagateSizeHints();
252
253     xcb_atom_t properties[4];
254     int propertyCount = 0;
255     properties[propertyCount++] = atom(QXcbAtom::WM_DELETE_WINDOW);
256     properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
257     properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
258
259     if (m_screen->syncRequestSupported())
260         properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
261
262     if (window()->windowFlags() & Qt::WindowContextHelpButtonHint)
263         properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP);
264
265     Q_XCB_CALL(xcb_change_property(xcb_connection(),
266                                    XCB_PROP_MODE_REPLACE,
267                                    m_window,
268                                    atom(QXcbAtom::WM_PROTOCOLS),
269                                    XCB_ATOM_ATOM,
270                                    32,
271                                    propertyCount,
272                                    properties));
273     m_syncValue.hi = 0;
274     m_syncValue.lo = 0;
275
276     if (m_screen->syncRequestSupported()) {
277         m_syncCounter = xcb_generate_id(xcb_connection());
278         Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue));
279
280         Q_XCB_CALL(xcb_change_property(xcb_connection(),
281                                        XCB_PROP_MODE_REPLACE,
282                                        m_window,
283                                        atom(QXcbAtom::_NET_WM_SYNC_REQUEST_COUNTER),
284                                        XCB_ATOM_CARDINAL,
285                                        32,
286                                        1,
287                                        &m_syncCounter));
288     }
289
290     // set the PID to let the WM kill the application if unresponsive
291     long pid = getpid();
292     Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
293                                    atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
294                                    1, &pid));
295
296     xcb_wm_hints_t hints;
297     memset(&hints, 0, sizeof(hints));
298     xcb_wm_hints_set_normal(&hints);
299
300     xcb_set_wm_hints(xcb_connection(), m_window, &hints);
301
302     xcb_window_t leader = m_screen->clientLeader();
303     Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
304                                    atom(QXcbAtom::WM_CLIENT_LEADER), XCB_ATOM_WINDOW, 32,
305                                    1, &leader));
306
307     setWindowFlags(window()->windowFlags());
308     setWindowTitle(window()->windowTitle());
309     setWindowState(window()->windowState());
310
311     if (window()->windowFlags() & Qt::WindowTransparentForInput)
312         setTransparentForMouseEvents(true);
313
314     connection()->drag()->dndEnable(this, true);
315 }
316
317 QXcbWindow::~QXcbWindow()
318 {
319     destroy();
320 }
321
322 void QXcbWindow::destroy()
323 {
324     if (m_syncCounter && m_screen->syncRequestSupported())
325         Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
326     if (m_window) {
327         connection()->removeWindow(m_window);
328         Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
329     }
330     m_mapped = false;
331
332 #if defined(XCB_USE_EGL)
333     delete m_eglSurface;
334     m_eglSurface = 0;
335 #endif
336 }
337
338 void QXcbWindow::setGeometry(const QRect &rect)
339 {
340     QPlatformWindow::setGeometry(rect);
341
342     propagateSizeHints();
343
344     const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
345     const quint32 values[] = { rect.x(),
346                                rect.y(),
347                                qBound(1, rect.width(), XCOORD_MAX),
348                                qBound(1, rect.height(), XCOORD_MAX) };
349
350     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
351
352     xcb_flush(xcb_connection());
353 }
354
355 QMargins QXcbWindow::frameMargins() const
356 {
357     if (m_dirtyFrameMargins) {
358         xcb_window_t window = m_window;
359         xcb_window_t parent = m_window;
360
361         bool foundRoot = false;
362
363         const QVector<xcb_window_t> &virtualRoots =
364             connection()->wmSupport()->virtualRoots();
365
366         while (!foundRoot) {
367             xcb_query_tree_cookie_t cookie = xcb_query_tree(xcb_connection(), parent);
368
369             xcb_generic_error_t *error;
370             xcb_query_tree_reply_t *reply = xcb_query_tree_reply(xcb_connection(), cookie, &error);
371             if (reply) {
372                 if (reply->root == reply->parent || virtualRoots.indexOf(reply->parent) != -1) {
373                     foundRoot = true;
374                 } else {
375                     window = parent;
376                     parent = reply->parent;
377                 }
378
379                 free(reply);
380             } else {
381                 if (error) {
382                     connection()->handleXcbError(error);
383                     free(error);
384                 }
385
386                 m_dirtyFrameMargins = false;
387                 m_frameMargins = QMargins();
388                 return m_frameMargins;
389             }
390         }
391
392         QPoint offset;
393
394         xcb_generic_error_t *error;
395         xcb_translate_coordinates_reply_t *reply =
396             xcb_translate_coordinates_reply(
397                 xcb_connection(),
398                 xcb_translate_coordinates(xcb_connection(), window, parent, 0, 0),
399                 &error);
400
401         if (reply) {
402             offset = QPoint(reply->dst_x, reply->dst_y);
403             free(reply);
404         } else if (error) {
405             free(error);
406         }
407
408         xcb_get_geometry_reply_t *geom =
409             xcb_get_geometry_reply(
410                 xcb_connection(),
411                 xcb_get_geometry(xcb_connection(), parent),
412                 &error);
413
414         if (geom) {
415             // --
416             // add the border_width for the window managers frame... some window managers
417             // do not use a border_width of zero for their frames, and if we the left and
418             // top strut, we ensure that pos() is absolutely correct.  frameGeometry()
419             // will still be incorrect though... perhaps i should have foffset as well, to
420             // indicate the frame offset (equal to the border_width on X).
421             // - Brad
422             // -- copied from qwidget_x11.cpp
423
424             int left = offset.x() + geom->border_width;
425             int top = offset.y() + geom->border_width;
426             int right = geom->width + geom->border_width - geometry().width() - offset.x();
427             int bottom = geom->height + geom->border_width - geometry().height() - offset.y();
428
429             m_frameMargins = QMargins(left, top, right, bottom);
430
431             free(geom);
432         } else if (error) {
433             free(error);
434         }
435
436         m_dirtyFrameMargins = false;
437     }
438
439     return m_frameMargins;
440 }
441
442 void QXcbWindow::setVisible(bool visible)
443 {
444     if (visible)
445         show();
446     else
447         hide();
448 }
449
450 void QXcbWindow::show()
451 {
452     if (window()->isTopLevel()) {
453         xcb_get_property_cookie_t cookie = xcb_get_wm_hints(xcb_connection(), m_window);
454
455         xcb_generic_error_t *error;
456
457         xcb_wm_hints_t hints;
458         xcb_get_wm_hints_reply(xcb_connection(), cookie, &hints, &error);
459
460         if (error) {
461             connection()->handleXcbError(error);
462             free(error);
463         }
464
465         if (window()->windowState() & Qt::WindowMinimized)
466             xcb_wm_hints_set_iconic(&hints);
467         else
468             xcb_wm_hints_set_normal(&hints);
469
470         xcb_set_wm_hints(xcb_connection(), m_window, &hints);
471
472         // update WM_NORMAL_HINTS
473         propagateSizeHints();
474
475         // update WM_TRANSIENT_FOR
476         if (window()->transientParent() && isTransient(window())) {
477             QXcbWindow *transientXcbParent = static_cast<QXcbWindow *>(window()->transientParent()->handle());
478             if (transientXcbParent) {
479                 // ICCCM 4.1.2.6
480                 xcb_window_t parentWindow = transientXcbParent->xcb_window();
481
482                 // todo: set transient for group (wm_client_leader) if no parent, a la qwidget_x11.cpp
483                 Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
484                                                XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
485                                                1, &parentWindow));
486             }
487         }
488
489         // update _MOTIF_WM_HINTS
490         updateMotifWmHintsBeforeMap();
491
492         // update _NET_WM_STATE
493         updateNetWmStateBeforeMap();
494     }
495
496     Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
497     xcb_flush(xcb_connection());
498
499     connection()->sync();
500 }
501
502 void QXcbWindow::hide()
503 {
504     Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
505
506     // send synthetic UnmapNotify event according to icccm 4.1.4
507     xcb_unmap_notify_event_t event;
508     event.response_type = XCB_UNMAP_NOTIFY;
509     event.event = m_screen->root();
510     event.window = m_window;
511     event.from_configure = false;
512     Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(),
513                               XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
514
515     xcb_flush(xcb_connection());
516
517     m_mapped = false;
518 }
519
520 struct QtMotifWmHints {
521     quint32 flags, functions, decorations;
522     qint32 input_mode;
523     quint32 status;
524 };
525
526 enum {
527     MWM_HINTS_FUNCTIONS   = (1L << 0),
528
529     MWM_FUNC_ALL      = (1L << 0),
530     MWM_FUNC_RESIZE   = (1L << 1),
531     MWM_FUNC_MOVE     = (1L << 2),
532     MWM_FUNC_MINIMIZE = (1L << 3),
533     MWM_FUNC_MAXIMIZE = (1L << 4),
534     MWM_FUNC_CLOSE    = (1L << 5),
535
536     MWM_HINTS_DECORATIONS = (1L << 1),
537
538     MWM_DECOR_ALL      = (1L << 0),
539     MWM_DECOR_BORDER   = (1L << 1),
540     MWM_DECOR_RESIZEH  = (1L << 2),
541     MWM_DECOR_TITLE    = (1L << 3),
542     MWM_DECOR_MENU     = (1L << 4),
543     MWM_DECOR_MINIMIZE = (1L << 5),
544     MWM_DECOR_MAXIMIZE = (1L << 6),
545
546     MWM_HINTS_INPUT_MODE = (1L << 2),
547
548     MWM_INPUT_MODELESS                  = 0L,
549     MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L,
550     MWM_INPUT_FULL_APPLICATION_MODAL    = 3L
551 };
552
553 static QtMotifWmHints getMotifWmHints(QXcbConnection *c, xcb_window_t window)
554 {
555     QtMotifWmHints hints;
556
557     xcb_get_property_cookie_t get_cookie =
558         xcb_get_property(c->xcb_connection(), 0, window, c->atom(QXcbAtom::_MOTIF_WM_HINTS),
559                          c->atom(QXcbAtom::_MOTIF_WM_HINTS), 0, 20);
560
561     xcb_generic_error_t *error;
562
563     xcb_get_property_reply_t *reply =
564         xcb_get_property_reply(c->xcb_connection(), get_cookie, &error);
565
566     if (reply && reply->format == 32 && reply->type == c->atom(QXcbAtom::_MOTIF_WM_HINTS)) {
567         hints = *((QtMotifWmHints *)xcb_get_property_value(reply));
568     } else if (error) {
569         c->handleXcbError(error);
570         free(error);
571
572         hints.flags = 0L;
573         hints.functions = MWM_FUNC_ALL;
574         hints.decorations = MWM_DECOR_ALL;
575         hints.input_mode = 0L;
576         hints.status = 0L;
577     }
578
579     free(reply);
580
581     return hints;
582 }
583
584 static void setMotifWmHints(QXcbConnection *c, xcb_window_t window, const QtMotifWmHints &hints)
585 {
586     if (hints.flags != 0l) {
587         Q_XCB_CALL2(xcb_change_property(c->xcb_connection(),
588                                        XCB_PROP_MODE_REPLACE,
589                                        window,
590                                        c->atom(QXcbAtom::_MOTIF_WM_HINTS),
591                                        c->atom(QXcbAtom::_MOTIF_WM_HINTS),
592                                        32,
593                                        5,
594                                        &hints), c);
595     } else {
596         Q_XCB_CALL2(xcb_delete_property(c->xcb_connection(), window, c->atom(QXcbAtom::_MOTIF_WM_HINTS)), c);
597     }
598 }
599
600 void QXcbWindow::printNetWmState(const QVector<xcb_atom_t> &state)
601 {
602     printf("_NET_WM_STATE (%d): ", state.size());
603     for (int i = 0; i < state.size(); ++i) {
604 #define CHECK_WM_STATE(state_atom) \
605         if (state.at(i) == atom(QXcbAtom::state_atom))\
606             printf(#state_atom " ");
607         CHECK_WM_STATE(_NET_WM_STATE_ABOVE)
608         CHECK_WM_STATE(_NET_WM_STATE_BELOW)
609         CHECK_WM_STATE(_NET_WM_STATE_FULLSCREEN)
610         CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_HORZ)
611         CHECK_WM_STATE(_NET_WM_STATE_MAXIMIZED_VERT)
612         CHECK_WM_STATE(_NET_WM_STATE_MODAL)
613         CHECK_WM_STATE(_NET_WM_STATE_STAYS_ON_TOP)
614         CHECK_WM_STATE(_NET_WM_STATE_DEMANDS_ATTENTION)
615 #undef CHECK_WM_STATE
616     }
617     printf("\n");
618 }
619
620 QVector<xcb_atom_t> QXcbWindow::getNetWmState()
621 {
622     QVector<xcb_atom_t> result;
623
624     xcb_get_property_cookie_t get_cookie =
625         xcb_get_property(xcb_connection(), 0, m_window, atom(QXcbAtom::_NET_WM_STATE),
626                          XCB_ATOM_ATOM, 0, 1024);
627
628     xcb_generic_error_t *error;
629
630     xcb_get_property_reply_t *reply =
631         xcb_get_property_reply(xcb_connection(), get_cookie, &error);
632
633     if (reply && reply->format == 32 && reply->type == XCB_ATOM_ATOM) {
634         result.resize(reply->length);
635
636         memcpy(result.data(), xcb_get_property_value(reply), reply->length * sizeof(xcb_atom_t));
637
638 #ifdef NET_WM_STATE_DEBUG
639         printf("getting net wm state (%x)\n", m_window);
640         printNetWmState(result);
641 #endif
642
643         free(reply);
644     } else if (error) {
645         connection()->handleXcbError(error);
646         free(error);
647     } else {
648 #ifdef NET_WM_STATE_DEBUG
649         printf("getting net wm state (%x), empty\n", m_window);
650 #endif
651     }
652
653     return result;
654 }
655
656 void QXcbWindow::setNetWmState(const QVector<xcb_atom_t> &atoms)
657 {
658     if (atoms.isEmpty()) {
659         Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_STATE)));
660     } else {
661         Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
662                                        atom(QXcbAtom::_NET_WM_STATE), XCB_ATOM_ATOM, 32,
663                                        atoms.count(), atoms.constData()));
664     }
665     xcb_flush(xcb_connection());
666 }
667
668
669 Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
670 {
671     Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
672
673     if (type == Qt::ToolTip)
674         flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
675     if (type == Qt::Popup)
676         flags |= Qt::X11BypassWindowManagerHint;
677
678     if (flags & Qt::WindowTransparentForInput) {
679         uint32_t mask = XCB_EVENT_MASK_NO_EVENT;
680         xcb_change_window_attributes(xcb_connection(), xcb_window(), XCB_CW_EVENT_MASK, &mask);
681     }
682
683     setNetWmWindowFlags(flags);
684     setMotifWindowFlags(flags);
685
686     setTransparentForMouseEvents(flags & Qt::WindowTransparentForInput);
687
688     return flags;
689 }
690
691 void QXcbWindow::setMotifWindowFlags(Qt::WindowFlags flags)
692 {
693     Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
694
695     QtMotifWmHints mwmhints;
696     mwmhints.flags = 0L;
697     mwmhints.functions = 0L;
698     mwmhints.decorations = 0;
699     mwmhints.input_mode = 0L;
700     mwmhints.status = 0L;
701
702     if (type != Qt::SplashScreen) {
703         mwmhints.flags |= MWM_HINTS_DECORATIONS;
704
705         bool customize = flags & Qt::CustomizeWindowHint;
706         if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
707             mwmhints.decorations |= MWM_DECOR_BORDER;
708             mwmhints.decorations |= MWM_DECOR_RESIZEH;
709
710             if (flags & Qt::WindowTitleHint)
711                 mwmhints.decorations |= MWM_DECOR_TITLE;
712
713             if (flags & Qt::WindowSystemMenuHint)
714                 mwmhints.decorations |= MWM_DECOR_MENU;
715
716             if (flags & Qt::WindowMinimizeButtonHint) {
717                 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
718                 mwmhints.functions |= MWM_FUNC_MINIMIZE;
719             }
720
721             if (flags & Qt::WindowMaximizeButtonHint) {
722                 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
723                 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
724             }
725
726             if (flags & Qt::WindowCloseButtonHint)
727                 mwmhints.functions |= MWM_FUNC_CLOSE;
728         }
729     } else {
730         // if type == Qt::SplashScreen
731         mwmhints.decorations = MWM_DECOR_ALL;
732     }
733
734     if (mwmhints.functions != 0) {
735         mwmhints.flags |= MWM_HINTS_FUNCTIONS;
736         mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
737     } else {
738         mwmhints.functions = MWM_FUNC_ALL;
739     }
740
741     if (!(flags & Qt::FramelessWindowHint)
742         && flags & Qt::CustomizeWindowHint
743         && flags & Qt::WindowTitleHint
744         && !(flags &
745              (Qt::WindowMinimizeButtonHint
746               | Qt::WindowMaximizeButtonHint
747               | Qt::WindowCloseButtonHint)))
748     {
749         // a special case - only the titlebar without any button
750         mwmhints.flags = MWM_HINTS_FUNCTIONS;
751         mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
752         mwmhints.decorations = 0;
753     }
754
755     setMotifWmHints(connection(), m_window, mwmhints);
756 }
757
758 void QXcbWindow::changeNetWmState(bool set, xcb_atom_t one, xcb_atom_t two)
759 {
760     xcb_client_message_event_t event;
761
762     event.response_type = XCB_CLIENT_MESSAGE;
763     event.format = 32;
764     event.window = m_window;
765     event.type = atom(QXcbAtom::_NET_WM_STATE);
766     event.data.data32[0] = set ? 1 : 0;
767     event.data.data32[1] = one;
768     event.data.data32[2] = two;
769     event.data.data32[3] = 0;
770     event.data.data32[4] = 0;
771
772     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));
773 }
774
775 Qt::WindowState QXcbWindow::setWindowState(Qt::WindowState state)
776 {
777     if (state == m_windowState)
778         return state;
779
780     // unset old state
781     switch (m_windowState) {
782     case Qt::WindowMinimized:
783         Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
784         break;
785     case Qt::WindowMaximized:
786         changeNetWmState(false,
787                          atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
788                          atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
789         break;
790     case Qt::WindowFullScreen:
791         changeNetWmState(false, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
792         break;
793     default:
794         break;
795     }
796
797     // set new state
798     switch (state) {
799     case Qt::WindowMinimized:
800         {
801             xcb_client_message_event_t event;
802
803             event.response_type = XCB_CLIENT_MESSAGE;
804             event.format = 32;
805             event.window = m_window;
806             event.type = atom(QXcbAtom::WM_CHANGE_STATE);
807             event.data.data32[0] = XCB_WM_STATE_ICONIC;
808             event.data.data32[1] = 0;
809             event.data.data32[2] = 0;
810             event.data.data32[3] = 0;
811             event.data.data32[4] = 0;
812
813             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));
814         }
815         break;
816     case Qt::WindowMaximized:
817         changeNetWmState(true,
818                          atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ),
819                          atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
820         break;
821     case Qt::WindowFullScreen:
822         changeNetWmState(true, atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
823         break;
824     case Qt::WindowNoState:
825         break;
826     default:
827         break;
828     }
829
830     connection()->sync();
831
832     m_windowState = state;
833     return m_windowState;
834 }
835
836 void QXcbWindow::setNetWmWindowFlags(Qt::WindowFlags flags)
837 {
838     // in order of decreasing priority
839     QVector<uint> windowTypes;
840
841     Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
842
843     switch (type) {
844     case Qt::Dialog:
845     case Qt::Sheet:
846         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG));
847         break;
848     case Qt::Tool:
849     case Qt::Drawer:
850         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY));
851         break;
852     case Qt::ToolTip:
853         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP));
854         break;
855     case Qt::SplashScreen:
856         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH));
857         break;
858     default:
859         break;
860     }
861
862     if (flags & Qt::FramelessWindowHint)
863         windowTypes.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
864
865     windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL));
866
867     Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
868                                    atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
869                                    windowTypes.count(), windowTypes.constData()));
870 }
871
872 void QXcbWindow::updateMotifWmHintsBeforeMap()
873 {
874     QtMotifWmHints mwmhints = getMotifWmHints(connection(), m_window);
875
876     if (window()->windowModality() != Qt::NonModal) {
877         switch (window()->windowModality()) {
878         case Qt::WindowModal:
879             mwmhints.input_mode = MWM_INPUT_PRIMARY_APPLICATION_MODAL;
880             break;
881         case Qt::ApplicationModal:
882         default:
883             mwmhints.input_mode = MWM_INPUT_FULL_APPLICATION_MODAL;
884             break;
885         }
886         mwmhints.flags |= MWM_HINTS_INPUT_MODE;
887     } else {
888         mwmhints.input_mode = MWM_INPUT_MODELESS;
889         mwmhints.flags &= ~MWM_HINTS_INPUT_MODE;
890     }
891
892     if (window()->minimumSize() == window()->maximumSize()) {
893         // fixed size, remove the resize handle (since mwm/dtwm
894         // isn't smart enough to do it itself)
895         mwmhints.flags |= MWM_HINTS_FUNCTIONS;
896         if (mwmhints.functions == MWM_FUNC_ALL) {
897             mwmhints.functions = MWM_FUNC_MOVE;
898         } else {
899             mwmhints.functions &= ~MWM_FUNC_RESIZE;
900         }
901
902         if (mwmhints.decorations == MWM_DECOR_ALL) {
903             mwmhints.flags |= MWM_HINTS_DECORATIONS;
904             mwmhints.decorations = (MWM_DECOR_BORDER
905                                     | MWM_DECOR_TITLE
906                                     | MWM_DECOR_MENU);
907         } else {
908             mwmhints.decorations &= ~MWM_DECOR_RESIZEH;
909         }
910     }
911
912     if (window()->windowFlags() & Qt::WindowMinimizeButtonHint) {
913         mwmhints.flags |= MWM_HINTS_DECORATIONS;
914         mwmhints.decorations |= MWM_DECOR_MINIMIZE;
915         mwmhints.functions |= MWM_FUNC_MINIMIZE;
916     }
917     if (window()->windowFlags() & Qt::WindowMaximizeButtonHint) {
918         mwmhints.flags |= MWM_HINTS_DECORATIONS;
919         mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
920         mwmhints.functions |= MWM_FUNC_MAXIMIZE;
921     }
922     if (window()->windowFlags() & Qt::WindowCloseButtonHint)
923         mwmhints.functions |= MWM_FUNC_CLOSE;
924
925     setMotifWmHints(connection(), m_window, mwmhints);
926 }
927
928 void QXcbWindow::updateNetWmStateBeforeMap()
929 {
930     QVector<xcb_atom_t> netWmState;
931
932     Qt::WindowFlags flags = window()->windowFlags();
933     if (flags & Qt::WindowStaysOnTopHint) {
934         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_ABOVE));
935         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_STAYS_ON_TOP));
936     } else if (flags & Qt::WindowStaysOnBottomHint) {
937         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_BELOW));
938     }
939
940     if (window()->windowState() & Qt::WindowFullScreen) {
941         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_FULLSCREEN));
942     }
943
944     if (window()->windowState() & Qt::WindowMaximized) {
945         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_HORZ));
946         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MAXIMIZED_VERT));
947     }
948
949     if (window()->windowModality() != Qt::NonModal) {
950         netWmState.append(atom(QXcbAtom::_NET_WM_STATE_MODAL));
951     }
952
953     setNetWmState(netWmState);
954 }
955
956 void QXcbWindow::updateNetWmUserTime(xcb_timestamp_t timestamp)
957 {
958     xcb_window_t wid = m_window;
959
960     const bool isSupportedByWM = connection()->wmSupport()->isSupportedByWM(atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
961     if (m_netWmUserTimeWindow || isSupportedByWM) {
962         if (!m_netWmUserTimeWindow) {
963             m_netWmUserTimeWindow = xcb_generate_id(xcb_connection());
964             Q_XCB_CALL(xcb_create_window(xcb_connection(),
965                                          XCB_COPY_FROM_PARENT,            // depth -- same as root
966                                          m_netWmUserTimeWindow,                        // window id
967                                          m_window,                   // parent window id
968                                          -1, -1, 1, 1,
969                                          0,                               // border width
970                                          XCB_WINDOW_CLASS_INPUT_OUTPUT,   // window class
971                                          m_screen->screen()->root_visual, // visual
972                                          0,                               // value mask
973                                          0));                             // value list
974             wid = m_netWmUserTimeWindow;
975             xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW),
976                                 XCB_ATOM_WINDOW, 32, 1, &m_netWmUserTimeWindow);
977             xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME));
978         } else if (!isSupportedByWM) {
979             // WM no longer supports it, then we should remove the
980             // _NET_WM_USER_TIME_WINDOW atom.
981             xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_NET_WM_USER_TIME_WINDOW));
982             xcb_destroy_window(xcb_connection(), m_netWmUserTimeWindow);
983             m_netWmUserTimeWindow = XCB_NONE;
984         } else {
985             wid = m_netWmUserTimeWindow;
986         }
987     }
988     xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, wid, atom(QXcbAtom::_NET_WM_USER_TIME),
989                         XCB_ATOM_CARDINAL, 32, 1, &timestamp);
990 }
991
992 void QXcbWindow::setTransparentForMouseEvents(bool transparent)
993 {
994     if (transparent == m_transparent)
995         return;
996
997     xcb_rectangle_t rectangle;
998
999     xcb_rectangle_t *rect = 0;
1000     int nrect = 0;
1001
1002     if (!transparent) {
1003         rectangle.x = 0;
1004         rectangle.y = 0;
1005         rectangle.width = geometry().width();
1006         rectangle.height = geometry().height();
1007         rect = &rectangle;
1008         nrect = 1;
1009     }
1010
1011     xcb_xfixes_region_t region = xcb_generate_id(xcb_connection());
1012     xcb_xfixes_create_region(xcb_connection(), region, nrect, rect);
1013     xcb_xfixes_set_window_shape_region_checked(xcb_connection(), m_window, XCB_SHAPE_SK_INPUT, 0, 0, region);
1014     xcb_xfixes_destroy_region(xcb_connection(), region);
1015
1016     m_transparent = transparent;
1017 }
1018
1019
1020 WId QXcbWindow::winId() const
1021 {
1022     return m_window;
1023 }
1024
1025 void QXcbWindow::setParent(const QPlatformWindow *parent)
1026 {
1027     // re-create for compatibility
1028     create();
1029
1030     QPoint topLeft = geometry().topLeft();
1031
1032     xcb_window_t xcb_parent_id = parent ? static_cast<const QXcbWindow *>(parent)->xcb_window() : m_screen->root();
1033     Q_XCB_CALL(xcb_reparent_window(xcb_connection(), xcb_window(), xcb_parent_id, topLeft.x(), topLeft.y()));
1034 }
1035
1036 void QXcbWindow::setWindowTitle(const QString &title)
1037 {
1038     QByteArray ba = title.toUtf8();
1039     Q_XCB_CALL(xcb_change_property(xcb_connection(),
1040                                    XCB_PROP_MODE_REPLACE,
1041                                    m_window,
1042                                    atom(QXcbAtom::_NET_WM_NAME),
1043                                    atom(QXcbAtom::UTF8_STRING),
1044                                    8,
1045                                    ba.length(),
1046                                    ba.constData()));
1047 }
1048
1049 void QXcbWindow::raise()
1050 {
1051     const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE;
1052     const quint32 values[] = { XCB_STACK_MODE_ABOVE };
1053     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
1054 }
1055
1056 void QXcbWindow::lower()
1057 {
1058     const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE;
1059     const quint32 values[] = { XCB_STACK_MODE_BELOW };
1060     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
1061 }
1062
1063 void QXcbWindow::propagateSizeHints()
1064 {
1065     // update WM_NORMAL_HINTS
1066     xcb_size_hints_t hints;
1067     memset(&hints, 0, sizeof(hints));
1068
1069     QRect rect = geometry();
1070
1071     QWindow *win = window();
1072
1073     xcb_size_hints_set_position(&hints, true, rect.x(), rect.y());
1074     xcb_size_hints_set_size(&hints, true, rect.width(), rect.height());
1075     xcb_size_hints_set_win_gravity(&hints, qt_window_private(win)->positionPolicy == QWindowPrivate::WindowFrameInclusive
1076                                            ? XCB_GRAVITY_NORTH_WEST : XCB_GRAVITY_STATIC);
1077
1078     QSize minimumSize = win->minimumSize();
1079     QSize maximumSize = win->maximumSize();
1080     QSize baseSize = win->baseSize();
1081     QSize sizeIncrement = win->sizeIncrement();
1082
1083     if (minimumSize.width() > 0 || minimumSize.height() > 0)
1084         xcb_size_hints_set_min_size(&hints, minimumSize.width(), minimumSize.height());
1085
1086     if (maximumSize.width() < QWINDOWSIZE_MAX || maximumSize.height() < QWINDOWSIZE_MAX)
1087         xcb_size_hints_set_max_size(&hints,
1088                                     qMin(XCOORD_MAX, maximumSize.width()),
1089                                     qMin(XCOORD_MAX, maximumSize.height()));
1090
1091     if (sizeIncrement.width() > 0 || sizeIncrement.height() > 0) {
1092         xcb_size_hints_set_base_size(&hints, baseSize.width(), baseSize.height());
1093         xcb_size_hints_set_resize_inc(&hints, sizeIncrement.width(), sizeIncrement.height());
1094     }
1095
1096     xcb_set_wm_normal_hints(xcb_connection(), m_window, &hints);
1097 }
1098
1099 void QXcbWindow::requestActivateWindow()
1100 {
1101     if (m_mapped){
1102         updateNetWmUserTime(connection()->time());
1103         Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, connection()->time()));
1104     }
1105     connection()->sync();
1106 }
1107
1108 QSurfaceFormat QXcbWindow::format() const
1109 {
1110     // ### return actual format
1111     return m_requestedFormat;
1112 }
1113
1114 #if defined(XCB_USE_EGL)
1115 QXcbEGLSurface *QXcbWindow::eglSurface() const
1116 {
1117     if (!m_eglSurface) {
1118         EGLDisplay display = connection()->egl_display();
1119         EGLConfig config = q_configFromGLFormat(display, window()->format(), true);
1120         EGLSurface surface = eglCreateWindowSurface(display, config, (EGLNativeWindowType)m_window, 0);
1121
1122         m_eglSurface = new QXcbEGLSurface(display, surface);
1123     }
1124
1125     return m_eglSurface;
1126 }
1127 #endif
1128
1129 void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
1130 {
1131     QRect rect(event->x, event->y, event->width, event->height);
1132
1133     if (m_exposeRegion.isEmpty())
1134         m_exposeRegion = rect;
1135     else
1136         m_exposeRegion |= rect;
1137
1138     // if count is non-zero there are more expose events pending
1139     if (event->count == 0) {
1140         QWindowSystemInterface::handleSynchronousExposeEvent(window(), m_exposeRegion);
1141         m_exposeRegion = QRegion();
1142     }
1143 }
1144
1145 void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event)
1146 {
1147     if (event->format != 32)
1148         return;
1149
1150     if (event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
1151         if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) {
1152             QWindowSystemInterface::handleCloseEvent(window());
1153         } else if (event->data.data32[0] == atom(QXcbAtom::WM_TAKE_FOCUS)) {
1154             connection()->setTime(event->data.data32[1]);
1155         } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
1156             xcb_client_message_event_t reply = *event;
1157
1158             reply.response_type = XCB_CLIENT_MESSAGE;
1159             reply.window = m_screen->root();
1160
1161             xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply);
1162             xcb_flush(xcb_connection());
1163         } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
1164             connection()->setTime(event->data.data32[1]);
1165             m_syncValue.lo = event->data.data32[2];
1166             m_syncValue.hi = event->data.data32[3];
1167         } else {
1168             qWarning() << "unhandled WM_PROTOCOLS message:" << connection()->atomName(event->data.data32[0]);
1169         }
1170     } else if (event->type == atom(QXcbAtom::XdndEnter)) {
1171         connection()->drag()->handleEnter(window(), event);
1172     } else if (event->type == atom(QXcbAtom::XdndPosition)) {
1173         connection()->drag()->handlePosition(window(), event, false);
1174     } else if (event->type == atom(QXcbAtom::XdndLeave)) {
1175         connection()->drag()->handleLeave(window(), event, false);
1176     } else if (event->type == atom(QXcbAtom::XdndDrop)) {
1177         connection()->drag()->handleDrop(window(), event, false);
1178     } else {
1179         qWarning() << "unhandled client message:" << connection()->atomName(event->type);
1180     }
1181 }
1182
1183 void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event)
1184 {
1185     QRect rect(event->x, event->y, event->width, event->height);
1186
1187     QPlatformWindow::setGeometry(rect);
1188     QWindowSystemInterface::handleGeometryChange(window(), rect);
1189
1190     m_dirtyFrameMargins = true;
1191
1192 #if XCB_USE_DRI2
1193     if (m_context)
1194         static_cast<QDri2Context *>(m_context)->resize(rect.size());
1195 #endif
1196 }
1197
1198 void QXcbWindow::handleMapNotifyEvent(const xcb_map_notify_event_t *event)
1199 {
1200     if (event->window == m_window) {
1201         m_mapped = true;
1202         QWindowSystemInterface::handleMapEvent(window());
1203     }
1204 }
1205
1206 void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event)
1207 {
1208     if (event->window == m_window) {
1209         m_mapped = false;
1210         QWindowSystemInterface::handleUnmapEvent(window());
1211     }
1212 }
1213
1214 static Qt::MouseButtons translateMouseButtons(int s)
1215 {
1216     Qt::MouseButtons ret = 0;
1217     if (s & XCB_BUTTON_MASK_1)
1218         ret |= Qt::LeftButton;
1219     if (s & XCB_BUTTON_MASK_2)
1220         ret |= Qt::MidButton;
1221     if (s & XCB_BUTTON_MASK_3)
1222         ret |= Qt::RightButton;
1223     return ret;
1224 }
1225
1226 static Qt::MouseButton translateMouseButton(xcb_button_t s)
1227 {
1228     switch (s) {
1229     case 1:
1230         return Qt::LeftButton;
1231     case 2:
1232         return Qt::MidButton;
1233     case 3:
1234         return Qt::RightButton;
1235     default:
1236         return Qt::NoButton;
1237     }
1238 }
1239
1240 void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
1241 {
1242     updateNetWmUserTime(event->time);
1243
1244     QPoint local(event->event_x, event->event_y);
1245     QPoint global(event->root_x, event->root_y);
1246
1247     Qt::KeyboardModifiers modifiers = Qt::NoModifier;
1248
1249     if (event->detail >= 4 && event->detail <= 7) {
1250         //logic borrowed from qapplication_x11.cpp
1251         int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
1252         bool hor = (((event->detail == 4 || event->detail == 5)
1253                      && (modifiers & Qt::AltModifier))
1254                     || (event->detail == 6 || event->detail == 7));
1255
1256         QWindowSystemInterface::handleWheelEvent(window(), event->time,
1257                                                  local, global, delta, hor ? Qt::Horizontal : Qt::Vertical);
1258         return;
1259     }
1260
1261     handleMouseEvent(event->detail, event->state, event->time, local, global);
1262 }
1263
1264 void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event)
1265 {
1266     QPoint local(event->event_x, event->event_y);
1267     QPoint global(event->root_x, event->root_y);
1268
1269     handleMouseEvent(event->detail, event->state, event->time, local, global);
1270 }
1271
1272 void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
1273 {
1274     QPoint local(event->event_x, event->event_y);
1275     QPoint global(event->root_x, event->root_y);
1276
1277     handleMouseEvent(event->detail, event->state, event->time, local, global);
1278 }
1279
1280 void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global)
1281 {
1282     connection()->setTime(time);
1283
1284     Qt::MouseButtons buttons = translateMouseButtons(state);
1285     Qt::MouseButton button = translateMouseButton(detail);
1286
1287     buttons ^= button; // X event uses state *before*, Qt uses state *after*
1288
1289     QWindowSystemInterface::handleMouseEvent(window(), time, local, global, buttons);
1290 }
1291
1292 void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event)
1293 {
1294     connection()->setTime(event->time);
1295
1296     if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB)
1297         || event->detail == XCB_NOTIFY_DETAIL_VIRTUAL
1298         || event->detail == XCB_NOTIFY_DETAIL_NONLINEAR_VIRTUAL)
1299     {
1300         return;
1301     }
1302
1303     QWindowSystemInterface::handleEnterEvent(window());
1304 }
1305
1306 void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *event)
1307 {
1308     connection()->setTime(event->time);
1309
1310     if ((event->mode != XCB_NOTIFY_MODE_NORMAL && event->mode != XCB_NOTIFY_MODE_UNGRAB)
1311         || event->detail == XCB_NOTIFY_DETAIL_INFERIOR)
1312     {
1313         return;
1314     }
1315
1316     QWindowSystemInterface::handleLeaveEvent(window());
1317 }
1318
1319 void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
1320 {
1321     QWindowSystemInterface::handleWindowActivated(window());
1322 }
1323
1324 static bool focusInPeeker(xcb_generic_event_t *event)
1325 {
1326     if (!event) {
1327         // FocusIn event is not in the queue, proceed with FocusOut normally.
1328         QWindowSystemInterface::handleWindowActivated(0);
1329         return true;
1330     }
1331     uint response_type = event->response_type & ~0x80;
1332     return response_type == XCB_FOCUS_IN;
1333 }
1334
1335 void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
1336 {
1337     // Do not set the active window to 0 if there is a FocusIn coming.
1338     // There is however no equivalent for XPutBackEvent so register a
1339     // callback for QXcbConnection instead.
1340     connection()->addPeekFunc(focusInPeeker);
1341 }
1342
1343 void QXcbWindow::updateSyncRequestCounter()
1344 {
1345     if (m_screen->syncRequestSupported() && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) {
1346         Q_XCB_CALL(xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue));
1347         xcb_flush(xcb_connection());
1348         connection()->sync();
1349
1350         m_syncValue.lo = 0;
1351         m_syncValue.hi = 0;
1352     }
1353 }
1354
1355 bool QXcbWindow::setKeyboardGrabEnabled(bool grab)
1356 {
1357     if (!grab) {
1358         xcb_ungrab_keyboard(xcb_connection(), XCB_TIME_CURRENT_TIME);
1359         return true;
1360     }
1361     xcb_grab_keyboard_cookie_t cookie = xcb_grab_keyboard(xcb_connection(), false,
1362                                                           m_window, XCB_TIME_CURRENT_TIME,
1363                                                           XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);
1364     xcb_generic_error_t *err;
1365     xcb_grab_keyboard_reply_t *reply = xcb_grab_keyboard_reply(xcb_connection(), cookie, &err);
1366     bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
1367     free(reply);
1368     free(err);
1369     return result;
1370 }
1371
1372 bool QXcbWindow::setMouseGrabEnabled(bool grab)
1373 {
1374     if (!grab) {
1375         xcb_ungrab_pointer(xcb_connection(), XCB_TIME_CURRENT_TIME);
1376         return true;
1377     }
1378     xcb_grab_pointer_cookie_t cookie = xcb_grab_pointer(xcb_connection(), false, m_window,
1379                                                         (XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE
1380                                                          | XCB_EVENT_MASK_BUTTON_MOTION | XCB_EVENT_MASK_ENTER_WINDOW
1381                                                          | XCB_EVENT_MASK_LEAVE_WINDOW | XCB_EVENT_MASK_POINTER_MOTION),
1382                                                         XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
1383                                                         XCB_WINDOW_NONE, XCB_CURSOR_NONE,
1384                                                         XCB_TIME_CURRENT_TIME);
1385     xcb_generic_error_t *err;
1386     xcb_grab_pointer_reply_t *reply = xcb_grab_pointer_reply(xcb_connection(), cookie, &err);
1387     bool result = !(err || !reply || reply->status != XCB_GRAB_STATUS_SUCCESS);
1388     free(reply);
1389     free(err);
1390     return result;
1391 }
1392
1393 void QXcbWindow::setCursor(xcb_cursor_t cursor)
1394 {
1395     xcb_change_window_attributes(xcb_connection(), m_window, XCB_CW_CURSOR, &cursor);
1396     xcb_flush(xcb_connection());
1397 }
1398
1399 QT_END_NAMESPACE