xcb: report wheel events from the correct device instance

Until now, all wheel events came from one "core pointer".  It's useful
in Qt Quick to tell the devices apart, because some support smooth scrolling
and some don't.

Also remove the QHash storing legacy ScrollingDevice structs, and use
a subclass of QPointingDevicePrivate instead.

Task-number: QTBUG-46412
Task-number: QTBUG-72167
Task-number: QTBUG-69433
Change-Id: Ie6a3d8dd494f981e8706b9a66a1021dfb51baec4
Reviewed-by: Liang Qi <liang.qi@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Volker Hilsheimer <volker.hilsheimer@qt.io>
This commit is contained in:
Shawn Rutledge 2020-11-26 16:38:55 +01:00
parent 50e1976437
commit ac210c73e4
8 changed files with 256 additions and 91 deletions

View File

@ -354,6 +354,25 @@ const QPointingDevice *QPointingDevicePrivate::queryTabletDevice(QInputDevice::D
return nullptr; return nullptr;
} }
/*!
\internal
Finds the device instance identified by its \a systemId.
Returns the device found, or \c nullptr if none was found.
*/
const QPointingDevice *QPointingDevicePrivate::pointingDeviceById(qint64 systemId)
{
const auto &devices = QInputDevice::devices();
for (const QInputDevice *dev : devices) {
if (dev->type() >= QPointingDevice::DeviceType::Keyboard)
continue;
const QPointingDevice *pdev = static_cast<const QPointingDevice *>(dev);
const auto devPriv = QPointingDevicePrivate::get(pdev);
if (devPriv->systemId == systemId)
return pdev;
}
return nullptr;
}
/*! /*!
\internal \internal
First, ensure that the \a cancelEvent's QTouchEvent::points() list contains First, ensure that the \a cancelEvent's QTouchEvent::points() list contains

View File

@ -132,6 +132,8 @@ public:
QPointingDevice::PointerType pointerType, QPointingDevice::PointerType pointerType,
QPointingDeviceUniqueId uniqueId, QPointingDeviceUniqueId uniqueId,
qint64 systemId = 0); qint64 systemId = 0);
static const QPointingDevice *pointingDeviceById(qint64 systemId);
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -26,6 +26,7 @@ qt_internal_add_module(XcbQpa
qxcbimage.cpp qxcbimage.h qxcbimage.cpp qxcbimage.h
qxcbintegration.cpp qxcbintegration.h qxcbintegration.cpp qxcbintegration.h
qxcbkeyboard.cpp qxcbkeyboard.h qxcbkeyboard.cpp qxcbkeyboard.h
qxcbscrollingdevice.cpp qxcbscrollingdevice_p.h
qxcbmime.cpp qxcbmime.h qxcbmime.cpp qxcbmime.h
qxcbnativeinterface.cpp qxcbnativeinterface.h qxcbnativeinterface.cpp qxcbnativeinterface.h
qxcbobject.h qxcbobject.h

View File

@ -78,6 +78,7 @@ class QXcbScreen;
class QXcbWindow; class QXcbWindow;
class QXcbDrag; class QXcbDrag;
class QXcbKeyboard; class QXcbKeyboard;
class QXcbScrollingDevicePrivate;
class QXcbClipboard; class QXcbClipboard;
class QXcbWMSupport; class QXcbWMSupport;
class QXcbNativeInterface; class QXcbNativeInterface;
@ -264,7 +265,7 @@ private:
void xi2SetupSlavePointerDevice(void *info, bool removeExisting = true, QPointingDevice *master = nullptr); void xi2SetupSlavePointerDevice(void *info, bool removeExisting = true, QPointingDevice *master = nullptr);
void xi2SetupDevices(); void xi2SetupDevices();
// TODO get rid of this: store a smaller struct in QPointingDevicePrivate::extra // TODO get rid of this: store minimal necessary info in a subclass of QPointingDevicePrivate
struct TouchDeviceData { struct TouchDeviceData {
QPointingDevice *qtTouchDevice = nullptr; QPointingDevice *qtTouchDevice = nullptr;
QHash<int, QWindowSystemInterface::TouchPoint> touchPoints; QHash<int, QWindowSystemInterface::TouchPoint> touchPoints;
@ -290,7 +291,7 @@ private:
void xi2HandleDeviceChangedEvent(void *event); void xi2HandleDeviceChangedEvent(void *event);
void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow); void xi2ProcessTouch(void *xiDevEvent, QXcbWindow *platformWindow);
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
// TODO get rid of this: store a smaller struct in QPointingDevicePrivate::extra // TODO get rid of this: store minimal necessary info in a subclass of QXcbScrollingDevice (some tablets can scroll)
struct TabletData { struct TabletData {
int deviceId = 0; int deviceId = 0;
QString name; QString name;
@ -314,21 +315,9 @@ private:
QList<TabletData> m_tabletData; QList<TabletData> m_tabletData;
TabletData *tabletDataForDevice(int id); TabletData *tabletDataForDevice(int id);
#endif // QT_CONFIG(tabletevent) #endif // QT_CONFIG(tabletevent)
// TODO get rid of this: store a smaller struct in QPointingDevicePrivate::extra void xi2HandleScrollEvent(void *event, const QPointingDevice *scrollingDevice);
struct ScrollingDevice { void xi2UpdateScrollingDevice(QXcbScrollingDevicePrivate *scrollingDevice);
int deviceId = 0; QXcbScrollingDevicePrivate *scrollingDeviceForId(int id);
int verticalIndex = 0;
int horizontalIndex = 0;
double verticalIncrement = 0;
double horizontalIncrement = 0;
Qt::Orientations orientations;
Qt::Orientations legacyOrientations;
QPointF lastScrollPosition;
};
QHash<int, ScrollingDevice> m_scrollingDevices;
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
void xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice);
ScrollingDevice *scrollingDeviceForId(int id);
static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value); static bool xi2GetValuatorValueIfSet(const void *event, int valuatorNum, double *value);

View File

@ -39,6 +39,7 @@
#include "qxcbconnection.h" #include "qxcbconnection.h"
#include "qxcbkeyboard.h" #include "qxcbkeyboard.h"
#include "qxcbscrollingdevice_p.h"
#include "qxcbscreen.h" #include "qxcbscreen.h"
#include "qxcbwindow.h" #include "qxcbwindow.h"
#include "QtCore/qmetaobject.h" #include "QtCore/qmetaobject.h"
@ -243,15 +244,24 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
} }
} }
#endif #endif
m_scrollingDevices.remove(deviceInfo->deviceid);
m_touchDevices.remove(deviceInfo->deviceid); m_touchDevices.remove(deviceInfo->deviceid);
} }
qCDebug(lcQpaXInputDevices) << "input device " << xcb_input_xi_device_info_name(deviceInfo) << "ID" << deviceInfo->deviceid; const QByteArray nameRaw = QByteArray(xcb_input_xi_device_info_name(deviceInfo),
xcb_input_xi_device_info_name_length(deviceInfo));
const QString name = QString::fromUtf8(nameRaw);
qCDebug(lcQpaXInputDevices) << "input device " << name << "ID" << deviceInfo->deviceid;
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
TabletData tabletData; TabletData tabletData;
#endif #endif
ScrollingDevice scrollingDevice; QXcbScrollingDevicePrivate *scrollingDeviceP = nullptr;
auto scrollingDevice = [&]() {
if (!scrollingDeviceP)
scrollingDeviceP = new QXcbScrollingDevicePrivate(name, deviceInfo->deviceid,
QInputDevice::Capability::Scroll);
return scrollingDeviceP;
};
int buttonCount = 32; int buttonCount = 32;
auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo); auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) { for (; classes_it.rem; xcb_input_device_class_next(&classes_it)) {
@ -271,21 +281,23 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
} }
#endif // QT_CONFIG(tabletevent) #endif // QT_CONFIG(tabletevent)
if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value)); scrollingDevice()->lastScrollPosition.setX(fixed3232ToReal(vci->value));
else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value)); scrollingDevice()->lastScrollPosition.setY(fixed3232ToReal(vci->value));
break; break;
} }
case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: { case XCB_INPUT_DEVICE_CLASS_TYPE_SCROLL: {
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) {
scrollingDevice.orientations |= Qt::Vertical; auto dev = scrollingDevice();
scrollingDevice.verticalIndex = sci->number; dev->orientations |= Qt::Vertical;
scrollingDevice.verticalIncrement = fixed3232ToReal(sci->increment); dev->verticalIndex = sci->number;
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) {
scrollingDevice.orientations |= Qt::Horizontal; auto dev = scrollingDevice();
scrollingDevice.horizontalIndex = sci->number; dev->orientations |= Qt::Horizontal;
scrollingDevice.horizontalIncrement = fixed3232ToReal(sci->increment); dev->horizontalIndex = sci->number;
dev->horizontalIncrement = fixed3232ToReal(sci->increment);
} }
break; break;
} }
@ -300,13 +312,13 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
// button 4 and the wrong one on button 5. So we just check that they are not labelled with unrelated buttons. // 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) && if ((!label4 || qatom(label4) == QXcbAtom::ButtonWheelUp || qatom(label4) == QXcbAtom::ButtonWheelDown) &&
(!label5 || qatom(label5) == QXcbAtom::ButtonWheelUp || qatom(label5) == QXcbAtom::ButtonWheelDown)) (!label5 || qatom(label5) == QXcbAtom::ButtonWheelUp || qatom(label5) == QXcbAtom::ButtonWheelDown))
scrollingDevice.legacyOrientations |= Qt::Vertical; scrollingDevice()->legacyOrientations |= Qt::Vertical;
} }
if (bci->num_buttons >= 7) { if (bci->num_buttons >= 7) {
xcb_atom_t label6 = labels[5]; xcb_atom_t label6 = labels[5];
xcb_atom_t label7 = labels[6]; xcb_atom_t label7 = labels[6];
if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight)) if ((!label6 || qatom(label6) == QXcbAtom::ButtonHorizWheelLeft) && (!label7 || qatom(label7) == QXcbAtom::ButtonHorizWheelRight))
scrollingDevice.legacyOrientations |= Qt::Horizontal; scrollingDevice()->legacyOrientations |= Qt::Horizontal;
} }
buttonCount = bci->num_buttons; buttonCount = bci->num_buttons;
qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons); qCDebug(lcQpaXInputDevices, " has %d buttons", bci->num_buttons);
@ -332,9 +344,7 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
isTablet = true; isTablet = true;
// But we need to be careful not to take the touch and tablet-button devices as tablets. // But we need to be careful not to take the touch and tablet-button devices as tablets.
QByteArray name = QByteArray(xcb_input_xi_device_info_name(deviceInfo), QByteArray nameLower = nameRaw.toLower();
xcb_input_xi_device_info_name_length(deviceInfo));
QByteArray nameLower = name.toLower();
QString dbgType = QLatin1String("UNKNOWN"); QString dbgType = QLatin1String("UNKNOWN");
if (nameLower.contains("eraser")) { if (nameLower.contains("eraser")) {
isTablet = true; isTablet = true;
@ -377,7 +387,7 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
if (isTablet) { if (isTablet) {
tabletData.deviceId = deviceInfo->deviceid; tabletData.deviceId = deviceInfo->deviceid;
tabletData.name = QLatin1String(name); tabletData.name = name;
m_tabletData.append(tabletData); m_tabletData.append(tabletData);
qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType; qCDebug(lcQpaXInputDevices) << " it's a tablet with pointer type" << dbgType;
QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None; QPointingDevice::Capabilities capsOverride = QInputDevice::Capability::None;
@ -394,11 +404,9 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
} }
#endif // QT_CONFIG(tabletevent) #endif // QT_CONFIG(tabletevent)
if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) { if (scrollingDeviceP) {
scrollingDevice.deviceId = deviceInfo->deviceid;
// Only use legacy wheel button events when we don't have real scroll valuators. // Only use legacy wheel button events when we don't have real scroll valuators.
scrollingDevice.legacyOrientations &= ~scrollingDevice.orientations; scrollingDeviceP->legacyOrientations &= ~scrollingDeviceP->orientations;
m_scrollingDevices.insert(scrollingDevice.deviceId, scrollingDevice);
qCDebug(lcQpaXInputDevices) << " it's a scrolling device"; qCDebug(lcQpaXInputDevices) << " it's a scrolling device";
} }
@ -420,12 +428,18 @@ void QXcbConnection::xi2SetupSlavePointerDevice(void *info, bool removeExisting,
if (!QInputDevicePrivate::fromId(deviceInfo->deviceid)) { if (!QInputDevicePrivate::fromId(deviceInfo->deviceid)) {
qCDebug(lcQpaXInputDevices) << " it's a mouse"; qCDebug(lcQpaXInputDevices) << " it's a mouse";
QInputDevice::Capabilities caps = QInputDevice::Capability::Position | QInputDevice::Capability::Hover; QInputDevice::Capabilities caps = QInputDevice::Capability::Position | QInputDevice::Capability::Hover;
if (scrollingDevice.orientations || scrollingDevice.legacyOrientations) if (scrollingDeviceP) {
caps.setFlag(QInputDevice::Capability::Scroll); scrollingDeviceP->capabilities |= caps;
QWindowSystemInterface::registerInputDevice(new QPointingDevice( scrollingDeviceP->buttonCount = buttonCount;
QString::fromUtf8(xcb_input_xi_device_info_name(deviceInfo)), deviceInfo->deviceid, if (master)
QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic, scrollingDeviceP->seatName = master->seatName();
caps, 1, buttonCount, (master ? master->seatName() : QString()), QPointingDeviceUniqueId(), master)); QWindowSystemInterface::registerInputDevice(new QXcbScrollingMouse(*scrollingDeviceP, master));
} else {
QWindowSystemInterface::registerInputDevice(new QPointingDevice(
name, deviceInfo->deviceid,
QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
caps, 1, buttonCount, (master ? master->seatName() : QString()), QPointingDeviceUniqueId(), master));
}
} }
} }
@ -434,7 +448,6 @@ void QXcbConnection::xi2SetupDevices()
#if QT_CONFIG(tabletevent) #if QT_CONFIG(tabletevent)
m_tabletData.clear(); m_tabletData.clear();
#endif #endif
m_scrollingDevices.clear();
m_touchDevices.clear(); m_touchDevices.clear();
m_xiMasterPointerIds.clear(); m_xiMasterPointerIds.clear();
@ -659,8 +672,8 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
} }
#endif // QT_CONFIG(tabletevent) #endif // QT_CONFIG(tabletevent)
if (ScrollingDevice *device = scrollingDeviceForId(sourceDeviceId)) if (auto device = QPointingDevicePrivate::pointingDeviceById(sourceDeviceId))
xi2HandleScrollEvent(event, *device); xi2HandleScrollEvent(event, device);
if (xiDeviceEvent) { if (xiDeviceEvent) {
switch (xiDeviceEvent->event_type) { switch (xiDeviceEvent->event_type) {
@ -968,8 +981,8 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
break; break;
} }
case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: { case XCB_INPUT_CHANGE_REASON_SLAVE_SWITCH: {
if (ScrollingDevice *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid)) if (auto *scrollingDevice = scrollingDeviceForId(xiEvent->sourceid))
xi2UpdateScrollingDevice(*scrollingDevice); xi2UpdateScrollingDevice(scrollingDevice);
break; break;
} }
default: default:
@ -978,16 +991,16 @@ void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
} }
} }
void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice) void QXcbConnection::xi2UpdateScrollingDevice(QXcbScrollingDevicePrivate *scrollingDevice)
{ {
auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice.deviceId); auto reply = Q_XCB_REPLY(xcb_input_xi_query_device, xcb_connection(), scrollingDevice->systemId);
if (!reply || reply->num_infos <= 0) { if (!reply || reply->num_infos <= 0) {
qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId); qCDebug(lcQpaXInputDevices, "scrolling device %lld no longer present", scrollingDevice->systemId);
return; return;
} }
QPointF lastScrollPosition; QPointF lastScrollPosition;
if (lcQpaXInputEvents().isDebugEnabled()) if (lcQpaXInputEvents().isDebugEnabled())
lastScrollPosition = scrollingDevice.lastScrollPosition; lastScrollPosition = scrollingDevice->lastScrollPosition;
xcb_input_xi_device_info_t *deviceInfo = xcb_input_xi_query_device_infos_iterator(reply.get()).data; 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); auto classes_it = xcb_input_xi_device_info_classes_iterator(deviceInfo);
@ -997,68 +1010,75 @@ void QXcbConnection::xi2UpdateScrollingDevice(ScrollingDevice &scrollingDevice)
auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classInfo); auto *vci = reinterpret_cast<xcb_input_valuator_class_t *>(classInfo);
const int valuatorAtom = qatom(vci->label); const int valuatorAtom = qatom(vci->label);
if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel) if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
scrollingDevice.lastScrollPosition.setX(fixed3232ToReal(vci->value)); scrollingDevice->lastScrollPosition.setX(fixed3232ToReal(vci->value));
else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel) else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
scrollingDevice.lastScrollPosition.setY(fixed3232ToReal(vci->value)); scrollingDevice->lastScrollPosition.setY(fixed3232ToReal(vci->value));
} }
} }
if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice.lastScrollPosition)) if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled() && lastScrollPosition != scrollingDevice->lastScrollPosition))
qCDebug(lcQpaXInputEvents, "scrolling device %d moved from (%f, %f) to (%f, %f)", scrollingDevice.deviceId, qCDebug(lcQpaXInputEvents, "scrolling device %lld moved from (%f, %f) to (%f, %f)", scrollingDevice->systemId,
lastScrollPosition.x(), lastScrollPosition.y(), lastScrollPosition.x(), lastScrollPosition.y(),
scrollingDevice.lastScrollPosition.x(), scrollingDevice->lastScrollPosition.x(),
scrollingDevice.lastScrollPosition.y()); scrollingDevice->lastScrollPosition.y());
} }
void QXcbConnection::xi2UpdateScrollingDevices() void QXcbConnection::xi2UpdateScrollingDevices()
{ {
QHash<int, ScrollingDevice>::iterator it = m_scrollingDevices.begin(); const auto &devices = QInputDevice::devices();
const QHash<int, ScrollingDevice>::iterator end = m_scrollingDevices.end(); for (const QInputDevice *dev : devices) {
while (it != end) { if (dev->capabilities().testFlag(QInputDevice::Capability::Scroll)) {
xi2UpdateScrollingDevice(it.value()); const auto devPriv = QPointingDevicePrivate::get(static_cast<QPointingDevice *>(const_cast<QInputDevice *>(dev)));
++it; xi2UpdateScrollingDevice(static_cast<QXcbScrollingDevicePrivate *>(devPriv));
}
} }
} }
QXcbConnection::ScrollingDevice *QXcbConnection::scrollingDeviceForId(int id) QXcbScrollingDevicePrivate *QXcbConnection::scrollingDeviceForId(int id)
{ {
ScrollingDevice *dev = nullptr; const QPointingDevice *dev = QPointingDevicePrivate::pointingDeviceById(id);
if (m_scrollingDevices.contains(id)) if (!dev)
dev = &m_scrollingDevices[id]; return nullptr;
return dev; if (!dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
return nullptr;
auto devPriv = QPointingDevicePrivate::get(const_cast<QPointingDevice *>(dev));
return static_cast<QXcbScrollingDevicePrivate *>(devPriv);
} }
void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice) void QXcbConnection::xi2HandleScrollEvent(void *event, const QPointingDevice *dev)
{ {
auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event); auto *xiDeviceEvent = reinterpret_cast<qt_xcb_input_device_event_t *>(event);
if (!dev->capabilities().testFlag(QInputDevice::Capability::Scroll))
return;
const auto scrollingDevice = static_cast<const QXcbScrollingDevicePrivate *>(QPointingDevicePrivate::get(dev));
if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice.orientations) { if (xiDeviceEvent->event_type == XCB_INPUT_MOTION && scrollingDevice->orientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint rawDelta; QPoint rawDelta;
QPoint angleDelta; QPoint angleDelta;
double value; double value;
if (scrollingDevice.orientations & Qt::Vertical) { if (scrollingDevice->orientations & Qt::Vertical) {
if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.verticalIndex, &value)) { if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->verticalIndex, &value)) {
double delta = scrollingDevice.lastScrollPosition.y() - value; double delta = scrollingDevice->lastScrollPosition.y() - value;
scrollingDevice.lastScrollPosition.setY(value); scrollingDevice->lastScrollPosition.setY(value);
angleDelta.setY((delta / scrollingDevice.verticalIncrement) * 120); angleDelta.setY((delta / scrollingDevice->verticalIncrement) * 120);
// With most drivers the increment is 1 for wheels. // With most drivers the increment is 1 for wheels.
// For libinput it is hardcoded to a useless 15. // For libinput it is hardcoded to a useless 15.
// For a proper touchpad driver it should be in the same order of magnitude as 120 // For a proper touchpad driver it should be in the same order of magnitude as 120
if (scrollingDevice.verticalIncrement > 15) if (scrollingDevice->verticalIncrement > 15)
rawDelta.setY(delta); rawDelta.setY(delta);
else if (scrollingDevice.verticalIncrement < -15) else if (scrollingDevice->verticalIncrement < -15)
rawDelta.setY(-delta); rawDelta.setY(-delta);
} }
} }
if (scrollingDevice.orientations & Qt::Horizontal) { if (scrollingDevice->orientations & Qt::Horizontal) {
if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice.horizontalIndex, &value)) { if (xi2GetValuatorValueIfSet(xiDeviceEvent, scrollingDevice->horizontalIndex, &value)) {
double delta = scrollingDevice.lastScrollPosition.x() - value; double delta = scrollingDevice->lastScrollPosition.x() - value;
scrollingDevice.lastScrollPosition.setX(value); scrollingDevice->lastScrollPosition.setX(value);
angleDelta.setX((delta / scrollingDevice.horizontalIncrement) * 120); angleDelta.setX((delta / scrollingDevice->horizontalIncrement) * 120);
// See comment under vertical // See comment under vertical
if (scrollingDevice.horizontalIncrement > 15) if (scrollingDevice->horizontalIncrement > 15)
rawDelta.setX(delta); rawDelta.setX(delta);
else if (scrollingDevice.horizontalIncrement < -15) else if (scrollingDevice->horizontalIncrement < -15)
rawDelta.setX(-delta); rawDelta.setX(-delta);
} }
} }
@ -1070,20 +1090,22 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
angleDelta = angleDelta.transposed(); angleDelta = angleDelta.transposed();
rawDelta = rawDelta.transposed(); rawDelta = rawDelta.transposed();
} }
qCDebug(lcQpaXInputEvents) << "scroll wheel @ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta; qCDebug(lcQpaXInputEvents) << "scroll wheel from device" << scrollingDevice->systemId
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, rawDelta, angleDelta, modifiers); << "@ window pos" << local << "delta px" << rawDelta << "angle" << angleDelta;
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
local, global, rawDelta, angleDelta, modifiers);
} }
} }
} else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice.legacyOrientations) { } else if (xiDeviceEvent->event_type == XCB_INPUT_BUTTON_RELEASE && scrollingDevice->legacyOrientations) {
if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) { if (QXcbWindow *platformWindow = platformWindowFromId(xiDeviceEvent->event)) {
QPoint angleDelta; QPoint angleDelta;
if (scrollingDevice.legacyOrientations & Qt::Vertical) { if (scrollingDevice->legacyOrientations & Qt::Vertical) {
if (xiDeviceEvent->detail == 4) if (xiDeviceEvent->detail == 4)
angleDelta.setY(120); angleDelta.setY(120);
else if (xiDeviceEvent->detail == 5) else if (xiDeviceEvent->detail == 5)
angleDelta.setY(-120); angleDelta.setY(-120);
} }
if (scrollingDevice.legacyOrientations & Qt::Horizontal) { if (scrollingDevice->legacyOrientations & Qt::Horizontal) {
if (xiDeviceEvent->detail == 6) if (xiDeviceEvent->detail == 6)
angleDelta.setX(120); angleDelta.setX(120);
else if (xiDeviceEvent->detail == 7) else if (xiDeviceEvent->detail == 7)
@ -1096,7 +1118,8 @@ void QXcbConnection::xi2HandleScrollEvent(void *event, ScrollingDevice &scrollin
if (modifiers & Qt::AltModifier) if (modifiers & Qt::AltModifier)
angleDelta = angleDelta.transposed(); angleDelta = angleDelta.transposed();
qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta; qCDebug(lcQpaXInputEvents) << "scroll wheel (button" << xiDeviceEvent->detail << ") @ window pos" << local << "delta angle" << angleDelta;
QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, local, global, QPoint(), angleDelta, modifiers); QWindowSystemInterface::handleWheelEvent(platformWindow->window(), xiDeviceEvent->time, dev,
local, global, QPoint(), angleDelta, modifiers);
} }
} }
} }

View File

@ -0,0 +1,50 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qxcbscrollingdevice_p.h"
QT_BEGIN_NAMESPACE
QXcbScrollingDevicePrivate::QXcbScrollingDevicePrivate(const QString &name, qint64 id, QInputDevice::Capabilities caps,
int buttonCount, const QString &seatName)
: QPointingDevicePrivate(name, id, QInputDevice::DeviceType::Mouse, QPointingDevice::PointerType::Generic,
caps, 1, buttonCount, seatName)
{
}
QT_END_NAMESPACE

View File

@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2020 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see https://www.qt.io/terms-conditions. For further
** information use the contact form at https://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 3 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL3 included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 3 requirements
** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 2.0 or (at your option) the GNU General
** Public license version 3 or any later version approved by the KDE Free
** Qt Foundation. The licenses are as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
** included in the packaging of this file. Please review the following
** information to ensure the GNU General Public License requirements will
** be met: https://www.gnu.org/licenses/gpl-2.0.html and
** https://www.gnu.org/licenses/gpl-3.0.html.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QXCBSCROLLINGDEVICE_P_H
#define QXCBSCROLLINGDEVICE_P_H
#include <QtGui/private/qpointingdevice_p.h>
QT_BEGIN_NAMESPACE
/*! \internal
On the xcb platform, if a device's QPointingDevice::capabilities() includes
QInputDevice::Capability::Scroll, then its d-pointer must point to
an instance of this subclass, which tracks the scrolling valuators.
*/
class QXcbScrollingDevicePrivate : public QPointingDevicePrivate
{
Q_DECLARE_PUBLIC(QPointingDevice)
public:
QXcbScrollingDevicePrivate(const QString &name, qint64 id, QPointingDevice::Capabilities caps,
int buttonCount = 3, const QString &seatName = QString());
// scrolling-related data
int verticalIndex = 0;
int horizontalIndex = 0;
double verticalIncrement = 0;
double horizontalIncrement = 0;
Qt::Orientations orientations;
Qt::Orientations legacyOrientations;
mutable QPointF lastScrollPosition;
// end of scrolling-related data
};
class QXcbScrollingMouse : public QPointingDevice
{
public:
QXcbScrollingMouse(QXcbScrollingDevicePrivate &d, QObject *parent)
: QPointingDevice(d, parent) {}
};
QT_END_NAMESPACE
#endif // QXCBSCROLLINGDEVICE_P_H

View File

@ -13,6 +13,7 @@ SOURCES = \
qxcbconnection.cpp \ qxcbconnection.cpp \
qxcbintegration.cpp \ qxcbintegration.cpp \
qxcbkeyboard.cpp \ qxcbkeyboard.cpp \
qxcbscrollingdevice.cpp \
qxcbmime.cpp \ qxcbmime.cpp \
qxcbscreen.cpp \ qxcbscreen.cpp \
qxcbwindow.cpp \ qxcbwindow.cpp \
@ -35,6 +36,7 @@ HEADERS = \
qxcbconnection.h \ qxcbconnection.h \
qxcbintegration.h \ qxcbintegration.h \
qxcbkeyboard.h \ qxcbkeyboard.h \
qxcbscrollingdevice_p.h \
qxcbmime.h \ qxcbmime.h \
qxcbobject.h \ qxcbobject.h \
qxcbscreen.h \ qxcbscreen.h \