From 68ea2f7e9bb2d4ea6182101521325dbfd9b74abb Mon Sep 17 00:00:00 2001 From: Romain Pokrzywka Date: Tue, 22 Sep 2015 11:38:09 -0700 Subject: [PATCH] Synchronize QInputDeviceManager touch device count with QTouchDevice This ensures that the values and signals reported by QInputDeviceManager for touch devices always have corresponding entries in the list returned by QTouchDevice::devices(). It also adds proper QTouchDevice unregistration when the underlying input device gets removed by the evdevtouch QPA plugin. Change-Id: I7bdf2f7435c775d15bddce8ba1e731afdc1d948a Reviewed-by: Friedemann Kleint Reviewed-by: Laszlo Agocs --- src/gui/kernel/qtouchdevice.cpp | 11 +++ src/gui/kernel/qtouchdevice_p.h | 1 + src/gui/kernel/qwindowsysteminterface.cpp | 7 +- src/gui/kernel/qwindowsysteminterface.h | 3 +- .../input/evdevtouch/qevdevtouchhandler.cpp | 83 ++++++++++++++----- .../input/evdevtouch/qevdevtouchhandler_p.h | 20 ++++- .../input/evdevtouch/qevdevtouchmanager.cpp | 27 ++++-- .../input/evdevtouch/qevdevtouchmanager_p.h | 2 + 8 files changed, 120 insertions(+), 34 deletions(-) diff --git a/src/gui/kernel/qtouchdevice.cpp b/src/gui/kernel/qtouchdevice.cpp index 9d19fa4b92..266b5308a2 100644 --- a/src/gui/kernel/qtouchdevice.cpp +++ b/src/gui/kernel/qtouchdevice.cpp @@ -237,6 +237,17 @@ void QTouchDevicePrivate::registerDevice(const QTouchDevice *dev) deviceList()->append(dev); } +/*! + \internal + */ +void QTouchDevicePrivate::unregisterDevice(const QTouchDevice *dev) +{ + QMutexLocker lock(&devicesMutex); + bool wasRemoved = deviceList()->removeOne(dev); + if (wasRemoved && deviceList()->isEmpty()) + qRemovePostRoutine(cleanupDevicesList); +} + #ifndef QT_NO_DEBUG_STREAM QDebug operator<<(QDebug debug, const QTouchDevice *device) { diff --git a/src/gui/kernel/qtouchdevice_p.h b/src/gui/kernel/qtouchdevice_p.h index 4aff8f2f33..63b83d33ec 100644 --- a/src/gui/kernel/qtouchdevice_p.h +++ b/src/gui/kernel/qtouchdevice_p.h @@ -65,6 +65,7 @@ public: int maxTouchPoints; static void registerDevice(const QTouchDevice *dev); + static void unregisterDevice(const QTouchDevice *dev); static bool isRegistered(const QTouchDevice *dev); }; diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 91a935ad0f..faa1ff8068 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -486,11 +486,16 @@ bool QWindowSystemInterfacePrivate::handleWindowSystemEvent(QWindowSystemInterfa return accepted; } -void QWindowSystemInterface::registerTouchDevice(QTouchDevice *device) +void QWindowSystemInterface::registerTouchDevice(const QTouchDevice *device) { QTouchDevicePrivate::registerDevice(device); } +void QWindowSystemInterface::unregisterTouchDevice(const QTouchDevice *device) +{ + QTouchDevicePrivate::unregisterDevice(device); +} + void QWindowSystemInterface::handleTouchEvent(QWindow *w, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods) { diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index 99589e8aa1..97bd087b53 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -127,7 +127,8 @@ public: QVector rawPositions; // in screen coordinates }; - static void registerTouchDevice(QTouchDevice *device); + static void registerTouchDevice(const QTouchDevice *device); + static void unregisterTouchDevice(const QTouchDevice *device); static void handleTouchEvent(QWindow *w, QTouchDevice *device, const QList &points, Qt::KeyboardModifiers mods = Qt::NoModifier); static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device, diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp index 5560d910ac..ad348cc083 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler.cpp @@ -107,9 +107,8 @@ public: int m_currentSlot; int findClosestContact(const QHash &contacts, int x, int y, int *dist); - void reportPoints(); - void registerDevice(); void addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates); + void reportPoints(); int hw_range_x_min; int hw_range_x_max; @@ -119,7 +118,6 @@ public: int hw_pressure_max; QString hw_name; bool m_forceToActiveWindow; - QTouchDevice *m_device; bool m_typeB; QTransform m_rotate; bool m_singleTouch; @@ -132,23 +130,11 @@ QEvdevTouchScreenData::QEvdevTouchScreenData(QEvdevTouchScreenHandler *q_ptr, co hw_range_x_min(0), hw_range_x_max(0), hw_range_y_min(0), hw_range_y_max(0), hw_pressure_min(0), hw_pressure_max(0), - m_device(0), m_typeB(false), m_singleTouch(false) + m_typeB(false), m_singleTouch(false) { m_forceToActiveWindow = args.contains(QLatin1String("force_window")); } -void QEvdevTouchScreenData::registerDevice() -{ - m_device = new QTouchDevice; - m_device->setName(hw_name); - m_device->setType(QTouchDevice::TouchScreen); - m_device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area); - if (hw_pressure_max > hw_pressure_min) - m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure); - - QWindowSystemInterface::registerTouchDevice(m_device); -} - #define LONG_BITS (sizeof(long) << 3) #define NUM_LONGS(bits) (((bits) + LONG_BITS - 1) / LONG_BITS) @@ -160,9 +146,9 @@ static inline bool testBit(long bit, const long *array) #endif QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const QString &spec, QObject *parent) - : QObject(parent), m_notify(0), m_fd(-1), d(0) + : QObject(parent), m_notify(Q_NULLPTR), m_fd(-1), d(Q_NULLPTR), m_device(Q_NULLPTR) #if !defined(QT_NO_MTDEV) - , m_mtdev(0) + , m_mtdev(Q_NULLPTR) #endif { setObjectName(QLatin1String("Evdev Touch Handler")); @@ -299,7 +285,7 @@ QEvdevTouchScreenHandler::QEvdevTouchScreenHandler(const QString &device, const if (inverty) d->m_rotate *= QTransform::fromTranslate(0.5, 0.5).scale(1.0, -1.0).translate(-0.5, -0.5); - d->registerDevice(); + registerTouchDevice(); } QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() @@ -315,6 +301,13 @@ QEvdevTouchScreenHandler::~QEvdevTouchScreenHandler() QT_CLOSE(m_fd); delete d; + + unregisterTouchDevice(); +} + +QTouchDevice *QEvdevTouchScreenHandler::touchDevice() const +{ + return m_device; } void QEvdevTouchScreenHandler::readData() @@ -368,15 +361,44 @@ err: qErrnoWarning(errno, "evdevtouch: Could not read from input device"); if (errno == ENODEV) { // device got disconnected -> stop reading delete m_notify; - m_notify = 0; + m_notify = Q_NULLPTR; + QT_CLOSE(m_fd); m_fd = -1; + + unregisterTouchDevice(); } return; } } } +void QEvdevTouchScreenHandler::registerTouchDevice() +{ + if (m_device) + return; + + m_device = new QTouchDevice; + m_device->setName(d->hw_name); + m_device->setType(QTouchDevice::TouchScreen); + m_device->setCapabilities(QTouchDevice::Position | QTouchDevice::Area); + if (d->hw_pressure_max > d->hw_pressure_min) + m_device->setCapabilities(m_device->capabilities() | QTouchDevice::Pressure); + + QWindowSystemInterface::registerTouchDevice(m_device); +} + +void QEvdevTouchScreenHandler::unregisterTouchDevice() +{ + if (!m_device) + return; + + QWindowSystemInterface::unregisterTouchDevice(m_device); + + delete m_device; + m_device = Q_NULLPTR; +} + void QEvdevTouchScreenData::addTouchPoint(const Contact &contact, Qt::TouchPointStates *combinedStates) { QWindowSystemInterface::TouchPoint tp; @@ -639,12 +661,12 @@ void QEvdevTouchScreenData::reportPoints() tp.pressure = (tp.pressure - hw_pressure_min) / qreal(hw_pressure_max - hw_pressure_min); } - QWindowSystemInterface::handleTouchEvent(0, m_device, m_touchPoints); + QWindowSystemInterface::handleTouchEvent(Q_NULLPTR, q->touchDevice(), m_touchPoints); } QEvdevTouchScreenHandlerThread::QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent) - : QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(0) + : QDaemonThread(parent), m_device(device), m_spec(spec), m_handler(Q_NULLPTR), m_touchDeviceRegistered(false) { start(); } @@ -658,9 +680,24 @@ QEvdevTouchScreenHandlerThread::~QEvdevTouchScreenHandlerThread() void QEvdevTouchScreenHandlerThread::run() { m_handler = new QEvdevTouchScreenHandler(m_device, m_spec); + // Report the registration to the parent thread by invoking the method asynchronously + QMetaObject::invokeMethod(this, "notifyTouchDeviceRegistered", Qt::QueuedConnection); + exec(); + delete m_handler; - m_handler = 0; + m_handler = Q_NULLPTR; +} + +bool QEvdevTouchScreenHandlerThread::isTouchDeviceRegistered() const +{ + return m_touchDeviceRegistered; +} + +void QEvdevTouchScreenHandlerThread::notifyTouchDeviceRegistered() +{ + m_touchDeviceRegistered = true; + emit touchDeviceRegistered(); } diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h index 8e7dfe59bb..ca9756d5de 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchhandler_p.h @@ -66,16 +66,22 @@ class QEvdevTouchScreenHandler : public QObject Q_OBJECT public: - explicit QEvdevTouchScreenHandler(const QString &device, const QString &spec = QString(), QObject *parent = 0); + explicit QEvdevTouchScreenHandler(const QString &device, const QString &spec = QString(), QObject *parent = Q_NULLPTR); ~QEvdevTouchScreenHandler(); + QTouchDevice *touchDevice() const; + private slots: void readData(); private: + void registerTouchDevice(); + void unregisterTouchDevice(); + QSocketNotifier *m_notify; int m_fd; QEvdevTouchScreenData *d; + QTouchDevice *m_device; #if !defined(QT_NO_MTDEV) mtdev *m_mtdev; #endif @@ -83,16 +89,24 @@ private: class QEvdevTouchScreenHandlerThread : public QDaemonThread { + Q_OBJECT public: - explicit QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent = 0); + explicit QEvdevTouchScreenHandlerThread(const QString &device, const QString &spec, QObject *parent = Q_NULLPTR); ~QEvdevTouchScreenHandlerThread(); void run() Q_DECL_OVERRIDE; - QEvdevTouchScreenHandler *handler() { return m_handler; } + + bool isTouchDeviceRegistered() const; + +signals: + void touchDeviceRegistered(); private: + Q_INVOKABLE void notifyTouchDeviceRegistered(); + QString m_device; QString m_spec; QEvdevTouchScreenHandler *m_handler; + bool m_touchDeviceRegistered; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp index 98fc83700c..35a685ff21 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager.cpp @@ -91,17 +91,17 @@ QEvdevTouchManager::QEvdevTouchManager(const QString &key, const QString &specif QEvdevTouchManager::~QEvdevTouchManager() { qDeleteAll(m_activeDevices); + updateInputDeviceCount(); } void QEvdevTouchManager::addDevice(const QString &deviceNode) { - qCDebug(qLcEvdevTouch) << "Adding device at" << deviceNode; + qCDebug(qLcEvdevTouch) << "evdevtouch: Adding device at" << deviceNode; QEvdevTouchScreenHandlerThread *handler; handler = new QEvdevTouchScreenHandlerThread(deviceNode, m_spec); if (handler) { m_activeDevices.insert(deviceNode, handler); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeTouch, m_activeDevices.count()); + connect(handler, &QEvdevTouchScreenHandlerThread::touchDeviceRegistered, this, &QEvdevTouchManager::updateInputDeviceCount); } else { qWarning("evdevtouch: Failed to open touch device %s", qPrintable(deviceNode)); } @@ -110,13 +110,28 @@ void QEvdevTouchManager::addDevice(const QString &deviceNode) void QEvdevTouchManager::removeDevice(const QString &deviceNode) { if (m_activeDevices.contains(deviceNode)) { - qCDebug(qLcEvdevTouch) << "Removing device at" << deviceNode; + qCDebug(qLcEvdevTouch) << "evdevtouch: Removing device at" << deviceNode; QEvdevTouchScreenHandlerThread *handler = m_activeDevices.value(deviceNode); m_activeDevices.remove(deviceNode); - QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( - QInputDeviceManager::DeviceTypeTouch, m_activeDevices.count()); delete handler; + + updateInputDeviceCount(); } } +void QEvdevTouchManager::updateInputDeviceCount() +{ + int registeredTouchDevices = 0; + Q_FOREACH (QEvdevTouchScreenHandlerThread *handler, m_activeDevices) { + if (handler->isTouchDeviceRegistered()) + ++registeredTouchDevices; + } + + qCDebug(qLcEvdevTouch) << "evdevtouch: Updating QInputDeviceManager device count:" << registeredTouchDevices << " touch devices," + << m_activeDevices.count() - registeredTouchDevices << "pending handler(s)" ; + + QInputDeviceManagerPrivate::get(QGuiApplicationPrivate::inputDeviceManager())->setDeviceCount( + QInputDeviceManager::DeviceTypeTouch, registeredTouchDevices); +} + QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h index bf484fd88b..289c345ac4 100644 --- a/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h +++ b/src/platformsupport/input/evdevtouch/qevdevtouchmanager_p.h @@ -65,6 +65,8 @@ private slots: void addDevice(const QString &deviceNode); void removeDevice(const QString &deviceNode); + void updateInputDeviceCount(); + private: QString m_spec; QDeviceDiscovery *m_deviceDiscovery;