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 <Friedemann.Kleint@theqtcompany.com>
Reviewed-by: Laszlo Agocs <laszlo.agocs@theqtcompany.com>
This commit is contained in:
Romain Pokrzywka 2015-09-22 11:38:09 -07:00 committed by Romain Pokrzywka
parent 29bc68cf16
commit 68ea2f7e9b
8 changed files with 120 additions and 34 deletions

View File

@ -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)
{

View File

@ -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);
};

View File

@ -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<TouchPoint> &points, Qt::KeyboardModifiers mods)
{

View File

@ -127,7 +127,8 @@ public:
QVector<QPointF> 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<struct TouchPoint> &points, Qt::KeyboardModifiers mods = Qt::NoModifier);
static void handleTouchEvent(QWindow *w, ulong timestamp, QTouchDevice *device,

View File

@ -107,9 +107,8 @@ public:
int m_currentSlot;
int findClosestContact(const QHash<int, Contact> &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();
}

View File

@ -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

View File

@ -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

View File

@ -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;