From a875503d9e001a05eb3c0998f6c1292f0fefc4e1 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. Change-Id: Id22131e075059cea783b5be0691a673a457c7364 Reviewed-by: Shawn Rutledge --- .../platforms/xcb/qxcbconnection_xi2.cpp | 53 +++++++++++-------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index c0bd2c6165..4c39c7ee3e 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -55,9 +55,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 @@ -65,9 +71,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); } @@ -76,23 +82,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; 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); @@ -974,22 +980,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; + 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()) { - 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); } 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"