Cocoa: Fix qmlscene flicker on startup.
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbconnection.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 <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
53 #include <QtAlgorithms>
54 #include <QSocketNotifier>
55 #include <QAbstractEventDispatcher>
56 #include <QTimer>
57
58 #include <stdio.h>
59 #include <errno.h>
60 #include <xcb/xfixes.h>
61
62 #ifdef XCB_USE_XLIB
63 #include <X11/Xlib.h>
64 #include <X11/Xlib-xcb.h>
65 #endif
66
67 #ifdef XCB_USE_RENDER
68 #include <xcb/render.h>
69 #endif
70
71 #ifdef XCB_USE_EGL //dont pull in eglext prototypes
72 #include <EGL/egl.h>
73 #endif
74
75 #ifdef XCB_USE_DRI2
76 #include <xcb/dri2.h>
77 extern "C" {
78 #include <xf86drm.h>
79 }
80 #define MESA_EGL_NO_X11_HEADERS
81 #define EGL_EGLEXT_PROTOTYPES
82 #include <EGL/egl.h>
83 #include <EGL/eglext.h>
84 #endif
85
86 QXcbConnection::QXcbConnection(const char *displayName)
87     : m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
88 #ifdef XCB_USE_DRI2
89     , m_dri2_major(0)
90     , m_dri2_minor(0)
91     , m_dri2_support_probed(false)
92     , m_has_support_for_dri2(false)
93 #endif
94     , xfixes_first_event(0)
95 {
96     m_primaryScreen = 0;
97
98 #ifdef XCB_USE_XLIB
99     Display *dpy = XOpenDisplay(m_displayName.constData());
100     m_primaryScreen = DefaultScreen(dpy);
101     m_connection = XGetXCBConnection(dpy);
102     XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
103     m_xlib_display = dpy;
104 #ifdef XCB_USE_EGL
105     EGLDisplay eglDisplay = eglGetDisplay(dpy);
106     m_egl_display = eglDisplay;
107     EGLint major, minor;
108     eglBindAPI(EGL_OPENGL_ES_API);
109     m_has_egl = eglInitialize(eglDisplay,&major,&minor);
110 #endif //XCB_USE_EGL
111 #else
112     m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen);
113 #endif //XCB_USE_XLIB
114
115     if (m_connection)
116         printf("Successfully connected to display %s\n", m_displayName.constData());
117
118     m_reader = new QXcbEventReader(m_connection);
119 #ifdef XCB_POLL_FOR_QUEUED_EVENT
120     connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection);
121     m_reader->start();
122 #else
123     QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this);
124     connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents()));
125
126     QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
127     connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents()));
128     connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents()));
129 #endif
130
131     xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id);
132
133     m_setup = xcb_get_setup(xcb_connection());
134
135     initializeAllAtoms();
136
137     m_time = XCB_CURRENT_TIME;
138
139     xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
140
141     int screenNumber = 0;
142     while (it.rem) {
143         m_screens << new QXcbScreen(this, it.data, screenNumber++);
144         xcb_screen_next(&it);
145     }
146
147     m_connectionEventListener = xcb_generate_id(m_connection);
148     xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
149                       m_connectionEventListener, m_screens.at(0)->root(),
150                       0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
151                       m_screens.at(0)->screen()->root_visual, 0, 0);
152
153     initializeXFixes();
154     initializeXRender();
155
156     m_wmSupport = new QXcbWMSupport(this);
157     m_keyboard = new QXcbKeyboard(this);
158     m_clipboard = new QXcbClipboard(this);
159     m_drag = new QXcbDrag(this);
160
161 #ifdef XCB_USE_DRI2
162     initializeDri2();
163 #endif
164     sync();
165 }
166
167 QXcbConnection::~QXcbConnection()
168 {
169     delete m_clipboard;
170
171     qDeleteAll(m_screens);
172
173 #ifdef XCB_POLL_FOR_QUEUED_EVENT
174     sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION);
175     m_reader->wait();
176 #endif
177     delete m_reader;
178
179 #ifdef XCB_USE_XLIB
180     XCloseDisplay((Display *)m_xlib_display);
181 #else
182     xcb_disconnect(xcb_connection());
183 #endif
184
185     delete m_keyboard;
186 }
187
188 void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window)
189 {
190     m_mapper.insert(id, window);
191 }
192
193 void QXcbConnection::removeWindow(xcb_window_t id)
194 {
195     m_mapper.remove(id);
196 }
197
198 QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
199 {
200     return m_mapper.value(id, 0);
201 }
202
203 #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
204 { \
205     event_t *e = (event_t *)event; \
206     if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) \
207         platformWindow->handler(e); \
208 } \
209 break;
210
211 #define HANDLE_KEYBOARD_EVENT(event_t, handler) \
212 { \
213     event_t *e = (event_t *)event; \
214     if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) \
215         m_keyboard->handler(platformWindow, e); \
216 } \
217 break;
218
219 //#define XCB_EVENT_DEBUG
220
221 void printXcbEvent(const char *message, xcb_generic_event_t *event)
222 {
223 #ifdef XCB_EVENT_DEBUG
224 #define PRINT_XCB_EVENT(ev) \
225     case ev: \
226         printf("%s: %d - %s - sequence: %d\n", message, int(ev), #ev, event->sequence); \
227         break;
228
229     switch (event->response_type & ~0x80) {
230     PRINT_XCB_EVENT(XCB_KEY_PRESS);
231     PRINT_XCB_EVENT(XCB_KEY_RELEASE);
232     PRINT_XCB_EVENT(XCB_BUTTON_PRESS);
233     PRINT_XCB_EVENT(XCB_BUTTON_RELEASE);
234     PRINT_XCB_EVENT(XCB_MOTION_NOTIFY);
235     PRINT_XCB_EVENT(XCB_ENTER_NOTIFY);
236     PRINT_XCB_EVENT(XCB_LEAVE_NOTIFY);
237     PRINT_XCB_EVENT(XCB_FOCUS_IN);
238     PRINT_XCB_EVENT(XCB_FOCUS_OUT);
239     PRINT_XCB_EVENT(XCB_KEYMAP_NOTIFY);
240     PRINT_XCB_EVENT(XCB_EXPOSE);
241     PRINT_XCB_EVENT(XCB_GRAPHICS_EXPOSURE);
242     PRINT_XCB_EVENT(XCB_VISIBILITY_NOTIFY);
243     PRINT_XCB_EVENT(XCB_CREATE_NOTIFY);
244     PRINT_XCB_EVENT(XCB_DESTROY_NOTIFY);
245     PRINT_XCB_EVENT(XCB_UNMAP_NOTIFY);
246     PRINT_XCB_EVENT(XCB_MAP_NOTIFY);
247     PRINT_XCB_EVENT(XCB_MAP_REQUEST);
248     PRINT_XCB_EVENT(XCB_REPARENT_NOTIFY);
249     PRINT_XCB_EVENT(XCB_CONFIGURE_NOTIFY);
250     PRINT_XCB_EVENT(XCB_CONFIGURE_REQUEST);
251     PRINT_XCB_EVENT(XCB_GRAVITY_NOTIFY);
252     PRINT_XCB_EVENT(XCB_RESIZE_REQUEST);
253     PRINT_XCB_EVENT(XCB_CIRCULATE_NOTIFY);
254     PRINT_XCB_EVENT(XCB_CIRCULATE_REQUEST);
255     PRINT_XCB_EVENT(XCB_PROPERTY_NOTIFY);
256     PRINT_XCB_EVENT(XCB_SELECTION_CLEAR);
257     PRINT_XCB_EVENT(XCB_SELECTION_REQUEST);
258     PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY);
259     PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY);
260     PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE);
261     PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY);
262     default:
263         printf("%s: unknown event - response_type: %d - sequence: %d\n", message, int(event->response_type & ~0x80), int(event->sequence));
264     }
265 #else
266     Q_UNUSED(message);
267     Q_UNUSED(event);
268 #endif
269 }
270
271 const char *xcb_errors[] =
272 {
273     "Success",
274     "BadRequest",
275     "BadValue",
276     "BadWindow",
277     "BadPixmap",
278     "BadAtom",
279     "BadCursor",
280     "BadFont",
281     "BadMatch",
282     "BadDrawable",
283     "BadAccess",
284     "BadAlloc",
285     "BadColor",
286     "BadGC",
287     "BadIDChoice",
288     "BadName",
289     "BadLength",
290     "BadImplementation",
291     "Unknown"
292 };
293
294 const char *xcb_protocol_request_codes[] =
295 {
296     "Null",
297     "CreateWindow",
298     "ChangeWindowAttributes",
299     "GetWindowAttributes",
300     "DestroyWindow",
301     "DestroySubwindows",
302     "ChangeSaveSet",
303     "ReparentWindow",
304     "MapWindow",
305     "MapSubwindows",
306     "UnmapWindow",
307     "UnmapSubwindows",
308     "ConfigureWindow",
309     "CirculateWindow",
310     "GetGeometry",
311     "QueryTree",
312     "InternAtom",
313     "GetAtomName",
314     "ChangeProperty",
315     "DeleteProperty",
316     "GetProperty",
317     "ListProperties",
318     "SetSelectionOwner",
319     "GetSelectionOwner",
320     "ConvertSelection",
321     "SendEvent",
322     "GrabPointer",
323     "UngrabPointer",
324     "GrabButton",
325     "UngrabButton",
326     "ChangeActivePointerGrab",
327     "GrabKeyboard",
328     "UngrabKeyboard",
329     "GrabKey",
330     "UngrabKey",
331     "AllowEvents",
332     "GrabServer",
333     "UngrabServer",
334     "QueryPointer",
335     "GetMotionEvents",
336     "TranslateCoords",
337     "WarpPointer",
338     "SetInputFocus",
339     "GetInputFocus",
340     "QueryKeymap",
341     "OpenFont",
342     "CloseFont",
343     "QueryFont",
344     "QueryTextExtents",
345     "ListFonts",
346     "ListFontsWithInfo",
347     "SetFontPath",
348     "GetFontPath",
349     "CreatePixmap",
350     "FreePixmap",
351     "CreateGC",
352     "ChangeGC",
353     "CopyGC",
354     "SetDashes",
355     "SetClipRectangles",
356     "FreeGC",
357     "ClearArea",
358     "CopyArea",
359     "CopyPlane",
360     "PolyPoint",
361     "PolyLine",
362     "PolySegment",
363     "PolyRectangle",
364     "PolyArc",
365     "FillPoly",
366     "PolyFillRectangle",
367     "PolyFillArc",
368     "PutImage",
369     "GetImage",
370     "PolyText8",
371     "PolyText16",
372     "ImageText8",
373     "ImageText16",
374     "CreateColormap",
375     "FreeColormap",
376     "CopyColormapAndFree",
377     "InstallColormap",
378     "UninstallColormap",
379     "ListInstalledColormaps",
380     "AllocColor",
381     "AllocNamedColor",
382     "AllocColorCells",
383     "AllocColorPlanes",
384     "FreeColors",
385     "StoreColors",
386     "StoreNamedColor",
387     "QueryColors",
388     "LookupColor",
389     "CreateCursor",
390     "CreateGlyphCursor",
391     "FreeCursor",
392     "RecolorCursor",
393     "QueryBestSize",
394     "QueryExtension",
395     "ListExtensions",
396     "ChangeKeyboardMapping",
397     "GetKeyboardMapping",
398     "ChangeKeyboardControl",
399     "GetKeyboardControl",
400     "Bell",
401     "ChangePointerControl",
402     "GetPointerControl",
403     "SetScreenSaver",
404     "GetScreenSaver",
405     "ChangeHosts",
406     "ListHosts",
407     "SetAccessControl",
408     "SetCloseDownMode",
409     "KillClient",
410     "RotateProperties",
411     "ForceScreenSaver",
412     "SetPointerMapping",
413     "GetPointerMapping",
414     "SetModifierMapping",
415     "GetModifierMapping",
416     "Unknown"
417 };
418
419 #ifdef Q_XCB_DEBUG
420 void QXcbConnection::log(const char *file, int line, int sequence)
421 {
422     CallInfo info;
423     info.sequence = sequence;
424     info.file = file;
425     info.line = line;
426     m_callLog << info;
427 }
428 #endif
429
430 void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
431 {
432     uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
433     uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
434
435     printf("XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d\n",
436            int(error->error_code), xcb_errors[clamped_error_code],
437            int(error->sequence), int(error->resource_id),
438            int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
439            int(error->minor_code));
440 #ifdef Q_XCB_DEBUG
441     int i = 0;
442     for (; i < m_callLog.size(); ++i) {
443         if (m_callLog.at(i).sequence == error->sequence) {
444             printf("Caused by: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
445             break;
446         } else if (m_callLog.at(i).sequence > error->sequence) {
447             printf("Caused some time before: %s:%d\n", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
448             if (i > 0)
449                 printf("and after: %s:%d\n", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
450             break;
451         }
452     }
453     if (i == m_callLog.size() && !m_callLog.isEmpty())
454         printf("Caused some time after: %s:%d\n", qPrintable(m_callLog.first().file), m_callLog.first().line);
455 #endif
456 }
457
458 void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
459 {
460 #ifdef Q_XCB_DEBUG
461     {
462         int i = 0;
463         for (; i < m_callLog.size(); ++i)
464             if (m_callLog.at(i).sequence >= event->sequence)
465                 break;
466         m_callLog.remove(0, i);
467     }
468 #endif
469     bool handled = true;
470
471     uint response_type = event->response_type & ~0x80;
472
473     switch (response_type) {
474     case XCB_EXPOSE:
475         HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleSynchronousExposeEvent);
476     case XCB_BUTTON_PRESS:
477         HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
478     case XCB_BUTTON_RELEASE:
479         HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
480     case XCB_MOTION_NOTIFY:
481         HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
482     case XCB_CONFIGURE_NOTIFY:
483         HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
484     case XCB_MAP_NOTIFY:
485         HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
486     case XCB_UNMAP_NOTIFY:
487         HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
488     case XCB_CLIENT_MESSAGE:
489         handleClientMessageEvent((xcb_client_message_event_t *)event);
490     case XCB_ENTER_NOTIFY:
491         HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
492     case XCB_LEAVE_NOTIFY:
493         HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
494     case XCB_FOCUS_IN:
495         HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
496     case XCB_FOCUS_OUT:
497         HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
498     case XCB_KEY_PRESS:
499         HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
500     case XCB_KEY_RELEASE:
501         HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
502     case XCB_MAPPING_NOTIFY:
503         m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
504         break;
505     case XCB_SELECTION_REQUEST:
506     {
507         xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
508         if (sr->selection == atom(QXcbAtom::XdndSelection))
509             m_drag->handleSelectionRequest(sr);
510         else
511             m_clipboard->handleSelectionRequest(sr);
512         break;
513     }
514     case XCB_SELECTION_CLEAR:
515         setTime(((xcb_selection_clear_event_t *)event)->time);
516         m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event);
517         handled = true;
518         break;
519     case XCB_SELECTION_NOTIFY:
520         setTime(((xcb_selection_notify_event_t *)event)->time);
521         qDebug() << "XCB_SELECTION_NOTIFY";
522         handled = false;
523         break;
524     case XCB_PROPERTY_NOTIFY:
525         setTime(((xcb_property_notify_event_t *)event)->time);
526 //        qDebug() << "XCB_PROPERTY_NOTIFY";
527         handled = false;
528         break;
529     default:
530         handled = false;
531         break;
532     }
533
534     if (!handled) {
535         if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
536             setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp);
537             m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
538             handled = true;
539         }
540     }
541
542     if (handled)
543         printXcbEvent("Handled XCB event", event);
544     else
545         printXcbEvent("Unhandled XCB event", event);
546 }
547
548 void QXcbConnection::addPeekFunc(PeekFunc f)
549 {
550     m_peekFuncs.append(f);
551 }
552
553 #ifdef XCB_POLL_FOR_QUEUED_EVENT
554 void QXcbEventReader::run()
555 {
556     xcb_generic_event_t *event;
557     while (m_connection && (event = xcb_wait_for_event(m_connection))) {
558         m_mutex.lock();
559         addEvent(event);
560         while (m_connection && (event = xcb_poll_for_queued_event(m_connection)))
561             addEvent(event);
562         m_mutex.unlock();
563         emit eventPending();
564     }
565
566     for (int i = 0; i < m_events.size(); ++i)
567         free(m_events.at(i));
568 }
569 #endif
570
571 void QXcbEventReader::addEvent(xcb_generic_event_t *event)
572 {
573     if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
574         && ((xcb_client_message_event_t *)event)->type == QXcbAtom::_QT_CLOSE_CONNECTION)
575         m_connection = 0;
576     m_events << event;
577 }
578
579 QList<xcb_generic_event_t *> *QXcbEventReader::lock()
580 {
581     m_mutex.lock();
582 #ifndef XCB_POLL_FOR_QUEUED_EVENT
583     while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection))
584         m_events << event;
585 #endif
586     return &m_events;
587 }
588
589 void QXcbEventReader::unlock()
590 {
591     m_mutex.unlock();
592 }
593
594 void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom atom, uint id)
595 {
596     xcb_client_message_event_t event;
597     memset(&event, 0, sizeof(event));
598
599     event.response_type = XCB_CLIENT_MESSAGE;
600     event.format = 32;
601     event.sequence = 0;
602     event.window = m_connectionEventListener;
603     event.type = atom;
604     event.data.data32[0] = id;
605
606     Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
607     xcb_flush(xcb_connection());
608 }
609
610 void QXcbConnection::processXcbEvents()
611 {
612     QList<xcb_generic_event_t *> *eventqueue = m_reader->lock();
613
614     for(int i = 0; i < eventqueue->size(); ++i) {
615         xcb_generic_event_t *event = eventqueue->at(i);
616         if (!event)
617             continue;
618         (*eventqueue)[i] = 0;
619
620         uint response_type = event->response_type & ~0x80;
621
622         if (!response_type) {
623             handleXcbError((xcb_generic_error_t *)event);
624         } else {
625             QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
626             while (it != m_peekFuncs.end()) {
627                 // These callbacks return true if the event is what they were
628                 // waiting for, remove them from the list in that case.
629                 if ((*it)(event))
630                     it = m_peekFuncs.erase(it);
631                 else
632                     ++it;
633             }
634             handleXcbEvent(event);
635         }
636
637         free(event);
638     }
639
640     eventqueue->clear();
641
642     m_reader->unlock();
643
644     // Indicate with a null event that the event the callbacks are waiting for
645     // is not in the queue currently.
646     Q_FOREACH (PeekFunc f, m_peekFuncs)
647         f(0);
648     m_peekFuncs.clear();
649
650     xcb_flush(xcb_connection());
651 }
652
653 void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event)
654 {
655     if (event->format != 32)
656         return;
657
658     if (event->type == atom(QXcbAtom::XdndStatus)) {
659         drag()->handleStatus(event, false);
660     } else if (event->type == atom(QXcbAtom::XdndFinished)) {
661         drag()->handleFinished(event, false);
662     }
663
664     QXcbWindow *window = platformWindowFromId(event->window);
665     if (!window)
666         return;
667
668     window->handleClientMessageEvent(event);
669 }
670
671 xcb_generic_event_t *QXcbConnection::checkEvent(int type)
672 {
673     QList<xcb_generic_event_t *> *eventqueue = m_reader->lock();
674
675     for (int i = 0; i < eventqueue->size(); ++i) {
676         xcb_generic_event_t *event = eventqueue->at(i);
677         if (event->response_type == type) {
678             (*eventqueue)[i] = 0;
679             m_reader->unlock();
680             return event;
681         }
682     }
683
684     m_reader->unlock();
685
686     return 0;
687 }
688
689 static const char * xcb_atomnames = {
690     // window-manager <-> client protocols
691     "WM_PROTOCOLS\0"
692     "WM_DELETE_WINDOW\0"
693     "WM_TAKE_FOCUS\0"
694     "_NET_WM_PING\0"
695     "_NET_WM_CONTEXT_HELP\0"
696     "_NET_WM_SYNC_REQUEST\0"
697     "_NET_WM_SYNC_REQUEST_COUNTER\0"
698
699     // ICCCM window state
700     "WM_STATE\0"
701     "WM_CHANGE_STATE\0"
702
703     // Session management
704     "WM_CLIENT_LEADER\0"
705     "WM_WINDOW_ROLE\0"
706     "SM_CLIENT_ID\0"
707
708     // Clipboard
709     "CLIPBOARD\0"
710     "INCR\0"
711     "TARGETS\0"
712     "MULTIPLE\0"
713     "TIMESTAMP\0"
714     "SAVE_TARGETS\0"
715     "CLIP_TEMPORARY\0"
716     "_QT_SELECTION\0"
717     "_QT_CLIPBOARD_SENTINEL\0"
718     "_QT_SELECTION_SENTINEL\0"
719     "CLIPBOARD_MANAGER\0"
720
721     "RESOURCE_MANAGER\0"
722
723     "_XSETROOT_ID\0"
724
725     "_QT_SCROLL_DONE\0"
726     "_QT_INPUT_ENCODING\0"
727
728     "_QT_CLOSE_CONNECTION\0"
729
730     "_MOTIF_WM_HINTS\0"
731
732     "DTWM_IS_RUNNING\0"
733     "ENLIGHTENMENT_DESKTOP\0"
734     "_DT_SAVE_MODE\0"
735     "_SGI_DESKS_MANAGER\0"
736
737     // EWMH (aka NETWM)
738     "_NET_SUPPORTED\0"
739     "_NET_VIRTUAL_ROOTS\0"
740     "_NET_WORKAREA\0"
741
742     "_NET_MOVERESIZE_WINDOW\0"
743     "_NET_WM_MOVERESIZE\0"
744
745     "_NET_WM_NAME\0"
746     "_NET_WM_ICON_NAME\0"
747     "_NET_WM_ICON\0"
748
749     "_NET_WM_PID\0"
750
751     "_NET_WM_WINDOW_OPACITY\0"
752
753     "_NET_WM_STATE\0"
754     "_NET_WM_STATE_ABOVE\0"
755     "_NET_WM_STATE_BELOW\0"
756     "_NET_WM_STATE_FULLSCREEN\0"
757     "_NET_WM_STATE_MAXIMIZED_HORZ\0"
758     "_NET_WM_STATE_MAXIMIZED_VERT\0"
759     "_NET_WM_STATE_MODAL\0"
760     "_NET_WM_STATE_STAYS_ON_TOP\0"
761     "_NET_WM_STATE_DEMANDS_ATTENTION\0"
762
763     "_NET_WM_USER_TIME\0"
764     "_NET_WM_USER_TIME_WINDOW\0"
765     "_NET_WM_FULL_PLACEMENT\0"
766
767     "_NET_WM_WINDOW_TYPE\0"
768     "_NET_WM_WINDOW_TYPE_DESKTOP\0"
769     "_NET_WM_WINDOW_TYPE_DOCK\0"
770     "_NET_WM_WINDOW_TYPE_TOOLBAR\0"
771     "_NET_WM_WINDOW_TYPE_MENU\0"
772     "_NET_WM_WINDOW_TYPE_UTILITY\0"
773     "_NET_WM_WINDOW_TYPE_SPLASH\0"
774     "_NET_WM_WINDOW_TYPE_DIALOG\0"
775     "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
776     "_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
777     "_NET_WM_WINDOW_TYPE_TOOLTIP\0"
778     "_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
779     "_NET_WM_WINDOW_TYPE_COMBO\0"
780     "_NET_WM_WINDOW_TYPE_DND\0"
781     "_NET_WM_WINDOW_TYPE_NORMAL\0"
782     "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
783
784     "_KDE_NET_WM_FRAME_STRUT\0"
785
786     "_NET_STARTUP_INFO\0"
787     "_NET_STARTUP_INFO_BEGIN\0"
788
789     "_NET_SUPPORTING_WM_CHECK\0"
790
791     "_NET_WM_CM_S0\0"
792
793     "_NET_SYSTEM_TRAY_VISUAL\0"
794
795     "_NET_ACTIVE_WINDOW\0"
796
797     // Property formats
798     "TEXT\0"
799     "UTF8_STRING\0"
800
801     // xdnd
802     "XdndEnter\0"
803     "XdndPosition\0"
804     "XdndStatus\0"
805     "XdndLeave\0"
806     "XdndDrop\0"
807     "XdndFinished\0"
808     "XdndTypeList\0"
809     "XdndActionList\0"
810
811     "XdndSelection\0"
812
813     "XdndAware\0"
814     "XdndProxy\0"
815
816     "XdndActionCopy\0"
817     "XdndActionLink\0"
818     "XdndActionMove\0"
819     "XdndActionPrivate\0"
820
821     // Motif DND
822     "_MOTIF_DRAG_AND_DROP_MESSAGE\0"
823     "_MOTIF_DRAG_INITIATOR_INFO\0"
824     "_MOTIF_DRAG_RECEIVER_INFO\0"
825     "_MOTIF_DRAG_WINDOW\0"
826     "_MOTIF_DRAG_TARGETS\0"
827
828     "XmTRANSFER_SUCCESS\0"
829     "XmTRANSFER_FAILURE\0"
830
831     // Xkb
832     "_XKB_RULES_NAMES\0"
833
834     // XEMBED
835     "_XEMBED\0"
836     "_XEMBED_INFO\0"
837
838     // Wacom old. (before version 0.10)
839     "Wacom Stylus\0"
840     "Wacom Cursor\0"
841     "Wacom Eraser\0"
842
843     // Tablet
844     "STYLUS\0"
845     "ERASER\0"
846 };
847
848 xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom)
849 {
850     return m_allAtoms[atom];
851 }
852
853 void QXcbConnection::initializeAllAtoms() {
854     const char *names[QXcbAtom::NAtoms];
855     const char *ptr = xcb_atomnames;
856
857     int i = 0;
858     while (*ptr) {
859         names[i++] = ptr;
860         while (*ptr)
861             ++ptr;
862         ++ptr;
863     }
864
865     Q_ASSERT(i == QXcbAtom::NPredefinedAtoms);
866
867     QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
868     settings_atom_name += m_displayName;
869     names[i++] = settings_atom_name;
870
871     xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
872
873     Q_ASSERT(i == QXcbAtom::NAtoms);
874     for (i = 0; i < QXcbAtom::NAtoms; ++i)
875         cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]);
876
877     for (i = 0; i < QXcbAtom::NAtoms; ++i) {
878         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0);
879         m_allAtoms[i] = reply->atom;
880         free(reply);
881     }
882 }
883
884 xcb_atom_t QXcbConnection::internAtom(const char *name)
885 {
886     if (!name || *name == 0)
887         return XCB_NONE;
888
889     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name);
890     xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0);
891     int atom = reply->atom;
892     free(reply);
893     return atom;
894 }
895
896 QByteArray QXcbConnection::atomName(xcb_atom_t atom)
897 {
898     if (!atom)
899         return QByteArray();
900
901     xcb_generic_error_t *error = 0;
902     xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom));
903     xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error);
904     if (error) {
905         qWarning() << "QXcbConnection::atomName: bad Atom" << atom;
906     }
907     if (reply) {
908         QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
909         free(reply);
910         return result;
911     }
912     return QByteArray();
913 }
914
915 const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
916 {
917     xcb_format_iterator_t iterator =
918         xcb_setup_pixmap_formats_iterator(m_setup);
919
920     while (iterator.rem) {
921         xcb_format_t *format = iterator.data;
922         if (format->depth == depth)
923             return format;
924         xcb_format_next(&iterator);
925     }
926
927     return 0;
928 }
929
930 void QXcbConnection::sync()
931 {
932     // from xcb_aux_sync
933     xcb_get_input_focus_cookie_t cookie = Q_XCB_CALL(xcb_get_input_focus(xcb_connection()));
934     free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
935 }
936
937 void QXcbConnection::initializeXFixes()
938 {
939     xcb_generic_error_t *error = 0;
940     const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id);
941     xfixes_first_event = reply->first_event;
942
943     xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
944                                                                                      XCB_XFIXES_MAJOR_VERSION,
945                                                                                      XCB_XFIXES_MINOR_VERSION);
946     xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection,
947                                                                                      xfixes_query_cookie, &error);
948     if (!xfixes_query || error || xfixes_query->major_version < 2) {
949         qWarning("Failed to initialize XFixes");
950         free(error);
951         xfixes_first_event = 0;
952     }
953     free(xfixes_query);
954
955 }
956
957 void QXcbConnection::initializeXRender()
958 {
959 #ifdef XCB_USE_RENDER
960     xcb_generic_error_t *error = 0;
961     xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection,
962                                                                                       XCB_RENDER_MAJOR_VERSION,
963                                                                                       XCB_RENDER_MINOR_VERSION);
964     xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection,
965                                                                                      xrender_query_cookie, &error);
966     if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) {
967         qWarning("Failed to initialize XRender");
968         free(error);
969     }
970     free(xrender_query);
971 #endif
972 }
973
974 #if defined(XCB_USE_EGL)
975 bool QXcbConnection::hasEgl() const
976 {
977     return m_has_egl;
978 }
979 #endif // defined(XCB_USE_EGL)
980
981 #ifdef XCB_USE_DRI2
982 void QXcbConnection::initializeDri2()
983 {
984     xcb_dri2_connect_cookie_t connect_cookie = xcb_dri2_connect_unchecked (m_connection,
985                                                                            m_screens[0]->root(),
986                                                                            XCB_DRI2_DRIVER_TYPE_DRI);
987
988     xcb_dri2_connect_reply_t *connect = xcb_dri2_connect_reply (m_connection,
989                                                                 connect_cookie, NULL);
990
991     if (! connect || connect->driver_name_length + connect->device_name_length == 0) {
992         qDebug() << "Failed to connect to dri2";
993         return;
994     }
995
996     m_dri2_device_name = QByteArray(xcb_dri2_connect_device_name (connect),
997                                                     xcb_dri2_connect_device_name_length (connect));
998     delete connect;
999
1000     int fd = open(m_dri2_device_name.constData(), O_RDWR);
1001     if (fd < 0) {
1002         qDebug() << "InitializeDri2: Could'nt open device << dri2DeviceName";
1003         m_dri2_device_name = QByteArray();
1004         return;
1005     }
1006
1007     drm_magic_t magic;
1008     if (drmGetMagic(fd, &magic)) {
1009         qDebug() << "Failed to get drmMagic";
1010         return;
1011     }
1012
1013     xcb_dri2_authenticate_cookie_t authenticate_cookie = xcb_dri2_authenticate_unchecked(m_connection,
1014                                                                                          m_screens[0]->root(), magic);
1015     xcb_dri2_authenticate_reply_t *authenticate = xcb_dri2_authenticate_reply(m_connection,
1016                                                                               authenticate_cookie, NULL);
1017     if (authenticate == NULL || !authenticate->authenticated) {
1018         fprintf(stderr, "DRI2: failed to authenticate\n");
1019         free(authenticate);
1020         return;
1021     }
1022
1023     delete authenticate;
1024
1025     EGLDisplay display = eglGetDRMDisplayMESA(fd);
1026     if (!display) {
1027         fprintf(stderr, "failed to create display\n");
1028         return;
1029     }
1030
1031     m_egl_display = display;
1032     EGLint major,minor;
1033     if (!eglInitialize(display, &major, &minor)) {
1034         fprintf(stderr, "failed to initialize display\n");
1035         return;
1036     }
1037 }
1038
1039 bool QXcbConnection::hasSupportForDri2() const
1040 {
1041     if (!m_dri2_support_probed) {
1042         xcb_generic_error_t *error = 0;
1043
1044         xcb_prefetch_extension_data (m_connection, &xcb_dri2_id);
1045
1046         xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection,
1047                                                                                     XCB_DRI2_MAJOR_VERSION,
1048                                                                                     XCB_DRI2_MINOR_VERSION);
1049
1050         xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection,
1051                                                                                    dri2_query_cookie, &error);
1052         if (!dri2_query || error) {
1053             delete error;
1054             delete dri2_query;
1055             return false;
1056         }
1057
1058         QXcbConnection *that = const_cast<QXcbConnection *>(this);
1059         that->m_dri2_major = dri2_query->major_version;
1060         that->m_dri2_minor = dri2_query->minor_version;
1061
1062         that->m_has_support_for_dri2 = true;
1063         that->m_dri2_support_probed = true;
1064     }
1065     return m_has_support_for_dri2;
1066 }
1067 #endif //XCB_USE_DRI2