diff --git a/kcms/input/CMakeLists.txt b/kcms/input/CMakeLists.txt --- a/kcms/input/CMakeLists.txt +++ b/kcms/input/CMakeLists.txt @@ -24,6 +24,9 @@ Critical ) +set(klauncher_xml ${KINIT_DBUS_INTERFACES_DIR}/kf5_org.kde.KLauncher.xml) +qt5_add_dbus_interface(common_SRCS ${klauncher_xml} klauncher_iface) + include(backends/x11.cmake) include(backends/kwin_wl.cmake) @@ -57,10 +60,7 @@ kcm/xlib/xlib_config.cpp ) -set(klauncher_xml ${KINIT_DBUS_INTERFACES_DIR}/kf5_org.kde.KLauncher.xml) - ki18n_wrap_ui(common_SRCS kcm/xlib/kcmmouse.ui) -qt5_add_dbus_interface(common_SRCS ${klauncher_xml} klauncher_iface) qt5_add_resources( common_SRCS kcm/resources.qrc ) 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 @@ -9,8 +9,12 @@ set(backend_SRCS ${backend_SRCS} - backends/x11/evdev_settings.cpp backends/x11/x11_backend.cpp + backends/x11/x11_evdev_backend.cpp + backends/x11/evdev_settings.cpp + backends/x11/x11_libinput_backend.cpp + backends/x11/x11_libinput_dummydevice.cpp + backends/x11/libinput_settings.cpp ) set(backend_LIBS diff --git a/kcms/input/backends/x11/evdev_settings.h b/kcms/input/backends/x11/evdev_settings.h --- a/kcms/input/backends/x11/evdev_settings.h +++ b/kcms/input/backends/x11/evdev_settings.h @@ -20,9 +20,7 @@ #ifndef EVDEVSETTINGS_H #define EVDEVSETTINGS_H -#include - -class X11Backend; +class X11EvdevBackend; enum class Handed { Right = 0, @@ -33,8 +31,8 @@ struct EvdevSettings { void save(); - void load(X11Backend *); - void apply(X11Backend *, bool force = false); + void load(X11EvdevBackend *); + void apply(X11EvdevBackend *, bool force = false); bool handedEnabled; bool handedNeedsApply; @@ -47,7 +45,6 @@ bool singleClick; int wheelScrollLines; bool reverseScrollPolarity; - QString currentAccelProfile; }; #endif // EVDEVSETTINGS_H diff --git a/kcms/input/backends/x11/evdev_settings.cpp b/kcms/input/backends/x11/evdev_settings.cpp --- a/kcms/input/backends/x11/evdev_settings.cpp +++ b/kcms/input/backends/x11/evdev_settings.cpp @@ -17,15 +17,15 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include "evdev_settings.h" -#include "x11_backend.h" +#include "x11_evdev_backend.h" #include #include #include #include #include "../migrationlib/kdelibs4config.h" -void EvdevSettings::apply(X11Backend *backend, bool force) +void EvdevSettings::apply(X11EvdevBackend *backend, bool force) { if (!backend) { return; @@ -35,24 +35,22 @@ handedNeedsApply = false; } -void EvdevSettings::load(X11Backend *backend) +void EvdevSettings::load(X11EvdevBackend *backend) { KConfig config("kcminputrc"); // TODO: what's a good threshold default value int threshold = 0; handed = Handed::Right; double accel = 1.0; - QString profile; if (backend) { auto handedOnServer = backend->handed(); handedEnabled = handedOnServer != Handed::NotSupported; if (handedEnabled) { handed = handedOnServer; } accel = backend->accelRate(); threshold = backend->threshold(); - profile = backend->accelerationProfile(); } KConfigGroup group = config.group("Mouse"); @@ -74,10 +72,7 @@ else if (key == "LeftHanded") handed = Handed::Left; reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false); - currentAccelProfile = group.readEntry("AccelerationProfile"); - if (currentAccelProfile.isEmpty()) { - currentAccelProfile = profile; - } + handedNeedsApply = false; // SC/DC/AutoSelect/ChangeCursor @@ -124,7 +119,6 @@ kcminputGroup.writeEntry("MouseButtonMapping",QString("LeftHanded")); } kcminputGroup.writeEntry("ReverseScrollPolarity", reverseScrollPolarity); - kcminputGroup.writeEntry("AccelerationProfile", currentAccelProfile); kcminputGroup.sync(); KSharedConfig::Ptr profile = KSharedConfig::openConfig("kdeglobals"); diff --git a/kcms/input/backends/x11/evdev_settings.h b/kcms/input/backends/x11/libinput_settings.h copy from kcms/input/backends/x11/evdev_settings.h copy to kcms/input/backends/x11/libinput_settings.h --- a/kcms/input/backends/x11/evdev_settings.h +++ b/kcms/input/backends/x11/libinput_settings.h @@ -1,5 +1,4 @@ /* - * Copyright 2017 Xuetian Weng * Copyright 2018 Roman Gilg * * This program is free software; you can redistribute it and/or modify @@ -17,37 +16,18 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef EVDEVSETTINGS_H -#define EVDEVSETTINGS_H +#ifndef LIBINPUTSETTINGS_H +#define LIBINPUTSETTINGS_H -#include +#include -class X11Backend; - -enum class Handed { - Right = 0, - Left = 1, - NotSupported = -1 -}; - -struct EvdevSettings +struct LibinputSettings { - void save(); - void load(X11Backend *); - void apply(X11Backend *, bool force = false); + template + T load(QString key, T defVal); - bool handedEnabled; - bool handedNeedsApply; - Handed handed; - double accelRate; - int thresholdMove; - int doubleClickInterval; - int dragStartTime; - int dragStartDist; - bool singleClick; - int wheelScrollLines; - bool reverseScrollPolarity; - QString currentAccelProfile; + template + void save(QString key, T val); }; -#endif // EVDEVSETTINGS_H +#endif // LIBINPUTSETTINGS_H diff --git a/kcms/input/backends/x11/libinput_settings.cpp b/kcms/input/backends/x11/libinput_settings.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/libinput_settings.cpp @@ -0,0 +1,63 @@ +/* + * 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_settings.h" + +#include +#include + +template<> +bool LibinputSettings::load(QString key, bool defVal) +{ + KSharedConfig::Ptr kcminputPtr = KSharedConfig::openConfig("kcminputrc"); + KConfigGroup group(kcminputPtr, "Mouse"); + + return group.readEntry(key, defVal); +} + +template<> +qreal LibinputSettings::load(QString key, qreal defVal) +{ + KSharedConfig::Ptr kcminputPtr = KSharedConfig::openConfig("kcminputrc"); + KConfigGroup group(kcminputPtr, "Mouse"); + + return group.readEntry(key, defVal); +} + +template<> +void LibinputSettings::save(QString key, bool val) +{ + KSharedConfig::Ptr kcminputPtr = KSharedConfig::openConfig("kcminputrc"); + KConfigGroup group(kcminputPtr, "Mouse"); + + group.writeEntry(key, val); + + group.sync(); + kcminputPtr->sync(); +} + +template<> +void LibinputSettings::save(QString key, qreal val) +{ + KSharedConfig::Ptr kcminputPtr = KSharedConfig::openConfig("kcminputrc"); + KConfigGroup group(kcminputPtr, "Mouse"); + + group.writeEntry(key, val); + + group.sync(); + kcminputPtr->sync(); +} diff --git a/kcms/input/backends/x11/x11_backend.h b/kcms/input/backends/x11/x11_backend.h --- a/kcms/input/backends/x11/x11_backend.h +++ b/kcms/input/backends/x11/x11_backend.h @@ -21,71 +21,31 @@ #define X11BACKEND_H #include "inputbackend.h" -#include "evdev_settings.h" #include #include -class ConfigPlugin; - class X11Backend : public InputBackend { Q_OBJECT + public: - X11Backend(QObject *parent = nullptr); + static X11Backend *implementation(QObject *parent = nullptr); ~X11Backend(); - bool isValid() const override { return m_dpy != nullptr; } - - void load() override; - - void apply(bool force = false); + void kcmInit() override; - EvdevSettings* settings() { - return m_settings; - } - - bool supportScrollPolarity(); - QStringList supportedAccelerationProfiles(); - QString accelerationProfile(); - double accelRate(); - Handed handed(); - int threshold(); + bool isValid() const override { return m_dpy != nullptr; } QString currentCursorTheme(); void applyCursorTheme(const QString &name, int size); -Q_SIGNALS: - void mouseStateChanged(); - void mousesChanged(); - void mouseReset(); - -private: - void initAtom(); - bool evdevApplyReverseScroll(int deviceid, bool reverse); - bool libinputApplyReverseScroll(int deviceid, bool reverse); - void libinputApplyAccelerationProfile(int deviceid, QString profile); - - Atom m_libinputAccelProfileAvailableAtom; - Atom m_libinputAccelProfileEnabledAtom; - Atom m_libinputNaturalScrollAtom; - - Atom m_evdevWheelEmulationAtom; - Atom m_evdevScrollDistanceAtom; - Atom m_evdevWheelEmulationAxesAtom; +protected: + X11Backend(QObject *parent = nullptr); - Atom m_touchpadAtom; // We may still need to do something on non-X11 platform due to Xwayland. - Display* m_dpy; + Display* m_dpy = nullptr; bool m_platformX11; - EvdevSettings *m_settings = nullptr; - int m_numButtons = 1; - 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 // X11BACKEND_H diff --git a/kcms/input/backends/x11/x11_backend.cpp b/kcms/input/backends/x11/x11_backend.cpp --- a/kcms/input/backends/x11/x11_backend.cpp +++ b/kcms/input/backends/x11/x11_backend.cpp @@ -18,14 +18,22 @@ */ #include "x11_backend.h" +#include "x11_evdev_backend.h" +#include "x11_libinput_backend.h" + +#include "logging.h" #include +#include + #include #include #include -#include -#include +#include +#include + +#include #include #include @@ -38,280 +46,40 @@ #include #endif -static const char PROFILE_NONE[] = I18N_NOOP("None"); -static const char PROFILE_ADAPTIVE[] = I18N_NOOP("Adaptive"); -static const char PROFILE_FLAT[] = I18N_NOOP("Flat"); - -struct ScopedXDeleter { - static inline void cleanup(void* pointer) - { - if (pointer) { - XFree(pointer); - } - } -}; - -template -static void XI2ForallPointerDevices(Display* dpy, const Callback& callback) +X11Backend *X11Backend::implementation(QObject *parent) { - int ndevices_return; - XIDeviceInfo* info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return); - if (!info) { - return; - } - for (int i = 0; i < ndevices_return; ++i) { - if ((info + i)->use == XISlavePointer) { - callback(info + i); - } - } - XIFreeDeviceInfo(info); -} + auto dpy = QX11Info::display(); + Atom testAtom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL, True); -template -static void XIForallPointerDevices(Display* dpy, const Callback& callback) -{ - int ndevices_return; - XDeviceInfo* info = XListInputDevices(dpy, &ndevices_return); - if (!info) { - return; + //There are multiple possible drivers + if (testAtom) { + qCDebug(KCM_INPUT) << "Using libinput driver on X11."; + return new X11LibinputBackend(parent); } - for (int i = 0; i < ndevices_return; ++i) { - if (info[i].use == IsXPointer || info[i].use == IsXExtensionPointer) { - callback(info + i); - } + else { + qCDebug(KCM_INPUT) << "Using evdev driver on X11."; + return new X11EvdevBackend(parent); } - XFreeDeviceList(info); } 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 X11Backend::initAtom() -{ - if (!m_dpy) { - return; - } - - m_libinputAccelProfileAvailableAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, True); - m_libinputAccelProfileEnabledAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); - m_libinputNaturalScrollAtom = XInternAtom(m_dpy, LIBINPUT_PROP_NATURAL_SCROLL, True); - - m_evdevScrollDistanceAtom = XInternAtom(m_dpy, EVDEV_PROP_SCROLL_DISTANCE, True); - m_evdevWheelEmulationAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL, True); - m_evdevWheelEmulationAxesAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL_AXES, True); - - m_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True); } - X11Backend::~X11Backend() { if (!m_platformX11 && m_dpy) { XCloseDisplay(m_dpy); } - delete m_settings; -} - -bool X11Backend::supportScrollPolarity() -{ - return m_numButtons >= 5; -} - -QStringList X11Backend::supportedAccelerationProfiles() -{ - return m_supportedAccelerationProfiles; -} - -QString X11Backend::accelerationProfile() -{ - return m_accelerationProfile; -} - -double X11Backend::accelRate() -{ - return m_accelRate; -} - -Handed X11Backend::handed() -{ - return m_handed; -} - -int X11Backend::threshold() -{ - return m_threshold; -} - -void X11Backend::load() -{ - if (!m_dpy) { - return; - } - - m_accelRate = 1.0; - int accel_num, accel_den; - XGetPointerControl(m_dpy, &accel_num, &accel_den, &m_threshold); - m_accelRate = double(accel_num) / double(accel_den); - - // get settings from X server - unsigned char map[256]; - m_numButtons = XGetPointerMapping(m_dpy, map, 256); - m_middleButton = -1; - - m_handed = Handed::NotSupported; - // ## keep this in sync with KGlobalSettings::mouseSettings - if (m_numButtons == 2) { - if (map[0] == 1 && map[1] == 2) { - m_handed = Handed::Right; - } else if (map[0] == 2 && map[1] == 1) { - m_handed = Handed::Left; - } - } else if (m_numButtons >= 3) { - m_middleButton = map[1]; - if (map[0] == 1 && map[2] == 3) { - m_handed = Handed::Right; - } else if (map[0] == 3 && map[2] == 1) { - m_handed = Handed::Left; - } - } - - m_supportedAccelerationProfiles.clear(); - bool adaptiveAvailable = false; - bool flatAvailable = false; - bool adaptiveEnabled = false; - bool flatEnabled = false; - if (m_libinputAccelProfileAvailableAtom != None && m_libinputAccelProfileEnabledAtom != None) { - XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { - int deviceid = info->deviceid; - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - //data returned is an 2 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - QScopedArrayPointer data(_data); - _data = nullptr; - if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { - return; - } - adaptiveAvailable = adaptiveAvailable || data[0]; - flatAvailable = flatAvailable || data[1]; - - //data returned is an 2 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, 0, 2, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - data.reset(_data); - _data = nullptr; - if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { - return; - } - adaptiveEnabled = adaptiveEnabled || data[0]; - flatEnabled = flatEnabled || data[1]; - }); - } - - if (adaptiveAvailable) { - m_supportedAccelerationProfiles << PROFILE_ADAPTIVE; - } - if (flatAvailable) { - m_supportedAccelerationProfiles << PROFILE_FLAT; - } - if (adaptiveAvailable || flatAvailable) { - m_supportedAccelerationProfiles << PROFILE_NONE; - } - - m_accelerationProfile = PROFILE_NONE; - if (adaptiveEnabled) { - m_accelerationProfile = PROFILE_ADAPTIVE; - } else if (flatEnabled) { - m_accelerationProfile = PROFILE_FLAT; - } - - m_settings->load(this); -} - -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 (m_settings->handedEnabled && (m_settings->handedNeedsApply || force)) { - if (m_numButtons == 1) { - map[0] = (unsigned char) 1; - } else if (m_numButtons == 2) { - 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 (m_settings->handed == Handed::Right) { - map[0] = (unsigned char) 1; - map[1] = (unsigned char) m_middleButton; - map[2] = (unsigned char) 3; - } else { - map[0] = (unsigned char) 3; - map[1] = (unsigned char) m_middleButton; - map[2] = (unsigned char) 1; - } - } - - int retval; - if (m_numButtons >= 1) { - while ((retval = XSetPointerMapping(m_dpy, map, - m_numButtons)) == MappingBusy) - /* keep trying until the pointer is free */ - { }; - } - - // apply reverseScrollPolarity for all non-touchpad pointer, touchpad - // are belong to kcm touchpad. - XIForallPointerDevices(m_dpy, [this](XDeviceInfo * info) { - int deviceid = info->id; - if (info->type == m_touchpadAtom) { - return; - } - if (libinputApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity)) { - return; - } - evdevApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity); - }); - - } - - XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { - libinputApplyAccelerationProfile(info->deviceid, m_settings->currentAccelProfile); - }); - - XChangePointerControl(m_dpy, - true, true, int(qRound(m_settings->accelRate * 10)), 10, m_settings->thresholdMove); - - XFlush(m_dpy); } QString X11Backend::currentCursorTheme() @@ -353,146 +121,37 @@ #endif } -bool X11Backend::evdevApplyReverseScroll(int deviceid, bool reverse) +void X11Backend::kcmInit() { - // Check atom availability first. - if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None || - m_evdevWheelEmulationAxesAtom == None) { - return false; - } - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char* _data = nullptr; - //data returned is an 1 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_evdevWheelEmulationAtom, 0, 1, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - QScopedArrayPointer data(_data); - _data = nullptr; - if (status != Success) { - return false; - } + KConfigGroup group = KConfig("kcminputrc", KConfig::NoGlobals).group("Mouse"); + QString theme = group.readEntry("cursorTheme", QString()); + QString size = group.readEntry("cursorSize", QString()); - // pointer device without wheel emulation - if (type_return != XA_INTEGER || data == NULL || *data == False) { - status = XIGetProperty(m_dpy, deviceid, m_evdevScrollDistanceAtom, 0, 3, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - data.reset(_data); - _data = nullptr; - // negate scroll distance - if (status == Success && type_return == XA_INTEGER && - format_return == 32 && num_items_return == 3) { - int32_t* vals = (int32_t*)data.data(); - for (unsigned long i = 0; i < num_items_return; ++i) { - int32_t val = *(vals + i); - *(vals + i) = (int32_t)(reverse ? -abs(val) : abs(val)); - } - XIChangeProperty(m_dpy, deviceid, m_evdevScrollDistanceAtom, XA_INTEGER, - 32, XIPropModeReplace, data.data(), 3); + int intSize = -1; + if (size.isEmpty()) { + bool ok; + uint value = size.toUInt(&ok); + if (ok) { + intSize = value; } - } else { // wheel emulation used, reverse wheel axes - status = XIGetProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, 0, 4, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - data.reset(_data); - _data = nullptr; - if (status == Success && type_return == XA_INTEGER && - format_return == 8 && num_items_return == 4) { - // when scroll direction is not reversed, - // up button id should be smaller than down button id, - // up/left are odd elements, down/right are even elements - for (int i = 0; i < 2; ++i) { - unsigned char odd = data[i * 2]; - unsigned char even = data[i * 2 + 1]; - unsigned char max_elem = std::max(odd, even); - unsigned char min_elem = std::min(odd, even); - data[i * 2] = reverse ? max_elem : min_elem; - data[i * 2 + 1] = reverse ? min_elem : max_elem; - } - XIChangeProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, XA_INTEGER, - 8, XIPropModeReplace, data.data(), 4); - } - } - - return true; -} - -bool X11Backend::libinputApplyReverseScroll(int deviceid, bool reverse) -{ - // Check atom availability first. - if (m_libinputNaturalScrollAtom == None) { - return false; } - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; + // Note: If you update this code, update kapplymousetheme as well. - unsigned char *_data = nullptr; - //data returned is an 1 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, 0, 1, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - if (status != Success) { - return false; + // use a default value for theme only if it's not configured at all, not even in X resources + if (theme.isEmpty() && currentCursorTheme().isEmpty()) { + theme = "breeze_cursors"; } - QScopedArrayPointer data(_data); - _data = nullptr; - if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 1) { - return false; - } - unsigned char natural = reverse ? 1 : 0; - XIChangeProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, XA_INTEGER, - 8, XIPropModeReplace, &natural, 1); - return true; -} + applyCursorTheme(theme, intSize); -void X11Backend::libinputApplyAccelerationProfile(int deviceid, QString profile) -{ - // Check atom availability first. - if (m_libinputAccelProfileAvailableAtom == None || m_libinputAccelProfileEnabledAtom == None) { - return; - } - - unsigned char profileData[2]; - if (profile == PROFILE_NONE) { - profileData[0] = profileData[1] = 0; - } else if (profile == PROFILE_ADAPTIVE) { - profileData[0] = 1; - profileData[1] = 0; - } else if (profile == PROFILE_FLAT) { - profileData[0] = 0; - profileData[1] = 1; - } - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - //data returned is an 1 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - if (status != Success) { - return; - } - QScopedArrayPointer data(_data); - _data = nullptr; - if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { - return; + // 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); } - // Check availability for profile. - if (profileData[0] > data[0] || profileData[1] > data[1]) { - return; + if (!size.isEmpty()) { + klauncher.setLaunchEnv(QStringLiteral("XCURSOR_SIZE"), size); } - XIChangeProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, XA_INTEGER, - 8, XIPropModeReplace, profileData, 2); } diff --git a/kcms/input/backends/x11/x11_backend.h b/kcms/input/backends/x11/x11_evdev_backend.h copy from kcms/input/backends/x11/x11_backend.h copy to kcms/input/backends/x11/x11_evdev_backend.h --- a/kcms/input/backends/x11/x11_backend.h +++ b/kcms/input/backends/x11/x11_evdev_backend.h @@ -17,23 +17,24 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#ifndef X11BACKEND_H -#define X11BACKEND_H +#ifndef X11EVDEVBACKEND_H +#define X11EVDEVBACKEND_H -#include "inputbackend.h" +#include "x11_backend.h" #include "evdev_settings.h" #include #include -class ConfigPlugin; - -class X11Backend : public InputBackend +class X11EvdevBackend : public X11Backend { Q_OBJECT + public: - X11Backend(QObject *parent = nullptr); - ~X11Backend(); + X11EvdevBackend(QObject *parent = nullptr); + ~X11EvdevBackend(); + + void kcmInit() override; bool isValid() const override { return m_dpy != nullptr; } @@ -46,46 +47,33 @@ } 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(); bool evdevApplyReverseScroll(int deviceid, bool reverse); - bool libinputApplyReverseScroll(int deviceid, bool reverse); - void libinputApplyAccelerationProfile(int deviceid, QString profile); - Atom m_libinputAccelProfileAvailableAtom; - Atom m_libinputAccelProfileEnabledAtom; - Atom m_libinputNaturalScrollAtom; Atom m_evdevWheelEmulationAtom; Atom m_evdevScrollDistanceAtom; Atom m_evdevWheelEmulationAxesAtom; Atom m_touchpadAtom; - // 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; 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 // X11BACKEND_H +#endif // X11EVDEVBACKEND_H diff --git a/kcms/input/backends/x11/x11_backend.cpp b/kcms/input/backends/x11/x11_evdev_backend.cpp copy from kcms/input/backends/x11/x11_backend.cpp copy to kcms/input/backends/x11/x11_evdev_backend.cpp --- a/kcms/input/backends/x11/x11_backend.cpp +++ b/kcms/input/backends/x11/x11_evdev_backend.cpp @@ -17,15 +17,14 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include "x11_backend.h" +#include "x11_evdev_backend.h" #include #include #include #include #include -#include #include #include @@ -38,10 +37,6 @@ #include #endif -static const char PROFILE_NONE[] = I18N_NOOP("None"); -static const char PROFILE_ADAPTIVE[] = I18N_NOOP("Adaptive"); -static const char PROFILE_FLAT[] = I18N_NOOP("Flat"); - struct ScopedXDeleter { static inline void cleanup(void* pointer) { @@ -51,22 +46,6 @@ } }; -template -static void XI2ForallPointerDevices(Display* dpy, const Callback& callback) -{ - int ndevices_return; - XIDeviceInfo* info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return); - if (!info) { - return; - } - for (int i = 0; i < ndevices_return; ++i) { - if ((info + i)->use == XISlavePointer) { - callback(info + i); - } - } - XIFreeDeviceInfo(info); -} - template static void XIForallPointerDevices(Display* dpy, const Callback& callback) { @@ -83,80 +62,54 @@ XFreeDeviceList(info); } -X11Backend::X11Backend(QObject* parent) - : InputBackend(parent) +X11EvdevBackend::X11EvdevBackend(QObject* parent) + : X11Backend(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 X11Backend::initAtom() +void X11EvdevBackend::initAtom() { if (!m_dpy) { return; } - m_libinputAccelProfileAvailableAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, True); - m_libinputAccelProfileEnabledAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); - m_libinputNaturalScrollAtom = XInternAtom(m_dpy, LIBINPUT_PROP_NATURAL_SCROLL, True); - m_evdevScrollDistanceAtom = XInternAtom(m_dpy, EVDEV_PROP_SCROLL_DISTANCE, True); m_evdevWheelEmulationAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL, True); m_evdevWheelEmulationAxesAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL_AXES, True); m_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True); } -X11Backend::~X11Backend() +X11EvdevBackend::~X11EvdevBackend() { - if (!m_platformX11 && m_dpy) { - XCloseDisplay(m_dpy); - } delete m_settings; } -bool X11Backend::supportScrollPolarity() +bool X11EvdevBackend::supportScrollPolarity() { return m_numButtons >= 5; } -QStringList X11Backend::supportedAccelerationProfiles() -{ - return m_supportedAccelerationProfiles; -} - -QString X11Backend::accelerationProfile() -{ - return m_accelerationProfile; -} - -double X11Backend::accelRate() +double X11EvdevBackend::accelRate() { return m_accelRate; } -Handed X11Backend::handed() +Handed X11EvdevBackend::handed() { return m_handed; } -int X11Backend::threshold() +int X11EvdevBackend::threshold() { return m_threshold; } -void X11Backend::load() +void X11EvdevBackend::load() { if (!m_dpy) { return; @@ -189,68 +142,10 @@ } } - m_supportedAccelerationProfiles.clear(); - bool adaptiveAvailable = false; - bool flatAvailable = false; - bool adaptiveEnabled = false; - bool flatEnabled = false; - if (m_libinputAccelProfileAvailableAtom != None && m_libinputAccelProfileEnabledAtom != None) { - XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { - int deviceid = info->deviceid; - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - //data returned is an 2 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - QScopedArrayPointer data(_data); - _data = nullptr; - if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { - return; - } - adaptiveAvailable = adaptiveAvailable || data[0]; - flatAvailable = flatAvailable || data[1]; - - //data returned is an 2 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, 0, 2, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - data.reset(_data); - _data = nullptr; - if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { - return; - } - adaptiveEnabled = adaptiveEnabled || data[0]; - flatEnabled = flatEnabled || data[1]; - }); - } - - if (adaptiveAvailable) { - m_supportedAccelerationProfiles << PROFILE_ADAPTIVE; - } - if (flatAvailable) { - m_supportedAccelerationProfiles << PROFILE_FLAT; - } - if (adaptiveAvailable || flatAvailable) { - m_supportedAccelerationProfiles << PROFILE_NONE; - } - - m_accelerationProfile = PROFILE_NONE; - if (adaptiveEnabled) { - m_accelerationProfile = PROFILE_ADAPTIVE; - } else if (flatEnabled) { - m_accelerationProfile = PROFILE_FLAT; - } - m_settings->load(this); } -void X11Backend::apply(bool force) +void X11EvdevBackend::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, @@ -296,64 +191,18 @@ if (info->type == m_touchpadAtom) { return; } - if (libinputApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity)) { - return; - } evdevApplyReverseScroll(deviceid, m_settings->reverseScrollPolarity); }); } - XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { - libinputApplyAccelerationProfile(info->deviceid, m_settings->currentAccelProfile); - }); - XChangePointerControl(m_dpy, true, true, int(qRound(m_settings->accelRate * 10)), 10, m_settings->thresholdMove); XFlush(m_dpy); } -QString X11Backend::currentCursorTheme() -{ - if (!m_dpy) { - return QString(); - } - - QByteArray name = XGetDefault(m_dpy, "Xcursor", "theme"); -#ifdef HAVE_XCURSOR - if (name.isEmpty()) { - name = QByteArray(XcursorGetTheme(m_dpy)); - } -#endif - return QFile::decodeName(name); -} - -void X11Backend::applyCursorTheme(const QString& theme, int size) -{ -#ifdef HAVE_XCURSOR - - // Apply the KDE cursor theme to ourselves - if (m_dpy) { - return; - } - if (!theme.isEmpty()) { - XcursorSetTheme(m_dpy, QFile::encodeName(theme)); - } - - if (size >= 0) { - XcursorSetDefaultSize(m_dpy, size); - } - - // Load the default cursor from the theme and apply it to the root window. - Cursor handle = XcursorLibraryLoadCursor(m_dpy, "left_ptr"); - XDefineCursor(m_dpy, DefaultRootWindow(m_dpy), handle); - XFreeCursor(m_dpy, handle); // Don't leak the cursor - XFlush(m_dpy); -#endif -} - -bool X11Backend::evdevApplyReverseScroll(int deviceid, bool reverse) +bool X11EvdevBackend::evdevApplyReverseScroll(int deviceid, bool reverse) { // Check atom availability first. if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None || @@ -422,77 +271,9 @@ return true; } -bool X11Backend::libinputApplyReverseScroll(int deviceid, bool reverse) -{ - // Check atom availability first. - if (m_libinputNaturalScrollAtom == None) { - return false; - } - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - //data returned is an 1 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, 0, 1, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - if (status != Success) { - return false; - } - QScopedArrayPointer data(_data); - _data = nullptr; - if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 1) { - return false; - } - unsigned char natural = reverse ? 1 : 0; - XIChangeProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, XA_INTEGER, - 8, XIPropModeReplace, &natural, 1); - return true; -} - -void X11Backend::libinputApplyAccelerationProfile(int deviceid, QString profile) +void X11EvdevBackend::kcmInit() { - // Check atom availability first. - if (m_libinputAccelProfileAvailableAtom == None || m_libinputAccelProfileEnabledAtom == None) { - return; - } - - unsigned char profileData[2]; - if (profile == PROFILE_NONE) { - profileData[0] = profileData[1] = 0; - } else if (profile == PROFILE_ADAPTIVE) { - profileData[0] = 1; - profileData[1] = 0; - } else if (profile == PROFILE_FLAT) { - profileData[0] = 0; - profileData[1] = 1; - } - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *_data = nullptr; - //data returned is an 1 byte boolean - status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &_data); - if (status != Success) { - return; - } - QScopedArrayPointer data(_data); - _data = nullptr; - if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) { - return; - } - // Check availability for profile. - if (profileData[0] > data[0] || profileData[1] > data[1]) { - return; - } - XIChangeProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, XA_INTEGER, - 8, XIPropModeReplace, profileData, 2); + m_settings->load(this); + apply(true); // force + X11Backend::kcmInit(); } diff --git a/kcms/input/backends/x11/x11_libinput_backend.h b/kcms/input/backends/x11/x11_libinput_backend.h new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/x11_libinput_backend.h @@ -0,0 +1,54 @@ +/* + * 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 X11LIBINPUTBACKEND_H +#define X11LIBINPUTBACKEND_H + +#include "x11_backend.h" + +#include + +class X11LibinputBackend : public X11Backend +{ + Q_OBJECT + + Q_PROPERTY(int deviceCount READ deviceCount CONSTANT) + +public: + explicit X11LibinputBackend(QObject *parent = 0); + ~X11LibinputBackend() = default; + + void kcmInit() override; + + 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 1; } + virtual QVector getDevices() const override { + return QVector(1, m_device); + } + +private: + QObject *m_device; + QString m_errorString = QString(); +}; + +#endif // X11LIBINPUTBACKEND_H diff --git a/kcms/input/backends/x11/x11_libinput_backend.cpp b/kcms/input/backends/x11/x11_libinput_backend.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/x11_libinput_backend.cpp @@ -0,0 +1,54 @@ +/* + * 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 "x11_libinput_backend.h" +#include "x11_libinput_dummydevice.h" + +X11LibinputBackend::X11LibinputBackend(QObject *parent) : + X11Backend(parent) +{ + m_mode = InputBackendMode::XLibinput; + m_device = new X11LibinputDummyDevice(this, m_dpy); +} + +bool X11LibinputBackend::applyConfig() +{ + return static_cast(m_device)->applyConfig(); +} + +bool X11LibinputBackend::getConfig() +{ + return static_cast(m_device)->getConfig(); +} + +bool X11LibinputBackend::getDefaultConfig() +{ + return static_cast(m_device)->getDefaultConfig(); +} + +bool X11LibinputBackend::isChangedConfig() const +{ + return static_cast(m_device)->isChangedConfig(); +} + +void X11LibinputBackend::kcmInit() +{ + getConfig(); + applyConfig(); + X11Backend::kcmInit(); +} diff --git a/kcms/input/backends/x11/x11_libinput_dummydevice.h b/kcms/input/backends/x11/x11_libinput_dummydevice.h new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/x11_libinput_dummydevice.h @@ -0,0 +1,273 @@ +/* + * 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 X11LIBINPUTDUMMYDEVICE_H +#define X11LIBINPUTDUMMYDEVICE_H + +#include +#include +#include + +#include + +class LibinputSettings; + +class X11LibinputDummyDevice : 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: + X11LibinputDummyDevice(QObject *parent, Display *dpy); + ~X11LibinputDummyDevice() override; + + 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 QString &_name, const QString &_cfgName = "") + : name(_name), + cfgName(_cfgName) + {} + + 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); + } + + void reset(T newVal) { + val = newVal; + old = newVal; + } + + QString name; + QString cfgName; + + bool avail = true; + T old; + T val; + + Atom atom; + }; + + template + bool valueWriter(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", "XLbInptLeftHanded"); + + Prop m_supportsMiddleEmulation = Prop("supportsMiddleEmulation"); + Prop m_middleEmulationEnabledByDefault = Prop("middleEmulationEnabledByDefault"); + Prop m_middleEmulation = Prop("middleEmulation", "XLbInptMiddleEmulation"); + + // + // acceleration speed and profile + Prop m_supportsPointerAcceleration = Prop("supportsPointerAcceleration"); + Prop m_defaultPointerAcceleration = Prop("defaultPointerAcceleration"); + Prop m_pointerAcceleration = Prop("pointerAcceleration", "XLbInptPointerAcceleration"); + + Prop m_supportsPointerAccelerationProfileFlat = Prop("supportsPointerAccelerationProfileFlat"); + Prop m_defaultPointerAccelerationProfileFlat = Prop("defaultPointerAccelerationProfileFlat"); + Prop m_pointerAccelerationProfileFlat = Prop("pointerAccelerationProfileFlat", "XLbInptAccelProfileFlat"); + + 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", "XLbInptNaturalScroll"); + + LibinputSettings *m_settings; + Display *m_dpy = nullptr; +}; + +#endif // X11LIBINPUTDUMMYDEVICE_H diff --git a/kcms/input/backends/x11/x11_libinput_dummydevice.cpp b/kcms/input/backends/x11/x11_libinput_dummydevice.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/x11_libinput_dummydevice.cpp @@ -0,0 +1,241 @@ +/* + * 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 "x11_libinput_dummydevice.h" +#include "libinput_settings.h" + +#include + +#include +#include +#include + +template +static void XI2ForallPointerDevices(Display* dpy, const Callback& callback) +{ + int ndevices_return; + XIDeviceInfo* info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return); + if (!info) { + return; + } + for (int i = 0; i < ndevices_return; ++i) { + if ((info + i)->use == XISlavePointer) { + callback(info + i); + } + } + XIFreeDeviceInfo(info); +} + +struct ScopedXDeleter { + static inline void cleanup(void* pointer) + { + if (pointer) { + XFree(pointer); + } + } +}; + +namespace { +template +void valueWriterPart(T val, Atom valAtom, Display *dpy) +{ + Q_UNUSED(val); + Q_UNUSED(valAtom); + Q_UNUSED(dpy); +} + +template<> +void valueWriterPart(bool val, Atom valAtom, Display *dpy) +{ + XI2ForallPointerDevices(dpy, [&] (XIDeviceInfo *info) { + Status status; + Atom type_return; + int format_return; + unsigned long num_items_return; + unsigned long bytes_after_return; + + unsigned char *_data = nullptr; + //data returned is an 1 byte boolean + status = XIGetProperty(dpy, info->deviceid, valAtom, 0, 1, + False, XA_INTEGER, &type_return, &format_return, + &num_items_return, &bytes_after_return, &_data); + if (status != Success) { + return; + } + + QScopedArrayPointer data(_data); + _data = nullptr; + + + if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 1) { + return; + } + + unsigned char sendVal = val ? 1 : 0; + + XIChangeProperty(dpy, info->deviceid, valAtom, XA_INTEGER, + 8, XIPropModeReplace, &sendVal, 1); + + }); +} + +template<> +void valueWriterPart(qreal val, Atom valAtom, Display *dpy) +{ + XI2ForallPointerDevices(dpy, [&] (XIDeviceInfo *info) { + Status status; + Atom float_type = XInternAtom (dpy, "FLOAT", False); + Atom type_return; + int format_return; + unsigned long num_items_return; + unsigned long bytes_after_return; + + unsigned char *_data = nullptr; + //data returned is an 1 byte boolean + status = XIGetProperty(dpy, info->deviceid, valAtom, 0, 1, + False, float_type, &type_return, &format_return, + &num_items_return, &bytes_after_return, &_data); + if (status != Success) { + return; + } + + QScopedArrayPointer data(_data); + _data = nullptr; + + + if (type_return != float_type || !data || format_return != 32 || num_items_return != 1) { + return; + } + + unsigned char buffer[4096]; + float *sendPtr = (float*)buffer; + *sendPtr = val; + + XIChangeProperty(dpy, info->deviceid, valAtom, float_type, + format_return, XIPropModeReplace, buffer, 1); + + }); +} +} + +X11LibinputDummyDevice::X11LibinputDummyDevice(QObject *parent, Display *dpy) + : QObject(parent), + m_settings(new LibinputSettings()), + m_dpy(dpy) +{ + m_leftHanded.atom = XInternAtom(dpy, LIBINPUT_PROP_LEFT_HANDED, True); + m_middleEmulation.atom = XInternAtom(dpy, LIBINPUT_PROP_MIDDLE_EMULATION_ENABLED, True); + m_naturalScroll.atom = XInternAtom(dpy, LIBINPUT_PROP_NATURAL_SCROLL, True); + m_pointerAcceleration.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL, True); + m_pointerAccelerationProfileFlat.atom = XInternAtom(dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True); + + m_supportsDisableEvents.val = false; + m_enabled.val = true; + m_supportedButtons.val = Qt::LeftButton | Qt::MidButton | Qt::RightButton; + m_supportsLeftHanded.val = true; + m_supportsMiddleEmulation.val = true; + m_middleEmulationEnabledByDefault.val = false; + + m_supportsPointerAcceleration.val = true; + m_defaultPointerAcceleration.val = 0; + + m_supportsPointerAccelerationProfileAdaptive.val = true; + m_supportsPointerAccelerationProfileFlat.val = true; + + m_defaultPointerAccelerationProfileAdaptive.val = true; + m_defaultPointerAccelerationProfileFlat.val = false; + + m_supportsNaturalScroll.val = true; + m_naturalScrollEnabledByDefault.val = false; +} + +X11LibinputDummyDevice::~X11LibinputDummyDevice() +{ + delete m_settings; +} + +bool X11LibinputDummyDevice::getConfig() +{ + auto reset = [this](Prop &prop, bool defVal) { + prop.reset(m_settings->load(prop.cfgName, defVal)); + }; + + reset(m_leftHanded, false); + + reset(m_middleEmulation, false); + reset(m_naturalScroll, false); + reset(m_pointerAccelerationProfileFlat, false); + + m_pointerAccelerationProfileAdaptive.reset(!m_settings->load(m_pointerAccelerationProfileFlat.cfgName, false)); + m_pointerAcceleration.reset(m_settings->load(m_pointerAcceleration.cfgName, 0.)); + + return true; +} + +bool X11LibinputDummyDevice::getDefaultConfig() +{ + 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 X11LibinputDummyDevice::applyConfig() +{ + valueWriter(m_leftHanded); + valueWriter(m_middleEmulation); + valueWriter(m_naturalScroll); + valueWriter(m_pointerAcceleration); + valueWriter(m_pointerAccelerationProfileFlat); + + return true; +} + +template +bool X11LibinputDummyDevice::valueWriter(Prop &prop) +{ + // Check atom availability first. + if (prop.atom == None) { + return false; + } + + if (prop.val != prop.old) { + m_settings->save(prop.cfgName, prop.val); + } + + valueWriterPart(prop.val, prop.atom, m_dpy); + + prop.old = prop.val; + + return true; +} + +bool X11LibinputDummyDevice::isChangedConfig() const +{ + return m_leftHanded.changed() || + m_pointerAcceleration.changed() || + m_pointerAccelerationProfileFlat.changed() || + m_pointerAccelerationProfileAdaptive.changed() || + m_middleEmulation.changed() || + m_naturalScroll.changed(); +} diff --git a/kcms/input/inputbackend.h b/kcms/input/inputbackend.h --- a/kcms/input/inputbackend.h +++ b/kcms/input/inputbackend.h @@ -28,7 +28,7 @@ enum class InputBackendMode { KWinWayland = 0, - XLibinput = 1, // TODO + XLibinput = 1, XEvdev = 2 }; @@ -47,6 +47,8 @@ return m_mode; } + virtual void kcmInit() {} + virtual bool isValid() const { return false; } virtual void load() {} diff --git a/kcms/input/inputbackend.cpp b/kcms/input/inputbackend.cpp --- a/kcms/input/inputbackend.cpp +++ b/kcms/input/inputbackend.cpp @@ -29,7 +29,7 @@ //There are multiple possible backends if (KWindowSystem::isPlatformX11()) { qCDebug(KCM_INPUT) << "Using X11 backend"; - return new X11Backend(parent); + return X11Backend::implementation(parent); } else if (KWindowSystem::isPlatformWayland()) { qCDebug(KCM_INPUT) << "Using KWin+Wayland backend"; diff --git a/kcms/input/kapplymousetheme.cpp b/kcms/input/kapplymousetheme.cpp --- a/kcms/input/kapplymousetheme.cpp +++ b/kcms/input/kapplymousetheme.cpp @@ -46,21 +46,23 @@ return 2; } - X11Backend backend; + X11Backend *backend = X11Backend::implementation(); - if (!backend.isValid()) { + 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()); + + delete backend; return ret; } diff --git a/kcms/input/kcm/configcontainer.cpp b/kcms/input/kcm/configcontainer.cpp --- a/kcms/input/kcm/configcontainer.cpp +++ b/kcms/input/kcm/configcontainer.cpp @@ -18,18 +18,18 @@ #include "configcontainer.h" #include "configplugin.h" -#include "kcm/libinput/libinput_config.h" -#include "kcm/xlib/xlib_config.h" + +#include "inputbackend.h" #include extern "C" { Q_DECL_EXPORT void kcminit_mouse() { - if (KWindowSystem::isPlatformX11()) { - XlibConfig::kcmInit(); - } + InputBackend *backend = InputBackend::implementation(); + backend->kcmInit(); + delete backend; } } diff --git a/kcms/input/kcm/libinput/libinput_config.cpp b/kcms/input/kcm/libinput/libinput_config.cpp --- a/kcms/input/kcm/libinput/libinput_config.cpp +++ b/kcms/input/kcm/libinput/libinput_config.cpp @@ -82,7 +82,12 @@ KDeclarative::KDeclarative kdeclarative; kdeclarative.setDeclarativeEngine(m_view->engine()); kdeclarative.setupBindings(); - m_view->setSource(QUrl("qrc:/libinput/main.qml")); + + if (m_backend->mode() == InputBackendMode::XLibinput) { + m_view->setSource(QUrl("qrc:/libinput/main_deviceless.qml")); + } else { + m_view->setSource(QUrl("qrc:/libinput/main.qml")); + } if (m_initError) { m_errorMessage->setMessageType(KMessageWidget::Error); diff --git a/kcms/input/kcm/libinput/main_deviceless.qml b/kcms/input/kcm/libinput/main_deviceless.qml new file mode 100644 --- /dev/null +++ b/kcms/input/kcm/libinput/main_deviceless.qml @@ -0,0 +1,251 @@ +/* + * 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, Math.round(1.1 * maincol.height)) + property size minimumSizeHint: Qt.size(maincol.width, Math.round(1.1 * maincol.height)) + signal changeSignal() + + property QtObject device: deviceModel[0] + + property bool loading: false + + function resetModel(index) { + // not implemented + } + + function syncValuesFromBackend() { + loading = true + + leftHanded.load() + accelSpeed.load() + accelProfile.load() + + naturalScroll.load() + + loading = false + } + + Controls.ScrollView { + anchors.fill: parent + + Layouts.ColumnLayout { + id: maincol + spacing: units.largeSpacing + + 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: 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 --- a/kcms/input/kcm/resources.qrc +++ b/kcms/input/kcm/resources.qrc @@ -1,6 +1,7 @@ libinput/main.qml + libinput/main_deviceless.qml libinput/components/ExclGroupBox.qml libinput/components/ToolTip.qml diff --git a/kcms/input/kcm/xlib/kcmmouse.ui b/kcms/input/kcm/xlib/kcmmouse.ui --- a/kcms/input/kcm/xlib/kcmmouse.ui +++ b/kcms/input/kcm/xlib/kcmmouse.ui @@ -202,7 +202,7 @@ - + Pointer acceleration: @@ -212,7 +212,7 @@ - + Pointer threshold: @@ -222,7 +222,7 @@ - + Double click interval: @@ -232,7 +232,7 @@ - + Drag start time: @@ -242,7 +242,7 @@ - + Drag start distance: @@ -252,7 +252,7 @@ - + Mouse wheel scrolls by: @@ -262,7 +262,7 @@ - + @@ -293,7 +293,7 @@ - + @@ -312,7 +312,7 @@ - + @@ -340,7 +340,7 @@ - + @@ -365,7 +365,7 @@ - + @@ -387,7 +387,7 @@ - + @@ -409,26 +409,6 @@ - - - - Acceleration Profile: - - - accelProfileComboBox - - - - - - - - 0 - 0 - - - - diff --git a/kcms/input/kcm/xlib/xlib_config.h b/kcms/input/kcm/xlib/xlib_config.h --- a/kcms/input/kcm/xlib/xlib_config.h +++ b/kcms/input/kcm/xlib/xlib_config.h @@ -36,7 +36,7 @@ class QSpinBox; class QTabWidget; -class X11Backend; +class X11EvdevBackend; class XlibConfig : public ConfigPlugin, public Ui::KCMMouse { @@ -68,7 +68,7 @@ void setThreshold(int); void setHandedness(Handed); - X11Backend *m_backend; + X11EvdevBackend *m_backend; }; #endif // XLIBCONFIG_H diff --git a/kcms/input/kcm/xlib/xlib_config.cpp b/kcms/input/kcm/xlib/xlib_config.cpp --- a/kcms/input/kcm/xlib/xlib_config.cpp +++ b/kcms/input/kcm/xlib/xlib_config.cpp @@ -26,7 +26,7 @@ */ #include "xlib_config.h" -#include "backends/x11/x11_backend.h" +#include "backends/x11/x11_evdev_backend.h" #include "../configcontainer.h" #include "../../../migrationlib/kdelibs4config.h" @@ -49,58 +49,12 @@ #include #include -#include - #include #include -void XlibConfig::kcmInit() -{ - X11Backend *backend = dynamic_cast(InputBackend::implementation()); - if (!backend) { - return; - } - - backend->settings()->load(backend); - backend->settings()->apply(backend, true); // force - - 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. - - // 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)) + m_backend(dynamic_cast(backend)) { setupUi(this); @@ -118,7 +72,6 @@ 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)), m_parent, SLOT(changed())); slotThreshChanged(thresh->value()); // It would be nice if the user had a test field. @@ -211,9 +164,6 @@ m_backend->settings()->handedNeedsApply = true; } - - - void XlibConfig::load() { EvdevSettings *settings = m_backend->settings(); @@ -235,21 +185,6 @@ } } - auto accelerationProfiles = m_backend->supportedAccelerationProfiles(); - accelProfileComboBox->setEnabled(!accelerationProfiles.isEmpty()); - accelProfileComboBox->setVisible(!accelerationProfiles.isEmpty()); - accelerationProfileLabel->setEnabled(!accelerationProfiles.isEmpty()); - accelerationProfileLabel->setVisible(!accelerationProfiles.isEmpty()); - accelProfileComboBox->clear(); - int idx = 0; - for (const auto &profile : accelerationProfiles) { - accelProfileComboBox->addItem(i18n(profile.toUtf8().constData()), profile); - if (profile == settings->currentAccelProfile) { - accelProfileComboBox->setCurrentIndex(idx); - } - idx++; - } - rightHanded->setEnabled(settings->handedEnabled); leftHanded->setEnabled(settings->handedEnabled); if (cbScrollPolarity->isEnabled()) @@ -312,7 +247,6 @@ settings->wheelScrollLines = wheelScrollLines->value(); settings->singleClick = !doubleClick->isChecked(); settings->reverseScrollPolarity = cbScrollPolarity->isChecked(); - settings->currentAccelProfile = accelProfileComboBox->itemData(accelProfileComboBox->currentIndex()).toString(); m_backend->apply(); settings->save();