diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbconnection.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 599 |
1 files changed, 289 insertions, 310 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index aca2c347ea..48715e0812 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -55,6 +55,7 @@ #include "qxcbsystemtraytracker.h" #include "qxcbglintegrationfactory.h" #include "qxcbglintegration.h" +#include "qxcbcursor.h" #include "qxcbbackingstore.h" #include <QSocketNotifier> @@ -81,8 +82,8 @@ #undef register #endif -#if QT_CONFIG(xinput2) -#include <X11/extensions/XI2proto.h> +#if QT_CONFIG(xcb_xinput) +#include <xcb/xinput.h> #endif #if QT_CONFIG(xcb_render) @@ -118,6 +119,7 @@ Q_LOGGING_CATEGORY(lcQpaEvents, "qt.qpa.events") Q_LOGGING_CATEGORY(lcQpaXcb, "qt.qpa.xcb") // for general (uncategorized) XCB logging Q_LOGGING_CATEGORY(lcQpaPeeker, "qt.qpa.peeker") Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") +Q_LOGGING_CATEGORY(lcQpaXDnd, "qt.qpa.xdnd") // this event type was added in libxcb 1.10, // but we support also older version @@ -125,7 +127,7 @@ Q_LOGGING_CATEGORY(lcQpaKeyboard, "qt.qpa.xkeyboard") #define XCB_GE_GENERIC 35 #endif -#if QT_CONFIG(xinput2) +#if QT_CONFIG(xcb_xinput) // Starting from the xcb version 1.9.3 struct xcb_ge_event_t has changed: // - "pad0" became "extension" // - "pad1" and "pad" became "pad0" @@ -143,7 +145,7 @@ static inline bool isXIEvent(xcb_generic_event_t *event, int opCode) qt_xcb_ge_event_t *e = reinterpret_cast<qt_xcb_ge_event_t *>(event); return e->extension == opCode; } -#endif // QT_CONFIG(xinput2) +#endif // QT_CONFIG(xcb_xinput) #if QT_CONFIG(xcb_xlib) static const char * const xcbConnectionErrors[] = { @@ -542,31 +544,59 @@ void QXcbConnection::initializeScreens() } } -QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGrabServer, xcb_visualid_t defaultVisualId, const char *displayName) - : m_canGrabServer(canGrabServer) - , m_defaultVisualId(defaultVisualId) - , m_displayName(displayName ? QByteArray(displayName) : qgetenv("DISPLAY")) - , m_nativeInterface(nativeInterface) +QXcbConnection *QXcbConnection::create(QXcbNativeInterface *nativeInterface, bool canGrabServer, + xcb_visualid_t defaultVisualId, + const char *displayNameIn) { + const QByteArray displayName = displayNameIn ? QByteArray(displayNameIn) : qgetenv("DISPLAY"); + int primaryScreenNumber = 0; + void *xlibDisplay = nullptr; + xcb_connection_t *connection = nullptr; #if QT_CONFIG(xcb_xlib) - Display *dpy = XOpenDisplay(m_displayName.constData()); + Display *dpy = XOpenDisplay(displayName.constData()); if (dpy) { - m_primaryScreenNumber = DefaultScreen(dpy); - m_connection = XGetXCBConnection(dpy); + primaryScreenNumber = DefaultScreen(dpy); + connection = XGetXCBConnection(dpy); XSetEventQueueOwner(dpy, XCBOwnsEventQueue); XSetErrorHandler(nullErrorHandler); XSetIOErrorHandler(ioErrorHandler); - m_xlib_display = dpy; + xlibDisplay = dpy; } #else - m_connection = xcb_connect(m_displayName.constData(), &m_primaryScreenNumber); + connection = xcb_connect(displayName.constData(), &primaryScreenNumber); #endif // QT_CONFIG(xcb_xlib) - - if (Q_UNLIKELY(!m_connection || xcb_connection_has_error(m_connection))) { - qCWarning(lcQpaScreen, "QXcbConnection: Could not connect to display %s", m_displayName.constData()); - return; + if (Q_UNLIKELY(connection == nullptr)) { + qWarning("QXcbConnection: Could not connect to display \"%s\"", displayName.constData()); + return nullptr; + } + if (Q_UNLIKELY(xcb_connection_has_error(connection))) { +#if QT_CONFIG(xcb_xlib) + XCloseDisplay(static_cast<Display *>(xlibDisplay)); +#else + xcb_disconnect(connection); +#endif + qWarning("QXcbConnection: Errors occurred connecting to display \"%s\"", displayName.constData()); + return nullptr; } + return new QXcbConnection(connection, primaryScreenNumber, nativeInterface, + canGrabServer, defaultVisualId, displayName, xlibDisplay); +} + +QXcbConnection::QXcbConnection(xcb_connection_t *c, int primaryScreenNumber, + QXcbNativeInterface *nativeInterface, bool canGrabServer, + xcb_visualid_t defaultVisualId, const QByteArray &displayName, + void *xlibDisplay) + : m_connection(c) + , m_canGrabServer(canGrabServer) + , m_defaultVisualId(defaultVisualId) + , m_primaryScreenNumber(primaryScreenNumber) + , m_displayName(displayName) + , m_nativeInterface(nativeInterface) +#if QT_CONFIG(xcb_xlib) + , m_xlib_display(xlibDisplay) +#endif +{ m_reader = new QXcbEventReader(this); m_reader->start(); @@ -578,6 +608,9 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra #if QT_CONFIG(xcb_render) &xcb_render_id, #endif +#if QT_CONFIG(xcb_xinput) + &xcb_input_id, +#endif 0 }; @@ -590,6 +623,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeAllAtoms(); + initializeXSync(); if (!qEnvironmentVariableIsSet("QT_XCB_NO_MITSHM")) initializeShm(); if (!qEnvironmentVariableIsSet("QT_XCB_NO_XRANDR")) @@ -600,7 +634,7 @@ QXcbConnection::QXcbConnection(QXcbNativeInterface *nativeInterface, bool canGra initializeScreens(); initializeXRender(); -#if QT_CONFIG(xinput2) +#if QT_CONFIG(xcb_xinput) if (!qEnvironmentVariableIsSet("QT_XCB_NO_XI2")) initializeXInput2(); #endif @@ -727,22 +761,22 @@ QXcbWindow *QXcbConnection::platformWindowFromId(xcb_window_t id) #define HANDLE_PLATFORM_WINDOW_EVENT(event_t, windowMember, handler) \ { \ - event_t *e = reinterpret_cast<event_t *>(event); \ + auto e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->windowMember)) { \ - handled = eventListener->handleGenericEvent(event, &result); \ - if (!handled) \ - eventListener->handler(e); \ + if (eventListener->handleNativeEvent(event)) \ + return; \ + eventListener->handler(e); \ } \ } \ break; #define HANDLE_KEYBOARD_EVENT(event_t, handler) \ { \ - event_t *e = reinterpret_cast<event_t *>(event); \ + auto e = reinterpret_cast<event_t *>(event); \ if (QXcbWindowEventListener *eventListener = windowEventListenerFromId(e->event)) { \ - handled = eventListener->handleGenericEvent(event, &result); \ - if (!handled) \ - m_keyboard->handler(e); \ + if (eventListener->handleNativeEvent(event)) \ + return; \ + m_keyboard->handler(e); \ } \ } \ break; @@ -968,7 +1002,7 @@ void QXcbConnection::handleXcbError(xcb_generic_error_t *error) { long result = 0; QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); - if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), error, &result)) + if (dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->nativeEventType(), error, &result)) return; printXcbError("QXcbConnection: XCB error", error); @@ -1060,197 +1094,206 @@ namespace { void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) { - long result = 0; + if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled())) + printXcbEvent(lcQpaEvents(), "Event", event); + + long result = 0; // Used only by MS Windows QAbstractEventDispatcher* dispatcher = QAbstractEventDispatcher::instance(); - bool handled = dispatcher && dispatcher->filterNativeEvent(m_nativeInterface->genericEventFilterType(), event, &result); + bool handledByNativeEventFilter = dispatcher && dispatcher->filterNativeEvent( + m_nativeInterface->nativeEventType(), event, &result); + if (handledByNativeEventFilter) + return; uint response_type = event->response_type & ~0x80; - if (!handled) { - switch (response_type) { - case XCB_EXPOSE: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); - - case XCB_BUTTON_PRESS: { - xcb_button_press_event_t *ev = (xcb_button_press_event_t *)event; - m_keyboard->updateXKBStateFromCore(ev->state); - // the event explicitly contains the state of the three first buttons, - // the rest we need to manage ourselves - m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - setButtonState(translateMouseButton(ev->detail), true); - if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState)); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); - } - case XCB_BUTTON_RELEASE: { - xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event; - m_keyboard->updateXKBStateFromCore(ev->state); - m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - setButtonState(translateMouseButton(ev->detail), false); - if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState)); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); - } - case XCB_MOTION_NOTIFY: { - xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)event; - m_keyboard->updateXKBStateFromCore(ev->state); - m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) - qCDebug(lcQpaXInputEvents, "legacy mouse move %d,%d button %d state %X", ev->event_x, ev->event_y, - ev->detail, static_cast<unsigned int>(m_buttonState)); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); - } - - case XCB_CONFIGURE_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); - case XCB_MAP_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); - case XCB_UNMAP_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); - case XCB_DESTROY_NOTIFY: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); - case XCB_CLIENT_MESSAGE: - handleClientMessageEvent((xcb_client_message_event_t *)event); - break; - case XCB_ENTER_NOTIFY: -#if QT_CONFIG(xinput2) - if (hasXInput2() && !xi2MouseEventsDisabled()) - break; + bool handled = true; + switch (response_type) { + case XCB_EXPOSE: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_expose_event_t, window, handleExposeEvent); + case XCB_BUTTON_PRESS: { + auto ev = reinterpret_cast<xcb_button_press_event_t *>(event); + m_keyboard->updateXKBStateFromCore(ev->state); + // the event explicitly contains the state of the three first buttons, + // the rest we need to manage ourselves + m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); + setButtonState(translateMouseButton(ev->detail), true); + if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) + qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", + ev->detail, static_cast<unsigned int>(m_buttonState)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); + } + case XCB_BUTTON_RELEASE: { + auto ev = reinterpret_cast<xcb_button_release_event_t *>(event); + m_keyboard->updateXKBStateFromCore(ev->state); + m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); + setButtonState(translateMouseButton(ev->detail), false); + if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) + qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", + ev->detail, static_cast<unsigned int>(m_buttonState)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); + } + case XCB_MOTION_NOTIFY: { + auto ev = reinterpret_cast<xcb_motion_notify_event_t *>(event); + m_keyboard->updateXKBStateFromCore(ev->state); + m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); + if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) + qCDebug(lcQpaXInputEvents, "legacy mouse move %d,%d button %d state %X", + ev->event_x, ev->event_y, ev->detail, static_cast<unsigned int>(m_buttonState)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_motion_notify_event_t, event, handleMotionNotifyEvent); + } + case XCB_CONFIGURE_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_configure_notify_event_t, event, handleConfigureNotifyEvent); + case XCB_MAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_map_notify_event_t, event, handleMapNotifyEvent); + case XCB_UNMAP_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_unmap_notify_event_t, event, handleUnmapNotifyEvent); + case XCB_DESTROY_NOTIFY: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_destroy_notify_event_t, event, handleDestroyNotifyEvent); + case XCB_CLIENT_MESSAGE: { + auto clientMessage = reinterpret_cast<xcb_client_message_event_t *>(event); + if (clientMessage->format != 32) + return; +#if QT_CONFIG(draganddrop) + if (clientMessage->type == atom(QXcbAtom::XdndStatus)) + drag()->handleStatus(clientMessage); + else if (clientMessage->type == atom(QXcbAtom::XdndFinished)) + drag()->handleFinished(clientMessage); #endif - HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); - case XCB_LEAVE_NOTIFY: -#if QT_CONFIG(xinput2) - if (hasXInput2() && !xi2MouseEventsDisabled()) - break; + if (m_systemTrayTracker && clientMessage->type == atom(QXcbAtom::MANAGER)) + m_systemTrayTracker->notifyManagerClientMessageEvent(clientMessage); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_client_message_event_t, window, handleClientMessageEvent); + } + case XCB_ENTER_NOTIFY: +#if QT_CONFIG(xcb_xinput) + if (hasXInput2() && !xi2MouseEventsDisabled()) + break; #endif - m_keyboard->updateXKBStateFromCore(((xcb_leave_notify_event_t *)event)->state); - HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); - case XCB_FOCUS_IN: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); - case XCB_FOCUS_OUT: - HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); - case XCB_KEY_PRESS: - { - xcb_key_press_event_t *kp = (xcb_key_press_event_t *)event; - m_keyboard->updateXKBStateFromCore(kp->state); - setTime(kp->time); - HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); - } - case XCB_KEY_RELEASE: - m_keyboard->updateXKBStateFromCore(((xcb_key_release_event_t *)event)->state); - HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); - case XCB_MAPPING_NOTIFY: - m_keyboard->updateKeymap(reinterpret_cast<xcb_mapping_notify_event_t *>(event)); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_enter_notify_event_t, event, handleEnterNotifyEvent); + case XCB_LEAVE_NOTIFY: +#if QT_CONFIG(xcb_xinput) + if (hasXInput2() && !xi2MouseEventsDisabled()) break; - case XCB_SELECTION_REQUEST: - { +#endif + m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_leave_notify_event_t *>(event)->state); + HANDLE_PLATFORM_WINDOW_EVENT(xcb_leave_notify_event_t, event, handleLeaveNotifyEvent); + case XCB_FOCUS_IN: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_in_event_t, event, handleFocusInEvent); + case XCB_FOCUS_OUT: + HANDLE_PLATFORM_WINDOW_EVENT(xcb_focus_out_event_t, event, handleFocusOutEvent); + case XCB_KEY_PRESS: + { + auto keyPress = reinterpret_cast<xcb_key_press_event_t *>(event); + m_keyboard->updateXKBStateFromCore(keyPress->state); + setTime(keyPress->time); + HANDLE_KEYBOARD_EVENT(xcb_key_press_event_t, handleKeyPressEvent); + } + case XCB_KEY_RELEASE: + m_keyboard->updateXKBStateFromCore(reinterpret_cast<xcb_key_release_event_t *>(event)->state); + HANDLE_KEYBOARD_EVENT(xcb_key_release_event_t, handleKeyReleaseEvent); + case XCB_MAPPING_NOTIFY: + m_keyboard->updateKeymap(reinterpret_cast<xcb_mapping_notify_event_t *>(event)); + break; + case XCB_SELECTION_REQUEST: + { #if QT_CONFIG(draganddrop) || QT_CONFIG(clipboard) - xcb_selection_request_event_t *sr = reinterpret_cast<xcb_selection_request_event_t *>(event); + auto selectionRequest = reinterpret_cast<xcb_selection_request_event_t *>(event); #endif #if QT_CONFIG(draganddrop) - if (sr->selection == atom(QXcbAtom::XdndSelection)) - m_drag->handleSelectionRequest(sr); - else + if (selectionRequest->selection == atom(QXcbAtom::XdndSelection)) + m_drag->handleSelectionRequest(selectionRequest); + else #endif - { + { #ifndef QT_NO_CLIPBOARD - m_clipboard->handleSelectionRequest(sr); + m_clipboard->handleSelectionRequest(selectionRequest); #endif - } - break; } - case XCB_SELECTION_CLEAR: - setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time); + break; + } + case XCB_SELECTION_CLEAR: + setTime((reinterpret_cast<xcb_selection_clear_event_t *>(event))->time); #ifndef QT_NO_CLIPBOARD - m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event)); + m_clipboard->handleSelectionClearRequest(reinterpret_cast<xcb_selection_clear_event_t *>(event)); #endif - handled = true; - break; - case XCB_SELECTION_NOTIFY: - setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time); - handled = false; - break; - case XCB_PROPERTY_NOTIFY: - { - xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); - if (pn->atom == atom(QXcbAtom::_NET_WORKAREA)) { - QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(pn->window); - if (virtualDesktop) - virtualDesktop->updateWorkArea(); - } else { - HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent); - } - break; + break; + case XCB_SELECTION_NOTIFY: + setTime((reinterpret_cast<xcb_selection_notify_event_t *>(event))->time); + break; + case XCB_PROPERTY_NOTIFY: + { + auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event); + if (propertyNotify->atom == atom(QXcbAtom::_NET_WORKAREA)) { + QXcbVirtualDesktop *virtualDesktop = virtualDesktopForRootWindow(propertyNotify->window); + if (virtualDesktop) + virtualDesktop->updateWorkArea(); + } else { + HANDLE_PLATFORM_WINDOW_EVENT(xcb_property_notify_event_t, window, handlePropertyNotifyEvent); } -#if QT_CONFIG(xinput2) - case XCB_GE_GENERIC: - // Here the windowEventListener is invoked from xi2HandleEvent() - if (hasXInput2() && isXIEvent(event, m_xiOpCode)) - xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event)); - break; + break; + } +#if QT_CONFIG(xcb_xinput) + case XCB_GE_GENERIC: + // Here the windowEventListener is invoked from xi2HandleEvent() + if (hasXInput2() && isXIEvent(event, m_xiOpCode)) + xi2HandleEvent(reinterpret_cast<xcb_ge_event_t *>(event)); + break; #endif - default: - handled = false; - break; - } + default: + handled = false; // event type not recognized + break; } - if (!handled) { - if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { - xcb_xfixes_selection_notify_event_t *notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event); - setTime(notify_event->timestamp); + if (handled) + return; + + handled = true; + if (has_xfixes && response_type == xfixes_first_event + XCB_XFIXES_SELECTION_NOTIFY) { + auto notify_event = reinterpret_cast<xcb_xfixes_selection_notify_event_t *>(event); + setTime(notify_event->timestamp); #ifndef QT_NO_CLIPBOARD - m_clipboard->handleXFixesSelectionRequest(notify_event); + m_clipboard->handleXFixesSelectionRequest(notify_event); #endif - for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) - virtualDesktop->handleXFixesSelectionNotify(notify_event); - - handled = true; - } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { - updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event)); - handled = true; - } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { - xcb_randr_screen_change_notify_event_t *change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event); - if (auto *virtualDesktop = virtualDesktopForRootWindow(change_event->root)) - virtualDesktop->handleScreenChange(change_event); - - handled = true; + for (QXcbVirtualDesktop *virtualDesktop : qAsConst(m_virtualDesktops)) + virtualDesktop->handleXFixesSelectionNotify(notify_event); + } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_NOTIFY) { + updateScreens(reinterpret_cast<xcb_randr_notify_event_t *>(event)); + } else if (has_randr_extension && response_type == xrandr_first_event + XCB_RANDR_SCREEN_CHANGE_NOTIFY) { + auto change_event = reinterpret_cast<xcb_randr_screen_change_notify_event_t *>(event); + if (auto virtualDesktop = virtualDesktopForRootWindow(change_event->root)) + virtualDesktop->handleScreenChange(change_event); #if QT_CONFIG(xkb) - } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295 - _xkb_event *xkb_event = reinterpret_cast<_xkb_event *>(event); - if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { - switch (xkb_event->any.xkbType) { - // XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap - // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations. - case XCB_XKB_STATE_NOTIFY: - m_keyboard->updateXKBState(&xkb_event->state_notify); - handled = true; - break; - case XCB_XKB_MAP_NOTIFY: + } else if (response_type == xkb_first_event) { // https://bugs.freedesktop.org/show_bug.cgi?id=51295 + auto xkb_event = reinterpret_cast<_xkb_event *>(event); + if (xkb_event->any.deviceID == m_keyboard->coreDeviceId()) { + switch (xkb_event->any.xkbType) { + // XkbNewKkdNotify and XkbMapNotify together capture all sorts of keymap + // updates (e.g. xmodmap, xkbcomp, setxkbmap), with minimal redundent recompilations. + case XCB_XKB_STATE_NOTIFY: + m_keyboard->updateXKBState(&xkb_event->state_notify); + break; + case XCB_XKB_MAP_NOTIFY: + m_keyboard->updateKeymap(); + break; + case XCB_XKB_NEW_KEYBOARD_NOTIFY: { + xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify; + if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES) m_keyboard->updateKeymap(); - handled = true; - break; - case XCB_XKB_NEW_KEYBOARD_NOTIFY: { - xcb_xkb_new_keyboard_notify_event_t *ev = &xkb_event->new_keyboard_notify; - if (ev->changed & XCB_XKB_NKN_DETAIL_KEYCODES) - m_keyboard->updateKeymap(); - break; - } - default: - break; + break; } + default: + break; } -#endif } +#endif + } else { + handled = false; // event type still not recognized } - if (!handled && m_glIntegration) - handled = m_glIntegration->handleXcbEvent(event, response_type); + if (handled) + return; -#if 0 - if (Q_UNLIKELY(lcQpaEvents().isDebugEnabled())) - printXcbEvent(lcQpaEvents(), handled ? "Handled" : "Unhandled", event); -#endif + if (m_glIntegration) + m_glIntegration->handleXcbEvent(event, response_type); } void QXcbConnection::addPeekFunc(PeekFunc f) @@ -1478,54 +1521,35 @@ void QXcbConnection::sendConnectionEvent(QXcbAtom::Atom a, uint id) xcb_flush(xcb_connection()); } -namespace -{ - class PropertyNotifyEvent { - public: - PropertyNotifyEvent(xcb_window_t win, xcb_atom_t property) - : window(win), type(XCB_PROPERTY_NOTIFY), atom(property) {} - xcb_window_t window; - int type; - xcb_atom_t atom; - bool checkEvent(xcb_generic_event_t *event) const { - if (!event) - return false; - if ((event->response_type & ~0x80) != type) { - return false; - } else { - xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); - if ((pn->window == window) && (pn->atom == atom)) - return true; - } - return false; - } - }; -} - xcb_timestamp_t QXcbConnection::getTimestamp() { // send a dummy event to myself to get the timestamp from X server. - xcb_window_t root_win = rootWindow(); - xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, root_win, atom(QXcbAtom::CLIP_TEMPORARY), - XCB_ATOM_INTEGER, 32, 0, NULL); + xcb_window_t window = rootWindow(); + xcb_atom_t dummyAtom = atom(QXcbAtom::CLIP_TEMPORARY); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_APPEND, window, dummyAtom, + XCB_ATOM_INTEGER, 32, 0, nullptr); connection()->flush(); - PropertyNotifyEvent checker(root_win, atom(QXcbAtom::CLIP_TEMPORARY)); - xcb_generic_event_t *event = 0; + xcb_generic_event_t *event = nullptr; // lets keep this inside a loop to avoid a possible race condition, where // reader thread has not yet had the time to acquire the mutex in order // to add the new set of events to its event queue while (!event) { connection()->sync(); - event = checkEvent(checker); + event = checkEvent([window, dummyAtom](xcb_generic_event_t *event, int type) { + if (type != XCB_PROPERTY_NOTIFY) + return false; + auto propertyNotify = reinterpret_cast<xcb_property_notify_event_t *>(event); + return propertyNotify->window == window && propertyNotify->atom == dummyAtom; + }); } xcb_property_notify_event_t *pn = reinterpret_cast<xcb_property_notify_event_t *>(event); xcb_timestamp_t timestamp = pn->time; free(event); - xcb_delete_property(xcb_connection(), root_win, atom(QXcbAtom::CLIP_TEMPORARY)); + xcb_delete_property(xcb_connection(), window, dummyAtom); return timestamp; } @@ -1552,6 +1576,9 @@ xcb_window_t QXcbConnection::getQtSelectionOwner() xcbScreen->root_visual, // visual 0, // value mask 0); // value list + + QXcbWindow::setWindowTitle(connection(), m_qtSelectionOwner, + QStringLiteral("Qt Selection Window")); } return m_qtSelectionOwner; } @@ -1576,17 +1603,11 @@ xcb_window_t QXcbConnection::clientLeader() XCB_WINDOW_CLASS_INPUT_OUTPUT, screen->screen()->root_visual, 0, 0); -#ifndef QT_NO_DEBUG - QByteArray ba("Qt client leader window"); - xcb_change_property(xcb_connection(), - XCB_PROP_MODE_REPLACE, - m_clientLeader, - atom(QXcbAtom::_NET_WM_NAME), - atom(QXcbAtom::UTF8_STRING), - 8, - ba.length(), - ba.constData()); -#endif + + + QXcbWindow::setWindowTitle(connection(), m_clientLeader, + QStringLiteral("Qt Client Leader Window")); + xcb_change_property(xcb_connection(), XCB_PROP_MODE_REPLACE, m_clientLeader, @@ -1614,39 +1635,14 @@ xcb_window_t QXcbConnection::clientLeader() return m_clientLeader; } -#if QT_CONFIG(xcb_xlib) -void *QXcbConnection::xlib_display() const -{ - return m_xlib_display; -} - -void *QXcbConnection::createVisualInfoForDefaultVisualId() const -{ - if (m_defaultVisualId == UINT_MAX) - return 0; - XVisualInfo info; - memset(&info, 0, sizeof info); - info.visualid = m_defaultVisualId; - - int count = 0; - Display *dpy = static_cast<Display *>(connection()->xlib_display()); - XVisualInfo *retVisual = XGetVisualInfo(dpy, VisualIDMask, &info, &count); - Q_ASSERT(count < 2); - return retVisual; -} - -#endif - -#if QT_CONFIG(xinput2) -// it is safe to cast XI_* events here as long as we are only touching the first 32 bytes, -// after that position event needs memmove, see xi2PrepareXIGenericDeviceEvent +#if QT_CONFIG(xcb_xinput) static inline bool isXIType(xcb_generic_event_t *event, int opCode, uint16_t type) { if (!isXIEvent(event, opCode)) return false; - xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); - return xiEvent->evtype == type; + auto *e = reinterpret_cast<qt_xcb_ge_event_t *>(event); + return e->event_type == type; } #endif static inline bool isValid(xcb_generic_event_t *event) @@ -1682,49 +1678,45 @@ bool QXcbConnection::compressEvent(xcb_generic_event_t *event, int currentIndex, } return false; } -#if QT_CONFIG(xinput2) +#if QT_CONFIG(xcb_xinput) // compress XI_* events if (responseType == XCB_GE_GENERIC) { if (!hasXInput2()) return false; // compress XI_Motion - if (isXIType(event, m_xiOpCode, XI_Motion)) { + if (isXIType(event, m_xiOpCode, XCB_INPUT_MOTION)) { #if QT_CONFIG(tabletevent) - xXIDeviceEvent *xdev = reinterpret_cast<xXIDeviceEvent *>(event); - // Xlib's XI2 events need memmove, see xi2PrepareXIGenericDeviceEvent() - auto sourceId = *reinterpret_cast<uint16_t *>(reinterpret_cast<char *>(&xdev->sourceid) + 4); + auto *xdev = reinterpret_cast<xcb_input_motion_event_t *>(event); if (!QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents) && - const_cast<QXcbConnection *>(this)->tabletDataForDevice(sourceId)) + const_cast<QXcbConnection *>(this)->tabletDataForDevice(xdev->sourceid)) return false; #endif // QT_CONFIG(tabletevent) for (int j = nextIndex; j < eventqueue->size(); ++j) { xcb_generic_event_t *next = eventqueue->at(j); if (!isValid(next)) continue; - if (isXIType(next, m_xiOpCode, XI_Motion)) + if (isXIType(next, m_xiOpCode, XCB_INPUT_MOTION)) return true; } return false; } -#ifdef XCB_USE_XINPUT22 // compress XI_TouchUpdate for the same touch point id - if (isXIType(event, m_xiOpCode, XI_TouchUpdate)) { - xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); - uint32_t id = xiDeviceEvent->detail % INT_MAX; + if (isXIType(event, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) { + auto *touchUpdateEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(event); + uint32_t id = touchUpdateEvent->detail % INT_MAX; for (int j = nextIndex; j < eventqueue->size(); ++j) { xcb_generic_event_t *next = eventqueue->at(j); if (!isValid(next)) continue; - if (isXIType(next, m_xiOpCode, XI_TouchUpdate)) { - xXIDeviceEvent *xiDeviceNextEvent = reinterpret_cast<xXIDeviceEvent *>(next); - if (id == xiDeviceNextEvent->detail % INT_MAX) + if (isXIType(next, m_xiOpCode, XCB_INPUT_TOUCH_UPDATE)) { + auto *touchUpdateNextEvent = reinterpret_cast<xcb_input_touch_update_event_t *>(next); + if (id == touchUpdateNextEvent->detail % INT_MAX) return true; } } return false; } -#endif return false; } #endif @@ -1806,28 +1798,6 @@ void QXcbConnection::processXcbEvents() xcb_flush(xcb_connection()); } -void QXcbConnection::handleClientMessageEvent(const xcb_client_message_event_t *event) -{ - if (event->format != 32) - return; - -#if QT_CONFIG(draganddrop) - if (event->type == atom(QXcbAtom::XdndStatus)) { - drag()->handleStatus(event); - } else if (event->type == atom(QXcbAtom::XdndFinished)) { - drag()->handleFinished(event); - } -#endif - if (m_systemTrayTracker && event->type == atom(QXcbAtom::MANAGER)) - m_systemTrayTracker->notifyManagerClientMessageEvent(event); - - QXcbWindow *window = platformWindowFromId(event->window); - if (!window) - return; - - window->handleClientMessageEvent(event); -} - static const char * xcb_atomnames = { // window-manager <-> client protocols "WM_PROTOCOLS\0" @@ -1850,6 +1820,7 @@ static const char * xcb_atomnames = { "WM_CLIENT_LEADER\0" "WM_WINDOW_ROLE\0" "SM_CLIENT_ID\0" + "WM_CLIENT_MACHINE\0" // Clipboard "CLIPBOARD\0" @@ -2021,6 +1992,10 @@ static const char * xcb_atomnames = { "_COMPIZ_DECOR_DELETE_PIXMAP\0" "_COMPIZ_TOOLKIT_ACTION\0" "_GTK_LOAD_ICONTHEMES\0" + "AT_SPI_BUS\0" + "EDID\0" + "EDID_DATA\0" + "XFree86_DDC_EDID1_RAWDATA\0" // \0\0 terminates loop. }; @@ -2041,10 +2016,7 @@ void QXcbConnection::initializeAllAtoms() { ++ptr; } - Q_ASSERT(i == QXcbAtom::NPredefinedAtoms); - - const QByteArray settings_atom_name = "_QT_SETTINGS_TIMESTAMP_" + m_displayName; - names[i++] = settings_atom_name; + Q_ASSERT(i == QXcbAtom::NAtoms); xcb_intern_atom_cookie_t cookies[QXcbAtom::NAtoms]; @@ -2297,6 +2269,15 @@ void QXcbConnection::initializeXKB() #endif } +void QXcbConnection::initializeXSync() +{ + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(xcb_connection(), &xcb_sync_id); + if (!reply || !reply->present) + return; + + has_sync_extension = true; +} + QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const { if (!m_systemTrayTracker) { @@ -2309,20 +2290,18 @@ QXcbSystemTrayTracker *QXcbConnection::systemTrayTracker() const return m_systemTrayTracker; } -bool QXcbConnection::xEmbedSystemTrayAvailable() +Qt::MouseButtons QXcbConnection::queryMouseButtons() const { - if (!QGuiApplicationPrivate::platformIntegration()) - return false; - QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection(); - return connection->systemTrayTracker(); + int stateMask = 0; + QXcbCursor::queryPointer(connection(), 0, 0, &stateMask); + return translateMouseButtons(stateMask); } -bool QXcbConnection::xEmbedSystemTrayVisualHasAlphaChannel() +Qt::KeyboardModifiers QXcbConnection::queryKeyboardModifiers() const { - if (!QGuiApplicationPrivate::platformIntegration()) - return false; - QXcbConnection *connection = static_cast<QXcbIntegration *>(QGuiApplicationPrivate::platformIntegration())->defaultConnection(); - return connection->systemTrayTracker() && connection->systemTrayTracker()->visualHasAlphaChannel(); + int stateMask = 0; + QXcbCursor::queryPointer(connection(), 0, 0, &stateMask); + return keyboard()->translateModifiers(stateMask); } bool QXcbConnection::event(QEvent *e) |