QEvdev: Replace manual memory management with unique_ptr

Make create() return, and m_mice/m_keyboards/etc store, handlers by unique_ptr.
In most cases, we can't use qt_make_unique(), since the ctor we're calling is
marked as private.

Since QHash can't hold move-only types, use a std::vector<{QString, unique_ptr}>
instead. As this pattern repeats in all four QEvdev*Manager classes, create a
small class template.

Saves almost 6KiB on optimized Linux AMD64 GCC 9.1 builds across all .so's that
link to QtInputSupport.a.

Change-Id: I8f62b6b629d6e1855314c0a4fb4fc069db9ae0ce
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
Marc Mutz 2019-06-08 12:00:05 +02:00
parent 12938ba70b
commit 3bc10fb9bb
14 changed files with 145 additions and 58 deletions

View File

@ -98,7 +98,7 @@ QEvdevKeyboardHandler::~QEvdevKeyboardHandler()
unloadKeymap();
}
QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device,
std::unique_ptr<QEvdevKeyboardHandler> QEvdevKeyboardHandler::create(const QString &device,
const QString &specification,
const QString &defaultKeymapFile)
{
@ -138,10 +138,10 @@ QEvdevKeyboardHandler *QEvdevKeyboardHandler::create(const QString &device,
::ioctl(fd.get(), EVIOCSREP, kbdrep);
}
return new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile);
return std::unique_ptr<QEvdevKeyboardHandler>(new QEvdevKeyboardHandler(device, fd, disableZap, enableCompose, keymapFile));
} else {
qErrnoWarning("Cannot open keyboard input device '%ls'", qUtf16Printable(device));
return 0;
return nullptr;
}
}

View File

