3365c22c391302733421ea48eeacbf4a582f76f0
[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 ** No Commercial Usage
11 ** This file contains pre-release code and may not be distributed.
12 ** You may use this file in accordance with the terms and conditions
13 ** contained in the Technology Preview License Agreement accompanying
14 ** this package.
15 **
16 ** GNU Lesser General Public License Usage
17 ** Alternatively, this file may be used under the terms of the GNU Lesser
18 ** General Public License version 2.1 as published by the Free Software
19 ** Foundation and appearing in the file LICENSE.LGPL included in the
20 ** packaging of this file.  Please review the following information to
21 ** ensure the GNU Lesser General Public License version 2.1 requirements
22 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
23 **
24 ** In addition, as a special exception, Nokia gives you certain additional
25 ** rights.  These rights are described in the Nokia Qt LGPL Exception
26 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
27 **
28 ** If you have questions regarding the use of this file, please contact
29 ** Nokia at qt-info@nokia.com.
30 **
31 **
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include "qxcbwindow.h"
43
44 #include <QtDebug>
45
46 #include "qxcbconnection.h"
47 #include "qxcbscreen.h"
48 #ifdef XCB_USE_DRI2
49 #include "qdri2context.h"
50 #endif
51
52 #include <xcb/xcb_icccm.h>
53
54 #include <private/qapplication_p.h>
55 #include <private/qwindowsurface_p.h>
56
57 #include <QtGui/QWindowSystemInterface>
58
59 #include <stdio.h>
60
61 #ifdef XCB_USE_XLIB
62 #include <X11/Xlib.h>
63 #include <X11/Xutil.h>
64 #endif
65
66 #if defined(XCB_USE_GLX)
67 #include "qglxintegration.h"
68 #include "qglxconvenience.h"
69 #elif defined(XCB_USE_EGL)
70 #include "../eglconvenience/qeglplatformcontext.h"
71 #include "../eglconvenience/qeglconvenience.h"
72 #include "../eglconvenience/qxlibeglintegration.h"
73 #endif
74
75 // Returns true if we should set WM_TRANSIENT_FOR on \a w
76 static inline bool isTransient(const QWidget *w)
77 {
78     return ((w->windowType() == Qt::Dialog
79              || w->windowType() == Qt::Sheet
80              || w->windowType() == Qt::Tool
81              || w->windowType() == Qt::SplashScreen
82              || w->windowType() == Qt::ToolTip
83              || w->windowType() == Qt::Drawer
84              || w->windowType() == Qt::Popup)
85             && !w->testAttribute(Qt::WA_X11BypassTransientForHint));
86 }
87
88 QXcbWindow::QXcbWindow(QWidget *tlw)
89     : QPlatformWindow(tlw)
90     , m_context(0)
91 {
92     m_screen = static_cast<QXcbScreen *>(QPlatformScreen::platformScreenForWidget(tlw));
93
94     setConnection(m_screen->connection());
95
96     const quint32 mask = XCB_CW_BACK_PIXMAP | XCB_CW_EVENT_MASK;
97     const quint32 values[] = {
98         // XCB_CW_BACK_PIXMAP
99         XCB_NONE,
100         // XCB_CW_EVENT_MASK
101         XCB_EVENT_MASK_EXPOSURE
102         | XCB_EVENT_MASK_STRUCTURE_NOTIFY
103         | XCB_EVENT_MASK_KEY_PRESS
104         | XCB_EVENT_MASK_KEY_RELEASE
105         | XCB_EVENT_MASK_BUTTON_PRESS
106         | XCB_EVENT_MASK_BUTTON_RELEASE
107         | XCB_EVENT_MASK_BUTTON_MOTION
108         | XCB_EVENT_MASK_ENTER_WINDOW
109         | XCB_EVENT_MASK_LEAVE_WINDOW
110         | XCB_EVENT_MASK_PROPERTY_CHANGE
111         | XCB_EVENT_MASK_FOCUS_CHANGE
112     };
113
114 #if defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
115     if (tlw->platformWindowFormat().windowApi() == QPlatformWindowFormat::OpenGL
116         && QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL))
117     {
118 #if defined(XCB_USE_GLX)
119         XVisualInfo *visualInfo = qglx_findVisualInfo(DISPLAY_FROM_XCB(m_screen),m_screen->screenNumber(), tlw->platformWindowFormat());
120 #elif defined(XCB_USE_EGL)
121         EGLDisplay eglDisplay = connection()->egl_display();
122         EGLConfig eglConfig = q_configFromQPlatformWindowFormat(eglDisplay,tlw->platformWindowFormat(),true);
123         VisualID id = QXlibEglIntegration::getCompatibleVisualId(DISPLAY_FROM_XCB(this), eglDisplay, eglConfig);
124
125         XVisualInfo visualInfoTemplate;
126         memset(&visualInfoTemplate, 0, sizeof(XVisualInfo));
127         visualInfoTemplate.visualid = id;
128
129         XVisualInfo *visualInfo;
130         int matchingCount = 0;
131         visualInfo = XGetVisualInfo(DISPLAY_FROM_XCB(this), VisualIDMask, &visualInfoTemplate, &matchingCount);
132 #endif //XCB_USE_GLX
133         if (visualInfo) {
134             m_depth = visualInfo->depth;
135             m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
136             Colormap cmap = XCreateColormap(DISPLAY_FROM_XCB(this), m_screen->root(), visualInfo->visual, AllocNone);
137
138             XSetWindowAttributes a;
139             a.background_pixel = WhitePixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
140             a.border_pixel = BlackPixel(DISPLAY_FROM_XCB(this), m_screen->screenNumber());
141             a.colormap = cmap;
142             m_window = XCreateWindow(DISPLAY_FROM_XCB(this), m_screen->root(), tlw->x(), tlw->y(), tlw->width(), tlw->height(),
143                                       0, visualInfo->depth, InputOutput, visualInfo->visual,
144                                       CWBackPixel|CWBorderPixel|CWColormap, &a);
145
146             printf("created GL window: %d\n", m_window);
147         } else {
148             qFatal("no window!");
149         }
150     } else
151 #endif //defined(XCB_USE_GLX) || defined(XCB_USE_EGL)
152     {
153         m_window = xcb_generate_id(xcb_connection());
154         m_depth = m_screen->screen()->root_depth;
155         m_format = (m_depth == 32) ? QImage::Format_ARGB32_Premultiplied : QImage::Format_RGB32;
156
157         Q_XCB_CALL(xcb_create_window(xcb_connection(),
158                                      XCB_COPY_FROM_PARENT,            // depth -- same as root
159                                      m_window,                        // window id
160                                      m_screen->root(),                // parent window id
161                                      tlw->x(),
162                                      tlw->y(),
163                                      tlw->width(),
164                                      tlw->height(),
165                                      0,                               // border width
166                                      XCB_WINDOW_CLASS_INPUT_OUTPUT,   // window class
167                                      m_screen->screen()->root_visual, // visual
168                                      0,                               // value mask
169                                      0));                             // value list
170
171         printf("created regular window: %d\n", m_window);
172     }
173
174     Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
175
176     xcb_atom_t properties[4];
177     int propertyCount = 0;
178     properties[propertyCount++] = atom(QXcbAtom::WM_DELETE_WINDOW);
179     properties[propertyCount++] = atom(QXcbAtom::WM_TAKE_FOCUS);
180     properties[propertyCount++] = atom(QXcbAtom::_NET_WM_PING);
181
182     if (m_screen->syncRequestSupported())
183         properties[propertyCount++] = atom(QXcbAtom::_NET_WM_SYNC_REQUEST);
184
185     if (tlw->windowFlags() & Qt::WindowContextHelpButtonHint)
186         properties[propertyCount++] = atom(QXcbAtom::_NET_WM_CONTEXT_HELP);
187
188     Q_XCB_CALL(xcb_change_property(xcb_connection(),
189                                    XCB_PROP_MODE_REPLACE,
190                                    m_window,
191                                    atom(QXcbAtom::WM_PROTOCOLS),
192                                    XCB_ATOM_ATOM,
193                                    32,
194                                    propertyCount,
195                                    properties));
196     m_syncValue.hi = 0;
197     m_syncValue.lo = 0;
198
199     if (m_screen->syncRequestSupported()) {
200         m_syncCounter = xcb_generate_id(xcb_connection());
201         Q_XCB_CALL(xcb_sync_create_counter(xcb_connection(), m_syncCounter, m_syncValue));
202
203         Q_XCB_CALL(xcb_change_property(xcb_connection(),
204                                        XCB_PROP_MODE_REPLACE,
205                                        m_window,
206                                        atom(QXcbAtom::_NET_WM_SYNC_REQUEST_COUNTER),
207                                        XCB_ATOM_CARDINAL,
208                                        32,
209                                        1,
210                                        &m_syncCounter));
211     }
212
213     if (isTransient(tlw) && tlw->parentWidget()) {
214         // ICCCM 4.1.2.6
215         QWidget *p = tlw->parentWidget()->window();
216         xcb_window_t parentWindow = p->winId();
217         Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
218                                        XCB_ATOM_WM_TRANSIENT_FOR, XCB_ATOM_WINDOW, 32,
219                                        1, &parentWindow));
220
221     }
222
223     // set the PID to let the WM kill the application if unresponsive
224     long pid = getpid();
225     Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
226                                    atom(QXcbAtom::_NET_WM_PID), XCB_ATOM_CARDINAL, 32,
227                                    1, &pid));
228 }
229
230 QXcbWindow::~QXcbWindow()
231 {
232     delete m_context;
233     if (m_screen->syncRequestSupported())
234         Q_XCB_CALL(xcb_sync_destroy_counter(xcb_connection(), m_syncCounter));
235     Q_XCB_CALL(xcb_destroy_window(xcb_connection(), m_window));
236 }
237
238 void QXcbWindow::setGeometry(const QRect &rect)
239 {
240     QPlatformWindow::setGeometry(rect);
241
242     const quint32 mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_WIDTH | XCB_CONFIG_WINDOW_HEIGHT;
243     const quint32 values[] = { rect.x(), rect.y(), rect.width(), rect.height() };
244
245     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
246 }
247
248 void QXcbWindow::setVisible(bool visible)
249 {
250     xcb_wm_hints_t hints;
251     if (visible) {
252         if (widget()->isMinimized())
253             xcb_wm_hints_set_iconic(&hints);
254         else
255             xcb_wm_hints_set_normal(&hints);
256         xcb_set_wm_hints(xcb_connection(), m_window, &hints);
257         Q_XCB_CALL(xcb_map_window(xcb_connection(), m_window));
258         connection()->sync();
259     } else {
260         Q_XCB_CALL(xcb_unmap_window(xcb_connection(), m_window));
261
262         // send synthetic UnmapNotify event according to icccm 4.1.4
263         xcb_unmap_notify_event_t event;
264         event.response_type = XCB_UNMAP_NOTIFY;
265         event.sequence = 0; // does this matter?
266         event.event = m_screen->root();
267         event.window = m_window;
268         event.from_configure = false;
269         Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_screen->root(),
270                                   XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&event));
271
272         xcb_flush(xcb_connection());
273     }
274 }
275
276 struct QtMWMHints {
277     quint32 flags, functions, decorations;
278     qint32 input_mode;
279     quint32 status;
280 };
281
282 enum {
283     MWM_HINTS_FUNCTIONS   = (1L << 0),
284
285     MWM_FUNC_ALL      = (1L << 0),
286     MWM_FUNC_RESIZE   = (1L << 1),
287     MWM_FUNC_MOVE     = (1L << 2),
288     MWM_FUNC_MINIMIZE = (1L << 3),
289     MWM_FUNC_MAXIMIZE = (1L << 4),
290     MWM_FUNC_CLOSE    = (1L << 5),
291
292     MWM_HINTS_DECORATIONS = (1L << 1),
293
294     MWM_DECOR_ALL      = (1L << 0),
295     MWM_DECOR_BORDER   = (1L << 1),
296     MWM_DECOR_RESIZEH  = (1L << 2),
297     MWM_DECOR_TITLE    = (1L << 3),
298     MWM_DECOR_MENU     = (1L << 4),
299     MWM_DECOR_MINIMIZE = (1L << 5),
300     MWM_DECOR_MAXIMIZE = (1L << 6),
301
302     MWM_HINTS_INPUT_MODE = (1L << 2),
303
304     MWM_INPUT_MODELESS                  = 0L,
305     MWM_INPUT_PRIMARY_APPLICATION_MODAL = 1L,
306     MWM_INPUT_FULL_APPLICATION_MODAL    = 3L
307 };
308
309 Qt::WindowFlags QXcbWindow::setWindowFlags(Qt::WindowFlags flags)
310 {
311     Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
312
313     setNetWmWindowTypes(flags);
314
315     if (type == Qt::ToolTip)
316         flags |= Qt::WindowStaysOnTopHint | Qt::FramelessWindowHint | Qt::X11BypassWindowManagerHint;
317     if (type == Qt::Popup)
318         flags |= Qt::X11BypassWindowManagerHint;
319
320     bool topLevel = (flags & Qt::Window);
321     bool popup = (type == Qt::Popup);
322     bool dialog = (type == Qt::Dialog
323                    || type == Qt::Sheet);
324     bool desktop = (type == Qt::Desktop);
325     bool tool = (type == Qt::Tool || type == Qt::SplashScreen
326                  || type == Qt::ToolTip || type == Qt::Drawer);
327
328     Q_UNUSED(topLevel);
329     Q_UNUSED(dialog);
330     Q_UNUSED(desktop);
331     Q_UNUSED(tool);
332
333     bool tooltip = (type == Qt::ToolTip);
334
335     QtMWMHints mwmhints;
336     mwmhints.flags = 0L;
337     mwmhints.functions = 0L;
338     mwmhints.decorations = 0;
339     mwmhints.input_mode = 0L;
340     mwmhints.status = 0L;
341
342     if (type != Qt::SplashScreen) {
343         mwmhints.flags |= MWM_HINTS_DECORATIONS;
344
345         bool customize = flags & Qt::CustomizeWindowHint;
346         if (!(flags & Qt::FramelessWindowHint) && !(customize && !(flags & Qt::WindowTitleHint))) {
347             mwmhints.decorations |= MWM_DECOR_BORDER;
348             mwmhints.decorations |= MWM_DECOR_RESIZEH;
349
350             if (flags & Qt::WindowTitleHint)
351                 mwmhints.decorations |= MWM_DECOR_TITLE;
352
353             if (flags & Qt::WindowSystemMenuHint)
354                 mwmhints.decorations |= MWM_DECOR_MENU;
355
356             if (flags & Qt::WindowMinimizeButtonHint) {
357                 mwmhints.decorations |= MWM_DECOR_MINIMIZE;
358                 mwmhints.functions |= MWM_FUNC_MINIMIZE;
359             }
360
361             if (flags & Qt::WindowMaximizeButtonHint) {
362                 mwmhints.decorations |= MWM_DECOR_MAXIMIZE;
363                 mwmhints.functions |= MWM_FUNC_MAXIMIZE;
364             }
365
366             if (flags & Qt::WindowCloseButtonHint)
367                 mwmhints.functions |= MWM_FUNC_CLOSE;
368         }
369     } else {
370         // if type == Qt::SplashScreen
371         mwmhints.decorations = MWM_DECOR_ALL;
372     }
373
374     if (mwmhints.functions != 0) {
375         mwmhints.flags |= MWM_HINTS_FUNCTIONS;
376         mwmhints.functions |= MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
377     } else {
378         mwmhints.functions = MWM_FUNC_ALL;
379     }
380
381     if (!(flags & Qt::FramelessWindowHint)
382         && flags & Qt::CustomizeWindowHint
383         && flags & Qt::WindowTitleHint
384         && !(flags &
385              (Qt::WindowMinimizeButtonHint
386               | Qt::WindowMaximizeButtonHint
387               | Qt::WindowCloseButtonHint)))
388     {
389         // a special case - only the titlebar without any button
390         mwmhints.flags = MWM_HINTS_FUNCTIONS;
391         mwmhints.functions = MWM_FUNC_MOVE | MWM_FUNC_RESIZE;
392         mwmhints.decorations = 0;
393     }
394
395     if (mwmhints.flags != 0l) {
396         Q_XCB_CALL(xcb_change_property(xcb_connection(),
397                                        XCB_PROP_MODE_REPLACE,
398                                        m_window,
399                                        atom(QXcbAtom::_MOTIF_WM_HINTS),
400                                        atom(QXcbAtom::_MOTIF_WM_HINTS),
401                                        32,
402                                        5,
403                                        &mwmhints));
404     } else {
405         Q_XCB_CALL(xcb_delete_property(xcb_connection(), m_window, atom(QXcbAtom::_MOTIF_WM_HINTS)));
406     }
407
408     if (popup || tooltip) {
409         const quint32 mask = XCB_CW_OVERRIDE_REDIRECT | XCB_CW_SAVE_UNDER;
410         const quint32 values[] = { true, true };
411
412         Q_XCB_CALL(xcb_change_window_attributes(xcb_connection(), m_window, mask, values));
413     }
414
415     return QPlatformWindow::setWindowFlags(flags);
416 }
417
418 void QXcbWindow::setNetWmWindowTypes(Qt::WindowFlags flags)
419 {
420     // in order of decreasing priority
421     QVector<uint> windowTypes;
422
423     Qt::WindowType type = static_cast<Qt::WindowType>(int(flags & Qt::WindowType_Mask));
424
425     switch (type) {
426     case Qt::Dialog:
427     case Qt::Sheet:
428         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_DIALOG));
429         break;
430     case Qt::Tool:
431     case Qt::Drawer:
432         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_UTILITY));
433         break;
434     case Qt::ToolTip:
435         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_TOOLTIP));
436         break;
437     case Qt::SplashScreen:
438         windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_SPLASH));
439         break;
440     default:
441         break;
442     }
443
444     if (flags & Qt::FramelessWindowHint)
445         windowTypes.append(atom(QXcbAtom::_KDE_NET_WM_WINDOW_TYPE_OVERRIDE));
446
447     windowTypes.append(atom(QXcbAtom::_NET_WM_WINDOW_TYPE_NORMAL));
448
449     Q_XCB_CALL(xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_window,
450                                    atom(QXcbAtom::_NET_WM_WINDOW_TYPE), XCB_ATOM_ATOM, 32,
451                                    windowTypes.count(), windowTypes.constData()));
452 }
453
454 WId QXcbWindow::winId() const
455 {
456     return m_window;
457 }
458
459 void QXcbWindow::setParent(const QPlatformWindow *parent)
460 {
461     QPoint topLeft = geometry().topLeft();
462     Q_XCB_CALL(xcb_reparent_window(xcb_connection(), window(), static_cast<const QXcbWindow *>(parent)->window(), topLeft.x(), topLeft.y()));
463 }
464
465 void QXcbWindow::setWindowTitle(const QString &title)
466 {
467     QByteArray ba = title.toUtf8();
468     Q_XCB_CALL(xcb_change_property(xcb_connection(),
469                                    XCB_PROP_MODE_REPLACE,
470                                    m_window,
471                                    atom(QXcbAtom::_NET_WM_NAME),
472                                    atom(QXcbAtom::UTF8_STRING),
473                                    8,
474                                    ba.length(),
475                                    ba.constData()));
476 }
477
478 void QXcbWindow::raise()
479 {
480     const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE;
481     const quint32 values[] = { XCB_STACK_MODE_ABOVE };
482     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
483 }
484
485 void QXcbWindow::lower()
486 {
487     const quint32 mask = XCB_CONFIG_WINDOW_STACK_MODE;
488     const quint32 values[] = { XCB_STACK_MODE_BELOW };
489     Q_XCB_CALL(xcb_configure_window(xcb_connection(), m_window, mask, values));
490 }
491
492 void QXcbWindow::requestActivateWindow()
493 {
494     Q_XCB_CALL(xcb_set_input_focus(xcb_connection(), XCB_INPUT_FOCUS_PARENT, m_window, XCB_TIME_CURRENT_TIME));
495     connection()->sync();
496 }
497
498 QPlatformGLContext *QXcbWindow::glContext() const
499 {
500     if (!QApplicationPrivate::platformIntegration()->hasCapability(QPlatformIntegration::OpenGL)) {
501         printf("no opengl\n");
502         return 0;
503     }
504     if (!m_context) {
505 #if defined(XCB_USE_GLX)
506         QXcbWindow *that = const_cast<QXcbWindow *>(this);
507         that->m_context = new QGLXContext(m_window, m_screen, widget()->platformWindowFormat());
508 #elif defined(XCB_USE_EGL)
509         EGLDisplay display = connection()->egl_display();
510         EGLConfig config = q_configFromQPlatformWindowFormat(display,widget()->platformWindowFormat(),true);
511         QVector<EGLint> eglContextAttrs;
512         eglContextAttrs.append(EGL_CONTEXT_CLIENT_VERSION);
513         eglContextAttrs.append(2);
514         eglContextAttrs.append(EGL_NONE);
515
516         EGLSurface eglSurface = eglCreateWindowSurface(display,config,(EGLNativeWindowType)m_window,0);
517         QXcbWindow *that = const_cast<QXcbWindow *>(this);
518         that->m_context = new QEGLPlatformContext(display, config, eglContextAttrs.data(), eglSurface, EGL_OPENGL_ES_API);
519 #elif defined(XCB_USE_DRI2)
520         QXcbWindow *that = const_cast<QXcbWindow *>(this);
521         that->m_context = new QDri2Context(that);
522 #endif
523     }
524     return m_context;
525 }
526
527 void QXcbWindow::handleExposeEvent(const xcb_expose_event_t *event)
528 {
529     QWindowSurface *surface = widget()->windowSurface();
530     if (surface) {
531         QRect rect(event->x, event->y, event->width, event->height);
532
533         surface->flush(widget(), rect, QPoint());
534     }
535 }
536
537 void QXcbWindow::handleClientMessageEvent(const xcb_client_message_event_t *event)
538 {
539     if (event->format == 32 && event->type == atom(QXcbAtom::WM_PROTOCOLS)) {
540         if (event->data.data32[0] == atom(QXcbAtom::WM_DELETE_WINDOW)) {
541             QWindowSystemInterface::handleCloseEvent(widget());
542         } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_PING)) {
543             xcb_client_message_event_t reply = *event;
544
545             reply.response_type = XCB_CLIENT_MESSAGE;
546             reply.window = m_screen->root();
547
548             xcb_send_event(xcb_connection(), 0, m_screen->root(), XCB_EVENT_MASK_STRUCTURE_NOTIFY | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT, (const char *)&reply);
549             xcb_flush(xcb_connection());
550         } else if (event->data.data32[0] == atom(QXcbAtom::_NET_WM_SYNC_REQUEST)) {
551             if (!m_hasReceivedSyncRequest) {
552                 m_hasReceivedSyncRequest = true;
553                 printf("Window manager supports _NET_WM_SYNC_REQUEST, syncing resizes\n");
554             }
555             m_syncValue.lo = event->data.data32[2];
556             m_syncValue.hi = event->data.data32[3];
557         }
558     }
559 }
560
561 void QXcbWindow::handleConfigureNotifyEvent(const xcb_configure_notify_event_t *event)
562 {
563     int xpos = geometry().x();
564     int ypos = geometry().y();
565
566     if ((event->width == geometry().width() && event->height == geometry().height()) || event->x != 0 || event->y != 0) {
567         xpos = event->x;
568         ypos = event->y;
569     }
570
571     QRect rect(xpos, ypos, event->width, event->height);
572
573     if (rect == geometry())
574         return;
575
576     QPlatformWindow::setGeometry(rect);
577     QWindowSystemInterface::handleGeometryChange(widget(), rect);
578
579 #if XCB_USE_DRI2
580     if (m_context)
581         static_cast<QDri2Context *>(m_context)->resize(rect.size());
582 #endif
583 }
584
585 static Qt::MouseButtons translateMouseButtons(int s)
586 {
587     Qt::MouseButtons ret = 0;
588     if (s & XCB_BUTTON_MASK_1)
589         ret |= Qt::LeftButton;
590     if (s & XCB_BUTTON_MASK_2)
591         ret |= Qt::MidButton;
592     if (s & XCB_BUTTON_MASK_3)
593         ret |= Qt::RightButton;
594     return ret;
595 }
596
597 static Qt::MouseButton translateMouseButton(xcb_button_t s)
598 {
599     switch (s) {
600     case 1:
601         return Qt::LeftButton;
602     case 2:
603         return Qt::MidButton;
604     case 3:
605         return Qt::RightButton;
606     default:
607         return Qt::NoButton;
608     }
609 }
610
611 void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event)
612 {
613     QPoint local(event->event_x, event->event_y);
614     QPoint global(event->root_x, event->root_y);
615
616     Qt::KeyboardModifiers modifiers = Qt::NoModifier;
617
618     if (event->detail >= 4 && event->detail <= 7) {
619         //logic borrowed from qapplication_x11.cpp
620         int delta = 120 * ((event->detail == 4 || event->detail == 6) ? 1 : -1);
621         bool hor = (((event->detail == 4 || event->detail == 5)
622                      && (modifiers & Qt::AltModifier))
623                     || (event->detail == 6 || event->detail == 7));
624
625         QWindowSystemInterface::handleWheelEvent(widget(), event->time,
626                                                  local, global, delta, hor ? Qt::Horizontal : Qt::Vertical);
627         return;
628     }
629
630     handleMouseEvent(event->detail, event->state, event->time, local, global);
631 }
632
633 void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event)
634 {
635     QPoint local(event->event_x, event->event_y);
636     QPoint global(event->root_x, event->root_y);
637
638     handleMouseEvent(event->detail, event->state, event->time, local, global);
639 }
640
641 void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event)
642 {
643     QPoint local(event->event_x, event->event_y);
644     QPoint global(event->root_x, event->root_y);
645
646     handleMouseEvent(event->detail, event->state, event->time, local, global);
647 }
648
649 void QXcbWindow::handleMouseEvent(xcb_button_t detail, uint16_t state, xcb_timestamp_t time, const QPoint &local, const QPoint &global)
650 {
651     Qt::MouseButtons buttons = translateMouseButtons(state);
652     Qt::MouseButton button = translateMouseButton(detail);
653
654     buttons ^= button; // X event uses state *before*, Qt uses state *after*
655
656     QWindowSystemInterface::handleMouseEvent(widget(), time, local, global, buttons);
657 }
658
659 void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *)
660 {
661     QWindowSystemInterface::handleEnterEvent(widget());
662 }
663
664 void QXcbWindow::handleLeaveNotifyEvent(const xcb_leave_notify_event_t *)
665 {
666     QWindowSystemInterface::handleLeaveEvent(widget());
667 }
668
669 void QXcbWindow::handleFocusInEvent(const xcb_focus_in_event_t *)
670 {
671     QWindowSystemInterface::handleWindowActivated(widget());
672 }
673
674 void QXcbWindow::handleFocusOutEvent(const xcb_focus_out_event_t *)
675 {
676     QWindowSystemInterface::handleWindowActivated(0);
677 }
678
679 void QXcbWindow::updateSyncRequestCounter()
680 {
681     if (m_screen->syncRequestSupported() && (m_syncValue.lo != 0 || m_syncValue.hi != 0)) {
682         Q_XCB_CALL(xcb_sync_set_counter(xcb_connection(), m_syncCounter, m_syncValue));
683         xcb_flush(xcb_connection());
684         connection()->sync();
685
686         m_syncValue.lo = 0;
687         m_syncValue.hi = 0;
688     }
689 }