diff --git a/CMakeLists.txt b/CMakeLists.txt --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -112,6 +112,10 @@ find_package(Synaptics) set_package_properties(Synaptics PROPERTIES TYPE OPTIONAL) add_feature_info("Synaptics" SYNAPTICS_FOUND "Synaptics libraries needed for touchpad KCM") + +find_package(XorgLibinput) +set_package_properties(XorgLibinput PROPERTIES TYPE OPTIONAL) +add_feature_info("XorgLibinput" XORGLIBINPUT_FOUND "Libinput driver headers needed for input and touchpad KCM") include(ConfigureChecks.cmake) if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL") diff --git a/cmake/modules/FindXorgLibinput.cmake b/cmake/modules/FindXorgLibinput.cmake new file mode 100644 --- /dev/null +++ b/cmake/modules/FindXorgLibinput.cmake @@ -0,0 +1,45 @@ +# - Find xorg libinput's libraries and headers. +# This module defines the following variables: +# +# XORGLIBINPUT_FOUND - true if libinput was found +# XORGLIBINPUT_INCLUDE_DIRS - include path for synaptics +# There are no libraries, just a header file +# +# Copyright (c) 2015 David Edmundson +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# 3. Neither the name of the University nor the names of its contributors +# may be used to endorse or promote products derived from this software +# without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. + +find_package(PkgConfig) +pkg_check_modules(PC_XORGLIBINPUT xorg-libinput) + +find_path(XORGLIBINPUT_INCLUDE_DIRS + NAMES libinput-properties.h + HINTS ${PC_XORGLIBINPUT_INCLUDE_DIRS} ${PC_XORGLIBINPUT_INCLUDEDIR} +) + +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(XorgLibinput REQUIRED_VARS XORGLIBINPUT_INCLUDE_DIRS) + +mark_as_advanced(XORGLIBINPUT_INCLUDE_DIRS) diff --git a/kcms/CMakeLists.txt b/kcms/CMakeLists.txt --- a/kcms/CMakeLists.txt +++ b/kcms/CMakeLists.txt @@ -14,7 +14,7 @@ add_subdirectory( keyboard ) endif() -if (EVDEV_FOUND AND X11_Xinput_FOUND) +if (EVDEV_FOUND AND XORGLIBINPUT_FOUND AND X11_Xinput_FOUND) add_subdirectory( input ) endif() @@ -55,7 +55,7 @@ add_subdirectory(solid_actions) add_subdirectory(cursortheme) -if (SYNAPTICS_FOUND AND X11_Xinput_FOUND) +if (SYNAPTICS_FOUND AND XORGLIBINPUT_FOUND AND X11_Xinput_FOUND) add_subdirectory(touchpad) endif() diff --git a/kcms/input/CMakeLists.txt b/kcms/input/CMakeLists.txt --- a/kcms/input/CMakeLists.txt +++ b/kcms/input/CMakeLists.txt @@ -7,55 +7,59 @@ add_subdirectory( pics ) +## Add common files here. +set(kcminput_backend_SRCS + mousebackend.cpp + mousesettings.cpp + logging.cpp) +set(kcminput_backend_LIBS) +include(backends/x11.cmake) ########### next target ############### -set(kapplymousetheme_SRCS kapplymousetheme.cpp ) +set(kapplymousetheme_SRCS + kapplymousetheme.cpp) -add_executable(kapplymousetheme ${kapplymousetheme_SRCS}) +add_executable(kapplymousetheme ${kapplymousetheme_SRCS} ${kcminput_backend_SRCS}) -target_link_libraries(kapplymousetheme ${X11_Xrender_LIB} ${X11_X11_LIB}) -if (X11_Xcursor_FOUND) - target_link_libraries(kapplymousetheme ${X11_Xcursor_LIB}) - target_include_directories(kapplymousetheme PRIVATE ${X11_Xcursor_INCLUDE_PATH}) -endif () +target_link_libraries(kapplymousetheme + Qt5::Gui + KF5::I18n + KF5::ConfigCore + KF5::WindowSystem + KF5::KDELibs4Support + ${kcminput_backend_LIBS} +) install(TARGETS kapplymousetheme ${INSTALL_TARGETS_DEFAULT_ARGS}) ########### next target ############### -set(kcm_input_PART_SRCS mouse.cpp main.cpp) +set(kcm_input_PART_SRCS + mouse.cpp + main.cpp + ${kcminput_backend_SRCS} +) set(klauncher_xml ${KINIT_DBUS_INTERFACES_DIR}/kf5_org.kde.KLauncher.xml) -ki18n_wrap_ui(kcm_input_PART_SRCS kmousedlg.ui) +ki18n_wrap_ui(kcm_input_PART_SRCS kmousedlg.ui kcmmouse.ui) qt5_add_dbus_interface(kcm_input_PART_SRCS ${klauncher_xml} klauncher_iface) -add_library(kcm_input MODULE ${kcm_input_PART_SRCS}) - -include_directories(${X11_X11_INCLUDE_PATH} - ${X11_Xinput_INCLUDE_PATH} - ${Evdev_INCLUDE_DIRS}) +add_library(kcm_input MODULE ${kcm_input_PART_SRCS} ${kcminput_backend_SRCS}) target_link_libraries(kcm_input Qt5::DBus - Qt5::X11Extras KF5::KCMUtils + KF5::WindowSystem KF5::I18n KF5::KIOCore KF5::KIOWidgets KF5::KDELibs4Support - ${X11_X11_LIB} - ${X11_Xinput_LIB} + ${kcminput_backend_LIBS} ) -if (X11_Xcursor_FOUND) - target_link_libraries(kcm_input ${X11_Xcursor_LIB}) -endif () -if (X11_Xfixes_FOUND) - target_link_libraries(kcm_input ${X11_Xfixes_LIB}) -endif () install(TARGETS kcm_input DESTINATION ${PLUGIN_INSTALL_DIR} ) diff --git a/kcms/input/backends/x11.cmake b/kcms/input/backends/x11.cmake new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11.cmake @@ -0,0 +1,26 @@ +# // krazy:excludeall=copyright,license + +set(kcminput_backend_SRCS + ${kcminput_backend_SRCS} + backends/x11/x11mousebackend.cpp +) + +set(kcminput_backend_LIBS + 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 + ${X11_Xcursor_LIB} + ${kcminput_backend_LIBS} + ) + include_directories(${X11_Xcursor_INCLUDE_PATH}) +endif () diff --git a/kcms/input/backends/x11/x11mousebackend.h b/kcms/input/backends/x11/x11mousebackend.h new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/x11mousebackend.h @@ -0,0 +1,72 @@ +/* + * 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 XLIBMOUSEBACKEND_H +#define XLIBMOUSEBACKEND_H + +#include "mousebackend.h" + +#include +#include + +class X11MouseBackend : public MouseBackend +{ + Q_OBJECT +public: + X11MouseBackend(QObject *parent = nullptr); + ~X11MouseBackend(); + + 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; + +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; + int m_numButtons = 1; + MouseHanded m_handed = MouseHanded::NotSupported; + double m_accelRate = 1.0; + int m_threshold = 0; + int m_middleButton = -1; + QStringList m_supportedAccelerationProfiles; + QString m_accelerationProfile; +}; + +#endif // XLIBMOUSEBACKEND_H diff --git a/kcms/input/backends/x11/x11mousebackend.cpp b/kcms/input/backends/x11/x11mousebackend.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/backends/x11/x11mousebackend.cpp @@ -0,0 +1,471 @@ +/* + * 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. + */ + +#include "x11mousebackend.h" +#include "mousesettings.h" +#include + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_XCURSOR +# include +#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) { + 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) { + int ndevices_return; + XDeviceInfo *info = XListInputDevices(dpy, &ndevices_return); + if (!info) { + return; + } + for (int i = 0; i < ndevices_return; ++i) { + if( info[i].use == IsXPointer || info[i].use == IsXExtensionPointer ) { + callback(info + i); + } + } + XFreeDeviceList(info); +} + +X11MouseBackend::X11MouseBackend(QObject* parent) : MouseBackend(parent), m_dpy(nullptr) +{ + m_platformX11 = QX11Info::isPlatformX11(); + if (m_platformX11) { + m_dpy = QX11Info::display(); + } else { + // let's hope we have a compatibility system like Xwayland ready + m_dpy = XOpenDisplay(nullptr); + } + initAtom(); +} + +void X11MouseBackend::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); +} + + +X11MouseBackend::~X11MouseBackend() +{ + if (!m_platformX11 && m_dpy) { + XCloseDisplay(m_dpy); + } +} + +QStringList X11MouseBackend::supportedAccelerationProfiles() +{ + return m_supportedAccelerationProfiles; +} + +QString X11MouseBackend::accelerationProfile() +{ + return m_accelerationProfile; +} + +bool X11MouseBackend::supportScrollPolarity() +{ + return m_numButtons >= 5; +} + +double X11MouseBackend::accelRate() { + return m_accelRate; +} + +MouseHanded X11MouseBackend::handed() +{ + return m_handed; +} + +int X11MouseBackend::threshold() { + return m_threshold; +} + +void X11MouseBackend::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[20]; + m_numButtons = XGetPointerMapping(m_dpy, map, 20); + m_middleButton = -1; + + m_handed = MouseHanded::NotSupported; + // ## keep this in sync with KGlobalSettings::mouseSettings + if (m_numButtons == 2) + { + if (map[0] == 1 && map[1] == 2) + m_handed = MouseHanded::Right; + else if (map[0] == 2 && map[1] == 1) + m_handed = MouseHanded::Left; + } + else if (m_numButtons >= 3) + { + m_middleButton = map[1]; + if (map[0] == 1 && map[2] == 3) + m_handed = MouseHanded::Right; + else if (map[0] == 3 && map[2] == 1) + m_handed = MouseHanded::Left; + } + + m_supportedAccelerationProfiles.clear(); + bool adaptiveAvaiable = false; + bool flatAvailable = false; + bool adaptiveEnabled = false; + bool flatEnabled = false; + 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; + } + adaptiveAvaiable = adaptiveAvaiable || 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 (adaptiveAvaiable) { + m_supportedAccelerationProfiles << PROFILE_ADAPTIVE; + } + if (flatAvailable) { + m_supportedAccelerationProfiles << PROFILE_FLAT; + } + if (adaptiveAvaiable || flatAvailable) { + m_supportedAccelerationProfiles << PROFILE_NONE; + } + + m_accelerationProfile = PROFILE_NONE; + if (adaptiveAvaiable) { + m_accelerationProfile = PROFILE_ADAPTIVE; + } else if (flatAvailable) { + m_accelerationProfile = PROFILE_FLAT; + } +} + +void X11MouseBackend::apply(const MouseSettings &settings, 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]; + m_numButtons = XGetPointerMapping(m_dpy, map, 256); + + int remap=(m_numButtons>=1); + if (settings.handedEnabled && (settings.m_handedNeedsApply || force)) { + if (m_numButtons == 1) + { + map[0] = (unsigned char) 1; + } + else if (m_numButtons == 2) + { + if (settings.handed == MouseHanded::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) + { + 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 (remap) { + 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, [&] (XDeviceInfo *info) { + int deviceid = info->id; + if (info->type == m_touchpadAtom) { + return; + } + if (libinputApplyReverseScroll(deviceid, settings.reverseScrollPolarity)) { + return; + } + evdevApplyReverseScroll(deviceid, settings.reverseScrollPolarity); + }); + + } + + XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) { + libinputApplyAccelerationProfile(info->deviceid, settings.m_currentAccelProfile); + }); + + XChangePointerControl(m_dpy, + true, true, int(qRound(settings.accelRate*10)), 10, settings.thresholdMove); + + XFlush(m_dpy); +} + +QString X11MouseBackend::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 X11MouseBackend::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 X11MouseBackend::evdevApplyReverseScroll(int deviceid, bool reverse) +{ + 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; + } + + // 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 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 X11MouseBackend::libinputApplyAccelerationProfile(int deviceid, QString profile) +{ + 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); +} diff --git a/kcms/input/kapplymousetheme.cpp b/kcms/input/kapplymousetheme.cpp --- a/kcms/input/kapplymousetheme.cpp +++ b/kcms/input/kapplymousetheme.cpp @@ -21,68 +21,33 @@ * 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 -#include -#include - -#ifdef HAVE_XCURSOR -# include -#endif - -static Display* dpy; -Display* display() { return dpy; } -Window appRootWindow() { return DefaultRootWindow( dpy ); } - -static bool isEmpty( const char* str ) - { - if( str == NULL ) - return true; - while( isspace( *str )) - ++str; - return *str == '\0'; - } +#include "mousebackend.h" int main( int argc, char* argv[] ) - { +{ + int ret = 0; + QGuiApplication app(argc, argv); if( argc != 3 ) return 1; - dpy = XOpenDisplay( NULL ); - if( dpy == NULL ) + QString theme = QFile::decodeName(argv[ 1 ]); + QString size = QFile::decodeName(argv[ 2 ]); + auto backend = MouseBackend::implementation(); + if (!backend || !backend->isValid()) { return 2; - int ret = 0; -#ifdef HAVE_XCURSOR - const char* theme = argv[ 1 ]; - const char* size = argv[ 2 ]; + } - // Note: If you update this code, update kapplymousetheme as well. + // 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( isEmpty( theme ) - && isEmpty( XGetDefault( display(), "Xcursor", "theme" )) - && isEmpty( XcursorGetTheme( display()))) + if(theme.isEmpty() && backend->currentCursorTheme().isEmpty()) { theme = "breeze_cursors"; ret = 10; // means to switch to default } - // Apply the KDE cursor theme to ourselves - if( !isEmpty( theme )) - XcursorSetTheme(display(), theme ); - - if (!isEmpty( size )) - XcursorSetDefaultSize(display(), atoi( size )); - - // Load the default cursor from the theme and apply it to the root window. - Cursor handle = XcursorLibraryLoadCursor(display(), "left_ptr"); - XDefineCursor(display(), appRootWindow(), handle); - XFreeCursor(display(), handle); // Don't leak the cursor - -#else - ( void ) argv; -#endif - XCloseDisplay( dpy ); + backend->applyCursorTheme(theme, size.toInt()); return ret; - } +} diff --git a/kcms/input/kcmmouse.ui b/kcms/input/kcmmouse.ui new file mode 100644 --- /dev/null +++ b/kcms/input/kcmmouse.ui @@ -0,0 +1,482 @@ + + + KCMMouse + + + + 0 + 0 + 653 + 452 + + + + <h1>Mouse</h1> This module allows you to choose various options for the way in which your pointing device works. Your pointing device may be a mouse, trackball, or some other hardware that performs a similar function. + + + + 0 + + + + + 0 + + + + &General + + + + + Advanced + + + + + + + + Pointer acceleration: + + + accel + + + + + + + Pointer threshold: + + + thresh + + + + + + + Double click interval: + + + doubleClickInterval + + + + + + + Drag start time: + + + dragStartTime + + + + + + + Drag start distance: + + + dragStartDist + + + + + + + Mouse wheel scrolls by: + + + wheelScrollLines + + + + + + + + 0 + 0 + + + + <p>This option allows you to change the relationship between the distance that the mouse pointer moves on the screen and the relative movement of the physical device itself (which may be a mouse, trackball, or some other pointing device.)</p><p> A high value for the acceleration will lead to large movements of the mouse pointer on the screen even when you only make a small movement with the physical device. Selecting very high values may result in the mouse pointer flying across the screen, making it hard to control.</p> + + + x + + + 1 + + + 0.100000000000000 + + + 20.000000000000000 + + + 0.100000000000000 + + + 2.000000000000000 + + + + + + + + 0 + 0 + + + + <p>The threshold is the smallest distance that the mouse pointer must move on the screen before acceleration has any effect. If the movement is smaller than the threshold, the mouse pointer moves as if the acceleration was set to 1X;</p><p> thus, when you make small movements with the physical device, there is no acceleration at all, giving you a greater degree of control over the mouse pointer. With larger movements of the physical device, you can move the mouse pointer rapidly to different areas on the screen.</p> + + + 20 + + + 2 + + + + + + + + 0 + 0 + + + + The double click interval is the maximal time (in milliseconds) between two mouse clicks which turns them into a double click. If the second click happens later than this time interval after the first click, they are recognized as two separate clicks. + + + msec + + + 100 + + + 2000 + + + 100 + + + 2000 + + + + + + + + 0 + 0 + + + + If you click with the mouse (e.g. in a multi-line editor) and begin to move the mouse within the drag start time, a drag operation will be initiated. + + + msec + + + 100 + + + 2000 + + + 100 + + + + + + + + 0 + 0 + + + + If you click with the mouse and begin to move the mouse at least the drag start distance, a drag operation will be initiated. + + + 1 + + + 20 + + + 20 + + + + + + + + 0 + 0 + + + + If you use the wheel of a mouse, this value determines the number of lines to scroll for each wheel movement. Note that if this number exceeds the number of visible lines, it will be ignored and the wheel movement will be handled as a page up/down movement. + + + 1 + + + 12 + + + 3 + + + + + + + + 0 + 0 + + + + + + + + Acceleration Profile: + + + comboBox + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + Keyboard Navigation + + + + + + + + &Move pointer with keyboard (using the num pad) + + + + + + + + 0 + 0 + + + + msec + + + 1 + + + 1000 + + + 50 + + + + + + + &Acceleration delay: + + + mk_delay + + + + + + + R&epeat interval: + + + mk_interval + + + + + + + + 0 + 0 + + + + msec + + + 1 + + + 1000 + + + 10 + + + + + + + Acceleration &time: + + + mk_time_to_max + + + + + + + + 0 + 0 + + + + msec + + + 100 + + + 10000 + + + 200 + + + + + + + Ma&ximum speed: + + + mk_max_speed + + + + + + + + 0 + 0 + + + + pixel/sec + + + 1 + + + 2000 + + + 20 + + + + + + + Acceleration &profile: + + + mk_curve + + + + + + + + 0 + 0 + + + + -1000 + + + 1000 + + + 100 + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + KMouseDlg + QWidget +
kmousedlg.h
+
+
+ + +
diff --git a/kcms/input/kmousedlg.h b/kcms/input/kmousedlg.h new file mode 100644 --- /dev/null +++ b/kcms/input/kmousedlg.h @@ -0,0 +1,32 @@ +/* + * 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 KMOUSEDLG_H +#define KMOUSEDLG_H + +#include "ui_kmousedlg.h" + +class KMouseDlg : public QWidget, public Ui::KMouseDlg +{ +public: + KMouseDlg( QWidget *parent = nullptr ) : QWidget( parent ) { + setupUi( this ); + } +}; + +#endif diff --git a/kcms/input/kmousedlg.ui b/kcms/input/kmousedlg.ui --- a/kcms/input/kmousedlg.ui +++ b/kcms/input/kmousedlg.ui @@ -23,6 +23,9 @@ 0 + + If you are left-handed, you may prefer to swap the functions of the left and right buttons on your pointing device by choosing the 'left-handed' option. If your pointing device has more than two buttons, only those that function as the left and right buttons are affected. For example, if you have a three-button mouse, the middle button is unaffected. + Button Order @@ -38,13 +41,19 @@ true + + handedGroup + Le&ft handed + + handedGroup + @@ -110,22 +119,34 @@ + + The default behavior in KDE is to select and activate icons with a single click of the left button on your pointing device. This behavior is consistent with what you would expect when you click links in most web browsers. If you would prefer to select with a single click, and activate with a double click, check this option. + Dou&ble-click to open files and folders (select icons on first click) false + + clickGroup + + + Activates and opens a file or folder with a single click. + &Single-click to open files and folders true + + clickGroup + @@ -161,4 +182,8 @@ + + + + diff --git a/kcms/input/logging.h b/kcms/input/logging.h new file mode 100644 --- /dev/null +++ b/kcms/input/logging.h @@ -0,0 +1,26 @@ +/* + * 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 KCM_INPUT_LOGGING_H +#define KCM_INPUT_LOGGING_H + +#include + +Q_DECLARE_LOGGING_CATEGORY(KCM_INPUT) +#endif + diff --git a/kcms/input/logging.cpp b/kcms/input/logging.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/logging.cpp @@ -0,0 +1,22 @@ +/* + * 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. + */ + +#include "logging.h" + +Q_LOGGING_CATEGORY(KCM_INPUT, "kcm_input") + diff --git a/kcms/input/main.cpp b/kcms/input/main.cpp --- a/kcms/input/main.cpp +++ b/kcms/input/main.cpp @@ -21,68 +21,46 @@ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -#include - -#include +#include +#include #include -#include "mouse.h" -#include +#include "mousesettings.h" +#include "mousebackend.h" #include -#include -#ifdef HAVE_XCURSOR -# include -#endif - extern "C" { Q_DECL_EXPORT void kcminit_mouse() { KConfig *config = new KConfig("kcminputrc", KConfig::NoGlobals ); - Display *dpy = nullptr; - const bool platformX11 = QX11Info::isPlatformX11(); - if (platformX11) { - dpy = QX11Info::display(); - } else { - // let's hope we have a compatibility system like Xwayland ready - dpy = XOpenDisplay(nullptr); - } + auto backend = MouseBackend::implementation(); MouseSettings settings; - settings.load(config, dpy); - settings.apply(true); // force + settings.load(config, backend); + settings.apply(backend, true); // force -#ifdef HAVE_XCURSOR KConfigGroup group = config->group("Mouse"); QString theme = group.readEntry("cursorTheme", QString()); QString size = group.readEntry("cursorSize", QString()); - - // 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() - && (!dpy || - (QByteArray( XGetDefault( dpy, "Xcursor", "theme" )).isEmpty() - && QByteArray( XcursorGetTheme( dpy)).isEmpty()))) - { - theme = "breeze_cursors"; - } - - // Apply the KDE cursor theme to ourselves - if (dpy) { - if( !theme.isEmpty()) - XcursorSetTheme(dpy, QFile::encodeName(theme)); - - if (!size.isEmpty()) - XcursorSetDefaultSize(dpy, size.toUInt()); - - // Load the default cursor from the theme and apply it to the root window. - Cursor handle = XcursorLibraryLoadCursor(dpy, "left_ptr"); - XDefineCursor(dpy, QX11Info::appRootWindow(), handle); - XFreeCursor(dpy, handle); // Don't leak the cursor + 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 @@ -92,16 +70,9 @@ QDBusConnection::sessionBus()); if(!theme.isEmpty()) klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), theme); - if( !size.isEmpty()) + if(!size.isEmpty()) klauncher.setLaunchEnv(QStringLiteral("XCURSOR_SIZE"), size); -#endif - - if (!platformX11) { - XFlush(dpy); - XCloseDisplay(dpy); - } - delete config; } } diff --git a/kcms/input/mouse.h b/kcms/input/mouse.h --- a/kcms/input/mouse.h +++ b/kcms/input/mouse.h @@ -31,54 +31,22 @@ #ifndef __MOUSECONFIG_H__ #define __MOUSECONFIG_H__ -#include - #include #include -#include "ui_kmousedlg.h" - -#define RIGHT_HANDED 0 -#define LEFT_HANDED 1 +#include "mousebackend.h" +#include "ui_kcmmouse.h" class QCheckBox; class QDoubleSpinBox; class QSlider; class QSpinBox; class QTabWidget; -class KMouseDlg : public QWidget, public Ui::KMouseDlg -{ -public: - KMouseDlg( QWidget *parent ) : QWidget( parent ) { - setupUi( this ); - } -}; - -class MouseSettings -{ -public: - void save(KConfig *); - void load(KConfig *, Display *dpy = QX11Info::display()); - void apply(bool force=false); - -public: - int num_buttons; - int middle_button; - bool handedEnabled; - bool m_handedNeedsApply; - int handed; - double accelRate; - int thresholdMove; - int doubleClickInterval; - int dragStartTime; - int dragStartDist; - bool singleClick; - int wheelScrollLines; - bool reverseScrollPolarity; -}; +class MouseSettings; +class MouseBackend; -class MouseConfig : public KCModule +class MouseConfig : public KCModule, public Ui::KCMMouse { Q_OBJECT public: @@ -100,30 +68,15 @@ private: double getAccel(); int getThreshold(); - int getHandedness(); + MouseHanded getHandedness(); void setAccel(double); void setThreshold(int); - void setHandedness(int); - - QDoubleSpinBox *accel; - QSpinBox *thresh; - QSpinBox *doubleClickInterval; - QSpinBox *dragStartTime; - QSpinBox *dragStartDist; - QSpinBox *wheelScrollLines; + void setHandedness(MouseHanded); - QTabWidget *tabwidget; - QWidget *advancedTab; - KMouseDlg* generalTab; MouseSettings *settings; - QCheckBox *mouseKeys; - QSpinBox *mk_delay; - QSpinBox *mk_interval; - QSpinBox *mk_time_to_max; - QSpinBox *mk_max_speed; - QSpinBox *mk_curve; + MouseBackend *backend; }; #endif diff --git a/kcms/input/mouse.cpp b/kcms/input/mouse.cpp --- a/kcms/input/mouse.cpp +++ b/kcms/input/mouse.cpp @@ -65,261 +65,55 @@ #include #include "mouse.h" +#include "mousebackend.h" +#include "mousesettings.h" -#include -#include -#include -#include -#include #include -#include -#include #undef Below #include "../migrationlib/kdelibs4config.h" K_PLUGIN_FACTORY(MouseConfigFactory, registerPlugin(); // mouse ) -K_EXPORT_PLUGIN(MouseConfigFactory("kcminput")) MouseConfig::MouseConfig(QWidget *parent, const QVariantList &args) - : KCModule(parent, args) + : KCModule(parent, args), backend(MouseBackend::implementation()) { - setQuickHelp(i18n("

