3d17e381598056a904ce91522c5046bb70bb7cd7
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbconnection.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
16 **
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
20 **
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
28 **
29 ** Other Usage
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
32 **
33 **
34 **
35 **
36 **
37 **
38 ** $QT_END_LICENSE$
39 **
40 ****************************************************************************/
41
42 #include <QtGui/private/qguiapplication_p.h>
43 #include <QtCore/QDebug>
44
45 #include "qxcbconnection.h"
46 #include "qxcbkeyboard.h"
47 #include "qxcbscreen.h"
48 #include "qxcbwindow.h"
49 #include "qxcbclipboard.h"
50 #include "qxcbdrag.h"
51 #include "qxcbwmsupport.h"
52 #include "qxcbnativeinterface.h"
53
54 #include <QtAlgorithms>
55 #include <QSocketNotifier>
56 #include <QAbstractEventDispatcher>
57 #include <QTimer>
58 #include <QByteArray>
59
60 #include <stdio.h>
61 #include <errno.h>
62 #include <xcb/xfixes.h>
63 #include <xcb/randr.h>
64
65 #ifdef XCB_USE_XLIB
66 #include <X11/Xlib.h>
67 #include <X11/Xlib-xcb.h>
68 #include <X11/Xlibint.h>
69 #endif
70
71 #ifdef XCB_USE_RENDER
72 #include <xcb/render.h>
73 #endif
74
75 #ifdef XCB_USE_EGL //dont pull in eglext prototypes
76 #include <EGL/egl.h>
77 #endif
78
79 #ifdef XCB_USE_DRI2
80 #include <xcb/dri2.h>
81 extern "C" {
82 #include <xf86drm.h>
83 }
84 #define MESA_EGL_NO_X11_HEADERS
85 #define EGL_EGLEXT_PROTOTYPES
86 #include <EGL/egl.h>
87 #include <EGL/eglext.h>
88 #endif
89
90 QT_BEGIN_NAMESPACE
91
92 #ifdef XCB_USE_XLIB
93 static int nullErrorHandler(Display *, XErrorEvent *)
94 {
95     return 0;
96 }
97 #endif
98
99 QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName)
100     : m_connection(0)
101     , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
102     , m_nativeInterface(nativeInterface)
103 #ifdef XCB_USE_XINPUT2_MAEMO
104     , m_xinputData(0)
105 #endif
106 #ifdef XCB_USE_DRI2
107     , m_dri2_major(0)
108     , m_dri2_minor(0)
109     , m_dri2_support_probed(false)
110     , m_has_support_for_dri2(false)
111 #endif
112     , xfixes_first_event(0)
113     , xrandr_first_event(0)
114     , has_shape_extension(false)
115     , has_randr_extension(false)
116     , has_input_shape(false)
117 {
118     m_primaryScreen = 0;
119
120 #ifdef XCB_USE_XLIB
121     Display *dpy = XOpenDisplay(m_displayName.constData());
122     if (dpy) {
123         m_primaryScreen = DefaultScreen(dpy);
124         m_connection = XGetXCBConnection(dpy);
125         XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
126         XSetErrorHandler(nullErrorHandler);
127         m_xlib_display = dpy;
128 #ifdef XCB_USE_EGL
129         EGLDisplay eglDisplay = eglGetDisplay(dpy);
130         m_egl_display = eglDisplay;
131         EGLint major, minor;
132         eglBindAPI(EGL_OPENGL_ES_API);
133         m_has_egl = eglInitialize(eglDisplay,&major,&minor);
134 #endif //XCB_USE_EGL
135     }
136 #else
137     m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen);
138 #endif //XCB_USE_XLIB
139
140     if (!m_connection || xcb_connection_has_error(m_connection))
141         qFatal("QXcbConnection: Could not connect to display %s", m_displayName.constData());
142
143     m_reader = new QXcbEventReader(this);
144 #ifdef XCB_POLL_FOR_QUEUED_EVENT
145     connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection);
146     m_reader->start();
147 #else
148     QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this);
149     connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents()));
150
151     QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
152     connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents()));
153     connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents()));
154 #endif
155
156     xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id);
157
158     m_setup = xcb_get_setup(xcb_connection());
159
160     initializeAllAtoms();
161
162     m_time = XCB_CURRENT_TIME;
163
164     xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
165
166     initializeXRandr();
167
168     int screenNumber = 0;
169     while (it.rem) {
170         m_screens << new QXcbScreen(this, it.data, screenNumber++);
171         xcb_screen_next(&it);
172     }
173
174     m_connectionEventListener = xcb_generate_id(m_connection);
175     xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
176                       m_connectionEventListener, m_screens.at(0)->root(),
177                       0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
178                       m_screens.at(0)->screen()->root_visual, 0, 0);
179
180     initializeXFixes();
181     initializeXRender();
182 #ifdef XCB_USE_XINPUT2_MAEMO
183     initializeXInput2();
184 #endif
185     initializeXShape();
186
187     m_wmSupport.reset(new QXcbWMSupport(this));
188     m_keyboard = new QXcbKeyboard(this);
189     m_clipboard = new QXcbClipboard(this);
190     m_drag = new QXcbDrag(this);
191
192 #ifdef XCB_USE_DRI2
193     initializeDri2();
194 #endif
195     sync();
196 }
197
198 QXcbConnection::~QXcbConnection()
199 {
200     delete m_clipboard;
201
202     // Delete screens in reverse order to avoid crash in case of multiple screens
203     while (!m_screens.isEmpty())
204         delete m_screens.takeLast();
205
206 #ifdef XCB_USE_XINPUT2_MAEMO
207     finalizeXInput2();
208 #endif
209
210 #ifdef XCB_POLL_FOR_QUEUED_EVENT
211     sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION);
212     m_reader->wait();
213 #endif
214     delete m_reader;
215
216 #ifdef XCB_USE_EGL
217     if (m_has_egl)
218         eglTerminate(m_egl_display);
219 #endif //XCB_USE_EGL
220
221 #ifdef XCB_USE_XLIB
222     XCloseDisplay((Display *)m_xlib_display);
223 #else
224     xcb_disconnect(xcb_connection());
225 #endif
226
227     delete m_keyboard;
228 }
229
230 void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window)
231 {
232     m_mapper.insert(id, window);
233 }
234
235 void QXcbConnection::removeWindow(xcb_window_t id)
236 {
237     m_mapper.remove(id);
238 }
239
240 QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
241 {
242     return m_mapper.value(id, 0);
243 }
244
245 #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
246 { \
247     event_t *e = (event_t *)event; \
248     if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember))  { \
249         long result = 0; \
250         handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
251         if (!handled) \
252             platformWindow->handler(e); \
253     } \
254 } \
255 break;
256
257 #define HANDLE_KEYBOARD_EVENT(event_t, handler) \
258 { \
259     event_t *e = (event_t *)event; \
260     if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \
261         long result = 0; \
262         handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
263         if (!handled) \
264             m_keyboard->handler(platformWindow, e); \
265     } \
266 } \
267 break;
268
269 //#define XCB_EVENT_DEBUG
270
271 void printXcbEvent(const char *message, xcb_generic_event_t *event)
272 {
273 #ifdef XCB_EVENT_DEBUG
274 #define PRINT_XCB_EVENT(ev) \
275     case ev: \
276         qDebug("QXcbConnection: %s: %d - %s - sequence: %d", message, int(ev), #ev, event->sequence); \
277         break;
278
279     switch (event->response_type & ~0x80) {
280     PRINT_XCB_EVENT(XCB_KEY_PRESS);
281     PRINT_XCB_EVENT(XCB_KEY_RELEASE);
282     PRINT_XCB_EVENT(XCB_BUTTON_PRESS);
283     PRINT_XCB_EVENT(XCB_BUTTON_RELEASE);
284     PRINT_XCB_EVENT(XCB_MOTION_NOTIFY);
285     PRINT_XCB_EVENT(XCB_ENTER_NOTIFY);
286     PRINT_XCB_EVENT(XCB_LEAVE_NOTIFY);
287     PRINT_XCB_EVENT(XCB_FOCUS_IN);
288     PRINT_XCB_EVENT(XCB_FOCUS_OUT);
289     PRINT_XCB_EVENT(XCB_KEYMAP_NOTIFY);
290     PRINT_XCB_EVENT(XCB_EXPOSE);
291     PRINT_XCB_EVENT(XCB_GRAPHICS_EXPOSURE);
292     PRINT_XCB_EVENT(XCB_VISIBILITY_NOTIFY);
293     PRINT_XCB_EVENT(XCB_CREATE_NOTIFY);
294     PRINT_XCB_EVENT(XCB_DESTROY_NOTIFY);
295     PRINT_XCB_EVENT(XCB_UNMAP_NOTIFY);
296     PRINT_XCB_EVENT(XCB_MAP_NOTIFY);
297     PRINT_XCB_EVENT(XCB_MAP_REQUEST);
298     PRINT_XCB_EVENT(XCB_REPARENT_NOTIFY);
299     PRINT_XCB_EVENT(XCB_CONFIGURE_NOTIFY);
300     PRINT_XCB_EVENT(XCB_CONFIGURE_REQUEST);
301     PRINT_XCB_EVENT(XCB_GRAVITY_NOTIFY);
302     PRINT_XCB_EVENT(XCB_RESIZE_REQUEST);
303     PRINT_XCB_EVENT(XCB_CIRCULATE_NOTIFY);
304     PRINT_XCB_EVENT(XCB_CIRCULATE_REQUEST);
305     PRINT_XCB_EVENT(XCB_PROPERTY_NOTIFY);
306     PRINT_XCB_EVENT(XCB_SELECTION_CLEAR);
307     PRINT_XCB_EVENT(XCB_SELECTION_REQUEST);
308     PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY);
309     PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY);
310     PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE);
311     PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY);
312     default:
313         qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence));
314     }
315 #else
316     Q_UNUSED(message);
317     Q_UNUSED(event);
318 #endif
319 }
320
321 const char *xcb_errors[] =
322 {
323     "Success",
324     "BadRequest",
325     "BadValue",
326     "BadWindow",
327     "BadPixmap",
328     "BadAtom",
329     "BadCursor",
330     "BadFont",
331     "BadMatch",
332     "BadDrawable",
333     "BadAccess",
334     "BadAlloc",
335     "BadColor",
336     "BadGC",
337     "BadIDChoice",
338     "BadName",
339     "BadLength",
340     "BadImplementation",
341     "Unknown"
342 };
343
344 const char *xcb_protocol_request_codes[] =
345 {
346     "Null",
347     "CreateWindow",
348     "ChangeWindowAttributes",
349     "GetWindowAttributes",
350     "DestroyWindow",
351     "DestroySubwindows",
352     "ChangeSaveSet",
353     "ReparentWindow",
354     "MapWindow",
355     "MapSubwindows",
356     "UnmapWindow",
357     "UnmapSubwindows",
358     "ConfigureWindow",
359     "CirculateWindow",
360     "GetGeometry",
361     "QueryTree",
362     "InternAtom",
363     "GetAtomName",
364     "ChangeProperty",
365     "DeleteProperty",
366     "GetProperty",
367     "ListProperties",
368     "SetSelectionOwner",
369     "GetSelectionOwner",
370     "ConvertSelection",
371     "SendEvent",
372     "GrabPointer",
373     "UngrabPointer",
374     "GrabButton",
375     "UngrabButton",
376     "ChangeActivePointerGrab",
377     "GrabKeyboard",
378     "UngrabKeyboard",
379     "GrabKey",
380     "UngrabKey",
381     "AllowEvents",
382     "GrabServer",
383     "UngrabServer",
384     "QueryPointer",
385     "GetMotionEvents",
386     "TranslateCoords",
387     "WarpPointer",
388     "SetInputFocus",
389     "GetInputFocus",
390     "QueryKeymap",
391     "OpenFont",
392     "CloseFont",
393     "QueryFont",
394     "QueryTextExtents",
395     "ListFonts",
396     "ListFontsWithInfo",
397     "SetFontPath",
398     "GetFontPath",
399     "CreatePixmap",
400     "FreePixmap",
401     "CreateGC",
402     "ChangeGC",
403     "CopyGC",
404     "SetDashes",
405     "SetClipRectangles",
406     "FreeGC",
407     "ClearArea",
408     "CopyArea",
409     "CopyPlane",
410     "PolyPoint",
411     "PolyLine",
412     "PolySegment",
413     "PolyRectangle",
414     "PolyArc",
415     "FillPoly",
416     "PolyFillRectangle",
417     "PolyFillArc",
418     "PutImage",
419     "GetImage",
420     "PolyText8",
421     "PolyText16",
422     "ImageText8",
423     "ImageText16",
424     "CreateColormap",
425     "FreeColormap",
426     "CopyColormapAndFree",
427     "InstallColormap",
428     "UninstallColormap",
429     "ListInstalledColormaps",
430     "AllocColor",
431     "AllocNamedColor",
432     "AllocColorCells",
433     "AllocColorPlanes",
434     "FreeColors",
435     "StoreColors",
436     "StoreNamedColor",
437     "QueryColors",
438     "LookupColor",
439     "CreateCursor",
440     "CreateGlyphCursor",
441     "FreeCursor",
442     "RecolorCursor",
443     "QueryBestSize",
444     "QueryExtension",
445     "ListExtensions",
446     "ChangeKeyboardMapping",
447     "GetKeyboardMapping",
448     "ChangeKeyboardControl",
449     "GetKeyboardControl",
450     "Bell",
451     "ChangePointerControl",
452     "GetPointerControl",
453     "SetScreenSaver",
454     "GetScreenSaver",
455     "ChangeHosts",
456     "ListHosts",
457     "SetAccessControl",
458     "SetCloseDownMode",
459     "KillClient",
460     "RotateProperties",
461     "ForceScreenSaver",
462     "SetPointerMapping",
463     "GetPointerMapping",
464     "SetModifierMapping",
465     "GetModifierMapping",
466     "Unknown"
467 };
468
469 #ifdef Q_XCB_DEBUG
470 void QXcbConnection::log(const char *file, int line, int sequence)
471 {
472     QMutexLocker locker(&m_callLogMutex);
473     CallInfo info;
474     info.sequence = sequence;
475     info.file = file;
476     info.line = line;
477     m_callLog << info;
478 }
479 #endif
480
481 void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
482 {
483     uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
484     uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
485
486     qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
487            int(error->error_code), xcb_errors[clamped_error_code],
488            int(error->sequence), int(error->resource_id),
489            int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
490            int(error->minor_code));
491 #ifdef Q_XCB_DEBUG
492     QMutexLocker locker(&m_callLogMutex);
493     int i = 0;
494     for (; i < m_callLog.size(); ++i) {
495         if (m_callLog.at(i).sequence == error->sequence) {
496             qDebug("Caused by: %s:%d", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
497             break;
498         } else if (m_callLog.at(i).sequence > error->sequence) {
499             qDebug("Caused some time before: %s:%d", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
500             if (i > 0)
501                 qDebug("and after: %s:%d", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
502             break;
503         }
504     }
505     if (i == m_callLog.size() && !m_callLog.isEmpty())
506         qDebug("Caused some time after: %s:%d", qPrintable(m_callLog.first().file), m_callLog.first().line);
507 #endif
508 }
509
510 void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
511 {
512 #ifdef Q_XCB_DEBUG
513     {
514         QMutexLocker locker(&m_callLogMutex);
515         int i = 0;
516         for (; i < m_callLog.size(); ++i)
517             if (m_callLog.at(i).sequence >= event->sequence)
518                 break;
519         m_callLog.remove(0, i);
520     }
521 #endif
522     bool handled = false;
523
524     if (QPlatformNativeInterface::EventFilter filter = m_nativeInterface->eventFilter(QXcbNativeInterface::GenericEventFilter))
525         handled = filter(event, 0);
526
527     uint response_type = event->response_type & ~0x80;
528
529     if (!handled) {
530         switch (response_type) {
531         case XCB_EXPOSE:
532             HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
533         case XCB_BUTTON_PRESS:
534             HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
535         case XCB_BUTTON_RELEASE:
536             HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
537         case XCB_MOTION_NOTIFY:
538             HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
539         case XCB_CONFIGURE_NOTIFY:
540             HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
541         case XCB_MAP_NOTIFY:
542             HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
543         case XCB_UNMAP_NOTIFY:
544             HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
545         case XCB_CLIENT_MESSAGE:
546             handleClientMessageEvent((xcb_client_message_event_t *)event);
547         case XCB_ENTER_NOTIFY:
548             HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
549         case XCB_LEAVE_NOTIFY:
550             HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
551         case XCB_FOCUS_IN:
552             HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
553         case XCB_FOCUS_OUT:
554             HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
555         case XCB_KEY_PRESS:
556             HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
557         case XCB_KEY_RELEASE:
558             HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
559         case XCB_MAPPING_NOTIFY:
560             m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
561             break;
562         case XCB_SELECTION_REQUEST:
563         {
564             xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
565             if (sr->selection == atom(QXcbAtom::XdndSelection))
566                 m_drag->handleSelectionRequest(sr);
567             else
568                 m_clipboard->handleSelectionRequest(sr);
569             break;
570         }
571         case XCB_SELECTION_CLEAR:
572             setTime(((xcb_selection_clear_event_t *)event)->time);
573             m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event);
574             handled = true;
575             break;
576         case XCB_SELECTION_NOTIFY:
577             setTime(((xcb_selection_notify_event_t *)event)->time);
578             handled = false;
579             break;
580         case XCB_PROPERTY_NOTIFY:
581             HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
582             break;
583     #ifdef XCB_USE_XINPUT2_MAEMO
584         case GenericEvent:
585             handleGenericEvent((xcb_ge_event_t*)event);
586             break;
587     #endif
588         default:
589             handled = false;
590             break;
591         }
592     }
593
594     if (!handled) {
595         if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
596             setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp);
597             m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
598             handled = true;
599         } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
600             xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event;
601             foreach (QXcbScreen *s, m_screens) {
602                 if (s->root() == change_event->root ) {
603                     s->updateRefreshRate();
604                     break;
605                 }
606             }
607             handled = true;
608         }
609     }
610
611 #ifdef XCB_USE_XLIB
612     if (!handled) {
613         // Check if a custom XEvent constructor was registered in xlib for this event type, and call it discarding the constructed XEvent if any.
614         // XESetWireToEvent might be used by libraries to intercept messages from the X server e.g. the OpenGL lib waiting for DRI2 events.
615
616         Display *xdisplay = (Display *)m_xlib_display;
617         XLockDisplay(xdisplay);
618         Bool (*proc)(Display*, XEvent*, xEvent*) = XESetWireToEvent(xdisplay, response_type, 0);
619         if (proc) {
620             XESetWireToEvent(xdisplay, response_type, proc);
621             XEvent dummy;
622             event->sequence = LastKnownRequestProcessed(m_xlib_display);
623             proc(xdisplay, &dummy, (xEvent*)event);
624         }
625         XUnlockDisplay(xdisplay);
626     }
627 #endif
628
629     if (handled)
630         printXcbEvent("Handled XCB event", event);
631     else
632         printXcbEvent("Unhandled XCB event", event);
633 }
634
635 void QXcbConnection::addPeekFunc(PeekFunc f)
636 {
637     m_peekFuncs.append(f);
638 }
639
640 #ifdef XCB_POLL_FOR_QUEUED_EVENT
641 void QXcbEventReader::run()
642 {
643     xcb_generic_event_t *event;
644     while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) {
645         m_mutex.lock();
646         addEvent(event);
647         while (m_connection && (event = xcb_poll_for_queued_event(m_connection->xcb_connection())))
648             addEvent(event);
649         m_mutex.unlock();
650         emit eventPending();
651     }
652
653     for (int i = 0; i < m_events.size(); ++i)
654         free(m_events.at(i));
655 }
656 #endif
657
658 void QXcbEventReader::addEvent(xcb_generic_event_t *event)
659 {
660     if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
661         && ((xcb_client_message_event_t *)event)->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
662         m_connection = 0;
663     m_events << event;
664 }
665
666 QXcbEventArray *QXcbEventReader::lock()
667 {
668     m_mutex.lock();
669 #ifndef XCB_POLL_FOR_QUEUED_EVENT
670     while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection()))
671         m_events << event;
672 #endif
673     return &m_events;
674 }
675
676 void QXcbEventReader::unlock()
677 {
678     m_mutex.unlock();
679 }
680
681 void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
682 {
683     xcb_client_message_event_t event;
684     memset(&event, 0, sizeof(event));
685
686     event.response_type = XCB_CLIENT_MESSAGE;
687     event.format = 32;
688     event.sequence = 0;
689     event.window = m_connectionEventListener;
690     event.type = atom(a);
691     event.data.data32[0] = id;
692
693     Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
694     xcb_flush(xcb_connection());
695 }
696
697 void QXcbConnection::processXcbEvents()
698 {
699     QXcbEventArray *eventqueue = m_reader->lock();
700
701     for(int i = 0; i < eventqueue->size(); ++i) {
702         xcb_generic_event_t *event = eventqueue->at(i);
703         if (!event)
704             continue;
705         (*eventqueue)[i] = 0;
706
707         uint response_type = event->response_type & ~0x80;
708
709         if (!response_type) {
710             handleXcbError((xcb_generic_error_t *)event);
711         } else {
712             QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
713             while (it != m_peekFuncs.end()) {
714                 // These callbacks return true if the event is what they were
715                 // waiting for, remove them from the list in that case.
716                 if ((*it)(event))
717                     it = m_peekFuncs.erase(it);
718                 else
719                     ++it;
720             }
721             m_reader->unlock();
722             handleXcbEvent(event);
723             m_reader->lock();
724         }
725
726         free(event);
727     }
728
729     eventqueue->clear();
730
731     m_reader->unlock();
732
733     // Indicate with a null event that the event the callbacks are waiting for
734     // is not in the queue currently.
735     Q_FOREACH (PeekFunc f, m_peekFuncs)
736         f(0);
737     m_peekFuncs.clear();
738
739     xcb_flush(xcb_connection());
740 }
741
742 void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event)
743 {
744     if (event->format != 32)
745         return;
746
747     if (event->type == atom(QXcbAtom::XdndStatus)) {
748         drag()->handleStatus(event);
749     } else if (event->type == atom(QXcbAtom::XdndFinished)) {
750         drag()->handleFinished(event);
751     }
752
753     QXcbWindow *window = platformWindowFromId(event->window);
754     if (!window)
755         return;
756
757     window->handleClientMessageEvent(event);
758 }
759
760 xcb_generic_event_t *QXcbConnection::checkEvent(int type)
761 {
762     QXcbEventArray *eventqueue = m_reader->lock();
763
764     for (int i = 0; i < eventqueue->size(); ++i) {
765         xcb_generic_event_t *event = eventqueue->at(i);
766         if (event && event->response_type == type) {
767             (*eventqueue)[i] = 0;
768             m_reader->unlock();
769             return event;
770         }
771     }
772
773     m_reader->unlock();
774
775     return 0;
776 }
777
778 static const char * xcb_atomnames = {
779     // window-manager <-> client protocols
780     "WM_PROTOCOLS\0"
781     "WM_DELETE_WINDOW\0"
782     "WM_TAKE_FOCUS\0"
783     "_NET_WM_PING\0"
784     "_NET_WM_CONTEXT_HELP\0"
785     "_NET_WM_SYNC_REQUEST\0"
786     "_NET_WM_SYNC_REQUEST_COUNTER\0"
787
788     // ICCCM window state
789     "WM_STATE\0"
790     "WM_CHANGE_STATE\0"
791
792     // Session management
793     "WM_CLIENT_LEADER\0"
794     "WM_WINDOW_ROLE\0"
795     "SM_CLIENT_ID\0"
796
797     // Clipboard
798     "CLIPBOARD\0"
799     "INCR\0"
800     "TARGETS\0"
801     "MULTIPLE\0"
802     "TIMESTAMP\0"
803     "SAVE_TARGETS\0"
804     "CLIP_TEMPORARY\0"
805     "_QT_SELECTION\0"
806     "_QT_CLIPBOARD_SENTINEL\0"
807     "_QT_SELECTION_SENTINEL\0"
808     "CLIPBOARD_MANAGER\0"
809
810     "RESOURCE_MANAGER\0"
811
812     "_XSETROOT_ID\0"
813
814     "_QT_SCROLL_DONE\0"
815     "_QT_INPUT_ENCODING\0"
816
817     "_QT_CLOSE_CONNECTION\0"
818
819     "_MOTIF_WM_HINTS\0"
820
821     "DTWM_IS_RUNNING\0"
822     "ENLIGHTENMENT_DESKTOP\0"
823     "_DT_SAVE_MODE\0"
824     "_SGI_DESKS_MANAGER\0"
825
826     // EWMH (aka NETWM)
827     "_NET_SUPPORTED\0"
828     "_NET_VIRTUAL_ROOTS\0"
829     "_NET_WORKAREA\0"
830
831     "_NET_MOVERESIZE_WINDOW\0"
832     "_NET_WM_MOVERESIZE\0"
833
834     "_NET_WM_NAME\0"
835     "_NET_WM_ICON_NAME\0"
836     "_NET_WM_ICON\0"
837
838     "_NET_WM_PID\0"
839
840     "_NET_WM_WINDOW_OPACITY\0"
841
842     "_NET_WM_STATE\0"
843     "_NET_WM_STATE_ABOVE\0"
844     "_NET_WM_STATE_BELOW\0"
845     "_NET_WM_STATE_FULLSCREEN\0"
846     "_NET_WM_STATE_MAXIMIZED_HORZ\0"
847     "_NET_WM_STATE_MAXIMIZED_VERT\0"
848     "_NET_WM_STATE_MODAL\0"
849     "_NET_WM_STATE_STAYS_ON_TOP\0"
850     "_NET_WM_STATE_DEMANDS_ATTENTION\0"
851
852     "_NET_WM_USER_TIME\0"
853     "_NET_WM_USER_TIME_WINDOW\0"
854     "_NET_WM_FULL_PLACEMENT\0"
855
856     "_NET_WM_WINDOW_TYPE\0"
857     "_NET_WM_WINDOW_TYPE_DESKTOP\0"
858     "_NET_WM_WINDOW_TYPE_DOCK\0"
859     "_NET_WM_WINDOW_TYPE_TOOLBAR\0"
860     "_NET_WM_WINDOW_TYPE_MENU\0"
861     "_NET_WM_WINDOW_TYPE_UTILITY\0"
862     "_NET_WM_WINDOW_TYPE_SPLASH\0"
863     "_NET_WM_WINDOW_TYPE_DIALOG\0"
864     "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
865     "_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
866     "_NET_WM_WINDOW_TYPE_TOOLTIP\0"
867     "_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
868     "_NET_WM_WINDOW_TYPE_COMBO\0"
869     "_NET_WM_WINDOW_TYPE_DND\0"
870     "_NET_WM_WINDOW_TYPE_NORMAL\0"
871     "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
872
873     "_KDE_NET_WM_FRAME_STRUT\0"
874
875     "_NET_STARTUP_INFO\0"
876     "_NET_STARTUP_INFO_BEGIN\0"
877
878     "_NET_SUPPORTING_WM_CHECK\0"
879
880     "_NET_WM_CM_S0\0"
881
882     "_NET_SYSTEM_TRAY_VISUAL\0"
883
884     "_NET_ACTIVE_WINDOW\0"
885
886     // Property formats
887     "TEXT\0"
888     "UTF8_STRING\0"
889
890     // xdnd
891     "XdndEnter\0"
892     "XdndPosition\0"
893     "XdndStatus\0"
894     "XdndLeave\0"
895     "XdndDrop\0"
896     "XdndFinished\0"
897     "XdndTypeList\0"
898     "XdndActionList\0"
899
900     "XdndSelection\0"
901
902     "XdndAware\0"
903     "XdndProxy\0"
904
905     "XdndActionCopy\0"
906     "XdndActionLink\0"
907     "XdndActionMove\0"
908     "XdndActionPrivate\0"
909
910     // Motif DND
911     "_MOTIF_DRAG_AND_DROP_MESSAGE\0"
912     "_MOTIF_DRAG_INITIATOR_INFO\0"
913     "_MOTIF_DRAG_RECEIVER_INFO\0"
914     "_MOTIF_DRAG_WINDOW\0"
915     "_MOTIF_DRAG_TARGETS\0"
916
917     "XmTRANSFER_SUCCESS\0"
918     "XmTRANSFER_FAILURE\0"
919
920     // Xkb
921     "_XKB_RULES_NAMES\0"
922
923     // XEMBED
924     "_XEMBED\0"
925     "_XEMBED_INFO\0"
926
927     // Wacom old. (before version 0.10)
928     "Wacom Stylus\0"
929     "Wacom Cursor\0"
930     "Wacom Eraser\0"
931
932     // Tablet
933     "STYLUS\0"
934     "ERASER\0"
935
936     // XInput2
937     "Button Left\0"
938     "Button Middle\0"
939     "Button Right\0"
940     "Button Wheel Up\0"
941     "Button Wheel Down\0"
942     "Button Horiz Wheel Left\0"
943     "Button Horiz Wheel Right\0"
944     "Abs MT Position X\0"
945     "Abs MT Position Y\0"
946     "Abs MT Touch Major\0"
947     "Abs MT Touch Minor\0"
948     "Abs MT Pressure\0"
949     "Abs MT Tracking ID\0"
950     "Max Contacts\0"
951 #if XCB_USE_MAEMO_WINDOW_PROPERTIES
952     "_MEEGOTOUCH_ORIENTATION_ANGLE\0"
953 #endif
954 };
955
956 xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom)
957 {
958     return m_allAtoms[atom];
959 }
960
961 void QXcbConnection::initializeAllAtoms() {
962     const char *names[QXcbAtom::NAtoms];
963     const char *ptr = xcb_atomnames;
964
965     int i = 0;
966     while (*ptr) {
967         names[i++] = ptr;
968         while (*ptr)
969             ++ptr;
970         ++ptr;
971     }
972
973     Q_ASSERT(i == QXcbAtom::NPredefinedAtoms);
974
975     QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
976     settings_atom_name += m_displayName;
977     names[i++] = settings_atom_name;
978
979     xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
980
981     Q_ASSERT(i == QXcbAtom::NAtoms);
982     for (i = 0; i < QXcbAtom::NAtoms; ++i)
983         cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]);
984
985     for (i = 0; i < QXcbAtom::NAtoms; ++i) {
986         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0);
987         m_allAtoms[i] = reply->atom;
988         free(reply);
989     }
990 }
991
992 xcb_atom_t QXcbConnection::internAtom(const char *name)
993 {
994     if (!name || *name == 0)
995         return XCB_NONE;
996
997     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name);
998     xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0);
999     int atom = reply->atom;
1000     free(reply);
1001     return atom;
1002 }
1003
1004 QByteArray QXcbConnection::atomName(xcb_atom_t atom)
1005 {
1006     if (!atom)
1007         return QByteArray();
1008
1009     xcb_generic_error_t *error = 0;
1010     xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom));
1011     xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error);
1012     if (error) {
1013         qWarning() << "QXcbConnection::atomName: bad Atom" << atom;
1014         free(error);
1015     }
1016     if (reply) {
1017         QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
1018         free(reply);
1019         return result;
1020     }
1021     return QByteArray();
1022 }
1023
1024 const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
1025 {
1026     xcb_format_iterator_t iterator =
1027         xcb_setup_pixmap_formats_iterator(m_setup);
1028
1029     while (iterator.rem) {
1030         xcb_format_t *format = iterator.data;
1031         if (format->depth == depth)
1032             return format;
1033         xcb_format_next(&iterator);
1034     }
1035
1036     return 0;
1037 }
1038
1039 void QXcbConnection::sync()
1040 {
1041     // from xcb_aux_sync
1042     xcb_get_input_focus_cookie_t cookie = Q_XCB_CALL(xcb_get_input_focus(xcb_connection()));
1043     free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
1044 }
1045
1046 void QXcbConnection::initializeXFixes()
1047 {
1048     xcb_generic_error_t *error = 0;
1049     const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id);
1050     xfixes_first_event = reply->first_event;
1051
1052     xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
1053                                                                                      XCB_XFIXES_MAJOR_VERSION,
1054                                                                                      XCB_XFIXES_MINOR_VERSION);
1055     xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection,
1056                                                                                      xfixes_query_cookie, &error);
1057     if (!xfixes_query || error || xfixes_query->major_version < 2) {
1058         qWarning("QXcbConnection: Failed to initialize XFixes");
1059         free(error);
1060         xfixes_first_event = 0;
1061     }
1062     free(xfixes_query);
1063 }
1064
1065 void QXcbConnection::initializeXRender()
1066 {
1067 #ifdef XCB_USE_RENDER
1068     xcb_generic_error_t *error = 0;
1069     xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection,
1070                                                                                       XCB_RENDER_MAJOR_VERSION,
1071                                                                                       XCB_RENDER_MINOR_VERSION);
1072     xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection,
1073                                                                                      xrender_query_cookie, &error);
1074     if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) {
1075         qWarning("QXcbConnection: Failed to initialize XRender");
1076         free(error);
1077     }
1078     free(xrender_query);
1079 #endif
1080 }
1081
1082 void QXcbConnection::initializeXRandr()
1083 {
1084     const xcb_query_extension_reply_t *xrandr_reply = xcb_get_extension_data(m_connection, &xcb_randr_id);
1085     if (!xrandr_reply || !xrandr_reply->present)
1086         return;
1087
1088     xrandr_first_event = xrandr_reply->first_event;
1089
1090     xcb_generic_error_t *error = 0;
1091     xcb_randr_query_version_cookie_t xrandr_query_cookie = xcb_randr_query_version(m_connection,
1092                                                                                    XCB_RANDR_MAJOR_VERSION,
1093                                                                                    XCB_RANDR_MINOR_VERSION);
1094
1095     has_randr_extension = true;
1096
1097     xcb_randr_query_version_reply_t *xrandr_query = xcb_randr_query_version_reply(m_connection,
1098                                                                                   xrandr_query_cookie, &error);
1099     if (!xrandr_query || error || (xrandr_query->major_version < 1 || (xrandr_query->major_version == 1 && xrandr_query->minor_version < 2))) {
1100         qWarning("QXcbConnection: Failed to initialize XRandr");
1101         free(error);
1102         has_randr_extension = false;
1103     }
1104     free(xrandr_query);
1105 }
1106
1107 void QXcbConnection::initializeXShape()
1108 {
1109     const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id);
1110     if (!xshape_reply || !xshape_reply->present)
1111         return;
1112
1113     has_shape_extension = true;
1114     xcb_shape_query_version_cookie_t cookie = xcb_shape_query_version(m_connection);
1115     xcb_shape_query_version_reply_t *shape_query = xcb_shape_query_version_reply(m_connection,
1116                                                                                  cookie, NULL);
1117     if (!shape_query) {
1118         qWarning("QXcbConnection: Failed to initialize SHAPE extension");
1119     } else if (shape_query->major_version > 1 || (shape_query->major_version == 1 && shape_query->minor_version >= 1)) {
1120         // The input shape is the only thing added in SHAPE 1.1
1121         has_input_shape = true;
1122     }
1123     free(shape_query);
1124 }
1125
1126 #if defined(XCB_USE_EGL)
1127 bool QXcbConnection::hasEgl() const
1128 {
1129     return m_has_egl;
1130 }
1131 #endif // defined(XCB_USE_EGL)
1132
1133 #ifdef XCB_USE_DRI2
1134 void QXcbConnection::initializeDri2()
1135 {
1136     xcb_dri2_connect_cookie_t connect_cookie = xcb_dri2_connect_unchecked (m_connection,
1137                                                                            m_screens[0]->root(),
1138                                                                            XCB_DRI2_DRIVER_TYPE_DRI);
1139
1140     xcb_dri2_connect_reply_t *connect = xcb_dri2_connect_reply (m_connection,
1141                                                                 connect_cookie, NULL);
1142
1143     if (! connect || connect->driver_name_length + connect->device_name_length == 0) {
1144         qWarning("QXcbConnection: Failed to connect to DRI2");
1145         return;
1146     }
1147
1148     m_dri2_device_name = QByteArray(xcb_dri2_connect_device_name (connect),
1149                                                     xcb_dri2_connect_device_name_length (connect));
1150     delete connect;
1151
1152     int fd = open(m_dri2_device_name.constData(), O_RDWR);
1153     if (fd < 0) {
1154         qWarning() << "QXcbConnection: Couldn't open DRI2 device" << m_dri2_device_name;
1155         m_dri2_device_name = QByteArray();
1156         return;
1157     }
1158
1159     drm_magic_t magic;
1160     if (drmGetMagic(fd, &magic)) {
1161         qWarning("QXcbConnection: Failed to get drmMagic");
1162         return;
1163     }
1164
1165     xcb_dri2_authenticate_cookie_t authenticate_cookie = xcb_dri2_authenticate_unchecked(m_connection,
1166                                                                                          m_screens[0]->root(), magic);
1167     xcb_dri2_authenticate_reply_t *authenticate = xcb_dri2_authenticate_reply(m_connection,
1168                                                                               authenticate_cookie, NULL);
1169     if (authenticate == NULL || !authenticate->authenticated) {
1170         qWarning("QXcbConnection: DRI2: failed to authenticate");
1171         free(authenticate);
1172         return;
1173     }
1174
1175     delete authenticate;
1176
1177     EGLDisplay display = eglGetDRMDisplayMESA(fd);
1178     if (!display) {
1179         qWarning("QXcbConnection: Failed to create EGL display using DRI2");
1180         return;
1181     }
1182
1183     m_egl_display = display;
1184     EGLint major,minor;
1185     if (!eglInitialize(display, &major, &minor)) {
1186         qWarning("QXcbConnection: Failed to initialize EGL display using DRI2");
1187         return;
1188     }
1189 }
1190
1191 bool QXcbConnection::hasSupportForDri2() const
1192 {
1193     if (!m_dri2_support_probed) {
1194         xcb_generic_error_t *error = 0;
1195
1196         xcb_prefetch_extension_data (m_connection, &xcb_dri2_id);
1197
1198         xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection,
1199                                                                                     XCB_DRI2_MAJOR_VERSION,
1200                                                                                     XCB_DRI2_MINOR_VERSION);
1201
1202         xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection,
1203                                                                                    dri2_query_cookie, &error);
1204         if (!dri2_query || error) {
1205             delete error;
1206             delete dri2_query;
1207             return false;
1208         }
1209
1210         QXcbConnection *that = const_cast<QXcbConnection *>(this);
1211         that->m_dri2_major = dri2_query->major_version;
1212         that->m_dri2_minor = dri2_query->minor_version;
1213
1214         that->m_has_support_for_dri2 = true;
1215         that->m_dri2_support_probed = true;
1216     }
1217     return m_has_support_for_dri2;
1218 }
1219 #endif //XCB_USE_DRI2
1220
1221 QT_END_NAMESPACE