diff options
Diffstat (limited to 'src/plugins/platforms/xcb/qxcbconnection_xi2.cpp')
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection_xi2.cpp | 596 |
1 files changed, 278 insertions, 318 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp index 0302d585b5..475afa65db 100644 --- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp @@ -47,59 +47,51 @@ #include <QDebug> #include <cmath> -#include <X11/extensions/XInput2.h> -#include <X11/extensions/XI2proto.h> +#include <xcb/xinput.h> + +using qt_xcb_input_device_event_t = xcb_input_button_press_event_t; void QXcbConnection::initializeXInput2() { - Display *xDisplay = static_cast<Display *>(m_xlib_display); - if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) { - int xiMajor = 2; -#if defined(XCB_USE_XINPUT22) - m_xi2Minor = 2; // for touch support 2.2 is enough -#elif defined(XCB_USE_XINPUT21) - m_xi2Minor = 1; // for smooth scrolling 2.1 is enough -#else - m_xi2Minor = 0; // for tablet support 2.0 is enough -#endif - qCDebug(lcQpaXInput, "Plugin build with support for XInput 2 version up " - "to %d.%d", xiMajor, m_xi2Minor); - - switch (XIQueryVersion(xDisplay, &xiMajor, &m_xi2Minor)) { - case Success: - // Server's supported version can be lower than the version we have - // announced to support. In this case Qt client will be limited by - // X server's supported version. - qCDebug(lcQpaXInput, "Using XInput version %d.%d", xiMajor, m_xi2Minor); - m_xi2Enabled = true; - xi2SetupDevices(); - xi2SelectStateEvents(); - break; - case BadRequest: // Must be an X server with XInput 1 - qCDebug(lcQpaXInput, "X server does not support XInput 2"); - break; - default: // BadValue - qCDebug(lcQpaXInput, "Internal error"); - break; - } + const xcb_query_extension_reply_t *reply = xcb_get_extension_data(m_connection, &xcb_input_id); + if (!reply || !reply->present) { + qCDebug(lcQpaXInput, "XInput extension is not present on the X server"); + return; + } + + m_xiOpCode = reply->major_opcode; + xinput_first_event = reply->first_event; + + auto xinput_query = Q_XCB_REPLY(xcb_input_xi_query_version, m_connection, 2, 2); + + if (!xinput_query || xinput_query->major_version != 2) { + qCWarning(lcQpaXInput, "X server does not support XInput 2"); + } else { + qCDebug(lcQpaXInput, "Using XInput version %d.%d", + xinput_query->major_version, xinput_query->minor_version); + m_xi2Minor = xinput_query->minor_version; + m_xi2Enabled = true; + xi2SetupDevices(); + xi2SelectStateEvents(); } } +struct qt_xcb_input_event_mask_t { + xcb_input_event_mask_t header; + uint32_t mask; +}; + void QXcbConnection::xi2SelectStateEvents() { // These state events do not depend on a specific X window, but are global // for the X client's (application's) state. - unsigned int bitMask = 0; - unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask); - XIEventMask xiEventMask; - bitMask = XI_HierarchyChangedMask; - bitMask |= XI_DeviceChangedMask; - bitMask |= XI_PropertyEventMask; - xiEventMask.deviceid = XIAllDevices; - xiEventMask.mask_len = sizeof(bitMask); - xiEventMask.mask = xiBitMask; - Display *dpy = static_cast<Display *>(m_xlib_display); - XISelectEvents(dpy, DefaultRootWindow(dpy), &xiEventMask, 1); + 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; + xcb_input_xi_select_events(m_connection, rootWindow(), 1, &xiEventMask.header); } void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) @@ -107,38 +99,42 @@ void QXcbConnection::xi2SelectDeviceEvents(xcb_window_t window) if (window == rootWindow()) return; - unsigned int bitMask = 0; - unsigned char *xiBitMask = reinterpret_cast<unsigned char *>(&bitMask); - bitMask |= XI_ButtonPressMask; - bitMask |= XI_ButtonReleaseMask; - bitMask |= XI_MotionMask; + 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; // 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 |= XI_EnterMask; - bitMask |= XI_LeaveMask; -#ifdef XCB_USE_XINPUT22 + bitMask |= XCB_INPUT_XI_EVENT_MASK_ENTER; + bitMask |= XCB_INPUT_XI_EVENT_MASK_LEAVE; if (isAtLeastXI22()) { - bitMask |= XI_TouchBeginMask; - bitMask |= XI_TouchUpdateMask; - bitMask |= XI_TouchEndMask; + bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN; + bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE; + bitMask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_END; } -#endif - XIEventMask mask; - mask.mask_len = sizeof(bitMask); - mask.mask = xiBitMask; - mask.deviceid = XIAllMasterDevices; - Display *dpy = static_cast<Display *>(m_xlib_display); - Status result = XISelectEvents(dpy, window, &mask, 1); - if (result == Success) + 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(m_connection, window, 1, &mask.header); + xcb_generic_error_t *error = xcb_request_check(m_connection, cookie); + if (error) { + qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code); + free(error); + } else { QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); - else - qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result); + } +} + +static inline qreal fixed3232ToReal(xcb_input_fp3232_t val) +{ + return qreal(val.integral) + qreal(val.frac) / (1ULL << 32); } void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) { - XIDeviceInfo *deviceInfo = reinterpret_cast<XIDeviceInfo *>(info); + auto *deviceInfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info); if (removeExisting) { #if QT_CONFIG(tabletevent) for (int i = 0; i < m_tabletData.count(); ++i) { @@ -152,53 +148,54 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) m_touchDevices.remove(deviceInfo->deviceid); } - qCDebug(lcQpaXInputDevices) << "input device " << deviceInfo->name << "ID" << deviceInfo->deviceid; + qCDebug(lcQpaXInputDevices) << "input device " << xcb_input_xi_device_info_name(deviceInfo) << "ID" << deviceInfo->deviceid; #if QT_CONFIG(tabletevent) TabletData tabletData; #endif ScrollingDevice scrollingDevice; - for (int c = 0; c < deviceInfo->num_classes; ++c) { - XIAnyClassInfo *classinfo = deviceInfo->classes[c]; + auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo); + for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) { + xcb_input_device_class_t *classinfo = classes_it.data; switch (classinfo->type) { - case XIValuatorClass: { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); + case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: { + auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo); const int valuatorAtom = qatom(vci->label); qCDebug(lcQpaXInputDevices) << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms); #if QT_CONFIG(tabletevent) if (valuatorAtom < QXcbAtom::NAtoms) { TabletData::ValuatorClassInfo info; - info.minVal = vci->min; - info.maxVal = vci->max; + info.minVal = fixed3232ToReal(vci->min); + info.maxVal = fixed3232ToReal(vci->max); info.number = vci->number; tabletData.valuatorInfo[valuatorAtom] = info; } #endif // QT_CONFIG(tabletevent) if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) - scrollingDevice.lastScrollPosition.setX(vci->value); + scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value)); else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) - scrollingDevice.lastScrollPosition.setY(vci->value); + scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value)); break; } -#ifdef XCB_USE_XINPUT21 - case XIScrollClass: { - XIScrollClassInfo *sci = reinterpret_cast<XIScrollClassInfo *>(classinfo); - if (sci->scroll_type == XIScrollTypeVertical) { + case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: { + auto *sci = reinterpret_cast<xcb_input_scroll_class_t *>(classinfo); + if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) { scrollingDevice.orientations |= Qt::Vertical; scrollingDevice.verticalIndex = sci->number; - scrollingDevice.verticalIncrement = sci->increment; - } - else if (sci->scroll_type == XIScrollTypeHorizontal) { + scrollingDevice.verticalIncrement = fixed3232ToReal(sci->increment); + } else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) { scrollingDevice.orientations |= Qt::Horizontal; scrollingDevice.horizontalIndex = sci->number; - scrollingDevice.horizontalIncrement = sci->increment; + scrollingDevice.horizontalIncrement = fixed3232ToReal(sci->increment); } break; } - case XIButtonClass: { - XIButtonClassInfo *bci = reinterpret_cast<XIButtonClassInfo *>(classinfo); + case XCB_INPUT_DEVICE_CLASS_TYPE_BUTTON: { + auto *bci = reinterpret_cast<xcb_input_button_class_t *>(classinfo); + xcb_atom_t *labels = 0; if (bci->num_buttons >= 5) { - Atom label4 = bci->labels[3]; - Atom label5 = bci->labels[4]; + labels = xcb_input_button_class_labels(bci); + xcb_atom_t label4 = labels[3]; + xcb_atom_t label5 = labels[4]; // Some drivers have no labels on the wheel buttons, some have no label on just one and some have no label on // button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons. if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) && @@ -206,23 +203,20 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) scrollingDevice.legacyOrientations |= Qt::Vertical; } if (bci->num_buttons >= 7) { - Atom label6 = bci->labels[5]; - Atom label7 = bci->labels[6]; + xcb_atom_t label6 = labels[5]; + xcb_atom_t label7 = labels[6]; if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight)) scrollingDevice.legacyOrientations |= Qt::Horizontal; } qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons); break; } -#endif - case XIKeyClass: + case XCB_INPUT_DEVICE_CLASS_TYPE_KEY: qCDebug(lcQpaXInputDevices) << " it's a keyboard"; break; -#ifdef XCB_USE_XINPUT22 - case XITouchClass: + case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: // will be handled in populateTouchDevices() break; -#endif default: qCDebug(lcQpaXInputDevices) << " has class" << classinfo->type; break; @@ -237,7 +231,8 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) isTablet = true; // But we need to be careful not to take the touch and tablet-button devices as tablets. - QByteArray name = QByteArray(deviceInfo->name).toLower(); + QByteArray name = QByteArray(xcb_input_xi_device_info_name(deviceInfo), + xcb_input_xi_device_info_name_length(deviceInfo)).toLower(); QString dbgType = QLatin1String("UNKNOWN"); if (name.contains("eraser")) { isTablet = true; @@ -281,7 +276,6 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) } #endif // QT_CONFIG(tabletevent) -#ifdef XCB_USE_XINPUT21 if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { scrollingDevice.deviceId = deviceInfo->deviceid; // Only use legacy wheel button events when we don't have real scroll valuators. @@ -289,7 +283,6 @@ void QXcbConnection::xi2SetupDevice(void *info, bool removeExisting) m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice); qCDebug(lcQpaXInputDevices) << " it's a scrolling device"; } -#endif if (!isTablet) { TouchDeviceData *dev = populateTouchDevices(deviceInfo); @@ -315,23 +308,28 @@ void QXcbConnection::xi2SetupDevices() #endif m_scrollingDevices.clear(); m_touchDevices.clear(); - - Display *xDisplay = static_cast<Display *>(m_xlib_display); - int deviceCount = 0; - XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount); m_xiMasterPointerIds.clear(); - for (int i = 0; i < deviceCount; ++i) { - XIDeviceInfo deviceInfo = devices[i]; - if (deviceInfo.use == XIMasterPointer) { - m_xiMasterPointerIds.append(deviceInfo.deviceid); + + auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, XCB_INPUT_DEVICE_ALL); + if (!reply) { + qCDebug(lcQpaXInputDevices) << "failed to query devices"; + return; + } + + auto it = xcb_input_xi_query_device_infos_iterator(reply.get()); + for (; it.rem; xcb_input_xi_device_info_next(&it)) { + xcb_input_xi_device_info_t *deviceInfo = it.data; + if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_MASTER_POINTER) { + m_xiMasterPointerIds.append(deviceInfo->deviceid); continue; } - if (deviceInfo.use == XISlavePointer) // only slave pointer devices are relevant here - xi2SetupDevice(&deviceInfo, false); + // only slave pointer devices are relevant here + if (deviceInfo->type == XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER) + xi2SetupDevice(deviceInfo, false); } + if (m_xiMasterPointerIds.size() > 1) qCDebug(lcQpaXInputDevices) << "multi-pointer X detected"; - XIFreeDeviceInfo(devices); } /*! \internal @@ -376,70 +374,64 @@ void QXcbConnection::xi2SelectDeviceEventsCompatibility(xcb_window_t window) if (window == rootWindow()) return; - unsigned int mask = 0; - unsigned char *bitMask = reinterpret_cast<unsigned char *>(&mask); - Display *dpy = static_cast<Display *>(m_xlib_display); + uint32_t mask = 0; -#ifdef XCB_USE_XINPUT22 if (isAtLeastXI22()) { - mask |= XI_TouchBeginMask; - mask |= XI_TouchUpdateMask; - mask |= XI_TouchEndMask; - - XIEventMask xiMask; - xiMask.mask_len = sizeof(mask); - xiMask.mask = bitMask; - xiMask.deviceid = XIAllMasterDevices; - Status result = XISelectEvents(dpy, window, &xiMask, 1); - if (result == Success) + mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_BEGIN; + mask |= XCB_INPUT_XI_EVENT_MASK_TOUCH_UPDATE; + mask |= XCB_INPUT_XI_EVENT_MASK_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; + + xcb_void_cookie_t cookie = + xcb_input_xi_select_events_checked(m_connection, window, 1, &xiMask.header); + xcb_generic_error_t *error = xcb_request_check(m_connection, cookie); + if (error) { + qCDebug(lcQpaXInput, "failed to select events, window %x, error code %d", window, error->error_code); + free(error); + } else { QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false); - else - qCDebug(lcQpaXInput, "failed to select events, window %x, result %d", window, result); + } } -#endif - mask = XI_ButtonPressMask; - mask |= XI_ButtonReleaseMask; - mask |= XI_MotionMask; + mask = XCB_INPUT_XI_EVENT_MASK_BUTTON_PRESS; + mask |= XCB_INPUT_XI_EVENT_MASK_BUTTON_RELEASE; + mask |= XCB_INPUT_XI_EVENT_MASK_MOTION; #if QT_CONFIG(tabletevent) QSet<int> tabletDevices; if (!m_tabletData.isEmpty()) { const int nrTablets = m_tabletData.count(); - QVector<XIEventMask> xiEventMask(nrTablets); + QVector<qt_xcb_input_event_mask_t> xiEventMask(nrTablets); for (int i = 0; i < nrTablets; ++i) { int deviceId = m_tabletData.at(i).deviceId; tabletDevices.insert(deviceId); - xiEventMask[i].deviceid = deviceId; - xiEventMask[i].mask_len = sizeof(mask); - xiEventMask[i].mask = bitMask; + xiEventMask[i].header.deviceid = deviceId; + xiEventMask[i].header.mask_len = 1; + xiEventMask[i].mask = mask; } - XISelectEvents(dpy, window, xiEventMask.data(), nrTablets); + xcb_input_xi_select_events(m_connection, window, nrTablets, &(xiEventMask.data()->header)); } #endif -#ifdef XCB_USE_XINPUT21 if (!m_scrollingDevices.isEmpty()) { - QVector<XIEventMask> xiEventMask(m_scrollingDevices.size()); + QVector<qt_xcb_input_event_mask_t> xiEventMask(m_scrollingDevices.size()); int i = 0; for (const ScrollingDevice& scrollingDevice : qAsConst(m_scrollingDevices)) { #if QT_CONFIG(tabletevent) if (tabletDevices.contains(scrollingDevice.deviceId)) continue; // All necessary events are already captured. #endif - xiEventMask[i].deviceid = scrollingDevice.deviceId; - xiEventMask[i].mask_len = sizeof(mask); - xiEventMask[i].mask = bitMask; + xiEventMask[i].header.deviceid = scrollingDevice.deviceId; + xiEventMask[i].header.mask_len = 1; + xiEventMask[i].mask = mask; i++; } - XISelectEvents(dpy, window, xiEventMask.data(), i); + xcb_input_xi_select_events(m_connection, window, i, &(xiEventMask.data()->header)); } -#endif - -#if !QT_CONFIG(tabletevent) && !defined(XCB_USE_XINPUT21) - Q_UNUSED(bitMask); - Q_UNUSED(dpy); -#endif } QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id) @@ -452,39 +444,38 @@ QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id) QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info) { - XIDeviceInfo *deviceinfo = reinterpret_cast<XIDeviceInfo *>(info); + auto *deviceinfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info); QTouchDevice::Capabilities caps = 0; int type = -1; int maxTouchPoints = 1; bool isTouchDevice = false; bool hasRelativeCoords = false; TouchDeviceData dev; - for (int i = 0; i < deviceinfo->num_classes; ++i) { - XIAnyClassInfo *classinfo = deviceinfo->classes[i]; + auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceinfo); + for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) { + xcb_input_device_class_t *classinfo = classes_it.data; switch (classinfo->type) { -#ifdef XCB_USE_XINPUT22 - case XITouchClass: { - XITouchClassInfo *tci = reinterpret_cast<XITouchClassInfo *>(classinfo); + case XCB_INPUT_DEVICE_CLASS_TYPE_TOUCH: { + auto *tci = reinterpret_cast<xcb_input_touch_class_t *>(classinfo); maxTouchPoints = tci->num_touches; qCDebug(lcQpaXInputDevices, " has touch class with mode %d", tci->mode); switch (tci->mode) { - case XIDependentTouch: + case XCB_INPUT_TOUCH_MODE_DEPENDENT: type = QTouchDevice::TouchPad; break; - case XIDirectTouch: + case XCB_INPUT_TOUCH_MODE_DIRECT: type = QTouchDevice::TouchScreen; break; } break; } -#endif // XCB_USE_XINPUT22 - case XIValuatorClass: { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo); + case XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR: { + auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classinfo); const QXcbAtom::Atom valuatorAtom = qatom(vci->label); if (valuatorAtom < QXcbAtom::NAtoms) { TouchDeviceData::ValuatorClassInfo info; - info.min = vci->min; - info.max = vci->max; + info.min = fixed3232ToReal(vci->min); + info.max = fixed3232ToReal(vci->max); info.number = vci->number; info.label = valuatorAtom; dev.valuatorInfo.append(info); @@ -502,16 +493,16 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info caps |= QTouchDevice::Pressure; else if (valuatorAtom == QXcbAtom::RelX) { hasRelativeCoords = true; - dev.size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution); + dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution); } else if (valuatorAtom == QXcbAtom::RelY) { hasRelativeCoords = true; - dev.size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); + dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution); } else if (valuatorAtom == QXcbAtom::AbsX) { caps |= QTouchDevice::Position; - dev.size.setWidth((vci->max - vci->min) * 1000.0 / vciResolution); + dev.size.setWidth((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution); } else if (valuatorAtom == QXcbAtom::AbsY) { caps |= QTouchDevice::Position; - dev.size.setHeight((vci->max - vci->min) * 1000.0 / vciResolution); + dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution); } break; } @@ -530,7 +521,8 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info if (type >= QTouchDevice::TouchScreen && type <= QTouchDevice::TouchPad) { dev.qtTouchDevice = new QTouchDevice; - dev.qtTouchDevice->setName(QString::fromUtf8(deviceinfo->name)); + dev.qtTouchDevice->setName(QString::fromUtf8(xcb_input_xi_device_info_name(deviceinfo), + xcb_input_xi_device_info_name_length(deviceinfo))); dev.qtTouchDevice->setType((QTouchDevice::DeviceType)type); dev.qtTouchDevice->setCapabilities(caps); dev.qtTouchDevice->setMaximumTouchPoints(maxTouchPoints); @@ -543,49 +535,46 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info return isTouchDevice ? &m_touchDevices[deviceinfo->deviceid] : nullptr; } -#if defined(XCB_USE_XINPUT21) || QT_CONFIG(tabletevent) -static inline qreal fixed1616ToReal(FP1616 val) +#if QT_CONFIG(tabletevent) +static inline qreal fixed1616ToReal(xcb_input_fp1616_t val) { return qreal(val) / 0x10000; } -#endif // defined(XCB_USE_XINPUT21) || QT_CONFIG(tabletevent) +#endif // QT_CONFIG(tabletevent) void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) { - xi2PrepareXIGenericDeviceEvent(event); - xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); + auto *xiEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event); int sourceDeviceId = xiEvent->deviceid; // may be the master id - xXIDeviceEvent *xiDeviceEvent = 0; - xXIEnterEvent *xiEnterEvent = 0; + qt_xcb_input_device_event_t *xiDeviceEvent = nullptr; + xcb_input_enter_event_t *xiEnterEvent = nullptr; QXcbWindowEventListener *eventListener = 0; - switch (xiEvent->evtype) { - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_Motion: -#ifdef XCB_USE_XINPUT22 - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: -#endif + switch (xiEvent->event_type) { + case XCB_INPUT_BUTTON_PRESS: + case XCB_INPUT_BUTTON_RELEASE: + case XCB_INPUT_MOTION: + case XCB_INPUT_TOUCH_BEGIN: + case XCB_INPUT_TOUCH_UPDATE: + case XCB_INPUT_TOUCH_END: { - xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + xiDeviceEvent = xiEvent; eventListener = windowEventListenerFromId(xiDeviceEvent->event); sourceDeviceId = xiDeviceEvent->sourceid; // use the actual device id instead of the master break; } - case XI_Enter: - case XI_Leave: { - xiEnterEvent = reinterpret_cast<xXIEnterEvent *>(event); + case XCB_INPUT_ENTER: + case XCB_INPUT_LEAVE: { + xiEnterEvent = reinterpret_cast<xcb_input_enter_event_t *>(event); eventListener = windowEventListenerFromId(xiEnterEvent->event); sourceDeviceId = xiEnterEvent->sourceid; // use the actual device id instead of the master break; } - case XI_HierarchyChanged: - xi2HandleHierarchyEvent(xiEvent); + case XCB_INPUT_HIERARCHY: + xi2HandleHierarchyEvent(event); return; - case XI_DeviceChanged: - xi2HandleDeviceChangedEvent(xiEvent); + case XCB_INPUT_DEVICE_CHANGED: + xi2HandleDeviceChangedEvent(event); return; default: break; @@ -600,32 +589,30 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) #if QT_CONFIG(tabletevent) if (!xiEnterEvent) { QXcbConnection::TabletData *tablet = tabletDataForDevice(sourceDeviceId); - if (tablet && xi2HandleTabletEvent(xiEvent, tablet)) + if (tablet && xi2HandleTabletEvent(event, tablet)) return; } #endif // QT_CONFIG(tabletevent) -#ifdef XCB_USE_XINPUT21 if (ScrollingDevice *device = scrollingDeviceForId(sourceDeviceId)) - xi2HandleScrollEvent(xiEvent, *device); -#endif // XCB_USE_XINPUT21 + xi2HandleScrollEvent(event, *device); -#ifdef XCB_USE_XINPUT22 if (xiDeviceEvent) { - switch (xiDeviceEvent->evtype) { - case XI_ButtonPress: - case XI_ButtonRelease: - case XI_Motion: - if (!xi2MouseEventsDisabled() && eventListener && !(xiDeviceEvent->flags & XIPointerEmulated)) + switch (xiDeviceEvent->event_type) { + case XCB_INPUT_BUTTON_PRESS: + case XCB_INPUT_BUTTON_RELEASE: + case XCB_INPUT_MOTION: + if (!xi2MouseEventsDisabled() && eventListener && + !(xiDeviceEvent->flags & XCB_INPUT_POINTER_EVENT_FLAGS_POINTER_EMULATED)) eventListener->handleXIMouseEvent(event); break; - case XI_TouchBegin: - case XI_TouchUpdate: - case XI_TouchEnd: + case XCB_INPUT_TOUCH_BEGIN: + case XCB_INPUT_TOUCH_UPDATE: + case XCB_INPUT_TOUCH_END: if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents, "XI2 touch event type %d seq %d detail %d pos %6.1f, %6.1f root pos %6.1f, %6.1f on window %x", - event->event_type, xiDeviceEvent->sequenceNumber, xiDeviceEvent->detail, + event->event_type, xiDeviceEvent->sequence, xiDeviceEvent->detail, fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y), fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y),xiDeviceEvent->event); if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) @@ -633,14 +620,13 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event) break; } } else if (xiEnterEvent && !xi2MouseEventsDisabled() && eventListener) { - switch (xiEnterEvent->evtype) { - case XI_Enter: - case XI_Leave: + switch (xiEnterEvent->event_type) { + case XCB_INPUT_ENTER: + case XCB_INPUT_LEAVE: eventListener->handleXIEnterLeave(event); break; } } -#endif // XCB_USE_XINPUT22 } bool QXcbConnection::xi2MouseEventsDisabled() const @@ -651,7 +637,6 @@ bool QXcbConnection::xi2MouseEventsDisabled() const return xi2MouseDisabled || has_xinerama_extension; } -#ifdef XCB_USE_XINPUT22 bool QXcbConnection::isTouchScreen(int id) { auto device = touchDeviceForId(id); @@ -660,11 +645,11 @@ bool QXcbConnection::isTouchScreen(int id) void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow) { - xXIDeviceEvent *xiDeviceEvent = static_cast<xXIDeviceEvent *>(xiDevEvent); + auto *xiDeviceEvent = reinterpret_cast<xcb_input_touch_begin_event_t *>(xiDevEvent); TouchDeviceData *dev = touchDeviceForId(xiDeviceEvent->sourceid); Q_ASSERT(dev); const bool firstTouch = dev->touchPoints.isEmpty(); - if (xiDeviceEvent->evtype == XI_TouchBegin) { + if (xiDeviceEvent->event_type == XCB_INPUT_TOUCH_BEGIN) { QWindowSystemInterface::TouchPoint tp; tp.id = xiDeviceEvent->detail % INT_MAX; tp.state = Qt::TouchPointPressed; @@ -735,7 +720,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo y = touchPoint.area.center().y(); ny = y / screen->geometry().height(); } - if (xiDeviceEvent->evtype != XI_TouchEnd) { + if (xiDeviceEvent->event_type != XCB_INPUT_TOUCH_END) { if (!dev->providesTouchOrientation) { if (w == 0.0) w = touchPoint.area.width(); @@ -750,8 +735,8 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo } } - switch (xiDeviceEvent->evtype) { - case XI_TouchBegin: + switch (xiDeviceEvent->event_type) { + case XCB_INPUT_TOUCH_BEGIN: if (firstTouch) { dev->firstPressedPosition = QPointF(x, y); dev->firstPressedNormalPosition = QPointF(nx, ny); @@ -761,14 +746,12 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo // Touches must be accepted when we are grabbing touch events. Otherwise the entire sequence // will get replayed when the grab ends. if (m_xiGrab) { - // Note that XIAllowTouchEvents is known to deadlock with older libXi versions, - // for details see qtbase/src/plugins/platforms/xcb/README. This has nothing to - // do with the XInput protocol version, but is a bug in libXi implementation instead. - XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid, - xiDeviceEvent->detail, xiDeviceEvent->event, XIAcceptTouch); + xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid, + XCB_INPUT_EVENT_MODE_ACCEPT_TOUCH, + xiDeviceEvent->detail, xiDeviceEvent->event); } break; - case XI_TouchUpdate: + case XCB_INPUT_TOUCH_UPDATE: if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { qreal dx = (nx - dev->firstPressedNormalPosition.x()) * dev->size.width() * screen->geometry().width() / screen->physicalSize().width(); @@ -789,14 +772,15 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo xiDeviceEvent->detail == m_startSystemMoveResizeInfo.pointid) { QXcbWindow *window = platformWindowFromId(m_startSystemMoveResizeInfo.window); if (window) { - XIAllowTouchEvents(static_cast<Display *>(m_xlib_display), xiDeviceEvent->deviceid, - xiDeviceEvent->detail, xiDeviceEvent->event, XIRejectTouch); + xcb_input_xi_allow_events(m_connection, XCB_CURRENT_TIME, xiDeviceEvent->deviceid, + XCB_INPUT_EVENT_MODE_REJECT_TOUCH, + xiDeviceEvent->detail, xiDeviceEvent->event); window->doStartSystemMoveResize(QPoint(x, y), m_startSystemMoveResizeInfo.corner); m_startSystemMoveResizeInfo.window = XCB_NONE; } } break; - case XI_TouchEnd: + case XCB_INPUT_TOUCH_END: touchPoint.state = Qt::TouchPointReleased; if (dev->qtTouchDevice->type() == QTouchDevice::TouchPad && dev->pointPressedPosition.value(touchPoint.id) == QPointF(x, y)) { qreal dx = (nx - dev->firstPressedNormalPosition.x()) * @@ -814,7 +798,7 @@ void QXcbConnection::xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindo if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents) << " touchpoint " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition << " area " << touchPoint.area << " pressure " << touchPoint.pressure; - Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); + Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective); QWindowSystemInterface::handleTouchEvent(platformWindow->window(), xiDeviceEvent->time, dev->qtTouchDevice, dev->touchPoints.values(), modifiers); if (touchPoint.state == Qt::TouchPointReleased) // If a touchpoint was released, we can forget it, because the ID won't be reused. @@ -845,46 +829,46 @@ bool QXcbConnection::startSystemMoveResizeForTouchBegin(xcb_window_t window, con } return false; } -#endif // XCB_USE_XINPUT22 bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) { - Display *xDisplay = static_cast<Display *>(xlib_display()); bool ok = false; if (grab) { // grab - XIEventMask evmask; - unsigned char mask[XIMaskLen(XI_LASTEVENT)]; - evmask.mask = mask; - evmask.mask_len = sizeof(mask); - memset(mask, 0, sizeof(mask)); - XISetMask(mask, XI_ButtonPress); - XISetMask(mask, XI_ButtonRelease); - XISetMask(mask, XI_Motion); - XISetMask(mask, XI_Enter); - XISetMask(mask, XI_Leave); - XISetMask(mask, XI_TouchBegin); - XISetMask(mask, XI_TouchUpdate); - XISetMask(mask, XI_TouchEnd); + 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; for (int id : m_xiMasterPointerIds) { - evmask.deviceid = id; - Status result = XIGrabDevice(xDisplay, id, w, CurrentTime, None, - XIGrabModeAsync, XIGrabModeAsync, False, &evmask); - if (result != Success) { + xcb_generic_error_t *error = nullptr; + auto cookie = xcb_input_xi_grab_device(m_connection, w, XCB_CURRENT_TIME, XCB_CURSOR_NONE, id, + XCB_INPUT_GRAB_MODE_22_ASYNC, XCB_INPUT_GRAB_MODE_22_ASYNC, + false, 1, &mask); + auto *reply = xcb_input_xi_grab_device_reply(m_connection, cookie, &error); + if (error) { qCDebug(lcQpaXInput, "failed to grab events for device %d on window %x" - "(result %d)", id, w, result); + "(error code %d)", id, w, error->error_code); + free(error); } else { // Managed to grab at least one of master pointers, that should be enough // to properly dismiss windows that rely on mouse grabbing. ok = true; } + free(reply); } } else { // ungrab for (int id : m_xiMasterPointerIds) { - Status result = XIUngrabDevice(xDisplay, id, CurrentTime); - if (result != Success) - qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (result %d)", id, result); + auto cookie = xcb_input_xi_ungrab_device_checked(m_connection, XCB_CURRENT_TIME, id); + xcb_generic_error_t *error = xcb_request_check(m_connection, cookie); + if (error) { + qCDebug(lcQpaXInput, "XIUngrabDevice failed - id: %d (error code %d)", id, error->error_code); + free(error); + } } // XIUngrabDevice does not seem to wait for a reply from X server (similar to // xcb_ungrab_pointer). Ungrabbing won't fail, unless NoSuchExtension error @@ -901,9 +885,9 @@ bool QXcbConnection::xi2SetMouseGrabEnabled(xcb_window_t w, bool grab) void QXcbConnection::xi2HandleHierarchyEvent(void *event) { - xXIHierarchyEvent *xiEvent = reinterpret_cast<xXIHierarchyEvent *>(event); + auto *xiEvent = reinterpret_cast<xcb_input_hierarchy_event_t *>(event); // We only care about hotplugged devices - if (!(xiEvent->flags & (XISlaveRemoved | XISlaveAdded))) + if (!(xiEvent->flags & (XCB_INPUT_HIERARCHY_MASK_SLAVE_REMOVED | XCB_INPUT_HIERARCHY_MASK_SLAVE_ADDED))) return; xi2SetupDevices(); @@ -920,23 +904,19 @@ void QXcbConnection::xi2HandleHierarchyEvent(void *event) void QXcbConnection::xi2HandleDeviceChangedEvent(void *event) { - xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event); + auto *xiEvent = reinterpret_cast<xcb_input_device_changed_event_t *>(event); switch (xiEvent->reason) { - case XIDeviceChange: { - int nrDevices = 0; - Display *dpy = static_cast<Display *>(m_xlib_display); - XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, xiEvent->sourceid, &nrDevices); - if (nrDevices <= 0) + case XCB_INPUT_CHANGE_REASON_DEVICE_CHANGE: { + auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, xiEvent->sourceid); + if (!reply || reply->num_infos <= 0) return; - xi2SetupDevice(deviceInfo); - XIFreeDeviceInfo(deviceInfo); + auto it = xcb_input_xi_query_device_infos_iterator(reply.get()); + xi2SetupDevice(it.data); break; } - case XISlaveSwitch: { -#ifdef XCB_USE_XINPUT21 + case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: { if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid)) xi2UpdateScrollingDevice(*scrollingDevice); -#endif break; } default: @@ -945,28 +925,28 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event) } } -#ifdef XCB_USE_XINPUT21 void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice) { - int nrDevices = 0; - Display *dpy = static_cast<Display *>(m_xlib_display); - XIDeviceInfo* deviceInfo = XIQueryDevice(dpy, scrollingDevice.deviceId, &nrDevices); - if (nrDevices <= 0) { + auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, m_connection, scrollingDevice.deviceId); + if (!reply || reply->num_infos <= 0) { qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId); return; } QPointF lastScrollPosition; if (lcQpaXInputEvents().isDebugEnabled()) lastScrollPosition = scrollingDevice.lastScrollPosition; - for (int c = 0; c < deviceInfo->num_classes; ++c) { - XIAnyClassInfo *classInfo = deviceInfo->classes[c]; - if (classInfo->type == XIValuatorClass) { - XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classInfo); + + xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data; + auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo); + for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) { + xcb_input_device_class_t *classInfo = classes_it.data; + if (classInfo->type == XCB_INPUT_DEVICE_CLASS_TYPE_VALUATOR) { + auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classInfo); const int valuatorAtom = qatom(vci->label); if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) - scrollingDevice.lastScrollPosition.setX(vci->value); + scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value)); else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) - scrollingDevice.lastScrollPosition.setY(vci->value); + scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value)); } } if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice.lastScrollPosition)) @@ -974,8 +954,6 @@ void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice) lastScrollPosition.x(), lastScrollPosition.y(), scrollingDevice.lastScrollPosition.x(), scrollingDevice.lastScrollPosition.y()); - - XIFreeDeviceInfo(deviceInfo); } void QXcbConnection::xi2UpdateScrollingDevices() @@ -998,10 +976,9 @@ QXcbConnection::ScrollingDevice *QXcbConnection::scrollingDeviceForId(int id) void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice) { - xXIGenericDeviceEvent *xiEvent = reinterpret_cast<xXIGenericDeviceEvent *>(event); + auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event); - if (xiEvent->evtype == XI_Motion && scrollingDevice.orientations) { - xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice.orientations) { if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { QPoint rawDelta; QPoint angleDelta; @@ -1035,16 +1012,15 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin if (!angleDelta.isNull()) { QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); - Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); + Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective); if (modifiers & Qt::AltModifier) { std::swap(angleDelta.rx(), angleDelta.ry()); std::swap(rawDelta.rx(), rawDelta.ry()); } - QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, rawDelta, angleDelta, modifiers); + QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers); } } - } else if (xiEvent->evtype == XI_ButtonRelease && scrollingDevice.legacyOrientations) { - xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event); + } else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice.legacyOrientations) { if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { QPoint angleDelta; if (scrollingDevice.legacyOrientations & Qt::Vertical) { @@ -1062,15 +1038,14 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin if (!angleDelta.isNull()) { QPoint local(fixed1616ToReal(xiDeviceEvent->event_x), fixed1616ToReal(xiDeviceEvent->event_y)); QPoint global(fixed1616ToReal(xiDeviceEvent->root_x), fixed1616ToReal(xiDeviceEvent->root_y)); - Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective_mods); + Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(xiDeviceEvent->mods.effective); if (modifiers & Qt::AltModifier) std::swap(angleDelta.rx(), angleDelta.ry()); - QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiEvent->time, local, global, QPoint(), angleDelta, modifiers); + QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers); } } } } -#endif // XCB_USE_XINPUT21 static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int number) { @@ -1093,10 +1068,10 @@ static int xi2ValuatorOffset(const unsigned char *maskPtr, int maskLen, int numb bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value) { - const xXIDeviceEvent *xideviceevent = static_cast<const xXIDeviceEvent *>(event); - const unsigned char *buttonsMaskAddr = (const unsigned char*)&xideviceevent[1]; - const unsigned char *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4; - FP3232 *valuatorsValuesAddr = (FP3232*)(valuatorsMaskAddr + xideviceevent->valuators_len * 4); + auto *xideviceevent = static_cast<const qt_xcb_input_device_event_t *>(event); + auto *buttonsMaskAddr = reinterpret_cast<const unsigned char *>(&xideviceevent[1]); + auto *valuatorsMaskAddr = buttonsMaskAddr + xideviceevent->buttons_len * 4; + auto *valuatorsValuesAddr = reinterpret_cast<const xcb_input_fp3232_t *>(valuatorsMaskAddr + xideviceevent->valuators_len * 4); int valuatorOffset = xi2ValuatorOffset(valuatorsMaskAddr, xideviceevent->valuators_len, valuatorNum); if (valuatorOffset < 0) @@ -1107,15 +1082,6 @@ bool QXcbConnection::xi2GetValuatorValueIfSet(const void *event, int valuatorNum return true; } -void QXcbConnection::xi2PrepareXIGenericDeviceEvent(xcb_ge_event_t *event) -{ - // xcb event structs contain stuff that wasn't on the wire, the full_sequence field - // adds an extra 4 bytes and generic events cookie data is on the wire right after the standard 32 bytes. - // Move this data back to have the same layout in memory as it was on the wire - // and allow casting, overwriting the full_sequence field. - memmove((char*) event + 32, (char*) event + 36, event->length * 4); -} - Qt::MouseButton QXcbConnection::xiToQtMouseButton(uint32_t b) { switch (b) { @@ -1179,31 +1145,29 @@ static const char *pointerTypeName(QTabletEvent::PointerType ptype) { bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletData) { bool handled = true; - Display *xDisplay = static_cast<Display *>(m_xlib_display); - const xXIGenericDeviceEvent *xiEvent = static_cast<const xXIGenericDeviceEvent *>(event); - const xXIDeviceEvent *xiDeviceEvent = reinterpret_cast<const xXIDeviceEvent *>(xiEvent); + const auto *xiDeviceEvent = reinterpret_cast<const qt_xcb_input_device_event_t *>(event); - switch (xiEvent->evtype) { - case XI_ButtonPress: { + switch (xiDeviceEvent->event_type) { + case XCB_INPUT_BUTTON_PRESS: { Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); tabletData->buttons |= b; - xi2ReportTabletEvent(xiEvent, tabletData); + xi2ReportTabletEvent(event, tabletData); break; } - case XI_ButtonRelease: { + case XCB_INPUT_BUTTON_RELEASE: { Qt::MouseButton b = xiToQtMouseButton(xiDeviceEvent->detail); tabletData->buttons ^= b; - xi2ReportTabletEvent(xiEvent, tabletData); + xi2ReportTabletEvent(event, tabletData); break; } - case XI_Motion: - xi2ReportTabletEvent(xiEvent, tabletData); + case XCB_INPUT_MOTION: + xi2ReportTabletEvent(event, tabletData); break; - case XI_PropertyEvent: { + case XCB_INPUT_PROPERTY: { // This is the wacom driver's way of reporting tool proximity. // The evdev driver doesn't do it this way. - const xXIPropertyEvent *ev = reinterpret_cast<const xXIPropertyEvent *>(event); - if (ev->what == XIPropertyModified) { + const auto *ev = reinterpret_cast<const xcb_input_property_event_t *>(event); + if (ev->what == XCB_INPUT_PROPERTY_FLAG_MODIFIED) { if (ev->property == atom(QXcbAtom::WacomSerialIDs)) { enum WacomSerialIndex { _WACSER_USB_ID = 0, @@ -1213,15 +1177,12 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD _WACSER_TOOL_ID, _WACSER_COUNT }; - Atom propType; - int propFormat; - unsigned long numItems, bytesAfter; - unsigned char *data; - if (XIGetProperty(xDisplay, tabletData->deviceId, ev->property, 0, 100, - 0, AnyPropertyType, &propType, &propFormat, - &numItems, &bytesAfter, &data) == Success) { - if (propType == atom(QXcbAtom::INTEGER) && propFormat == 32 && numItems == _WACSER_COUNT) { - quint32 *ptr = reinterpret_cast<quint32 *>(data); + + auto reply = Q_XCB_REPLY(xcb_input_xi_get_property, m_connection, tabletData->deviceId, 0, + ev->property, XCB_GET_PROPERTY_TYPE_ANY, 0, 100); + if (reply) { + if (reply->type == atom(QXcbAtom::INTEGER) && reply->format == 32 && reply->num_items == _WACSER_COUNT) { + quint32 *ptr = reinterpret_cast<quint32 *>(xcb_input_xi_get_property_items(reply.get())); quint32 tool = ptr[_WACSER_TOOL_ID]; // Workaround for http://sourceforge.net/p/linuxwacom/bugs/246/ // e.g. on Thinkpad Helix, tool ID will be 0 and serial will be 1 @@ -1253,7 +1214,6 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD tabletData->deviceId, ptr[_WACSER_USB_ID], ptr[_WACSER_LAST_TOOL_SERIAL], ptr[_WACSER_LAST_TOOL_ID], ptr[_WACSER_TOOL_SERIAL], ptr[_WACSER_TOOL_ID], toolName(tabletData->tool)); } - XFree(data); } } } @@ -1269,12 +1229,12 @@ bool QXcbConnection::xi2HandleTabletEvent(const void *event, TabletData *tabletD void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletData) { - const xXIDeviceEvent *ev = reinterpret_cast<const xXIDeviceEvent *>(event); + auto *ev = reinterpret_cast<const qt_xcb_input_device_event_t *>(event); QXcbWindow *xcbWindow = platformWindowFromId(ev->event); if (!xcbWindow) return; QWindow *window = xcbWindow->window(); - const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective_mods); + const Qt::KeyboardModifiers modifiers = keyboard()->translateModifiers(ev->mods.effective); QPointF local(fixed1616ToReal(ev->event_x), fixed1616ToReal(ev->event_y)); QPointF global(fixed1616ToReal(ev->root_x), fixed1616ToReal(ev->root_y)); double pressure = 0, rotation = 0, tangentialPressure = 0; @@ -1317,7 +1277,7 @@ void QXcbConnection::xi2ReportTabletEvent(const void *event, TabletData *tabletD qCDebug(lcQpaXInputEvents, "XI2 event on tablet %d with tool %s type %s seq %d detail %d time %d " "pos %6.1f, %6.1f root pos %6.1f, %6.1f buttons 0x%x pressure %4.2lf tilt %d, %d rotation %6.2lf modifiers 0x%x", tabletData->deviceId, toolName(tabletData->tool), pointerTypeName(tabletData->pointerType), - ev->sequenceNumber, ev->detail, ev->time, + ev->sequence, ev->detail, ev->time, local.x(), local.y(), global.x(), global.y(), (int)tabletData->buttons, pressure, xTilt, yTilt, rotation, (int)modifiers); |