Add PLUGIN_CLASS_NAME to qtbase plugins
[profile/ivi/qtbase.git] / src / plugins / platforms / xcb / qxcbconnection.cpp
1 /****************************************************************************
2 **
3 ** Copyright (C) 2012 Digia Plc and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/legal
5 **
6 ** This file is part of the plugins of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and Digia.  For licensing terms and
14 ** conditions see http://qt.digia.com/licensing.  For further information
15 ** use the contact form at http://qt.digia.com/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 2.1 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL included in the
21 ** packaging of this file.  Please review the following information to
22 ** ensure the GNU Lesser General Public License version 2.1 requirements
23 ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
24 **
25 ** In addition, as a special exception, Digia gives you certain additional
26 ** rights.  These rights are described in the Digia Qt LGPL Exception
27 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
28 **
29 ** GNU General Public License Usage
30 ** Alternatively, this file may be used under the terms of the GNU
31 ** General Public License version 3.0 as published by the Free Software
32 ** Foundation and appearing in the file LICENSE.GPL included in the
33 ** packaging of this file.  Please review the following information to
34 ** ensure the GNU General Public License version 3.0 requirements will be
35 ** met: http://www.gnu.org/copyleft/gpl.html.
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 #include "qxcbintegration.h"
54
55 #include <QtAlgorithms>
56 #include <QSocketNotifier>
57 #include <QAbstractEventDispatcher>
58 #include <QTimer>
59 #include <QByteArray>
60
61 #include <dlfcn.h>
62 #include <stdio.h>
63 #include <errno.h>
64 #include <xcb/shm.h>
65 #include <xcb/sync.h>
66 #include <xcb/xfixes.h>
67
68 #ifdef XCB_USE_XLIB
69 #include <X11/Xlib.h>
70 #include <X11/Xlib-xcb.h>
71 #include <X11/Xlibint.h>
72 #endif
73
74 #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO)
75 #include <X11/extensions/XInput2.h>
76 #include <X11/extensions/XI2proto.h>
77 #endif
78
79 #ifdef XCB_USE_RENDER
80 #include <xcb/render.h>
81 #endif
82
83 #if defined(XCB_HAS_XCB_GLX)
84 #include <xcb/glx.h>
85 #endif
86
87 #ifdef XCB_USE_EGL //don't pull in eglext prototypes
88 #include <EGL/egl.h>
89 #endif
90
91 QT_BEGIN_NAMESPACE
92
93 #ifdef XCB_USE_XLIB
94 static int nullErrorHandler(Display *, XErrorEvent *)
95 {
96     return 0;
97 }
98 #endif
99
100 QXcbScreen* QXcbConnection::findOrCreateScreen(QList<QXcbScreen *>& newScreens,
101     int screenNumber, xcb_screen_t* xcbScreen, xcb_randr_get_output_info_reply_t *output)
102 {
103     QString name;
104     if (output)
105         name = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
106                 xcb_randr_get_output_info_name_length(output));
107     else {
108         QByteArray displayName = m_displayName;
109         int dotPos = displayName.lastIndexOf('.');
110         if (dotPos != -1)
111             displayName.truncate(dotPos);
112         name = displayName + QLatin1Char('.') + QString::number(screenNumber);
113     }
114     foreach (QXcbScreen* scr, m_screens)
115         if (scr->name() == name && scr->root() == xcbScreen->root)
116             return scr;
117     QXcbScreen *ret = new QXcbScreen(this, xcbScreen, output, name, screenNumber);
118     newScreens << ret;
119     return ret;
120 }
121
122 /*!
123     \brief Synchronizes the screen list, adds new screens, removes deleted ones
124 */
125 void QXcbConnection::updateScreens()
126 {
127     xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
128     int screenNumber = 0;       // index of this QScreen in QGuiApplication::screens()
129     int xcbScreenNumber = 0;    // screen number in the xcb sense
130     QSet<QXcbScreen *> activeScreens;
131     QList<QXcbScreen *> newScreens;
132     QXcbScreen* primaryScreen = NULL;
133     while (it.rem) {
134         // Each "screen" in xcb terminology is a virtual desktop,
135         // potentially a collection of separate juxtaposed monitors.
136         // But we want a separate QScreen for each output (e.g. DVI-I-1, VGA-1, etc.)
137         // which will become virtual siblings.
138         xcb_screen_t *xcbScreen = it.data;
139         QList<QPlatformScreen *> siblings;
140         int outputCount = 0;
141         if (has_randr_extension) {
142             xcb_generic_error_t *error = NULL;
143             xcb_randr_get_output_primary_cookie_t primaryCookie =
144                 xcb_randr_get_output_primary(xcb_connection(), xcbScreen->root);
145             xcb_randr_get_screen_resources_current_cookie_t resourcesCookie =
146                 xcb_randr_get_screen_resources_current(xcb_connection(), xcbScreen->root);
147             xcb_randr_get_output_primary_reply_t *primary =
148                     xcb_randr_get_output_primary_reply(xcb_connection(), primaryCookie, &error);
149             if (!primary || error) {
150                 qWarning("QXcbConnection: Failed to get the primary output of the screen");
151                 free(error);
152             } else {
153                 xcb_randr_get_screen_resources_current_reply_t *resources =
154                         xcb_randr_get_screen_resources_current_reply(xcb_connection(), resourcesCookie, &error);
155                 if (!resources || error) {
156                     qWarning("QXcbConnection: Failed to get the screen resources");
157                     free(error);
158                 } else {
159                     xcb_timestamp_t timestamp = resources->config_timestamp;
160                     outputCount = xcb_randr_get_screen_resources_current_outputs_length(resources);
161                     xcb_randr_output_t *outputs = xcb_randr_get_screen_resources_current_outputs(resources);
162
163                     for (int i = 0; i < outputCount; i++) {
164                         xcb_randr_get_output_info_reply_t *output =
165                                 xcb_randr_get_output_info_reply(xcb_connection(),
166                                     xcb_randr_get_output_info_unchecked(xcb_connection(), outputs[i], timestamp), NULL);
167                         if (output == NULL)
168                             continue;
169
170 #ifdef Q_XCB_DEBUG
171                         QString outputName = QString::fromUtf8((const char*)xcb_randr_get_output_info_name(output),
172                                                                xcb_randr_get_output_info_name_length(output));
173 #endif
174
175                         if (output->crtc == XCB_NONE) {
176 #ifdef Q_XCB_DEBUG
177                             qDebug("Screen output %s is not connected", qPrintable(outputName));
178 #endif
179                             continue;
180                         }
181
182                         QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen, output);
183                         siblings << screen;
184                         activeScreens << screen;
185                         ++screenNumber;
186                         if (!primaryScreen && primary) {
187                             if (primary->output == XCB_NONE || outputs[i] == primary->output) {
188                                 primaryScreen = screen;
189                                 siblings.prepend(siblings.takeLast());
190 #ifdef Q_XCB_DEBUG
191                                 qDebug("Primary output is %d: %s", primary->output, qPrintable(outputName));
192 #endif
193                             }
194                         }
195                         free(output);
196                     }
197                 }
198                 free(resources);
199             }
200             free(primary);
201         }
202         // If there's no randr extension, or there was some error above, or the screen
203         // doesn't have outputs for some other reason (e.g. on VNC or ssh -X), just assume there is one screen.
204         if (outputCount == 0) {
205 #ifdef Q_XCB_DEBUG
206                 qDebug("Found a screen with zero outputs");
207 #endif
208             QXcbScreen *screen = findOrCreateScreen(newScreens, xcbScreenNumber, xcbScreen);
209             siblings << screen;
210             activeScreens << screen;
211             if (!primaryScreen)
212                 primaryScreen = screen;
213             ++screenNumber;
214         }
215         foreach (QPlatformScreen* s, siblings)
216             ((QXcbScreen*)s)->setVirtualSiblings(siblings);
217         xcb_screen_next(&it);
218         ++xcbScreenNumber;
219     } // for each xcb screen
220
221     // Now activeScreens is the complete set of screens which are active at this time.
222     // Delete any existing screens which are not in activeScreens
223     for (int i = m_screens.count() - 1; i >= 0; --i) {
224         if (!activeScreens.contains(m_screens[i])) {
225             ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->removeDefaultOpenGLContextInfo(m_screens[i]);
226             delete m_screens[i];
227             m_screens.removeAt(i);
228         }
229     }
230
231     // Add any new screens, and make sure the primary screen comes first
232     // since it is used by QGuiApplication::primaryScreen()
233     foreach (QXcbScreen* screen, newScreens) {
234         if (screen == primaryScreen)
235             m_screens.prepend(screen);
236         else
237             m_screens.append(screen);
238     }
239
240     // Now that they are in the right order, emit the added signals for new screens only
241     foreach (QXcbScreen* screen, m_screens)
242         if (newScreens.contains(screen))
243             ((QXcbIntegration*)QGuiApplicationPrivate::platformIntegration())->screenAdded(screen);
244 }
245
246 QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName)
247     : m_connection(0)
248     , m_primaryScreen(0)
249     , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
250     , m_nativeInterface(nativeInterface)
251 #ifdef XCB_USE_XINPUT2_MAEMO
252     , m_xinputData(0)
253 #endif
254     , xfixes_first_event(0)
255     , xrandr_first_event(0)
256     , has_glx_extension(false)
257     , has_shape_extension(false)
258     , has_randr_extension(false)
259     , has_input_shape(false)
260 {
261 #ifdef XCB_USE_XLIB
262     Display *dpy = XOpenDisplay(m_displayName.constData());
263     if (dpy) {
264         m_primaryScreen = DefaultScreen(dpy);
265         m_connection = XGetXCBConnection(dpy);
266         XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
267         XSetErrorHandler(nullErrorHandler);
268         m_xlib_display = dpy;
269 #ifdef XCB_USE_EGL
270         EGLDisplay eglDisplay = eglGetDisplay(dpy);
271         m_egl_display = eglDisplay;
272         EGLint major, minor;
273         eglBindAPI(EGL_OPENGL_ES_API);
274         m_has_egl = eglInitialize(eglDisplay,&major,&minor);
275 #endif //XCB_USE_EGL
276     }
277 #else
278     m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen);
279 #endif //XCB_USE_XLIB
280
281     if (!m_connection || xcb_connection_has_error(m_connection))
282         qFatal("QXcbConnection: Could not connect to display %s", m_displayName.constData());
283
284     m_reader = new QXcbEventReader(this);
285     connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection);
286     connect(m_reader, SIGNAL(finished()), this, SLOT(processXcbEvents()));
287     if (!m_reader->startThread()) {
288         QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this);
289         connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents()));
290
291         QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
292         connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents()));
293         connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents()));
294     }
295
296     xcb_extension_t *extensions[] = {
297         &xcb_shm_id, &xcb_xfixes_id, &xcb_randr_id, &xcb_shape_id, &xcb_sync_id,
298 #ifdef XCB_USE_RENDER
299         &xcb_render_id,
300 #endif
301 #ifdef XCB_HAS_XCB_GLX
302         &xcb_glx_id,
303 #endif
304         0
305     };
306
307     for (xcb_extension_t **ext_it = extensions; *ext_it; ++ext_it)
308         xcb_prefetch_extension_data (m_connection, *ext_it);
309
310     m_setup = xcb_get_setup(xcb_connection());
311
312     initializeAllAtoms();
313
314     m_time = XCB_CURRENT_TIME;
315
316     initializeXRandr();
317     updateScreens();
318
319     m_connectionEventListener = xcb_generate_id(m_connection);
320     xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
321                       m_connectionEventListener, m_screens.at(0)->root(),
322                       0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
323                       m_screens.at(0)->screen()->root_visual, 0, 0);
324
325     initializeGLX();
326     initializeXFixes();
327     initializeXRender();
328     m_xi2Enabled = false;
329 #ifdef XCB_USE_XINPUT2_MAEMO
330     initializeXInput2Maemo();
331 #elif defined(XCB_USE_XINPUT2)
332     initializeXInput2();
333 #endif
334     initializeXShape();
335
336     m_wmSupport.reset(new QXcbWMSupport(this));
337     m_keyboard = new QXcbKeyboard(this);
338 #ifndef QT_NO_CLIPBOARD
339     m_clipboard = new QXcbClipboard(this);
340 #endif
341 #ifndef QT_NO_DRAGANDDROP
342     m_drag = new QXcbDrag(this);
343 #endif
344
345     sync();
346 }
347
348 QXcbConnection::~QXcbConnection()
349 {
350 #ifndef QT_NO_CLIPBOARD
351     delete m_clipboard;
352 #endif
353 #ifndef QT_NO_DRAGANDDROP
354     delete m_drag;
355 #endif
356     // Delete screens in reverse order to avoid crash in case of multiple screens
357     while (!m_screens.isEmpty())
358         delete m_screens.takeLast();
359
360 #ifdef XCB_USE_XINPUT2_MAEMO
361     finalizeXInput2Maemo();
362 #elif defined(XCB_USE_XINPUT2)
363     finalizeXInput2();
364 #endif
365
366     if (m_reader->isRunning()) {
367         sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION);
368         m_reader->wait();
369     }
370
371     delete m_reader;
372
373 #ifdef XCB_USE_EGL
374     if (m_has_egl)
375         eglTerminate(m_egl_display);
376 #endif //XCB_USE_EGL
377
378 #ifdef XCB_USE_XLIB
379     XCloseDisplay((Display *)m_xlib_display);
380 #else
381     xcb_disconnect(xcb_connection());
382 #endif
383
384     delete m_keyboard;
385 }
386
387 void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window)
388 {
389     m_mapper.insert(id, window);
390 }
391
392 void QXcbConnection::removeWindow(xcb_window_t id)
393 {
394     m_mapper.remove(id);
395 }
396
397 QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
398 {
399     return m_mapper.value(id, 0);
400 }
401
402 #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
403 { \
404     event_t *e = (event_t *)event; \
405     if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember))  { \
406         handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
407         if (!handled) \
408             platformWindow->handler(e); \
409     } \
410 } \
411 break;
412
413 #define HANDLE_KEYBOARD_EVENT(event_t, handler) \
414 { \
415     event_t *e = (event_t *)event; \
416     if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \
417         handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
418         if (!handled) \
419             m_keyboard->handler(platformWindow, e); \
420     } \
421 } \
422 break;
423
424 //#define XCB_EVENT_DEBUG
425
426 void printXcbEvent(const char *message, xcb_generic_event_t *event)
427 {
428 #ifdef XCB_EVENT_DEBUG
429 #define PRINT_XCB_EVENT(ev) \
430     case ev: \
431         qDebug("QXcbConnection: %s: %d - %s - sequence: %d", message, int(ev), #ev, event->sequence); \
432         break;
433
434     switch (event->response_type & ~0x80) {
435     PRINT_XCB_EVENT(XCB_KEY_PRESS);
436     PRINT_XCB_EVENT(XCB_KEY_RELEASE);
437     PRINT_XCB_EVENT(XCB_BUTTON_PRESS);
438     PRINT_XCB_EVENT(XCB_BUTTON_RELEASE);
439     PRINT_XCB_EVENT(XCB_MOTION_NOTIFY);
440     PRINT_XCB_EVENT(XCB_ENTER_NOTIFY);
441     PRINT_XCB_EVENT(XCB_LEAVE_NOTIFY);
442     PRINT_XCB_EVENT(XCB_FOCUS_IN);
443     PRINT_XCB_EVENT(XCB_FOCUS_OUT);
444     PRINT_XCB_EVENT(XCB_KEYMAP_NOTIFY);
445     PRINT_XCB_EVENT(XCB_EXPOSE);
446     PRINT_XCB_EVENT(XCB_GRAPHICS_EXPOSURE);
447     PRINT_XCB_EVENT(XCB_VISIBILITY_NOTIFY);
448     PRINT_XCB_EVENT(XCB_CREATE_NOTIFY);
449     PRINT_XCB_EVENT(XCB_DESTROY_NOTIFY);
450     PRINT_XCB_EVENT(XCB_UNMAP_NOTIFY);
451     PRINT_XCB_EVENT(XCB_MAP_NOTIFY);
452     PRINT_XCB_EVENT(XCB_MAP_REQUEST);
453     PRINT_XCB_EVENT(XCB_REPARENT_NOTIFY);
454     PRINT_XCB_EVENT(XCB_CONFIGURE_NOTIFY);
455     PRINT_XCB_EVENT(XCB_CONFIGURE_REQUEST);
456     PRINT_XCB_EVENT(XCB_GRAVITY_NOTIFY);
457     PRINT_XCB_EVENT(XCB_RESIZE_REQUEST);
458     PRINT_XCB_EVENT(XCB_CIRCULATE_NOTIFY);
459     PRINT_XCB_EVENT(XCB_CIRCULATE_REQUEST);
460     PRINT_XCB_EVENT(XCB_PROPERTY_NOTIFY);
461     PRINT_XCB_EVENT(XCB_SELECTION_CLEAR);
462     PRINT_XCB_EVENT(XCB_SELECTION_REQUEST);
463     PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY);
464     PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY);
465     PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE);
466     PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY);
467     default:
468         qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence));
469     }
470 #else
471     Q_UNUSED(message);
472     Q_UNUSED(event);
473 #endif
474 }
475
476 const char *xcb_errors[] =
477 {
478     "Success",
479     "BadRequest",
480     "BadValue",
481     "BadWindow",
482     "BadPixmap",
483     "BadAtom",
484     "BadCursor",
485     "BadFont",
486     "BadMatch",
487     "BadDrawable",
488     "BadAccess",
489     "BadAlloc",
490     "BadColor",
491     "BadGC",
492     "BadIDChoice",
493     "BadName",
494     "BadLength",
495     "BadImplementation",
496     "Unknown"
497 };
498
499 const char *xcb_protocol_request_codes[] =
500 {
501     "Null",
502     "CreateWindow",
503     "ChangeWindowAttributes",
504     "GetWindowAttributes",
505     "DestroyWindow",
506     "DestroySubwindows",
507     "ChangeSaveSet",
508     "ReparentWindow",
509     "MapWindow",
510     "MapSubwindows",
511     "UnmapWindow",
512     "UnmapSubwindows",
513     "ConfigureWindow",
514     "CirculateWindow",
515     "GetGeometry",
516     "QueryTree",
517     "InternAtom",
518     "GetAtomName",
519     "ChangeProperty",
520     "DeleteProperty",
521     "GetProperty",
522     "ListProperties",
523     "SetSelectionOwner",
524     "GetSelectionOwner",
525     "ConvertSelection",
526     "SendEvent",
527     "GrabPointer",
528     "UngrabPointer",
529     "GrabButton",
530     "UngrabButton",
531     "ChangeActivePointerGrab",
532     "GrabKeyboard",
533     "UngrabKeyboard",
534     "GrabKey",
535     "UngrabKey",
536     "AllowEvents",
537     "GrabServer",
538     "UngrabServer",
539     "QueryPointer",
540     "GetMotionEvents",
541     "TranslateCoords",
542     "WarpPointer",
543     "SetInputFocus",
544     "GetInputFocus",
545     "QueryKeymap",
546     "OpenFont",
547     "CloseFont",
548     "QueryFont",
549     "QueryTextExtents",
550     "ListFonts",
551     "ListFontsWithInfo",
552     "SetFontPath",
553     "GetFontPath",
554     "CreatePixmap",
555     "FreePixmap",
556     "CreateGC",
557     "ChangeGC",
558     "CopyGC",
559     "SetDashes",
560     "SetClipRectangles",
561     "FreeGC",
562     "ClearArea",
563     "CopyArea",
564     "CopyPlane",
565     "PolyPoint",
566     "PolyLine",
567     "PolySegment",
568     "PolyRectangle",
569     "PolyArc",
570     "FillPoly",
571     "PolyFillRectangle",
572     "PolyFillArc",
573     "PutImage",
574     "GetImage",
575     "PolyText8",
576     "PolyText16",
577     "ImageText8",
578     "ImageText16",
579     "CreateColormap",
580     "FreeColormap",
581     "CopyColormapAndFree",
582     "InstallColormap",
583     "UninstallColormap",
584     "ListInstalledColormaps",
585     "AllocColor",
586     "AllocNamedColor",
587     "AllocColorCells",
588     "AllocColorPlanes",
589     "FreeColors",
590     "StoreColors",
591     "StoreNamedColor",
592     "QueryColors",
593     "LookupColor",
594     "CreateCursor",
595     "CreateGlyphCursor",
596     "FreeCursor",
597     "RecolorCursor",
598     "QueryBestSize",
599     "QueryExtension",
600     "ListExtensions",
601     "ChangeKeyboardMapping",
602     "GetKeyboardMapping",
603     "ChangeKeyboardControl",
604     "GetKeyboardControl",
605     "Bell",
606     "ChangePointerControl",
607     "GetPointerControl",
608     "SetScreenSaver",
609     "GetScreenSaver",
610     "ChangeHosts",
611     "ListHosts",
612     "SetAccessControl",
613     "SetCloseDownMode",
614     "KillClient",
615     "RotateProperties",
616     "ForceScreenSaver",
617     "SetPointerMapping",
618     "GetPointerMapping",
619     "SetModifierMapping",
620     "GetModifierMapping",
621     "Unknown"
622 };
623
624 #ifdef Q_XCB_DEBUG
625 void QXcbConnection::log(const char *file, int line, int sequence)
626 {
627     QMutexLocker locker(&m_callLogMutex);
628     CallInfo info;
629     info.sequence = sequence;
630     info.file = file;
631     info.line = line;
632     m_callLog << info;
633 }
634 #endif
635
636 void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
637 {
638     uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
639     uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
640
641     qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
642            int(error->error_code), xcb_errors[clamped_error_code],
643            int(error->sequence), int(error->resource_id),
644            int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
645            int(error->minor_code));
646 #ifdef Q_XCB_DEBUG
647     QMutexLocker locker(&m_callLogMutex);
648     int i = 0;
649     for (; i < m_callLog.size(); ++i) {
650         if (m_callLog.at(i).sequence == error->sequence) {
651             qDebug("Caused by: %s:%d", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
652             break;
653         } else if (m_callLog.at(i).sequence > error->sequence) {
654             qDebug("Caused some time before: %s:%d", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
655             if (i > 0)
656                 qDebug("and after: %s:%d", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
657             break;
658         }
659     }
660     if (i == m_callLog.size() && !m_callLog.isEmpty())
661         qDebug("Caused some time after: %s:%d", qPrintable(m_callLog.first().file), m_callLog.first().line);
662 #endif
663 }
664
665 void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
666 {
667 #ifdef Q_XCB_DEBUG
668     {
669         QMutexLocker locker(&m_callLogMutex);
670         int i = 0;
671         for (; i < m_callLog.size(); ++i)
672             if (m_callLog.at(i).sequence >= event->sequence)
673                 break;
674         m_callLog.remove(0, i);
675     }
676 #endif
677
678     long result = 0;
679     QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance();
680     bool handled = dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), event, &result);
681
682     uint response_type = event->response_type & ~0x80;
683
684     if (!handled) {
685         switch (response_type) {
686         case XCB_EXPOSE:
687             HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
688         case XCB_BUTTON_PRESS:
689             HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
690         case XCB_BUTTON_RELEASE:
691             HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
692         case XCB_MOTION_NOTIFY:
693             HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
694         case XCB_CONFIGURE_NOTIFY:
695             HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
696         case XCB_MAP_NOTIFY:
697             HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
698         case XCB_UNMAP_NOTIFY:
699             HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
700         case XCB_CLIENT_MESSAGE:
701             handleClientMessageEvent((xcb_client_message_event_t *)event);
702         case XCB_ENTER_NOTIFY:
703             HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
704         case XCB_LEAVE_NOTIFY:
705             HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
706         case XCB_FOCUS_IN:
707             HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
708         case XCB_FOCUS_OUT:
709             HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
710         case XCB_KEY_PRESS:
711             HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
712         case XCB_KEY_RELEASE:
713             HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
714         case XCB_MAPPING_NOTIFY:
715             m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
716             break;
717         case XCB_SELECTION_REQUEST:
718         {
719             xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
720 #ifndef QT_NO_DRAGANDDROP
721             if (sr->selection == atom(QXcbAtom::XdndSelection))
722                 m_drag->handleSelectionRequest(sr);
723             else
724 #endif
725             {
726 #ifndef QT_NO_CLIPBOARD
727                 m_clipboard->handleSelectionRequest(sr);
728 #endif
729             }
730             break;
731         }
732         case XCB_SELECTION_CLEAR:
733             setTime(((xcb_selection_clear_event_t *)event)->time);
734 #ifndef QT_NO_CLIPBOARD
735             m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event);
736 #endif
737             handled = true;
738             break;
739         case XCB_SELECTION_NOTIFY:
740             setTime(((xcb_selection_notify_event_t *)event)->time);
741             handled = false;
742             break;
743         case XCB_PROPERTY_NOTIFY:
744             HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
745             break;
746 #ifdef XCB_USE_XINPUT2_MAEMO
747         case GenericEvent:
748             handleGenericEventMaemo((xcb_ge_event_t*)event);
749             break;
750 #elif defined(XCB_USE_XINPUT2)
751         case GenericEvent:
752             if (m_xi2Enabled)
753                 xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event));
754             break;
755 #endif
756         default:
757             handled = false;
758             break;
759         }
760     }
761
762     if (!handled) {
763         if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
764             setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp);
765 #ifndef QT_NO_CLIPBOARD
766             m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
767 #endif
768             handled = true;
769         } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
770             updateScreens();
771             xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event;
772             foreach (QXcbScreen *s, m_screens) {
773                 if (s->root() == change_event->root ) {
774                     s->handleScreenChange(change_event);
775                     s->updateRefreshRate();
776                 }
777             }
778             handled = true;
779         }
780     }
781
782 #ifdef XCB_USE_XLIB
783     if (!handled) {
784         // Check if a custom XEvent constructor was registered in xlib for this event type, and call it discarding the constructed XEvent if any.
785         // XESetWireToEvent might be used by libraries to intercept messages from the X server e.g. the OpenGL lib waiting for DRI2 events.
786
787         Display *xdisplay = (Display *)m_xlib_display;
788         XLockDisplay(xdisplay);
789         Bool (*proc)(Display*, XEvent*, xEvent*) = XESetWireToEvent(xdisplay, response_type, 0);
790         if (proc) {
791             XESetWireToEvent(xdisplay, response_type, proc);
792             XEvent dummy;
793             event->sequence = LastKnownRequestProcessed(m_xlib_display);
794             proc(xdisplay, &dummy, (xEvent*)event);
795         }
796         XUnlockDisplay(xdisplay);
797     }
798 #endif
799
800     if (handled)
801         printXcbEvent("Handled XCB event", event);
802     else
803         printXcbEvent("Unhandled XCB event", event);
804 }
805
806 void QXcbConnection::addPeekFunc(PeekFunc f)
807 {
808     m_peekFuncs.append(f);
809 }
810
811 QXcbEventReader::QXcbEventReader(QXcbConnection *connection)
812     : m_connection(connection)
813     , m_xcb_poll_for_queued_event(0)
814 {
815 #ifdef RTLD_DEFAULT
816     m_xcb_poll_for_queued_event = (XcbPollForQueuedEventFunctionPointer)dlsym(RTLD_DEFAULT, "xcb_poll_for_queued_event");
817 #endif
818
819 #ifdef Q_XCB_DEBUG
820     if (m_xcb_poll_for_queued_event)
821         qDebug("Using threaded event reader with xcb_poll_for_queued_event");
822 #endif
823 }
824
825 bool QXcbEventReader::startThread()
826 {
827     if (m_xcb_poll_for_queued_event) {
828         QThread::start();
829         return true;
830     }
831
832     return false;
833 }
834
835 void QXcbEventReader::run()
836 {
837     xcb_generic_event_t *event;
838     while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) {
839         m_mutex.lock();
840         addEvent(event);
841         while (m_connection && (event = m_xcb_poll_for_queued_event(m_connection->xcb_connection())))
842             addEvent(event);
843         m_mutex.unlock();
844         emit eventPending();
845     }
846
847     for (int i = 0; i < m_events.size(); ++i)
848         free(m_events.at(i));
849 }
850
851 void QXcbEventReader::addEvent(xcb_generic_event_t *event)
852 {
853     if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
854         && ((xcb_client_message_event_t *)event)->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
855         m_connection = 0;
856     m_events << event;
857 }
858
859 QXcbEventArray *QXcbEventReader::lock()
860 {
861     m_mutex.lock();
862     if (!m_xcb_poll_for_queued_event) {
863         while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection()))
864             m_events << event;
865     }
866     return &m_events;
867 }
868
869 void QXcbEventReader::unlock()
870 {
871     m_mutex.unlock();
872 }
873
874 void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
875 {
876     xcb_client_message_event_t event;
877     memset(&event, 0, sizeof(event));
878
879     event.response_type = XCB_CLIENT_MESSAGE;
880     event.format = 32;
881     event.sequence = 0;
882     event.window = m_connectionEventListener;
883     event.type = atom(a);
884     event.data.data32[0] = id;
885
886     Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
887     xcb_flush(xcb_connection());
888 }
889
890 namespace
891 {
892     class PropertyNotifyEvent {
893     public:
894         PropertyNotifyEvent(xcb_window_t win, xcb_atom_t property)
895             : window(win), type(XCB_PROPERTY_NOTIFY), atom(property) {}
896         xcb_window_t window;
897         int type;
898         xcb_atom_t atom;
899         bool checkEvent(xcb_generic_event_t *event) const {
900             if (!event)
901                 return false;
902             if ((event->response_type & ~0x80) != type) {
903                 return false;
904             } else {
905                 xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
906                 if ((pn->window == window) && (pn->atom == atom))
907                     return true;
908             }
909             return false;
910         }
911     };
912 }
913
914 xcb_timestamp_t QXcbConnection::getTimestamp()
915 {
916     // send a dummy event to myself to get the timestamp from X server.
917     xcb_window_t rootWindow = screens().at(primaryScreen())->root();
918     xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, rootWindow, atom(QXcbAtom::CLIP_TEMPORARY),
919                         XCB_ATOM_INTEGER, 32, 0, NULL);
920
921     connection()->flush();
922     PropertyNotifyEvent checker(rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
923
924     xcb_generic_event_t *event = 0;
925     // lets keep this inside a loop to avoid a possible race condition, where
926     // reader thread has not yet had the time to acquire the mutex in order
927     // to add the new set of events to its event queue
928     while (true) {
929         connection()->sync();
930         if ((event = checkEvent(checker)))
931             break;
932     }
933
934     xcb_property_notify_event_t *pn = (xcb_property_notify_event_t *)event;
935     xcb_timestamp_t timestamp = pn->time;
936     free(event);
937
938     xcb_delete_property(xcb_connection(), rootWindow, atom(QXcbAtom::CLIP_TEMPORARY));
939
940     return timestamp;
941 }
942
943 void QXcbConnection::processXcbEvents()
944 {
945     int connection_error = xcb_connection_has_error(xcb_connection());
946     if (connection_error) {
947         qWarning("The X11 connection broke (error %d). Did the X11 server die?", connection_error);
948         exit(1);
949     }
950
951     QXcbEventArray *eventqueue = m_reader->lock();
952
953     for(int i = 0; i < eventqueue->size(); ++i) {
954         xcb_generic_event_t *event = eventqueue->at(i);
955         if (!event)
956             continue;
957         (*eventqueue)[i] = 0;
958
959         uint response_type = event->response_type & ~0x80;
960
961         if (!response_type) {
962             handleXcbError((xcb_generic_error_t *)event);
963         } else {
964             if (response_type == XCB_MOTION_NOTIFY) {
965                 // compress multiple motion notify events in a row
966                 // to avoid swamping the event queue
967                 xcb_generic_event_t *next = eventqueue->value(i+1, 0);
968                 if (next && (next->response_type & ~0x80) == XCB_MOTION_NOTIFY)
969                     continue;
970             }
971
972             if (response_type == XCB_CONFIGURE_NOTIFY) {
973                 // compress multiple configure notify events for the same window
974                 bool found = false;
975                 for (int j = i; j < eventqueue->size(); ++j) {
976                     xcb_generic_event_t *other = eventqueue->at(j);
977                     if (other && (other->response_type & ~0x80) == XCB_CONFIGURE_NOTIFY
978                         && ((xcb_configure_notify_event_t *)other)->event == ((xcb_configure_notify_event_t *)event)->event)
979                     {
980                         found = true;
981                         break;
982                     }
983                 }
984                 if (found)
985                     continue;
986             }
987
988             QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
989             while (it != m_peekFuncs.end()) {
990                 // These callbacks return true if the event is what they were
991                 // waiting for, remove them from the list in that case.
992                 if ((*it)(event))
993                     it = m_peekFuncs.erase(it);
994                 else
995                     ++it;
996             }
997             m_reader->unlock();
998             handleXcbEvent(event);
999             m_reader->lock();
1000         }
1001
1002         free(event);
1003     }
1004
1005     eventqueue->clear();
1006
1007     m_reader->unlock();
1008
1009     // Indicate with a null event that the event the callbacks are waiting for
1010     // is not in the queue currently.
1011     Q_FOREACH (PeekFunc f, m_peekFuncs)
1012         f(0);
1013     m_peekFuncs.clear();
1014
1015     xcb_flush(xcb_connection());
1016 }
1017
1018 void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event)
1019 {
1020     if (event->format != 32)
1021         return;
1022
1023 #ifndef QT_NO_DRAGANDDROP
1024     if (event->type == atom(QXcbAtom::XdndStatus)) {
1025         drag()->handleStatus(event);
1026     } else if (event->type == atom(QXcbAtom::XdndFinished)) {
1027         drag()->handleFinished(event);
1028     }
1029 #endif
1030
1031     QXcbWindow *window = platformWindowFromId(event->window);
1032     if (!window)
1033         return;
1034
1035     window->handleClientMessageEvent(event);
1036 }
1037
1038 xcb_generic_event_t *QXcbConnection::checkEvent(int type)
1039 {
1040     QXcbEventArray *eventqueue = m_reader->lock();
1041
1042     for (int i = 0; i < eventqueue->size(); ++i) {
1043         xcb_generic_event_t *event = eventqueue->at(i);
1044         if (event && event->response_type == type) {
1045             (*eventqueue)[i] = 0;
1046             m_reader->unlock();
1047             return event;
1048         }
1049     }
1050
1051     m_reader->unlock();
1052
1053     return 0;
1054 }
1055
1056 static const char * xcb_atomnames = {
1057     // window-manager <-> client protocols
1058     "WM_PROTOCOLS\0"
1059     "WM_DELETE_WINDOW\0"
1060     "WM_TAKE_FOCUS\0"
1061     "_NET_WM_PING\0"
1062     "_NET_WM_CONTEXT_HELP\0"
1063     "_NET_WM_SYNC_REQUEST\0"
1064     "_NET_WM_SYNC_REQUEST_COUNTER\0"
1065
1066     // ICCCM window state
1067     "WM_STATE\0"
1068     "WM_CHANGE_STATE\0"
1069
1070     // Session management
1071     "WM_CLIENT_LEADER\0"
1072     "WM_WINDOW_ROLE\0"
1073     "SM_CLIENT_ID\0"
1074
1075     // Clipboard
1076     "CLIPBOARD\0"
1077     "INCR\0"
1078     "TARGETS\0"
1079     "MULTIPLE\0"
1080     "TIMESTAMP\0"
1081     "SAVE_TARGETS\0"
1082     "CLIP_TEMPORARY\0"
1083     "_QT_SELECTION\0"
1084     "_QT_CLIPBOARD_SENTINEL\0"
1085     "_QT_SELECTION_SENTINEL\0"
1086     "CLIPBOARD_MANAGER\0"
1087
1088     "RESOURCE_MANAGER\0"
1089
1090     "_XSETROOT_ID\0"
1091
1092     "_QT_SCROLL_DONE\0"
1093     "_QT_INPUT_ENCODING\0"
1094
1095     "_QT_CLOSE_CONNECTION\0"
1096
1097     "_MOTIF_WM_HINTS\0"
1098
1099     "DTWM_IS_RUNNING\0"
1100     "ENLIGHTENMENT_DESKTOP\0"
1101     "_DT_SAVE_MODE\0"
1102     "_SGI_DESKS_MANAGER\0"
1103
1104     // EWMH (aka NETWM)
1105     "_NET_SUPPORTED\0"
1106     "_NET_VIRTUAL_ROOTS\0"
1107     "_NET_WORKAREA\0"
1108
1109     "_NET_MOVERESIZE_WINDOW\0"
1110     "_NET_WM_MOVERESIZE\0"
1111
1112     "_NET_WM_NAME\0"
1113     "_NET_WM_ICON_NAME\0"
1114     "_NET_WM_ICON\0"
1115
1116     "_NET_WM_PID\0"
1117
1118     "_NET_WM_WINDOW_OPACITY\0"
1119
1120     "_NET_WM_STATE\0"
1121     "_NET_WM_STATE_ABOVE\0"
1122     "_NET_WM_STATE_BELOW\0"
1123     "_NET_WM_STATE_FULLSCREEN\0"
1124     "_NET_WM_STATE_MAXIMIZED_HORZ\0"
1125     "_NET_WM_STATE_MAXIMIZED_VERT\0"
1126     "_NET_WM_STATE_MODAL\0"
1127     "_NET_WM_STATE_STAYS_ON_TOP\0"
1128     "_NET_WM_STATE_DEMANDS_ATTENTION\0"
1129
1130     "_NET_WM_USER_TIME\0"
1131     "_NET_WM_USER_TIME_WINDOW\0"
1132     "_NET_WM_FULL_PLACEMENT\0"
1133
1134     "_NET_WM_WINDOW_TYPE\0"
1135     "_NET_WM_WINDOW_TYPE_DESKTOP\0"
1136     "_NET_WM_WINDOW_TYPE_DOCK\0"
1137     "_NET_WM_WINDOW_TYPE_TOOLBAR\0"
1138     "_NET_WM_WINDOW_TYPE_MENU\0"
1139     "_NET_WM_WINDOW_TYPE_UTILITY\0"
1140     "_NET_WM_WINDOW_TYPE_SPLASH\0"
1141     "_NET_WM_WINDOW_TYPE_DIALOG\0"
1142     "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
1143     "_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
1144     "_NET_WM_WINDOW_TYPE_TOOLTIP\0"
1145     "_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
1146     "_NET_WM_WINDOW_TYPE_COMBO\0"
1147     "_NET_WM_WINDOW_TYPE_DND\0"
1148     "_NET_WM_WINDOW_TYPE_NORMAL\0"
1149     "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
1150
1151     "_KDE_NET_WM_FRAME_STRUT\0"
1152
1153     "_NET_STARTUP_INFO\0"
1154     "_NET_STARTUP_INFO_BEGIN\0"
1155
1156     "_NET_SUPPORTING_WM_CHECK\0"
1157
1158     "_NET_WM_CM_S0\0"
1159
1160     "_NET_SYSTEM_TRAY_VISUAL\0"
1161
1162     "_NET_ACTIVE_WINDOW\0"
1163
1164     // Property formats
1165     "TEXT\0"
1166     "UTF8_STRING\0"
1167     "CARDINAL\0"
1168
1169     // xdnd
1170     "XdndEnter\0"
1171     "XdndPosition\0"
1172     "XdndStatus\0"
1173     "XdndLeave\0"
1174     "XdndDrop\0"
1175     "XdndFinished\0"
1176     "XdndTypeList\0"
1177     "XdndActionList\0"
1178
1179     "XdndSelection\0"
1180
1181     "XdndAware\0"
1182     "XdndProxy\0"
1183
1184     "XdndActionCopy\0"
1185     "XdndActionLink\0"
1186     "XdndActionMove\0"
1187     "XdndActionPrivate\0"
1188
1189     // Motif DND
1190     "_MOTIF_DRAG_AND_DROP_MESSAGE\0"
1191     "_MOTIF_DRAG_INITIATOR_INFO\0"
1192     "_MOTIF_DRAG_RECEIVER_INFO\0"
1193     "_MOTIF_DRAG_WINDOW\0"
1194     "_MOTIF_DRAG_TARGETS\0"
1195
1196     "XmTRANSFER_SUCCESS\0"
1197     "XmTRANSFER_FAILURE\0"
1198
1199     // Xkb
1200     "_XKB_RULES_NAMES\0"
1201
1202     // XEMBED
1203     "_XEMBED\0"
1204     "_XEMBED_INFO\0"
1205
1206     // XInput2
1207     "Button Left\0"
1208     "Button Middle\0"
1209     "Button Right\0"
1210     "Button Wheel Up\0"
1211     "Button Wheel Down\0"
1212     "Button Horiz Wheel Left\0"
1213     "Button Horiz Wheel Right\0"
1214     "Abs MT Position X\0"
1215     "Abs MT Position Y\0"
1216     "Abs MT Touch Major\0"
1217     "Abs MT Touch Minor\0"
1218     "Abs MT Pressure\0"
1219     "Abs MT Tracking ID\0"
1220     "Max Contacts\0"
1221     // XInput2 tablet
1222     "Abs X\0"
1223     "Abs Y\0"
1224     "Abs Pressure\0"
1225     "Abs Tilt X\0"
1226     "Abs Tilt Y\0"
1227     "Abs Wheel\0"
1228     "Abs Distance\0"
1229     "Wacom Serial IDs\0"
1230     "INTEGER\0"
1231 #if XCB_USE_MAEMO_WINDOW_PROPERTIES
1232     "_MEEGOTOUCH_ORIENTATION_ANGLE\0"
1233 #endif
1234 };
1235
1236 xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom)
1237 {
1238     return m_allAtoms[atom];
1239 }
1240
1241 void QXcbConnection::initializeAllAtoms() {
1242     const char *names[QXcbAtom::NAtoms];
1243     const char *ptr = xcb_atomnames;
1244
1245     int i = 0;
1246     while (*ptr) {
1247         names[i++] = ptr;
1248         while (*ptr)
1249             ++ptr;
1250         ++ptr;
1251     }
1252
1253     Q_ASSERT(i == QXcbAtom::NPredefinedAtoms);
1254
1255     QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
1256     settings_atom_name += m_displayName;
1257     names[i++] = settings_atom_name;
1258
1259     xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
1260
1261     Q_ASSERT(i == QXcbAtom::NAtoms);
1262     for (i = 0; i < QXcbAtom::NAtoms; ++i)
1263         cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]);
1264
1265     for (i = 0; i < QXcbAtom::NAtoms; ++i) {
1266         xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0);
1267         m_allAtoms[i] = reply->atom;
1268         free(reply);
1269     }
1270 }
1271
1272 xcb_atom_t QXcbConnection::internAtom(const char *name)
1273 {
1274     if (!name || *name == 0)
1275         return XCB_NONE;
1276
1277     xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name);
1278     xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0);
1279     int atom = reply->atom;
1280     free(reply);
1281     return atom;
1282 }
1283
1284 QByteArray QXcbConnection::atomName(xcb_atom_t atom)
1285 {
1286     if (!atom)
1287         return QByteArray();
1288
1289     xcb_generic_error_t *error = 0;
1290     xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom));
1291     xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error);
1292     if (error) {
1293         qWarning() << "QXcbConnection::atomName: bad Atom" << atom;
1294         free(error);
1295     }
1296     if (reply) {
1297         QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
1298         free(reply);
1299         return result;
1300     }
1301     return QByteArray();
1302 }
1303
1304 const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
1305 {
1306     xcb_format_iterator_t iterator =
1307         xcb_setup_pixmap_formats_iterator(m_setup);
1308
1309     while (iterator.rem) {
1310         xcb_format_t *format = iterator.data;
1311         if (format->depth == depth)
1312             return format;
1313         xcb_format_next(&iterator);
1314     }
1315
1316     return 0;
1317 }
1318
1319 void QXcbConnection::sync()
1320 {
1321     // from xcb_aux_sync
1322     xcb_get_input_focus_cookie_t cookie = Q_XCB_CALL(xcb_get_input_focus(xcb_connection()));
1323     free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
1324 }
1325
1326 void QXcbConnection::initializeXFixes()
1327 {
1328     xcb_generic_error_t *error = 0;
1329     const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id);
1330     if (!reply || !reply->present)
1331         return;
1332
1333     xfixes_first_event = reply->first_event;
1334     xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
1335                                                                                      XCB_XFIXES_MAJOR_VERSION,
1336                                                                                      XCB_XFIXES_MINOR_VERSION);
1337     xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection,
1338                                                                                      xfixes_query_cookie, &error);
1339     if (!xfixes_query || error || xfixes_query->major_version < 2) {
1340         qWarning("QXcbConnection: Failed to initialize XFixes");
1341         free(error);
1342         xfixes_first_event = 0;
1343     }
1344     free(xfixes_query);
1345 }
1346
1347 void QXcbConnection::initializeXRender()
1348 {
1349 #ifdef XCB_USE_RENDER
1350     const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_render_id);
1351     if (!reply || !reply->present)
1352         return;
1353
1354     xcb_generic_error_t *error = 0;
1355     xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection,
1356                                                                                       XCB_RENDER_MAJOR_VERSION,
1357                                                                                       XCB_RENDER_MINOR_VERSION);
1358     xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection,
1359                                                                                      xrender_query_cookie, &error);
1360     if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) {
1361         qWarning("QXcbConnection: Failed to initialize XRender");
1362         free(error);
1363     }
1364     free(xrender_query);
1365 #endif
1366 }
1367
1368 void QXcbConnection::initializeGLX()
1369 {
1370 #ifdef XCB_HAS_XCB_GLX
1371     const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_glx_id);
1372     if (!reply || !reply->present)
1373         return;
1374
1375     has_glx_extension = true;
1376
1377     xcb_generic_error_t *error = 0;
1378     xcb_glx_query_version_cookie_t xglx_query_cookie = xcb_glx_query_version(m_connection,
1379                                                                              XCB_GLX_MAJOR_VERSION,
1380                                                                              XCB_GLX_MINOR_VERSION);
1381     xcb_glx_query_version_reply_t *xglx_query = xcb_glx_query_version_reply(m_connection,
1382                                                                             xglx_query_cookie, &error);
1383     if (!xglx_query || error) {
1384         qWarning("QXcbConnection: Failed to initialize GLX");
1385         free(error);
1386         has_glx_extension = false;
1387     }
1388     free(xglx_query);
1389 #else
1390     // no way to check, assume GLX is present
1391     has_glx_extension = true;
1392 #endif
1393 }
1394
1395 void QXcbConnection::initializeXRandr()
1396 {
1397     const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_randr_id);
1398     if (!reply || !reply->present)
1399         return;
1400
1401     xrandr_first_event = reply->first_event;
1402
1403     xcb_generic_error_t *error = 0;
1404     xcb_randr_query_version_cookie_t xrandr_query_cookie = xcb_randr_query_version(m_connection,
1405                                                                                    XCB_RANDR_MAJOR_VERSION,
1406                                                                                    XCB_RANDR_MINOR_VERSION);
1407
1408     has_randr_extension = true;
1409
1410     xcb_randr_query_version_reply_t *xrandr_query = xcb_randr_query_version_reply(m_connection,
1411                                                                                   xrandr_query_cookie, &error);
1412     if (!xrandr_query || error || (xrandr_query->major_version < 1 || (xrandr_query->major_version == 1 && xrandr_query->minor_version < 2))) {
1413         qWarning("QXcbConnection: Failed to initialize XRandr");
1414         free(error);
1415         has_randr_extension = false;
1416     }
1417     free(xrandr_query);
1418 }
1419
1420 void QXcbConnection::initializeXShape()
1421 {
1422     const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id);
1423     if (!xshape_reply || !xshape_reply->present)
1424         return;
1425
1426     has_shape_extension = true;
1427     xcb_shape_query_version_cookie_t cookie = xcb_shape_query_version(m_connection);
1428     xcb_shape_query_version_reply_t *shape_query = xcb_shape_query_version_reply(m_connection,
1429                                                                                  cookie, NULL);
1430     if (!shape_query) {
1431         qWarning("QXcbConnection: Failed to initialize SHAPE extension");
1432     } else if (shape_query->major_version > 1 || (shape_query->major_version == 1 && shape_query->minor_version >= 1)) {
1433         // The input shape is the only thing added in SHAPE 1.1
1434         has_input_shape = true;
1435     }
1436     free(shape_query);
1437 }
1438
1439 #if defined(XCB_USE_EGL)
1440 bool QXcbConnection::hasEgl() const
1441 {
1442     return m_has_egl;
1443 }
1444 #endif // defined(XCB_USE_EGL)
1445
1446 #if defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO)
1447 // Borrowed from libXi.
1448 int QXcbConnection::xi2CountBits(unsigned char *ptr, int len)
1449 {
1450     int bits = 0;
1451     int i;
1452     unsigned char x;
1453
1454     for (i = 0; i < len; i++) {
1455         x = ptr[i];
1456         while (x > 0) {
1457             bits += (x & 0x1);
1458             x >>= 1;
1459         }
1460     }
1461     return bits;
1462 }
1463
1464 bool QXcbConnection::xi2GetValuatorValueIfSet(void *event, int valuatorNum, double *value)
1465 {
1466     xXIDeviceEvent *xideviceevent = static_cast<xXIDeviceEvent *>(event);
1467     unsigned char *buttonsMaskAddr = (unsigned char*)&xideviceevent[1];
1468     unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4;
1469     FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4);
1470     int numValuatorValues = xi2CountBits(valuatorsMaskAddr, xideviceevent->valuators_len * 4);
1471     // This relies on all bit being set until a certain number i.e. it doesn't support only bit 0 and 5 being set in the mask.
1472     // Just like the original code, works for now.
1473     if (valuatorNum >= numValuatorValues)
1474         return false;
1475     *value = valuatorsValuesAddr[valuatorNum].integral;
1476     *value += ((double)valuatorsValuesAddr[valuatorNum].frac / (1 << 16) / (1 << 16));
1477     return true;
1478 }
1479
1480 bool QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event, int opCode)
1481 {
1482     // xGenericEvent has "extension" on the second byte, xcb_ge_event_t has "pad0".
1483     if (event->pad0 == opCode) {
1484         // xcb event structs contain stuff that wasn't on the wire, the full_sequence field
1485         // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes.
1486         // Move this data back to have the same layout in memory as it was on the wire
1487         // and allow casting, overwriting the full_sequence field.
1488         memmove((char*) event + 32, (char*) event + 36, event->length * 4);
1489         return true;
1490     }
1491     return false;
1492 }
1493 #endif // defined(XCB_USE_XINPUT2) || defined(XCB_USE_XINPUT2_MAEMO)
1494
1495 QT_END_NAMESPACE