Mouse

This module allows you to choose various" - " options for the way in which your pointing device works. Your" - " pointing device may be a mouse, trackball, or some other hardware" - " that performs a similar function.")); + setupUi(this); - QBoxLayout *topLayout = new QVBoxLayout(this); - topLayout->setMargin(0); - - tabwidget = new QTabWidget(this); - topLayout->addWidget(tabwidget); - - generalTab = new KMouseDlg(this); - QButtonGroup *group = new QButtonGroup(generalTab); - group->setExclusive(true); - group->addButton(generalTab->singleClick); - group->addButton(generalTab->doubleClick); - - tabwidget->addTab(generalTab, i18n("&General")); - - group = new QButtonGroup(generalTab); - group->setExclusive(true); - group->addButton(generalTab->rightHanded,RIGHT_HANDED); - group->addButton(generalTab->leftHanded,LEFT_HANDED); - - connect(group, SIGNAL(buttonClicked(int)), this, SLOT(changed())); - connect(group, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int))); - - QString wtstr = i18n("If you are left-handed, you may prefer to swap the" - " functions of the left and right buttons on your pointing device" - " by choosing the 'left-handed' option. If your pointing device" - " has more than two buttons, only those that function as the" - " left and right buttons are affected. For example, if you have" - " a three-button mouse, the middle button is unaffected."); - generalTab->handedBox->setWhatsThis(wtstr); + generalTab->handedGroup->setId(generalTab->rightHanded, static_cast(MouseHanded::Right)); + generalTab->handedGroup->setId(generalTab->leftHanded, static_cast(MouseHanded::Left)); + connect(generalTab->handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed())); + connect(generalTab->handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int))); connect(generalTab->doubleClick, SIGNAL(clicked()), SLOT(changed())); - wtstr = i18n("The default behavior in KDE is to select and activate" - " icons with a single click of the left button on your pointing" - " device. This behavior is consistent with what you would expect" - " when you click links in most web browsers. If you would prefer" - " to select with a single click, and activate with a double click," - " check this option."); - generalTab->doubleClick->setWhatsThis(wtstr); - - wtstr = i18n("Activates and opens a file or folder with a single click."); - generalTab->singleClick->setWhatsThis(wtstr); - connect(generalTab->singleClick, SIGNAL(clicked()), this, SLOT(changed())); - - // Only allow setting reversing scroll polarity if we have scroll buttons - unsigned char map[20]; - if (QX11Info::isPlatformX11() && XGetPointerMapping(QX11Info::display(), map, 20) >= 5) - { - generalTab->cbScrollPolarity->setEnabled(true); - generalTab->cbScrollPolarity->show(); - } - else - { - generalTab->cbScrollPolarity->setEnabled(false); - generalTab->cbScrollPolarity->hide(); - } connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(changed())); connect(generalTab->cbScrollPolarity, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged())); - // Advanced tab - advancedTab = new QWidget(0); - advancedTab->setObjectName("Advanced Tab"); - tabwidget->addTab(advancedTab, i18n("Advanced")); - - QFormLayout *formLayout = new QFormLayout; - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - - accel = new QDoubleSpinBox(advancedTab); - accel->setDecimals(1); - accel->setRange(0.1, 20); - accel->setSingleStep(0.1); - accel->setValue(2); - accel->setSuffix(i18n(" x")); - accel->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - - formLayout->addRow(i18n("Pointer acceleration:"), accel); connect(accel, SIGNAL(valueChanged(double)), this, SLOT(changed())); - - wtstr = i18n("

