summaryrefslogtreecommitdiffstats
path: root/src/plugins
diff options
context:
space:
mode:
authorAllan Sandfeld Jensen <allan.jensen@digia.com>2014-08-21 10:45:27 +0200
committerAllan Sandfeld Jensen <allan.jensen@theqtcompany.com>2015-02-09 14:39:39 +0000
commite67ebe8ba4f59a4554a47fa26e9c374b1022d36f (patch)
treeffdb0e67ee9e167a3f84babb1b77d53d64273388 /src/plugins
parente558e71791bb0cdcf77f81fe904c61597c01ae1e (diff)
Listen to XI2 deviceChanged events to reset last position
Some drivers appears to reset their scroll positions when make the primary point. This patch listens for the device changed event and uses the information in it to update the position. Task-number: QTBUG-40829 Change-Id: If354dfde6300ceb2b81be14ea24594ab0658a6aa Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/plugins')
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h2
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp76
2 files changed, 68 insertions, 10 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 7286b6b89b..4d0596550c 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -506,6 +506,7 @@ private:
XInput2TouchDeviceData *touchDeviceForId(int id);
void xi2HandleEvent(xcb_ge_event_t *event);
void xi2HandleHierachyEvent(void *event);
+ void xi2HandleDeviceChangedEvent(void *event);
int m_xiOpCode, m_xiEventBase, m_xiErrorBase;
#ifndef QT_NO_TABLETEVENT
struct TabletData {
@@ -539,6 +540,7 @@ private:
Qt::Orientations legacyOrientations;
QPointF lastScrollPosition;
};
+ void updateScrollingDevice(ScrollingDevice& scrollingDevice, int num_classes, void *classes);
void xi2HandleScrollEvent(void *event, ScrollingDevice &scrollingDevice);
QHash<int, ScrollingDevice> m_scrollingDevices;
#endif // XCB_USE_XINPUT2
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 90d323ed34..60ae062586 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -346,6 +346,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// Listen for hotplug events
XIEventMask xiEventMask;
bitMask = XI_HierarchyChangedMask;
+ bitMask |= XI_DeviceChangedMask;
xiEventMask.deviceid = XIAllDevices;
xiEventMask.mask_len = sizeof(bitMask);
xiEventMask.mask = xiBitMask;
@@ -464,6 +465,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
xi2HandleHierachyEvent(xiEvent);
return;
}
+ if (xiEvent->evtype == XI_DeviceChanged) {
+ xi2HandleDeviceChangedEvent(xiEvent);
+ return;
+ }
+
#ifndef QT_NO_TABLETEVENT
for (int i = 0; i < m_tabletData.count(); ++i) {
if (m_tabletData.at(i).deviceId == xiEvent->deviceid) {
@@ -624,6 +630,64 @@ void QXcbConnection::xi2HandleHierachyEvent(void *event)
}
}
+void QXcbConnection::xi2HandleDeviceChangedEvent(void *event)
+{
+ xXIDeviceChangedEvent *xiEvent = reinterpret_cast<xXIDeviceChangedEvent *>(event);
+
+ // ### If a slave device changes (XIDeviceChange), we should probably run setup on it again.
+ if (xiEvent->reason != XISlaveSwitch)
+ return;
+
+#ifdef XCB_USE_XINPUT21
+ // This code handles broken scrolling device drivers that reset absolute positions
+ // when they are made active. Whenever a new slave device is made active the
+ // primary pointer sends a DeviceChanged event with XISlaveSwitch, and the new
+ // active slave in sourceid.
+
+ QHash<int, ScrollingDevice>::iterator device = m_scrollingDevices.find(xiEvent->sourceid);
+ if (device == m_scrollingDevices.end())
+ return;
+
+ int nrDevices = 0;
+ XIDeviceInfo* xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), xiEvent->sourceid, &nrDevices);
+ if (nrDevices <= 0) {
+ qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", xiEvent->sourceid);
+ return;
+ }
+ updateScrollingDevice(*device, xiDeviceInfo->num_classes, xiDeviceInfo->classes);
+ XIFreeDeviceInfo(xiDeviceInfo);
+#endif
+}
+
+void QXcbConnection::updateScrollingDevice(ScrollingDevice &scrollingDevice, int num_classes, void *classInfo)
+{
+#ifdef XCB_USE_XINPUT21
+ XIAnyClassInfo **classes = reinterpret_cast<XIAnyClassInfo**>(classInfo);
+ QPointF lastScrollPosition;
+ if (lcQpaXInput().isDebugEnabled())
+ lastScrollPosition = scrollingDevice.lastScrollPosition;
+ for (int c = 0; c < num_classes; ++c) {
+ if (classes[c]->type == XIValuatorClass) {
+ XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classes[c]);
+ const int valuatorAtom = qatom(vci->label);
+ if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
+ scrollingDevice.lastScrollPosition.setX(vci->value);
+ else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
+ scrollingDevice.lastScrollPosition.setY(vci->value);
+ }
+ }
+ if (lcQpaXInput().isDebugEnabled() && lastScrollPosition != scrollingDevice.lastScrollPosition)
+ qCDebug(lcQpaXInput, "scrolling device %d moved from (%f, %f) to (%f, %f)", scrollingDevice.deviceId,
+ lastScrollPosition.x(), lastScrollPosition.y(),
+ scrollingDevice.lastScrollPosition.x(),
+ scrollingDevice.lastScrollPosition.y());
+#else
+ Q_UNUSED(scrollingDevice);
+ Q_UNUSED(num_classes);
+ Q_UNUSED(classInfo);
+#endif
+}
+
void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
{
#ifdef XCB_USE_XINPUT21
@@ -634,19 +698,11 @@ void QXcbConnection::handleEnterEvent(const xcb_enter_notify_event_t *)
int nrDevices = 0;
XIDeviceInfo* xiDeviceInfo = XIQueryDevice(static_cast<Display *>(m_xlib_display), scrollingDevice.deviceId, &nrDevices);
if (nrDevices <= 0) {
+ qCDebug(lcQpaXInputDevices, "scrolling device %d no longer present", scrollingDevice.deviceId);
it = m_scrollingDevices.erase(it);
continue;
}
- for (int c = 0; c < xiDeviceInfo->num_classes; ++c) {
- if (xiDeviceInfo->classes[c]->type == XIValuatorClass) {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(xiDeviceInfo->classes[c]);
- const int valuatorAtom = qatom(vci->label);
- if (valuatorAtom == QXcbAtom::RelHorizScroll || valuatorAtom == QXcbAtom::RelHorizWheel)
- scrollingDevice.lastScrollPosition.setX(vci->value);
- else if (valuatorAtom == QXcbAtom::RelVertScroll || valuatorAtom == QXcbAtom::RelVertWheel)
- scrollingDevice.lastScrollPosition.setY(vci->value);
- }
- }
+ updateScrollingDevice(scrollingDevice, xiDeviceInfo->num_classes, xiDeviceInfo->classes);
XIFreeDeviceInfo(xiDeviceInfo);
++it;
}