xcb: use QXcbScrollingDevice for a touchpad

When using XQuartz on macOS, the virtual pointer device is detected as
a touchpad, not a mouse; but QXcbConnection::xi2HandleScrollEvent()
expects the device to be an instance of QXcbScrollingDevice for storage
of some state. A touchpad that has the scrolling capability must be
that type, not a plain QPointingDevice.

Fixes: QTBUG-91402
Change-Id: I1b82766d4a3f87f656e56c0d8904def26fb0979a
Reviewed-by: Liang Qi <liang.qi@qt.io>
(cherry picked from commit f85e70c569f4aa979004889d20de8acec9a790bf)
Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
This commit is contained in:
Shawn Rutledge 2021-03-08 15:56:07 +01:00 committed by Qt Cherry-pick Bot
parent 434c2a6be6
commit 84f0b4df0e
2 changed files with 26 additions and 10 deletions

View File

@ -79,6 +79,7 @@ class QXcbWindow;
class QXcbDrag; class QXcbDrag;
class QXcbKeyboard; class QXcbKeyboard;
class QXcbScrollingDevice; class QXcbScrollingDevice;
class QXcbScrollingDevicePrivate;
class QXcbClipboard; class QXcbClipboard;
class QXcbWMSupport; class QXcbWMSupport;
class QXcbNativeInterface; class QXcbNativeInterface;
@ -284,7 +285,7 @@ private:
QSizeF size; // device size in mm QSizeF size; // device size in mm
bool providesTouchOrientation = false; bool providesTouchOrientation = false;
}; };
TouchDeviceData *populateTouchDevices(void *info); TouchDeviceData *populateTouchDevices(void *info, QXcbScrollingDevicePrivate *scrollingDeviceP);
TouchDeviceData *touchDeviceForId(int id); TouchDeviceData *touchDeviceForId(int id);
void xi2HandleEvent(xcb_ge_event_t *event); void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierarchyEvent(void *event); void xi2HandleHierarchyEvent(void *event);

View File

@ -290,12 +290,12 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
auto *sci = reinterpret_cast<xcb_input_scroll_class_t *>(classinfo); auto *sci = reinterpret_cast<xcb_input_scroll_class_t *>(classinfo);
if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) { if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_VERTICAL) {
auto dev = scrollingDevice(); auto dev = scrollingDevice();
dev->orientations |= Qt::Vertical; dev->orientations.setFlag(Qt::Vertical);
dev->verticalIndex = sci->number; dev->verticalIndex = sci->number;
dev->verticalIncrement = fixed3232ToReal(sci->increment); dev->verticalIncrement = fixed3232ToReal(sci->increment);
} else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) { } else if (sci->scroll_type == XCB_INPUT_SCROLL_TYPE_HORIZONTAL) {
auto dev = scrollingDevice(); auto dev = scrollingDevice();
dev->orientations |= Qt::Horizontal; dev->orientations.setFlag(Qt::Horizontal);
dev->horizontalIndex = sci->number; dev->horizontalIndex = sci->number;
dev->horizontalIncrement = fixed3232ToReal(sci->increment); dev->horizontalIncrement = fixed3232ToReal(sci->increment);
} }
@ -411,7 +411,7 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
} }
if (!isTablet) { if (!isTablet) {
TouchDeviceData *dev = populateTouchDevices(deviceInfo); TouchDeviceData *dev = populateTouchDevices(deviceInfo, scrollingDeviceP);
if (dev && lcQpaXInputDevices().isDebugEnabled()) { if (dev && lcQpaXInputDevices().isDebugEnabled()) {
if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen) if (dev->qtTouchDevice->type() == QInputDevice::DeviceType::TouchScreen)
qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d", qCDebug(lcQpaXInputDevices, " it's a touchscreen with type %d capabilities 0x%X max touch points %d",
@ -520,7 +520,7 @@ QXcbConnection::TouchDeviceData *QXcbConnection::touchDeviceForId(int id)
return dev; return dev;
} }
QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info) QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info, QXcbScrollingDevicePrivate *scrollingDeviceP)
{ {
auto *deviceInfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info); auto *deviceInfo = reinterpret_cast<xcb_input_xi_device_info_t *>(info);
QPointingDevice::Capabilities caps; QPointingDevice::Capabilities caps;
@ -581,6 +581,8 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
} else if (valuatorAtom == QXcbAtom::AbsY) { } else if (valuatorAtom == QXcbAtom::AbsY) {
caps |= QInputDevice::Capability::Position; caps |= QInputDevice::Capability::Position;
dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution); dev.size.setHeight((fixed3232ToReal(vci->max) - fixed3232ToReal(vci->min)) * 1000.0 / vciResolution);
} else if (valuatorAtom == QXcbAtom::RelVertWheel || valuatorAtom == QXcbAtom::RelHorizWheel) {
caps |= QInputDevice::Capability::Scroll;
} }
break; break;
} }
@ -600,11 +602,24 @@ QXcbConnection::TouchDeviceData *QXcbConnection::populateTouchDevices(void *info
if (type == QInputDevice::DeviceType::TouchScreen || type == QInputDevice::DeviceType::TouchPad) { if (type == QInputDevice::DeviceType::TouchScreen || type == QInputDevice::DeviceType::TouchPad) {
QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment)); QInputDevice *master = const_cast<QInputDevice *>(QInputDevicePrivate::fromId(deviceInfo->attachment));
Q_ASSERT(master); Q_ASSERT(master);
dev.qtTouchDevice = new QPointingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo), if (scrollingDeviceP) {
xcb_input_xi_device_info_name_length(deviceInfo)), // valuators were already discovered in QXcbConnection::xi2SetupSlavePointerDevice, so just finish initialization
deviceInfo->deviceid, scrollingDeviceP->deviceType = type;
type, QPointingDevice::PointerType::Finger, caps, maxTouchPoints, 0, scrollingDeviceP->pointerType = QPointingDevice::PointerType::Finger;
master->seatName(), QPointingDeviceUniqueId(), master); scrollingDeviceP->capabilities |= caps;
scrollingDeviceP->maximumTouchPoints = maxTouchPoints;
scrollingDeviceP->buttonCount = 3;
scrollingDeviceP->seatName = master->seatName();
dev.qtTouchDevice = new QXcbScrollingDevice(*scrollingDeviceP, master);
if (Q_UNLIKELY(!caps.testFlag(QInputDevice::Capability::Scroll)))
qCDebug(lcQpaXInputDevices) << "unexpectedly missing RelVert/HorizWheel atoms for touchpad with scroll capability" << dev.qtTouchDevice;
} else {
dev.qtTouchDevice = new QPointingDevice(QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo),
xcb_input_xi_device_info_name_length(deviceInfo)),
deviceInfo->deviceid,
type, QPointingDevice::PointerType::Finger, caps, maxTouchPoints, 0,
master->seatName(), QPointingDeviceUniqueId(), master);
}
if (caps != 0) if (caps != 0)
QWindowSystemInterface::registerInputDevice(dev.qtTouchDevice); QWindowSystemInterface::registerInputDevice(dev.qtTouchDevice);
m_touchDevices[deviceInfo->deviceid] = dev; m_touchDevices[deviceInfo->deviceid] = dev;