1 /****************************************************************************
3 ** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
4 ** Contact: http://www.qt-project.org/
6 ** This file is part of the plugins of the Qt Toolkit.
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** GNU Lesser General Public License Usage
10 ** This file may be used under the terms of the GNU Lesser General Public
11 ** License version 2.1 as published by the Free Software Foundation and
12 ** appearing in the file LICENSE.LGPL included in the packaging of this
13 ** file. Please review the following information to ensure the GNU Lesser
14 ** General Public License version 2.1 requirements will be met:
15 ** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
17 ** In addition, as a special exception, Nokia gives you certain additional
18 ** rights. These rights are described in the Nokia Qt LGPL Exception
19 ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
21 ** GNU General Public License Usage
22 ** Alternatively, this file may be used under the terms of the GNU General
23 ** Public License version 3.0 as published by the Free Software Foundation
24 ** and appearing in the file LICENSE.GPL included in the packaging of this
25 ** file. Please review the following information to ensure the GNU General
26 ** Public License version 3.0 requirements will be met:
27 ** http://www.gnu.org/copyleft/gpl.html.
30 ** Alternatively, this file may be used in accordance with the terms and
31 ** conditions contained in a signed written agreement between you and Nokia.
40 ****************************************************************************/
42 #include <QtGui/private/qguiapplication_p.h>
43 #include <QtCore/QDebug>
45 #include "qxcbconnection.h"
46 #include "qxcbkeyboard.h"
47 #include "qxcbscreen.h"
48 #include "qxcbwindow.h"
49 #include "qxcbclipboard.h"
51 #include "qxcbwmsupport.h"
52 #include "qxcbnativeinterface.h"
54 #include <QtAlgorithms>
55 #include <QSocketNotifier>
56 #include <QAbstractEventDispatcher>
62 #include <xcb/xfixes.h>
63 #include <xcb/randr.h>
67 #include <X11/Xlib-xcb.h>
68 #include <X11/Xlibint.h>
72 #include <xcb/render.h>
75 #ifdef XCB_USE_EGL //dont pull in eglext prototypes
84 #define MESA_EGL_NO_X11_HEADERS
85 #define EGL_EGLEXT_PROTOTYPES
87 #include <EGL/eglext.h>
93 static int nullErrorHandler(Display *, XErrorEvent *)
99 QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, const char *displayName)
101 , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY"))
102 , m_nativeInterface(nativeInterface)
103 #ifdef XCB_USE_XINPUT2_MAEMO
109 , m_dri2_support_probed(false)
110 , m_has_support_for_dri2(false)
112 , xfixes_first_event(0)
113 , xrandr_first_event(0)
114 , has_shape_extension(false)
115 , has_randr_extension(false)
116 , has_input_shape(false)
121 Display *dpy = XOpenDisplay(m_displayName.constData());
123 m_primaryScreen = DefaultScreen(dpy);
124 m_connection = XGetXCBConnection(dpy);
125 XSetEventQueueOwner(dpy, XCBOwnsEventQueue);
126 XSetErrorHandler(nullErrorHandler);
127 m_xlib_display = dpy;
129 EGLDisplay eglDisplay = eglGetDisplay(dpy);
130 m_egl_display = eglDisplay;
132 eglBindAPI(EGL_OPENGL_ES_API);
133 m_has_egl = eglInitialize(eglDisplay,&major,&minor);
137 m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreen);
138 #endif //XCB_USE_XLIB
140 if (!m_connection || xcb_connection_has_error(m_connection))
141 qFatal("QXcbConnection: Could not connect to display %s", m_displayName.constData());
143 m_reader = new QXcbEventReader(this);
144 #ifdef XCB_POLL_FOR_QUEUED_EVENT
145 connect(m_reader, SIGNAL(eventPending()), this, SLOT(processXcbEvents()), Qt::QueuedConnection);
148 QSocketNotifier *notifier = new QSocketNotifier(xcb_get_file_descriptor(xcb_connection()), QSocketNotifier::Read, this);
149 connect(notifier, SIGNAL(activated(int)), this, SLOT(processXcbEvents()));
151 QAbstractEventDispatcher *dispatcher = QGuiApplicationPrivate::eventDispatcher;
152 connect(dispatcher, SIGNAL(aboutToBlock()), this, SLOT(processXcbEvents()));
153 connect(dispatcher, SIGNAL(awake()), this, SLOT(processXcbEvents()));
156 xcb_prefetch_extension_data (m_connection, &xcb_xfixes_id);
158 m_setup = xcb_get_setup(xcb_connection());
160 initializeAllAtoms();
162 m_time = XCB_CURRENT_TIME;
164 xcb_screen_iterator_t it = xcb_setup_roots_iterator(m_setup);
168 int screenNumber = 0;
170 m_screens << new QXcbScreen(this, it.data, screenNumber++);
171 xcb_screen_next(&it);
174 m_connectionEventListener = xcb_generate_id(m_connection);
175 xcb_create_window(m_connection, XCB_COPY_FROM_PARENT,
176 m_connectionEventListener, m_screens.at(0)->root(),
177 0, 0, 1, 1, 0, XCB_WINDOW_CLASS_INPUT_ONLY,
178 m_screens.at(0)->screen()->root_visual, 0, 0);
182 #ifdef XCB_USE_XINPUT2_MAEMO
187 m_wmSupport.reset(new QXcbWMSupport(this));
188 m_keyboard = new QXcbKeyboard(this);
189 m_clipboard = new QXcbClipboard(this);
190 m_drag = new QXcbDrag(this);
198 QXcbConnection::~QXcbConnection()
202 // Delete screens in reverse order to avoid crash in case of multiple screens
203 while (!m_screens.isEmpty())
204 delete m_screens.takeLast();
206 #ifdef XCB_USE_XINPUT2_MAEMO
210 #ifdef XCB_POLL_FOR_QUEUED_EVENT
211 sendConnectionEvent(QXcbAtom::_QT_CLOSE_CONNECTION);
218 eglTerminate(m_egl_display);
222 XCloseDisplay((Display *)m_xlib_display);
224 xcb_disconnect(xcb_connection());
230 void QXcbConnection::addWindow(xcb_window_t id, QXcbWindow *window)
232 m_mapper.insert(id, window);
235 void QXcbConnection::removeWindow(xcb_window_t id)
240 QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id)
242 return m_mapper.value(id, 0);
245 #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \
247 event_t *e = (event_t *)event; \
248 if (QXcbWindow *platformWindow = platformWindowFromId(e->windowMember)) { \
250 handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
252 platformWindow->handler(e); \
257 #define HANDLE_KEYBOARD_EVENT(event_t, handler) \
259 event_t *e = (event_t *)event; \
260 if (QXcbWindow *platformWindow = platformWindowFromId(e->event)) { \
262 handled = QWindowSystemInterface::handleNativeEvent(platformWindow->window(), m_nativeInterface->genericEventFilterType(), event, &result); \
264 m_keyboard->handler(platformWindow, e); \
269 //#define XCB_EVENT_DEBUG
271 void printXcbEvent(const char *message, xcb_generic_event_t *event)
273 #ifdef XCB_EVENT_DEBUG
274 #define PRINT_XCB_EVENT(ev) \
276 qDebug("QXcbConnection: %s: %d - %s - sequence: %d", message, int(ev), #ev, event->sequence); \
279 switch (event->response_type & ~0x80) {
280 PRINT_XCB_EVENT(XCB_KEY_PRESS);
281 PRINT_XCB_EVENT(XCB_KEY_RELEASE);
282 PRINT_XCB_EVENT(XCB_BUTTON_PRESS);
283 PRINT_XCB_EVENT(XCB_BUTTON_RELEASE);
284 PRINT_XCB_EVENT(XCB_MOTION_NOTIFY);
285 PRINT_XCB_EVENT(XCB_ENTER_NOTIFY);
286 PRINT_XCB_EVENT(XCB_LEAVE_NOTIFY);
287 PRINT_XCB_EVENT(XCB_FOCUS_IN);
288 PRINT_XCB_EVENT(XCB_FOCUS_OUT);
289 PRINT_XCB_EVENT(XCB_KEYMAP_NOTIFY);
290 PRINT_XCB_EVENT(XCB_EXPOSE);
291 PRINT_XCB_EVENT(XCB_GRAPHICS_EXPOSURE);
292 PRINT_XCB_EVENT(XCB_VISIBILITY_NOTIFY);
293 PRINT_XCB_EVENT(XCB_CREATE_NOTIFY);
294 PRINT_XCB_EVENT(XCB_DESTROY_NOTIFY);
295 PRINT_XCB_EVENT(XCB_UNMAP_NOTIFY);
296 PRINT_XCB_EVENT(XCB_MAP_NOTIFY);
297 PRINT_XCB_EVENT(XCB_MAP_REQUEST);
298 PRINT_XCB_EVENT(XCB_REPARENT_NOTIFY);
299 PRINT_XCB_EVENT(XCB_CONFIGURE_NOTIFY);
300 PRINT_XCB_EVENT(XCB_CONFIGURE_REQUEST);
301 PRINT_XCB_EVENT(XCB_GRAVITY_NOTIFY);
302 PRINT_XCB_EVENT(XCB_RESIZE_REQUEST);
303 PRINT_XCB_EVENT(XCB_CIRCULATE_NOTIFY);
304 PRINT_XCB_EVENT(XCB_CIRCULATE_REQUEST);
305 PRINT_XCB_EVENT(XCB_PROPERTY_NOTIFY);
306 PRINT_XCB_EVENT(XCB_SELECTION_CLEAR);
307 PRINT_XCB_EVENT(XCB_SELECTION_REQUEST);
308 PRINT_XCB_EVENT(XCB_SELECTION_NOTIFY);
309 PRINT_XCB_EVENT(XCB_COLORMAP_NOTIFY);
310 PRINT_XCB_EVENT(XCB_CLIENT_MESSAGE);
311 PRINT_XCB_EVENT(XCB_MAPPING_NOTIFY);
313 qDebug("QXcbConnection: %s: unknown event - response_type: %d - sequence: %d", message, int(event->response_type & ~0x80), int(event->sequence));
321 const char *xcb_errors[] =
344 const char *xcb_protocol_request_codes[] =
348 "ChangeWindowAttributes",
349 "GetWindowAttributes",
376 "ChangeActivePointerGrab",
426 "CopyColormapAndFree",
429 "ListInstalledColormaps",
446 "ChangeKeyboardMapping",
447 "GetKeyboardMapping",
448 "ChangeKeyboardControl",
449 "GetKeyboardControl",
451 "ChangePointerControl",
464 "SetModifierMapping",
465 "GetModifierMapping",
470 void QXcbConnection::log(const char *file, int line, int sequence)
472 QMutexLocker locker(&m_callLogMutex);
474 info.sequence = sequence;
481 void QXcbConnection::handleXcbError(xcb_generic_error_t *error)
483 uint clamped_error_code = qMin<uint>(error->error_code, (sizeof(xcb_errors) / sizeof(xcb_errors[0])) - 1);
484 uint clamped_major_code = qMin<uint>(error->major_code, (sizeof(xcb_protocol_request_codes) / sizeof(xcb_protocol_request_codes[0])) - 1);
486 qWarning("QXcbConnection: XCB error: %d (%s), sequence: %d, resource id: %d, major code: %d (%s), minor code: %d",
487 int(error->error_code), xcb_errors[clamped_error_code],
488 int(error->sequence), int(error->resource_id),
489 int(error->major_code), xcb_protocol_request_codes[clamped_major_code],
490 int(error->minor_code));
492 QMutexLocker locker(&m_callLogMutex);
494 for (; i < m_callLog.size(); ++i) {
495 if (m_callLog.at(i).sequence == error->sequence) {
496 qDebug("Caused by: %s:%d", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
498 } else if (m_callLog.at(i).sequence > error->sequence) {
499 qDebug("Caused some time before: %s:%d", qPrintable(m_callLog.at(i).file), m_callLog.at(i).line);
501 qDebug("and after: %s:%d", qPrintable(m_callLog.at(i-1).file), m_callLog.at(i-1).line);
505 if (i == m_callLog.size() && !m_callLog.isEmpty())
506 qDebug("Caused some time after: %s:%d", qPrintable(m_callLog.first().file), m_callLog.first().line);
510 void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event)
514 QMutexLocker locker(&m_callLogMutex);
516 for (; i < m_callLog.size(); ++i)
517 if (m_callLog.at(i).sequence >= event->sequence)
519 m_callLog.remove(0, i);
522 bool handled = false;
524 if (QPlatformNativeInterface::EventFilter filter = m_nativeInterface->eventFilter(QXcbNativeInterface::GenericEventFilter))
525 handled = filter(event, 0);
527 uint response_type = event->response_type & ~0x80;
530 switch (response_type) {
532 HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent);
533 case XCB_BUTTON_PRESS:
534 HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent);
535 case XCB_BUTTON_RELEASE:
536 HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent);
537 case XCB_MOTION_NOTIFY:
538 HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent);
539 case XCB_CONFIGURE_NOTIFY:
540 HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent);
542 HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent);
543 case XCB_UNMAP_NOTIFY:
544 HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent);
545 case XCB_CLIENT_MESSAGE:
546 handleClientMessageEvent((xcb_client_message_event_t *)event);
547 case XCB_ENTER_NOTIFY:
548 HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent);
549 case XCB_LEAVE_NOTIFY:
550 HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent);
552 HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent);
554 HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent);
556 HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent);
557 case XCB_KEY_RELEASE:
558 HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent);
559 case XCB_MAPPING_NOTIFY:
560 m_keyboard->handleMappingNotifyEvent((xcb_mapping_notify_event_t *)event);
562 case XCB_SELECTION_REQUEST:
564 xcb_selection_request_event_t *sr = (xcb_selection_request_event_t *)event;
565 if (sr->selection == atom(QXcbAtom::XdndSelection))
566 m_drag->handleSelectionRequest(sr);
568 m_clipboard->handleSelectionRequest(sr);
571 case XCB_SELECTION_CLEAR:
572 setTime(((xcb_selection_clear_event_t *)event)->time);
573 m_clipboard->handleSelectionClearRequest((xcb_selection_clear_event_t *)event);
576 case XCB_SELECTION_NOTIFY:
577 setTime(((xcb_selection_notify_event_t *)event)->time);
580 case XCB_PROPERTY_NOTIFY:
581 HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent);
583 #ifdef XCB_USE_XINPUT2_MAEMO
585 handleGenericEvent((xcb_ge_event_t*)event);
595 if (response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) {
596 setTime(((xcb_xfixes_selection_notify_event_t *)event)->timestamp);
597 m_clipboard->handleXFixesSelectionRequest((xcb_xfixes_selection_notify_event_t *)event);
599 } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) {
600 xcb_randr_screen_change_notify_event_t *change_event = (xcb_randr_screen_change_notify_event_t *)event;
601 foreach (QXcbScreen *s, m_screens) {
602 if (s->root() == change_event->root ) {
603 s->updateRefreshRate();
613 // Check if a custom XEvent constructor was registered in xlib for this event type, and call it discarding the constructed XEvent if any.
614 // XESetWireToEvent might be used by libraries to intercept messages from the X server e.g. the OpenGL lib waiting for DRI2 events.
616 Display *xdisplay = (Display *)m_xlib_display;
617 XLockDisplay(xdisplay);
618 Bool (*proc)(Display*, XEvent*, xEvent*) = XESetWireToEvent(xdisplay, response_type, 0);
620 XESetWireToEvent(xdisplay, response_type, proc);
622 event->sequence = LastKnownRequestProcessed(m_xlib_display);
623 proc(xdisplay, &dummy, (xEvent*)event);
625 XUnlockDisplay(xdisplay);
630 printXcbEvent("Handled XCB event", event);
632 printXcbEvent("Unhandled XCB event", event);
635 void QXcbConnection::addPeekFunc(PeekFunc f)
637 m_peekFuncs.append(f);
640 #ifdef XCB_POLL_FOR_QUEUED_EVENT
641 void QXcbEventReader::run()
643 xcb_generic_event_t *event;
644 while (m_connection && (event = xcb_wait_for_event(m_connection->xcb_connection()))) {
647 while (m_connection && (event = xcb_poll_for_queued_event(m_connection->xcb_connection())))
653 for (int i = 0; i < m_events.size(); ++i)
654 free(m_events.at(i));
658 void QXcbEventReader::addEvent(xcb_generic_event_t *event)
660 if ((event->response_type & ~0x80) == XCB_CLIENT_MESSAGE
661 && ((xcb_client_message_event_t *)event)->type == m_connection->atom(QXcbAtom::_QT_CLOSE_CONNECTION))
666 QXcbEventArray *QXcbEventReader::lock()
669 #ifndef XCB_POLL_FOR_QUEUED_EVENT
670 while (xcb_generic_event_t *event = xcb_poll_for_event(m_connection->xcb_connection()))
676 void QXcbEventReader::unlock()
681 void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id)
683 xcb_client_message_event_t event;
684 memset(&event, 0, sizeof(event));
686 event.response_type = XCB_CLIENT_MESSAGE;
689 event.window = m_connectionEventListener;
690 event.type = atom(a);
691 event.data.data32[0] = id;
693 Q_XCB_CALL(xcb_send_event(xcb_connection(), false, m_connectionEventListener, XCB_EVENT_MASK_NO_EVENT, (const char *)&event));
694 xcb_flush(xcb_connection());
697 void QXcbConnection::processXcbEvents()
699 QXcbEventArray *eventqueue = m_reader->lock();
701 for(int i = 0; i < eventqueue->size(); ++i) {
702 xcb_generic_event_t *event = eventqueue->at(i);
705 (*eventqueue)[i] = 0;
707 uint response_type = event->response_type & ~0x80;
709 if (!response_type) {
710 handleXcbError((xcb_generic_error_t *)event);
712 QVector<PeekFunc>::iterator it = m_peekFuncs.begin();
713 while (it != m_peekFuncs.end()) {
714 // These callbacks return true if the event is what they were
715 // waiting for, remove them from the list in that case.
717 it = m_peekFuncs.erase(it);
722 handleXcbEvent(event);
733 // Indicate with a null event that the event the callbacks are waiting for
734 // is not in the queue currently.
735 Q_FOREACH (PeekFunc f, m_peekFuncs)
739 xcb_flush(xcb_connection());
742 void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event)
744 if (event->format != 32)
747 if (event->type == atom(QXcbAtom::XdndStatus)) {
748 drag()->handleStatus(event);
749 } else if (event->type == atom(QXcbAtom::XdndFinished)) {
750 drag()->handleFinished(event);
753 QXcbWindow *window = platformWindowFromId(event->window);
757 window->handleClientMessageEvent(event);
760 xcb_generic_event_t *QXcbConnection::checkEvent(int type)
762 QXcbEventArray *eventqueue = m_reader->lock();
764 for (int i = 0; i < eventqueue->size(); ++i) {
765 xcb_generic_event_t *event = eventqueue->at(i);
766 if (event && event->response_type == type) {
767 (*eventqueue)[i] = 0;
778 static const char * xcb_atomnames = {
779 // window-manager <-> client protocols
784 "_NET_WM_CONTEXT_HELP\0"
785 "_NET_WM_SYNC_REQUEST\0"
786 "_NET_WM_SYNC_REQUEST_COUNTER\0"
788 // ICCCM window state
792 // Session management
806 "_QT_CLIPBOARD_SENTINEL\0"
807 "_QT_SELECTION_SENTINEL\0"
808 "CLIPBOARD_MANAGER\0"
815 "_QT_INPUT_ENCODING\0"
817 "_QT_CLOSE_CONNECTION\0"
822 "ENLIGHTENMENT_DESKTOP\0"
824 "_SGI_DESKS_MANAGER\0"
828 "_NET_VIRTUAL_ROOTS\0"
831 "_NET_MOVERESIZE_WINDOW\0"
832 "_NET_WM_MOVERESIZE\0"
835 "_NET_WM_ICON_NAME\0"
840 "_NET_WM_WINDOW_OPACITY\0"
843 "_NET_WM_STATE_ABOVE\0"
844 "_NET_WM_STATE_BELOW\0"
845 "_NET_WM_STATE_FULLSCREEN\0"
846 "_NET_WM_STATE_MAXIMIZED_HORZ\0"
847 "_NET_WM_STATE_MAXIMIZED_VERT\0"
848 "_NET_WM_STATE_MODAL\0"
849 "_NET_WM_STATE_STAYS_ON_TOP\0"
850 "_NET_WM_STATE_DEMANDS_ATTENTION\0"
852 "_NET_WM_USER_TIME\0"
853 "_NET_WM_USER_TIME_WINDOW\0"
854 "_NET_WM_FULL_PLACEMENT\0"
856 "_NET_WM_WINDOW_TYPE\0"
857 "_NET_WM_WINDOW_TYPE_DESKTOP\0"
858 "_NET_WM_WINDOW_TYPE_DOCK\0"
859 "_NET_WM_WINDOW_TYPE_TOOLBAR\0"
860 "_NET_WM_WINDOW_TYPE_MENU\0"
861 "_NET_WM_WINDOW_TYPE_UTILITY\0"
862 "_NET_WM_WINDOW_TYPE_SPLASH\0"
863 "_NET_WM_WINDOW_TYPE_DIALOG\0"
864 "_NET_WM_WINDOW_TYPE_DROPDOWN_MENU\0"
865 "_NET_WM_WINDOW_TYPE_POPUP_MENU\0"
866 "_NET_WM_WINDOW_TYPE_TOOLTIP\0"
867 "_NET_WM_WINDOW_TYPE_NOTIFICATION\0"
868 "_NET_WM_WINDOW_TYPE_COMBO\0"
869 "_NET_WM_WINDOW_TYPE_DND\0"
870 "_NET_WM_WINDOW_TYPE_NORMAL\0"
871 "_KDE_NET_WM_WINDOW_TYPE_OVERRIDE\0"
873 "_KDE_NET_WM_FRAME_STRUT\0"
875 "_NET_STARTUP_INFO\0"
876 "_NET_STARTUP_INFO_BEGIN\0"
878 "_NET_SUPPORTING_WM_CHECK\0"
882 "_NET_SYSTEM_TRAY_VISUAL\0"
884 "_NET_ACTIVE_WINDOW\0"
908 "XdndActionPrivate\0"
911 "_MOTIF_DRAG_AND_DROP_MESSAGE\0"
912 "_MOTIF_DRAG_INITIATOR_INFO\0"
913 "_MOTIF_DRAG_RECEIVER_INFO\0"
914 "_MOTIF_DRAG_WINDOW\0"
915 "_MOTIF_DRAG_TARGETS\0"
917 "XmTRANSFER_SUCCESS\0"
918 "XmTRANSFER_FAILURE\0"
927 // Wacom old. (before version 0.10)
941 "Button Wheel Down\0"
942 "Button Horiz Wheel Left\0"
943 "Button Horiz Wheel Right\0"
944 "Abs MT Position X\0"
945 "Abs MT Position Y\0"
946 "Abs MT Touch Major\0"
947 "Abs MT Touch Minor\0"
949 "Abs MT Tracking ID\0"
951 #if XCB_USE_MAEMO_WINDOW_PROPERTIES
952 "_MEEGOTOUCH_ORIENTATION_ANGLE\0"
956 xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom)
958 return m_allAtoms[atom];
961 void QXcbConnection::initializeAllAtoms() {
962 const char *names[QXcbAtom::NAtoms];
963 const char *ptr = xcb_atomnames;
973 Q_ASSERT(i == QXcbAtom::NPredefinedAtoms);
975 QByteArray settings_atom_name("_QT_SETTINGS_TIMESTAMP_");
976 settings_atom_name += m_displayName;
977 names[i++] = settings_atom_name;
979 xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms];
981 Q_ASSERT(i == QXcbAtom::NAtoms);
982 for (i = 0; i < QXcbAtom::NAtoms; ++i)
983 cookies[i] = xcb_intern_atom(xcb_connection(), false, strlen(names[i]), names[i]);
985 for (i = 0; i < QXcbAtom::NAtoms; ++i) {
986 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookies[i], 0);
987 m_allAtoms[i] = reply->atom;
992 xcb_atom_t QXcbConnection::internAtom(const char *name)
994 if (!name || *name == 0)
997 xcb_intern_atom_cookie_t cookie = xcb_intern_atom(xcb_connection(), false, strlen(name), name);
998 xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(xcb_connection(), cookie, 0);
999 int atom = reply->atom;
1004 QByteArray QXcbConnection::atomName(xcb_atom_t atom)
1007 return QByteArray();
1009 xcb_generic_error_t *error = 0;
1010 xcb_get_atom_name_cookie_t cookie = Q_XCB_CALL(xcb_get_atom_name(xcb_connection(), atom));
1011 xcb_get_atom_name_reply_t *reply = xcb_get_atom_name_reply(xcb_connection(), cookie, &error);
1013 qWarning() << "QXcbConnection::atomName: bad Atom" << atom;
1017 QByteArray result(xcb_get_atom_name_name(reply), xcb_get_atom_name_name_length(reply));
1021 return QByteArray();
1024 const xcb_format_t *QXcbConnection::formatForDepth(uint8_t depth) const
1026 xcb_format_iterator_t iterator =
1027 xcb_setup_pixmap_formats_iterator(m_setup);
1029 while (iterator.rem) {
1030 xcb_format_t *format = iterator.data;
1031 if (format->depth == depth)
1033 xcb_format_next(&iterator);
1039 void QXcbConnection::sync()
1041 // from xcb_aux_sync
1042 xcb_get_input_focus_cookie_t cookie = Q_XCB_CALL(xcb_get_input_focus(xcb_connection()));
1043 free(xcb_get_input_focus_reply(xcb_connection(), cookie, 0));
1046 void QXcbConnection::initializeXFixes()
1048 xcb_generic_error_t *error = 0;
1049 const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_xfixes_id);
1050 xfixes_first_event = reply->first_event;
1052 xcb_xfixes_query_version_cookie_t xfixes_query_cookie = xcb_xfixes_query_version(m_connection,
1053 XCB_XFIXES_MAJOR_VERSION,
1054 XCB_XFIXES_MINOR_VERSION);
1055 xcb_xfixes_query_version_reply_t *xfixes_query = xcb_xfixes_query_version_reply (m_connection,
1056 xfixes_query_cookie, &error);
1057 if (!xfixes_query || error || xfixes_query->major_version < 2) {
1058 qWarning("QXcbConnection: Failed to initialize XFixes");
1060 xfixes_first_event = 0;
1065 void QXcbConnection::initializeXRender()
1067 #ifdef XCB_USE_RENDER
1068 xcb_generic_error_t *error = 0;
1069 xcb_render_query_version_cookie_t xrender_query_cookie = xcb_render_query_version(m_connection,
1070 XCB_RENDER_MAJOR_VERSION,
1071 XCB_RENDER_MINOR_VERSION);
1072 xcb_render_query_version_reply_t *xrender_query = xcb_render_query_version_reply(m_connection,
1073 xrender_query_cookie, &error);
1074 if (!xrender_query || error || (xrender_query->major_version == 0 && xrender_query->minor_version < 5)) {
1075 qWarning("QXcbConnection: Failed to initialize XRender");
1078 free(xrender_query);
1082 void QXcbConnection::initializeXRandr()
1084 const xcb_query_extension_reply_t *xrandr_reply = xcb_get_extension_data(m_connection, &xcb_randr_id);
1085 if (!xrandr_reply || !xrandr_reply->present)
1088 xrandr_first_event = xrandr_reply->first_event;
1090 xcb_generic_error_t *error = 0;
1091 xcb_randr_query_version_cookie_t xrandr_query_cookie = xcb_randr_query_version(m_connection,
1092 XCB_RANDR_MAJOR_VERSION,
1093 XCB_RANDR_MINOR_VERSION);
1095 has_randr_extension = true;
1097 xcb_randr_query_version_reply_t *xrandr_query = xcb_randr_query_version_reply(m_connection,
1098 xrandr_query_cookie, &error);
1099 if (!xrandr_query || error || (xrandr_query->major_version < 1 || (xrandr_query->major_version == 1 && xrandr_query->minor_version < 2))) {
1100 qWarning("QXcbConnection: Failed to initialize XRandr");
1102 has_randr_extension = false;
1107 void QXcbConnection::initializeXShape()
1109 const xcb_query_extension_reply_t *xshape_reply = xcb_get_extension_data(m_connection, &xcb_shape_id);
1110 if (!xshape_reply || !xshape_reply->present)
1113 has_shape_extension = true;
1114 xcb_shape_query_version_cookie_t cookie = xcb_shape_query_version(m_connection);
1115 xcb_shape_query_version_reply_t *shape_query = xcb_shape_query_version_reply(m_connection,
1118 qWarning("QXcbConnection: Failed to initialize SHAPE extension");
1119 } else if (shape_query->major_version > 1 || (shape_query->major_version == 1 && shape_query->minor_version >= 1)) {
1120 // The input shape is the only thing added in SHAPE 1.1
1121 has_input_shape = true;
1126 #if defined(XCB_USE_EGL)
1127 bool QXcbConnection::hasEgl() const
1131 #endif // defined(XCB_USE_EGL)
1134 void QXcbConnection::initializeDri2()
1136 xcb_dri2_connect_cookie_t connect_cookie = xcb_dri2_connect_unchecked (m_connection,
1137 m_screens[0]->root(),
1138 XCB_DRI2_DRIVER_TYPE_DRI);
1140 xcb_dri2_connect_reply_t *connect = xcb_dri2_connect_reply (m_connection,
1141 connect_cookie, NULL);
1143 if (! connect || connect->driver_name_length + connect->device_name_length == 0) {
1144 qWarning("QXcbConnection: Failed to connect to DRI2");
1148 m_dri2_device_name = QByteArray(xcb_dri2_connect_device_name (connect),
1149 xcb_dri2_connect_device_name_length (connect));
1152 int fd = open(m_dri2_device_name.constData(), O_RDWR);
1154 qWarning() << "QXcbConnection: Couldn't open DRI2 device" << m_dri2_device_name;
1155 m_dri2_device_name = QByteArray();
1160 if (drmGetMagic(fd, &magic)) {
1161 qWarning("QXcbConnection: Failed to get drmMagic");
1165 xcb_dri2_authenticate_cookie_t authenticate_cookie = xcb_dri2_authenticate_unchecked(m_connection,
1166 m_screens[0]->root(), magic);
1167 xcb_dri2_authenticate_reply_t *authenticate = xcb_dri2_authenticate_reply(m_connection,
1168 authenticate_cookie, NULL);
1169 if (authenticate == NULL || !authenticate->authenticated) {
1170 qWarning("QXcbConnection: DRI2: failed to authenticate");
1175 delete authenticate;
1177 EGLDisplay display = eglGetDRMDisplayMESA(fd);
1179 qWarning("QXcbConnection: Failed to create EGL display using DRI2");
1183 m_egl_display = display;
1185 if (!eglInitialize(display, &major, &minor)) {
1186 qWarning("QXcbConnection: Failed to initialize EGL display using DRI2");
1191 bool QXcbConnection::hasSupportForDri2() const
1193 if (!m_dri2_support_probed) {
1194 xcb_generic_error_t *error = 0;
1196 xcb_prefetch_extension_data (m_connection, &xcb_dri2_id);
1198 xcb_dri2_query_version_cookie_t dri2_query_cookie = xcb_dri2_query_version (m_connection,
1199 XCB_DRI2_MAJOR_VERSION,
1200 XCB_DRI2_MINOR_VERSION);
1202 xcb_dri2_query_version_reply_t *dri2_query = xcb_dri2_query_version_reply (m_connection,
1203 dri2_query_cookie, &error);
1204 if (!dri2_query || error) {
1210 QXcbConnection *that = const_cast<QXcbConnection *>(this);
1211 that->m_dri2_major = dri2_query->major_version;
1212 that->m_dri2_minor = dri2_query->minor_version;
1214 that->m_has_support_for_dri2 = true;
1215 that->m_dri2_support_probed = true;
1217 return m_has_support_for_dri2;
1219 #endif //XCB_USE_DRI2