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