[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [plasma-desktop] kcms/touchpad/src: Refactor kcm touchpad to fix some issue related to hotplug touch
From:       Weng Xuetian <wengxt () gmail ! com>
Date:       2016-01-11 20:54:10
Message-ID: E1aIjTe-0004Lk-KY () scm ! kde ! org
[Download RAW message or body]

Git commit a39677c1fd1e6303ddaf31da5ccd0a6454104066 by Weng Xuetian.
Committed on 11/01/2016 at 20:38.
Pushed by xuetianweng into branch 'master'.

Refactor kcm touchpad to fix some issue related to hotplug touchpad

1. Remove SynapticsBackend and LibinputBackend and add three new classes
called XlibTouchpad/SynapticsTouchpad/LibinputTouchpad. So findTouchpad
may pick up both synaptics or libinput device, and no need to depend on
a fixed backend. This change also make it easier to support multiple
touchpad device easier if needed.

2. hotplug touchpad config not being applied (bug 356923) is mainly
because one can't apply settings to a disabled device. Change the
statement order in handleReset, apply settings first then set enable
status.

3. findTouchpad() is changed to use XListInputDevices, because it
provides necessary information of device type in order to filter
out non-touchpad device. xf86-input-libinput doesn't have a
unique atom for touchpad, so current identityAtom cannot
guarantee that findTouchpad always returns a touchpad device for
libinput.

4. On my surface pro 4 system, if touchpad is unpluged, the device will
be set to disabled automatically first, then touchpadDetached is called,
which makes m_enabled in TouchpadDisabled always to be false after
unplug the touchapd. This patch makes TouchpadDisabler have two
different enabled property. m_userRequestedState only stores the user
requested status, so when handleReset is called, it can properly set
enabled state to the last user requested state.

REVIEW: 126513
BUG: 349545
BUG: 356923
FIXED-IN: 5.6.0

M  +2    -2    kcms/touchpad/src/applet/qml/contents/ui/touchpad.qml
M  +7    -6    kcms/touchpad/src/applet/touchpadengine.cpp
M  +1    -0    kcms/touchpad/src/applet/touchpadengine.h
M  +5    -3    kcms/touchpad/src/backends/x11.cmake
R  +28   -2    kcms/touchpad/src/backends/x11/libinputtouchpad.cpp [from: \
kcms/touchpad/src/backends/x11/libinputproperties.c - 059% similarity] C  +7    -22   \
kcms/touchpad/src/backends/x11/libinputtouchpad.h [from: \
kcms/touchpad/src/applet/touchpadengine.h - 055% similarity] A  +90   -0    \
kcms/touchpad/src/backends/x11/propertyinfo.cpp     [License: GPL (v2+)] C  +23   -18 \
kcms/touchpad/src/backends/x11/propertyinfo.h [from: \
kcms/touchpad/src/applet/touchpadengine.h - 060% similarity] R  +178  -69   \
kcms/touchpad/src/backends/x11/synapticstouchpad.cpp [from: \
kcms/touchpad/src/backends/x11/synclientproperties.c - 053% similarity] C  +12   -20  \
kcms/touchpad/src/backends/x11/synapticstouchpad.h [from: \
kcms/touchpad/src/applet/touchpadengine.h - 056% similarity] D  +0    -71   \
kcms/touchpad/src/backends/x11/synclientproperties.h M  +79   -557  \
kcms/touchpad/src/backends/x11/xlibbackend.cpp M  +20   -30   \
kcms/touchpad/src/backends/x11/xlibbackend.h A  +292  -0    \
kcms/touchpad/src/backends/x11/xlibtouchpad.cpp     [License: UNKNOWN]  * A  +88   -0 \
kcms/touchpad/src/backends/x11/xlibtouchpad.h     [License: GPL (v2+)] M  +39   -13   \
kcms/touchpad/src/kded/kded.cpp M  +5    -1    kcms/touchpad/src/kded/kded.h
M  +2    -1    kcms/touchpad/src/touchpadbackend.h

The files marked with a * at the end have a non valid license. Please read: \
http://techbase.kde.org/Policies/Licensing_Policy and use the headers which are \
listed at that page.


http://commits.kde.org/plasma-desktop/a39677c1fd1e6303ddaf31da5ccd0a6454104066

diff --git a/kcms/touchpad/src/applet/qml/contents/ui/touchpad.qml \
b/kcms/touchpad/src/applet/qml/contents/ui/touchpad.qml index 8dec7c2..f91b4d4 100644
--- a/kcms/touchpad/src/applet/qml/contents/ui/touchpad.qml
+++ b/kcms/touchpad/src/applet/qml/contents/ui/touchpad.qml
@@ -42,7 +42,7 @@ Item {
                 //Hide plasmoid from notification area after short delay
                 delayedStatusUpdate.restart()
             } else {
-                plasmoid.status = PlasmaCore.Types.ActiveStatus
+                plasmoid.status = data.workingTouchpadFound ? \
PlasmaCore.Types.ActiveStatus : PlasmaCore.Types.PassiveStatus  }
 
             icon.elementId = data.enabled ? "touchpad_enabled"
@@ -53,7 +53,7 @@ Item {
         }
     }
 
-    property bool hasTouchpad: typeof dataSource.data.touchpad != 'undefined'
+    property bool hasTouchpad: typeof dataSource.data.touchpad != 'undefined' && \
dataSource.data.touchpad.workingTouchpadFound  property bool enabled: hasTouchpad ? \
dataSource.data.touchpad.enabled  : false
     property bool mouse: hasTouchpad ? dataSource.data.touchpad.mousePluggedIn
diff --git a/kcms/touchpad/src/applet/touchpadengine.cpp \
b/kcms/touchpad/src/applet/touchpadengine.cpp index eae429e..a6a923b 100644
--- a/kcms/touchpad/src/applet/touchpadengine.cpp
+++ b/kcms/touchpad/src/applet/touchpadengine.cpp
@@ -43,20 +43,21 @@ void TouchpadEngine::init()
         return;
     }
 
-    QDBusPendingReply<bool> check(m_daemon->workingTouchpadFound());
-    check.waitForFinished();
-    if (!check.isValid() || !check.value()) {
-        return;
-    }
-
+    connect(m_daemon, SIGNAL(workingTouchpadFoundChanged(bool)), \
                SLOT(workingTouchpadFoundChanged(bool)));
     connect(m_daemon, SIGNAL(enabledChanged(bool)), SLOT(enabledChanged(bool)));
     connect(m_daemon, SIGNAL(mousePluggedInChanged(bool)),
             SLOT(mousePluggedInChanged(bool)));
 
+    workingTouchpadFoundChanged(m_daemon->workingTouchpadFound());
     enabledChanged(m_daemon->isEnabled());
     mousePluggedInChanged(m_daemon->isMousePluggedIn());
 }
 
