From 570200145c5cfec886241909c26edb0dc88db9f7 Mon Sep 17 00:00:00 2001 From: Povilas Kanapickas Date: Tue, 28 Sep 2021 20:17:00 +0300 Subject: [PATCH] xcb: Use byte buffer for event masks This prepares for use of masks larger than 32 bits which happens on XI 2.4. Additionally, since the XI protocol always sends the masks using little-endian, the XI protocol support on big-endian machines was currently broken. Done-with: Marcus Comstedt Fixes: QTBUG-105157 Change-Id: Id22131e075059cea783b5be0691a673a457c7364 Reviewed-by: Shawn Rutledge (cherry modified from commit a875503d9e001a05eb3c0998f6c1292f0fefc4e1) --- .../platforms/xcb/qxcbconnection_xi2.cpp | 76 +++++++++++-------- 1 file changed, 43 insertions(+), 33 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 147245b76e..e5e1757ccf 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -53,9 +53,15 @@ using qt_xcb_input_device_event_t = xcb_input_button_press_event_t; struct qt_xcb_input_event_mask_t { xcb_input_event_mask_t header; - uint32_t mask; + alignas(4) uint8_t mask[4] = {}; }; +static inline void setXcbMask(uint8_t* mask, int bit) +{ + // note that XI protocol always uses little endian for masks over the wire + mask[bit >> 3] |= 1 << (bit & 7); +} + void QXcbConnection::xi2SelectStateEvents() { // These state events do not depend on a specific X window, but are global @@ -63,9 +69,9 @@ void QXcbConnection::xi2SelectStateEvents() qt_xcb_input_event_mask_t xiEventMask; xiEventMask.header.deviceid = XCB_INPUT_DEVICE_ALL; xiEventMask.header.mask_len = 1; - xiEventMask.mask = XCB_INPUT_XI_EVENT_MASK_HIERARCHY; - xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_DEVICE_CHANGED; - xiEventMask.mask |= XCB_INPUT_XI_EVENT_MASK_PROPERTY; + setXcbMask(xiEventMask.mask, XCB_INPUT_HIERARCHY); + setXcbMask(xiEventMask.mask, XCB_INPUT_DEVICE_CHANGED); + setXcbMask(xiEventMask.mask, XCB_INPUT_PROPERTY); xcb_input_xi_select_events(xcb_connection(), rootWindow(), 1, &xiEventMask.header); } @@ -74,23 +80,23 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) if (window == rootWindow()) return; - uint32_t bitMask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS; - bitMask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE; - bitMask |= XCB_INPUT_XI_EVENT_MASK_MOTION; + qt_xcb_input_event_mask_t mask; + + setXcbMask(mask.mask, XCB_INPUT_BUTTON_PRESS); + setXcbMask(mask.mask, XCB_INPUT_BUTTON_RELEASE); + setXcbMask(mask.mask, XCB_INPUT_MOTION); // There is a check for enter/leave events in plain xcb enter/leave event handler, // core enter/leave events will be ignored in this case. - bitMask |= XCB_INPUT_XI_EVENT_MASK_ENTER; - bitMask |= XCB_INPUT_XI_EVENT_MASK_LEAVE; + setXcbMask(mask.mask, XCB_INPUT_ENTER); + setXcbMask(mask.mask, XCB_INPUT_LEAVE); if (isAtLeastXI22()) { - bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN; - bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE; - bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END; + setXcbMask(mask.mask, XCB_INPUT_TOUCH_BEGIN); + setXcbMask(mask.mask, XCB_INPUT_TOUCH_UPDATE); + setXcbMask(mask.mask, XCB_INPUT_TOUCH_END); } - qt_xcb_input_event_mask_t mask; mask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER; mask.header.mask_len = 1; - mask.mask = bitMask; xcb_void_cookie_t cookie = xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &mask.header); xcb_generic_error_t *error = xcb_request_check(xcb_connection(), cookie); @@ -353,17 +359,17 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) if (window == rootWindow()) return; - uint32_t mask = 0; + uint8_t mask[8] = {}; if (isAtLeastXI22()) { - mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN; - mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE; - mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END; + setXcbMask(mask, XCB_INPUT_TOUCH_BEGIN); + setXcbMask(mask, XCB_INPUT_TOUCH_UPDATE); + setXcbMask(mask, XCB_INPUT_TOUCH_END); qt_xcb_input_event_mask_t xiMask; xiMask.header.deviceid = XCB_INPUT_DEVICE_ALL_MASTER; xiMask.header.mask_len = 1; - xiMask.mask = mask; + memcpy(xiMask.mask, mask, sizeof(xiMask.mask)); xcb_void_cookie_t cookie = xcb_input_xi_select_events_checked(xcb_connection(), window, 1, &xiMask.header); @@ -376,9 +382,10 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) } } - mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS; - mask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE; - mask |= XCB_INPUT_XI_EVENT_MASK_MOTION; + memset(mask, 0, sizeof(mask)); + setXcbMask(mask, XCB_INPUT_BUTTON_PRESS); + setXcbMask(mask, XCB_INPUT_BUTTON_RELEASE); + setXcbMask(mask, XCB_INPUT_MOTION); #if QT_CONFIG(tabletevent) QSet tabletDevices; @@ -390,7 +397,7 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) tabletDevices.insert(deviceId); xiEventMask[i].header.deviceid = deviceId; xiEventMask[i].header.mask_len = 1; - xiEventMask[i].mask = mask; + memcpy(xiEventMask[i].mask, mask, sizeof(xiEventMask[i].mask)); } xcb_input_xi_select_events(xcb_connection(), window, nrTablets, &(xiEventMask.data()->header)); } @@ -406,7 +413,7 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) #endif xiEventMask[i].header.deviceid = scrollingDevice.deviceId; xiEventMask[i].header.mask_len = 1; - xiEventMask[i].mask = mask; + memcpy(xiEventMask[i].mask, mask, sizeof(xiEventMask[i].mask)); i++; } xcb_input_xi_select_events(xcb_connection(), window, i, &(xiEventMask.data()->header)); @@ -821,20 +828,23 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) bool ok = false; if (grab) { // grab - uint32_t mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS - | XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE - | XCB_INPUT_XI_EVENT_MASK_MOTION - | XCB_INPUT_XI_EVENT_MASK_ENTER - | XCB_INPUT_XI_EVENT_MASK_LEAVE - | XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN - | XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE - | XCB_INPUT_XI_EVENT_MASK_TOUCH_END; + uint8_t mask[8] = {}; + setXcbMask(mask, XCB_INPUT_BUTTON_PRESS); + setXcbMask(mask, XCB_INPUT_BUTTON_RELEASE); + setXcbMask(mask, XCB_INPUT_MOTION); + setXcbMask(mask, XCB_INPUT_ENTER); + setXcbMask(mask, XCB_INPUT_LEAVE); + if (isAtLeastXI22()) { + setXcbMask(mask, XCB_INPUT_TOUCH_BEGIN); + setXcbMask(mask, XCB_INPUT_TOUCH_UPDATE); + setXcbMask(mask, XCB_INPUT_TOUCH_END); + } for (int id : qAsConst(m_xiMasterPointerIds)) { xcb_generic_error_t *error = nullptr; auto cookie = xcb_input_xi_grab_device(xcb_connection(), w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id, XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC, - false, 1, &mask); + false, 1, reinterpret_cast(mask)); auto *reply = xcb_input_xi_grab_device_reply(xcb_connection(), cookie, &error); if (error) { qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x" -- 2.34.1