diff --git a/kcms/input/AUTHORS b/kcms/input/AUTHORS deleted file mode 100644 --- a/kcms/input/AUTHORS +++ /dev/null @@ -1,7 +0,0 @@ -Mouse & Keyboard Configuration Modules: - - Pat Dowler (dowler@pt1B1106.FSH.UVic.CA) - -Conversion to kcontrol applet: - - Matthias Hoelzer (hoelzer@physik.uni-wuerzburg.de) diff --git a/kcms/input/CMakeLists.txt b/kcms/input/CMakeLists.txt --- a/kcms/input/CMakeLists.txt +++ b/kcms/input/CMakeLists.txt @@ -5,47 +5,85 @@ # KI18N Translation Domain for this library add_definitions(-DTRANSLATION_DOMAIN=\"kcminput\") -add_subdirectory( pics ) +add_subdirectory( misc ) ## Add common files here. -set(kcminput_backend_SRCS - mousebackend.cpp - mousesettings.cpp - logging.cpp) -set(kcminput_backend_LIBS) +set(common_SRCS + inputbackend.cpp +) + +include(ECMQtDeclareLoggingCategory) +ecm_qt_declare_logging_category(common_SRCS + HEADER + logging.h + IDENTIFIER + KCM_INPUT + CATEGORY_NAME + kcm_input + DEFAULT_SEVERITY + Critical +) + include(backends/x11.cmake) +include(backends/kwin_wl.cmake) + +########### next target ############### +add_executable(kapplymousetheme + kapplymousetheme.cpp + ${common_SRCS} + ${backend_SRCS} +) + +target_link_libraries(kapplymousetheme + ${backend_LIBS} + Qt5::Gui + Qt5::DBus + KF5::CoreAddons + KF5::ConfigCore + KF5::I18n +) + +install(TARGETS kapplymousetheme ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) ########### next target ############### -set(kcm_input_PART_SRCS - mouse.cpp - main.cpp - ${kcminput_backend_SRCS} +set(common_SRCS + ${common_SRCS} + plugin.cpp + kcm/configcontainer.cpp + kcm/configplugin.cpp + kcm/libinput/libinput_config.cpp + kcm/xlib/xlib_config.cpp ) set(klauncher_xml ${KINIT_DBUS_INTERFACES_DIR}/kf5_org.kde.KLauncher.xml) -ki18n_wrap_ui(kcm_input_PART_SRCS kcmmouse.ui) -qt5_add_dbus_interface(kcm_input_PART_SRCS ${klauncher_xml} klauncher_iface) +ki18n_wrap_ui(common_SRCS kcm/xlib/kcmmouse.ui) +qt5_add_dbus_interface(common_SRCS ${klauncher_xml} klauncher_iface) -add_library(kcm_input MODULE ${kcm_input_PART_SRCS} ${kcminput_backend_SRCS}) +qt5_add_resources( common_SRCS kcm/resources.qrc ) + +add_library(kcm_input MODULE + ${common_SRCS} + ${backend_SRCS} +) target_link_libraries(kcm_input - Qt5::DBus + ${backend_LIBS} KF5::KCMUtils KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::KDELibs4Support - ${kcminput_backend_LIBS} + KF5::Declarative + + Qt5::DBus + Qt5::QuickWidgets ) install(TARGETS kcm_input DESTINATION ${KDE_INSTALL_PLUGINDIR} ) - ########### install files ############### install( FILES mouse.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) -install( FILES cursor_large_black.pcf.gz cursor_large_white.pcf.gz cursor_small_white.pcf.gz DESTINATION ${KDE_INSTALL_DATADIR}/kcminput ) - diff --git a/kcms/input/ChangeLog b/kcms/input/ChangeLog deleted file mode 100644 --- a/kcms/input/ChangeLog +++ /dev/null @@ -1,11 +0,0 @@ -2002-07-01 Fabian Wolf - * added option to select a white cursor - -2000-03-14 David Faure - - * mouse.cpp: Added global settings for SC/DC/AutoSelect/ChangeCursor - * mousedefaults.h: New file, to store default values - -1998-11-30 Alex Zepeda - - * Makefile.am: Move all the icons into pics/ && pics/mini/ diff --git a/kcms/input/backends/kwin_wl.cmake b/kcms/input/backends/kwin_wl.cmake new file mode 100644 --- /dev/null +++ b/kcms/input/backends/kwin_wl.cmake @@ -0,0 +1,5 @@ +SET(backend_SRCS + ${backend_SRCS} + backends/kwin_wl/kwin_wl_backend.cpp + backends/kwin_wl/kwin_wl_device.cpp +) diff --git a/kcms/input/backends/kwin_wl/kwin_wl_backend.h b/kcms/input/backends/kwin_wl/kwin_wl_backend.h new file mode 100644 --- /dev/null +++ b/kcms/input/backends/kwin_wl/kwin_wl_backend.h @@ -0,0 +1,61 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KWINWAYLANDBACKEND_H +#define KWINWAYLANDBACKEND_H + +#include "inputbackend.h" + +#include + +class KWinWaylandDevice; +class QDBusInterface; + +class KWinWaylandBackend : public InputBackend +{ + Q_OBJECT + + Q_PROPERTY(int deviceCount READ deviceCount CONSTANT) + +public: + explicit KWinWaylandBackend(QObject *parent = 0); + ~KWinWaylandBackend(); + + bool applyConfig() override; + bool getConfig() override; + bool getDefaultConfig() override; + bool isChangedConfig() const override; + QString errorString() const override { return m_errorString; } + + virtual int deviceCount() const override { return m_devices.count(); } + virtual QVector getDevices() const override { return m_devices; } + +private Q_SLOTS: + void onDeviceAdded(QString); + void onDeviceRemoved(QString); + +private: + void findDevices(); + + QDBusInterface* m_deviceManager; + QVector m_devices; + + QString m_errorString = QString(); +}; + +#endif // KWINWAYLANDBACKEND_H diff --git a/kcms/input/backends/kwin_wl/kwin_wl_backend.cpp b/kcms/input/backends/kwin_wl/kwin_wl_backend.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/backends/kwin_wl/kwin_wl_backend.cpp @@ -0,0 +1,175 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kwin_wl_backend.h" +#include "kwin_wl_device.h" + +#include + +#include + +#include +#include +#include +#include + +#include "logging.h" + +KWinWaylandBackend::KWinWaylandBackend(QObject *parent) : + InputBackend(parent) +{ + m_mode = InputBackendMode::KWinWayland; + + m_deviceManager = new QDBusInterface (QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin/InputDevice"), + QStringLiteral("org.kde.KWin.InputDeviceManager"), + QDBusConnection::sessionBus(), + this); + + findDevices(); + + m_deviceManager->connection().connect(QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin/InputDevice"), + QStringLiteral("org.kde.KWin.InputDeviceManager"), + QStringLiteral("deviceAdded"), + this, + SLOT(onDeviceAdded(QString))); + m_deviceManager->connection().connect(QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin/InputDevice"), + QStringLiteral("org.kde.KWin.InputDeviceManager"), + QStringLiteral("deviceRemoved"), + this, + SLOT(onDeviceRemoved(QString))); +} + +KWinWaylandBackend::~KWinWaylandBackend() +{ + qDeleteAll(m_devices); + delete m_deviceManager; +} + +void KWinWaylandBackend::findDevices() +{ + QStringList devicesSysNames; + const QVariant reply = m_deviceManager->property("devicesSysNames"); + if (reply.isValid()) { + qCDebug(KCM_INPUT) << "Devices list received successfully from KWin."; + devicesSysNames = reply.toStringList(); + } + else { + qCCritical(KCM_INPUT) << "Error on receiving device list from KWin."; + m_errorString = i18n("Querying input devices failed. Please reopen this settings module."); + return; + } + + for (QString sn : devicesSysNames) { + QDBusInterface deviceIface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin/InputDevice/") + sn, + QStringLiteral("org.kde.KWin.InputDevice"), + QDBusConnection::sessionBus(), + this); + QVariant reply = deviceIface.property("pointer"); + if (reply.isValid() && reply.toBool()) { + reply = deviceIface.property("touchpad"); + if (reply.isValid() && reply.toBool()) { + continue; + } + + KWinWaylandDevice* dev = new KWinWaylandDevice(sn); + if (!dev->init()) { + qCCritical(KCM_INPUT) << "Error on creating device object" << sn; + m_errorString = i18n("Critical error on reading fundamental device infos of %1.", sn); + return; + } + m_devices.append(dev); + qCDebug(KCM_INPUT).nospace() << "Device found: " << dev->name() << " (" << dev->sysName() << ")"; + } + } +} + +bool KWinWaylandBackend::applyConfig() +{ + return std::all_of(m_devices.constBegin(), m_devices.constEnd(), + [] (QObject *t) { return static_cast(t)->applyConfig(); }); +} + +bool KWinWaylandBackend::getConfig() +{ + return std::all_of(m_devices.constBegin(), m_devices.constEnd(), + [] (QObject *t) { return static_cast(t)->getConfig(); }); +} + +bool KWinWaylandBackend::getDefaultConfig() +{ + return std::all_of(m_devices.constBegin(), m_devices.constEnd(), + [] (QObject *t) { return static_cast(t)->getDefaultConfig(); }); +} + +bool KWinWaylandBackend::isChangedConfig() const +{ + return std::any_of(m_devices.constBegin(), m_devices.constEnd(), + [] (QObject *t) { return static_cast(t)->isChangedConfig(); }); +} + +void KWinWaylandBackend::onDeviceAdded(QString sysName) +{ + if (std::any_of(m_devices.constBegin(), m_devices.constEnd(), + [sysName] (QObject *t) { return static_cast(t)->sysName() == sysName; })) { + return; + } + + QDBusInterface deviceIface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin/InputDevice/") + sysName, + QStringLiteral("org.kde.KWin.InputDevice"), + QDBusConnection::sessionBus(), + this); + QVariant reply = deviceIface.property("pointer"); + + if (reply.isValid() && reply.toBool()) { + reply = deviceIface.property("touchpad"); + if (reply.isValid() && reply.toBool()) { + return; + } + + KWinWaylandDevice* dev = new KWinWaylandDevice(sysName); + if (!dev->init() || !dev->getConfig()) { + emit deviceAdded(false); + return; + } + + m_devices.append(dev); + qCDebug(KCM_INPUT).nospace() << "Device connected: " << dev->name() << " (" << dev->sysName() << ")"; + emit deviceAdded(true); + } +} + +void KWinWaylandBackend::onDeviceRemoved(QString sysName) +{ + QVector::const_iterator it = std::find_if(m_devices.constBegin(), m_devices.constEnd(), + [sysName] (QObject *t) { return static_cast(t)->sysName() == sysName; }); + if (it == m_devices.cend()) { + return; + } + + KWinWaylandDevice *dev = static_cast(*it); + qCDebug(KCM_INPUT).nospace() << "Device disconnected: " << dev->name() << " (" << dev->sysName() << ")"; + + int index = it - m_devices.cbegin(); + m_devices.removeAt(index); + emit deviceRemoved(index); +} diff --git a/kcms/input/backends/kwin_wl/kwin_wl_device.h b/kcms/input/backends/kwin_wl/kwin_wl_device.h new file mode 100644 --- /dev/null +++ b/kcms/input/backends/kwin_wl/kwin_wl_device.h @@ -0,0 +1,264 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef KWINWAYLANDDEVICE_H +#define KWINWAYLANDDEVICE_H + +#include +#include + +class QDBusInterface; + +class KWinWaylandDevice : public QObject +{ + Q_OBJECT + + // + // general + Q_PROPERTY(QString name READ name CONSTANT) + Q_PROPERTY(bool supportsDisableEvents READ supportsDisableEvents CONSTANT) + Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled NOTIFY enabledChanged) + + // + // advanced + Q_PROPERTY(Qt::MouseButtons supportedButtons READ supportedButtons CONSTANT) + + Q_PROPERTY(bool supportsLeftHanded READ supportsLeftHanded CONSTANT) + Q_PROPERTY(bool leftHandedEnabledByDefault READ leftHandedEnabledByDefault CONSTANT) + Q_PROPERTY(bool leftHanded READ isLeftHanded WRITE setLeftHanded NOTIFY leftHandedChanged) + + Q_PROPERTY(bool supportsMiddleEmulation READ supportsMiddleEmulation CONSTANT) + Q_PROPERTY(bool middleEmulationEnabledByDefault READ middleEmulationEnabledByDefault CONSTANT) + Q_PROPERTY(bool middleEmulation READ isMiddleEmulation WRITE setMiddleEmulation NOTIFY middleEmulationChanged) + + // + // acceleration speed and profile + Q_PROPERTY(bool supportsPointerAcceleration READ supportsPointerAcceleration CONSTANT) + Q_PROPERTY(qreal pointerAcceleration READ pointerAcceleration WRITE setPointerAcceleration NOTIFY pointerAccelerationChanged) + + Q_PROPERTY(bool supportsPointerAccelerationProfileFlat READ supportsPointerAccelerationProfileFlat CONSTANT) + Q_PROPERTY(bool defaultPointerAccelerationProfileFlat READ defaultPointerAccelerationProfileFlat CONSTANT) + Q_PROPERTY(bool pointerAccelerationProfileFlat READ pointerAccelerationProfileFlat WRITE setPointerAccelerationProfileFlat NOTIFY pointerAccelerationProfileChanged) + + Q_PROPERTY(bool supportsPointerAccelerationProfileAdaptive READ supportsPointerAccelerationProfileAdaptive CONSTANT) + Q_PROPERTY(bool defaultPointerAccelerationProfileAdaptive READ defaultPointerAccelerationProfileAdaptive CONSTANT) + Q_PROPERTY(bool pointerAccelerationProfileAdaptive READ pointerAccelerationProfileAdaptive WRITE setPointerAccelerationProfileAdaptive NOTIFY pointerAccelerationProfileChanged) + + // + // scrolling + Q_PROPERTY(bool supportsNaturalScroll READ supportsNaturalScroll CONSTANT) + Q_PROPERTY(bool naturalScrollEnabledByDefault READ naturalScrollEnabledByDefault CONSTANT) + Q_PROPERTY(bool naturalScroll READ isNaturalScroll WRITE setNaturalScroll NOTIFY naturalScrollChanged) + +public: + KWinWaylandDevice(QString dbusName); + ~KWinWaylandDevice() override; + + bool init(); + + bool getConfig(); + bool getDefaultConfig(); + bool applyConfig(); + bool isChangedConfig() const; + + // + // general + QString name() const { + return m_name.val; + } + QString sysName() const { + return m_sysName.val; + } + bool supportsDisableEvents() const { + return m_supportsDisableEvents.val; + } + void setEnabled(bool enabled) { + m_enabled.set(enabled); + } + bool isEnabled() const { + return m_enabled.val; + } + Qt::MouseButtons supportedButtons() const { + return m_supportedButtons.val; + } + + // + // advanced + bool supportsLeftHanded() const { + return m_supportsLeftHanded.val; + } + bool leftHandedEnabledByDefault() const { + return m_leftHandedEnabledByDefault.val; + } + bool isLeftHanded() const { + return m_leftHanded.val; + } + void setLeftHanded(bool set) { + m_leftHanded.set(set); + } + + bool supportsMiddleEmulation() const { + return m_supportsMiddleEmulation.val; + } + bool middleEmulationEnabledByDefault() const { + return m_middleEmulationEnabledByDefault.val; + } + bool isMiddleEmulation() const { + return m_middleEmulation.val; + } + void setMiddleEmulation(bool set) { + m_middleEmulation.set(set); + } + + // + // acceleration speed and profile + bool supportsPointerAcceleration() const { + return m_supportsPointerAcceleration.val; + } + qreal pointerAcceleration() const { + return m_pointerAcceleration.val; + } + void setPointerAcceleration(qreal acceleration) { + m_pointerAcceleration.set(acceleration); + } + + bool supportsPointerAccelerationProfileFlat() const { + return m_supportsPointerAccelerationProfileFlat.val; + } + bool defaultPointerAccelerationProfileFlat() const { + return m_defaultPointerAccelerationProfileFlat.val; + } + bool pointerAccelerationProfileFlat() const { + return m_pointerAccelerationProfileFlat.val; + } + void setPointerAccelerationProfileFlat(bool set) { + m_pointerAccelerationProfileFlat.set(set); + } + + bool supportsPointerAccelerationProfileAdaptive() const { + return m_supportsPointerAccelerationProfileAdaptive.val; + } + bool defaultPointerAccelerationProfileAdaptive() const { + return m_defaultPointerAccelerationProfileAdaptive.val; + } + bool pointerAccelerationProfileAdaptive() const { + return m_pointerAccelerationProfileAdaptive.val; + } + void setPointerAccelerationProfileAdaptive(bool set) { + m_pointerAccelerationProfileAdaptive.set(set); + } + + // + // scrolling + bool supportsNaturalScroll() const { + return m_supportsNaturalScroll.val; + } + bool naturalScrollEnabledByDefault() const { + return m_naturalScrollEnabledByDefault.val; + } + bool isNaturalScroll() const { + return m_naturalScroll.val; + } + void setNaturalScroll(bool set) { + m_naturalScroll.set(set); + } + +Q_SIGNALS: + void leftHandedChanged(); + void pointerAccelerationChanged(); + void pointerAccelerationProfileChanged(); + void enabledChanged(); + void middleEmulationChanged(); + void naturalScrollChanged(); + +private: + template + struct Prop { + explicit Prop(const QByteArray &dbusName) + : dbus(dbusName) + {} + + void set(T newVal) { + if (avail && val != newVal) { + val = newVal; + } + } + void set(const Prop &p) { + if (avail && val != p.val) { + val = p.val; + } + } + bool changed() const { + return avail && (old != val); + } + + QByteArray dbus; + bool avail; + T old; + T val; + }; + + template + bool valueLoader(Prop &prop); + + template + QString valueWriter(const Prop &prop); + + // + // general + Prop m_name = Prop("name"); + Prop m_sysName = Prop("sysName"); + Prop m_supportsDisableEvents = Prop("supportsDisableEvents"); + Prop m_enabled = Prop("enabled"); + + // + // advanced + Prop m_supportedButtons = Prop("supportedButtons"); + + Prop m_supportsLeftHanded = Prop("supportsLeftHanded"); + Prop m_leftHandedEnabledByDefault = Prop("leftHandedEnabledByDefault"); + Prop m_leftHanded = Prop("leftHanded"); + + Prop m_supportsMiddleEmulation = Prop("supportsMiddleEmulation"); + Prop m_middleEmulationEnabledByDefault = Prop("middleEmulationEnabledByDefault"); + Prop m_middleEmulation = Prop("middleEmulation"); + + // + // acceleration speed and profile + Prop m_supportsPointerAcceleration = Prop("supportsPointerAcceleration"); + Prop m_defaultPointerAcceleration = Prop("defaultPointerAcceleration"); + Prop m_pointerAcceleration = Prop("pointerAcceleration"); + + Prop m_supportsPointerAccelerationProfileFlat = Prop("supportsPointerAccelerationProfileFlat"); + Prop m_defaultPointerAccelerationProfileFlat = Prop("defaultPointerAccelerationProfileFlat"); + Prop m_pointerAccelerationProfileFlat = Prop("pointerAccelerationProfileFlat"); + + Prop m_supportsPointerAccelerationProfileAdaptive = Prop("supportsPointerAccelerationProfileAdaptive"); + Prop m_defaultPointerAccelerationProfileAdaptive = Prop("defaultPointerAccelerationProfileAdaptive"); + Prop m_pointerAccelerationProfileAdaptive = Prop("pointerAccelerationProfileAdaptive"); + + // + // scrolling + Prop m_supportsNaturalScroll = Prop("supportsNaturalScroll"); + Prop m_naturalScrollEnabledByDefault = Prop("naturalScrollEnabledByDefault"); + Prop m_naturalScroll = Prop("naturalScroll"); + + QDBusInterface *m_iface; +}; + +#endif // KWINWAYLANDDEVICE_H diff --git a/kcms/input/backends/kwin_wl/kwin_wl_device.cpp b/kcms/input/backends/kwin_wl/kwin_wl_device.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/backends/kwin_wl/kwin_wl_device.cpp @@ -0,0 +1,192 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "kwin_wl_device.h" + +#include +#include +#include + +#include "logging.h" + +namespace { +template +T valueLoaderPart(QVariant const &reply) { Q_UNUSED(reply); return T(); } + +template<> +bool valueLoaderPart(QVariant const &reply) { return reply.toBool(); } + +template<> +int valueLoaderPart(QVariant const &reply) { return reply.toInt(); } + +template<> +quint32 valueLoaderPart(QVariant const &reply) { return reply.toInt(); } + +template<> +qreal valueLoaderPart(QVariant const &reply) { return reply.toReal(); } + +template<> +QString valueLoaderPart(QVariant const &reply) { return reply.toString(); } + +template<> +Qt::MouseButtons valueLoaderPart(QVariant const &reply) { return static_cast(reply.toInt()); } +} + +KWinWaylandDevice::KWinWaylandDevice(QString dbusName) +{ + m_iface = new QDBusInterface(QStringLiteral("org.kde.KWin"), + QStringLiteral("/org/kde/KWin/InputDevice/") + dbusName, + QStringLiteral("org.kde.KWin.InputDevice"), + QDBusConnection::sessionBus(), + this); +} + +KWinWaylandDevice::~KWinWaylandDevice() +{ + delete m_iface; +} + +bool KWinWaylandDevice::init() +{ + // need to do it here in order to populate combobox and handle events + return valueLoader(m_name) && valueLoader(m_sysName); +} + +bool KWinWaylandDevice::getConfig() +{ + bool success = true; + + // general + success &= valueLoader(m_supportsDisableEvents); + success &= valueLoader(m_enabled); + // advanced + success &= valueLoader(m_supportedButtons); + success &= valueLoader(m_supportsLeftHanded); + success &= valueLoader(m_leftHandedEnabledByDefault); + success &= valueLoader(m_leftHanded); + success &= valueLoader(m_supportsMiddleEmulation); + success &= valueLoader(m_middleEmulationEnabledByDefault); + success &= valueLoader(m_middleEmulation); + // acceleration + success &= valueLoader(m_supportsPointerAcceleration); + success &= valueLoader(m_supportsPointerAccelerationProfileFlat); + success &= valueLoader(m_supportsPointerAccelerationProfileAdaptive); + success &= valueLoader(m_defaultPointerAcceleration); + success &= valueLoader(m_defaultPointerAccelerationProfileFlat); + success &= valueLoader(m_defaultPointerAccelerationProfileAdaptive); + success &= valueLoader(m_pointerAcceleration); + success &= valueLoader(m_pointerAccelerationProfileFlat); + success &= valueLoader(m_pointerAccelerationProfileAdaptive); + // natural scroll + success &= valueLoader(m_supportsNaturalScroll); + success &= valueLoader(m_naturalScrollEnabledByDefault); + success &= valueLoader(m_naturalScroll); + + return success; +} + +bool KWinWaylandDevice::getDefaultConfig() +{ + m_enabled.set(true); + m_leftHanded.set(false); + + m_pointerAcceleration.set(m_defaultPointerAcceleration); + m_pointerAccelerationProfileFlat.set(m_defaultPointerAccelerationProfileFlat); + m_pointerAccelerationProfileAdaptive.set(m_defaultPointerAccelerationProfileAdaptive); + + m_middleEmulation.set(m_middleEmulationEnabledByDefault); + m_naturalScroll.set(m_naturalScrollEnabledByDefault); + + return true; +} + +bool KWinWaylandDevice::applyConfig() +{ + QVector msgs; + + msgs << valueWriter(m_enabled) + << valueWriter(m_leftHanded) + << valueWriter(m_pointerAcceleration) + << valueWriter(m_defaultPointerAccelerationProfileFlat) + << valueWriter(m_defaultPointerAccelerationProfileAdaptive) + << valueWriter(m_middleEmulation) + << valueWriter(m_naturalScroll); + + bool success = true; + QString error_msg; + + for (QString m : msgs) { + if (!m.isNull()) { + qCCritical(KCM_INPUT) << "in error:" << m; + if (!success) { + error_msg.append("\n"); + } + error_msg.append(m); + success = false; + } + } + + if (!success) { + qCCritical(KCM_INPUT) << error_msg; + } + return success; +} + +bool KWinWaylandDevice::isChangedConfig() const +{ + return m_enabled.changed() || + m_leftHanded.changed() || + m_pointerAcceleration.changed() || + m_pointerAccelerationProfileFlat.changed() || + m_pointerAccelerationProfileAdaptive.changed() || + m_middleEmulation.changed() || + m_naturalScroll.changed(); +} + +template +QString KWinWaylandDevice::valueWriter(const Prop &prop) +{ + if (!prop.changed()) { + return QString(); + } + m_iface->setProperty(prop.dbus, prop.val); + QDBusError error = m_iface->lastError(); + if (error.isValid()) { + qCCritical(KCM_INPUT) << error.message(); + return error.message(); + } + return QString(); +} + +template +bool KWinWaylandDevice::valueLoader(Prop &prop) +{ + QVariant reply = m_iface->property(prop.dbus); + if (!reply.isValid()) { + qCCritical(KCM_INPUT) << "Error on d-bus read of" << prop.dbus; + prop.avail = false; + return false; + } + prop.avail = true; + + T replyValue = valueLoaderPart(reply); + + prop.old = replyValue; + prop.val = replyValue; + return true; +} diff --git a/kcms/input/backends/x11.cmake b/kcms/input/backends/x11.cmake --- a/kcms/input/backends/x11.cmake +++ b/kcms/input/backends/x11.cmake @@ -1,43 +1,30 @@ # // krazy:excludeall=copyright,license -set(kcminput_backend_SRCS - ${kcminput_backend_SRCS} - backends/x11/x11mousebackend.cpp +include_directories( + ${X11_X11_INCLUDE_PATH} + ${X11_Xinput_INCLUDE_PATH} + ${Evdev_INCLUDE_DIRS} + ${XORGLIBINPUT_INCLUDE_DIRS} ) -set(kcminput_backend_LIBS +set(backend_SRCS + ${backend_SRCS} + backends/x11/evdev_settings.cpp + backends/x11/x11_backend.cpp +) + +set(backend_LIBS + ${backend_LIBS} + KF5::WindowSystem Qt5::X11Extras ${X11_X11_LIB} ${X11_Xinput_LIB} - ${kcminput_backend_LIBS} ) -include_directories(${X11_X11_INCLUDE_PATH} - ${X11_Xinput_INCLUDE_PATH} - ${Evdev_INCLUDE_DIRS} - ${XORGLIBINPUT_INCLUDE_DIRS}) - if (X11_Xcursor_FOUND) - set(kcminput_backend_LIBS + set(backend_LIBS ${X11_Xcursor_LIB} - ${kcminput_backend_LIBS} + ${backend_LIBS} ) include_directories(${X11_Xcursor_INCLUDE_PATH}) endif () - - -set(kapplymousetheme_SRCS - backends/x11/kapplymousetheme.cpp) - -add_executable(kapplymousetheme ${kapplymousetheme_SRCS} ${kcminput_backend_SRCS}) - -target_link_libraries(kapplymousetheme - Qt5::Gui - Qt5::DBus - KF5::CoreAddons - KF5::ConfigCore - KF5::I18n - ${kcminput_backend_LIBS} -) - -install(TARGETS kapplymousetheme ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/kcms/input/mousesettings.h b/kcms/input/backends/x11/evdev_settings.h rename from kcms/input/mousesettings.h rename to kcms/input/backends/x11/evdev_settings.h --- a/kcms/input/mousesettings.h +++ b/kcms/input/backends/x11/evdev_settings.h @@ -1,5 +1,6 @@ /* * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,28 +17,28 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef MOUSESETTINGS_H -#define MOUSESETTINGS_H +#ifndef EVDEVSETTINGS_H +#define EVDEVSETTINGS_H #include -class MouseBackend; +class X11Backend; -enum class MouseHanded { +enum class Handed { Right = 0, Left = 1, NotSupported = -1 }; -struct MouseSettings +struct EvdevSettings { - void save(KConfig *); - void load(KConfig *, MouseBackend*); - void apply(MouseBackend*, bool force = false); + void save(); + void load(X11Backend *); + void apply(X11Backend *, bool force = false); bool handedEnabled; bool handedNeedsApply; - MouseHanded handed; + Handed handed; double accelRate; int thresholdMove; int doubleClickInterval; @@ -49,4 +50,4 @@ QString currentAccelProfile; }; -#endif // MOUSESETTINGS_H +#endif // EVDEVSETTINGS_H diff --git a/kcms/input/mousesettings.cpp b/kcms/input/backends/x11/evdev_settings.cpp rename from kcms/input/mousesettings.cpp rename to kcms/input/backends/x11/evdev_settings.cpp --- a/kcms/input/mousesettings.cpp +++ b/kcms/input/backends/x11/evdev_settings.cpp @@ -1,5 +1,6 @@ /* * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,47 +16,46 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ - -#include "mousesettings.h" - -#include "mousebackend.h" +#include "evdev_settings.h" +#include "x11_backend.h" #include #include #include #include #include "../migrationlib/kdelibs4config.h" -void MouseSettings::apply(MouseBackend* backend, bool force) +void EvdevSettings::apply(X11Backend *backend, bool force) { if (!backend) { return; } - backend->apply(*this, force); + backend->apply(force); handedNeedsApply = false; } -void MouseSettings::load(KConfig *config, MouseBackend *backend) +void EvdevSettings::load(X11Backend *backend) { + KConfig config("kcminputrc"); + // TODO: what's a good threshold default value int threshold = 0; - handed = MouseHanded::Right; + handed = Handed::Right; double accel = 1.0; QString profile; if (backend) { - backend->load(); auto handedOnServer = backend->handed(); - handedEnabled = handedOnServer != MouseHanded::NotSupported; + handedEnabled = handedOnServer != Handed::NotSupported; if (handedEnabled) { handed = handedOnServer; } accel = backend->accelRate(); threshold = backend->threshold(); profile = backend->accelerationProfile(); } - KConfigGroup group = config->group("Mouse"); + KConfigGroup group = config.group("Mouse"); double a = group.readEntry("Acceleration", -1.0); if (a == -1) accelRate = accel; @@ -70,18 +70,18 @@ QString key = group.readEntry("MouseButtonMapping"); if (key == "RightHanded") - handed = MouseHanded::Right; + handed = Handed::Right; else if (key == "LeftHanded") - handed = MouseHanded::Left; + handed = Handed::Left; reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false); currentAccelProfile = group.readEntry("AccelerationProfile"); if (currentAccelProfile.isEmpty()) { currentAccelProfile = profile; } handedNeedsApply = false; // SC/DC/AutoSelect/ChangeCursor - group = config->group("KDE"); + group = config.group("KDE"); doubleClickInterval = group.readEntry("DoubleClickInterval", 400); dragStartTime = group.readEntry("StartDragTime", 500); dragStartDist = group.readEntry("StartDragDist", 4); @@ -112,13 +112,13 @@ QDBusConnection::sessionBus().send(message); } -void MouseSettings::save(KConfig *config) +void EvdevSettings::save() { KSharedConfig::Ptr kcminputProfile = KSharedConfig::openConfig("kcminputrc"); KConfigGroup kcminputGroup(kcminputProfile, "Mouse"); kcminputGroup.writeEntry("Acceleration",accelRate); kcminputGroup.writeEntry("Threshold",thresholdMove); - if (handed == MouseHanded::Right) { + if (handed == Handed::Right) { kcminputGroup.writeEntry("MouseButtonMapping",QString("RightHanded")); } else { kcminputGroup.writeEntry("MouseButtonMapping",QString("LeftHanded")); @@ -136,7 +136,7 @@ group.writeEntry("SingleClick", singleClick, KConfig::Persistent); group.sync(); - config->sync(); + kcminputProfile->sync(); Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Mouse"), "kcminputrc"); Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("KDE"), "kdeglobals"); diff --git a/kcms/input/backends/x11/x11mousebackend.h b/kcms/input/backends/x11/x11_backend.h rename from kcms/input/backends/x11/x11mousebackend.h rename to kcms/input/backends/x11/x11_backend.h --- a/kcms/input/backends/x11/x11mousebackend.h +++ b/kcms/input/backends/x11/x11_backend.h @@ -1,5 +1,6 @@ /* * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,34 +17,48 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef XLIBMOUSEBACKEND_H -#define XLIBMOUSEBACKEND_H +#ifndef X11BACKEND_H +#define X11BACKEND_H -#include "mousebackend.h" +#include "inputbackend.h" +#include "evdev_settings.h" #include #include -class X11MouseBackend : public MouseBackend +class ConfigPlugin; + +class X11Backend : public InputBackend { Q_OBJECT public: - X11MouseBackend(QObject *parent = nullptr); - ~X11MouseBackend(); + X11Backend(QObject *parent = nullptr); + ~X11Backend(); bool isValid() const override { return m_dpy != nullptr; } void load() override; - bool supportScrollPolarity() override; - QStringList supportedAccelerationProfiles() override; - QString accelerationProfile() override; - double accelRate() override; - MouseHanded handed() override; - int threshold() override; - void apply(const MouseSettings & settings, bool force) override; - QString currentCursorTheme() override; - void applyCursorTheme(const QString &name, int size) override; + void apply(bool force = false); + + EvdevSettings* settings() { + return m_settings; + } + + bool supportScrollPolarity(); + QStringList supportedAccelerationProfiles(); + QString accelerationProfile(); + double accelRate(); + Handed handed(); + int threshold(); + + QString currentCursorTheme(); + void applyCursorTheme(const QString &name, int size); + +Q_SIGNALS: + void mouseStateChanged(); + void mousesChanged(); + void mouseReset(); private: void initAtom(); @@ -63,13 +78,14 @@ // We may still need to do something on non-X11 platform due to Xwayland. Display* m_dpy; bool m_platformX11; + EvdevSettings *m_settings = nullptr; int m_numButtons = 1; - MouseHanded m_handed = MouseHanded::NotSupported; + Handed m_handed = Handed::NotSupported; double m_accelRate = 1.0; int m_threshold = 0; int m_middleButton = -1; QStringList m_supportedAccelerationProfiles; QString m_accelerationProfile; }; -#endif // XLIBMOUSEBACKEND_H +#endif // X11BACKEND_H diff --git a/kcms/input/backends/x11/x11mousebackend.cpp b/kcms/input/backends/x11/x11_backend.cpp rename from kcms/input/backends/x11/x11mousebackend.cpp rename to kcms/input/backends/x11/x11_backend.cpp --- a/kcms/input/backends/x11/x11mousebackend.cpp +++ b/kcms/input/backends/x11/x11_backend.cpp @@ -1,5 +1,6 @@ /* * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,8 +17,8 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "x11mousebackend.h" -#include "mousesettings.h" +#include "x11_backend.h" + #include #include @@ -33,7 +34,7 @@ #include #include #ifdef HAVE_XCURSOR -# include +#include #include #endif @@ -82,19 +83,24 @@ XFreeDeviceList(info); } -X11MouseBackend::X11MouseBackend(QObject* parent) : MouseBackend(parent), m_dpy(nullptr) +X11Backend::X11Backend(QObject* parent) + : InputBackend(parent) { + m_mode = InputBackendMode::XEvdev; + m_platformX11 = QX11Info::isPlatformX11(); if (m_platformX11) { m_dpy = QX11Info::display(); } else { + // TODO: remove this - not needed anymore with Wayland backend! // let's hope we have a compatibility system like Xwayland ready m_dpy = XOpenDisplay(nullptr); } + m_settings = new EvdevSettings(); initAtom(); } -void X11MouseBackend::initAtom() +void X11Backend::initAtom() { if (!m_dpy) { return; @@ -112,44 +118,45 @@ } -X11MouseBackend::~X11MouseBackend() +X11Backend::~X11Backend() { if (!m_platformX11 && m_dpy) { XCloseDisplay(m_dpy); } + delete m_settings; } -bool X11MouseBackend::supportScrollPolarity() +bool X11Backend::supportScrollPolarity() { return m_numButtons >= 5; } -QStringList X11MouseBackend::supportedAccelerationProfiles() +QStringList X11Backend::supportedAccelerationProfiles() { return m_supportedAccelerationProfiles; } -QString X11MouseBackend::accelerationProfile() +QString X11Backend::accelerationProfile() { return m_accelerationProfile; } -double X11MouseBackend::accelRate() +double X11Backend::accelRate() { return m_accelRate; } -MouseHanded X11MouseBackend::handed() +Handed X11Backend::handed() { return m_handed; } -int X11MouseBackend::threshold() +int X11Backend::threshold() { return m_threshold; } -void X11MouseBackend::load() +void X11Backend::load() { if (!m_dpy) { return; @@ -165,20 +172,20 @@ m_numButtons = XGetPointerMapping(m_dpy, map, 256); m_middleButton = -1; - m_handed = MouseHanded::NotSupported; + m_handed = Handed::NotSupported; // ## keep this in sync with KGlobalSettings::mouseSettings if (m_numButtons == 2) { if (map[0] == 1 && map[1] == 2) { - m_handed = MouseHanded::Right; + m_handed = Handed::Right; } else if (map[0] == 2 && map[1] == 1) { - m_handed = MouseHanded::Left; + m_handed = Handed::Left; } } else if (m_numButtons >= 3) { m_middleButton = map[1]; if (map[0] == 1 && map[2] == 3) { - m_handed = MouseHanded::Right; + m_handed = Handed::Right; } else if (map[0] == 3 && map[2] == 1) { - m_handed = MouseHanded::Left; + m_handed = Handed::Left; } } @@ -239,29 +246,31 @@ } else if (flatEnabled) { m_accelerationProfile = PROFILE_FLAT; } + + m_settings->load(this); } -void X11MouseBackend::apply(const MouseSettings& settings, bool force) +void X11Backend::apply(bool force) { // 256 might seems extreme, but X has already been known to return 32, // and we don't want to truncate things. Xlib limits the table to 256 bytes, // so it's a good upper bound.. unsigned char map[256]; XGetPointerMapping(m_dpy, map, 256); - if (settings.handedEnabled && (settings.handedNeedsApply || force)) { + if (m_settings->handedEnabled && (m_settings->handedNeedsApply || force)) { if (m_numButtons == 1) { map[0] = (unsigned char) 1; } else if (m_numButtons == 2) { - if (settings.handed == MouseHanded::Right) { + if (m_settings->handed == Handed::Right) { map[0] = (unsigned char) 1; map[1] = (unsigned char) 3; } else { map[0] = (unsigned char) 3; map[1] = (unsigned char) 1; } } else { // 3 buttons and more - if (settings.handed == MouseHanded::Right) { + if (m_settings->handed == Handed::Right) { map[0] = (unsigned char) 1; map[1] = (unsigned char) m_middleButton; map[2] = (unsigned char) 3; @@ -282,30 +291,30 @@ // apply reverseScrollPolarity for all non-touchpad pointer, touchpad // are belong to kcm touchpad. - XIForallPointerDevices(m_dpy, [this, &settings](XDeviceInfo * info) { + XIForallPointerDevices(m_dpy, [this](XDeviceInfo * info) { int deviceid = info->id; if (info->type == m_touchpadAtom) { return; } - if (libinputApplyReverseScroll(deviceid, settings.reverseScrollPolarity)) { + if (libinputApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity)) { return; } - evdevApplyReverseScroll(deviceid, settings.reverseScrollPolarity); + evdevApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity); }); } XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { - libinputApplyAccelerationProfile(info->deviceid, settings.currentAccelProfile); + libinputApplyAccelerationProfile(info->deviceid, m_settings->currentAccelProfile); }); XChangePointerControl(m_dpy, - true, true, int(qRound(settings.accelRate * 10)), 10, settings.thresholdMove); + true, true, int(qRound(m_settings->accelRate * 10)), 10, m_settings->thresholdMove); XFlush(m_dpy); } -QString X11MouseBackend::currentCursorTheme() +QString X11Backend::currentCursorTheme() { if (!m_dpy) { return QString(); @@ -320,7 +329,7 @@ return QFile::decodeName(name); } -void X11MouseBackend::applyCursorTheme(const QString& theme, int size) +void X11Backend::applyCursorTheme(const QString& theme, int size) { #ifdef HAVE_XCURSOR @@ -344,7 +353,7 @@ #endif } -bool X11MouseBackend::evdevApplyReverseScroll(int deviceid, bool reverse) +bool X11Backend::evdevApplyReverseScroll(int deviceid, bool reverse) { // Check atom availability first. if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None || @@ -413,7 +422,7 @@ return true; } -bool X11MouseBackend::libinputApplyReverseScroll(int deviceid, bool reverse) +bool X11Backend::libinputApplyReverseScroll(int deviceid, bool reverse) { // Check atom availability first. if (m_libinputNaturalScrollAtom == None) { @@ -444,7 +453,7 @@ return true; } -void X11MouseBackend::libinputApplyAccelerationProfile(int deviceid, QString profile) +void X11Backend::libinputApplyAccelerationProfile(int deviceid, QString profile) { // Check atom availability first. if (m_libinputAccelProfileAvailableAtom == None || m_libinputAccelProfileEnabledAtom == None) { diff --git a/kcms/input/inputbackend.h b/kcms/input/inputbackend.h new file mode 100644 --- /dev/null +++ b/kcms/input/inputbackend.h @@ -0,0 +1,73 @@ +/* + * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef INPUTBACKEND_H +#define INPUTBACKEND_H + +#include +#include +#include + +class ConfigPlugin; + +enum class InputBackendMode { + KWinWayland = 0, + XLibinput = 1, // TODO + XEvdev = 2 +}; + +class InputBackend : public QObject +{ + Q_OBJECT + +protected: + explicit InputBackend(QObject *parent) : QObject(parent) {} + InputBackendMode m_mode; + +public: + static InputBackend *implementation(QObject *parent = nullptr); + + InputBackendMode mode() { + return m_mode; + } + + virtual bool isValid() const { return false; } + + virtual void load() {} + + virtual bool applyConfig(const QVariantHash &) { return false; } + virtual bool getConfig(QVariantHash &) { return false; } + + virtual bool applyConfig() { return false; } + virtual bool getConfig() { return false; } + + virtual bool getDefaultConfig() { return false; } + virtual bool isChangedConfig() const { return false; } + + virtual QString errorString() const { return QString(); } + + virtual int deviceCount() const { return 0; } + virtual QVector getDevices() const { return QVector(); } + +Q_SIGNALS: + void deviceAdded(bool success); + void deviceRemoved(int index); +}; + +#endif // INPUTBACKEND_H diff --git a/kcms/input/mousebackend.cpp b/kcms/input/inputbackend.cpp rename from kcms/input/mousebackend.cpp rename to kcms/input/inputbackend.cpp --- a/kcms/input/mousebackend.cpp +++ b/kcms/input/inputbackend.cpp @@ -1,5 +1,6 @@ /* * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,29 +16,27 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "inputbackend.h" -#include "mousebackend.h" - -#include "backends/x11/x11mousebackend.h" +#include "backends/x11/x11_backend.h" +#include "backends/kwin_wl/kwin_wl_backend.h" #include "logging.h" -#include -#include - -#include +#include -MouseBackend *MouseBackend::implementation() +InputBackend *InputBackend::implementation(QObject *parent) { - //There are multiple possible backends, always use X11 backend for now. - static QThreadStorage> backend; - if (!backend.hasLocalData()) { + //There are multiple possible backends + if (KWindowSystem::isPlatformX11()) { qCDebug(KCM_INPUT) << "Using X11 backend"; - backend.setLocalData(QSharedPointer(new X11MouseBackend)); + return new X11Backend(parent); + } + else if (KWindowSystem::isPlatformWayland()) { + qCDebug(KCM_INPUT) << "Using KWin+Wayland backend"; + return new KWinWaylandBackend(parent); + } + else { + qCCritical(KCM_INPUT) << "Not able to select appropriate backend."; + return nullptr; } - return backend.localData().data(); - -#if 0 - qCCritical(KCM_INPUT) << "Not able to select appropriate backend."; - return nullptr; -#endif } diff --git a/kcms/input/backends/x11/kapplymousetheme.cpp b/kcms/input/kapplymousetheme.cpp rename from kcms/input/backends/x11/kapplymousetheme.cpp rename to kcms/input/kapplymousetheme.cpp --- a/kcms/input/backends/x11/kapplymousetheme.cpp +++ b/kcms/input/kapplymousetheme.cpp @@ -4,6 +4,7 @@ * Copyright (c) 1999 Matthias Hoelzer-Kluepfel * Copyright (c) 2005 Lubos Lunak * Copyright (c) 2017 Xuetian Weng + * Copyright (c) 2018 Roman Gilg * * Requires the Qt widget libraries, available at no cost at * http://www.troll.no/ @@ -22,10 +23,14 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "backends/x11/x11_backend.h" + +#include + #include #include -#include "mousebackend.h" +#include int main( int argc, char* argv[] ) { @@ -35,20 +40,27 @@ return 1; QString theme = QFile::decodeName(argv[ 1 ]); QString size = QFile::decodeName(argv[ 2 ]); - auto backend = MouseBackend::implementation(); - if (!backend || !backend->isValid()) { + + if (!KWindowSystem::isPlatformX11()) { + qDebug() << "X11 backend not detected. Exit."; + return 2; + } + + X11Backend backend; + + if (!backend.isValid()) { return 2; } // Note: If you update this code, update main.cpp as well. // use a default value for theme only if it's not configured at all, not even in X resources - if(theme.isEmpty() && backend->currentCursorTheme().isEmpty()) + if(theme.isEmpty() && backend.currentCursorTheme().isEmpty()) { theme = "breeze_cursors"; ret = 10; // means to switch to default } - backend->applyCursorTheme(theme, size.toInt()); + backend.applyCursorTheme(theme, size.toInt()); return ret; } diff --git a/kcms/input/kcm/configcontainer.h b/kcms/input/kcm/configcontainer.h new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/configcontainer.h @@ -0,0 +1,53 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef CONFIGCONTAINER_H +#define CONFIGCONTAINER_H + +#include + +class ConfigPlugin; + +class ConfigContainer : public KCModule +{ + Q_OBJECT + +public: + explicit ConfigContainer(QWidget *parent, + const QVariantList &args = QVariantList()); + + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + void resizeEvent(QResizeEvent *event) override; + + void load() override; + void save() override; + void defaults() override; + + void kcmLoad() { KCModule::load(); } + void kcmSave() { KCModule::save(); } + void kcmDefaults() { KCModule::defaults(); } + +protected: + void hideEvent(QHideEvent *) override; + +private: + ConfigPlugin* m_plugin = nullptr; +}; + +#endif // CONFIGCONTAINER_H diff --git a/kcms/input/kcm/configcontainer.cpp b/kcms/input/kcm/configcontainer.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/configcontainer.cpp @@ -0,0 +1,75 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "configcontainer.h" +#include "configplugin.h" +#include "kcm/libinput/libinput_config.h" +#include "kcm/xlib/xlib_config.h" + +#include + +extern "C" +{ + Q_DECL_EXPORT void kcminit_mouse() + { + if (KWindowSystem::isPlatformX11()) { + XlibConfig::kcmInit(); + } + } +} + +ConfigContainer::ConfigContainer(QWidget *parent, const QVariantList &args) + : KCModule(parent, args) +{ + m_plugin = ConfigPlugin::implementation(this); +} + +QSize ConfigContainer::minimumSizeHint() const +{ + return m_plugin->minimumSizeHint(); +} +QSize ConfigContainer::sizeHint() const +{ + return m_plugin->sizeHint(); +} +void ConfigContainer::resizeEvent(QResizeEvent *event) +{ + Q_EMIT changed(false); + m_plugin->resize(this->size()); +} + +void ConfigContainer::load() +{ + m_plugin->load(); +} + +void ConfigContainer::save() +{ + m_plugin->save(); +} + +void ConfigContainer::defaults() +{ + m_plugin->defaults(); +} + +void ConfigContainer::hideEvent(QHideEvent *e) +{ + m_plugin->hideEvent(e); + KCModule::hideEvent(e); +} diff --git a/kcms/input/logging.h b/kcms/input/kcm/configplugin.h rename from kcms/input/logging.h rename to kcms/input/kcm/configplugin.h --- a/kcms/input/logging.h +++ b/kcms/input/kcm/configplugin.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,10 +16,33 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef KCM_INPUT_LOGGING_H -#define KCM_INPUT_LOGGING_H +#ifndef CONFIGPLUGIN_H +#define CONFIGPLUGIN_H -#include +#include -Q_DECLARE_LOGGING_CATEGORY(KCM_INPUT) -#endif +class ConfigContainer; +class InputBackend; + +class ConfigPlugin : public QWidget +{ + Q_OBJECT + +public: + static ConfigPlugin *implementation(ConfigContainer *parent); + + explicit ConfigPlugin(ConfigContainer *parent); + virtual ~ConfigPlugin() {} + + virtual void load() {} + virtual void save() {} + virtual void defaults() {} + + void hideEvent(QHideEvent *) override {} + +protected: + ConfigContainer *m_parent; + InputBackend *m_backend; +}; + +#endif // CONFIGPLUGIN_H diff --git a/kcms/input/kcm/configplugin.cpp b/kcms/input/kcm/configplugin.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/configplugin.cpp @@ -0,0 +1,49 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "configplugin.h" +#include "configcontainer.h" +#include "inputbackend.h" + +#include "libinput/libinput_config.h" +#include "xlib/xlib_config.h" + +#include + +ConfigPlugin* ConfigPlugin::implementation(ConfigContainer *parent) +{ + InputBackend *backend = InputBackend::implementation(parent); + InputBackendMode mode = backend->mode(); + + if (mode == InputBackendMode::KWinWayland || mode == InputBackendMode::XLibinput) { + qCDebug(KCM_INPUT) << "With libinput user interface."; + return new LibinputConfig(parent, backend); + } else if (mode == InputBackendMode::XEvdev) { + qCDebug(KCM_INPUT) << "With X11 evdev user interface."; + return new XlibConfig(parent, backend); + } else { + qCCritical(KCM_INPUT) << "Not able to select appropriate backend."; + return nullptr; + } +} + +ConfigPlugin::ConfigPlugin(ConfigContainer *parent) + : QWidget(parent), + m_parent(parent) +{ +} diff --git a/kcms/input/kcm/libinput/components/ExclGroupBox.qml b/kcms/input/kcm/libinput/components/ExclGroupBox.qml new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/libinput/components/ExclGroupBox.qml @@ -0,0 +1,57 @@ +/* + * Copyright 2017 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 1.4 as Controls + +import org.kde.plasma.core 2.0 as PlasmaCore + +Column { + spacing: units.smallSpacing / 2 + property alias label: textlabel.text + property alias model: repeater.model + property alias current: exlGroupbox.current + + function itemAt(index) { + return repeater.itemAt(index) + } + + Controls.Label { + id: textlabel + } + + Controls.ExclusiveGroup { id: exlGroupbox } + Column { + leftPadding: units.smallSpacing + spacing: units.smallSpacing / 2 + + Repeater { + id: repeater + Controls.RadioButton { + text: modelData + exclusiveGroup: exlGroupbox + + property alias tooltiptext: tooltip.text + + ToolTip { + id: tooltip + } + } + } + } +} diff --git a/kcms/input/mousesettings.h b/kcms/input/kcm/libinput/components/ToolTip.qml rename from kcms/input/mousesettings.h rename to kcms/input/kcm/libinput/components/ToolTip.qml --- a/kcms/input/mousesettings.h +++ b/kcms/input/kcm/libinput/components/ToolTip.qml @@ -1,5 +1,5 @@ /* - * Copyright 2017 Xuetian Weng + * Copyright 2017 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -16,37 +16,37 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef MOUSESETTINGS_H -#define MOUSESETTINGS_H - -#include - -class MouseBackend; - -enum class MouseHanded { - Right = 0, - Left = 1, - NotSupported = -1 -}; - -struct MouseSettings -{ - void save(KConfig *); - void load(KConfig *, MouseBackend*); - void apply(MouseBackend*, bool force = false); - - bool handedEnabled; - bool handedNeedsApply; - MouseHanded handed; - double accelRate; - int thresholdMove; - int doubleClickInterval; - int dragStartTime; - int dragStartDist; - bool singleClick; - int wheelScrollLines; - bool reverseScrollPolarity; - QString currentAccelProfile; -}; - -#endif // MOUSESETTINGS_H +import QtQuick 2.7 + +import QtQuick.Controls.Private 1.0 + +MouseArea { + anchors.fill: parent + + property string text: "" + + hoverEnabled: true + acceptedButtons: Qt.NoButton + + onEntered: timer.start() + onExited: timer.killTooltip() + onPositionChanged: timer.resetTooltip() + + Timer { + id: timer + interval: 1000 + onTriggered: { + Tooltip.showText(parent, Qt.point(mouseX, mouseY), text) + } + + function killTooltip() { + stop() + Tooltip.hideText() + } + + function resetTooltip() { + restart() + Tooltip.hideText() + } + } +} diff --git a/kcms/input/kcm/libinput/libinput_config.h b/kcms/input/kcm/libinput/libinput_config.h new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/libinput/libinput_config.h @@ -0,0 +1,59 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef LIBINPUTCONFIG_H +#define LIBINPUTCONFIG_H + +#include "../configplugin.h" + +class QHideEvent; +class QQuickWidget; +class KMessageWidget; + +class LibinputConfig : public ConfigPlugin +{ + Q_OBJECT + +public: + explicit LibinputConfig(ConfigContainer *parent, InputBackend *backend); + virtual ~LibinputConfig() {} + + void load() override; + void save() override; + void defaults() override; + + QSize sizeHint() const override; + QSize minimumSizeHint() const override; + + void hideEvent(QHideEvent *) override {} + +private Q_SLOTS: + void onChange(); + void onDeviceAdded(bool success); + void onDeviceRemoved(int index); + +private: + void hideErrorMessage(); + + QQuickWidget *m_view; + KMessageWidget *m_errorMessage; + + bool m_initError; +}; + +#endif // LIBINPUTCONFIG_H diff --git a/kcms/input/kcm/libinput/libinput_config.cpp b/kcms/input/kcm/libinput/libinput_config.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/libinput/libinput_config.cpp @@ -0,0 +1,225 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#include "libinput_config.h" +#include "../configcontainer.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include "inputbackend.h" + +static QVariant getDeviceList(InputBackend *backend) +{ + return QVariant::fromValue(backend->getDevices().toList()); +} + +LibinputConfig::LibinputConfig(ConfigContainer *parent, InputBackend *backend) + : ConfigPlugin(parent) +{ + m_backend = backend; + + KAboutData* data = new KAboutData(QStringLiteral("kcmmouse"), + i18n("Pointer device KCM"), + QStringLiteral("1.0"), + i18n("System Settings module for managing mice and trackballs."), + KAboutLicense::GPL_V2, + i18n("Copyright 2018 Roman Gilg"), + QString()); + + data->addAuthor(i18n("Roman Gilg"), + i18n("Developer"), + QStringLiteral("subdiff@gmail.com")); + + m_parent->setAboutData(data); + + m_initError = !m_backend->errorString().isNull(); + + m_view = new QQuickWidget(this); + + m_errorMessage = new KMessageWidget(this); + m_errorMessage->setCloseButtonVisible(false); + m_errorMessage->setWordWrap(true); + m_errorMessage->setVisible(false); + + QVBoxLayout *layout = new QVBoxLayout(parent); + + layout->addWidget(m_errorMessage); + layout->addWidget(m_view); + parent->setLayout(layout); + + m_view->setResizeMode(QQuickWidget::SizeRootObjectToView); + m_view->setClearColor(Qt::transparent); + m_view->setAttribute(Qt::WA_AlwaysStackOnTop); + + m_view->rootContext()->setContextProperty("backend", m_backend); + m_view->rootContext()->setContextProperty("deviceModel", getDeviceList(m_backend)); + + KDeclarative::KDeclarative kdeclarative; + kdeclarative.setDeclarativeEngine(m_view->engine()); + kdeclarative.setupBindings(); + m_view->setSource(QUrl("qrc:/libinput/main.qml")); + + if (m_initError) { + m_errorMessage->setMessageType(KMessageWidget::Error); + m_errorMessage->setText(m_backend->errorString()); + QMetaObject::invokeMethod(m_errorMessage, "animatedShow", + Qt::QueuedConnection); + } else { + connect(m_backend, SIGNAL(deviceAdded(bool)), this, SLOT(onDeviceAdded(bool))); + connect(m_backend, SIGNAL(deviceRemoved(int)), this, SLOT(onDeviceRemoved(int))); + connect(m_view->rootObject(), SIGNAL(changeSignal()), this, SLOT(onChange())); + } + + m_view->show(); +} + +QSize LibinputConfig::sizeHint() const +{ + return QQmlProperty::read(m_view->rootObject(), "sizeHint").toSize(); +} + +QSize LibinputConfig::minimumSizeHint() const +{ + return QQmlProperty::read(m_view->rootObject(), "minimumSizeHint").toSize(); +} + +void LibinputConfig::load() +{ + // in case of critical init error in backend, don't try + if (m_initError) { + return; + } + + if (!m_backend->getConfig()) { + m_errorMessage->setMessageType(KMessageWidget::Error); + m_errorMessage->setText(i18n("Error while loading values. See logs for more informations. Please restart this configuration module.")); + m_errorMessage->animatedShow(); + } else { + if (!m_backend->deviceCount()) { + m_errorMessage->setMessageType(KMessageWidget::Information); + m_errorMessage->setText(i18n("No pointer device found. Connect now.")); + m_errorMessage->animatedShow(); + } + } + QMetaObject::invokeMethod(m_view->rootObject(), "syncValuesFromBackend"); +} + +void LibinputConfig::save() +{ + if (!m_backend->applyConfig()) { + m_errorMessage->setMessageType(KMessageWidget::Error); + m_errorMessage->setText(i18n("Not able to save all changes. See logs for more informations. Please restart this configuration module and try again.")); + m_errorMessage->animatedShow(); + } else { + hideErrorMessage(); + } + // load newly written values + load(); + // in case of error, config still in changed state + emit m_parent->changed(m_backend->isChangedConfig()); +} + +void LibinputConfig::defaults() +{ + // in case of critical init error in backend, don't try + if (m_initError) { + return; + } + + if (!m_backend->getDefaultConfig()) { + m_errorMessage->setMessageType(KMessageWidget::Error); + m_errorMessage->setText(i18n("Error while loading default values. Failed to set some options to their default values.")); + m_errorMessage->animatedShow(); + } + QMetaObject::invokeMethod(m_view->rootObject(), "syncValuesFromBackend"); + emit m_parent->changed(m_backend->isChangedConfig()); +} + +void LibinputConfig::onChange() +{ + if (!m_backend->deviceCount()) { + return; + } + hideErrorMessage(); + emit m_parent->changed(m_backend->isChangedConfig()); +} + +void LibinputConfig::onDeviceAdded(bool success) +{ + QQuickItem *rootObj = m_view->rootObject(); + + if (!success) { + m_errorMessage->setMessageType(KMessageWidget::Error); + m_errorMessage->setText(i18n("Error while adding newly connected device. Please reconnect it and restart this configuration module.")); + } + + int activeIndex; + if (m_backend->deviceCount() == 1) { + // if no pointer device was connected previously, show the new device and hide the no-device-message + activeIndex = 0; + hideErrorMessage(); + } else { + activeIndex = QQmlProperty::read(rootObj, "deviceIndex").toInt(); + } + m_view->rootContext()->setContextProperty("deviceModel", getDeviceList(m_backend)); + QMetaObject::invokeMethod(rootObj, "resetModel", Q_ARG(QVariant, activeIndex)); + QMetaObject::invokeMethod(rootObj, "syncValuesFromBackend"); +} + +void LibinputConfig::onDeviceRemoved(int index) +{ + QQuickItem *rootObj = m_view->rootObject(); + + int activeIndex = QQmlProperty::read(rootObj, "deviceIndex").toInt(); + if (activeIndex == index) { + m_errorMessage->setMessageType(KMessageWidget::Information); + if (m_backend->deviceCount()) { + m_errorMessage->setText(i18n("Pointer device disconnected. Closed its setting dialog.")); + } else { + m_errorMessage->setText(i18n("Pointer device disconnected. No other devices found.")); + } + m_errorMessage->animatedShow(); + activeIndex = 0; + } else { + if (index < activeIndex) { + activeIndex--; + } + } + m_view->rootContext()->setContextProperty("deviceModel", getDeviceList(m_backend)); + QMetaObject::invokeMethod(m_view->rootObject(), "resetModel", Q_ARG(QVariant, activeIndex)); + QMetaObject::invokeMethod(rootObj, "syncValuesFromBackend"); + + emit m_parent->changed(m_backend->isChangedConfig()); +} + +void LibinputConfig::hideErrorMessage() +{ + if (m_errorMessage->isVisible()) { + m_errorMessage->animatedHide(); + } +} diff --git a/kcms/input/kcm/libinput/main.qml b/kcms/input/kcm/libinput/main.qml new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/libinput/main.qml @@ -0,0 +1,323 @@ +/* + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +import QtQuick 2.7 +import QtQuick.Controls 1.4 as Controls +import QtQuick.Layouts 1.3 as Layouts +import QtQuick.Controls.Styles 1.4 as Styles + +import org.kde.plasma.core 2.0 as PlasmaCore + +import "components" + +Item { + id: root + + property size sizeHint: Qt.size(maincol.width, maincol.height) + property size minimumSizeHint: Qt.size(maincol.width/2, deviceSelector.height) + property alias deviceIndex: deviceSelector.currentIndex + signal changeSignal() + + property QtObject device + property int deviceCount: backend.deviceCount + + property bool loading: false + + function resetModel(index) { + deviceCount = backend.deviceCount + maincol.enabled = deviceCount + deviceSelector.enabled = deviceCount > 1 + + loading = true + if (deviceCount) { + device = deviceModel[index] + deviceSelector.model = deviceModel + deviceSelector.currentIndex = index + console.log("Configuration of device '" + + (index + 1) + " : " + device.name + "' opened") + } else { + deviceSelector.model = [""] + console.log("No device found") + } + loading = false + } + + function syncValuesFromBackend() { + loading = true + + deviceEnabled.load() + leftHanded.load() + accelSpeed.load() + accelProfile.load() + + naturalScroll.load() + + loading = false + } + + Controls.ScrollView { + anchors.fill: parent + + Layouts.ColumnLayout { + id: maincol + enabled: deviceCount + spacing: units.largeSpacing + + Layouts.RowLayout { + spacing: units.largeSpacing + + Controls.Label { + text: i18n("Device:") + } + + Controls.ComboBox { + id: deviceSelector + enabled: deviceCount > 1 + Layouts.Layout.fillWidth: true + model: deviceModel + textRole: "name" + + onCurrentIndexChanged: { + if (deviceCount) { + device = deviceModel[currentIndex] + if (!loading) { + changeSignal() + } + console.log("Configuration of device '" + + (currentIndex+1) + " : " + device.name + "' opened") + } + root.syncValuesFromBackend() + } + } + } + + Column { + spacing: units.smallSpacing * 2 + + Column { + leftPadding: units.smallSpacing + Column { + spacing: units.smallSpacing + Controls.Label { + text: i18n("General settings:") + } + + Column { + leftPadding: units.smallSpacing + Column { + spacing: units.smallSpacing + Controls.CheckBox { + id: deviceEnabled + text: i18n("Device enabled") + + function load() { + if (!maincol.enabled) { + checked = false + return + } + enabled = device.supportsDisableEvents + checked = enabled && device.enabled + } + + onCheckedChanged: { + if (enabled && !root.loading) { + device.enabled = checked + root.changeSignal() + } + } + + ToolTip { + text: i18n("Accept input through this device.") + } + } + + Controls.CheckBox { + id: leftHanded + text: i18n("Left handed mode") + + function load() { + if (!maincol.enabled) { + checked = false + return + } + enabled = device.supportsLeftHanded + checked = enabled && device.leftHanded + } + + onCheckedChanged: { + if (enabled && !root.loading) { + device.leftHanded = checked + root.changeSignal() + } + } + + ToolTip { + text: i18n("Swap left and right buttons.") + } + } + + Controls.CheckBox { + id: middleEmulation + text: i18n("Emulate middle button") + + function load() { + if (!maincol.enabled) { + checked = false + return + } + enabled = device.supportsMiddleEmulation + checked = enabled && device.middleEmulation + } + + onCheckedChanged: { + if (enabled && !root.loading) { + device.middleEmulation = checked + root.changeSignal() + } + } + + ToolTip { + text: i18n("Clicking left and right button simultaneously sends middle button click.") + } + } + } + } + } + } + + Column { + leftPadding: units.smallSpacing + Column { + spacing: units.smallSpacing + Controls.Label { + text: i18n("Acceleration:") + } + + Column { + leftPadding: units.smallSpacing + Column { + spacing: units.smallSpacing * 2 + + Row { + Controls.Slider { + id: accelSpeed + anchors.verticalCenter: parent.verticalCenter + + tickmarksEnabled: true + + minimumValue: 1 + maximumValue: 10 + stepSize: 1 + + implicitWidth: units.gridUnit * 9 + + function load() { + enabled = device.supportsPointerAcceleration + if (!enabled) { + value = 0.1 + return + } + // transform libinput's pointer acceleration range [-1, 1] to slider range [1, 10] + value = 4.5 * device.pointerAcceleration + 5.5 + } + + onValueChanged: { + if (device != undefined && enabled && !root.loading) { + // transform slider range [1, 10] to libinput's pointer acceleration range [-1, 1] + device.pointerAcceleration = Math.round( (value - 5.5) / 4.5 * 100 ) / 100 + root.changeSignal() + } + } + } + } + + ExclGroupBox { + id: accelProfile + label: i18n("Acceleration Profile:") + model: [i18n("Flat"), i18n("Adaptive")] + + function load() { + enabled = device.supportsPointerAccelerationProfileAdaptive + + if (!enabled) { + itemAt(0).checked = false + itemAt(1).checked = false + return + } + + itemAt(0).tooltiptext = i18n("Cursor moves the same distance as finger.") + itemAt(1).tooltiptext = i18n("Cursor travel distance depends on movement speed of finger.") + + var toCheck = device.pointerAccelerationProfileAdaptive ? 1 : 0 + itemAt(toCheck).checked = true + } + + onCurrentChanged: { + if (enabled && !root.loading) { + device.pointerAccelerationProfileFlat = itemAt(0).checked + device.pointerAccelerationProfileAdaptive = itemAt(1).checked + root.changeSignal() + } + } + } + } + } + } + } + + Column { + leftPadding: units.smallSpacing + Column { + spacing: units.smallSpacing + Controls.Label { + text: i18n("Scrolling:") + } + + Column { + leftPadding: units.smallSpacing + Column { + spacing: units.smallSpacing + + Controls.CheckBox { + id: naturalScroll + text: i18n("Invert scroll direction") + + function load() { + enabled = device.supportsNaturalScroll + checked = enabled && device.naturalScroll + } + + onCheckedChanged: { + if (enabled && !root.loading) { + device.naturalScroll = checked + root.changeSignal() + } + } + + ToolTip { + text: i18n("Touchscreen like scrolling.") + } + } + } + } + } + } + } + } + } +} diff --git a/kcms/input/kcm/resources.qrc b/kcms/input/kcm/resources.qrc new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/resources.qrc @@ -0,0 +1,7 @@ + + + libinput/main.qml + libinput/components/ExclGroupBox.qml + libinput/components/ToolTip.qml + + diff --git a/kcms/input/kcmmouse.ui b/kcms/input/kcm/xlib/kcmmouse.ui rename from kcms/input/kcmmouse.ui rename to kcms/input/kcm/xlib/kcmmouse.ui diff --git a/kcms/input/kcm/xlib/xlib_config.h b/kcms/input/kcm/xlib/xlib_config.h new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/xlib/xlib_config.h @@ -0,0 +1,74 @@ +/* + * Copyright 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * Copyright 1999 Dirk A. Mueller + * Copyright 2000 David Faure + * Copyright 2018 Roman Gilg + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef XLIBCONFIG_H +#define XLIBCONFIG_H + +#include "../configplugin.h" +#include "backends/x11/evdev_settings.h" + +#include "ui_kcmmouse.h" +#include + +#include + +class QCheckBox; +class QDoubleSpinBox; +class QSlider; +class QSpinBox; +class QTabWidget; + +class X11Backend; + +class XlibConfig : public ConfigPlugin, public Ui::KCMMouse +{ + Q_OBJECT +public: + XlibConfig(ConfigContainer *parent, InputBackend *backend); + ~XlibConfig() = default; + + static void kcmInit(); + + void load() override; + void save() override; + void defaults() override; + +private Q_SLOTS: + void slotHandedChanged(int val); + void slotScrollPolarityChanged(); + void checkAccess(); + void slotThreshChanged(int value); + void slotDragStartDistChanged(int value); + void slotWheelScrollLinesChanged(int value); + +private: + double getAccel(); + int getThreshold(); + Handed getHandedness(); + + void setAccel(double); + void setThreshold(int); + void setHandedness(Handed); + + X11Backend *m_backend; +}; + +#endif // XLIBCONFIG_H diff --git a/kcms/input/mouse.cpp b/kcms/input/kcm/xlib/xlib_config.cpp rename from kcms/input/mouse.cpp rename to kcms/input/kcm/xlib/xlib_config.cpp --- a/kcms/input/mouse.cpp +++ b/kcms/input/kcm/xlib/xlib_config.cpp @@ -1,214 +1,229 @@ /* - * mouse.cpp + * Copyright 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * Copyright 1999 Dirk A. Mueller + * Copyright 1999 Matthias Hoelzer-Kluepfel + * Copyright 2000 David Faure + * Copyright 2000 Bernd Gehrmann + * Copyright 2000 Rik Hemsley + * Copyright 2000 Brad Hughes + * Copyright 2001 Ralf Nolden + * Copyright 2004 Brad Hards + * Copyright 2018 Roman Gilg * - * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. * - * Layout management, enhancements: - * Copyright (c) 1999 Dirk A. Mueller + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. * - * SC/DC/AutoSelect/ChangeCursor: - * Copyright (c) 2000 David Faure - * - * Double click interval, drag time & dist - * Copyright (c) 2000 Bernd Gehrmann - * - * Large cursor support - * Visual activation TODO: speed - * Copyright (c) 2000 Rik Hemsley - * - * White cursor support - * TODO: give user the option to choose a certain cursor font - * -> Theming - * - * General/Advanced tabs - * Copyright (c) 2000 Brad Hughes - * - * redesign for KDE 2.2 - * Copyright (c) 2001 Ralf Nolden - * - * Logitech mouse support - * Copyright (C) 2004 Brad Hards - * - * Requires the Qt widget libraries, available at no cost at - * http://www.troll.no/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "xlib_config.h" -#include -#include -#include -#include -#include -#include +#include "backends/x11/x11_backend.h" +#include "../configcontainer.h" + +#include "../../../migrationlib/kdelibs4config.h" + +#include +#include #include #include -#include +//#include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include -#include "mouse.h" -#include "mousebackend.h" -#include "mousesettings.h" +#include -#include +#include +#include -#undef Below +void XlibConfig::kcmInit() +{ + X11Backend *backend = dynamic_cast(InputBackend::implementation()); + if (!backend) { + return; + } -#include "../migrationlib/kdelibs4config.h" + backend->settings()->load(backend); + backend->settings()->apply(backend, true); // force -K_PLUGIN_FACTORY(MouseConfigFactory, - registerPlugin(); // mouse - ) + KConfigGroup group = KConfig("kcminputrc", KConfig::NoGlobals).group("Mouse"); + QString theme = group.readEntry("cursorTheme", QString()); + QString size = group.readEntry("cursorSize", QString()); + if (backend) { + int intSize = -1; + if (size.isEmpty()) { + bool ok; + uint value = size.toUInt(&ok); + if (ok) { + intSize = value; + } + } + // Note: If you update this code, update kapplymousetheme as well. -MouseConfig::MouseConfig(QWidget *parent, const QVariantList &args) - : KCModule(parent, args), - backend(MouseBackend::implementation()) + // use a default value for theme only if it's not configured at all, not even in X resources + if (theme.isEmpty() && backend->currentCursorTheme().isEmpty()) { + theme = "breeze_cursors"; + } + backend->applyCursorTheme(theme, intSize); + } + + // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment + // variables when launching applications. + OrgKdeKLauncherInterface klauncher(QStringLiteral("org.kde.klauncher5"), + QStringLiteral("/KLauncher"), + QDBusConnection::sessionBus()); + if (!theme.isEmpty()) { + klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), theme); + } + if (!size.isEmpty()) { + klauncher.setLaunchEnv(QStringLiteral("XCURSOR_SIZE"), size); + } +} + +XlibConfig::XlibConfig(ConfigContainer *parent, InputBackend *backend) + : ConfigPlugin(parent), + m_backend(dynamic_cast(backend)) { setupUi(this); - handedGroup->setId(rightHanded, static_cast(MouseHanded::Right)); - handedGroup->setId(leftHanded, static_cast(MouseHanded::Left)); + handedGroup->setId(rightHanded, static_cast(Handed::Right)); + handedGroup->setId(leftHanded, static_cast(Handed::Left)); - connect(handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed())); + connect(handedGroup, SIGNAL(buttonClicked(int)), m_parent, SLOT(changed())); connect(handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int))); - connect(doubleClick, SIGNAL(clicked()), SLOT(changed())); + connect(doubleClick, SIGNAL(clicked()), m_parent, SLOT(changed())); - connect(singleClick, SIGNAL(clicked()), this, SLOT(changed())); - connect(cbScrollPolarity, SIGNAL(clicked()), this, SLOT(changed())); + connect(singleClick, SIGNAL(clicked()), m_parent, SLOT(changed())); + connect(cbScrollPolarity, SIGNAL(clicked()), m_parent, SLOT(changed())); connect(cbScrollPolarity, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged())); - connect(accel, SIGNAL(valueChanged(double)), this, SLOT(changed())); - connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(accel, SIGNAL(valueChanged(double)), m_parent, SLOT(changed())); + connect(thresh, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int))); - connect(accelProfileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); + connect(accelProfileComboBox, SIGNAL(currentIndexChanged(int)), m_parent, SLOT(changed())); slotThreshChanged(thresh->value()); // It would be nice if the user had a test field. // Selecting such values in milliseconds is not intuitive - connect(doubleClickInterval, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(doubleClickInterval, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); - connect(dragStartTime, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(dragStartTime, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); - connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(dragStartDist, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(slotDragStartDistChanged(int))); slotDragStartDistChanged(dragStartDist->value()); - connect(wheelScrollLines, SIGNAL(valueChanged(int)), this, SLOT(changed())); + connect(wheelScrollLines, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); connect(wheelScrollLines, SIGNAL(valueChanged(int)), SLOT(slotWheelScrollLinesChanged(int))); slotWheelScrollLinesChanged(wheelScrollLines->value()); connect(mouseKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); - connect(mouseKeys, SIGNAL(clicked()), this, SLOT(changed())); - connect(mk_delay, SIGNAL(valueChanged(int)), this, SLOT(changed())); - connect(mk_interval, SIGNAL(valueChanged(int)), this, SLOT(changed())); - connect(mk_time_to_max, SIGNAL(valueChanged(int)), this, SLOT(changed())); - connect(mk_max_speed, SIGNAL(valueChanged(int)), this, SLOT(changed())); - connect(mk_curve, SIGNAL(valueChanged(int)), this, SLOT(changed())); - - settings = new MouseSettings; + connect(mouseKeys, SIGNAL(clicked()), m_parent, SLOT(changed())); + connect(mk_delay, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); + connect(mk_interval, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); + connect(mk_time_to_max, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); + connect(mk_max_speed, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); + connect(mk_curve, SIGNAL(valueChanged(int)), m_parent, SLOT(changed())); KAboutData* about = new KAboutData(QStringLiteral("kcmmouse"), i18n("Mouse"), QStringLiteral("1.0"), QString(), KAboutLicense::GPL, - i18n("(c) 1997 - 2005 Mouse developers")); + i18n("(c) 1997 - 2018 Mouse developers")); about->addAuthor(i18n("Patrick Dowler")); about->addAuthor(i18n("Dirk A. Mueller")); about->addAuthor(i18n("David Faure")); about->addAuthor(i18n("Bernd Gehrmann")); about->addAuthor(i18n("Rik Hemsley")); about->addAuthor(i18n("Brad Hughes")); about->addAuthor(i18n("Ralf Nolden")); about->addAuthor(i18n("Brad Hards")); - setAboutData(about); + about->addAuthor(i18n("Roman Gilg")); + m_parent->setAboutData(about); } -void MouseConfig::checkAccess() +void XlibConfig::checkAccess() { mk_delay->setEnabled(mouseKeys->isChecked()); mk_interval->setEnabled(mouseKeys->isChecked()); mk_time_to_max->setEnabled(mouseKeys->isChecked()); mk_max_speed->setEnabled(mouseKeys->isChecked()); mk_curve->setEnabled(mouseKeys->isChecked()); } - -MouseConfig::~MouseConfig() -{ - delete settings; -} - -double MouseConfig::getAccel() +double XlibConfig::getAccel() { return accel->value(); } -void MouseConfig::setAccel(double val) +void XlibConfig::setAccel(double val) { accel->setValue(val); } -int MouseConfig::getThreshold() +int XlibConfig::getThreshold() { return thresh->value(); } -void MouseConfig::setThreshold(int val) +void XlibConfig::setThreshold(int val) { thresh->setValue(val); } - -MouseHanded MouseConfig::getHandedness() +Handed XlibConfig::getHandedness() { if (rightHanded->isChecked()) - return MouseHanded::Right; + return Handed::Right; else - return MouseHanded::Left; + return Handed::Left; } -void MouseConfig::setHandedness(MouseHanded val) +void XlibConfig::setHandedness(Handed val) { rightHanded->setChecked(false); leftHanded->setChecked(false); - if (val == MouseHanded::Right) { + if (val == Handed::Right) { rightHanded->setChecked(true); mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); } else { leftHanded->setChecked(true); mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); } - settings->handedNeedsApply = true; + m_backend->settings()->handedNeedsApply = true; } -void MouseConfig::load() + + + +void XlibConfig::load() { - KConfig config("kcminputrc"); - settings->load(&config, backend); + EvdevSettings *settings = m_backend->settings(); + + m_parent->kcmLoad(); + m_backend->load(); - // settings->load will trigger backend->load so information will be avaialbe - // here. // Only allow setting reversing scroll polarity if we have scroll buttons - if (backend) { - if (backend->supportScrollPolarity()) + if (m_backend) { + if (m_backend->supportScrollPolarity()) { cbScrollPolarity->setEnabled(true); cbScrollPolarity->show(); @@ -220,7 +235,7 @@ } } - auto accelerationProfiles = backend->supportedAccelerationProfiles(); + auto accelerationProfiles = m_backend->supportedAccelerationProfiles(); accelProfileComboBox->setEnabled(!accelerationProfiles.isEmpty()); accelProfileComboBox->setVisible(!accelerationProfiles.isEmpty()); accelerationProfileLabel->setEnabled(!accelerationProfiles.isEmpty()); @@ -235,7 +250,6 @@ idx++; } - rightHanded->setEnabled(settings->handedEnabled); leftHanded->setEnabled(settings->handedEnabled); if (cbScrollPolarity->isEnabled()) @@ -281,11 +295,13 @@ mk_curve->setValue(group.readEntry("MKCurve", 0)); checkAccess(); - emit changed(false); + emit m_parent->changed(false); } -void MouseConfig::save() +void XlibConfig::save() { + EvdevSettings *settings = m_backend->settings(); + settings->accelRate = getAccel(); settings->thresholdMove = getThreshold(); settings->handed = getHandedness(); @@ -298,9 +314,8 @@ settings->reverseScrollPolarity = cbScrollPolarity->isChecked(); settings->currentAccelProfile = accelProfileComboBox->itemData(accelProfileComboBox->currentIndex()).toString(); - settings->apply(backend); - KConfig config("kcminputrc"); - settings->save(&config); + m_backend->apply(); + settings->save(); KConfig ac("kaccessrc"); @@ -320,14 +335,14 @@ // restart kaccess KToolInvocation::startServiceByDesktopName("kaccess"); - emit changed(false); + emit m_parent->changed(false); } -void MouseConfig::defaults() +void XlibConfig::defaults() { setThreshold(2); setAccel(2); - setHandedness(MouseHanded::Right); + setHandedness(Handed::Right); cbScrollPolarity->setChecked(false); doubleClickInterval->setValue(400); dragStartTime->setValue(500); @@ -344,37 +359,39 @@ mk_curve->setValue(0); checkAccess(); - changed(); + m_parent->kcmDefaults(); + + m_parent->changed(true); } /** No descriptions */ -void MouseConfig::slotHandedChanged(int val) +void XlibConfig::slotHandedChanged(int val) { - if (val == static_cast(MouseHanded::Right)) + if (val == static_cast(Handed::Right)) mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); else mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); - settings->handedNeedsApply = true; + m_backend->settings()->handedNeedsApply = true; } -void MouseConfig::slotThreshChanged(int value) +void XlibConfig::slotThreshChanged(int value) { thresh->setSuffix(i18np(" pixel", " pixels", value)); } -void MouseConfig::slotDragStartDistChanged(int value) +void XlibConfig::slotDragStartDistChanged(int value) { dragStartDist->setSuffix(i18np(" pixel", " pixels", value)); } -void MouseConfig::slotWheelScrollLinesChanged(int value) +void XlibConfig::slotWheelScrollLinesChanged(int value) { wheelScrollLines->setSuffix(i18np(" line", " lines", value)); } -void MouseConfig::slotScrollPolarityChanged() +void XlibConfig::slotScrollPolarityChanged() { - settings->handedNeedsApply = true; + m_backend->settings()->handedNeedsApply = true; } -#include "mouse.moc" +#include "xlib_config.moc" diff --git a/kcms/input/main.cpp b/kcms/input/main.cpp deleted file mode 100644 --- a/kcms/input/main.cpp +++ /dev/null @@ -1,80 +0,0 @@ -/* - * main.cpp - * - * Copyright (c) 1999 Matthias Hoelzer-Kluepfel - * - * Requires the Qt widget libraries, available at no cost at - * http://www.troll.no/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#include -#include -#include - -#include "mousesettings.h" -#include "mousebackend.h" - -#include - -extern "C" -{ - Q_DECL_EXPORT void kcminit_mouse() - { - KConfig* config = new KConfig("kcminputrc", KConfig::NoGlobals); - - auto backend = MouseBackend::implementation(); - - MouseSettings settings; - settings.load(config, backend); - settings.apply(backend, true); // force - - KConfigGroup group = config->group("Mouse"); - QString theme = group.readEntry("cursorTheme", QString()); - QString size = group.readEntry("cursorSize", QString()); - if (backend) { - int intSize = -1; - if (size.isEmpty()) { - bool ok; - uint value = size.toUInt(&ok); - if (ok) { - intSize = value; - } - } - // Note: If you update this code, update kapplymousetheme as well. - - // use a default value for theme only if it's not configured at all, not even in X resources - if (theme.isEmpty() && backend->currentCursorTheme().isEmpty()) { - theme = "breeze_cursors"; - } - backend->applyCursorTheme(theme, intSize); - } - - // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment - // variables when launching applications. - OrgKdeKLauncherInterface klauncher(QStringLiteral("org.kde.klauncher5"), - QStringLiteral("/KLauncher"), - QDBusConnection::sessionBus()); - if (!theme.isEmpty()) { - klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), theme); - } - if (!size.isEmpty()) { - klauncher.setLaunchEnv(QStringLiteral("XCURSOR_SIZE"), size); - } - - delete config; - } -} diff --git a/kcms/input/misc/CMakeLists.txt b/kcms/input/misc/CMakeLists.txt new file mode 100644 --- /dev/null +++ b/kcms/input/misc/CMakeLists.txt @@ -0,0 +1,6 @@ +install( FILES mouse_rh.png mouse_lh.png + DESTINATION ${KDE_INSTALL_DATADIR}/kcminput/pics +) +install( FILES cursor_large_black.pcf.gz cursor_large_white.pcf.gz cursor_small_white.pcf.gz + DESTINATION ${KDE_INSTALL_DATADIR}/kcminput +) diff --git a/kcms/input/consoleUserPerms b/kcms/input/misc/consoleUserPerms rename from kcms/input/consoleUserPerms rename to kcms/input/misc/consoleUserPerms diff --git a/kcms/input/cursor_large.bdf b/kcms/input/misc/cursor_large.bdf rename from kcms/input/cursor_large.bdf rename to kcms/input/misc/cursor_large.bdf diff --git a/kcms/input/cursor_large_black.pcf.gz b/kcms/input/misc/cursor_large_black.pcf.gz rename from kcms/input/cursor_large_black.pcf.gz rename to kcms/input/misc/cursor_large_black.pcf.gz diff --git a/kcms/input/cursor_large_white.pcf.gz b/kcms/input/misc/cursor_large_white.pcf.gz rename from kcms/input/cursor_large_white.pcf.gz rename to kcms/input/misc/cursor_large_white.pcf.gz diff --git a/kcms/input/cursor_small_white.pcf.gz b/kcms/input/misc/cursor_small_white.pcf.gz rename from kcms/input/cursor_small_white.pcf.gz rename to kcms/input/misc/cursor_small_white.pcf.gz diff --git a/kcms/input/pics/mouse_lh.png b/kcms/input/misc/mouse_lh.png rename from kcms/input/pics/mouse_lh.png rename to kcms/input/misc/mouse_lh.png diff --git a/kcms/input/pics/mouse_lh.svgz b/kcms/input/misc/mouse_lh.svgz rename from kcms/input/pics/mouse_lh.svgz rename to kcms/input/misc/mouse_lh.svgz diff --git a/kcms/input/pics/mouse_rh.png b/kcms/input/misc/mouse_rh.png rename from kcms/input/pics/mouse_rh.png rename to kcms/input/misc/mouse_rh.png diff --git a/kcms/input/pics/mouse_rh.svgz b/kcms/input/misc/mouse_rh.svgz rename from kcms/input/pics/mouse_rh.svgz rename to kcms/input/misc/mouse_rh.svgz diff --git a/kcms/input/mouse.h b/kcms/input/mouse.h deleted file mode 100644 --- a/kcms/input/mouse.h +++ /dev/null @@ -1,82 +0,0 @@ -/* - * mouse.h - * - * Copyright (c) 1997 Patrick Dowler dowler@morgul.fsh.uvic.ca - * - * Layout management, enhancements: - * Copyright (c) 1999 Dirk A. Mueller - * - * SC/DC/AutoSelect/ChangeCursor: - * Copyright (c) 2000 David Faure - * - * Requires the Qt widget libraries, available at no cost at - * http://www.troll.no/ - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - - -#ifndef __MOUSECONFIG_H__ -#define __MOUSECONFIG_H__ - -#include - -#include -#include "ui_kcmmouse.h" -#include "mousesettings.h" - -class QCheckBox; -class QDoubleSpinBox; -class QSlider; -class QSpinBox; -class QTabWidget; - -class MouseSettings; -class MouseBackend; - -class MouseConfig : public KCModule, public Ui::KCMMouse -{ - Q_OBJECT -public: - MouseConfig(QWidget *parent, const QVariantList &args); - ~MouseConfig(); - - void save(); - void load(); - void defaults(); - -private Q_SLOTS: - void slotHandedChanged(int val); - void slotScrollPolarityChanged(); - void checkAccess(); - void slotThreshChanged(int value); - void slotDragStartDistChanged(int value); - void slotWheelScrollLinesChanged(int value); - -private: - double getAccel(); - int getThreshold(); - MouseHanded getHandedness(); - - void setAccel(double); - void setThreshold(int); - void setHandedness(MouseHanded); - - MouseSettings *settings; - - MouseBackend *backend; -}; - -#endif diff --git a/kcms/input/mousebackend.h b/kcms/input/mousebackend.h deleted file mode 100644 --- a/kcms/input/mousebackend.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright 2017 Xuetian Weng - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef MOUSEBACKEND_H -#define MOUSEBACKEND_H - -#include -#include "mousesettings.h" - -class MouseBackend : public QObject -{ - Q_OBJECT -protected: - explicit MouseBackend(QObject *parent) : QObject(parent) {} - -public: - static MouseBackend *implementation(); - - virtual bool isValid() const = 0; - - // This function will be called before query any property below, thus it - // can be used to save some round trip. - virtual void load() = 0; - virtual void apply(const MouseSettings &settings, bool force) = 0; - - // Return the value from display server or compositor if applicable. - virtual bool supportScrollPolarity() = 0; - virtual QStringList supportedAccelerationProfiles() = 0; - virtual QString accelerationProfile() = 0; - virtual double accelRate() = 0; - virtual int threshold() = 0; - virtual MouseHanded handed() = 0; - - virtual QString currentCursorTheme() = 0; - virtual void applyCursorTheme(const QString &name, int size) = 0; -}; - -#endif // MOUSEBACKEND_H diff --git a/kcms/input/pics/CMakeLists.txt b/kcms/input/pics/CMakeLists.txt deleted file mode 100644 --- a/kcms/input/pics/CMakeLists.txt +++ /dev/null @@ -1 +0,0 @@ -install( FILES mouse_rh.png mouse_lh.png DESTINATION ${KDE_INSTALL_DATADIR}/kcminput/pics ) diff --git a/kcms/input/logging.cpp b/kcms/input/plugin.h rename from kcms/input/logging.cpp rename to kcms/input/plugin.h --- a/kcms/input/logging.cpp +++ b/kcms/input/plugin.h @@ -1,5 +1,5 @@ /* - * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,7 +15,11 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#ifndef PLUGIN_H +#define PLUGIN_H -#include "logging.h" +#include -Q_LOGGING_CATEGORY(KCM_INPUT, "kcm_input") +K_PLUGIN_FACTORY_DECLARATION(MousePluginFactory) + +#endif // PLUGIN_H diff --git a/kcms/input/logging.h b/kcms/input/plugin.cpp rename from kcms/input/logging.h rename to kcms/input/plugin.cpp --- a/kcms/input/logging.h +++ b/kcms/input/plugin.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2017 Xuetian Weng + * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -15,11 +15,12 @@ * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +#include "kcm/configcontainer.h" -#ifndef KCM_INPUT_LOGGING_H -#define KCM_INPUT_LOGGING_H +#include -#include +K_PLUGIN_FACTORY(MousePluginFactory, + registerPlugin(); +) -Q_DECLARE_LOGGING_CATEGORY(KCM_INPUT) -#endif +#include