File 0001-Refactor-kcm-touchpad-to-fix-some-issue-related-to-h.patch of Package plasma5-desktop

From 02c725d148a956b87d19da3db427640b76f302d9 Mon Sep 17 00:00:00 2001
From: Weng Xuetian <wengxt@gmail.com>
Date: Tue, 29 Dec 2015 18:19:26 -0800
Subject: [PATCH 1/3] 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
(cherry picked from commit a39677c1fd1e6303ddaf31da5ccd0a6454104066)
---
 .../src/applet/qml/contents/ui/touchpad.qml        |   4 +-
 kcms/touchpad/src/applet/touchpadengine.cpp        |  13 +-
 kcms/touchpad/src/applet/touchpadengine.h          |   1 +
 kcms/touchpad/src/backends/x11.cmake               |   8 +-
 .../touchpad/src/backends/x11/libinputproperties.c |  35 --
 .../touchpad/src/backends/x11/libinputtouchpad.cpp |  61 ++
 kcms/touchpad/src/backends/x11/libinputtouchpad.h  |  30 +
 kcms/touchpad/src/backends/x11/propertyinfo.cpp    |  90 +++
 kcms/touchpad/src/backends/x11/propertyinfo.h      |  50 ++
 .../src/backends/x11/synapticstouchpad.cpp         | 235 ++++++++
 kcms/touchpad/src/backends/x11/synapticstouchpad.h |  37 ++
 .../src/backends/x11/synclientproperties.c         | 126 ----
 .../src/backends/x11/synclientproperties.h         |  71 ---
 kcms/touchpad/src/backends/x11/xlibbackend.cpp     | 636 +++------------------
 kcms/touchpad/src/backends/x11/xlibbackend.h       |  50 +-
 kcms/touchpad/src/backends/x11/xlibtouchpad.cpp    | 292 ++++++++++
 kcms/touchpad/src/backends/x11/xlibtouchpad.h      |  88 +++
 kcms/touchpad/src/kded/kded.cpp                    |  52 +-
 kcms/touchpad/src/kded/kded.h                      |   6 +-
 kcms/touchpad/src/touchpadbackend.h                |   3 +-
 20 files changed, 1043 insertions(+), 845 deletions(-)
 delete mode 100644 kcms/touchpad/src/backends/x11/libinputproperties.c
 create mode 100644 kcms/touchpad/src/backends/x11/libinputtouchpad.cpp
 create mode 100644 kcms/touchpad/src/backends/x11/libinputtouchpad.h
 create mode 100644 kcms/touchpad/src/backends/x11/propertyinfo.cpp
 create mode 100644 kcms/touchpad/src/backends/x11/propertyinfo.h
 create mode 100644 kcms/touchpad/src/backends/x11/synapticstouchpad.cpp
 create mode 100644 kcms/touchpad/src/backends/x11/synapticstouchpad.h
 delete mode 100644 kcms/touchpad/src/backends/x11/synclientproperties.c
 delete mode 100644 kcms/touchpad/src/backends/x11/synclientproperties.h
 create mode 100644 kcms/touchpad/src/backends/x11/xlibtouchpad.cpp
 create mode 100644 kcms/touchpad/src/backends/x11/xlibtouchpad.h

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/libinputproperties.c
deleted file mode 100644
index 9dbf9ea..0000000
--- a/kcms/touchpad/src/backends/x11/libinputproperties.c
+++ /dev/null
@@ -1,35 +0,0 @@
-/*
- * Copyright (C) 2015 Red Hat, Inc.
- *
- * 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 "synclientproperties.h"
-
-#include <stddef.h>
-#include <limits.h>
-
-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},
-    /* libinput normalizes the accel to -1/1 */
-    {"AccelFactor",             PT_DOUBLE, -1.0, 1.0,   "libinput Accel Speed",  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},
-    /* libinput doesn't have a separate toggle for horiz scrolling */
-    { NULL, 0, 0, 0, 0, 0, 0 }
-};
diff --git a/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp
new file mode 100644
index 0000000..fea6e81
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/libinputtouchpad.cpp
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2015 Red Hat, Inc.
+ *
+ * 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 "libinputtouchpad.h"
+
+#include <stddef.h>
+#include <limits.h>
+
+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},
+    /* libinput normalizes the accel to -1/1 */
+    {"AccelFactor",             PT_DOUBLE, -1.0, 1.0,   "libinput Accel Speed",  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},
+    /* libinput doesn't have a separate toggle for horiz scrolling */
+    { 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/backends/x11/libinputtouchpad.h b/kcms/touchpad/src/backends/x11/libinputtouchpad.h
new file mode 100644
index 0000000..2de8215
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/libinputtouchpad.h
@@ -0,0 +1,30 @@
+/*
+ * 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 LIBINPUTTOUCHPAD_H
+#define LIBINPUTTOUCHPAD_H
+
+#include "xlibtouchpad.h"
+
+class LibinputTouchpad : public XlibTouchpad
+{
+public:
+    LibinputTouchpad(Display *display, int deviceId);
+};
+
+#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/backends/x11/propertyinfo.h b/kcms/touchpad/src/backends/x11/propertyinfo.h
new file mode 100644
index 0000000..5a36242
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/propertyinfo.h
@@ -0,0 +1,50 @@
+/*
+ * 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.
+ */
+
+#ifndef PROPERTYINFO_H
+#define PROPERTYINFO_H
+
+#include <QSharedPointer>
+#include <QX11Info>
+#include <X11/Xdefs.h>
+
+void XDeleter(void *p);
+
+struct PropertyInfo
+{
+    Atom type;
+    int format;
+    QSharedPointer<unsigned char> data;
+    unsigned long nitems;
+
+    float *f;
+    int *i;
+    char *b;
+
+    Display *display;
+    int device;
+    Atom prop;
+
+    PropertyInfo();
+    PropertyInfo(Display *display, int device, Atom prop, Atom floatType);
+    QVariant value(unsigned offset) const;
+
+    void set();
+};
+
+#endif // PROPERTYINFO_H
diff --git a/kcms/touchpad/src/backends/x11/synapticstouchpad.cpp b/kcms/touchpad/src/backends/x11/synapticstouchpad.cpp
new file mode 100644
index 0000000..1e01894
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/synapticstouchpad.cpp
@@ -0,0 +1,235 @@
+/*
+ * 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)
+ */
+
+#include <QDebug>
+
+#include "synapticstouchpad.h"
+
+#include <stddef.h>
+#include <limits.h>
+#include <xorg/synaptics-properties.h>
+
+#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, 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/backends/x11/synapticstouchpad.h b/kcms/touchpad/src/backends/x11/synapticstouchpad.h
new file mode 100644
index 0000000..716687b
--- /dev/null
+++ b/kcms/touchpad/src/backends/x11/synapticstouchpad.h
@@ -0,0 +1,37 @@
+/*
+ * 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 SYNAPTICSTOUCHPAD_H
+#define SYNAPTICSTOUCHPAD_H
+
+#include "xlibtouchpad.h"
+#include "xcbatom.h"
+
+class SynapticsTouchpad : public XlibTouchpad
+{
+public:
+    SynapticsTouchpad(Display *display, int deviceId);
+
+private:
+    XcbAtom m_capsAtom, m_touchpadOffAtom;
+    int m_resX, m_resY;
+    QMap<QString, QString> m_negate;
+    QStringList m_scaleByResX, m_scaleByResY, m_toRadians;
+};
+
+#endif // SYNAPTICSTOUCHPAD_H
diff --git a/kcms/touchpad/src/backends/x11/synclientproperties.c b/kcms/touchpad/src/backends/x11/synclientproperties.c
deleted file mode 100644
index 5fd1ed6..0000000
--- a/kcms/touchpad/src/backends/x11/synclientproperties.c
+++ /dev/null
@@ -1,126 +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)
- */
-
-#include "synclientproperties.h"
-
-#include <stddef.h>
-#include <limits.h>
-#include <xorg/synaptics-properties.h>
-
-#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 }
-};
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;
 
-- 
2.6.2