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