From 0319a66ead71d0f7bf8862c22099cefc019d888d Mon Sep 17 00:00:00 2001 From: Arjen Hiemstra Date: Wed, 15 Dec 2021 16:46:18 +0100 Subject: [PATCH] Refactor libinput::Device::ConfigData Rather than an awkward combination of template functions, function pointers and multiple calls to almost-the-same-but-not-entirely functions, make ConfigData itself a template and use type erasure to store them in the config map. This makes the data object aware of its type and allows us to specialise the reading of config values through template specialisation. It also removes the need for multiple constructors and setters in the ConfigData object. --- src/backends/libinput/device.cpp | 202 ++++++++++++++----------------- src/backends/libinput/device.h | 6 +- 2 files changed, 95 insertions(+), 113 deletions(-) diff --git a/src/backends/libinput/device.cpp b/src/backends/libinput/device.cpp index 342a2b9d0a..709e380676 100644 --- a/src/backends/libinput/device.cpp +++ b/src/backends/libinput/device.cpp @@ -112,83 +112,98 @@ enum class ConfigKey { OutputName }; -struct ConfigData { - explicit ConfigData(QByteArray _key, void (Device::*_setter)(bool), bool (Device::*_defaultValue)() const = nullptr) - : key(_key) - { booleanSetter.setter = _setter; booleanSetter.defaultValue = _defaultValue; } - - explicit ConfigData(QByteArray _key, void (Device::*_setter)(quint32), quint32 (Device::*_defaultValue)() const = nullptr) - : key(_key) - { quint32Setter.setter = _setter; quint32Setter.defaultValue = _defaultValue; } - - explicit ConfigData(QByteArray _key, void (Device::*_setter)(const QString&), QString (Device::*_defaultValue)() const = nullptr) - : key(_key) - { stringSetter.setter = _setter; stringSetter.defaultValue = _defaultValue; } - - explicit ConfigData(QByteArray _key, void (Device::*_setter)(qreal), qreal (Device::*_defaultValue)() const = nullptr) - : key(_key) - { qrealSetter.setter = _setter; qrealSetter.defaultValue = _defaultValue; } - - explicit ConfigData(QByteArray _key, void (Device::*_setter)(Qt::ScreenOrientation), Qt::ScreenOrientation (Device::*_defaultValue)() const = nullptr) - : key(_key) - { - screenOrientationSetter.setter = _setter; - screenOrientationSetter.defaultValue = _defaultValue; - } - - explicit ConfigData(QByteArray _key, void (Device::*_setter)(const QMatrix4x4 &), QMatrix4x4 (Device::*_defaultValue)() const = nullptr) - : key(_key) - { - qMatrix4x4Setter.setter = _setter, qMatrix4x4Setter.defaultValue = _defaultValue; - } +struct ConfigDataBase { + ConfigDataBase(const QByteArray &_key) : key(_key) { } + virtual ~ConfigDataBase() = default; QByteArray key; - - struct { - void (Device::*setter)(bool) = nullptr; - bool (Device::*defaultValue)() const; - } booleanSetter; - struct { - void (Device::*setter)(quint32) = nullptr; - quint32 (Device::*defaultValue)() const; - } quint32Setter; - struct { - void (Device::*setter)(const QString&) = nullptr; - QString (Device::*defaultValue)() const; - } stringSetter; - struct { - void (Device::*setter)(qreal) = nullptr; - qreal (Device::*defaultValue)() const; - } qrealSetter; - struct { - void (Device::*setter)(Qt::ScreenOrientation) = nullptr; - Qt::ScreenOrientation (Device::*defaultValue)() const; - } screenOrientationSetter; - struct { - void (Device::*setter)(const QMatrix4x4 &) = nullptr; - QMatrix4x4 (Device::*defaultValue)() const; - } qMatrix4x4Setter; + virtual void read(Device */*device*/, const KConfigGroup &/*values*/) const = 0; }; -static const QMap s_configData { - {ConfigKey::Enabled, ConfigData(QByteArrayLiteral("Enabled"), &Device::setEnabled)}, - {ConfigKey::LeftHanded, ConfigData(QByteArrayLiteral("LeftHanded"), &Device::setLeftHanded, &Device::leftHandedEnabledByDefault)}, - {ConfigKey::DisableWhileTyping, ConfigData(QByteArrayLiteral("DisableWhileTyping"), &Device::setDisableWhileTyping, &Device::disableWhileTypingEnabledByDefault)}, - {ConfigKey::PointerAcceleration, ConfigData(QByteArrayLiteral("PointerAcceleration"), &Device::setPointerAccelerationFromString, &Device::defaultPointerAccelerationToString)}, - {ConfigKey::PointerAccelerationProfile, ConfigData(QByteArrayLiteral("PointerAccelerationProfile"), &Device::setPointerAccelerationProfileFromInt, &Device::defaultPointerAccelerationProfileToInt)}, - {ConfigKey::TapToClick, ConfigData(QByteArrayLiteral("TapToClick"), &Device::setTapToClick, &Device::tapToClickEnabledByDefault)}, - {ConfigKey::TapAndDrag, ConfigData(QByteArrayLiteral("TapAndDrag"), &Device::setTapAndDrag, &Device::tapAndDragEnabledByDefault)}, - {ConfigKey::TapDragLock, ConfigData(QByteArrayLiteral("TapDragLock"), &Device::setTapDragLock, &Device::tapDragLockEnabledByDefault)}, - {ConfigKey::MiddleButtonEmulation, ConfigData(QByteArrayLiteral("MiddleButtonEmulation"), &Device::setMiddleEmulation, &Device::middleEmulationEnabledByDefault)}, - {ConfigKey::LmrTapButtonMap, ConfigData(QByteArrayLiteral("LmrTapButtonMap"), &Device::setLmrTapButtonMap, &Device::lmrTapButtonMapEnabledByDefault)}, - {ConfigKey::NaturalScroll, ConfigData(QByteArrayLiteral("NaturalScroll"), &Device::setNaturalScroll, &Device::naturalScrollEnabledByDefault)}, - {ConfigKey::ScrollMethod, ConfigData(QByteArrayLiteral("ScrollMethod"), &Device::activateScrollMethodFromInt, &Device::defaultScrollMethodToInt)}, - {ConfigKey::ScrollButton, ConfigData(QByteArrayLiteral("ScrollButton"), &Device::setScrollButton, &Device::defaultScrollButton)}, - {ConfigKey::ClickMethod, ConfigData(QByteArrayLiteral("ClickMethod"), &Device::setClickMethodFromInt, &Device::defaultClickMethodToInt)}, - {ConfigKey::ScrollFactor, ConfigData(QByteArrayLiteral("ScrollFactor"), &Device::setScrollFactor, &Device::scrollFactorDefault)}, - {ConfigKey::Orientation, ConfigData(QByteArrayLiteral("Orientation"), &Device::setOrientation, &Device::defaultOrientation)}, - {ConfigKey::Calibration, ConfigData(QByteArrayLiteral("CalibrationMatrix"), &Device::setCalibrationMatrix, &Device::defaultCalibrationMatrix)}, - {ConfigKey::OutputName, ConfigData(QByteArrayLiteral("OutputName"), &Device::setOutputName, &Device::defaultOutputName)}}; +template +struct ConfigData : public ConfigDataBase { + using SetterFunction = std::function; + using DefaultValueFunction = std::function; + + explicit ConfigData(const QByteArray &_key, const SetterFunction &_setter, const DefaultValueFunction &_defaultValue) + : ConfigDataBase(_key) + , setterFunction(_setter) + , defaultValueFunction(_defaultValue) + { + } + + void read(Device *device, const KConfigGroup &values) const override + { + if (!setterFunction || !defaultValueFunction) { + return; + } + + setterFunction(device, values.readEntry(key.constData(), defaultValueFunction(device))); + } + + SetterFunction setterFunction; + DefaultValueFunction defaultValueFunction; +}; + +// Template specializations for some specific config types that can't be handled +// through plain readEntry. +// +// This uses tagged types to avoid specialising the general type since we +// directly call the getters/setters. + +using DeviceOrientation = Qt::ScreenOrientation; + +template <> +struct ConfigData : public ConfigDataBase { + explicit ConfigData() : ConfigDataBase(QByteArrayLiteral("Orientation") ) { } + + void read(Device *device, const KConfigGroup &values) const override + { + int defaultValue = device->defaultOrientation(); + device->setOrientation(static_cast(values.readEntry(key.constData(), defaultValue))); + } +}; + +using CalibrationMatrix = QMatrix4x4; + +template <> +struct ConfigData : public ConfigDataBase { + explicit ConfigData() : ConfigDataBase(QByteArrayLiteral("CalibrationMatrix")) { } + + void read(Device *device, const KConfigGroup &values) const override + { + if (values.hasKey(key.constData())) { + auto list = values.readEntry(key.constData(), QList()); + if (list.size() == 16) { + device->setCalibrationMatrix(QMatrix4x4{list.toVector().constData()}); + return; + } + } + + device->setCalibrationMatrix(device->defaultCalibrationMatrix()); + } +}; + +static const QMap s_configData { + {ConfigKey::Enabled, new ConfigData(QByteArrayLiteral("Enabled"), &Device::setEnabled, &Device::isEnabledByDefault)}, + {ConfigKey::LeftHanded, new ConfigData(QByteArrayLiteral("LeftHanded"), &Device::setLeftHanded, &Device::leftHandedEnabledByDefault)}, + {ConfigKey::DisableWhileTyping, new ConfigData(QByteArrayLiteral("DisableWhileTyping"), &Device::setDisableWhileTyping, &Device::disableWhileTypingEnabledByDefault)}, + {ConfigKey::PointerAcceleration, new ConfigData(QByteArrayLiteral("PointerAcceleration"), &Device::setPointerAccelerationFromString, &Device::defaultPointerAccelerationToString)}, + {ConfigKey::PointerAccelerationProfile, new ConfigData(QByteArrayLiteral("PointerAccelerationProfile"), &Device::setPointerAccelerationProfileFromInt, &Device::defaultPointerAccelerationProfileToInt)}, + {ConfigKey::TapToClick, new ConfigData(QByteArrayLiteral("TapToClick"), &Device::setTapToClick, &Device::tapToClickEnabledByDefault)}, + {ConfigKey::TapAndDrag, new ConfigData(QByteArrayLiteral("TapAndDrag"), &Device::setTapAndDrag, &Device::tapAndDragEnabledByDefault)}, + {ConfigKey::TapDragLock, new ConfigData(QByteArrayLiteral("TapDragLock"), &Device::setTapDragLock, &Device::tapDragLockEnabledByDefault)}, + {ConfigKey::MiddleButtonEmulation, new ConfigData(QByteArrayLiteral("MiddleButtonEmulation"), &Device::setMiddleEmulation, &Device::middleEmulationEnabledByDefault)}, + {ConfigKey::LmrTapButtonMap, new ConfigData(QByteArrayLiteral("LmrTapButtonMap"), &Device::setLmrTapButtonMap, &Device::lmrTapButtonMapEnabledByDefault)}, + {ConfigKey::NaturalScroll, new ConfigData(QByteArrayLiteral("NaturalScroll"), &Device::setNaturalScroll, &Device::naturalScrollEnabledByDefault)}, + {ConfigKey::ScrollMethod, new ConfigData(QByteArrayLiteral("ScrollMethod"), &Device::activateScrollMethodFromInt, &Device::defaultScrollMethodToInt)}, + {ConfigKey::ScrollButton, new ConfigData(QByteArrayLiteral("ScrollButton"), &Device::setScrollButton, &Device::defaultScrollButton)}, + {ConfigKey::ClickMethod, new ConfigData(QByteArrayLiteral("ClickMethod"), &Device::setClickMethodFromInt, &Device::defaultClickMethodToInt)}, + {ConfigKey::ScrollFactor, new ConfigData(QByteArrayLiteral("ScrollFactor"), &Device::setScrollFactor, &Device::scrollFactorDefault)}, + {ConfigKey::Orientation, new ConfigData{}}, + {ConfigKey::Calibration, new ConfigData{}}, + {ConfigKey::OutputName, new ConfigData(QByteArrayLiteral("OutputName"), &Device::setOutputName, &Device::defaultOutputName)} +}; namespace { QMatrix4x4 getMatrix(libinput_device *device, std::function getter) @@ -388,54 +403,19 @@ void Device::writeEntry(const ConfigKey &key, const T &value) } auto it = s_configData.find(key); Q_ASSERT(it != s_configData.end()); - m_config.writeEntry(it.value().key.constData(), value); + m_config.writeEntry(it.value()->key.constData(), value); m_config.sync(); } -template -void Device::readEntry(const QByteArray &key, const Setter &s, const T &defaultValue) -{ - if (!s.setter) { - return; - } - - (this->*(s.setter))(m_config.readEntry(key.constData(), s.defaultValue ? (this->*(s.defaultValue))() : defaultValue)); -} - void Device::loadConfiguration() { if (!m_config.isValid()) { return; } + m_loading = true; for (auto it = s_configData.begin(), end = s_configData.end(); it != end; ++it) { - const auto key = it.value().key; - if (!m_config.hasKey(key.constData())) { - continue; - } - readEntry(key, it.value().booleanSetter, true); - readEntry(key, it.value().quint32Setter, 0); - readEntry(key, it.value().stringSetter, ""); - readEntry(key, it.value().qrealSetter, 1.0); - - if (it.value().screenOrientationSetter.setter != nullptr) { - auto setter = it.value().screenOrientationSetter; - int def = setter.defaultValue ? (this->*(setter.defaultValue))() : Qt::PrimaryOrientation; - int orientation = m_config.readEntry(key.constData(), def); - (this->*(setter.setter))(static_cast(orientation)); - } - - if (it.value().qMatrix4x4Setter.setter != nullptr) { - auto setter = it.value().qMatrix4x4Setter; - QList list = m_config.readEntry(key.constData(), QList()); - QMatrix4x4 matrix; - if (list.size() == 16) { - matrix = QMatrix4x4(list.toVector().constData()); - } else if (setter.defaultValue) { - matrix = (this->*(setter.defaultValue))(); - } - (this->*(setter.setter))(matrix); - } + (*it)->read(this, m_config); }; m_loading = false; diff --git a/src/backends/libinput/device.h b/src/backends/libinput/device.h index ce6e58b84b..751aef316a 100644 --- a/src/backends/libinput/device.h +++ b/src/backends/libinput/device.h @@ -458,6 +458,10 @@ public: } void setEnabled(bool enabled) override; + bool isEnabledByDefault() const { + return true; + } + libinput_device *device() const { return m_device; } @@ -541,8 +545,6 @@ Q_SIGNALS: private: template void writeEntry(const ConfigKey &key, const T &value); - template - void readEntry(const QByteArray &key, const Setter &s, const T &defaultValue = T()); libinput_device *m_device; bool m_keyboard; bool m_alphaNumericKeyboard = false;