@ -55,6 +55,8 @@
#include <QTimer>
#include <QDataStream>
#include <memory>
QT_BEGIN_NAMESPACE
class QSocketNotifier;
@ -168,7 +170,7 @@ public:
SwitchConsoleMask = 0x0000007f
};
static QEvdevKeyboardHandler *create(const QString &device,
static std::unique_ptr<QEvdevKeyboardHandler> create(const QString &device,
const QString &specification,
const QString &defaultKeymapFile = QString());

View File

@ -98,17 +98,14 @@ QEvdevKeyboardManager::QEvdevKeyboardManager(const QString &key, const QString &
QEvdevKeyboardManager::~QEvdevKeyboardManager()
{
qDeleteAll(m_keyboards);
m_keyboards.clear();
}
void QEvdevKeyboardManager::addKeyboard(const QString &deviceNode)
{
qCDebug(qLcEvdevKey, "Adding keyboard at %ls", qUtf16Printable(deviceNode));
QEvdevKeyboardHandler *keyboard;
keyboard = QEvdevKeyboardHandler::create(deviceNode, m_spec, m_defaultKeymapFile);
auto keyboard = QEvdevKeyboardHandler::create(deviceNode, m_spec, m_defaultKeymapFile);
if (keyboard) {
m_keyboards.insert(deviceNode, keyboard);
m_keyboards.add(deviceNode, std::move(keyboard));
updateDeviceCount();
} else {
qWarning("Failed to open keyboard device %ls", qUtf16Printable(deviceNode));
@ -117,12 +114,9 @@ void QEvdevKeyboardManager::addKeyboard(const QString &deviceNode)
void QEvdevKeyboardManager::removeKeyboard(const QString &deviceNode)
{
if (m_keyboards.contains(deviceNode)) {
if (m_keyboards.remove(deviceNode)) {
qCDebug(qLcEvdevKey, "Removing keyboard at %ls", qUtf16Printable(deviceNode));
QEvdevKeyboardHandler *keyboard = m_keyboards.value(deviceNode);
m_keyboards.remove(deviceNode);
updateDeviceCount();
delete keyboard;
}
}
@ -145,22 +139,22 @@ void QEvdevKeyboardManager::loadKeymap(const QString &file)
if (arg.startsWith(QLatin1String("keymap=")))
keymapFromSpec = arg.mid(7).toString();
}
foreach (QEvdevKeyboardHandler *handler, m_keyboards) {
for (const auto &keyboard : m_keyboards) {
if (keymapFromSpec.isEmpty())
handler->unloadKeymap();
keyboard.handler->unloadKeymap();
else
handler->loadKeymap(keymapFromSpec);
keyboard.handler->loadKeymap(keymapFromSpec);
}
} else {
foreach (QEvdevKeyboardHandler *handler, m_keyboards)
handler->loadKeymap(file);
for (const auto &keyboard : m_keyboards)
keyboard.handler->loadKeymap(file);
}
}
void QEvdevKeyboardManager::switchLang()
{
foreach (QEvdevKeyboardHandler *handler, m_keyboards)
handler->switchLang();
for (const auto &keyboard : m_keyboards)
keyboard.handler->switchLang();
}
QT_END_NAMESPACE

View File

@ -53,6 +53,7 @@
#include "qevdevkeyboardhandler_p.h"
#include <QtInputSupport/private/devicehandlerlist_p.h>
#include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h>
#include <QObject>
@ -77,7 +78,7 @@ private:
void updateDeviceCount();
QString m_spec;
QHash<QString,QEvdevKeyboardHandler*> m_keyboards;
QtInputSupport::DeviceHandlerList<QEvdevKeyboardHandler> m_keyboards;
QDeviceDiscovery *m_deviceDiscovery;
QString m_defaultKeymapFile;
};

View File

@ -66,7 +66,7 @@ QT_BEGIN_NAMESPACE
Q_LOGGING_CATEGORY(qLcEvdevMouse, "qt.qpa.input")
QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QString &specification)
std::unique_ptr<QEvdevMouseHandler> QEvdevMouseHandler::create(const QString &device, const QString &specification)
{
qCDebug(qLcEvdevMouse) << "create mouse handler for" << device << specification;
@ -91,10 +91,10 @@ QEvdevMouseHandler *QEvdevMouseHandler::create(const QString &device, const QStr
fd = qt_safe_open(device.toLocal8Bit().constData(), O_RDONLY | O_NDELAY, 0);
if (fd >= 0) {
::ioctl(fd, EVIOCGRAB, grab);
return new QEvdevMouseHandler(device, fd, abs, compression, jitterLimit);
return std::unique_ptr<QEvdevMouseHandler>(new QEvdevMouseHandler(device, fd, abs, compression, jitterLimit));
} else {
qErrnoWarning(errno, "Cannot open mouse input device %s", qPrintable(device));
return 0;
return nullptr;
}
}

View File

@ -56,6 +56,8 @@
#include <QPoint>
#include <QEvent>
#include <memory>
QT_BEGIN_NAMESPACE
class QSocketNotifier;
@ -64,7 +66,7 @@ class QEvdevMouseHandler : public QObject
{
Q_OBJECT
public:
static QEvdevMouseHandler *create(const QString &device, const QString &specification);
static std::unique_ptr<QEvdevMouseHandler> create(const QString &device, const QString &specification);
~QEvdevMouseHandler();
void readMouseData();

View File

@ -111,8 +111,6 @@ QEvdevMouseManager::QEvdevMouseManager(const QString &key, const QString &specif
QEvdevMouseManager::~QEvdevMouseManager()
{
qDeleteAll(m_mice);
m_mice.clear();
}
void QEvdevMouseManager::clampPosition()
@ -160,13 +158,13 @@ void QEvdevMouseManager::handleWheelEvent(QPoint delta)
void QEvdevMouseManager::addMouse(const QString &deviceNode)
{
qCDebug(qLcEvdevMouse, "Adding mouse at %ls", qUtf16Printable(deviceNode));
QEvdevMouseHandler *handler = QEvdevMouseHandler::create(deviceNode, m_spec);
auto handler = QEvdevMouseHandler::create(deviceNode, m_spec);
if (handler) {
connect(handler, &QEvdevMouseHandler::handleMouseEvent,
connect(handler.get(), &QEvdevMouseHandler::handleMouseEvent,
this, &QEvdevMouseManager::handleMouseEvent);
connect(handler, &QEvdevMouseHandler::handleWheelEvent,
connect(handler.get(), &QEvdevMouseHandler::handleWheelEvent,
this, &QEvdevMouseManager::handleWheelEvent);
m_mice.insert(deviceNode, handler);
m_mice.add(deviceNode, std::move(handler));
updateDeviceCount();
} else {
qWarning("evdevmouse: Failed to open mouse device %ls", qUtf16Printable(deviceNode));
@ -175,12 +173,9 @@ void QEvdevMouseManager::addMouse(const QString &deviceNode)
void QEvdevMouseManager::removeMouse(const QString &deviceNode)
{
if (m_mice.contains(deviceNode)) {
if (m_mice.remove(deviceNode)) {
qCDebug(qLcEvdevMouse, "Removing mouse at %ls", qUtf16Printable(deviceNode));
QEvdevMouseHandler *handler = m_mice.value(deviceNode);
m_mice.remove(deviceNode);
updateDeviceCount();
delete handler;
}
}

View File

@ -53,6 +53,8 @@
#include "qevdevmousehandler_p.h"
#include <QtInputSupport/private/devicehandlerlist_p.h>
#include <QObject>
#include <QHash>
#include <QSocketNotifier>
@ -80,7 +82,7 @@ private:
void updateDeviceCount();
QString m_spec;
QHash<QString,QEvdevMouseHandler*> m_mice;
QtInputSupport::DeviceHandlerList<QEvdevMouseHandler> m_mice;
QDeviceDiscovery *m_deviceDiscovery;
int m_x;
int m_y;

View File

@ -46,6 +46,7 @@
#include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h>
#include <private/qguiapplication_p.h>
#include <private/qinputdevicemanager_p_p.h>
#include <private/qmemory_p.h>
QT_BEGIN_NAMESPACE
@ -99,16 +100,14 @@ QEvdevTabletManager::QEvdevTabletManager(const QString &key, const QString &spec
QEvdevTabletManager::~QEvdevTabletManager()
{
qDeleteAll(m_activeDevices);
}
void QEvdevTabletManager::addDevice(const QString &deviceNode)
{
qCDebug(qLcEvdevTablet, "Adding device at %ls", qUtf16Printable(deviceNode));
QEvdevTabletHandlerThread *handler;
handler = new QEvdevTabletHandlerThread(deviceNode, m_spec);
auto handler = qt_make_unique<QEvdevTabletHandlerThread>(deviceNode, m_spec);
if (handler) {
m_activeDevices.insert(deviceNode, handler);
m_activeDevices.add(deviceNode, std::move(handler));
updateDeviceCount();
} else {
qWarning("evdevtablet: Failed to open tablet device %ls", qUtf16Printable(deviceNode));
@ -117,12 +116,9 @@ void QEvdevTabletManager::addDevice(const QString &deviceNode)
void QEvdevTabletManager::removeDevice(const QString &deviceNode)
{
if (m_activeDevices.contains(deviceNode)) {
if (m_activeDevices.remove(deviceNode)) {
qCDebug(qLcEvdevTablet, "Removing device at %ls", qUtf16Printable(deviceNode));
QEvdevTabletHandlerThread *handler = m_activeDevices.value(deviceNode);
m_activeDevices.remove(deviceNode);
updateDeviceCount();
delete handler;
}
}

View File

@ -51,6 +51,8 @@
// We mean it.
//
#include <QtInputSupport/private/devicehandlerlist_p.h>
#include <QObject>
#include <QHash>
#include <QSocketNotifier>
@ -74,7 +76,7 @@ private:
QString m_spec;
QDeviceDiscovery *m_deviceDiscovery;
QHash<QString, QEvdevTabletHandlerThread *> m_activeDevices;
QtInputSupport::DeviceHandlerList<QEvdevTabletHandlerThread> m_activeDevices;
};
QT_END_NAMESPACE

View File

@ -46,6 +46,7 @@
#include <QtDeviceDiscoverySupport/private/qdevicediscovery_p.h>
#include <private/qguiapplication_p.h>
#include <private/qinputdevicemanager_p_p.h>
#include <private/qmemory_p.h>
QT_BEGIN_NAMESPACE
@ -99,17 +100,15 @@ QEvdevTouchManager::QEvdevTouchManager(const QString &key, const QString &specif
QEvdevTouchManager::~QEvdevTouchManager()
{
qDeleteAll(m_activeDevices);
}
void QEvdevTouchManager::addDevice(const QString &deviceNode)
{
qCDebug(qLcEvdevTouch, "evdevtouch: Adding device at %ls", qUtf16Printable(deviceNode));
QEvdevTouchScreenHandlerThread *handler;
handler = new QEvdevTouchScreenHandlerThread(deviceNode, m_spec);
auto handler = qt_make_unique<QEvdevTouchScreenHandlerThread>(deviceNode, m_spec);
if (handler) {
m_activeDevices.insert(deviceNode, handler);
connect(handler, &QEvdevTouchScreenHandlerThread::touchDeviceRegistered, this, &QEvdevTouchManager::updateInputDeviceCount);
m_activeDevices.add(deviceNode, std::move(handler));
connect(handler.get(), &QEvdevTouchScreenHandlerThread::touchDeviceRegistered, this, &QEvdevTouchManager::updateInputDeviceCount);
} else {
qWarning("evdevtouch: Failed to open touch device %ls", qUtf16Printable(deviceNode));
}
@ -117,12 +116,8 @@ void QEvdevTouchManager::addDevice(const QString &deviceNode)
void QEvdevTouchManager::removeDevice(const QString &deviceNode)
{
if (m_activeDevices.contains(deviceNode)) {
if (m_activeDevices.remove(deviceNode)) {
qCDebug(qLcEvdevTouch, "evdevtouch: Removing device at %ls", qUtf16Printable(deviceNode));
QEvdevTouchScreenHandlerThread *handler = m_activeDevices.value(deviceNode);
m_activeDevices.remove(deviceNode);
delete handler;
updateInputDeviceCount();
}
}
@ -130,8 +125,8 @@ void QEvdevTouchManager::removeDevice(const QString &deviceNode)
void QEvdevTouchManager::updateInputDeviceCount()
{
int registeredTouchDevices = 0;
Q_FOREACH (QEvdevTouchScreenHandlerThread *handler, m_activeDevices) {
if (handler->isTouchDeviceRegistered())
for (const auto &device : m_activeDevices) {
if (device.handler->isTouchDeviceRegistered())
++registeredTouchDevices;
}

View File

@ -51,6 +51,8 @@
// We mean it.
//
#include <QtInputSupport/private/devicehandlerlist_p.h>
#include <QObject>
#include <QHash>
#include <QSocketNotifier>
@ -74,7 +76,7 @@ public:
private:
QString m_spec;
QDeviceDiscovery *m_deviceDiscovery;
QHash<QString, QEvdevTouchScreenHandlerThread *> m_activeDevices;
QtInputSupport::DeviceHandlerList<QEvdevTouchScreenHandlerThread> m_activeDevices;
};
QT_END_NAMESPACE

View File

@ -0,0 +1,95 @@
/****************************************************************************
**
** Copyright (C) 2019 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Marc Mutz <marc.mutz@kdab.com>
** Contact: https://www.qt.io/licensing/
**
** This file is part of the QtGui module 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 QTINPUTSUPPORT_DEVICEHANDLERLIST_P_H
#define QTINPUTSUPPORT_DEVICEHANDLERLIST_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QString>
#include <vector>
#include <memory>
namespace QtInputSupport {
template <typename Handler>
class DeviceHandlerList {
public:
struct Device {
QString deviceNode;
std::unique_ptr<Handler> handler;
};
void add(const QString &deviceNode, std::unique_ptr<Handler> handler)
{
v.push_back({deviceNode, std::move(handler)});
}
bool remove(const QString &deviceNode)
{
const auto deviceNodeMatches = [&] (const Device &d) { return d.deviceNode == deviceNode; };
const auto it = std::find_if(v.cbegin(), v.cend(), deviceNodeMatches);
if (it == v.cend())
return false;
v.erase(it);
return true;
}
int count() const noexcept { return static_cast<int>(v.size()); }
typename std::vector<Device>::const_iterator begin() const noexcept { return v.begin(); }
typename std::vector<Device>::const_iterator end() const noexcept { return v.end(); }
private:
std::vector<Device> v;
};
} // QtInputSupport
#endif // QTINPUTSUPPORT_DEVICEHANDLERLIST_P_H

View File

@ -1,4 +1,5 @@
HEADERS += \
$$PWD/devicehandlerlist_p.h \
$$PWD/qtouchoutputmapping_p.h
SOURCES += \