summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShawn Rutledge <shawn.rutledge@digia.com>2013-07-04 10:19:00 +0200
committerThe Qt Project <gerrit-noreply@qt-project.org>2013-07-05 10:21:33 +0200
commitce2fe90faad84a6e3a976a6f111a0fa4883937d9 (patch)
tree13ba08d78e238e73c50d88c5c6756c0aace3991d
parent785bc64f8e743ac269f15cbe7fecba93d3d507ac (diff)
xcb XI2: simplify and generalize tablet detection
We're looking for any tablet which has appropriate valuators, not just Wacom tablets that have recognizable names. The name recognition was always brittle and already stopped working, probably because of changed udev rules or something like that. Change-Id: Ib3a6dfdd9972b16f08f270e3f0a1aa54d6660c9f Reviewed-by: Friedemann Kleint <Friedemann.Kleint@digia.com>
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.cpp7
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection.h5
-rw-r--r--src/plugins/platforms/xcb/qxcbconnection_xi2.cpp161
3 files changed, 74 insertions, 99 deletions
diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp
index 209c7bb187..ca7896995f 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection.cpp
@@ -1400,11 +1400,16 @@ static const char * xcb_atomnames = {
"_XSETTINGS_SETTINGS"
};
-xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom)
+xcb_atom_t QXcbConnection::atom(QXcbAtom::Atom atom) const
{
return m_allAtoms[atom];
}
+QXcbAtom::Atom QXcbConnection::qatom(xcb_atom_t xatom) const
+{
+ return static_cast<QXcbAtom::Atom>(qFind(m_allAtoms, m_allAtoms + QXcbAtom::NAtoms, xatom) - m_allAtoms);
+}
+
void QXcbConnection::initializeAllAtoms() {
const char *names[QXcbAtom::NAtoms];
const char *ptr = xcb_atomnames;
diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h
index 883ee95e22..98d55abde1 100644
--- a/src/plugins/platforms/xcb/qxcbconnection.h
+++ b/src/plugins/platforms/xcb/qxcbconnection.h
@@ -345,7 +345,8 @@ public:
const QList<QXcbScreen *> &screens() const { return m_screens; }
int primaryScreen() const { return m_primaryScreen; }
- xcb_atom_t atom(QXcbAtom::Atom atom);
+ xcb_atom_t atom(QXcbAtom::Atom atom) const;
+ QXcbAtom::Atom qatom(xcb_atom_t atom) const;
xcb_atom_t internAtom(const char *name);
QByteArray atomName(xcb_atom_t atom);
@@ -477,8 +478,6 @@ private:
};
QHash<int, ValuatorClassInfo> valuatorInfo;
};
- void xi2QueryTabletData(void *dev, TabletData *tabletData); // use no XI stuff in headers
- void xi2SetupTabletDevices();
bool xi2HandleTabletEvent(void *event, TabletData *tabletData);
void xi2ReportTabletEvent(const TabletData &tabletData, void *event);
QVector<TabletData> m_tabletData;
diff --git a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
index 991c82eaaa..b95d276c18 100644
--- a/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
+++ b/src/plugins/platforms/xcb/qxcbconnection_xi2.cpp
@@ -44,8 +44,8 @@
#include "qxcbwindow.h"
#include "qtouchdevice.h"
#include <qpa/qwindowsysteminterface.h>
-//#define XI2_TOUCH_DEBUG
-#ifdef XI2_TOUCH_DEBUG
+//#define XI2_DEBUG
+#ifdef XI2_DEBUG
#include <QDebug>
#endif
@@ -65,18 +65,11 @@ struct XInput2DeviceData {
QTouchDevice *qtTouchDevice;
};
-#ifndef QT_NO_TABLETEVENT
-static inline bool q_xi2_is_tablet(XIDeviceInfo *dev)
-{
- QByteArray name(dev->name);
- name = name.toLower();
- // Cannot just check for "wacom" because that would also pick up the touch and tablet-button devices.
- return name.contains("stylus") || name.contains("eraser");
-}
-#endif // QT_NO_TABLETEVENT
-
void QXcbConnection::initializeXInput2()
{
+#ifndef QT_NO_TABLETEVENT
+ m_tabletData.clear();
+#endif
Display *xDisplay = static_cast<Display *>(m_xlib_display);
if (XQueryExtension(xDisplay, "XInputExtension", &m_xiOpCode, &m_xiEventBase, &m_xiErrorBase)) {
int xiMajor = 2;
@@ -88,13 +81,60 @@ void QXcbConnection::initializeXInput2()
m_xi2Enabled = true;
}
if (m_xi2Enabled) {
+#ifdef XI2_DEBUG
+ qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor);
+#endif
+ int deviceCount = 0;
+ XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
+ for (int i = 0; i < deviceCount; ++i) {
+ // Only non-master pointing devices are relevant here.
+ if (devices[i].use != XISlavePointer)
+ continue;
+#ifdef XI2_DEBUG
+ qDebug() << "input device "<< devices[i].name;
+#endif
+#ifndef QT_NO_TABLETEVENT
+ TabletData tabletData;
+#endif
+ for (int c = 0; c < devices[i].num_classes; ++c) {
+ switch (devices[i].classes[c]->type) {
+ case XIValuatorClass: {
+ XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(devices[i].classes[c]);
+ const int valuatorAtom = qatom(vci->label);
+#ifdef XI2_DEBUG
+ qDebug() << " has valuator" << atomName(vci->label) << "recognized?" << (valuatorAtom < QXcbAtom::NAtoms);
+#endif
#ifndef QT_NO_TABLETEVENT
- // Tablet support: Find the stylus-related devices.
- xi2SetupTabletDevices();
+ if (valuatorAtom < QXcbAtom::NAtoms) {
+ TabletData::ValuatorClassInfo info;
+ info.minVal = vci->min;
+ info.maxVal = vci->max;
+ info.number = vci->number;
+ tabletData.valuatorInfo[valuatorAtom] = info;
+ }
#endif // QT_NO_TABLETEVENT
-#ifdef XI2_TOUCH_DEBUG
- qDebug("XInput version %d.%d is supported", xiMajor, m_xi2Minor);
+ } break;
+ default:
+ break;
+ }
+ }
+#ifndef QT_NO_TABLETEVENT
+ // If we have found the valuators which we expect a tablet to have, assume it's a tablet.
+ if (tabletData.valuatorInfo.contains(QXcbAtom::AbsX) &&
+ tabletData.valuatorInfo.contains(QXcbAtom::AbsY) &&
+ tabletData.valuatorInfo.contains(QXcbAtom::AbsPressure)) {
+ tabletData.deviceId = devices[i].deviceid;
+ tabletData.pointerType = QTabletEvent::Pen;
+ if (QByteArray(devices[i].name).toLower().contains("eraser"))
+ tabletData.pointerType = QTabletEvent::Eraser;
+ m_tabletData.append(tabletData);
+#ifdef XI2_DEBUG
+ qDebug() << " it's a tablet";
#endif
+ }
+#endif // QT_NO_TABLETEVENT
+ }
+ XIFreeDeviceInfo(devices);
}
}
}
@@ -131,7 +171,7 @@ void QXcbConnection::xi2Select(xcb_window_t window)
// to interact with mouse-oriented QWidgets; so we have to let Qt do it.
if (m_xi2Minor >= 2 && result == Success)
has_touch_without_mouse_emulation = true;
-#endif
+#endif // XCB_USE_XINPUT22
#ifndef QT_NO_TABLETEVENT
// For each tablet, select some additional event types.
@@ -179,7 +219,7 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
break;
}
} break;
-#endif
+#endif // XCB_USE_XINPUT22
case XIValuatorClass: {
XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(classinfo);
if (vci->label == atom(QXcbAtom::AbsMTPositionX))
@@ -195,9 +235,9 @@ XInput2DeviceData *QXcbConnection::deviceForId(int id)
dev->qtTouchDevice->setName(dev->xiDeviceInfo->name);
if (caps != 0)
QWindowSystemInterface::registerTouchDevice(dev->qtTouchDevice);
-#ifdef XI2_TOUCH_DEBUG
- qDebug("registered new device %s with %d classes and %d max touch points",
- dev->xiDeviceInfo->name, dev->xiDeviceInfo->num_classes, dev->qtTouchDevice->maxTouchPoints());
+#ifdef XI2_DEBUG
+ qDebug("registered new device %s with %d classes",
+ dev->xiDeviceInfo->name, dev->xiDeviceInfo->num_classes);
#endif
m_touchDevices[id] = dev;
}
@@ -218,7 +258,7 @@ static qreal valuatorNormalized(double value, XIValuatorClassInfo *vci)
value = vci->min;
return (value - vci->min) / (vci->max - vci->min);
}
-#endif
+#endif // XCB_USE_XINPUT22
void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
{
@@ -237,7 +277,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
#ifdef XCB_USE_XINPUT22
if (xiEvent->evtype == XI_TouchBegin || xiEvent->evtype == XI_TouchUpdate || xiEvent->evtype == XI_TouchEnd) {
xXIDeviceEvent* xiDeviceEvent = reinterpret_cast<xXIDeviceEvent *>(event);
-#ifdef XI2_TOUCH_DEBUG
+#ifdef XI2_DEBUG
qDebug("XI2 event type %d seq %d detail %d pos 0x%X,0x%X %f,%f root pos %f,%f",
event->event_type, xiEvent->sequenceNumber, xiDeviceEvent->detail,
xiDeviceEvent->event_x, xiDeviceEvent->event_y,
@@ -267,7 +307,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
double value;
if (!xi2GetValuatorValueIfSet(xiDeviceEvent, n, &value))
continue;
-#ifdef XI2_TOUCH_DEBUG
+#ifdef XI2_DEBUG
qDebug(" valuator class label %d value %lf from range %lf -> %lf name %s",
vci->label, value, vci->min, vci->max, XGetAtomName(static_cast<Display *>(m_xlib_display), vci->label) );
#endif
@@ -318,7 +358,7 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
touchPoint.area = QRectF(x - w/2, y - h/2, w, h);
touchPoint.normalPosition = QPointF(nx, ny);
-#ifdef XI2_TOUCH_DEBUG
+#ifdef XI2_DEBUG
qDebug() << " tp " << touchPoint.id << " state " << touchPoint.state << " pos norm " << touchPoint.normalPosition <<
" area " << touchPoint.area << " pressure " << touchPoint.pressure;
#endif
@@ -328,80 +368,11 @@ void QXcbConnection::xi2HandleEvent(xcb_ge_event_t *event)
m_touchPoints.remove(touchPoint.id);
}
}
-#endif
+#endif // XCB_USE_XINPUT22
}
}
#ifndef QT_NO_TABLETEVENT
-void QXcbConnection::xi2QueryTabletData(void *dev, TabletData *tabletData)
-{
- XIDeviceInfo *device = static_cast<XIDeviceInfo *>(dev);
- tabletData->deviceId = device->deviceid;
-
- tabletData->pointerType = QTabletEvent::Pen;
- if (QByteArray(device->name).toLower().contains("eraser"))
- tabletData->pointerType = QTabletEvent::Eraser;
-
- for (int i = 0; i < device->num_classes; ++i) {
- switch (device->classes[i]->type) {
- case XIValuatorClass: {
- XIValuatorClassInfo *vci = reinterpret_cast<XIValuatorClassInfo *>(device->classes[i]);
- int val = 0;
- if (vci->label == atom(QXcbAtom::AbsX))
- val = QXcbAtom::AbsX;
- else if (vci->label == atom(QXcbAtom::AbsY))
- val = QXcbAtom::AbsY;
- else if (vci->label == atom(QXcbAtom::AbsPressure))
- val = QXcbAtom::AbsPressure;
- else if (vci->label == atom(QXcbAtom::AbsTiltX))
- val = QXcbAtom::AbsTiltX;
- else if (vci->label == atom(QXcbAtom::AbsTiltY))
- val = QXcbAtom::AbsTiltY;
- else if (vci->label == atom(QXcbAtom::AbsWheel))
- val = QXcbAtom::AbsWheel;
- else if (vci->label == atom(QXcbAtom::AbsDistance))
- val = QXcbAtom::AbsDistance;
- if (val) {
- TabletData::ValuatorClassInfo info;
- info.minVal = vci->min;
- info.maxVal = vci->max;
- info.number = vci->number;
- tabletData->valuatorInfo[val] = info;
- }
- }
- break;
- default:
- break;
- }
- }
-}
-
-void QXcbConnection::xi2SetupTabletDevices()
-{
- Display *xDisplay = static_cast<Display *>(m_xlib_display);
- m_tabletData.clear();
- int deviceCount = 0;
- XIDeviceInfo *devices = XIQueryDevice(xDisplay, XIAllDevices, &deviceCount);
- if (devices) {
- for (int i = 0; i < deviceCount; ++i) {
- int unused = 0;
- XIDeviceInfo *dev = XIQueryDevice(xDisplay, devices[i].deviceid, &unused);
- if (dev) {
- if (q_xi2_is_tablet(dev)) {
- TabletData tabletData;
- xi2QueryTabletData(dev, &tabletData);
-#ifdef XI2_TOUCH_DEBUG
- qDebug() << "found tablet" << dev->name;
-#endif
- m_tabletData.append(tabletData);
- }
- XIFreeDeviceInfo(dev);
- }
- }
- XIFreeDeviceInfo(devices);
- }
-}
-
bool QXcbConnection::xi2HandleTabletEvent(void *event, TabletData *tabletData)
{
bool handled = true;