This option allows you to change the relationship" - " between the distance that the mouse pointer moves on the" - " screen and the relative movement of the physical device" - " itself (which may be a mouse, trackball, or some other" - " pointing device.)

" - " A high value for the acceleration will lead to large" - " movements of the mouse pointer on the screen even when" - " you only make a small movement with the physical device." - " Selecting very high values may result in the mouse pointer" - " flying across the screen, making it hard to control.

"); - accel->setWhatsThis(wtstr); - - thresh = new QSpinBox(advancedTab); - thresh->setRange(0, 20); - thresh->setSingleStep(1); - thresh->setValue(2); - thresh->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Pointer threshold:"), thresh); connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(changed())); connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int))); + connect(accelProfileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changed())); slotThreshChanged(thresh->value()); - wtstr = i18n("

The threshold is the smallest distance that the" - " mouse pointer must move on the screen before acceleration" - " has any effect. If the movement is smaller than the threshold," - " the mouse pointer moves as if the acceleration was set to 1X;

" - " thus, when you make small movements with the physical device," - " there is no acceleration at all, giving you a greater degree" - " of control over the mouse pointer. With larger movements of" - " the physical device, you can move the mouse pointer" - " rapidly to different areas on the screen.

"); - thresh->setWhatsThis(wtstr); - // It would be nice if the user had a test field. // Selecting such values in milliseconds is not intuitive - doubleClickInterval = new QSpinBox(advancedTab); - doubleClickInterval->setRange(100, 2000); - doubleClickInterval->setSuffix(i18n(" msec")); - doubleClickInterval->setSingleStep(100); - doubleClickInterval->setValue(2000); - doubleClickInterval->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Double click interval:"), doubleClickInterval); connect(doubleClickInterval, SIGNAL(valueChanged(int)), this, SLOT(changed())); - wtstr = i18n("The double click interval is the maximal time" - " (in milliseconds) between two mouse clicks which" - " turns them into a double click. If the second" - " click happens later than this time interval after" - " the first click, they are recognized as two" - " separate clicks."); - doubleClickInterval->setWhatsThis(wtstr); - - dragStartTime = new QSpinBox(advancedTab); - dragStartTime->setRange(100, 2000); - dragStartTime->setSuffix(i18n(" msec")); - dragStartTime->setSingleStep(100); - dragStartTime->setValue(2000); - dragStartTime->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Drag start time:"), dragStartTime); connect(dragStartTime, SIGNAL(valueChanged(int)), this, SLOT(changed())); - wtstr = i18n("If you click with the mouse (e.g. in a multi-line" - " editor) and begin to move the mouse within the" - " drag start time, a drag operation will be initiated."); - dragStartTime->setWhatsThis(wtstr); - - dragStartDist = new QSpinBox(advancedTab); - dragStartDist->setRange(1, 20); - dragStartDist->setSingleStep(1); - dragStartDist->setValue(20); - dragStartDist->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Drag start distance:"), dragStartDist); connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(changed())); connect(dragStartDist, SIGNAL(valueChanged(int)), this, SLOT(slotDragStartDistChanged(int))); slotDragStartDistChanged(dragStartDist->value()); - wtstr = i18n("If you click with the mouse and begin to move the" - " mouse at least the drag start distance, a drag" - " operation will be initiated."); - dragStartDist->setWhatsThis(wtstr); - - wheelScrollLines = new QSpinBox(advancedTab); - wheelScrollLines->setRange(1, 12); - wheelScrollLines->setSingleStep(1); - wheelScrollLines->setValue(3); - wheelScrollLines->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Mouse wheel scrolls by:"), wheelScrollLines); connect(wheelScrollLines, SIGNAL(valueChanged(int)), this, SLOT(changed())); connect(wheelScrollLines, SIGNAL(valueChanged(int)), SLOT(slotWheelScrollLinesChanged(int))); slotWheelScrollLinesChanged(wheelScrollLines->value()); - wtstr = i18n("If you use the wheel of a mouse, this value determines the number" - " of lines to scroll for each wheel movement. Note that if this" - " number exceeds the number of visible lines, it will be ignored" - " and the wheel movement will be handled as a page up/down movement."); - wheelScrollLines->setWhatsThis(wtstr); - - QHBoxLayout *outerLayout = new QHBoxLayout(advancedTab); - outerLayout->addLayout(formLayout, 0); - outerLayout->addStretch(1); - - QWidget *keysTab = new QWidget(this); - keysTab->setObjectName("Mouse Navigation"); - tabwidget->addTab(keysTab, i18n("Keyboard Navigation")); - - formLayout = new QFormLayout; - formLayout->setFieldGrowthPolicy(QFormLayout::ExpandingFieldsGrow); - - mouseKeys = new QCheckBox(i18n("&Move pointer with keyboard (using the num pad)"), keysTab); - formLayout->addRow(mouseKeys); - - mk_delay = new QSpinBox(keysTab); - mk_delay->setRange(1, 1000); - mk_delay->setSingleStep(50); - mk_delay->setSuffix(i18n(" msec")); - mk_delay->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("&Acceleration delay:"), mk_delay); - - mk_interval = new QSpinBox(keysTab); - mk_interval->setRange(1, 1000); - mk_interval->setSingleStep(10); - mk_interval->setSuffix(i18n(" msec")); - mk_interval->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("R&epeat interval:"), mk_interval); - - mk_time_to_max = new QSpinBox(keysTab); - mk_time_to_max->setRange(100, 10000); - mk_time_to_max->setSingleStep(200); - mk_time_to_max->setSuffix(i18n(" msec")); - mk_time_to_max->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Acceleration &time:"), mk_time_to_max); - - mk_max_speed = new QSpinBox(keysTab); - mk_max_speed->setRange(1, 2000); - mk_max_speed->setSingleStep(20); - mk_max_speed->setSuffix(i18n(" pixel/sec")); - mk_max_speed->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Ma&ximum speed:"), mk_max_speed); - - mk_curve = new QSpinBox(keysTab); - mk_curve->setRange(-1000, 1000); - mk_curve->setSingleStep(100); - mk_curve->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Fixed); - formLayout->addRow(i18n("Acceleration &profile:"), mk_curve); - - outerLayout = new QHBoxLayout(keysTab); - outerLayout->addLayout(formLayout, 0); - outerLayout->addStretch(1); - connect(mouseKeys, SIGNAL(clicked()), this, SLOT(checkAccess())); connect(mouseKeys, SIGNAL(clicked()), this, SLOT(changed())); connect(mk_delay, SIGNAL(valueChanged(int)), this, SLOT(changed())); @@ -381,19 +175,19 @@ } -int MouseConfig::getHandedness() +MouseHanded MouseConfig::getHandedness() { if (generalTab->rightHanded->isChecked()) - return RIGHT_HANDED; + return MouseHanded::Right; else - return LEFT_HANDED; + return MouseHanded::Left; } -void MouseConfig::setHandedness(int val) +void MouseConfig::setHandedness(MouseHanded val) { generalTab->rightHanded->setChecked(false); generalTab->leftHanded->setChecked(false); - if (val == RIGHT_HANDED) { + if (val == MouseHanded::Right) { generalTab->rightHanded->setChecked(true); generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); } @@ -407,7 +201,38 @@ void MouseConfig::load() { KConfig config("kcminputrc"); - settings->load(&config); + settings->load(&config, backend); + + // 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()) + { + generalTab->cbScrollPolarity->setEnabled(true); + generalTab->cbScrollPolarity->show(); + } + else + { + generalTab->cbScrollPolarity->setEnabled(false); + generalTab->cbScrollPolarity->hide(); + } + + auto accelProfile = backend->supportedAccelerationProfiles(); + accelProfileComboBox->setEnabled(!accelProfile.isEmpty()); + accelProfileComboBox->setVisible(!accelProfile.isEmpty()); + accelerationProfileLabel->setEnabled(!accelProfile.isEmpty()); + accelerationProfileLabel->setVisible(!accelProfile.isEmpty()); + accelProfileComboBox->clear(); + int idx = 0; + for (const auto &profile : accelProfile) { + accelProfileComboBox->addItem(i18n(profile.toUtf8().constData()), profile); + if (profile == settings->m_currentAccelProfile) { + accelProfileComboBox->setCurrentIndex(idx); + } + idx++; + } + } generalTab->rightHanded->setEnabled(settings->handedEnabled); generalTab->leftHanded->setEnabled(settings->handedEnabled); @@ -469,8 +294,9 @@ settings->wheelScrollLines = wheelScrollLines->value(); settings->singleClick = !generalTab->doubleClick->isChecked(); settings->reverseScrollPolarity = generalTab->cbScrollPolarity->isChecked(); + settings->m_currentAccelProfile = accelProfileComboBox->itemData(accelProfileComboBox->currentIndex()).toString(); - settings->apply(); + settings->apply(backend); KConfig config("kcminputrc"); settings->save(&config); @@ -499,7 +325,7 @@ { setThreshold(2); setAccel(2); - setHandedness(RIGHT_HANDED); + setHandedness(MouseHanded::Right); generalTab->cbScrollPolarity->setChecked(false); doubleClickInterval->setValue(400); dragStartTime->setValue(500); @@ -522,101 +348,13 @@ /** No descriptions */ void MouseConfig::slotHandedChanged(int val) { - if (val==RIGHT_HANDED) + if (val == static_cast(MouseHanded::Right)) generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png")); else generalTab->mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png")); settings->m_handedNeedsApply = true; } -void MouseSettings::load(KConfig *config, Display *dpy) -{ - // TODO: what's a good threshold default value - int threshold = 0; - int h = RIGHT_HANDED; - double accel = 1.0; - if (QX11Info::isPlatformX11()) { - int accel_num, accel_den; - - XGetPointerControl(dpy, &accel_num, &accel_den, &threshold); - accel = float(accel_num) / float(accel_den); - - // get settings from X server - unsigned char map[20]; - num_buttons = XGetPointerMapping(dpy, map, 20); - - handedEnabled = true; - - // ## keep this in sync with KGlobalSettings::mouseSettings - if (num_buttons == 1) - { - /* disable button remapping */ - handedEnabled = false; - } - else if (num_buttons == 2) - { - if ((int)map[0] == 1 && (int)map[1] == 2) - h = RIGHT_HANDED; - else if ((int)map[0] == 2 && (int)map[1] == 1) - h = LEFT_HANDED; - else - /* custom button setup: disable button remapping */ - handedEnabled = false; - } - else - { - middle_button = (int)map[1]; - if ((int)map[0] == 1 && (int)map[2] == 3) - h = RIGHT_HANDED; - else if ((int)map[0] == 3 && (int)map[2] == 1) - h = LEFT_HANDED; - else - { - /* custom button setup: disable button remapping */ - handedEnabled = false; - } - } - } else { - // other platforms - handedEnabled = true; - } - - KConfigGroup group = config->group("Mouse"); - double a = group.readEntry("Acceleration", -1.0); - if (a == -1) - accelRate = accel; - else - accelRate = a; - - int t = group.readEntry("Threshold", -1); - if (t == -1) - thresholdMove = threshold; - else - thresholdMove = t; - - QString key = group.readEntry("MouseButtonMapping"); - if (key == "RightHanded") - handed = RIGHT_HANDED; - else if (key == "LeftHanded") - handed = LEFT_HANDED; -#ifdef __GNUC__ -#warning was key == NULL how was this working? is key.isNull() what the coder meant? -#endif - else if (key.isNull()) - handed = h; - reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false); - m_handedNeedsApply = false; - - // SC/DC/AutoSelect/ChangeCursor - group = config->group("KDE"); - doubleClickInterval = group.readEntry("DoubleClickInterval", 400); - dragStartTime = group.readEntry("StartDragTime", 500); - dragStartDist = group.readEntry("StartDragDist", 4); - wheelScrollLines = group.readEntry("WheelScrollLines", 3); - - singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK); -} - void MouseConfig::slotThreshChanged(int value) { thresh->setSuffix(i18np(" pixel", " pixels", value)); @@ -632,169 +370,6 @@ wheelScrollLines->setSuffix(i18np(" line", " lines", value)); } -void MouseSettings::apply(bool force) -{ - if (!QX11Info::isPlatformX11()) { - return; - } - XChangePointerControl(QX11Info::display(), - true, true, int(qRound(accelRate*10)), 10, thresholdMove); - - // 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]; - num_buttons = XGetPointerMapping(QX11Info::display(), map, 256); - - int remap=(num_buttons>=1); - if (handedEnabled && (m_handedNeedsApply || force)) { - if (num_buttons == 1) - { - map[0] = (unsigned char) 1; - } - else if (num_buttons == 2) - { - if (handed == RIGHT_HANDED) - { - 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 (handed == RIGHT_HANDED) - { - map[0] = (unsigned char) 1; - map[1] = (unsigned char) middle_button; - map[2] = (unsigned char) 3; - } - else - { - map[0] = (unsigned char) 3; - map[1] = (unsigned char) middle_button; - map[2] = (unsigned char) 1; - } - } - - int retval; - if (remap) { - while ((retval=XSetPointerMapping(QX11Info::display(), map, - num_buttons)) == MappingBusy) - /* keep trying until the pointer is free */ - { }; - } - - // apply reverseScrollPolarity - Display *dpy = QX11Info::display(); - Atom prop_wheel_emulation = XInternAtom(dpy, EVDEV_PROP_WHEEL, True); - Atom prop_scroll_distance = XInternAtom(dpy, EVDEV_PROP_SCROLL_DISTANCE, True); - Atom prop_wheel_emulation_axes = XInternAtom(dpy, EVDEV_PROP_WHEEL_AXES, True); - 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) { - int deviceid = (info + i)->deviceid; - Status status; - Atom type_return; - int format_return; - unsigned long num_items_return; - unsigned long bytes_after_return; - - unsigned char *data = nullptr; - unsigned char *data2 = nullptr; - //data returned is an 1 byte boolean - status = XIGetProperty(dpy, deviceid, prop_wheel_emulation, 0, 1, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &data); - if (status != Success) { - continue; - } - - // pointer device without wheel emulation - if (type_return != XA_INTEGER || data == NULL || *data == False) { - status = XIGetProperty(dpy, deviceid, prop_scroll_distance, 0, 3, - False, XA_INTEGER, &type_return, &format_return, - &num_items_return, &bytes_after_return, &data2); - // negate scroll distance - if (status == Success && type_return == XA_INTEGER && - format_return == 32 && num_items_return == 3) { - int32_t *vals = (int32_t*)data2; - for (unsigned long i=0; isync(); - - Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Mouse"), "kcminputrc"); - Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("KDE"), "kdeglobals"); - - KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_MOUSE); -} - void MouseConfig::slotScrollPolarityChanged() { settings->m_handedNeedsApply = true; diff --git a/kcms/input/mousebackend.h b/kcms/input/mousebackend.h new file mode 100644 --- /dev/null +++ b/kcms/input/mousebackend.h @@ -0,0 +1,61 @@ +/* + * 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 + +class MouseSettings; + +enum class MouseHanded { + Right = 0, + Left = 1, + NotSupported = -1 +}; + +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/mousebackend.cpp b/kcms/input/mousebackend.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/mousebackend.cpp @@ -0,0 +1,44 @@ +/* + * 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. + */ + +#include "mousebackend.h" + +#include "backends/x11/x11mousebackend.h" +#include "logging.h" + +#include +#include + +#include + +MouseBackend *MouseBackend::implementation() +{ + //There are multiple possible backends + if (KWindowSystem::isPlatformX11()) { + static QThreadStorage> backend; + if (!backend.hasLocalData()) { + qCDebug(KCM_INPUT) << "Using X11 backend"; + backend.setLocalData(QSharedPointer(new X11MouseBackend)); + } + return backend.localData().data(); + } + + qCCritical(KCM_INPUT) << "Not able to select appropriate backend."; + return nullptr; +} + diff --git a/kcms/input/mousesettings.h b/kcms/input/mousesettings.h new file mode 100644 --- /dev/null +++ b/kcms/input/mousesettings.h @@ -0,0 +1,49 @@ +/* + * 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 MOUSESETTINGS_H +#define MOUSESETTINGS_H + +#include "mousebackend.h" +#include + +class MouseBackend; + +class MouseSettings +{ +public: + void save(KConfig *); + void load(KConfig *, MouseBackend*); + void apply(MouseBackend*, bool force = false); + +public: + bool handedEnabled; + bool m_handedNeedsApply; + MouseHanded handed; + double accelRate; + int thresholdMove; + int doubleClickInterval; + int dragStartTime; + int dragStartDist; + bool singleClick; + int wheelScrollLines; + bool reverseScrollPolarity; + QString m_currentAccelProfile; +}; + +#endif // MOUSESETTINGS_H diff --git a/kcms/input/mousesettings.cpp b/kcms/input/mousesettings.cpp new file mode 100644 --- /dev/null +++ b/kcms/input/mousesettings.cpp @@ -0,0 +1,120 @@ +/* + * 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. + */ + +#include "mousesettings.h" + +#include +#include +#include + +#include "../migrationlib/kdelibs4config.h" + +void MouseSettings::apply(MouseBackend* backend, bool force) +{ + if (!backend) { + return; + } + + backend->apply(*this, force); + m_handedNeedsApply = false; +} + +void MouseSettings::load(KConfig *config, MouseBackend *backend) +{ + // TODO: what's a good threshold default value + int threshold = 0; + handed = MouseHanded::Right; + double accel = 1.0; + QString profile; + if (backend) { + backend->load(); + auto handedOnServer = backend->handed(); + handedEnabled = handedOnServer != MouseHanded::NotSupported; + if (handedEnabled) { + handed = handedOnServer; + } + accel = backend->accelRate(); + threshold = backend->threshold(); + profile = backend->accelerationProfile(); + } + + KConfigGroup group = config->group("Mouse"); + double a = group.readEntry("Acceleration", -1.0); + if (a == -1) + accelRate = accel; + else + accelRate = a; + + int t = group.readEntry("Threshold", -1); + if (t == -1) + thresholdMove = threshold; + else + thresholdMove = t; + + QString key = group.readEntry("MouseButtonMapping"); + if (key == "RightHanded") + handed = MouseHanded::Right; + else if (key == "LeftHanded") + handed = MouseHanded::Left; + reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false); + m_currentAccelProfile = group.readEntry("AccelerationProfile"); + if (m_currentAccelProfile.isEmpty()) { + m_currentAccelProfile = profile; + } + m_handedNeedsApply = false; + + // SC/DC/AutoSelect/ChangeCursor + group = config->group("KDE"); + doubleClickInterval = group.readEntry("DoubleClickInterval", 400); + dragStartTime = group.readEntry("StartDragTime", 500); + dragStartDist = group.readEntry("StartDragDist", 4); + wheelScrollLines = group.readEntry("WheelScrollLines", 3); + + singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK); +} + +void MouseSettings::save(KConfig *config) +{ + KSharedConfig::Ptr kcminputProfile = KSharedConfig::openConfig("kcminputrc"); + KConfigGroup kcminputGroup(kcminputProfile, "Mouse"); + kcminputGroup.writeEntry("Acceleration",accelRate); + kcminputGroup.writeEntry("Threshold",thresholdMove); + if (handed == MouseHanded::Right) + kcminputGroup.writeEntry("MouseButtonMapping",QString("RightHanded")); + else + kcminputGroup.writeEntry("MouseButtonMapping",QString("LeftHanded")); + kcminputGroup.writeEntry("ReverseScrollPolarity", reverseScrollPolarity); + kcminputGroup.writeEntry("AccelerationProfile", m_currentAccelProfile); + kcminputGroup.sync(); + + KSharedConfig::Ptr profile = KSharedConfig::openConfig("kdeglobals"); + KConfigGroup group(profile, "KDE"); + group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent); + group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent); + group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent); + group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent); + group.writeEntry("SingleClick", singleClick, KConfig::Persistent); + + group.sync(); + config->sync(); + + Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Mouse"), "kcminputrc"); + Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("KDE"), "kdeglobals"); + + KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_MOUSE); +} diff --git a/kcms/touchpad/src/backends/x11.cmake b/kcms/touchpad/src/backends/x11.cmake --- a/kcms/touchpad/src/backends/x11.cmake +++ b/kcms/touchpad/src/backends/x11.cmake @@ -13,6 +13,7 @@ ${X11_Xinput_INCLUDE_PATH} ${X11_X11_INCLUDE_PATH} ${Synaptics_INCLUDE_DIRS} + ${XORGLIBINPUT_INCLUDE_DIRS} ${XORG_INCLUDE_DIRS} ) diff --git a/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp --- a/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp +++ b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp @@ -21,15 +21,17 @@ #include #include +#include + const struct Parameter libinputProperties[] = { /* This is a boolean for all three fingers, no per-finger config */ - {"Tapping", PT_INT, 0, 1, "libinput Tapping Enabled", 8, 0}, + {"Tapping", PT_INT, 0, 1, LIBINPUT_PROP_TAP, 8, 0}, /* libinput normalizes the accel to -1/1 */ - {"AccelFactor", PT_DOUBLE, -1.0, 1.0, "libinput Accel Speed", 0 /*float */, 0}, + {"AccelFactor", PT_DOUBLE, -1.0, 1.0, LIBINPUT_PROP_ACCEL, 0 /*float */, 0}, /* Only one of these may be set at one time */ - {"VertEdgeScroll", PT_INT, 0, 1, "libinput Scroll Method Enabled", 8, 1}, - {"VertTwoFingerScroll", PT_INT, 0, 1, "libinput Scroll Method Enabled", 8, 0}, - {"InvertVertScroll", PT_INT, 0, 1, "libinput Natural Scrolling Enabled", 8, 0}, + {"VertEdgeScroll", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 1}, + {"VertTwoFingerScroll", PT_INT, 0, 1, LIBINPUT_PROP_SCROLL_METHOD_ENABLED, 8, 0}, + {"InvertVertScroll", PT_INT, 0, 1, LIBINPUT_PROP_NATURAL_SCROLL, 8, 0}, /* libinput doesn't have a separate toggle for horiz scrolling */ { NULL, PT_INT, 0, 0, 0, 0, 0 } }; @@ -42,11 +44,11 @@ the toggle so this is just to stop it from crashing when we check m_touchpadOffAtom */ m_touchpadOffAtom.intern(m_connection, - "libinput Send Events Mode enabled"); + LIBINPUT_PROP_SENDEVENTS_ENABLED); XcbAtom scroll_methods(m_connection, - "libinput Scroll Methods Available", + LIBINPUT_PROP_SCROLL_METHODS_AVAILABLE, true); if (scroll_methods.atom() != 0) { PropertyInfo methods(m_display, diff --git a/kcms/touchpad/src/backends/x11/xlibbackend.cpp b/kcms/touchpad/src/backends/x11/xlibbackend.cpp --- a/kcms/touchpad/src/backends/x11/xlibbackend.cpp +++ b/kcms/touchpad/src/backends/x11/xlibbackend.cpp @@ -39,6 +39,7 @@ #include #include +#include #include struct DeviceListDeleter @@ -91,7 +92,7 @@ m_enabledAtom.intern(m_connection, XI_PROP_ENABLED); m_synapticsIdentifierAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES); - m_libinputIdentifierAtom.intern(m_connection, "libinput Send Events Modes Available"); + m_libinputIdentifierAtom.intern(m_connection, LIBINPUT_PROP_SENDEVENTS_AVAILABLE); m_device.reset(findTouchpad()); if (!m_device) {