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