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