+void TouchpadEngine::workingTouchpadFoundChanged(bool value)
+{
+    setData(m_source, "workingTouchpadFound", value);
+}
+
 void TouchpadEngine::mousePluggedInChanged(bool value)
 {
     setData(m_source, "mousePluggedIn", value);
diff --git a/kcms/touchpad/src/applet/touchpadengine.h \
b/kcms/touchpad/src/applet/touchpadengine.h index 16b98c2..6bb535e 100644
--- a/kcms/touchpad/src/applet/touchpadengine.h
+++ b/kcms/touchpad/src/applet/touchpadengine.h
@@ -33,6 +33,7 @@ public:
     Plasma::Service *serviceForSource(const QString &source);
 
 private Q_SLOTS:
+    void workingTouchpadFoundChanged(bool);
     void mousePluggedInChanged(bool);
     void enabledChanged(bool);
 
diff --git a/kcms/touchpad/src/backends/x11.cmake \
b/kcms/touchpad/src/backends/x11.cmake index c9fcea8..d532888 100644
--- a/kcms/touchpad/src/backends/x11.cmake
+++ b/kcms/touchpad/src/backends/x11.cmake
@@ -20,10 +20,12 @@ add_definitions(${X11_XCB_DEFINITIONS} ${XCB_DEFINITIONS})
 
 SET(backend_SRCS
     ${backend_SRCS}
-    backends/x11/synclientproperties.c
-    backends/x11/libinputproperties.c
-    backends/x11/xcbatom.cpp
+    backends/x11/propertyinfo.cpp
     backends/x11/xlibbackend.cpp
+    backends/x11/synapticstouchpad.cpp
+    backends/x11/libinputtouchpad.cpp
+    backends/x11/xlibtouchpad.cpp
+    backends/x11/xcbatom.cpp
     backends/x11/xlibnotifications.cpp
     backends/x11/xrecordkeyboardmonitor.cpp
 )
diff --git a/kcms/touchpad/src/backends/x11/libinputproperties.c \
b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp similarity index 59%
rename from kcms/touchpad/src/backends/x11/libinputproperties.c
rename to kcms/touchpad/src/backends/x11/libinputtouchpad.cpp
index 9dbf9ea..fea6e81 100644
--- a/kcms/touchpad/src/backends/x11/libinputproperties.c
+++ b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp
@@ -16,7 +16,7 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
 
-#include "synclientproperties.h"
+#include "libinputtouchpad.h"
 
 #include <stddef.h>
 #include <limits.h>
@@ -31,5 +31,31 @@ const struct Parameter libinputProperties[] = {
     {"VertTwoFingerScroll",     PT_INT, 0, 1, "libinput Scroll Method Enabled", 8,   \
                0},
     {"InvertVertScroll",     PT_INT, 0, 1, "libinput Natural Scrolling Enabled", 8,  \
0},  /* libinput doesn't have a separate toggle for horiz scrolling */
-    { NULL, 0, 0, 0, 0, 0, 0 }
+    { NULL, PT_INT, 0, 0, 0, 0, 0 }
 };
+
+LibinputTouchpad::LibinputTouchpad(Display *display, int deviceId): \
XlibTouchpad(display, deviceId) +{
+    loadSupportedProperties(libinputProperties);
+
+    /* FIXME: has a different format than Synaptics Off but we don't expose
+       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");
+
+
+    XcbAtom scroll_methods(m_connection,
+                           "libinput Scroll Methods Available",
+                           true);
+    if (scroll_methods.atom() != 0) {
+        PropertyInfo methods(m_display,
+                             m_deviceId,
+                             scroll_methods.atom(),
+                             0);
+        if (!methods.value(0).toInt())
+            m_supported.removeAll("VertTwoFingerScroll");
+        else if (!methods.value(1).toInt())
+            m_supported.removeAll("VertEdgeScroll");
+    }
+}
diff --git a/kcms/touchpad/src/applet/touchpadengine.h \
b/kcms/touchpad/src/backends/x11/libinputtouchpad.h similarity index 55%
copy from kcms/touchpad/src/applet/touchpadengine.h
copy to kcms/touchpad/src/backends/x11/libinputtouchpad.h
index 16b98c2..2de8215 100644
--- a/kcms/touchpad/src/applet/touchpadengine.h
+++ b/kcms/touchpad/src/backends/x11/libinputtouchpad.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Alexander Mezin <mezin.alexander@gmail.com>
+ * Copyright (C) 2015 Weng Xuetian <wengxt@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -15,31 +15,16 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-#ifndef TOUCHPADENGINE_H
-#define TOUCHPADENGINE_H
 
-#include <Plasma/DataEngine>
+#ifndef LIBINPUTTOUCHPAD_H
+#define LIBINPUTTOUCHPAD_H
 
-class OrgKdeTouchpadInterface;
+#include "xlibtouchpad.h"
 
-class TouchpadEngine : public Plasma::DataEngine
+class LibinputTouchpad : public XlibTouchpad
 {
-    Q_OBJECT
-
 public:
-    TouchpadEngine(QObject *parent, const QVariantList &args);
-    ~TouchpadEngine();
-
-    Plasma::Service *serviceForSource(const QString &source);
-
-private Q_SLOTS:
-    void mousePluggedInChanged(bool);
-    void enabledChanged(bool);
-
-private:
-    void init();
-    QString m_source;
-    OrgKdeTouchpadInterface *m_daemon;
+    LibinputTouchpad(Display *display, int deviceId);
 };
 
-#endif // TOUCHPADENGINE_H
+#endif // LIBINPUTTOUCHPAD_H
diff --git a/kcms/touchpad/src/backends/x11/propertyinfo.cpp \
b/kcms/touchpad/src/backends/x11/propertyinfo.cpp new file mode 100644
index 0000000..95e1e44
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/propertyinfo.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2013 Alexander Mezin <mezin.alexander@gmail.com>
+ *
+ * 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 "propertyinfo.h"
+
+#include <QVariant>
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/XInput2.h>
+
+void XDeleter(void* p)
+{
+    if (p) {
+        XFree(p);
+    }
+}
+
+PropertyInfo::PropertyInfo() :
+    type(0), format(0), nitems(0), f(0), i(0), b(0),
+    display(0), device(0), prop(0)
+{
+}
+
+PropertyInfo::PropertyInfo(Display *display, int device, Atom prop, Atom floatType)
+    : type(0), format(0), nitems(0), f(0), i(0), b(0),
+      display(display), device(device), prop(prop)
+{
+    unsigned char *dataPtr = 0;
+    unsigned long bytes_after;
+    XIGetProperty(display, device, prop, 0, 1000, False,
+                    AnyPropertyType, &type, &format, &nitems,
+                    &bytes_after, &dataPtr);
+    data = QSharedPointer<unsigned char>(dataPtr, XDeleter);
+
+    if (format == CHAR_BIT && type == XA_INTEGER) {
+        b = reinterpret_cast<char *>(dataPtr);
+    }
+    if (format == sizeof(int) * CHAR_BIT &&
+            (type == XA_INTEGER || type == XA_CARDINAL))
+    {
+        i = reinterpret_cast<int *>(dataPtr);
+    }
+    if (format == sizeof(float) * CHAR_BIT &&
+            floatType && type == floatType)
+    {
+        f = reinterpret_cast<float *>(dataPtr);
+    }
+}
+
+QVariant PropertyInfo::value(unsigned offset) const
+{
+    QVariant v;
+    if (offset >= nitems) {
+        return v;
+    }
+
+    if (b) {
+        v = QVariant(static_cast<int>(b[offset]));
+    }
+    if (i) {
+        v = QVariant(i[offset]);
+    }
+    if (f) {
+        v = QVariant(f[offset]);
+    }
+
+    return v;
+}
+
+void PropertyInfo::set()
+{
+    XIChangeProperty(display, device, prop, type, format,
+                        XIPropModeReplace, data.data(), nitems);
+}
diff --git a/kcms/touchpad/src/applet/touchpadengine.h \
b/kcms/touchpad/src/backends/x11/propertyinfo.h similarity index 60%
copy from kcms/touchpad/src/applet/touchpadengine.h
copy to kcms/touchpad/src/backends/x11/propertyinfo.h
index 16b98c2..5a36242 100644
--- a/kcms/touchpad/src/applet/touchpadengine.h
+++ b/kcms/touchpad/src/backends/x11/propertyinfo.h
@@ -15,31 +15,36 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-#ifndef TOUCHPADENGINE_H
-#define TOUCHPADENGINE_H
 
-#include <Plasma/DataEngine>
+#ifndef PROPERTYINFO_H
+#define PROPERTYINFO_H
 
-class OrgKdeTouchpadInterface;
+#include <QSharedPointer>
+#include <QX11Info>
+#include <X11/Xdefs.h>
 
-class TouchpadEngine : public Plasma::DataEngine
+void XDeleter(void *p);
+
+struct PropertyInfo
 {
-    Q_OBJECT
+    Atom type;
+    int format;
+    QSharedPointer<unsigned char> data;
+    unsigned long nitems;
 
-public:
-    TouchpadEngine(QObject *parent, const QVariantList &args);
-    ~TouchpadEngine();
+    float *f;
+    int *i;
+    char *b;
 
-    Plasma::Service *serviceForSource(const QString &source);
+    Display *display;
+    int device;
+    Atom prop;
 
-private Q_SLOTS:
-    void mousePluggedInChanged(bool);
-    void enabledChanged(bool);
+    PropertyInfo();
+    PropertyInfo(Display *display, int device, Atom prop, Atom floatType);
+    QVariant value(unsigned offset) const;
 
-private:
-    void init();
-    QString m_source;
-    OrgKdeTouchpadInterface *m_daemon;
+    void set();
 };
 
-#endif // TOUCHPADENGINE_H
+#endif // PROPERTYINFO_H
diff --git a/kcms/touchpad/src/backends/x11/synclientproperties.c \
b/kcms/touchpad/src/backends/x11/synapticstouchpad.cpp similarity index 53%
rename from kcms/touchpad/src/backends/x11/synclientproperties.c
rename to kcms/touchpad/src/backends/x11/synapticstouchpad.cpp
index 5fd1ed6..1e01894 100644
--- a/kcms/touchpad/src/backends/x11/synclientproperties.c
+++ b/kcms/touchpad/src/backends/x11/synapticstouchpad.cpp
@@ -46,7 +46,9 @@
  *      Peter Osterlund (petero2@telia.com)
  */
 
-#include "synclientproperties.h"
+#include <QDebug>
+
+#include "synapticstouchpad.h"
 
 #include <stddef.h>
 #include <limits.h>
@@ -55,72 +57,179 @@
 #define SYN_MAX_BUTTONS 12
 
 const struct Parameter synapticsProperties[] = {
-    {"LeftEdge",              PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	0},
-    {"RightEdge",             PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	1},
-    {"TopEdge",               PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	2},
-    {"BottomEdge",            PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,	32,	3},
-    {"FingerLow",             PT_INT,    0, 255,   SYNAPTICS_PROP_FINGER,	32,	0},
-    {"FingerHigh",            PT_INT,    0, 255,   SYNAPTICS_PROP_FINGER,	32,	1},
-    {"MaxTapTime",            PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_TIME,	32,	0},
-    {"MaxTapMove",            PT_INT,    0, 2000,  SYNAPTICS_PROP_TAP_MOVE,	32,	0},
-    {"MaxDoubleTapTime",      PT_INT,    0, 1000,  \
                SYNAPTICS_PROP_TAP_DURATIONS,32,	1},
-    {"SingleTapTimeout",      PT_INT,    0, 1000,  \
                SYNAPTICS_PROP_TAP_DURATIONS,32,	0},
-    {"ClickTime",             PT_INT,    0, 1000,  \
                SYNAPTICS_PROP_TAP_DURATIONS,32,	2},
-    {"FastTaps",              PT_BOOL,   0, 1,     SYNAPTICS_PROP_TAP_FAST,	8,	0},
-    {"EmulateMidButtonTime",  PT_INT,    0, 1000,  \
                SYNAPTICS_PROP_MIDDLE_TIMEOUT,32,	0},
-    {"EmulateTwoFingerMinZ",  PT_INT,    0, 1000,  \
                SYNAPTICS_PROP_TWOFINGER_PRESSURE,	32,	0},
-    {"EmulateTwoFingerMinW",  PT_INT,    0, 15,    \
                SYNAPTICS_PROP_TWOFINGER_WIDTH,	32,	0},
-    {"VertScrollDelta",       PT_INT,    -1000, 1000,  \
                SYNAPTICS_PROP_SCROLL_DISTANCE,	32,	0},
-    {"HorizScrollDelta",      PT_INT,    -1000, 1000,  \
                SYNAPTICS_PROP_SCROLL_DISTANCE,	32,	1},
-    {"VertEdgeScroll",        PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_SCROLL_EDGE,	8,	0},
-    {"HorizEdgeScroll",       PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_SCROLL_EDGE,	8,	1},
-    {"CornerCoasting",        PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_SCROLL_EDGE,	8,	2},
-    {"VertTwoFingerScroll",   PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_SCROLL_TWOFINGER,	8,	0},
-    {"HorizTwoFingerScroll",  PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_SCROLL_TWOFINGER,	8,	1},
-    {"MinSpeed",              PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,	0, \
                /*float */	0},
-    {"MaxSpeed",              PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,	0, \
                /*float */	1},
-    {"AccelFactor",           PT_DOUBLE, 0, 1.0,   SYNAPTICS_PROP_SPEED,	0, /*float \
                */	2},
-    /*{"TouchpadOff",           PT_INT,    0, 2,     SYNAPTICS_PROP_OFF,		8,	0},*/
-    {"LockedDrags",           PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_LOCKED_DRAGS,	8,	0},
-    {"LockedDragTimeout",     PT_INT,    0, 30000, \
                SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT,	32,	0},
-    {"RTCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	0},
-    {"RBCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	1},
-    {"LTCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	2},
-    {"LBCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	3},
-    {"OneFingerTapButton",    PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	4},
-    {"TwoFingerTapButton",    PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	5},
-    {"ThreeFingerTapButton",  PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_TAP_ACTION,	8,	6},
-    {"ClickFinger1",          PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_CLICK_ACTION,	8,	0},
-    {"ClickFinger2",          PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_CLICK_ACTION,	8,	1},
-    {"ClickFinger3",          PT_INT,    0, SYN_MAX_BUTTONS, \
                SYNAPTICS_PROP_CLICK_ACTION,	8,	2},
-    {"CircularScrolling",     PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_CIRCULAR_SCROLLING,	8,	0},
-    {"CircScrollDelta",       PT_DOUBLE, .01, 3,   \
                SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST,	0 /* float */,	0},
-    {"CircScrollTrigger",     PT_INT,    0, 8,     \
                SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER,	8,	0},
-    {"PalmDetect",            PT_BOOL,   0, 1,     \
                SYNAPTICS_PROP_PALM_DETECT,	8,	0},
-    {"PalmMinWidth",          PT_INT,    0, 15,    \
                SYNAPTICS_PROP_PALM_DIMENSIONS,	32,	0},
-    {"PalmMinZ",              PT_INT,    0, 255,   \
                SYNAPTICS_PROP_PALM_DIMENSIONS,	32,	1},
-    {"CoastingSpeed",         PT_DOUBLE, 0, 255,    SYNAPTICS_PROP_COASTING_SPEED,	0 \
                /* float*/,	0},
-    {"CoastingFriction",      PT_DOUBLE, 0, 255,   SYNAPTICS_PROP_COASTING_SPEED,	0 \
                /* float*/,	1},
-    {"PressureMotionMinZ",    PT_INT,    1, 255,   \
                SYNAPTICS_PROP_PRESSURE_MOTION,	32,	0},
-    {"PressureMotionMaxZ",    PT_INT,    1, 255,   \
                SYNAPTICS_PROP_PRESSURE_MOTION,	32,	1},
-    {"PressureMotionMinFactor", PT_DOUBLE, 0, \
                10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR,	0 /*float*/,	0},
-    {"PressureMotionMaxFactor", PT_DOUBLE, 0, \
                10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR,	0 /*float*/,	1},
-    {"GrabEventDevice",       PT_BOOL,   0, 1,     SYNAPTICS_PROP_GRAB,	8,	0},
-    {"TapAndDragGesture",     PT_BOOL,   0, 1,     SYNAPTICS_PROP_GESTURES,	8,	0},
-    {"AreaLeftEdge",          PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	0},
-    {"AreaRightEdge",         PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	1},
-    {"AreaTopEdge",           PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	2},
-    {"AreaBottomEdge",        PT_INT,    0, 10000, SYNAPTICS_PROP_AREA,	32,	3},
-    {"HorizHysteresis",       PT_INT,    0, 10000, \
                SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	0},
-    {"VertHysteresis",        PT_INT,    0, 10000, \
                SYNAPTICS_PROP_NOISE_CANCELLATION, 32,	1},
-    {"ClickPad",              PT_BOOL,   0, 1,     SYNAPTICS_PROP_CLICKPAD,	8,	0},
-    {"RightButtonAreaLeft",   PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	0},
-    {"RightButtonAreaRight",  PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	1},
-    {"RightButtonAreaTop",    PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	2},
-    {"RightButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	3},
-    {"MiddleButtonAreaLeft",  PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	4},
-    {"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	5},
-    {"MiddleButtonAreaTop",   PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	6},
-    {"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, \
                SYNAPTICS_PROP_SOFTBUTTON_AREAS,	32,	7},
-    { NULL, 0, 0, 0, 0, 0, 0 }
+    {"LeftEdge",              PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,    32, 0},
+    {"RightEdge",             PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,    32, 1},
+    {"TopEdge",               PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,    32, 2},
+    {"BottomEdge",            PT_INT,    0, 10000, SYNAPTICS_PROP_EDGES,    32, 3},
+    {"FingerLow",             PT_INT,    0, 255,   SYNAPTICS_PROP_FINGER,   32, 0},
+    {"FingerHigh",            PT_INT,    0, 255,   SYNAPTICS_PROP_FINGER,   32, 1},
+    {"MaxTapTime",            PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_TIME, 32, 0},
+    {"MaxTapMove",            PT_INT,    0, 2000,  SYNAPTICS_PROP_TAP_MOVE, 32, 0},
+    {"MaxDoubleTapTime",      PT_INT,    0, 1000,  SYNAPTICS_PROP_TAP_DURATIONS,32, \
1}, +    {"SingleTapTimeout",      PT_INT,    0, 1000,  \
SYNAPTICS_PROP_TAP_DURATIONS,32, 0}, +    {"ClickTime",             PT_INT,    0, \
1000,  SYNAPTICS_PROP_TAP_DURATIONS,32, 2}, +    {"FastTaps",              PT_BOOL,   \
0, 1,     SYNAPTICS_PROP_TAP_FAST, 8,  0}, +    {"EmulateMidButtonTime",  PT_INT,    \
0, 1000,  SYNAPTICS_PROP_MIDDLE_TIMEOUT,32,    0}, +    {"EmulateTwoFingerMinZ",  \
PT_INT,    0, 1000,  SYNAPTICS_PROP_TWOFINGER_PRESSURE,   32, 0}, +    \
{"EmulateTwoFingerMinW",  PT_INT,    0, 15,    SYNAPTICS_PROP_TWOFINGER_WIDTH,  32, \
0}, +    {"VertScrollDelta",       PT_INT,    -1000, 1000,  \
SYNAPTICS_PROP_SCROLL_DISTANCE,  32, 0}, +    {"HorizScrollDelta",      PT_INT,    \
-1000, 1000,  SYNAPTICS_PROP_SCROLL_DISTANCE,  32, 1}, +    {"VertEdgeScroll",        \
PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_EDGE,  8,  0}, +    {"HorizEdgeScroll",    \
PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_EDGE,  8,  1}, +    {"CornerCoasting",     \
PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_EDGE,  8,  2}, +    \
{"VertTwoFingerScroll",   PT_BOOL,   0, 1,     SYNAPTICS_PROP_SCROLL_TWOFINGER, 8,  \
0}, +    {"HorizTwoFingerScroll",  PT_BOOL,   0, 1,     \
SYNAPTICS_PROP_SCROLL_TWOFINGER, 8,  1}, +    {"MinSpeed",              PT_DOUBLE, 0, \
255.0,   SYNAPTICS_PROP_SPEED,  0, /*float */   0}, +    {"MaxSpeed",              \
PT_DOUBLE, 0, 255.0,   SYNAPTICS_PROP_SPEED,  0, /*float */   1}, +    \
{"AccelFactor",           PT_DOUBLE, 0, 1.0,   SYNAPTICS_PROP_SPEED,    0, /*float */ \
2}, +    /*{"TouchpadOff",           PT_INT,    0, 2,     SYNAPTICS_PROP_OFF,        \
8,  0},*/ +    {"LockedDrags",           PT_BOOL,   0, 1,     \
SYNAPTICS_PROP_LOCKED_DRAGS, 8,  0}, +    {"LockedDragTimeout",     PT_INT,    0, \
30000, SYNAPTICS_PROP_LOCKED_DRAGS_TIMEOUT, 32, 0}, +    {"RTCornerButton",        \
PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8,  0}, +    \
{"RBCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, \
8,  1}, +    {"LTCornerButton",        PT_INT,    0, SYN_MAX_BUTTONS, \
SYNAPTICS_PROP_TAP_ACTION, 8,  2}, +    {"LBCornerButton",        PT_INT,    0, \
SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8,  3}, +    {"OneFingerTapButton",    \
PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, 8,  4}, +    \
{"TwoFingerTapButton",    PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_TAP_ACTION, \
8,  5}, +    {"ThreeFingerTapButton",  PT_INT,    0, SYN_MAX_BUTTONS, \
SYNAPTICS_PROP_TAP_ACTION, 8,  6}, +    {"ClickFinger1",          PT_INT,    0, \
SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION,   8,  0}, +    {"ClickFinger2",         \
PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION,   8,  1}, +    \
{"ClickFinger3",          PT_INT,    0, SYN_MAX_BUTTONS, SYNAPTICS_PROP_CLICK_ACTION, \
8,  2}, +    {"CircularScrolling",     PT_BOOL,   0, 1,     \
SYNAPTICS_PROP_CIRCULAR_SCROLLING,   8,  0}, +    {"CircScrollDelta",       \
PT_DOUBLE, .01, 3,   SYNAPTICS_PROP_CIRCULAR_SCROLLING_DIST,  0 /* float */,  0}, +   \
{"CircScrollTrigger",     PT_INT,    0, 8,     \
SYNAPTICS_PROP_CIRCULAR_SCROLLING_TRIGGER,   8,  0}, +    {"PalmDetect",            \
PT_BOOL,   0, 1,     SYNAPTICS_PROP_PALM_DETECT,  8,  0}, +    {"PalmMinWidth",       \
PT_INT,    0, 15,    SYNAPTICS_PROP_PALM_DIMENSIONS,  32, 0}, +    {"PalmMinZ",       \
PT_INT,    0, 255,   SYNAPTICS_PROP_PALM_DIMENSIONS,  32, 1}, +    {"CoastingSpeed",  \
PT_DOUBLE, 0, 255,    SYNAPTICS_PROP_COASTING_SPEED,  0 /* float*/,   0}, +    \
{"CoastingFriction",      PT_DOUBLE, 0, 255,   SYNAPTICS_PROP_COASTING_SPEED,   0 /* \
float*/,   1}, +    {"PressureMotionMinZ",    PT_INT,    1, 255,   \
SYNAPTICS_PROP_PRESSURE_MOTION,  32, 0}, +    {"PressureMotionMaxZ",    PT_INT,    1, \
255,   SYNAPTICS_PROP_PRESSURE_MOTION,  32, 1}, +    {"PressureMotionMinFactor", \
PT_DOUBLE, 0, 10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR,   0 /*float*/,    0}, +    \
{"PressureMotionMaxFactor", PT_DOUBLE, 0, 10.0,SYNAPTICS_PROP_PRESSURE_MOTION_FACTOR, \
0 /*float*/,    1}, +    {"GrabEventDevice",       PT_BOOL,   0, 1,     \
SYNAPTICS_PROP_GRAB, 8,  0}, +    {"TapAndDragGesture",     PT_BOOL,   0, 1,     \
SYNAPTICS_PROP_GESTURES, 8,  0}, +    {"AreaLeftEdge",          PT_INT,    0, 10000, \
SYNAPTICS_PROP_AREA, 32, 0}, +    {"AreaRightEdge",         PT_INT,    0, 10000, \
SYNAPTICS_PROP_AREA, 32, 1}, +    {"AreaTopEdge",           PT_INT,    0, 10000, \
SYNAPTICS_PROP_AREA, 32, 2}, +    {"AreaBottomEdge",        PT_INT,    0, 10000, \
SYNAPTICS_PROP_AREA, 32, 3}, +    {"HorizHysteresis",       PT_INT,    0, 10000, \
SYNAPTICS_PROP_NOISE_CANCELLATION, 32,   0}, +    {"VertHysteresis",        PT_INT,   \
0, 10000, SYNAPTICS_PROP_NOISE_CANCELLATION, 32,   1}, +    {"ClickPad",              \
PT_BOOL,   0, 1,     SYNAPTICS_PROP_CLICKPAD, 8,  0}, +    {"RightButtonAreaLeft",   \
PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,    32, 0}, +    \
{"RightButtonAreaRight",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,  \
32, 1}, +    {"RightButtonAreaTop",    PT_INT, INT_MIN, INT_MAX, \
SYNAPTICS_PROP_SOFTBUTTON_AREAS,    32, 2}, +    {"RightButtonAreaBottom", PT_INT, \
INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,    32, 3}, +    \
{"MiddleButtonAreaLeft",  PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,  \
32, 4}, +    {"MiddleButtonAreaRight", PT_INT, INT_MIN, INT_MAX, \
SYNAPTICS_PROP_SOFTBUTTON_AREAS,    32, 5}, +    {"MiddleButtonAreaTop",   PT_INT, \
INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS,    32, 6}, +    \
{"MiddleButtonAreaBottom", PT_INT, INT_MIN, INT_MAX, SYNAPTICS_PROP_SOFTBUTTON_AREAS, \
32, 7}, +    { NULL, PT_INT, 0, 0, 0, 0, 0 }
 };
+
+SynapticsTouchpad::SynapticsTouchpad(Display *display, int deviceId): \
XlibTouchpad(display, deviceId), +    m_resX(1), m_resY(1)
+{
+    m_capsAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES);
+    m_touchpadOffAtom.intern(m_connection, SYNAPTICS_PROP_OFF);
+    XcbAtom resolutionAtom(m_connection, SYNAPTICS_PROP_RESOLUTION);
+    XcbAtom edgesAtom(m_connection, SYNAPTICS_PROP_EDGES);
+
+    loadSupportedProperties(synapticsProperties);
+
+    m_toRadians.append("CircScrollDelta");
+
+    PropertyInfo edges(m_display, m_deviceId, edgesAtom, 0);
+    if (edges.i && edges.nitems == 4) {
+        int w = qAbs(edges.i[1] - edges.i[0]);
+        int h = qAbs(edges.i[3] - edges.i[2]);
+        m_resX = w / 90;
+        m_resY = h / 50;
+        qDebug() << "Width: " << w << " height: " << h;
+        qDebug() << "Approx. resX: " << m_resX << " resY: " << m_resY;
+    }
+
+    PropertyInfo resolution(m_display, m_deviceId, resolutionAtom, 0);
+    if (resolution.i && resolution.nitems == 2 &&
+        resolution.i[0] > 1 && resolution.i[1] > 1)
+    {
+        m_resY = qMin(static_cast<unsigned long>(resolution.i[0]),
+                static_cast<unsigned long>(INT_MAX));
+        m_resX = qMin(static_cast<unsigned long>(resolution.i[1]),
+                static_cast<unsigned long>(INT_MAX));
+        qDebug() << "Touchpad resolution: x: " << m_resX << " y: " << m_resY;
+    }
+
+    m_scaleByResX.append("HorizScrollDelta");
+    m_scaleByResY.append("VertScrollDelta");
+    m_scaleByResX.append("MaxTapMove");
+    m_scaleByResY.append("MaxTapMove");
+
+    m_resX = qMax(10, m_resX);
+    m_resY = qMax(10, m_resY);
+    qDebug() << "Final resolution x:" << m_resX << " y:" << m_resY;
+    m_negate["HorizScrollDelta"] = "InvertHorizScroll";
+    m_negate["VertScrollDelta"] = "InvertVertScroll";
+    m_supported.append(m_negate.values());
+    m_supported.append("Coasting");
+
+    PropertyInfo caps(m_display, m_deviceId, m_capsAtom.atom(), 0);
+    if (!caps.b) {
+        return;
+    }
+
+    enum TouchpadCapabilitiy
+    {
+        TouchpadHasLeftButton,
+        TouchpadHasMiddleButton,
+        TouchpadHasRightButton,
+        TouchpadTwoFingerDetect,
+        TouchpadThreeFingerDetect,
+        TouchpadPressureDetect,
+        TouchpadPalmDetect,
+        TouchpadCapsCount
+    };
+
+    QVector<bool> cap(TouchpadCapsCount, false);
+    qCopy(caps.b, caps.b + qMin(cap.size(), static_cast<int>(caps.nitems)),
+          cap.begin());
+
+    if (!cap[TouchpadTwoFingerDetect]) {
+        m_supported.removeAll("HorizTwoFingerScroll");
+        m_supported.removeAll("VertTwoFingerScroll");
+        m_supported.removeAll("TwoFingerTapButton");
+    }
+
+    if (!cap[TouchpadThreeFingerDetect]) {
+        m_supported.removeAll("ThreeFingerTapButton");
+    }
+
+    if (!cap[TouchpadPressureDetect]) {
+        m_supported.removeAll("FingerHigh");
+        m_supported.removeAll("FingerLow");
+
+        m_supported.removeAll("PalmMinZ");
+        m_supported.removeAll("PressureMotionMinZ");
+        m_supported.removeAll("PressureMotionMinFactor");
+        m_supported.removeAll("PressureMotionMaxZ");
+        m_supported.removeAll("PressureMotionMaxFactor");
+        m_supported.removeAll("EmulateTwoFingerMinZ");
+    }
+
+    if (!cap[TouchpadPalmDetect]) {
+        m_supported.removeAll("PalmDetect");
+        m_supported.removeAll("PalmMinWidth");
+        m_supported.removeAll("PalmMinZ");
+        m_supported.removeAll("EmulateTwoFingerMinW");
+    }
+
+    for (QMap<QString, QString>::Iterator i = m_negate.begin();
+         i != m_negate.end(); ++i)
+    {
+        if (!m_supported.contains(i.key())) {
+            m_supported.removeAll(i.value());
+        }
+    }
+
+    m_paramList = synapticsProperties;
+}
diff --git a/kcms/touchpad/src/applet/touchpadengine.h \
b/kcms/touchpad/src/backends/x11/synapticstouchpad.h similarity index 56%
copy from kcms/touchpad/src/applet/touchpadengine.h
copy to kcms/touchpad/src/backends/x11/synapticstouchpad.h
index 16b98c2..716687b 100644
--- a/kcms/touchpad/src/applet/touchpadengine.h
+++ b/kcms/touchpad/src/backends/x11/synapticstouchpad.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2013 Alexander Mezin <mezin.alexander@gmail.com>
+ * Copyright (C) 2015 Weng Xuetian <wengxt@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -15,31 +15,23 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  */
-#ifndef TOUCHPADENGINE_H
-#define TOUCHPADENGINE_H
 
-#include <Plasma/DataEngine>
+#ifndef SYNAPTICSTOUCHPAD_H
+#define SYNAPTICSTOUCHPAD_H
 
-class OrgKdeTouchpadInterface;
+#include "xlibtouchpad.h"
+#include "xcbatom.h"
 
-class TouchpadEngine : public Plasma::DataEngine
+class SynapticsTouchpad : public XlibTouchpad
 {
-    Q_OBJECT
-
 public:
-    TouchpadEngine(QObject *parent, const QVariantList &args);
-    ~TouchpadEngine();
-
-    Plasma::Service *serviceForSource(const QString &source);
-
-private Q_SLOTS:
-    void mousePluggedInChanged(bool);
-    void enabledChanged(bool);
+    SynapticsTouchpad(Display *display, int deviceId);
 
 private:
-    void init();
-    QString m_source;
-    OrgKdeTouchpadInterface *m_daemon;
+    XcbAtom m_capsAtom, m_touchpadOffAtom;
+    int m_resX, m_resY;
+    QMap<QString, QString> m_negate;
+    QStringList m_scaleByResX, m_scaleByResY, m_toRadians;
 };
 
-#endif // TOUCHPADENGINE_H
+#endif // SYNAPTICSTOUCHPAD_H
diff --git a/kcms/touchpad/src/backends/x11/synclientproperties.h \
b/kcms/touchpad/src/backends/x11/synclientproperties.h deleted file mode 100644
index 43d18d2..0000000
--- a/kcms/touchpad/src/backends/x11/synclientproperties.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Copyright (C) 2013 Alexander Mezin <mezin.alexander@gmail.com>
- *
- * 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.
- */
-
-/*
-//krazy:excludeall=copyright
- * This file incorporates work covered by the following copyright and
- * permission notice:
- *
- * Copyright  © 2002-2005,2007 Peter Osterlund
- *
- * Permission to use, copy, modify, distribute, and sell this software
- * and its documentation for any purpose is hereby granted without
- * fee, provided that the above copyright notice appear in all copies
- * and that both that copyright notice and this permission notice
- * appear in supporting documentation, and that the name of Red Hat
- * not be used in advertising or publicity pertaining to distribution
- * of the software without specific, written prior permission.  Red
- * Hat makes no representations about the suitability of this software
- * for any purpose.  It is provided "as is" without express or implied
- * warranty.
- *
- * THE AUTHORS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
- * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN
- * NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
- * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
- * OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
- * NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
- * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- *
- * Authors:
- *      Peter Osterlund (petero2@telia.com)
- */
-
-#ifndef SYNCLIENTPROPERTIES_H
-#define SYNCLIENTPROPERTIES_H
-
-enum ParaType {
-    PT_INT,
-    PT_BOOL,
-    PT_DOUBLE
-};
-
-struct Parameter {
-    const char *name;           /* Name of parameter */
-    enum ParaType type;         /* Type of parameter */
-    double min_val;             /* Minimum allowed value */
-    double max_val;             /* Maximum allowed value */
-    const char *prop_name;      /* Property name */
-    int prop_format;            /* Property format (0 for floats) */
-    unsigned prop_offset;       /* Offset inside property */
-};
-
-extern const struct Parameter synapticsProperties[];
-extern const struct Parameter libinputProperties[];
-
-#endif
diff --git a/kcms/touchpad/src/backends/x11/xlibbackend.cpp \
b/kcms/touchpad/src/backends/x11/xlibbackend.cpp index b55a45f..8dedcc8 100644
--- a/kcms/touchpad/src/backends/x11/xlibbackend.cpp
+++ b/kcms/touchpad/src/backends/x11/xlibbackend.cpp
@@ -29,6 +29,9 @@
 #include "xrecordkeyboardmonitor.h" // krazy:exclude=includes
 #include "xlibbackend.h" // krazy:exclude=includes
 #include "xlibnotifications.h" // krazy:exclude=includes
+#include "libinputtouchpad.h"
+#include "synapticstouchpad.h"
+#include "propertyinfo.h"
 
 #include <X11/Xlib-xcb.h>
 #include <X11/Xatom.h>
@@ -38,300 +41,28 @@
 #include <synaptics-properties.h>
 #include <xserver-properties.h>
 
-#include "synclientproperties.h"
-
-static void XDeleter(void *p)
-{
-    if (p) {
-        XFree(p);
-    }
-}
-
-static void XIDeviceInfoDeleter(XIDeviceInfo *p)
-{
-    if (p) {
-        XIFreeDeviceInfo(p);
-    }
-}
-
-void XlibBackend::XDisplayCleanup::cleanup(Display *p)
-{
-    if (p) {
-        XCloseDisplay(p);
-    }
-}
-
-struct PropertyInfo
+struct DeviceListDeleter
 {
-    Atom type;
-    int format;
-    QSharedPointer<unsigned char> data;
-    unsigned long nitems;
-
-    float *f;
-    int *i;
-    char *b;
-
-    Display *display;
-    int device;
-    Atom prop;
-
-    PropertyInfo() :
-        type(0), format(0), nitems(0), f(0), i(0), b(0),
-        display(0), device(0), prop(0)
-    {
-    }
-
-    PropertyInfo(Display *display, int device, Atom prop, Atom floatType)
-        : type(0), format(0), nitems(0), f(0), i(0), b(0),
-          display(display), device(device), prop(prop)
-    {
-        unsigned char *dataPtr = 0;
-        unsigned long bytes_after;
-        XIGetProperty(display, device, prop, 0, 1000, False,
-                      AnyPropertyType, &type, &format, &nitems,
-                      &bytes_after, &dataPtr);
-        data = QSharedPointer<unsigned char>(dataPtr, XDeleter);
-
-        if (format == CHAR_BIT && type == XA_INTEGER) {
-            b = reinterpret_cast<char *>(dataPtr);
-        }
-        if (format == sizeof(int) * CHAR_BIT &&
-                (type == XA_INTEGER || type == XA_CARDINAL))
-        {
-            i = reinterpret_cast<int *>(dataPtr);
-        }
-        if (format == sizeof(float) * CHAR_BIT &&
-                floatType && type == floatType)
-        {
-            f = reinterpret_cast<float *>(dataPtr);
-        }
-    }
-
-    QVariant value(unsigned offset) const
+    static void cleanup(XDeviceInfo *p)
     {
-        QVariant v;
-        if (offset >= nitems) {
-            return v;
-        }
-
-        if (b) {
-            v = QVariant(static_cast<int>(b[offset]));
-        }
-        if (i) {
-            v = QVariant(i[offset]);
-        }
-        if (f) {
-            v = QVariant(f[offset]);
+        if (p) {
+            XFreeDeviceList(p);
         }
-
-        return v;
-    }
-
-    void set()
-    {
-        XIChangeProperty(display, device, prop, type, format,
-                         XIPropModeReplace, data.data(), nitems);
     }
 };
 
-class XlibSynapticsBackend : public XlibBackend
-{
-public:
-    XlibSynapticsBackend(QObject *parent = 0);
-};
-
-class XlibLibinputBackend : public XlibBackend
-{
-public:
-    XlibLibinputBackend(QObject *parent = 0);
-};
-
-XlibSynapticsBackend::XlibSynapticsBackend(QObject *parent) :
-    XlibBackend(parent)
-{
-    m_capsAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES);
-    if (!m_capsAtom.atom()) {
-        m_errorString = i18nc("Synaptics touchpad driver","Synaptics backend not \
                found");
-        return;
-    }
-
-    m_device = findTouchpad(m_capsAtom);
-    if (m_device == XIAllDevices) {
-        m_errorString = i18n("No touchpad found");
-        return;
-    }
-
-    m_touchpadOffAtom.intern(m_connection, SYNAPTICS_PROP_OFF);
-    XcbAtom resolutionAtom(m_connection, SYNAPTICS_PROP_RESOLUTION);
-    XcbAtom edgesAtom(m_connection, SYNAPTICS_PROP_EDGES);
-
-    if (!loadSupportedProperties(synapticsProperties)) {
-        m_errorString = i18n("Cannot read any of touchpad's properties");
-        return;
-    }
-
-    m_toRadians.append("CircScrollDelta");
-
-    PropertyInfo edges(m_display.data(), m_device, edgesAtom, 0);
-    if (edges.i && edges.nitems == 4) {
-        int w = qAbs(edges.i[1] - edges.i[0]);
-        int h = qAbs(edges.i[3] - edges.i[2]);
-        m_resX = w / 90;
-        m_resY = h / 50;
-        qDebug() << "Width: " << w << " height: " << h;
-        qDebug() << "Approx. resX: " << m_resX << " resY: " << m_resY;
-    }
-
-    PropertyInfo resolution(m_display.data(), m_device, resolutionAtom, 0);
-    if (resolution.i && resolution.nitems == 2 &&
-        resolution.i[0] > 1 && resolution.i[1] > 1)
-    {
-        m_resY = qMin(static_cast<unsigned long>(resolution.i[0]),
-                static_cast<unsigned long>(INT_MAX));
-        m_resX = qMin(static_cast<unsigned long>(resolution.i[1]),
-                static_cast<unsigned long>(INT_MAX));
-        qDebug() << "Touchpad resolution: x: " << m_resX << " y: " << m_resY;
-    }
-
-    m_scaleByResX.append("HorizScrollDelta");
-    m_scaleByResY.append("VertScrollDelta");
-    m_scaleByResX.append("MaxTapMove");
-    m_scaleByResY.append("MaxTapMove");
-
-    m_resX = qMax(10, m_resX);
-    m_resY = qMax(10, m_resY);
-    qDebug() << "Final resolution x:" << m_resX << " y:" << m_resY;
-    m_negate["HorizScrollDelta"] = "InvertHorizScroll";
-    m_negate["VertScrollDelta"] = "InvertVertScroll";
-    m_supported.append(m_negate.values());
-    m_supported.append("Coasting");
-
-    PropertyInfo caps(m_display.data(), m_device, m_capsAtom.atom(), 0);
-    if (!caps.b) {
-        m_errorString = i18n("Cannot read touchpad's capabilities");
-        return;
-    }
-
-    enum TouchpadCapabilitiy
-    {
-        TouchpadHasLeftButton,
-        TouchpadHasMiddleButton,
-        TouchpadHasRightButton,
-        TouchpadTwoFingerDetect,
-        TouchpadThreeFingerDetect,
-        TouchpadPressureDetect,
-        TouchpadPalmDetect,
-        TouchpadCapsCount
-    };
-
-    QVector<bool> cap(TouchpadCapsCount, false);
-    qCopy(caps.b, caps.b + qMin(cap.size(), static_cast<int>(caps.nitems)),
-          cap.begin());
-
-    if (!cap[TouchpadTwoFingerDetect]) {
-        m_supported.removeAll("HorizTwoFingerScroll");
-        m_supported.removeAll("VertTwoFingerScroll");
-        m_supported.removeAll("TwoFingerTapButton");
-    }
-
-    if (!cap[TouchpadThreeFingerDetect]) {
-        m_supported.removeAll("ThreeFingerTapButton");
-    }
-
-    if (!cap[TouchpadPressureDetect]) {
-        m_supported.removeAll("FingerHigh");
-        m_supported.removeAll("FingerLow");
-
-        m_supported.removeAll("PalmMinZ");
-        m_supported.removeAll("PressureMotionMinZ");
-        m_supported.removeAll("PressureMotionMinFactor");
-        m_supported.removeAll("PressureMotionMaxZ");
-        m_supported.removeAll("PressureMotionMaxFactor");
-        m_supported.removeAll("EmulateTwoFingerMinZ");
-    }
-
-    if (!cap[TouchpadPalmDetect]) {
-        m_supported.removeAll("PalmDetect");
-        m_supported.removeAll("PalmMinWidth");
-        m_supported.removeAll("PalmMinZ");
-        m_supported.removeAll("EmulateTwoFingerMinW");
-    }
-
-    for (QMap<QString, QString>::Iterator i = m_negate.begin();
-         i != m_negate.end(); ++i)
-    {
-        if (!m_supported.contains(i.key())) {
-            m_supported.removeAll(i.value());
-        }
-    }
-
-    m_identifierAtom.intern(m_connection, SYNAPTICS_PROP_CAPABILITIES);
-    m_paramList = synapticsProperties;
-}
-
-XlibLibinputBackend::XlibLibinputBackend(QObject *parent) :
-    XlibBackend(parent)
+void XlibBackend::XDisplayCleanup::cleanup(Display *p)
 {
-    XcbAtom identifier(m_connection,
-                       "libinput Tapping Enabled",
-                       true);
-
-    if (!identifier.atom()) {
-        m_errorString = i18nc("Libinput touchpad driver","Libinput backend not \
                found");
-        return;
-    }
-
-    m_device = findTouchpad(identifier);
-    if (m_device == XIAllDevices) {
-        m_errorString = i18n("No touchpad found");
-        return;
-    }
-
-    m_identifierAtom.intern(m_connection,
-                            "libinput Send Events Modes Available");
-
-    if (!loadSupportedProperties(libinputProperties)) {
-        m_errorString = i18n("Cannot read any of touchpad's properties");
-        return;
-    }
-
-    /* FIXME: has a different format than Synaptics Off but we don't expose
-       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");
-
-
-    XcbAtom scroll_methods(m_connection,
-                           "libinput Scroll Methods Available",
-                           true);
-    if (scroll_methods.atom() != 0) {
-        PropertyInfo methods(m_display.data(),
-                             m_device,
-                             scroll_methods.atom(),
-                             0);
-        if (!methods.value(0).toInt())
-            m_supported.removeAll("VertTwoFingerScroll");
-        else if (!methods.value(1).toInt())
-            m_supported.removeAll("VertEdgeScroll");
+    if (p) {
+        XCloseDisplay(p);
     }
-
-    m_paramList = libinputProperties;
 }
 
 XlibBackend* XlibBackend::initialize(QObject *parent)
 {
     XlibBackend* backend = nullptr;
-    QScopedPointer<Display, XDisplayCleanup> display(XOpenDisplay(0));
-    xcb_connection_t *connection = XGetXCBConnection(display.data());
-    XcbAtom synaptics_prop_capablities, libinput_prop_tapping;
-
-    backend = new XlibLibinputBackend(parent);
-    if (! backend->errorString().isNull()) {
-        delete backend;
-        backend = new XlibSynapticsBackend(parent);
-    }
+
+    backend = new XlibBackend(parent);
     return backend;
 }
 
@@ -341,8 +72,7 @@ XlibBackend::~XlibBackend()
 
 XlibBackend::XlibBackend(QObject *parent) :
     TouchpadBackend(parent),
-    m_display(XOpenDisplay(0)), m_connection(0),
-    m_resX(1), m_resY(1)
+    m_display(XOpenDisplay(0)), m_connection(0)
 {
     if (m_display) {
         m_connection = XGetXCBConnection(m_display.data());
@@ -353,297 +83,93 @@ XlibBackend::XlibBackend(QObject *parent) :
         return;
     }
 
-    m_floatType.intern(m_connection, "FLOAT");
     m_mouseAtom.intern(m_connection, XI_MOUSE);
     m_keyboardAtom.intern(m_connection, XI_KEYBOARD);
+    m_touchpadAtom.intern(m_connection, XI_TOUCHPAD);
     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_device.reset(findTouchpad());
+    if (!m_device) {
+        m_errorString = ("No touchpad found");
+    }
 }
 
-int XlibBackend::findTouchpad(XcbAtom &identifier)
+XlibTouchpad* XlibBackend::findTouchpad()
 {
     int nDevices = 0;
-    QSharedPointer<XIDeviceInfo> deviceInfo(
-                XIQueryDevice(m_display.data(), XIAllDevices, &nDevices),
-                XIDeviceInfoDeleter);
+    QScopedPointer<XDeviceInfo, DeviceListDeleter>
+            deviceInfo(XListInputDevices(m_display.data(), &nDevices));
 
-    for (XIDeviceInfo *info = deviceInfo.data();
+    for (XDeviceInfo *info = deviceInfo.data();
          info < deviceInfo.data() + nDevices; info++)
     {
+        // Make sure device is touchpad
+        if (info->type != m_touchpadAtom.atom()) {
+            continue;
+        }
         int nProperties = 0;
         QSharedPointer<Atom> properties(
-                    XIListProperties(m_display.data(), info->deviceid,
+                    XIListProperties(m_display.data(), info->id,
                                      &nProperties), XDeleter);
 
-        if (std::count(properties.data(), properties.data() + nProperties,
-                       identifier.atom()))
-        {
-            return info->deviceid;
-        }
-    }
-
-    return XIAllDevices;
-}
-
-const Parameter * XlibBackend::findParameter(const QString &name)
-{
-    for (const Parameter *par = m_paramList; par->name; par++) {
-        if (name == par->name) {
-            return par;
-        }
-    }
-    return 0;
-}
-
-bool XlibBackend::loadSupportedProperties(const Parameter *props)
-{
-    for (const Parameter *param = props; param->name; param++) {
-        QLatin1String name(param->prop_name);
-
-        if (!m_atoms.contains(name)) {
-            m_atoms.insert(name, QSharedPointer<XcbAtom>(
-                               new XcbAtom(m_connection, param->prop_name)));
-        }
-    }
-
-    for (const Parameter *p = props; p->name; p++) {
-        if (getParameter(p).isValid()) {
-            m_supported.append(p->name);
+        Atom *atom = properties.data(), *atomEnd = properties.data() + nProperties;
+        for (; atom != atomEnd; atom++) {
+            if (*atom == m_libinputIdentifierAtom.atom()) {
+                return new LibinputTouchpad(m_display.data(), info->id);
+            } else if (*atom == m_synapticsIdentifierAtom.atom()) {
+                return new SynapticsTouchpad(m_display.data(), info->id);
+            }
         }
     }
 
-    return !m_supported.isEmpty();
-}
-
-double XlibBackend::getPropertyScale(const QString &name) const
-{
-    if (m_scaleByResX.contains(name) && m_scaleByResY.contains(name)) {
-        return std::sqrt(static_cast<double>(m_resX) * m_resX
-                         + static_cast<double>(m_resY) * m_resY);
-    } else if (m_scaleByResX.contains(name)) {
-        return m_resX;
-    } else if (m_scaleByResY.contains(name)) {
-        return m_resY;
-    } else if (m_toRadians.contains(name)) {
-        return M_PI_4 / 45.0;
-    }
-    return 1.0;
-}
-
-static QVariant negateVariant(const QVariant &value)
-{
-    if (value.type() == QVariant::Double) {
-        return QVariant(-value.toDouble());
-    } else if (value.type() == QVariant::Int) {
-        return QVariant(-value.toInt());
-    }
-    return value;
+    return nullptr;
 }
 
 bool XlibBackend::applyConfig(const QVariantHash &p)
 {
-    if (m_supported.isEmpty()) {
+    if (!m_device) {
         return false;
     }
 
-    m_props.clear();
-
-    bool error = false;
-    Q_FOREACH(const QString &name, m_supported) {
-        QVariantHash::ConstIterator i = p.find(name);
-        if (i == p.end()) {
-            continue;
-        }
-        const Parameter *par = findParameter(name);
-        if (par) {
-            QVariant value(i.value());
-
-            double k = getPropertyScale(name);
-            if (k != 1.0) {
-                bool ok = false;
-                value = QVariant(value.toDouble(&ok) * k);
-                if (!ok) {
-                    error = true;
-                    continue;
-                }
-            }
-
-            if (m_negate.contains(name)) {
-                QVariantHash::ConstIterator i = p.find(m_negate[name]);
-                if (i != p.end() && i.value().toBool()) {
-                    value = negateVariant(value);
-                }
-            }
-
-            if (name == "CoastingSpeed") {
-                QVariantHash::ConstIterator coastingEnabled = p.find("Coasting");
-                if (coastingEnabled != p.end() &&
-                        !coastingEnabled.value().toBool())
-                {
-                    value = QVariant(0);
-                }
-            }
-
-            if (!setParameter(par, value)) {
-                error = true;
-            }
-        }
-    }
-
-    flush();
-
-    if (error) {
+    bool success = m_device->applyConfig(p);
+    if (!success) {
         m_errorString = i18n("Cannot apply touchpad configuration");
     }
-    return !error;
-}
-
-void XlibBackend::flush()
-{
-    Q_FOREACH(const QLatin1String &name, m_changed) {
-        m_props[name].set();
-    }
-    m_changed.clear();
 
-    XFlush(m_display.data());
+    return success;
 }
 
 bool XlibBackend::getConfig(QVariantHash &p)
 {
-    if (m_supported.isEmpty()) {
+    if (!m_device) {
         return false;
     }
 
-    m_props.clear();
-
-    bool error = false;
-    Q_FOREACH(const QString &name, m_supported) {
-        const Parameter *par = findParameter(name);
-        if (!par) {
-            continue;
-        }
-
-        QVariant value(getParameter(par));
-        if (!value.isValid()) {
-            error = true;
-            continue;
-        }
-
-        double k = getPropertyScale(name);
-        if (k != 1.0) {
-            bool ok = false;
-            value = QVariant(value.toDouble(&ok) / k);
-            if (!ok) {
-                error = true;
-                continue;
-            }
-        }
-
-        if (m_negate.contains(name)) {
-            bool negative = value.toDouble() < 0.0;
-            p[m_negate[name]] = QVariant(negative);
-            if (negative) {
-                value = negateVariant(value);
-            }
-        }
-
-        if (name == "CoastingSpeed") {
-            bool coasting = value.toDouble() != 0.0;
-            p["Coasting"] = QVariant(coasting);
-            if (!coasting) {
-                continue;
-            }
-        }
-
-        p[name] = value;
-    }
-
-    if (error) {
+    bool success = m_device->getConfig(p);
+    if (!success) {
         m_errorString = i18n("Cannot read touchpad configuration");
     }
-    return !error;
-}
-
-QVariant XlibBackend::getParameter(const Parameter *par)
-{
-    PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name));
-    if (!p || par->prop_offset >= p->nitems) {
-        return QVariant();
-    }
-
-    return p->value(par->prop_offset);
-}
-
-PropertyInfo *XlibBackend::getDevProperty(const QLatin1String &propName)
-{
-    if (m_props.contains(propName)) {
-        return &m_props[propName];
-    }
-
-    if (!m_atoms.contains(propName) || !m_atoms[propName]) {
-        return 0;
-    }
-
-    xcb_atom_t prop = m_atoms[propName]->atom();
-    if (!prop) {
-        return 0;
-    }
-
-    PropertyInfo p(m_display.data(), m_device, prop, m_floatType.atom());
-    if (!p.b && !p.f && !p.i) {
-        return 0;
-    }
-    return &m_props.insert(propName, p).value();
-}
-
-bool XlibBackend::setParameter(const Parameter *par, const QVariant &value)
-{
-    QLatin1String propName(par->prop_name);
-    PropertyInfo *p = getDevProperty(propName);
-    if (!p || par->prop_offset >= p->nitems) {
-        return false;
-    }
-
-    QVariant converted(value);
-    QVariant::Type convType = QVariant::Int;
-    if (p->f) {
-        convType = QVariant::Double;
-    } else if (value.type() == QVariant::Double) {
-        converted = QVariant(qRound(static_cast<qreal>(value.toDouble())));
-    }
-
-    if (!converted.convert(convType)) {
-        return false;
-    }
-
-    if (converted == p->value(par->prop_offset)) {
-        return true;
-    }
-
-    if (p->b) {
-        p->b[par->prop_offset] = static_cast<char>(converted.toInt());
-    } else if (p->i) {
-        p->i[par->prop_offset] = converted.toInt();
-    } else if (p->f) {
-        p->f[par->prop_offset] = converted.toDouble();
-    }
-
-    m_changed.insert(propName);
-    return true;
+    return success;
 }
 
 void XlibBackend::setTouchpadEnabled(bool enable)
 {
-    PropertyInfo enabled(m_display.data(), m_device, m_enabledAtom.atom(), 0);
-    if (enabled.b && *(enabled.b) != enable) {
-        *(enabled.b) = enable;
-        enabled.set();
+    if (!m_device) {
+        return;
     }
 
-    flush();
+    m_device->setEnabled(enable);
 }
 
 void XlibBackend::setTouchpadOff(TouchpadBackend::TouchpadOffState state)
 {
+    if (!m_device) {
+        return;
+    }
+
     int touchpadOff = 0;
     switch (state) {
     case TouchpadEnabled:
@@ -660,25 +186,30 @@ void \
XlibBackend::setTouchpadOff(TouchpadBackend::TouchpadOffState state)  return;
     }
 
-    PropertyInfo off(m_display.data(), m_device, m_touchpadOffAtom.atom(), 0);
-    if (off.b && *(off.b) != touchpadOff) {
-        *(off.b) = touchpadOff;
-        off.set();
-    }
+    m_device->setTouchpadOff(touchpadOff);
+}
 
-    flush();
+bool XlibBackend::isTouchpadAvailable()
+{
+    return m_device;
 }
 
 bool XlibBackend::isTouchpadEnabled()
 {
-    PropertyInfo enabled(m_display.data(), m_device, m_enabledAtom.atom(), 0);
-    return enabled.value(0).toBool();
+    if (!m_device) {
+        return false;
+    }
+
+    return m_device->enabled();
 }
 
 TouchpadBackend::TouchpadOffState XlibBackend::getTouchpadOff()
 {
-    PropertyInfo off(m_display.data(), m_device, m_touchpadOffAtom.atom(), 0);
-    switch (off.value(0).toInt()) {
+    if (!m_device) {
+        return TouchpadFullyDisabled;
+    }
+    int value = m_device->touchpadOff();
+    switch (value) {
     case 0:
         return TouchpadEnabled;
     case 1:
@@ -686,7 +217,7 @@ TouchpadBackend::TouchpadOffState XlibBackend::getTouchpadOff()
     case 2:
         return TouchpadTapAndScrollDisabled;
     default:
-        qCritical() << "Unknown TouchpadOff value" << off.value(0).toInt();
+        qCritical() << "Unknown TouchpadOff value" << value;
         return TouchpadFullyDisabled;
     }
 }
@@ -694,44 +225,35 @@ TouchpadBackend::TouchpadOffState XlibBackend::getTouchpadOff()
 void XlibBackend::touchpadDetached()
 {
     qWarning() << "Touchpad detached";
-    m_device = XIAllDevices;
+    m_device.reset();
+    Q_EMIT touchpadReset();
 }
 
 void XlibBackend::devicePlugged(int device)
 {
-    if (m_device == XIAllDevices) {
-        m_device = findTouchpad(m_identifierAtom);
-        if (m_device != XIAllDevices) {
+    if (!m_device) {
+        m_device.reset(findTouchpad());
+        if (m_device) {
             qWarning() << "Touchpad reset";
             m_notifications.reset();
             watchForEvents(m_keyboard);
             Q_EMIT touchpadReset();
         }
     }
-    if (device != m_device) {
+    if (!m_device || device != m_device->deviceId()) {
         Q_EMIT mousesChanged();
     }
 }
 
 void XlibBackend::propertyChanged(xcb_atom_t prop)
 {
-    if (prop == m_touchpadOffAtom.atom() ||
+    if ((m_device && prop == m_device->touchpadOffAtom().atom()) ||
             prop == m_enabledAtom.atom())
     {
         Q_EMIT touchpadStateChanged();
     }
 }
 
-struct DeviceListDeleter
-{
-    static void cleanup(XDeviceInfo *p)
-    {
-        if (p) {
-            XFreeDeviceList(p);
-        }
-    }
-};
-
 QStringList XlibBackend::listMouses(const QStringList &blacklist)
 {
     int nDevices = 0;
@@ -739,7 +261,7 @@ QStringList XlibBackend::listMouses(const QStringList &blacklist)
             info(XListInputDevices(m_display.data(), &nDevices));
     QStringList list;
     for (XDeviceInfo *i = info.data(); i != info.data() + nDevices; i++) {
-        if (i->id == static_cast<XID>(m_device)) {
+        if (m_device && i->id == static_cast<XID>(m_device->deviceId())) {
             continue;
         }
         if (i->use != IsXExtensionPointer && i->use != IsXPointer) {
@@ -767,7 +289,7 @@ QStringList XlibBackend::listMouses(const QStringList &blacklist)
 void XlibBackend::watchForEvents(bool keyboard)
 {
     if (!m_notifications) {
-        m_notifications.reset(new XlibNotifications(m_display.data(), m_device));
+        m_notifications.reset(new XlibNotifications(m_display.data(), m_device ? \
m_device->deviceId() : XIAllDevices));  connect(m_notifications.data(), \
SIGNAL(devicePlugged(int)),  SLOT(devicePlugged(int)));
         connect(m_notifications.data(), SIGNAL(touchpadDetached()),
diff --git a/kcms/touchpad/src/backends/x11/xlibbackend.h \
b/kcms/touchpad/src/backends/x11/xlibbackend.h index 7cecb4a..4aa006e 100644
--- a/kcms/touchpad/src/backends/x11/xlibbackend.h
+++ b/kcms/touchpad/src/backends/x11/xlibbackend.h
@@ -28,12 +28,14 @@
 #include <QX11Info>
 
 #include "touchpadbackend.h"
-#include "synclientproperties.h"
+#include "xlibtouchpad.h"
 
 #include <xcb/xcb.h>
 
 #include "xcbatom.h"
+#include "propertyinfo.h"
 
+class XlibTouchpad;
 class XlibNotifications;
 class XRecordKeyboardMonitor;
 
@@ -45,20 +47,23 @@ public:
     static XlibBackend* initialize(QObject *parent = 0);
     ~XlibBackend();
 
-    bool applyConfig(const QVariantHash &);
-    bool getConfig(QVariantHash &);
-    const QStringList &supportedParameters() const { return m_supported; }
+    bool applyConfig(const QVariantHash &) Q_DECL_OVERRIDE;
+    bool getConfig(QVariantHash &) Q_DECL_OVERRIDE;
+    QStringList supportedParameters() const Q_DECL_OVERRIDE {
+        return m_device ? m_device->supportedParameters() : QStringList();
+    }
     const QString &errorString() const { return m_errorString; }
 
-    void setTouchpadOff(TouchpadOffState);
-    TouchpadOffState getTouchpadOff();
+    void setTouchpadOff(TouchpadOffState) Q_DECL_OVERRIDE;
+    TouchpadOffState getTouchpadOff() Q_DECL_OVERRIDE;
 
-    void setTouchpadEnabled(bool);
-    bool isTouchpadEnabled();
+    bool isTouchpadAvailable() Q_DECL_OVERRIDE;
+    bool isTouchpadEnabled() Q_DECL_OVERRIDE;
+    void setTouchpadEnabled(bool) Q_DECL_OVERRIDE;
 
-    void watchForEvents(bool keyboard);
+    void watchForEvents(bool keyboard) Q_DECL_OVERRIDE;
 
-    QStringList listMouses(const QStringList &blacklist);
+    QStringList listMouses(const QStringList &blacklist) Q_DECL_OVERRIDE;
 
 private slots:
     void propertyChanged(xcb_atom_t);
@@ -67,11 +72,6 @@ private slots:
 
 protected:
     explicit XlibBackend(QObject *parent);
-    struct PropertyInfo *getDevProperty(const QLatin1String &propName);
-    bool setParameter(const struct Parameter *, const QVariant &);
-    QVariant getParameter(const struct Parameter *);
-    void flush();
-    double getPropertyScale(const QString &name) const;
 
     struct XDisplayCleanup {
         static void cleanup(Display *);
@@ -80,24 +80,14 @@ protected:
     QScopedPointer<Display, XDisplayCleanup> m_display;
     xcb_connection_t *m_connection;
 
-    XcbAtom m_floatType, m_capsAtom, m_identifierAtom, m_enabledAtom, \
                m_touchpadOffAtom,
-    m_mouseAtom, m_keyboardAtom;
+    XcbAtom m_enabledAtom, m_mouseAtom, m_keyboardAtom, m_touchpadAtom;
+    XcbAtom m_synapticsIdentifierAtom;
+    XcbAtom m_libinputIdentifierAtom;
 
-    int findTouchpad(XcbAtom &identifier);
-    int m_device;
+    XlibTouchpad *findTouchpad();
+    QScopedPointer<XlibTouchpad> m_device;
 
-    const struct Parameter *m_paramList;
-    const Parameter *findParameter(const QString &name);
-    bool loadSupportedProperties(const struct Parameter *props);
-
-    QMap<QLatin1String, QSharedPointer<XcbAtom> > m_atoms;
-    QMap<QLatin1String, struct PropertyInfo> m_props;
-    QSet<QLatin1String> m_changed;
-    QStringList m_supported;
     QString m_errorString;
-    int m_resX, m_resY;
-    QStringList m_scaleByResX, m_scaleByResY, m_toRadians;
-    QMap<QString, QString> m_negate;
     QScopedPointer<XlibNotifications> m_notifications;
     QScopedPointer<XRecordKeyboardMonitor> m_keyboard;
 };
diff --git a/kcms/touchpad/src/backends/x11/xlibtouchpad.cpp \
b/kcms/touchpad/src/backends/x11/xlibtouchpad.cpp new file mode 100644
index 0000000..e380d93
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/xlibtouchpad.cpp
@@ -0,0 +1,292 @@
+#include "xlibtouchpad.h"
+#include <X11/Xlib-xcb.h>
+#include <X11/extensions/XInput.h>
+#include <X11/extensions/XInput2.h>
+#include <xserver-properties.h>
+
+static QVariant negateVariant(const QVariant &value)
+{
+    if (value.type() == QVariant::Double) {
+        return QVariant(-value.toDouble());
+    } else if (value.type() == QVariant::Int) {
+        return QVariant(-value.toInt());
+    }
+    return value;
+}
+
+XlibTouchpad::XlibTouchpad(Display *display, int deviceId) :
+    m_display(display),
+    m_connection(XGetXCBConnection(display)),
+    m_deviceId(deviceId)
+{
+    m_floatType.intern(m_connection, "FLOAT");
+    m_enabledAtom.intern(m_connection, XI_PROP_ENABLED);
+}
+
+bool XlibTouchpad::applyConfig(const QVariantHash& p)
+{
+    m_props.clear();
+
+    bool error = false;
+    Q_FOREACH(const QString &name, m_supported) {
+        QVariantHash::ConstIterator i = p.find(name);
+        if (i == p.end()) {
+            continue;
+        }
+        const Parameter *par = findParameter(name);
+        if (par) {
+            QVariant value(i.value());
+
+            double k = getPropertyScale(name);
+            if (k != 1.0) {
+                bool ok = false;
+                value = QVariant(value.toDouble(&ok) * k);
+                if (!ok) {
+                    error = true;
+                    continue;
+                }
+            }
+
+            if (m_negate.contains(name)) {
+                QVariantHash::ConstIterator i = p.find(m_negate[name]);
+                if (i != p.end() && i.value().toBool()) {
+                    value = negateVariant(value);
+                }
+            }
+
+            if (name == "CoastingSpeed") {
+                QVariantHash::ConstIterator coastingEnabled = p.find("Coasting");
+                if (coastingEnabled != p.end() &&
+                        !coastingEnabled.value().toBool())
+                {
+                    value = QVariant(0);
+                }
+            }
+
+            if (!setParameter(par, value)) {
+                error = true;
+            }
+        }
+    }
+
+    flush();
+
+    return !error;
+}
+
+bool XlibTouchpad::getConfig(QVariantHash& p)
+{
+    if (m_supported.isEmpty()) {
+        return false;
+    }
+
+    m_props.clear();
+
+    bool error = false;
+    Q_FOREACH(const QString &name, m_supported) {
+        const Parameter *par = findParameter(name);
+        if (!par) {
+            continue;
+        }
+
+        QVariant value(getParameter(par));
+        if (!value.isValid()) {
+            error = true;
+            continue;
+        }
+
+        double k = getPropertyScale(name);
+        if (k != 1.0) {
+            bool ok = false;
+            value = QVariant(value.toDouble(&ok) / k);
+            if (!ok) {
+                error = true;
+                continue;
+            }
+        }
+
+        if (m_negate.contains(name)) {
+            bool negative = value.toDouble() < 0.0;
+            p[m_negate[name]] = QVariant(negative);
+            if (negative) {
+                value = negateVariant(value);
+            }
+        }
+
+        if (name == "CoastingSpeed") {
+            bool coasting = value.toDouble() != 0.0;
+            p["Coasting"] = QVariant(coasting);
+            if (!coasting) {
+                continue;
+            }
+        }
+
+        p[name] = value;
+    }
+
+    return !error;
+}
+
+void XlibTouchpad::loadSupportedProperties(const Parameter* props)
+{
+    m_paramList = props;
+    for (const Parameter *param = props; param->name; param++) {
+        QLatin1String name(param->prop_name);
+
+        if (!m_atoms.contains(name)) {
+            m_atoms.insert(name, QSharedPointer<XcbAtom>(
+                            new XcbAtom(m_connection, param->prop_name)));
+        }
+    }
+
+    for (const Parameter *p = props; p->name; p++) {
+        if (getParameter(p).isValid()) {
+            m_supported.append(p->name);
+        }
+    }
+}
+
+QVariant XlibTouchpad::getParameter(const Parameter* par)
+{
+    PropertyInfo *p = getDevProperty(QLatin1String(par->prop_name));
+    if (!p || par->prop_offset >= p->nitems) {
+        return QVariant();
+    }
+
+    return p->value(par->prop_offset);
+}
+
+
+void XlibTouchpad::flush()
+{
+    Q_FOREACH(const QLatin1String &name, m_changed) {
+        m_props[name].set();
+    }
+    m_changed.clear();
+
+    XFlush(m_display);
+}
+
+double XlibTouchpad::getPropertyScale(const QString& name) const
+{
+    if (m_scaleByResX.contains(name) && m_scaleByResY.contains(name)) {
+        return std::sqrt(static_cast<double>(m_resX) * m_resX
+                         + static_cast<double>(m_resY) * m_resY);
+    } else if (m_scaleByResX.contains(name)) {
+        return m_resX;
+    } else if (m_scaleByResY.contains(name)) {
+        return m_resY;
+    } else if (m_toRadians.contains(name)) {
+        return M_PI_4 / 45.0;
+    }
+    return 1.0;
+}
+
+PropertyInfo* XlibTouchpad::getDevProperty(const QLatin1String& propName)
+{
+    if (m_props.contains(propName)) {
+        return &m_props[propName];
+    }
+
+    if (!m_atoms.contains(propName) || !m_atoms[propName]) {
+        return 0;
+    }
+
+    xcb_atom_t prop = m_atoms[propName]->atom();
+    if (!prop) {
+        return 0;
+    }
+
+    PropertyInfo p(m_display, m_deviceId, prop, m_floatType.atom());
+    if (!p.b && !p.f && !p.i) {
+        return 0;
+    }
+    return &m_props.insert(propName, p).value();
+}
+
+bool XlibTouchpad::setParameter(const Parameter *par, const QVariant &value)
+{
+    QLatin1String propName(par->prop_name);
+    PropertyInfo *p = getDevProperty(propName);
+    if (!p || par->prop_offset >= p->nitems) {
+        return false;
+    }
+
+    QVariant converted(value);
+    QVariant::Type convType = QVariant::Int;
+    if (p->f) {
+        convType = QVariant::Double;
+    } else if (value.type() == QVariant::Double) {
+        converted = QVariant(qRound(static_cast<qreal>(value.toDouble())));
+    }
+
+    if (!converted.convert(convType)) {
+        return false;
+    }
+
+    if (converted == p->value(par->prop_offset)) {
+        return true;
+    }
+
+    if (p->b) {
+        p->b[par->prop_offset] = static_cast<char>(converted.toInt());
+    } else if (p->i) {
+        p->i[par->prop_offset] = converted.toInt();
+    } else if (p->f) {
+        p->f[par->prop_offset] = converted.toDouble();
+    }
+
+    m_changed.insert(propName);
+    return true;
+}
+
+
+void XlibTouchpad::setEnabled(bool enable)
+{
+    PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0);
+    if (enabled.b && *(enabled.b) != enable) {
+        *(enabled.b) = enable;
+        enabled.set();
+    }
+
+    flush();
+}
+
+bool XlibTouchpad::enabled()
+{
+    PropertyInfo enabled(m_display, m_deviceId, m_enabledAtom.atom(), 0);
+    return enabled.value(0).toBool();
+}
+
+
+void XlibTouchpad::setTouchpadOff(int touchpadOff)
+{
+    PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0);
+    if (off.b && *(off.b) != touchpadOff) {
+        *(off.b) = touchpadOff;
+        off.set();
+    }
+
+    flush();
+}
+
+int XlibTouchpad::touchpadOff()
+{
+    PropertyInfo off(m_display, m_deviceId, m_touchpadOffAtom.atom(), 0);
+    return  off.value(0).toInt();
+}
+
+XcbAtom& XlibTouchpad::touchpadOffAtom()
+{
+    return m_touchpadOffAtom;
+}
+
+const Parameter* XlibTouchpad::findParameter(const QString& name)
+{
+    for (const Parameter *par = m_paramList; par->name; par++) {
+        if (name == par->name) {
+            return par;
+        }
+    }
+    return 0;
+}
diff --git a/kcms/touchpad/src/backends/x11/xlibtouchpad.h \
b/kcms/touchpad/src/backends/x11/xlibtouchpad.h new file mode 100644
index 0000000..0eb58fb
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/xlibtouchpad.h
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 Weng Xuetian <wengxt@gmail.com>
+ *
+ * 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 XLIBTOUCHPAD_H
+#define XLIBTOUCHPAD_H
+
+#include <QVariantHash>
+#include <QSet>
+
+#include <xcb/xcb.h>
+#include "xcbatom.h"
+#include "propertyinfo.h"
+
+enum ParaType {
+    PT_INT,
+    PT_BOOL,
+    PT_DOUBLE
+};
+
+struct Parameter {
+    const char *name;           /* Name of parameter */
+    enum ParaType type;         /* Type of parameter */
+    double min_val;             /* Minimum allowed value */
+    double max_val;             /* Maximum allowed value */
+    const char *prop_name;      /* Property name */
+    int prop_format;            /* Property format (0 for floats) */
+    unsigned prop_offset;       /* Offset inside property */
+};
+
+class XlibTouchpad
+{
+public:
+    XlibTouchpad(Display *display, int deviceId);
+
+    int deviceId() { return m_deviceId; }
+    const QStringList &supportedParameters() const { return m_supported; }
+    bool applyConfig(const QVariantHash &p);
+    bool getConfig(QVariantHash &p);
+    void setEnabled(bool enable);
+    bool enabled();
+    void setTouchpadOff(int touchpadOff);
+    int touchpadOff();
+
+    XcbAtom &touchpadOffAtom();
+
+protected:
+    void loadSupportedProperties(const Parameter *props);
+    bool setParameter(const struct Parameter *, const QVariant &);
+    QVariant getParameter(const struct Parameter *);
+    struct PropertyInfo *getDevProperty(const QLatin1String &propName);
+    void flush();
+    double getPropertyScale(const QString &name) const;
+    const Parameter * findParameter(const QString &name);
+
+    Display *m_display;
+    xcb_connection_t *m_connection;
+    int m_deviceId;
+
+    XcbAtom m_floatType, m_enabledAtom, m_touchpadOffAtom;
+
+    QMap<QLatin1String, QSharedPointer<XcbAtom> > m_atoms;
+
+    int m_resX, m_resY;
+    QStringList m_scaleByResX, m_scaleByResY, m_toRadians;
+    QMap<QString, QString> m_negate;
+
+    QMap<QLatin1String, struct PropertyInfo> m_props;
+    QSet<QLatin1String> m_changed;
+    QStringList m_supported;
+    const struct Parameter *m_paramList;
+};
+
+#endif
diff --git a/kcms/touchpad/src/kded/kded.cpp b/kcms/touchpad/src/kded/kded.cpp
index 409126b..45aaf2f 100644
--- a/kcms/touchpad/src/kded/kded.cpp
+++ b/kcms/touchpad/src/kded/kded.cpp
@@ -18,6 +18,7 @@
 
 #include "kded.h"
 
+#include <QDebug>
 #include <KNotification>
 #include <KLocalizedString>
 
@@ -26,7 +27,7 @@
 
 bool TouchpadDisabler::workingTouchpadFound() const
 {
-    return m_backend && !(m_backend->supportedParameters().isEmpty());
+    return m_workingTouchpadFound;
 }
 
 void TouchpadDisabler::serviceRegistered(const QString &service)
@@ -42,11 +43,11 @@ void TouchpadDisabler::serviceRegistered(const QString &service)
 
 TouchpadDisabler::TouchpadDisabler(QObject *parent, const QVariantList &)
     : KDEDModule(parent), m_backend(TouchpadBackend::implementation()),
-      m_enabled(true), m_keyboardActivity(false), m_mouse(false)
+      m_userRequestedState(true), m_touchpadEnabled(true), \
m_workingTouchpadFound(false), m_keyboardActivity(false), m_mouse(false)  {
     KLocalizedString::setApplicationDomain("kcm_touchpad");
 
-    if (!workingTouchpadFound()) {
+    if (!m_backend) {
         return;
     }
 
@@ -70,6 +71,7 @@ TouchpadDisabler::TouchpadDisabler(QObject *parent, const \
QVariantList &)  SLOT(timerElapsed()));
 
     updateCurrentState();
+    m_userRequestedState = m_touchpadEnabled;
     reloadSettings();
 
     m_dependecies.setWatchMode(QDBusServiceWatcher::WatchForRegistration);
@@ -100,30 +102,37 @@ void \
TouchpadDisabler::serviceNameFetchFinished(QDBusPendingCallWatcher *callWat  
 bool TouchpadDisabler::isEnabled() const
 {
-    return m_enabled;
+    return m_touchpadEnabled;
 }
 
 void TouchpadDisabler::updateCurrentState()
 {
+    updateWorkingTouchpadFound();
+    if (!m_backend->isTouchpadAvailable()) {
+        return;
+    }
     bool newEnabled = m_backend->isTouchpadEnabled();
-    if (newEnabled != m_enabled) {
-        m_enabled = newEnabled;
-        Q_EMIT enabledChanged(m_enabled);
+    if (newEnabled != m_touchpadEnabled) {
+        m_touchpadEnabled = newEnabled;
+        Q_EMIT enabledChanged(m_touchpadEnabled);
     }
 }
 
 void TouchpadDisabler::toggle()
 {
-    m_backend->setTouchpadEnabled(!isEnabled());
+    m_userRequestedState = !m_touchpadEnabled;
+    m_backend->setTouchpadEnabled(m_userRequestedState);
 }
 
 void TouchpadDisabler::disable()
 {
+    m_userRequestedState = false;
     m_backend->setTouchpadEnabled(false);
 }
 
 void TouchpadDisabler::enable()
 {
+    m_userRequestedState = true;
     m_backend->setTouchpadEnabled(true);
 }
 
@@ -187,19 +196,23 @@ void TouchpadDisabler::mousePlugged()
     }
     m_mouse = disable;
 
-    if (m_enabled == !disable) {
+    bool newState = disable ? false : m_userRequestedState;
+    if (newState == m_touchpadEnabled) {
         return;
     }
 
-    if (disable) {
+    // If the disable is caused by plugin mouse, show the message, otherwise it \
might +    // be user already disables touchpad themselves.
+    if (!newState && disable) {
         showNotification("TouchpadDisabled",
                          i18n("Touchpad was disabled because a mouse was plugged \
                in"));
-    } else {
+    }
+    if (newState) {
         showNotification("TouchpadEnabled",
                          i18n("Touchpad was enabled because the mouse was \
unplugged"));  }
 
-    m_backend->setTouchpadEnabled(!disable);
+    m_backend->setTouchpadEnabled(newState);
 }
 
 void TouchpadDisabler::showNotification(const QString &name, const QString &text)
@@ -231,6 +244,19 @@ void touchpadApplySavedConfig();
 
 void TouchpadDisabler::handleReset()
 {
-    m_backend->setTouchpadEnabled(m_enabled);
+    updateWorkingTouchpadFound();
+    if (!m_workingTouchpadFound) {
+        return;
+    }
     touchpadApplySavedConfig();
+    m_backend->setTouchpadEnabled(m_userRequestedState);
+}
+
+void TouchpadDisabler::updateWorkingTouchpadFound()
+{
+    bool newWorkingTouchpadFound = m_backend && m_backend->isTouchpadAvailable();
+    if (newWorkingTouchpadFound != m_workingTouchpadFound) {
+        m_workingTouchpadFound = newWorkingTouchpadFound;
+        Q_EMIT workingTouchpadFoundChanged(m_workingTouchpadFound);
+    }
 }
diff --git a/kcms/touchpad/src/kded/kded.h b/kcms/touchpad/src/kded/kded.h
index 9b8fe6e..c1aab4f 100644
--- a/kcms/touchpad/src/kded/kded.h
+++ b/kcms/touchpad/src/kded/kded.h
@@ -39,6 +39,7 @@ public:
 Q_SIGNALS:
     Q_SCRIPTABLE void enabledChanged(bool);
     Q_SCRIPTABLE void mousePluggedInChanged(bool);
+    Q_SCRIPTABLE void workingTouchpadFoundChanged(bool);
 
 public Q_SLOTS:
     Q_SCRIPTABLE Q_NOREPLY void reloadSettings();
@@ -62,6 +63,7 @@ private Q_SLOTS:
 private:
     void showNotification(const QString &name, const QString &text);
     void lateInit();
+    void updateWorkingTouchpadFound();
 
     TouchpadBackend *m_backend;
     TouchpadDisablerSettings m_settings;
@@ -69,7 +71,9 @@ private:
     QDBusServiceWatcher m_dependecies;
 
     TouchpadBackend::TouchpadOffState m_keyboardDisableState;
-    bool m_enabled, m_keyboardActivity, m_mouse;
+    bool m_userRequestedState, m_touchpadEnabled;
+    bool m_workingTouchpadFound;
+    bool m_keyboardActivity, m_mouse;
 };
 
 #endif // KDED_H
diff --git a/kcms/touchpad/src/touchpadbackend.h \
b/kcms/touchpad/src/touchpadbackend.h index b225ed9..2f8093f 100644
--- a/kcms/touchpad/src/touchpadbackend.h
+++ b/kcms/touchpad/src/touchpadbackend.h
@@ -37,7 +37,7 @@ public:
 
     virtual bool applyConfig(const QVariantHash &) = 0;
     virtual bool getConfig(QVariantHash &) = 0;
-    virtual const QStringList &supportedParameters() const = 0;
+    virtual QStringList supportedParameters() const = 0;
     virtual const QString &errorString() const = 0;
 
     enum TouchpadOffState {
@@ -46,6 +46,7 @@ public:
     virtual void setTouchpadOff(TouchpadOffState) = 0;
     virtual TouchpadOffState getTouchpadOff() = 0;
 
+    virtual bool isTouchpadAvailable() = 0;
     virtual bool isTouchpadEnabled() = 0;
     virtual void setTouchpadEnabled(bool) = 0;
 


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic