[plasma-desktop/mart/lookandfeeltool] /: Add a commandline tool to switch lnf package

Marco Martin null at kde.org
Tue Dec 19 16:39:51 UTC 2017


Git commit 60f739f22025d2ffa8fd95f337efe9ada62ecad7 by Marco Martin.
Committed on 19/12/2017 at 16:39.
Pushed by mart into branch 'mart/lookandfeeltool'.

Add a commandline tool to switch lnf package

Summary:
using the kcm c++ itself to do the switch, have a tool
that can be used to switch lnf package from the command line

Test Plan: running the tool has the same effect of chosing a lnf trough the kcm

Reviewers: #plasma, davidedmundson

Reviewed By: #plasma, davidedmundson

Subscribers: davidedmundson, plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D9411

M  +6    -14   CMakeLists.txt
M  +1    -1    applets/kicker/package/contents/config/main.xml
M  +3    -3    applets/kicker/package/contents/ui/ItemListDialog.qml
M  +2    -2    applets/kicker/package/metadata.desktop
M  +12   -3    applets/kicker/plugin/kastatsfavoritesmodel.cpp
M  +23   -27   applets/kickoff/package/contents/ui/FullRepresentation.qml
M  +0    -1    applets/kickoff/package/contents/ui/Header.qml
M  +0    -7    applets/kickoff/package/contents/ui/Kickoff.qml
M  +1    -1    applets/kickoff/package/metadata.desktop
M  +1    -1    applets/kimpanel/backend/scim/CMakeLists.txt
M  +13   -5    applets/pager/plugin/pagermodel.cpp
M  +1    -0    applets/pager/plugin/pagermodel.h
M  +33   -7    applets/taskmanager/plugin/backend.cpp
M  +1    -0    applets/taskmanager/plugin/backend.h
M  +1    -0    applets/trash/package/contents/ui/main.qml
M  +1    -0    applets/trash/package/metadata.desktop
D  +0    -52   cmake/modules/FindOpenGLES.cmake
A  +45   -0    cmake/modules/FindXorgLibinput.cmake
M  +96   -24   containments/desktop/package/contents/ui/ConfigFilter.qml
M  +15   -0    containments/desktop/package/contents/ui/FolderView.qml
M  +3    -3    containments/desktop/package/contents/ui/FolderViewDialog.qml
M  +1    -1    containments/desktop/package/contents/ui/main.qml
M  +1    -0    containments/desktop/plugins/folder/CMakeLists.txt
M  +1    -0    containments/desktop/plugins/folder/autotests/CMakeLists.txt
M  +127  -11   containments/desktop/plugins/folder/autotests/foldermodeltest.cpp
M  +5    -3    containments/desktop/plugins/folder/autotests/foldermodeltest.h
M  +100  -0    containments/desktop/plugins/folder/autotests/positionertest.cpp
M  +1    -0    containments/desktop/plugins/folder/autotests/positionertest.h
A  +159  -0    containments/desktop/plugins/folder/autotests/screenmappertest.cpp     [License: GPL (v2+)]
C  +17   -24   containments/desktop/plugins/folder/autotests/screenmappertest.h [from: containments/desktop/plugins/folder/autotests/foldermodeltest.h - 073% similarity]
M  +327  -34   containments/desktop/plugins/folder/foldermodel.cpp
M  +33   -1    containments/desktop/plugins/folder/foldermodel.h
M  +14   -0    containments/desktop/plugins/folder/folderplugin.cpp
M  +4    -1    containments/desktop/plugins/folder/mimetypesmodel.cpp
M  +30   -3    containments/desktop/plugins/folder/positioner.cpp
M  +10   -0    containments/desktop/plugins/folder/positioner.h
A  +255  -0    containments/desktop/plugins/folder/screenmapper.cpp     [License: GPL (v2+)]
A  +84   -0    containments/desktop/plugins/folder/screenmapper.h     [License: GPL (v2+)]
M  +7    -11   containments/panel/contents/ui/main.qml
M  +1    -1    desktoppackage/contents/configuration/ConfigCategoryDelegate.qml
M  +1    -1    desktoppackage/contents/views/Panel.qml
M  +4    -4    doc/kcontrol/colors/index.docbook
M  +3    -3    doc/kcontrol/icons/index.docbook
M  +3    -3    doc/kcontrol/kcmaccess/index.docbook
M  +5    -5    doc/kcontrol/kcmstyle/index.docbook
M  +7    -7    kaccess/kaccess.notifyrc
M  +2    -1    kcms/CMakeLists.txt
M  +3    -3    kcms/access/accessibility.ui
M  +0    -1    kcms/access/kcmaccess.cpp
M  +19   -39   kcms/access/kcmaccess.desktop
M  +3    -0    kcms/activities/qml/activitiesTab/ActivitiesView.qml
M  +4    -0    kcms/autostart/autostart.desktop
M  +1    -0    kcms/colors/colors.desktop
M  +2    -2    kcms/colors/scmeditoroptions.ui
M  +1    -1    kcms/componentchooser/componentchooser.desktop
M  +13   -0    kcms/desktoptheme/kcm.cpp
M  +5    -0    kcms/desktoptheme/kcm.h
M  +37   -16   kcms/desktoptheme/package/contents/ui/main.qml
M  +1    -1    kcms/formats/kcmformats.cpp
M  +1    -1    kcms/formats/kcmformatswidget.ui
M  +1    -1    kcms/icons/icons.cpp
M  +14   -30   kcms/input/CMakeLists.txt
A  +43   -0    kcms/input/backends/x11.cmake
A  +54   -0    kcms/input/backends/x11/kapplymousetheme.cpp     [License: GPL (v2+)]
A  +482  -0    kcms/input/backends/x11/x11mousebackend.cpp     [License: GPL (v2+)]
A  +75   -0    kcms/input/backends/x11/x11mousebackend.h     [License: GPL (v2+)]
D  +0    -88   kcms/input/kapplymousetheme.cpp
M  +32   -12   kcms/input/kcmmouse.ui
A  +21   -0    kcms/input/logging.cpp     [License: GPL (v2+)]
A  +25   -0    kcms/input/logging.h     [License: GPL (v2+)]
M  +47   -76   kcms/input/main.cpp
M  +54   -288  kcms/input/mouse.cpp
M  +2    -2    kcms/input/mouse.desktop
M  +7    -31   kcms/input/mouse.h
A  +43   -0    kcms/input/mousebackend.cpp     [License: GPL (v2+)]
A  +53   -0    kcms/input/mousebackend.h     [License: GPL (v2+)]
A  +145  -0    kcms/input/mousesettings.cpp     [License: GPL (v2+)]
A  +52   -0    kcms/input/mousesettings.h     [License: GPL (v2+)]
M  +1    -1    kcms/keyboard/kcm_keyboard.desktop
M  +1    -1    kcms/kfontinst/apps/org.kde.kfontview.desktop
M  +1    -1    kcms/kfontinst/kcmfontinst/fontinst.desktop
M  +1    -1    kcms/krdb/krdb_libpathwipe.upd
M  +3    -8    kcms/lookandfeel/CMakeLists.txt
M  +37   -0    kcms/lookandfeel/kcm.cpp
M  +1    -0    kcms/lookandfeel/lnftool.cpp
A  +24   -0    kcms/nightcolor/CMakeLists.txt
A  +2    -0    kcms/nightcolor/Messages.sh
A  +55   -0    kcms/nightcolor/kcm.cpp     [License: GPL (v2)]
A  +44   -0    kcms/nightcolor/kcm.h     [License: GPL (v2)]
A  +65   -0    kcms/nightcolor/kcm_nightcolor.desktop
A  +53   -0    kcms/nightcolor/package/contents/ui/LocationsAutoView.qml     [License: GPL (v2)]
A  +75   -0    kcms/nightcolor/package/contents/ui/LocationsFixedView.qml     [License: GPL (v2)]
A  +48   -0    kcms/nightcolor/package/contents/ui/NumberField.qml     [License: GPL (v2)]
A  +71   -0    kcms/nightcolor/package/contents/ui/TimeField.qml     [License: GPL (v2)]
A  +78   -0    kcms/nightcolor/package/contents/ui/TimingsView.qml     [License: GPL (v2)]
A  +362  -0    kcms/nightcolor/package/contents/ui/main.qml     [License: GPL (v2)]
A  +50   -0    kcms/nightcolor/package/metadata.desktop
M  +1    -1    kcms/phonon/CMakeLists.txt
M  +11   -0    kcms/runners/kcm_plasmasearch.desktop
M  +2    -2    kcms/solid_actions/device-actions/solid-device-OpticalDisc.desktop
M  +1    -1    kcms/solid_actions/device-actions/solid-device-StorageVolume.desktop
M  +1    -1    kcms/solid_actions/solid-device-type.desktop
M  +4    -66   kcms/style/finetuning.ui
M  +0    -52   kcms/style/kcmstyle.cpp
M  +5    -0    kcms/style/style.desktop
M  +1    -1    kcms/touchpad/src/kcm/kcm_touchpad.desktop
M  +2    -2    kcms/workspaceoptions/mainpage.ui
M  +15   -9    org.kde.plasmashell.metainfo.xml
M  +1    -1    runners/kwin/plasma-runner-kwin.desktop
M  +2    -2    runners/plasma-desktop/plasma-runner-plasma-desktop.desktop
M  +1    -1    toolboxes/plasma-toolbox-paneltoolbox.desktop

https://commits.kde.org/plasma-desktop/60f739f22025d2ffa8fd95f337efe9ada62ecad7

diff --git a/CMakeLists.txt b/CMakeLists.txt
index c117cc68..fd889a3b 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -56,6 +56,7 @@ find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS
 
 find_package(LibKWorkspace CONFIG REQUIRED)
 find_package(LibTaskManager CONFIG REQUIRED)
+find_package(LibColorCorrect CONFIG REQUIRED)
 find_package(KWinDBusInterface CONFIG REQUIRED)
 find_package(ScreenSaverDBusInterface CONFIG REQUIRED)
 find_package(KRunnerAppDBusInterface CONFIG REQUIRED)
@@ -112,21 +113,12 @@ add_feature_info("Evdev" EVDEV_FOUND "Evdev driver headers needed for input KCM"
 find_package(Synaptics)
 set_package_properties(Synaptics PROPERTIES TYPE OPTIONAL)
 add_feature_info("Synaptics" SYNAPTICS_FOUND "Synaptics libraries needed for touchpad KCM")
-include(ConfigureChecks.cmake)
 
-if(${Qt5Gui_OPENGL_IMPLEMENTATION} STREQUAL "GL")
-    find_package(OpenGL)
-    set_package_properties(OpenGL PROPERTIES DESCRIPTION "The OpenGL libraries"
-                        URL "http://www.opengl.org"
-                        TYPE REQUIRED
-                        )
-else()
-    find_package(OpenGLES)
-    set_package_properties(OpenGLES PROPERTIES DESCRIPTION "The OpenGLES libraries"
-                        URL "http://www.khronos.org/opengles"
-                        TYPE REQUIRED
-                        )
-endif()
+find_package(XorgLibinput)
+set_package_properties(XorgLibinput PROPERTIES TYPE OPTIONAL)
+add_feature_info("XorgLibinput" XORGLIBINPUT_FOUND "Libinput driver headers needed for input KCM")
+
+include(ConfigureChecks.cmake)
 
 find_package(Breeze ${PROJECT_VERSION} CONFIG)
 set_package_properties(Breeze PROPERTIES
diff --git a/applets/kicker/package/contents/config/main.xml b/applets/kicker/package/contents/config/main.xml
index 0d75ef1f..c1884e8e 100644
--- a/applets/kicker/package/contents/config/main.xml
+++ b/applets/kicker/package/contents/config/main.xml
@@ -72,7 +72,7 @@
     </entry>
     <entry name="extraRunners" type="StringList">
       <label>The plugin id's of additional KRunner plugins to use. Only used if useExtraRunners is true.</label>
-      <default>bookmarks,baloosearch,locations</default>
+      <default>shell,bookmarks,baloosearch,locations</default>
     </entry>
     <entry name="alignResultsToBottom" type="Bool">
       <label>Whether to align search results to the bottom of the menu representation (e.g. panel popup) instead of the top.</label>
diff --git a/applets/kicker/package/contents/ui/ItemListDialog.qml b/applets/kicker/package/contents/ui/ItemListDialog.qml
index 663de02f..760ecfc4 100644
--- a/applets/kicker/package/contents/ui/ItemListDialog.qml
+++ b/applets/kicker/package/contents/ui/ItemListDialog.qml
@@ -75,9 +75,9 @@ Kicker.SubMenu {
     }
 
     function delayedDestroy() {
-        var timer = Qt.createQmlObject('import QtQuick 2.0; Timer { onTriggered: itemDialog.destroy() }', itemDialog);
-        timer.interval = 0;
-        timer.start();
+        Qt.callLater(function() {
+            itemDialog.destroy();
+        });
     }
 
 
diff --git a/applets/kicker/package/metadata.desktop b/applets/kicker/package/metadata.desktop
index 0aa8a7db..cebe694d 100644
--- a/applets/kicker/package/metadata.desktop
+++ b/applets/kicker/package/metadata.desktop
@@ -5,7 +5,7 @@ Name[bs]=Aplikacijski meni
 Name[ca]=Menú d'aplicacions
 Name[ca at valencia]=Menú d'aplicacions
 Name[cs]=Nabídka aplikací
-Name[da]=Startmenu
+Name[da]=Programmenu
 Name[de]=Anwendungsmenü
 Name[el]=Μενού εφαρμογών
 Name[en_GB]=Application Menu
@@ -54,7 +54,7 @@ Comment[bs]=Pokretač baziran na kaskadnim iskakajucim menijima
 Comment[ca]=Un llançador basat en menús emergents en cascada
 Comment[ca at valencia]=Un llançador basat en menús emergents en cascada
 Comment[cs]=Spouštěč založený na vyskakovacích nabídkách v kaskádě
-Comment[da]=Startmenu baseret på pop-op-menuer i kaskader
+Comment[da]=En starter baseret på pop op-menuer i kaskader
 Comment[de]=Ein Anwendungsstarter auf der Grundlage von kaskadierenden Aufklappmenüs
 Comment[el]=Εκτελεστής βασισμένος σε επικαλυπτόμενα αναδυόμενα μενού
 Comment[en_GB]=A launcher based on cascading popup menus
diff --git a/applets/kicker/plugin/kastatsfavoritesmodel.cpp b/applets/kicker/plugin/kastatsfavoritesmodel.cpp
index 027d0b8f..42f3f7ee 100644
--- a/applets/kicker/plugin/kastatsfavoritesmodel.cpp
+++ b/applets/kicker/plugin/kastatsfavoritesmodel.cpp
@@ -464,8 +464,10 @@ KAStatsFavoritesModel::KAStatsFavoritesModel(QObject *parent)
             this, [&] (const QString &currentActivity) {
                 qCDebug(KICKER_DEBUG) << "Activity just got changed to" << currentActivity;
                 Q_UNUSED(currentActivity);
-                auto clientId = d->m_clientId;
-                initForClient(clientId);
+                if (d) {
+                    auto clientId = d->m_clientId;
+                    initForClient(clientId);
+                }
             });
 }
 
@@ -495,7 +497,7 @@ QString KAStatsFavoritesModel::description() const
 
 bool KAStatsFavoritesModel::trigger(int row, const QString &actionId, const QVariant &argument)
 {
-    return d->trigger(row, actionId, argument);
+    return d && d->trigger(row, actionId, argument);
 }
 
 bool KAStatsFavoritesModel::enabled() const
@@ -541,6 +543,7 @@ bool KAStatsFavoritesModel::isFavorite(const QString &id) const
 
 void KAStatsFavoritesModel::portOldFavorites(const QStringList &ids)
 {
+    if (!d) return;
     qCDebug(KICKER_DEBUG) << "portOldFavorites" << ids;
 
     const auto activityId = ":global";
@@ -611,6 +614,8 @@ void KAStatsFavoritesModel::addFavoriteTo(const QString &id, const Activity &act
 
 void KAStatsFavoritesModel::removeFavoriteFrom(const QString &id, const Activity &activity)
 {
+    if (!d || id.isEmpty()) return;
+
     const auto url = d->normalizedId(id).value();
 
     Q_ASSERT(!activity.values.isEmpty());
@@ -625,6 +630,8 @@ void KAStatsFavoritesModel::removeFavoriteFrom(const QString &id, const Activity
 
 void KAStatsFavoritesModel::setFavoriteOn(const QString &id, const QString &activityId)
 {
+    if (!d || id.isEmpty()) return;
+
     const auto url = d->normalizedId(id).value();
 
     qCDebug(KICKER_DEBUG) << "setFavoriteOn" << id << activityId << url << " (actual)";
@@ -644,6 +651,8 @@ void KAStatsFavoritesModel::setFavoriteOn(const QString &id, const QString &acti
 
 void KAStatsFavoritesModel::moveRow(int from, int to)
 {
+    if (!d) return;
+
     d->move(from, to);
 }
 
diff --git a/applets/kickoff/package/contents/ui/FullRepresentation.qml b/applets/kickoff/package/contents/ui/FullRepresentation.qml
index a795cce0..ffd4ebe0 100644
--- a/applets/kickoff/package/contents/ui/FullRepresentation.qml
+++ b/applets/kickoff/package/contents/ui/FullRepresentation.qml
@@ -43,10 +43,13 @@ Item {
     property QtObject globalFavorites: rootModelFavorites
 
     state: "Normal"
-    focus: true
+
+    onFocusChanged: {
+        header.input.forceActiveFocus();
+    }
 
     function switchToInitial() {
-        if(firstButton != null) {
+        if (firstButton != null) {
             mainTabGroup.currentTab = firstButton.tab;
             tabBar.currentTab = firstButton;
             header.query = ""
@@ -55,6 +58,13 @@ Item {
         }
     }
 
+    Kicker.DragHelper {
+        id: dragHelper
+
+        dragIconSize: units.iconSizes.medium
+        onDropped: kickoff.dragSource = null
+    }
+
     Kicker.AppsModel {
         id: rootModel
 
@@ -400,7 +410,7 @@ Item {
             }
         }
 
-        onCurrentTabChanged: root.forceActiveFocus();
+        onCurrentTabChanged: header.input.forceActiveFocus();
 
         Connections {
             target: plasmoid
@@ -409,7 +419,7 @@ Item {
                     createButtons();
                 }
                 if (!expanded) {
-                    switchToInitial()
+                    switchToInitial();
                 }
             }
         }
@@ -437,7 +447,7 @@ Item {
                 break;
             }
             case Qt.Key_Left: {
-                if (header.input.focus) {
+                if (header.input.focus && header.state == "query") {
                     break;
                 }
                 if (!currentView.deactivateCurrentIndex()) {
@@ -451,7 +461,7 @@ Item {
                 break;
             }
             case Qt.Key_Right: {
-                if (header.input.focus) {
+                if (header.input.focus && header.state == "query") {
                     break;
                 }
                 currentView.activateCurrentIndex();
@@ -473,7 +483,7 @@ Item {
                 if (header.state != "query") {
                     plasmoid.expanded = false;
                 } else {
-                    switchToInitial();
+                    header.query = "";
                 }
                 event.accepted = true;
                 break;
@@ -483,28 +493,10 @@ Item {
                 event.accepted = true;
                 break;
             }
-
-            default: { // forward key to searchView
-                //header.query += event.text will break if the key is backspace,
-                //since if the user continues to type, it will produce an invalid query,
-                //having backspace as the first character
-                if (event.key == Qt.Key_Backspace && header.query == "") {
-                    return;
-                }
-                if (event.text != "" && !header.input.focus) {
-                    root.currentView.listView.currentIndex = -1;
-
-                    if (event.matches(StandardKey.Paste) ) {
-                        header.input.paste();
-                    } else if (! (event.key & Qt.Key_Escape)) {
-                        //if special key, do nothing. Qt.Escape is 0x10000000 which happens to be a mask used for all special keys in Qt.
-                        header.query = "";
-                        header.query += event.text;
-                    }
+            default:
+                if (!header.input.focus) {
                     header.input.forceActiveFocus();
-                    event.accepted = true;
                 }
-            }
         }
     }
 
@@ -541,6 +533,10 @@ Item {
                 target: mainTabGroup
                 currentTab: searchPage
             }
+            PropertyChanges {
+                target: root
+                Keys.forwardTo: [root]
+            }
         }
     ] // states
 
diff --git a/applets/kickoff/package/contents/ui/Header.qml b/applets/kickoff/package/contents/ui/Header.qml
index 9d342255..928a6ba2 100644
--- a/applets/kickoff/package/contents/ui/Header.qml
+++ b/applets/kickoff/package/contents/ui/Header.qml
@@ -177,7 +177,6 @@ Item {
                     }
                     if (text == "") {
                         root.state = root.previousState;
-                        root.forceActiveFocus();
                         header.state = "info";
                     } else {
                         header.state = "query";
diff --git a/applets/kickoff/package/contents/ui/Kickoff.qml b/applets/kickoff/package/contents/ui/Kickoff.qml
index baf69719..a7afa92c 100644
--- a/applets/kickoff/package/contents/ui/Kickoff.qml
+++ b/applets/kickoff/package/contents/ui/Kickoff.qml
@@ -75,13 +75,6 @@ Item {
 
     property Item dragSource: null
 
-    Kicker.DragHelper {
-        id: dragHelper
-
-        dragIconSize: units.iconSizes.medium
-        onDropped: kickoff.dragSource = null
-    }
-
     Kicker.ProcessRunner {
         id: processRunner;
     }
diff --git a/applets/kickoff/package/metadata.desktop b/applets/kickoff/package/metadata.desktop
index c221dbb7..64e2e4a7 100644
--- a/applets/kickoff/package/metadata.desktop
+++ b/applets/kickoff/package/metadata.desktop
@@ -12,7 +12,7 @@ Name[ca]=Llançador d'aplicacions
 Name[ca at valencia]=Llançador d'aplicacions
 Name[cs]=Spouštěč aplikací
 Name[csb]=Zrëszôcz programów
-Name[da]=Startmenu
+Name[da]=Programstarter
 Name[de]=Anwendungs-Starter
 Name[el]=Εκτελεστής εφαρμογών
 Name[en_GB]=Application Launcher
diff --git a/applets/kimpanel/backend/scim/CMakeLists.txt b/applets/kimpanel/backend/scim/CMakeLists.txt
index f357f5d3..e79b8283 100644
--- a/applets/kimpanel/backend/scim/CMakeLists.txt
+++ b/applets/kimpanel/backend/scim/CMakeLists.txt
@@ -4,8 +4,8 @@ if(SCIM_FOUND)
     set(SCIM_ICON_DIR "${PC_SCIM_PREFIX}/share/scim/icons")
     configure_file(config-scim.h.cmake config-scim.h)
     set(kimpanel_scim_panel_SRCS main.cpp)
-    qt4_generate_moc(${kimpanel_scim_panel_SRCS} ${CMAKE_CURRENT_BINARY_DIR}/main.moc)
     add_executable(kimpanel-scim-panel ${kimpanel_scim_panel_SRCS})
+    set_target_properties(kimpanel-scim-panel PROPERTIES AUTOMOC TRUE)
     target_link_libraries(kimpanel-scim-panel Qt5::Core Qt5::DBus ${SCIM_LIBRARIES})
     install(TARGETS kimpanel-scim-panel DESTINATION ${LIBEXEC_INSTALL_DIR})
 endif(SCIM_FOUND)
diff --git a/applets/pager/plugin/pagermodel.cpp b/applets/pager/plugin/pagermodel.cpp
index a0d44a7a..9268ed63 100644
--- a/applets/pager/plugin/pagermodel.cpp
+++ b/applets/pager/plugin/pagermodel.cpp
@@ -60,7 +60,8 @@ public:
     WindowTasksModel *tasksModel = nullptr;
 
     static ActivityInfo *activityInfo;
-    QMetaObject::Connection activityInfoConn;
+    QMetaObject::Connection activityNumberConn;
+    QMetaObject::Connection activityNamesConn;
 
     static VirtualDesktopInfo *virtualDesktopInfo;
     QMetaObject::Connection virtualDesktopNumberConn;
@@ -164,18 +165,24 @@ void PagerModel::Private::refreshDataSource()
             }
         );
 
-        QObject::disconnect(activityInfoConn);
+        QObject::disconnect(activityNumberConn);
+        QObject::disconnect(activityNamesConn);
 
         QObject::disconnect(activityInfo, &ActivityInfo::currentActivityChanged,
             q, &PagerModel::currentPageChanged);
         QObject::connect(virtualDesktopInfo, &VirtualDesktopInfo::currentDesktopChanged,
             q, &PagerModel::currentPageChanged, Qt::UniqueConnection);
     } else {
-        QObject::disconnect(activityInfoConn);
-        activityInfoConn = QObject::connect(activityInfo,
+        QObject::disconnect(activityNumberConn);
+        activityNumberConn = QObject::connect(activityInfo,
             &ActivityInfo::numberOfRunningActivitiesChanged,
             q, [this]() { q->refresh(); });
 
+        QObject::disconnect(activityNamesConn);
+        activityNamesConn = QObject::connect(activityInfo,
+            &ActivityInfo::namesOfRunningActivitiesChanged,
+            q, [this]() { q->refresh(); });
+
         QObject::disconnect(virtualDesktopNumberConn);
         QObject::disconnect(virtualDesktopNamesConn);
 
@@ -272,7 +279,8 @@ void PagerModel::setEnabled(bool enabled)
     } else if (!enabled && d->enabled) {
         beginResetModel();
 
-        disconnect(d->activityInfoConn);
+        disconnect(d->activityNumberConn);
+        disconnect(d->activityNamesConn);
         disconnect(d->virtualDesktopNumberConn);
         disconnect(d->virtualDesktopNamesConn);
 
diff --git a/applets/pager/plugin/pagermodel.h b/applets/pager/plugin/pagermodel.h
index ce32cb95..c917676b 100644
--- a/applets/pager/plugin/pagermodel.h
+++ b/applets/pager/plugin/pagermodel.h
@@ -27,6 +27,7 @@ Free Software Foundation, Inc.,
 #include <QX11Info>
 #endif
 
+#include <qwindowdefs.h>
 #include <QAbstractListModel>
 #include <QQmlParserStatus>
 
diff --git a/applets/taskmanager/plugin/backend.cpp b/applets/taskmanager/plugin/backend.cpp
index 69b7663f..552880e4 100644
--- a/applets/taskmanager/plugin/backend.cpp
+++ b/applets/taskmanager/plugin/backend.cpp
@@ -33,6 +33,7 @@
 #include <QActionGroup>
 #include <QApplication>
 #include <QJsonArray>
+#include <QMenu>
 #include <QScopedPointer>
 #include <QQuickItem>
 #include <QQuickWindow>
@@ -216,21 +217,24 @@ QVariantList Backend::placesActions(const QUrl &launcherUrl, bool showAllPlaces,
         return actions;
     }
 
+    QString previousGroup;
+    QMenu *subMenu = nullptr;
+
     QScopedPointer<KFilePlacesModel> placesModel(new KFilePlacesModel());
     for (int i = 0; i < placesModel->rowCount(); ++i) {
         QModelIndex idx = placesModel->index(i, 0);
 
-        if (placesModel->data(idx, KFilePlacesModel::HiddenRole).toBool()) {
+        if (idx.data(KFilePlacesModel::HiddenRole).toBool()) {
             continue;
         }
 
-        const QString &title = placesModel->data(idx, Qt::DisplayRole).toString();
-        const QIcon &icon = placesModel->data(idx, Qt::DecorationRole).value<QIcon>();
-        const QUrl &url = placesModel->data(idx, KFilePlacesModel::UrlRole).toUrl();
+        const QString &title = idx.data(Qt::DisplayRole).toString();
+        const QIcon &icon = idx.data(Qt::DecorationRole).value<QIcon>();
+        const QUrl &url = idx.data(KFilePlacesModel::UrlRole).toUrl();
 
-        QAction *action = new QAction(icon, title, parent);
+        QAction *placeAction = new QAction(icon, title, parent);
 
-        connect(action, &QAction::triggered, this, [this, action, url, desktopEntryUrl] {
+        connect(placeAction, &QAction::triggered, this, [this, url, desktopEntryUrl] {
             KService::Ptr service = KService::serviceByDesktopPath(desktopEntryUrl.toLocalFile());
             if (!service) {
                 return;
@@ -239,7 +243,29 @@ QVariantList Backend::placesActions(const QUrl &launcherUrl, bool showAllPlaces,
             KRun::runService(*service, {url}, QApplication::activeWindow());
         });
 
-        actions << QVariant::fromValue(action);
+        const QString &groupName = idx.data(KFilePlacesModel::GroupRole).toString();
+        if (previousGroup.isEmpty()) { // Skip first group heading.
+            previousGroup = groupName;
+        }
+
+        // Put all subsequent categories into a submenu.
+        if (previousGroup != groupName) {
+            QAction *subMenuAction = new QAction(groupName, parent);
+            subMenu = new QMenu();
+            // Cannot parent a QMenu to a QAction, need to delete it manually.
+            connect(parent, &QObject::destroyed, subMenu, &QObject::deleteLater);
+            subMenuAction->setMenu(subMenu);
+
+            actions << QVariant::fromValue(subMenuAction);
+
+            previousGroup = groupName;
+        }
+
+        if (subMenu) {
+            subMenu->addAction(placeAction);
+        } else {
+            actions << QVariant::fromValue(placeAction);
+        }
     }
 
     // There is nothing more frustrating than having a "More" entry that ends up showing just one or two
diff --git a/applets/taskmanager/plugin/backend.h b/applets/taskmanager/plugin/backend.h
index c3ac6d96..f7e8d1d7 100644
--- a/applets/taskmanager/plugin/backend.h
+++ b/applets/taskmanager/plugin/backend.h
@@ -24,6 +24,7 @@
 #include <QRect>
 
 #include <netwm.h>
+#include <qwindowdefs.h>
 
 class QAction;
 class QActionGroup;
diff --git a/applets/trash/package/contents/ui/main.qml b/applets/trash/package/contents/ui/main.qml
index bdc9c535..1eaecc61 100644
--- a/applets/trash/package/contents/ui/main.qml
+++ b/applets/trash/package/contents/ui/main.qml
@@ -59,6 +59,7 @@ DragDrop.DropArea {
     Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation
     Plasmoid.backgroundHints: PlasmaCore.Types.NoBackground
     Plasmoid.icon: (dirModel.count > 0) ? "user-trash-full": "user-trash"
+    Plasmoid.onActivated: action_open()
 
     preventStealing: true
 
diff --git a/applets/trash/package/metadata.desktop b/applets/trash/package/metadata.desktop
index 3d710e78..f14d549b 100644
--- a/applets/trash/package/metadata.desktop
+++ b/applets/trash/package/metadata.desktop
@@ -95,6 +95,7 @@ Comment[he]=מספק גישה לקבצים שנזרקו לאשפה
 Comment[hu]=Hozzáférést biztosít a kukába helyezett fájlokhoz
 Comment[id]=Menyediakan akses ke file yang dikirim ke tempat sampah
 Comment[it]=Fornisce l'accesso ai file cestinati
+Comment[ko]=휴지통에 버린 파일 접근 제공
 Comment[nl]=Biedt toegang tot de bestanden verzonden naar de prullenbak
 Comment[nn]=Gjev tilgang til filer sende til papirkorga
 Comment[pl]=Zapewna dostęp do plików w koszu
diff --git a/cmake/modules/FindOpenGLES.cmake b/cmake/modules/FindOpenGLES.cmake
deleted file mode 100644
index 60b07e29..00000000
--- a/cmake/modules/FindOpenGLES.cmake
+++ /dev/null
@@ -1,52 +0,0 @@
-# - Try to find OpenGLES
-# Once done this will define
-#  
-#  OPENGLES_FOUND           - system has OpenGLES and EGL
-#  OPENGL_EGL_FOUND         - system has EGL
-#  OPENGLES_INCLUDE_DIR     - the GLES include directory
-#  OPENGLES_LIBRARY	    - the GLES library
-#  OPENGLES_EGL_INCLUDE_DIR - the EGL include directory
-#  OPENGLES_EGL_LIBRARY	    - the EGL library
-#  OPENGLES_LIBRARIES       - all libraries needed for OpenGLES
-#  OPENGLES_INCLUDES        - all includes needed for OpenGLES
-
-FIND_PATH(OPENGLES_INCLUDE_DIR GLES2/gl2.h
-  /usr/openwin/share/include
-  /opt/graphics/OpenGL/include /usr/X11R6/include
-  /usr/include
-)
-
-FIND_LIBRARY(OPENGLES_LIBRARY
-  NAMES GLESv2
-  PATHS /opt/graphics/OpenGL/lib
-        /usr/openwin/lib
-        /usr/shlib /usr/X11R6/lib
-        /usr/lib
-)
-
-FIND_PATH(OPENGLES_EGL_INCLUDE_DIR EGL/egl.h
-  /usr/openwin/share/include
-  /opt/graphics/OpenGL/include /usr/X11R6/include
-  /usr/include
-)
-
-FIND_LIBRARY(OPENGLES_EGL_LIBRARY
-    NAMES EGL
-    PATHS /usr/shlib /usr/X11R6/lib
-          /usr/lib
-)
-
-SET(OPENGL_EGL_FOUND "NO")
-IF(OPENGLES_EGL_LIBRARY AND OPENGLES_EGL_INCLUDE_DIR)
-    SET(OPENGL_EGL_FOUND "YES")
-ENDIF()
-
-SET(OPENGLES_FOUND "NO")
-IF(OPENGLES_LIBRARY AND OPENGLES_INCLUDE_DIR AND
-   OPENGLES_EGL_LIBRARY AND OPENGLES_EGL_INCLUDE_DIR)
-    SET(OPENGLES_LIBRARIES ${OPENGLES_LIBRARY} ${OPENGLES_LIBRARIES}
-                           ${OPENGLES_EGL_LIBRARY})
-    SET(OPENGLES_INCLUDES ${OPENGLES_INCLUDE_DIR} ${OPENGLES_EGL_INCLUDE_DIR})
-    SET(OPENGLES_FOUND "YES")
-ENDIF()
-
diff --git a/cmake/modules/FindXorgLibinput.cmake b/cmake/modules/FindXorgLibinput.cmake
new file mode 100644
index 00000000..1550751a
--- /dev/null
+++ b/cmake/modules/FindXorgLibinput.cmake
@@ -0,0 +1,45 @@
+# - Find xorg libinput's libraries and headers.
+# This module defines the following variables:
+#
+#  XORGLIBINPUT_FOUND        - true if libinput was found
+#  XORGLIBINPUT_INCLUDE_DIRS - include path for synaptics
+#  There are no libraries, just a header file
+#
+# Copyright (c) 2017 Weng Xuetian <wengxt at gmail.com>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+# 1. Redistributions of source code must retain the above copyright
+#    notice, this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright
+#    notice, this list of conditions and the following disclaimer in the
+#    documentation and/or other materials provided with the distribution.
+# 3. Neither the name of the University nor the names of its contributors
+#    may be used to endorse or promote products derived from this software
+#    without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+# ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+# SUCH DAMAGE.
+
+find_package(PkgConfig)
+pkg_check_modules(PC_XORGLIBINPUT xorg-libinput)
+
+find_path(XORGLIBINPUT_INCLUDE_DIRS
+    NAMES libinput-properties.h
+    HINTS ${PC_XORGLIBINPUT_INCLUDE_DIRS} ${PC_XORGLIBINPUT_INCLUDEDIR}
+)
+
+include(FindPackageHandleStandardArgs)
+find_package_handle_standard_args(XorgLibinput REQUIRED_VARS XORGLIBINPUT_INCLUDE_DIRS)
+
+mark_as_advanced(XORGLIBINPUT_INCLUDE_DIRS)
diff --git a/containments/desktop/package/contents/ui/ConfigFilter.qml b/containments/desktop/package/contents/ui/ConfigFilter.qml
index 497fc742..ce753cc3 100644
--- a/containments/desktop/package/contents/ui/ConfigFilter.qml
+++ b/containments/desktop/package/contents/ui/ConfigFilter.qml
@@ -45,7 +45,10 @@ Item {
         // SortFilterModel doesn't have a case-sensitivity option
         // but filterRegExp always causes case-insensitive sorting.
         filterRegExp: mimeFilter.text
-        filterRole: "display"
+        filterRole: "name"
+
+        sortRole: mimeTypesView.getColumn(mimeTypesView.sortIndicatorColumn).role
+        sortOrder: mimeTypesView.sortIndicatorOrder
     }
 
     ColumnLayout {
@@ -94,50 +97,118 @@ Item {
             Layout.fillWidth: true
             Layout.fillHeight: true
 
-            ScrollView {
+            CheckBox { // Purely for metrics.
+                id: metricsCheckBox
+                visible: false
+            }
+
+            TableView {
+                id: mimeTypesView
+
+                // Signal the delegates listen to when user presses space to toggle current row.
+                signal toggleCurrent
+
                 Layout.fillWidth: true
                 Layout.fillHeight: true
 
-                frameVisible: true
-
                 enabled: (filterMode.currentIndex > 0)
 
-                ListView {
-                    model: filderedMimeTypesModel
-
-                    delegate: RowLayout {
-                        CheckBox {
-                            Layout.maximumWidth: 18 // FIXME HACK: Use actual radio button width.
+                model: filderedMimeTypesModel
 
-                            checked: model.checked
-                            onCheckedChanged: model.checked = checked
-                        }
+                sortIndicatorVisible: true
+                sortIndicatorColumn: 2 // Default to sort by "File type".
 
-                        PlasmaCore.IconItem {
-                            anchors.verticalCenter: parent.verticalCenter
+                onSortIndicatorColumnChanged: { // Disallow sorting by icon.
+                    if (sortIndicatorColumn === 1) {
+                        sortIndicatorColumn = 2;
+                    }
+                }
 
-                            width: units.iconSizes.small
-                            height: units.iconSizes.small
+                Keys.onSpacePressed: toggleCurrent()
 
-                            Layout.maximumWidth: width
-                            Layout.maximumHeight: height
+                function adjustColumns() {
+                    // Resize description column to take whatever space is left.
+                    var width = viewport.width;
+                    for (var i = 0; i < columnCount - 1; ++i) {
+                        width -= getColumn(i).width;
+                    }
+                    descriptionColumn.width = width;
+                }
 
-                            source: model.decoration
+                onWidthChanged: adjustColumns()
+                // Component.onCompleted is too early to do this...
+                onRowCountChanged: adjustColumns()
+
+                TableViewColumn {
+                    role: "checked"
+                    width: metricsCheckBox.width
+                    resizable: false
+                    movable: false
+
+                    delegate: CheckBox {
+                        id: checkBox
+
+                        checked: styleData.value
+                        activeFocusOnTab: false // only let the TableView as a whole get focus
+                        onClicked: {
+                            model.checked = checked
+                            // Clicking it breaks the binding to the model value which becomes
+                            // an issue during sorting as TableView re-uses delegates.
+                            checked = Qt.binding(function() {
+                                return styleData.value;
+                            });
                         }
 
-                        Label {
-                            Layout.fillWidth: true
-
-                            text: model.display
+                        Connections {
+                            target: mimeTypesView
+                            onToggleCurrent: {
+                                if (styleData.row === mimeTypesView.currentRow) {
+                                    model.checked = !checkBox.checked
+                                }
+                            }
                         }
                     }
                 }
+
+                TableViewColumn {
+                    role: "decoration"
+                    width: units.iconSizes.small
+                    resizable: false
+                    movable: false
+
+                    delegate: PlasmaCore.IconItem {
+                        width: units.iconSizes.small
+                        height: units.iconSizes.small
+                        animated: false // TableView re-uses delegates, avoid animation when sorting/filtering.
+                        source: styleData.value
+                    }
+                }
+
+                TableViewColumn {
+                    id: nameColumn
+                    role: "name"
+                    title: i18n("File type")
+                    width: units.gridUnit * 10 // Assume somewhat reasonable default for mime type name.
+                    onWidthChanged: mimeTypesView.adjustColumns()
+                    movable: false
+                }
+                TableViewColumn {
+                    id: descriptionColumn
+                    role: "comment"
+                    title: i18n("Description")
+                    movable: false
+                    resizable: false
+                }
             }
 
             ColumnLayout {
                 Layout.alignment: Qt.AlignTop
+                // Need to explicitly base the size off the button's implicitWidth
+                // to avoid the column from growing way too wide due to fillWidth...
+                Layout.maximumWidth: Math.max(selectAllButton.implicitWidth, deselectAllButton.implicitWidth)
 
                 Button {
+                    id: selectAllButton
                     Layout.fillWidth: true
 
                     enabled: (filterMode.currentIndex > 0)
@@ -150,6 +221,7 @@ Item {
                 }
 
                 Button {
+                    id: deselectAllButton
                     Layout.fillWidth: true
 
                     enabled: (filterMode.currentIndex > 0)
diff --git a/containments/desktop/package/contents/ui/FolderView.qml b/containments/desktop/package/contents/ui/FolderView.qml
index 516d287b..470fbd67 100644
--- a/containments/desktop/package/contents/ui/FolderView.qml
+++ b/containments/desktop/package/contents/ui/FolderView.qml
@@ -253,6 +253,7 @@ Item {
             if (mouse.buttons & Qt.BackButton) {
                 if (root.isPopup && dir.resolvedUrl != dir.resolve(plasmoid.configuration.url)) {
                     doBack();
+                    mouse.accepted = true;
                 }
 
                 return;
@@ -273,6 +274,7 @@ Item {
                 if (mouse.buttons & Qt.RightButton) {
                     clearPressState();
                     dir.openContextMenu();
+                    mouse.accepted = true;
                 }
             } else {
                 pressedItem = hoveredItem;
@@ -308,6 +310,7 @@ Item {
                         clearPressState();
 
                         dir.openContextMenu();
+                        mouse.accepted = true;
                     }
                 }
             }
@@ -420,6 +423,11 @@ Item {
                     rB.height = Math.min(ceil - rB.y, Math.abs(rB.y - cPos.y));
                 }
 
+                // Ensure rubberband is at least 1px in size or else it will become
+                // invisible and not match any items.
+                rB.width = Math.max(1, rB.width);
+                rB.height = Math.max(1, rB.height);
+
                 gridView.rectangleSelect(rB.x, rB.y, rB.width, rB.height);
 
                 return;
@@ -1072,6 +1080,8 @@ Item {
             parseDesktopFiles: (plasmoid.configuration.url == "desktop:/")
             previews: plasmoid.configuration.previews
             previewPlugins: plasmoid.configuration.previewPlugins
+            screenMapper: Folder.ScreenMapper
+            appletInterface: plasmoid
 
             onListingCompleted: {
                 if (!gridView.model && plasmoid.expanded) {
@@ -1095,6 +1105,11 @@ Item {
                 var from = -1;
                 var to = -1;
 
+                // round the drop pos to half of an item's size to have a more exact
+                // placement in the grid and avoid jumping items
+                dropPos.x = Math.floor((2 * dropPos.x) / cellWidth) * (cellWidth / 2);
+                dropPos.y = Math.floor((2 * dropPos.y) / cellHeight) * (cellHeight / 2);
+
                 for (var i = 0; i < urls.length; i++) {
                     from = positioner.indexForUrl(urls[i]);
                     to = -1;
diff --git a/containments/desktop/package/contents/ui/FolderViewDialog.qml b/containments/desktop/package/contents/ui/FolderViewDialog.qml
index 3d308f81..a2f0308d 100644
--- a/containments/desktop/package/contents/ui/FolderViewDialog.qml
+++ b/containments/desktop/package/contents/ui/FolderViewDialog.qml
@@ -118,9 +118,9 @@ Folder.SubDialog {
     }
 
     function delayedDestroy() {
-        var timer = Qt.createQmlObject('import QtQuick 2.0; Timer { onTriggered: itemDialog.destroy() }', itemDialog);
-        timer.interval = 0;
-        timer.start();
+        Qt.callLater(function() {
+            itemDialog.destroy();
+        });
     }
 
     Component.onDestruction: {
diff --git a/containments/desktop/package/contents/ui/main.qml b/containments/desktop/package/contents/ui/main.qml
index 7d64b406..bad5245d 100644
--- a/containments/desktop/package/contents/ui/main.qml
+++ b/containments/desktop/package/contents/ui/main.qml
@@ -311,7 +311,7 @@ FolderViewDropArea {
         }
 
         onImmutableChanged: {
-            if (!plasmoid.immutable) {
+            if (root.isContainment && !plasmoid.immutable) {
                 pressToMoveHelp.show();
             }
         }
diff --git a/containments/desktop/plugins/folder/CMakeLists.txt b/containments/desktop/plugins/folder/CMakeLists.txt
index 7fc01313..d6338072 100644
--- a/containments/desktop/plugins/folder/CMakeLists.txt
+++ b/containments/desktop/plugins/folder/CMakeLists.txt
@@ -20,6 +20,7 @@ set(folderplugin_SRCS
     viewpropertiesmenu.cpp
     wheelinterceptor.cpp
     shortcut.cpp
+    screenmapper.cpp
 )
 
 install(FILES qmldir DESTINATION ${QML_INSTALL_DIR}/org/kde/private/desktopcontainment/folder)
diff --git a/containments/desktop/plugins/folder/autotests/CMakeLists.txt b/containments/desktop/plugins/folder/autotests/CMakeLists.txt
index 73c2d06d..23c40121 100644
--- a/containments/desktop/plugins/folder/autotests/CMakeLists.txt
+++ b/containments/desktop/plugins/folder/autotests/CMakeLists.txt
@@ -5,6 +5,7 @@ include(ECMAddTests)
 include_directories("..";${include_directories})
 
 ecm_add_tests(
+   screenmappertest.cpp
    foldermodeltest.cpp 
    positionertest.cpp
    viewpropertiesmenutest.cpp
diff --git a/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp b/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp
index df9e47fe..008174b7 100644
--- a/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp
+++ b/containments/desktop/plugins/folder/autotests/foldermodeltest.cpp
@@ -21,6 +21,7 @@
 
 #include "foldermodeltest.h"
 #include "foldermodel.h"
+#include "screenmapper.h"
 
 #include <QTest>
 #include <QTemporaryDir>
@@ -30,13 +31,11 @@ QTEST_MAIN(FolderModelTest)
 
 static const QLatin1String desktop(QLatin1String("Desktop"));
 
-void FolderModelTest::initTestCase()
+void FolderModelTest::createTestFolder(const QString &path)
 {
-    m_folderDir = new QTemporaryDir();
-        
     QDir dir(m_folderDir->path());
-    dir.mkdir(desktop);
-    dir.cd(desktop);
+    dir.mkdir(path);
+    dir.cd(path);
     dir.mkdir("firstDir");
     QFile f;
     for (int i = 1; i < 10; i++) {
@@ -44,24 +43,24 @@ void FolderModelTest::initTestCase()
         f.open(QFile::WriteOnly);
         f.close();
     }
-    
-}
-
-void FolderModelTest::cleanupTestCase()
-{
-    delete m_folderDir;
 }
 
 void FolderModelTest::init()
 {
+    m_folderDir = new QTemporaryDir();
+    createTestFolder(desktop);
     m_folderModel = new FolderModel(this);
+    m_folderModel->classBegin();
     m_folderModel->setUrl(m_folderDir->path()  + QDir::separator() + desktop );
+    m_folderModel->componentComplete();
     QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
     s.wait(1000);
 }
 
 void FolderModelTest::cleanup()
 {
+    delete m_folderDir;
+    m_folderDir = 0;
     delete m_folderModel;
     m_folderModel = nullptr;
 }
@@ -265,3 +264,120 @@ void FolderModelTest::tst_lockedChanged()
     m_folderModel->setLocked(true);
     QCOMPARE(s.count(), 2);
 }
+
+void FolderModelTest::tst_multiScreen()
+{
+    delete m_folderModel;
+    // Custom instance for this test to set screen mapper before marking component
+    // as complete.
+    m_folderModel = new FolderModel(this);
+    m_folderModel->classBegin();
+    m_folderModel->setUrl(m_folderDir->path()  + QDir::separator() + desktop );
+    auto *screenMapper = ScreenMapper::instance();
+    m_folderModel->setUsedByContainment(true);
+    m_folderModel->setScreenMapper(screenMapper);
+    m_folderModel->setScreen(0);
+    m_folderModel->componentComplete();
+
+    QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
+    s.wait(1000);
+    const auto count = m_folderModel->rowCount();
+    for (int i = 0; i < count; i++) {
+        const auto index = m_folderModel->index(i, 0);
+        const auto name = index.data(FolderModel::UrlRole).toString();
+        // all items are on the first screen by default
+        QCOMPARE(screenMapper->screenForItem(name), 0);
+    }
+
+    // move one file to a new screen
+    const auto movedItem = m_folderModel->index(0, 0).data(FolderModel::UrlRole).toString();
+    FolderModel secondFolderModel;
+    secondFolderModel.classBegin();
+    secondFolderModel.setUrl(m_folderDir->path()  + QDir::separator() + desktop );
+    secondFolderModel.setUsedByContainment(true);
+    secondFolderModel.setScreenMapper(screenMapper);
+    secondFolderModel.setScreen(1);
+    secondFolderModel.componentComplete();
+    QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted);
+    s2.wait(1000);
+    const auto count2 = secondFolderModel.rowCount();
+    QCOMPARE(count2, 0);
+
+    screenMapper->addMapping(movedItem, 1);
+    m_folderModel->invalidate();
+    secondFolderModel.invalidate();
+    s.wait(1000);
+    s2.wait(1000);
+    // we have one less item
+    QCOMPARE(m_folderModel->rowCount(), count - 1);
+    QCOMPARE(secondFolderModel.rowCount(), 1);
+    QCOMPARE(secondFolderModel.index(0,0).data(FolderModel::UrlRole).toString(), movedItem);
+    QCOMPARE(screenMapper->screenForItem(movedItem), 1);
+
+    // remove extra screen, we have all items back
+    screenMapper->removeScreen(1, m_folderModel->url());
+    s.wait(500);
+    QCOMPARE(m_folderModel->rowCount(), count);
+    QCOMPARE(secondFolderModel.rowCount(), 0);
+    QCOMPARE(screenMapper->screenForItem(movedItem), 0);
+
+    // add back extra screen, the item is moved there
+    screenMapper->addScreen(1, m_folderModel->url());
+    s.wait(500);
+    s2.wait(500);
+    QCOMPARE(m_folderModel->rowCount(), count - 1);
+    QCOMPARE(secondFolderModel.rowCount(), 1);
+    QCOMPARE(secondFolderModel.index(0,0).data(FolderModel::UrlRole).toString(), movedItem);
+    QCOMPARE(screenMapper->screenForItem(movedItem), 1);
+
+    // create a new item, it appears on the first screen
+    QDir dir(m_folderDir->path());
+    dir.cd(desktop);
+    dir.mkdir("secondDir");
+    dir.cd("secondDir");
+    s.wait(1000);
+    QCOMPARE(m_folderModel->rowCount(), count);
+    QCOMPARE(secondFolderModel.rowCount(), 1);
+    QCOMPARE(screenMapper->screenForItem("file://" + dir.path()), 0);
+}
+
+void FolderModelTest::tst_multiScreenDifferenPath()
+{
+    auto *screenMapper = ScreenMapper::instance();
+    m_folderModel->setUsedByContainment(true);
+    m_folderModel->setScreenMapper(screenMapper);
+    m_folderModel->setScreen(0);
+    QSignalSpy s(m_folderModel, &FolderModel::listingCompleted);
+    s.wait(1000);
+    const auto count = m_folderModel->rowCount();
+    QCOMPARE(count, 10);
+
+    const QLatin1String desktop2(QLatin1String("Desktop2"));
+    createTestFolder(desktop2);
+    FolderModel secondFolderModel;
+    secondFolderModel.setUsedByContainment(true);
+    secondFolderModel.setScreenMapper(screenMapper);
+    secondFolderModel.setUrl(m_folderDir->path()  + QDir::separator() + desktop2 );
+    secondFolderModel.setScreen(1);
+    QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted);
+    s2.wait(1000);
+    const auto count2 = secondFolderModel.rowCount();
+    QCOMPARE(count2, 10);
+
+    // create a new item, it appears on the first screen
+    QDir dir(m_folderDir->path());
+    dir.cd(desktop);
+    dir.mkdir("secondDir");
+    s.wait(1000);
+    QCOMPARE(m_folderModel->rowCount(), count + 1);
+    QCOMPARE(secondFolderModel.rowCount(), count2);
+
+
+    // create a new item, it appears on the second screen
+    dir.cd(m_folderDir->path() + QDir::separator() + desktop2);
+    dir.mkdir("secondDir2");
+    s.wait(1000);
+    QCOMPARE(m_folderModel->rowCount(), count + 1);
+    QCOMPARE(secondFolderModel.rowCount(), count2 + 1);
+}
+
diff --git a/containments/desktop/plugins/folder/autotests/foldermodeltest.h b/containments/desktop/plugins/folder/autotests/foldermodeltest.h
index c5c4aa71..6f1726d2 100644
--- a/containments/desktop/plugins/folder/autotests/foldermodeltest.h
+++ b/containments/desktop/plugins/folder/autotests/foldermodeltest.h
@@ -32,9 +32,6 @@ class FolderModelTest : public QObject
     Q_OBJECT
 
 private Q_SLOTS:
-    void initTestCase();
-    void cleanupTestCase();
-
     void init();
     void cleanup();
     void tst_listing();
@@ -48,8 +45,13 @@ private Q_SLOTS:
     void tst_defaultValues();
     void tst_actionMenu();
     void tst_lockedChanged();
+    void tst_multiScreen();
+    void tst_multiScreenDifferenPath();
+
 
 private:    
+    void createTestFolder(const QString &path);
+
     FolderModel *m_folderModel;
     QTemporaryDir *m_folderDir;
 };
diff --git a/containments/desktop/plugins/folder/autotests/positionertest.cpp b/containments/desktop/plugins/folder/autotests/positionertest.cpp
index 455879d3..08a65840 100644
--- a/containments/desktop/plugins/folder/autotests/positionertest.cpp
+++ b/containments/desktop/plugins/folder/autotests/positionertest.cpp
@@ -29,6 +29,7 @@
 
 #include "foldermodel.h"
 #include "positioner.h"
+#include "screenmapper.h"
 
 QTEST_MAIN(PositionerTest)
 
@@ -58,6 +59,11 @@ void PositionerTest::cleanupTestCase()
 void PositionerTest::init()
 {
     m_folderModel = new FolderModel(this);
+    m_folderModel->classBegin();
+    m_folderModel->setScreen(0);
+    m_folderModel->setScreenMapper(ScreenMapper::instance());
+    m_folderModel->setUsedByContainment(true);
+    m_folderModel->componentComplete();
     m_positioner = new Positioner(this);
     m_positioner->setEnabled(true);
     m_positioner->setFolderModel(m_folderModel);
@@ -209,6 +215,100 @@ void PositionerTest::tst_changePerStripe()
     QCOMPARE(s.count(), 2);
 }
 
+void PositionerTest::tst_proxyMapping()
+{
+    auto *screenMapper = ScreenMapper::instance();
+    FolderModel secondFolderModel;
+    secondFolderModel.classBegin();
+    secondFolderModel.setUrl(m_folderDir->path()  + QDir::separator() + desktop );
+    secondFolderModel.setUsedByContainment(true);
+    secondFolderModel.setScreenMapper(screenMapper);
+    secondFolderModel.setScreen(1);
+    secondFolderModel.componentComplete();
+    Positioner secondPositioner;
+    secondPositioner.setEnabled(true);
+    secondPositioner.setFolderModel(&secondFolderModel);
+    secondPositioner.setPerStripe(3);
+
+    QSignalSpy s2(&secondFolderModel, &FolderModel::listingCompleted);
+    QVERIFY(s2.wait(1000));
+
+    QHash<int, int> expectedSource2ProxyScreen0;
+    QHash<int, int> expectedProxy2SourceScreen0;
+    QHash<int, int> expectedProxy2SourceScreen1;
+    QHash<int, int> expectedSource2ProxyScreen1;
+
+    for (int i = 0; i < m_folderModel->rowCount(); i++) {
+        expectedSource2ProxyScreen0[i] = i;
+        expectedProxy2SourceScreen0[i] = i;
+    }
+
+    // swap items 1 and 2 in the positioner
+    m_positioner->move({1, 2, 2, 1});
+    expectedSource2ProxyScreen0[1] = 2;
+    expectedSource2ProxyScreen0[2] = 1;
+    expectedProxy2SourceScreen0[1] = 2;
+    expectedProxy2SourceScreen0[2] = 1;
+
+    auto savedSource2ProxyScreen0 = expectedSource2ProxyScreen0;
+    auto savedProxy2SourceScreen0 = expectedProxy2SourceScreen0;
+
+    auto verifyMapping = [](const QHash<int, int> &actual, const QHash<int, int> &expected) {
+
+        auto ensureUnique = [](const QHash<int, int> mapping) {
+            auto values = mapping.values();
+            qSort(values);
+            auto uniqueValues = values.toSet().toList();
+            qSort(uniqueValues);
+            QVERIFY(uniqueValues == values);
+        };
+
+        ensureUnique(actual);
+        QCOMPARE(actual, expected);
+    };
+
+    verifyMapping(m_positioner->proxyToSourceMapping(), expectedProxy2SourceScreen0);
+    verifyMapping(m_positioner->sourceToProxyMapping(), expectedSource2ProxyScreen0);
+    verifyMapping(secondPositioner.proxyToSourceMapping(), expectedProxy2SourceScreen1);
+    verifyMapping(secondPositioner.sourceToProxyMapping(), expectedSource2ProxyScreen1);
+
+    const auto movedItem = m_folderModel->index(1, 0).data(FolderModel::UrlRole).toString();
+
+    // move the item 1 from source (now in position 2) to the second screen
+    screenMapper->addMapping(movedItem, 1);
+
+    expectedProxy2SourceScreen1[0] = 0;
+    expectedSource2ProxyScreen1[0] = 0;
+    expectedSource2ProxyScreen0.clear();
+    expectedProxy2SourceScreen0.clear();
+    for (int i = 0; i < m_folderModel->rowCount(); i++) {
+        // as item 1 disappeared, the mapping of all items after that are shifted
+        auto proxyIndex = (i <= 1) ? i : i + 1;
+        expectedProxy2SourceScreen0[proxyIndex] = i;
+        expectedSource2ProxyScreen0[i] = proxyIndex;
+    }
+
+    verifyMapping(m_positioner->proxyToSourceMapping(), expectedProxy2SourceScreen0);
+    verifyMapping(m_positioner->sourceToProxyMapping(), expectedSource2ProxyScreen0);
+    verifyMapping(secondPositioner.proxyToSourceMapping(), expectedProxy2SourceScreen1);
+    verifyMapping(secondPositioner.sourceToProxyMapping(), expectedSource2ProxyScreen1);
+
+    // move back the same item to the first screen
+    screenMapper->addMapping(movedItem, 0);
+
+    // nothing on the second screen
+    expectedSource2ProxyScreen1.clear();
+    expectedProxy2SourceScreen1.clear();
+    // first screen should look like in the beginning
+    expectedSource2ProxyScreen0 = savedSource2ProxyScreen0;
+    expectedProxy2SourceScreen0 = savedProxy2SourceScreen0;
+
+    verifyMapping(m_positioner->proxyToSourceMapping(), expectedProxy2SourceScreen0);
+    verifyMapping(m_positioner->sourceToProxyMapping(), expectedSource2ProxyScreen0);
+    verifyMapping(secondPositioner.proxyToSourceMapping(), expectedProxy2SourceScreen1);
+    verifyMapping(secondPositioner.sourceToProxyMapping(), expectedSource2ProxyScreen1);
+}
+
 void PositionerTest::checkPositions(int perStripe)
 {
     QSignalSpy s(m_positioner, &Positioner::positionsChanged);
diff --git a/containments/desktop/plugins/folder/autotests/positionertest.h b/containments/desktop/plugins/folder/autotests/positionertest.h
index f4431530..9a1ce038 100644
--- a/containments/desktop/plugins/folder/autotests/positionertest.h
+++ b/containments/desktop/plugins/folder/autotests/positionertest.h
@@ -52,6 +52,7 @@ private Q_SLOTS:
     void tst_defaultValues();
     void tst_changeEnabledStatus();
     void tst_changePerStripe();
+    void tst_proxyMapping();
 
 private:
     void checkPositions(int perStripe);
diff --git a/containments/desktop/plugins/folder/autotests/screenmappertest.cpp b/containments/desktop/plugins/folder/autotests/screenmappertest.cpp
new file mode 100644
index 00000000..ed810318
--- /dev/null
+++ b/containments/desktop/plugins/folder/autotests/screenmappertest.cpp
@@ -0,0 +1,159 @@
+/***************************************************************************
+ *   Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company *
+ *                      <info at kdab.com>                                    *
+ *   Author: Andras Mantia <andras.mantia at kdab.com>                        *
+ *           Work sponsored by the LiMux project of the city of Munich.    *
+ *                                                                         *
+ *   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 "screenmappertest.h"
+#include "screenmapper.h"
+
+#include <QTest>
+#include <QSignalSpy>
+
+QTEST_MAIN(ScreenMapperTest)
+
+void ScreenMapperTest::initTestCase()
+{
+    m_screenMapper = ScreenMapper::instance();
+}
+
+void ScreenMapperTest::init()
+{
+    m_screenMapper->cleanup();
+}
+
+void ScreenMapperTest::tst_addScreens()
+{
+    const auto path = QStringLiteral("desktop:/");
+    QSignalSpy s(m_screenMapper, &ScreenMapper::screensChanged);
+    m_screenMapper->addScreen(-1, path);
+    QCOMPARE(s.count(), 0);
+    m_screenMapper->addScreen(1, path);
+    QCOMPARE(s.count(), 1);
+    m_screenMapper->addScreen(0, path);
+    QCOMPARE(s.count(), 2);
+    m_screenMapper->addScreen(1, path);
+    QCOMPARE(s.count(), 2);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), 0);
+}
+
+void ScreenMapperTest::tst_removeScreens()
+{
+    const auto path = QStringLiteral("desktop:/");
+    addScreens(path);
+    QSignalSpy s(m_screenMapper, &ScreenMapper::screensChanged);
+    m_screenMapper->removeScreen(-1, path);
+    QCOMPARE(s.count(), 0);
+    m_screenMapper->removeScreen(1, path);
+    QCOMPARE(s.count(), 1);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), 0);
+    m_screenMapper->removeScreen(1, path);
+    QCOMPARE(s.count(), 1);
+    m_screenMapper->addScreen(3, path);
+    QCOMPARE(s.count(), 2);
+    m_screenMapper->removeScreen(0, path);
+    QCOMPARE(s.count(), 3);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), 2);
+}
+
+void ScreenMapperTest::tst_addMapping()
+{
+    const auto path = QStringLiteral("desktop:/");
+    addScreens(path);
+    QSignalSpy s(m_screenMapper, &ScreenMapper::screenMappingChanged);
+    QString file("desktop:/foo%1.txt");
+
+    for (int i = 0 ; i < 3; i++) {
+        const QString name = file.arg(i);
+        m_screenMapper->addMapping(name, i);
+        QCOMPARE(s.count(), i + 1);
+        QCOMPARE(m_screenMapper->screenForItem(name), i);
+    }
+}
+
+void ScreenMapperTest::tst_addRemoveScreenWithItems()
+{
+    const auto path = QStringLiteral("desktop:/");
+    addScreens(path);
+    QString file("desktop:/foo%1.txt");
+
+    for (int i = 0 ; i < 3; i++) {
+        const QString name = file.arg(i);
+        m_screenMapper->addMapping(name, i);
+    }
+
+    // remove one screen
+    m_screenMapper->removeScreen(1, path);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(0)), 0);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(1)), -1);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(2)), 2);
+
+    // add removed screen back, items screen is restored
+    m_screenMapper->addScreen(1, path);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(0)), 0);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(1)), 1);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(2)), 2);
+
+    // remove all screens, firstAvailableScreen changes
+    m_screenMapper->removeScreen(0, path);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), 1);
+    m_screenMapper->removeScreen(1, path);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), 2);
+    m_screenMapper->removeScreen(2, path);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), -1);
+
+
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(0)), -1);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(1)), -1);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(2)), -1);
+
+    // add all screens back, all item's screen is restored
+    addScreens(path);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(0)), 0);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(1)), 1);
+    QCOMPARE(m_screenMapper->screenForItem(file.arg(2)), 2);
+
+    // remove one screen and move its item
+    const QString movedItem = file.arg(1);
+    m_screenMapper->removeScreen(1, path);
+    QCOMPARE(m_screenMapper->screenForItem(movedItem), -1);
+    m_screenMapper->addMapping(movedItem, 0);
+    QCOMPARE(m_screenMapper->screenForItem(movedItem), 0);
+
+    // add back the screen, item goes back to the original place
+    m_screenMapper->addScreen(1, path);
+    QCOMPARE(m_screenMapper->screenForItem(movedItem), 1);
+}
+
+void ScreenMapperTest::tst_addRemoveScreenDifferentPaths()
+{
+    const auto path = QStringLiteral("desktop:/Foo");
+    const auto path2 = QStringLiteral("desktop:/Foo2");
+    m_screenMapper->addScreen(0, path);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path), 0);
+    QCOMPARE(m_screenMapper->firstAvailableScreen(path2), -1);
+
+}
+
+void ScreenMapperTest::addScreens(const QString &path)
+{
+    m_screenMapper->addScreen(0, path);
+    m_screenMapper->addScreen(1, path);
+    m_screenMapper->addScreen(2, path);
+}
diff --git a/containments/desktop/plugins/folder/autotests/foldermodeltest.h b/containments/desktop/plugins/folder/autotests/screenmappertest.h
similarity index 73%
copy from containments/desktop/plugins/folder/autotests/foldermodeltest.h
copy to containments/desktop/plugins/folder/autotests/screenmappertest.h
index c5c4aa71..8e64b468 100644
--- a/containments/desktop/plugins/folder/autotests/foldermodeltest.h
+++ b/containments/desktop/plugins/folder/autotests/screenmappertest.h
@@ -2,6 +2,7 @@
  *   Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company *
  *                      <info at kdab.com>                                    *
  *   Author: Andras Mantia <andras.mantia at kdab.com>                        *
+ *           Work sponsored by the LiMux project of the city of Munich.    *
  *                                                                         *
  *   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  *
@@ -19,39 +20,31 @@
  *   51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA .        *
  ***************************************************************************/
 
-#ifndef FOLDERMODELTEST_H
-#define FOLDERMODELTEST_H
+#ifndef SCREENMAPPERTEST_H
+#define SCREENMAPPERTEST_H
 
 #include <QObject>
 
-class QTemporaryDir;
-class FolderModel;
+class ScreenMapper;
 
-class FolderModelTest : public QObject
+class ScreenMapperTest : public QObject
 {
     Q_OBJECT
 
 private Q_SLOTS:
     void initTestCase();
-    void cleanupTestCase();
-
     void init();
-    void cleanup();
-    void tst_listing();
-    void tst_listingDescending();
-    void tst_listingFolderNotFirst();
-    void tst_filterListing();
-    void tst_cd();
-    void tst_rename_data();
-    void tst_rename();
-    void tst_selection();
-    void tst_defaultValues();
-    void tst_actionMenu();
-    void tst_lockedChanged();
-
-private:    
-    FolderModel *m_folderModel;
-    QTemporaryDir *m_folderDir;
+
+    void tst_addScreens();
+    void tst_removeScreens();
+    void tst_addMapping();
+    void tst_addRemoveScreenWithItems();
+    void tst_addRemoveScreenDifferentPaths();
+
+private:
+    void addScreens(const QString &path);
+
+    ScreenMapper *m_screenMapper;
 };
 
-#endif // FOLDERMODELTEST_H
+#endif // SCREENMAPPERTEST_H
diff --git a/containments/desktop/plugins/folder/foldermodel.cpp b/containments/desktop/plugins/folder/foldermodel.cpp
index 8d1a9b13..ff9dbad3 100644
--- a/containments/desktop/plugins/folder/foldermodel.cpp
+++ b/containments/desktop/plugins/folder/foldermodel.cpp
@@ -24,6 +24,7 @@
 #include "foldermodel.h"
 #include "itemviewadapter.h"
 #include "positioner.h"
+#include "screenmapper.h"
 
 #include <QApplication>
 #include <QClipboard>
@@ -39,6 +40,8 @@
 #include <QPixmap>
 #include <QQuickItem>
 #include <QQuickWindow>
+#include <QTimer>
+#include <QLoggingCategory>
 #include <qplatformdefs.h>
 
 #include <KDirWatch>
@@ -70,10 +73,16 @@
 #include <KProtocolInfo>
 #include <KRun>
 
+#include <Plasma/Applet>
+#include <Plasma/Containment>
+#include <Plasma/Corona>
+
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
+Q_LOGGING_CATEGORY(FOLDERMODEL, "plasma.containments.desktop.folder.foldermodel")
+
 DirLister::DirLister(QObject *parent) : KDirLister(parent)
 {
 }
@@ -96,6 +105,7 @@ FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent),
     m_dirWatch(nullptr),
     m_dragInProgress(false),
     m_urlChangedWhileDragging(false),
+    m_dropTargetPositionsCleanup(new QTimer(this)),
     m_previewGenerator(nullptr),
     m_viewAdapter(nullptr),
     m_actionCollection(this),
@@ -109,7 +119,8 @@ FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent),
     m_parseDesktopFiles(false),
     m_previews(false),
     m_filterMode(NoFilter),
-    m_filterPatternMatchAll(true)
+    m_filterPatternMatchAll(true),
+    m_complete(false)
 {
     //needed to pass the job around with qml
     qmlRegisterType<KIO::DropJob>();
@@ -137,6 +148,44 @@ FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent),
     m_dirModel->setDirLister(dirLister);
     m_dirModel->setDropsAllowed(KDirModel::DropOnDirectory | KDirModel::DropOnLocalExecutable);
 
+    /*
+     * position dropped items at the desired target position
+     * delay this via queued connection, such that the row is available and can be mapped
+     * when we emit the move request
+     */
+    connect(this, &QAbstractItemModel::rowsInserted,
+            this, [this](const QModelIndex &parent, int first, int last) {
+        for (int i = first; i <= last; ++i) {
+            const auto idx = index(i, 0, parent);
+            const auto url = itemForIndex(idx).url();
+            auto it = m_dropTargetPositions.find(url.fileName());
+            if (it != m_dropTargetPositions.end()) {
+                const auto pos = it.value();
+                m_dropTargetPositions.erase(it);
+                setSortMode(-1);
+                emit move(pos.x(), pos.y(), {url});
+            }
+        }
+    });
+    /*
+     * Dropped files may not actually show up as new files, e.g. when we overwrite
+     * an existing file. Or files that fail to be listed by the dirLister, or...
+     * To ensure we don't grow the map indefinitely, clean it up periodically.
+     * The cleanup timer is (re)started whenever we modify the map. We use a quite
+     * high interval of 10s. This should ensure, that we don't accidentally wipe
+     * the mapping when we actually still want to use it. Since the time between
+     * adding an entry in the map and it showing up in the model should be
+     * small, this should rarely, if ever happen.
+     */
+    m_dropTargetPositionsCleanup->setInterval(10000);
+    m_dropTargetPositionsCleanup->setSingleShot(true);
+    connect(m_dropTargetPositionsCleanup, &QTimer::timeout, this, [this]() {
+        if (!m_dropTargetPositions.isEmpty()) {
+            qCDebug(FOLDERMODEL) << "clearing drop target positions after timeout:" << m_dropTargetPositions;
+            m_dropTargetPositions.clear();
+        }
+    });
+
     m_selectionModel = new QItemSelectionModel(this, this);
     connect(m_selectionModel, &QItemSelectionModel::selectionChanged,
             this, &FolderModel::selectionChanged);
@@ -154,6 +203,12 @@ FolderModel::FolderModel(QObject *parent) : QSortFilterProxyModel(parent),
 
 FolderModel::~FolderModel()
 {
+    if (m_screenMapper) {
+        // disconnect so we don't handle signals from the screen mapper when
+        // removeScreen is called
+        m_screenMapper->disconnect(this);
+        m_screenMapper->removeScreen(m_screen, url());
+    }
 }
 
 QHash< int, QByteArray > FolderModel::roleNames() const
@@ -180,6 +235,44 @@ QHash< int, QByteArray > FolderModel::staticRoleNames()
     return roleNames;
 }
 
+void FolderModel::classBegin()
+{
+}
+
+void FolderModel::componentComplete()
+{
+    m_complete = true;
+    invalidate();
+}
+
+void FolderModel::invalidateIfComplete()
+{
+    if (!m_complete) {
+        return;
+    }
+
+    invalidate();
+}
+
+void FolderModel::invalidateFilterIfComplete()
+{
+    if (!m_complete) {
+        return;
+    }
+
+    invalidateFilter();
+}
+
+void FolderModel::newFileMenuItemCreated(const QUrl &url)
+{
+    if (m_screenMapper) {
+        m_screenMapper->addMapping(url.toString(), m_screen, ScreenMapper::DelayedSignal);
+        m_dropTargetPositions.insert(url.fileName(), m_menuPosition);
+        m_menuPosition = {};
+        m_dropTargetPositionsCleanup->start();
+    }
+}
+
 QString FolderModel::url() const
 {
     return m_url;
@@ -194,6 +287,8 @@ void FolderModel::setUrl(const QString& url)
         return;
     }
 
+    const auto oldUrl = m_url;
+
     beginResetModel();
     m_url = url;
     m_isDirCache.clear();
@@ -225,6 +320,11 @@ void FolderModel::setUrl(const QString& url)
     }
 
     emit iconNameChanged();
+
+    if (m_screenMapper) {
+        m_screenMapper->removeScreen(m_screen, oldUrl);
+        m_screenMapper->addScreen(m_screen, url);
+    }
 }
 
 QUrl FolderModel::resolvedUrl() const
@@ -333,7 +433,7 @@ void FolderModel::setSortMode(int mode)
         if (mode == -1 /* Unsorted */) {
             setDynamicSortFilter(false);
         } else {
-            invalidate();
+            invalidateIfComplete();
             sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder);
             setDynamicSortFilter(true);
         }
@@ -353,7 +453,7 @@ void FolderModel::setSortDesc(bool desc)
         m_sortDesc = desc;
 
         if (m_sortMode != -1 /* Unsorted */) {
-            invalidate();
+            invalidateIfComplete();
             sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder);
         }
 
@@ -372,7 +472,7 @@ void FolderModel::setSortDirsFirst(bool enable)
         m_sortDirsFirst = enable;
 
         if (m_sortMode != -1 /* Unsorted */) {
-            invalidate();
+            invalidateIfComplete();
             sort(m_sortMode, m_sortDesc ? Qt::DescendingOrder : Qt::AscendingOrder);
         }
 
@@ -463,7 +563,7 @@ void FolderModel::setFilterMode(int filterMode)
     if (m_filterMode != (FilterMode)filterMode) {
         m_filterMode = (FilterMode)filterMode;
 
-        invalidateFilter();
+        invalidateFilterIfComplete();
 
         emit filterModeChanged();
     }
@@ -494,7 +594,7 @@ void FolderModel::setFilterPattern(const QString &pattern)
         m_regExps.append(rx);
     }
 
-    invalidateFilter();
+    invalidateFilterIfComplete();
 
     emit filterPatternChanged();
 }
@@ -512,12 +612,24 @@ void FolderModel::setFilterMimeTypes(const QStringList &mimeList)
 
         m_mimeSet = set;
 
-        invalidateFilter();
+        invalidateFilterIfComplete();
 
         emit filterMimeTypesChanged();
     }
 }
 
+void FolderModel::setScreen(int screen)
+{
+    if (m_screen == screen)
+        return;
+
+    m_screen = screen;
+    if (m_usedByContainment && m_screenMapper) {
+        m_screenMapper->addScreen(screen, url());
+    }
+    emit screenChanged();
+}
+
 KFileItem FolderModel::rootItem() const
 {
     return m_dirModel->dirLister()->rootItem();
@@ -762,7 +874,7 @@ QPoint FolderModel::dragCursorOffset(int row)
 {
     DragImage *image = m_dragImages.value(row);
     if (!image) {
-        return QPoint(-1, -1);
+        return QPoint(0, 0);
     }
 
     return image->cursorOffset;
@@ -884,6 +996,16 @@ void FolderModel::dragSelectedInternal(int x, int y)
     }
 }
 
+static bool isDropBetweenSharedViews(const QList<QUrl> &urls, const QUrl &folderUrl)
+{
+    for (const auto &url : urls) {
+        if (folderUrl != url.adjusted(QUrl::RemoveFilename)) {
+            return false;
+        }
+    }
+    return true;
+}
+
 void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row)
 {
     QMimeData *mimeData = qobject_cast<QMimeData *>(dropEvent->property("mimeData").value<QObject *>());
@@ -892,19 +1014,6 @@ void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row)
         return;
     }
 
-    if (m_dragInProgress && row == -1 && !m_urlChangedWhileDragging) {
-        if (m_locked || mimeData->urls().isEmpty()) {
-            return;
-        }
-
-        setSortMode(-1);
-
-        emit move(dropEvent->property("x").toInt(), dropEvent->property("y").toInt(),
-            mimeData->urls());
-
-        return;
-    }
-
     QModelIndex idx;
     KFileItem item;
 
@@ -934,6 +1043,50 @@ void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row)
         dropTargetUrl = item.mostLocalUrl();
     }
 
+    auto dropTargetFolderUrl = dropTargetUrl;
+    if (dropTargetFolderUrl.fileName() == QLatin1String(".")) {
+        // the target URL for desktop:/ is e.g. 'file://home/user/Desktop/.'
+        dropTargetFolderUrl = dropTargetFolderUrl.adjusted(QUrl::RemoveFilename);
+    }
+
+    // use dropTargetUrl to resolve desktop:/ to the actual file location which is also used by the mime data
+    /* QMimeData operates on local URLs, but the dir lister and thus screen mapper and positioner may
+     * use a fancy scheme like desktop:/ instead. Ensure we always use the latter to properly map URLs,
+     * i.e. go from file:///home/user/Desktop/file to desktop:/file
+     */
+    auto mappableUrl = [this, dropTargetFolderUrl](const QUrl &url) -> QString {
+        QString mappedUrl = url.toString();
+        if (dropTargetFolderUrl != m_dirModel->dirLister()->url()) {
+            const auto local = dropTargetFolderUrl.toString();
+            const auto internal = m_dirModel->dirLister()->url().toString();
+            if (mappedUrl.startsWith(local)) {
+                mappedUrl.replace(0, local.size(), internal);
+            }
+        }
+        return mappedUrl;
+    };
+
+    const int x = dropEvent->property("x").toInt();
+    const int y = dropEvent->property("y").toInt();
+    const QPoint dropPos = {x, y};
+
+    if (m_dragInProgress && row == -1 && !m_urlChangedWhileDragging) {
+        if (m_locked || mimeData->urls().isEmpty()) {
+            return;
+        }
+
+        setSortMode(-1);
+
+        for (const auto &url : mimeData->urls()) {
+            m_dropTargetPositions.insert(url.fileName(), dropPos);
+            m_screenMapper->addMapping(mappableUrl(url), m_screen, ScreenMapper::DelayedSignal);
+            m_screenMapper->removeItemFromDisabledScreen(mappableUrl(url));
+        }
+        emit move(x, y, mimeData->urls());
+
+        return;
+    }
+
     if (mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-service")) &&
         mimeData->hasFormat(QStringLiteral("application/x-kde-ark-dndextract-path"))) {
         const QString remoteDBusClient = mimeData->data(QStringLiteral("application/x-kde-ark-dndextract-service"));
@@ -954,25 +1107,34 @@ void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row)
         return;
     }
 
-    QPoint pos;
-    pos.setX(dropEvent->property("x").toInt());
-    pos.setY(dropEvent->property("y").toInt());
 
-    pos = target->mapToScene(pos).toPoint();
-    pos = target->window()->mapToGlobal(pos);
+    if (m_usedByContainment) {
+        if (isDropBetweenSharedViews(mimeData->urls(), dropTargetFolderUrl)) {
+            setSortMode(-1);
+            if (m_screenMapper) {
+                for (const auto &url : mimeData->urls()) {
+                    m_dropTargetPositions.insert(url.fileName(), dropPos);
+                    m_screenMapper->addMapping(mappableUrl(url), m_screen, ScreenMapper::DelayedSignal);
+                    m_screenMapper->removeItemFromDisabledScreen(mappableUrl(url));
+                }
+            }
+            m_dropTargetPositionsCleanup->start();
+            return;
+        }
+    }
 
     Qt::DropAction proposedAction((Qt::DropAction)dropEvent->property("proposedAction").toInt());
     Qt::DropActions possibleActions(dropEvent->property("possibleActions").toInt());
     Qt::MouseButtons buttons(dropEvent->property("buttons").toInt());
     Qt::KeyboardModifiers modifiers(dropEvent->property("modifiers").toInt());
 
+    auto pos = target->mapToScene(dropPos).toPoint();
+    pos = target->window()->mapToGlobal(pos);
     QDropEvent ev(pos, possibleActions, mimeData, buttons, modifiers);
     ev.setDropAction(proposedAction);
 
     KIO::DropJob *dropJob = KIO::drop(&ev, dropTargetUrl);
     dropJob->uiDelegate()->setAutoErrorHandlingEnabled(true);
-    const int x = dropEvent->property("x").toInt();
-    const int y = dropEvent->property("y").toInt();
 
     // The QMimeData we extract from the DropArea's drop event is deleted as soon as this method
     // ends but we need to keep a copy for when popupMenuAboutToShow fires.
@@ -981,10 +1143,52 @@ void FolderModel::drop(QQuickItem *target, QObject* dropEvent, int row)
         mimeCopy->setData(format, mimeData->data(format));
     }
 
-    connect(dropJob, static_cast<void(KIO::DropJob::*)(const KFileItemListProperties &)>(&KIO::DropJob::popupMenuAboutToShow), this, [this, mimeCopy, x, y, dropJob](const KFileItemListProperties &) {
+    connect(dropJob, &KIO::DropJob::popupMenuAboutToShow, this, [this, mimeCopy, x, y, dropJob](const KFileItemListProperties &) {
         emit popupMenuAboutToShow(dropJob, mimeCopy, x, y);
         mimeCopy->deleteLater();
     });
+
+    /*
+     * Position files that come from a drag'n'drop event at the drop event
+     * target position. To do so, we first listen to copy job to figure out
+     * the target URL. Then we store the position of this drop event in the
+     * hash and eventually trigger a move request when we get notified about
+     * the new file event from the source model.
+     */
+    connect(dropJob, &KIO::DropJob::copyJobStarted, this, [this, dropPos, dropTargetUrl](KIO::CopyJob* copyJob) {
+        auto map = [this, dropPos, dropTargetUrl](const QUrl &targetUrl) {
+            m_dropTargetPositions.insert(targetUrl.fileName(), dropPos);
+            m_dropTargetPositionsCleanup->start();
+
+            if (m_usedByContainment && m_screenMapper) {
+                // assign a screen for the item before the copy is actually done, so
+                // filterAcceptsRow doesn't assign the default screen to it
+                QUrl url = QUrl::fromUserInput(m_url, {}, QUrl::AssumeLocalFile);
+                // if the folderview's folder is a standard path, just use the targetUrl for mapping
+                if (targetUrl.toString().startsWith(url.toString())) {
+                    m_screenMapper->addMapping(targetUrl.toString(), m_screen, ScreenMapper::DelayedSignal);
+                } else if (targetUrl.toString().startsWith(dropTargetUrl.toString())) {
+                    // if the folderview's folder is a special path, like desktop:// , we need to convert
+                    // the targetUrl file:// path to a desktop:/ path for mapping
+                    auto destPath = dropTargetUrl.path();
+                    auto filePath = targetUrl.path();
+                    if (filePath.startsWith(destPath)) {
+                        url.setPath(filePath.remove(0, destPath.length()));
+                        m_screenMapper->addMapping(url.toString(), m_screen, ScreenMapper::DelayedSignal);
+                    }
+                }
+            }
+        };
+        // remember drop target position for target URL and forget about the source URL
+        connect(copyJob, &KIO::CopyJob::copyingDone,
+                this, [this, map](KIO::Job *, const QUrl &, const QUrl &targetUrl, const QDateTime &, bool, bool) {
+            map(targetUrl);
+        });
+        connect(copyJob, &KIO::CopyJob::copyingLinkDone,
+                this, [this, map](KIO::Job *, const QUrl &, const QString &, const QUrl &targetUrl) {
+            map(targetUrl);
+        });
+    });
 }
 
 void FolderModel::dropCwd(QObject* dropEvent)
@@ -1165,6 +1369,9 @@ void FolderModel::statResult(KJob *job)
 void FolderModel::evictFromIsDirCache(const KFileItemList& items)
 {
     foreach (const KFileItem &item, items) {
+        if (m_screenMapper) {
+            m_screenMapper->removeFromMap(item.url().toString());
+        }
         m_isDirCache.remove(item.url());
     }
 }
@@ -1286,13 +1493,34 @@ inline bool FolderModel::matchPattern(const KFileItem &item) const
 
 bool FolderModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
 {
+    const KDirModel *dirModel = static_cast<KDirModel*>(sourceModel());
+    const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent));
+
+    if (m_usedByContainment && m_screenMapper) {
+        const QString name = item.url().toString();
+        const int screen = m_screenMapper->screenForItem(name);
+        // don't do anything if the folderview is not associated with a screen
+        if (m_screen != -1) {
+            if (screen == -1) {
+                // The item is not associated with a screen, probably because this is the first
+                // time we see it or the folderview was previously used as a regular applet.
+                // Associated with this folderview if the view is on the first available screen
+                if (m_screen == m_screenMapper->firstAvailableScreen(url())) {
+                    m_screenMapper->addMapping(name, m_screen, ScreenMapper::DelayedSignal);
+                } else {
+                    return false;
+                }
+            } else if (m_screen != screen) {
+                // the item belongs to a different screen, filter it out
+                return false;
+            }
+        }
+    }
+
     if (m_filterMode == NoFilter) {
         return true;
     }
 
-    const KDirModel *dirModel = static_cast<KDirModel*>(sourceModel());
-    const KFileItem item = dirModel->itemForIndex(dirModel->index(sourceRow, KDirModel::Name, sourceParent));
-
     if (m_filterMode == FilterShowMatches) {
         return (matchPattern(item) && matchMimeType(item));
     } else {
@@ -1356,6 +1584,8 @@ void FolderModel::createActions()
 
     m_newMenu = new KNewFileMenu(&m_actionCollection, QStringLiteral("newMenu"), QApplication::desktop());
     m_newMenu->setModal(false);
+    connect(m_newMenu, &KNewFileMenu::directoryCreated, this, &FolderModel::newFileMenuItemCreated);
+    connect(m_newMenu, &KNewFileMenu::fileCreated, this, &FolderModel::newFileMenuItemCreated);
 
     m_copyToMenu = new KFileCopyToMenu(nullptr);
 }
@@ -1375,6 +1605,8 @@ void FolderModel::updateActions()
     if (m_newMenu) {
         m_newMenu->checkUpToDate();
         m_newMenu->setPopupFiles(m_dirModel->dirLister()->url());
+        // we need to set here as well, when the menu is shown via AppletInterface::eventFilter
+        m_menuPosition = QCursor::pos();
     }
 
     const bool isTrash = (resolvedUrl().scheme() == QLatin1String("trash"));
@@ -1548,10 +1780,11 @@ void FolderModel::openContextMenu(QQuickItem *visualParent)
     }
 
     if (visualParent) {
-        menu->popup(visualParent->mapToGlobal(QPointF(0, visualParent->height())).toPoint());
+        m_menuPosition = visualParent->mapToGlobal(QPointF(0, visualParent->height())).toPoint();
     } else {
-        menu->popup(QCursor::pos());
+        m_menuPosition = QCursor::pos();
     }
+    menu->popup(m_menuPosition);
     connect(menu, &QMenu::aboutToHide, [menu]() { menu->deleteLater(); });
 }
 
@@ -1620,6 +1853,66 @@ void FolderModel::refresh()
     m_dirModel->dirLister()->updateDirectory(m_dirModel->dirLister()->url());
 }
 
+ScreenMapper *FolderModel::screenMapper() const
+{
+    return m_screenMapper;
+}
+
+void FolderModel::setScreenMapper(ScreenMapper *screenMapper)
+{
+    if (m_screenMapper == screenMapper)
+        return;
+
+    Q_ASSERT(!m_screenMapper);
+
+    if (m_screenMapper) {
+        m_screenMapper->disconnect(this);
+    }
+
+    m_screenMapper = screenMapper;
+    if (m_screenMapper) {
+        connect(m_screenMapper, &ScreenMapper::screensChanged, this, &FolderModel::invalidateFilterIfComplete);
+        connect(m_screenMapper, &ScreenMapper::screenMappingChanged, this, &FolderModel::invalidateFilterIfComplete);
+    }
+
+    invalidateFilterIfComplete();
+    emit screenMapperChanged();
+}
+
+QObject *FolderModel::appletInterface() const
+{
+    return m_appletInterface;
+}
+
+void FolderModel::setAppletInterface(QObject *appletInterface)
+{
+    if (m_appletInterface != appletInterface) {
+        Q_ASSERT(!m_appletInterface);
+
+        m_appletInterface = appletInterface;
+
+        if (appletInterface) {
+            Plasma::Applet *applet = appletInterface->property("_plasma_applet").value<Plasma::Applet *>();
+
+            if (applet) {
+                Plasma::Containment *containment = applet->containment();
+
+                if (containment) {
+                    Plasma::Corona *corona = containment->corona();
+
+                    if (corona && m_screenMapper) {
+                        m_screenMapper->setCorona(corona);
+                    }
+                    setScreen(containment->screen());
+                    connect(containment, &Plasma::Containment::screenChanged, this, &FolderModel::setScreen);
+                }
+            }
+        }
+
+        emit appletInterfaceChanged();
+    }
+}
+
 void FolderModel::moveSelectedToTrash()
 {
     if (!m_selectionModel->hasSelection()) {
diff --git a/containments/desktop/plugins/folder/foldermodel.h b/containments/desktop/plugins/folder/foldermodel.h
index 86b776b9..4557ac4c 100644
--- a/containments/desktop/plugins/folder/foldermodel.h
+++ b/containments/desktop/plugins/folder/foldermodel.h
@@ -24,6 +24,7 @@
 
 #include <QImage>
 #include <QItemSelection>
+#include <QQmlParserStatus>
 #include <QPointer>
 #include <QSortFilterProxyModel>
 #include <QStringList>
@@ -56,6 +57,8 @@ namespace KIO {
     class DropJob;
 }
 
+class ScreenMapper;
+
 class DirLister : public KDirLister
 {
     Q_OBJECT
@@ -71,9 +74,10 @@ class DirLister : public KDirLister
         void handleError(KIO::Job *job) override;
 };
 
-class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
+class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel, public QQmlParserStatus
 {
     Q_OBJECT
+    Q_INTERFACES(QQmlParserStatus)
 
     Q_PROPERTY(QString url READ url WRITE setUrl NOTIFY urlChanged)
     Q_PROPERTY(QString iconName READ iconName NOTIFY iconNameChanged)
@@ -94,6 +98,8 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
     Q_PROPERTY(QString filterPattern READ filterPattern WRITE setFilterPattern NOTIFY filterPatternChanged)
     Q_PROPERTY(QStringList filterMimeTypes READ filterMimeTypes WRITE setFilterMimeTypes NOTIFY filterMimeTypesChanged)
     Q_PROPERTY(QObject* newMenu READ newMenu CONSTANT)
+    Q_PROPERTY(ScreenMapper* screenMapper READ screenMapper WRITE setScreenMapper NOTIFY screenMapperChanged)
+    Q_PROPERTY(QObject* appletInterface READ appletInterface WRITE setAppletInterface NOTIFY appletInterfaceChanged);
 
     public:
         enum DataRole {
@@ -130,6 +136,9 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         QHash<int, QByteArray> roleNames() const override;
         static QHash<int, QByteArray> staticRoleNames();
 
+        void classBegin() override;
+        void componentComplete() override;
+
         QString url() const;
         void setUrl(const QString &url);
 
@@ -180,6 +189,12 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         QStringList filterMimeTypes() const;
         void setFilterMimeTypes(const QStringList &mimeList);
 
+        ScreenMapper* screenMapper() const;
+        void setScreenMapper(ScreenMapper* screenMapper);
+
+        QObject *appletInterface() const;
+        void setAppletInterface(QObject *appletInterface);
+
         KFileItem rootItem() const;
 
         Q_INVOKABLE void up();
@@ -233,6 +248,8 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         Q_INVOKABLE void undo();
         Q_INVOKABLE void refresh();
 
+        void setScreen(int screen);
+
     Q_SIGNALS:
         void urlChanged() const;
         void listingCompleted() const;
@@ -254,6 +271,9 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         void filterModeChanged() const;
         void filterPatternChanged() const;
         void filterMimeTypesChanged() const;
+        void screenChanged() const;
+        void screenMapperChanged() const;
+        void appletInterfaceChanged() const;
         void requestRename() const;
         void move(int x, int y, QList<QUrl> urls);
         void popupMenuAboutToShow(KIO::DropJob *dropJob, QMimeData *mimeData, int x, int y);
@@ -274,6 +294,9 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         void emptyTrashBin();
         void restoreSelectedFromTrash();
         void undoTextChanged(const QString &text);
+        void invalidateIfComplete();
+        void invalidateFilterIfComplete();
+        void newFileMenuItemCreated(const QUrl &url);
 
     private:
         struct DragImage {
@@ -300,6 +323,10 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         QPoint m_dragHotSpotScrollOffset;
         bool m_dragInProgress;
         bool m_urlChangedWhileDragging;
+        // target filename to target position of a drop event, note that this deliberately
+        // is not using the URL to easily support desktop:/ URL schemes
+        QHash<QString, QPoint> m_dropTargetPositions;
+        QTimer *m_dropTargetPositionsCleanup;
         QPointer<KFilePreviewGenerator> m_previewGenerator;
         QPointer<KAbstractViewAdapter> m_viewAdapter;
         KActionCollection m_actionCollection;
@@ -321,6 +348,11 @@ class FOLDERPLUGIN_TESTS_EXPORT FolderModel : public QSortFilterProxyModel
         bool m_filterPatternMatchAll;
         QSet<QString> m_mimeSet;
         QList<QRegExp> m_regExps;
+        int m_screen = -1;
+        ScreenMapper *m_screenMapper = nullptr;
+        QObject *m_appletInterface = nullptr;
+        bool m_complete;
+        QPoint m_menuPosition;
 };
 
 #endif
diff --git a/containments/desktop/plugins/folder/folderplugin.cpp b/containments/desktop/plugins/folder/folderplugin.cpp
index 0624fdd6..0961c7de 100644
--- a/containments/desktop/plugins/folder/folderplugin.cpp
+++ b/containments/desktop/plugins/folder/folderplugin.cpp
@@ -32,7 +32,10 @@
 #include "viewpropertiesmenu.h"
 #include "wheelinterceptor.h"
 #include "shortcut.h"
+#include "screenmapper.h"
 
+#include <QQmlContext>
+#include <QQmlEngine>
 
 static QObject *menuHelperSingletonProvider(QQmlEngine *engine, QJSEngine *jsEngine)
 {
@@ -41,6 +44,16 @@ static QObject *menuHelperSingletonProvider(QQmlEngine *engine, QJSEngine *jsEng
     return new MenuHelper();
 }
 
+static QObject *screenMapperProvider(QQmlEngine *engine, QJSEngine *scriptEngine)
+{
+    Q_UNUSED(scriptEngine);
+
+    QObject *mapper = ScreenMapper::instance();
+    engine->setObjectOwnership(mapper, QQmlEngine::CppOwnership);
+    return mapper;
+}
+
+
 void FolderPlugin::registerTypes(const char *uri)
 {
     Q_ASSERT(uri == QLatin1String("org.kde.private.desktopcontainment.folder"));
@@ -58,5 +71,6 @@ void FolderPlugin::registerTypes(const char *uri)
     qmlRegisterType<ViewPropertiesMenu>(uri, 0, 1, "ViewPropertiesMenu");
     qmlRegisterType<WheelInterceptor>(uri, 0, 1, "WheelInterceptor");
     qmlRegisterType<ShortCut>(uri, 0, 1, "ShortCut");
+    qmlRegisterSingletonType<ScreenMapper>(uri, 0, 1, "ScreenMapper", screenMapperProvider);
 }
 
diff --git a/containments/desktop/plugins/folder/mimetypesmodel.cpp b/containments/desktop/plugins/folder/mimetypesmodel.cpp
index 3254396e..6701e1f0 100644
--- a/containments/desktop/plugins/folder/mimetypesmodel.cpp
+++ b/containments/desktop/plugins/folder/mimetypesmodel.cpp
@@ -42,7 +42,8 @@ MimeTypesModel::~MimeTypesModel()
 QHash<int, QByteArray> MimeTypesModel::roleNames() const
 {
     return {
-        { Qt::DisplayRole, "display" },
+        { Qt::DisplayRole, "comment" },
+        { Qt::UserRole, "name" },
         { Qt::DecorationRole, "decoration" },
         { Qt::CheckStateRole, "checked" }
     };
@@ -56,6 +57,8 @@ QVariant MimeTypesModel::data(const QModelIndex &index, int role) const
 
     switch (role) {
         case Qt::DisplayRole:
+            return m_mimeTypesList.at(index.row()).comment();
+        case Qt::UserRole:
             return m_mimeTypesList.at(index.row()).name();
 
         case Qt::DecorationRole:
diff --git a/containments/desktop/plugins/folder/positioner.cpp b/containments/desktop/plugins/folder/positioner.cpp
index ee45f502..258a1ca2 100644
--- a/containments/desktop/plugins/folder/positioner.cpp
+++ b/containments/desktop/plugins/folder/positioner.cpp
@@ -399,7 +399,10 @@ void Positioner::move(const QVariantList &moves) {
         }
 
         if (!fromIndices.contains(to) && !isBlank(to)) {
-            continue;
+            // find the next blank space
+            while (!isBlank(to) &&  from != to) {
+                to++;
+            }
         }
 
         toIndices[i] = to;
@@ -422,6 +425,10 @@ void Positioner::move(const QVariantList &moves) {
     const int newCount = rowCount();
 
     if (newCount > oldCount) {
+        if (m_beginInsertRowsCalled) {
+            endInsertRows();
+            m_beginInsertRowsCalled = false;
+        }
         beginInsertRows(QModelIndex(), oldCount, newCount - 1);
         endInsertRows();
     }
@@ -507,7 +514,8 @@ void Positioner::sourceRowsAboutToBeInserted(const QModelIndex &parent, int star
     if (m_enabled) {
         if (m_proxyToSource.isEmpty()) {
             if (!m_pendingPositions) {
-                emit beginInsertRows(parent, start, end);
+                beginInsertRows(parent, start, end);
+                m_beginInsertRowsCalled = true;
 
                 initMaps(end + 1);
             }
@@ -515,6 +523,19 @@ void Positioner::sourceRowsAboutToBeInserted(const QModelIndex &parent, int star
             return;
         }
 
+        // When new rows are inserted, they might go in the beginning or in the middle.
+        // In this case we must update first the existing proxy->source and source->proxy
+        // mapping, otherwise the proxy items will point to the wrong source item.
+        int count = end - start + 1;
+        m_sourceToProxy.clear();
+        for (auto it = m_proxyToSource.begin(); it != m_proxyToSource.end(); ++it) {
+            int sourceIdx = *it;
+            if (sourceIdx >= start) {
+                *it += count;
+            }
+            m_sourceToProxy[*it] = it.key();
+        }
+
         int free = -1;
         int rest = -1;
 
@@ -535,6 +556,7 @@ void Positioner::sourceRowsAboutToBeInserted(const QModelIndex &parent, int star
             int remainder = (end - rest);
 
             beginInsertRows(parent, firstNew, firstNew + remainder);
+            m_beginInsertRowsCalled = true;
 
             for (int i = 0; i <= remainder; ++i) {
                 updateMaps(firstNew + i, rest + i);
@@ -544,6 +566,8 @@ void Positioner::sourceRowsAboutToBeInserted(const QModelIndex &parent, int star
         }
     } else {
         emit beginInsertRows(parent, start, end);
+        beginInsertRows(parent, start, end);
+        m_beginInsertRowsCalled = true;
     }
 }
 
@@ -614,7 +638,10 @@ void Positioner::sourceRowsInserted(const QModelIndex &parent, int first, int la
 
     if (!m_ignoreNextTransaction) {
         if (!m_pendingPositions) {
-            emit endInsertRows();
+            if (m_beginInsertRowsCalled) {
+                endInsertRows();
+                m_beginInsertRowsCalled = false;
+            }
         } else {
             applyPositions();
         }
diff --git a/containments/desktop/plugins/folder/positioner.h b/containments/desktop/plugins/folder/positioner.h
index e9c0ae05..7a175657 100644
--- a/containments/desktop/plugins/folder/positioner.h
+++ b/containments/desktop/plugins/folder/positioner.h
@@ -76,6 +76,15 @@ class FOLDERPLUGIN_TESTS_EXPORT Positioner : public QAbstractItemModel
         int rowCount(const QModelIndex &parent = QModelIndex()) const override;
         int columnCount(const QModelIndex &parent = QModelIndex()) const override;
 
+#ifdef BUILD_TESTING
+        QHash<int, int> proxyToSourceMapping() const {
+            return m_proxyToSource;
+        }
+        QHash<int, int> sourceToProxyMapping() const {
+            return m_sourceToProxy;
+        }
+#endif
+
     Q_SIGNALS:
         void enabledChanged() const;
         void folderModelChanged() const;
@@ -128,6 +137,7 @@ class FOLDERPLUGIN_TESTS_EXPORT Positioner : public QAbstractItemModel
 
         QHash<int, int> m_proxyToSource;
         QHash<int, int> m_sourceToProxy;
+        bool m_beginInsertRowsCalled = false; // used to sync the amount of begin/endInsertRows calls
 };
 
 #endif
diff --git a/containments/desktop/plugins/folder/screenmapper.cpp b/containments/desktop/plugins/folder/screenmapper.cpp
new file mode 100644
index 00000000..f99cbbb7
--- /dev/null
+++ b/containments/desktop/plugins/folder/screenmapper.cpp
@@ -0,0 +1,255 @@
+/***************************************************************************
+ *   Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company *
+ *                      <info at kdab.com>                                    *
+ *   Author: Andras Mantia <andras.mantia at kdab.com>                        *
+ *           Work sponsored by the LiMux project of the city of Munich.    *
+ *   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 "screenmapper.h"
+
+#include <QScreen>
+#include <QTimer>
+
+#include <Plasma/Corona>
+#include <KConfig>
+#include <KConfigGroup>
+
+ScreenMapper *ScreenMapper::instance()
+{
+    static ScreenMapper *s_instance = new ScreenMapper();
+    return s_instance;
+}
+
+ScreenMapper::ScreenMapper(QObject *parent)
+    : QObject(parent)
+    , m_screenMappingChangedTimer(new QTimer(this))
+
+{
+    connect(m_screenMappingChangedTimer, &QTimer::timeout,
+            this, &ScreenMapper::screenMappingChanged);
+
+    connect(this, &ScreenMapper::screenMappingChanged, this, [this] {
+       if (!m_corona)
+           return;
+
+       auto config = m_corona->config();
+       KConfigGroup group(config, QLatin1String("ScreenMapping"));
+       group.writeEntry(QLatin1String("screenMapping"), screenMapping());
+       config->sync();
+    });
+
+    // used to compress screenMappingChanged signals when addMapping is called multiple times,
+    // eg. from FolderModel::filterAcceptRows. The timer interval is an arbitrary number,
+    // that doesn't delay too much the signal, but still compresses as much as possible
+    m_screenMappingChangedTimer->setInterval(100);
+    m_screenMappingChangedTimer->setSingleShot(true);
+}
+
+void ScreenMapper::removeScreen(int screenId, const QString &path)
+{
+    if (screenId < 0 || !m_availableScreens.contains(screenId))
+        return;
+
+    QUrl screenUrl = QUrl::fromUserInput(path, {}, QUrl::AssumeLocalFile);
+    const auto screenPathWithScheme = screenUrl.url();
+    // store the original location for the items
+    auto it = m_screenItemMap.constBegin();
+    while (it != m_screenItemMap.constEnd()) {
+        const auto name = it.key();
+        if (it.value() == screenId && name.startsWith(screenPathWithScheme)) {
+            m_itemsOnDisabledScreensMap[screenId].append(name);
+        }
+        ++it;
+    }
+
+    m_availableScreens.removeAll(screenId);
+
+    const auto newFirstScreen = std::min_element(m_availableScreens.constBegin(), m_availableScreens.constEnd());
+    auto pathIt = m_screensPerPath.find(path);
+    if (pathIt != m_screensPerPath.end() && pathIt.value() > 0) {
+        int firstScreen = m_firstScreenForPath.value(path, -1);
+        if (firstScreen == screenId) {
+            m_firstScreenForPath[path] = (newFirstScreen == m_availableScreens.constEnd()) ? -1 : *newFirstScreen;
+        }
+        *pathIt = pathIt.value() - 1;
+    } else if (path.isEmpty()) {
+        // The screen got completely removed, not only its path changed.
+        // If the removed screen was the first screen for a desktop path, the first screen for that path
+        // needs to be updated.
+        for (auto it = m_firstScreenForPath.begin(); it != m_firstScreenForPath.end(); ++it) {
+            if (*it == screenId) {
+                *it = *newFirstScreen;
+
+                // we have now the path for the screen that was removed, so adjust it
+                pathIt = m_screensPerPath.find(it.key());
+                if (pathIt != m_screensPerPath.end()) {
+                    *pathIt = pathIt.value() - 1;
+                }
+            }
+        }
+    }
+
+    emit screensChanged();
+}
+
+void ScreenMapper::addScreen(int screenId, const QString &path)
+{
+    if (screenId < 0 || m_availableScreens.contains(screenId))
+        return;
+
+    QUrl screenUrl = QUrl::fromUserInput(path, {}, QUrl::AssumeLocalFile);
+    const auto screenPathWithScheme = screenUrl.url();
+    const bool isEmpty = (path.isEmpty() || screenUrl.path() == "/");
+    // restore the stored locations
+    auto it = m_itemsOnDisabledScreensMap.find(screenId);
+    if (it != m_itemsOnDisabledScreensMap.end()) {
+        auto items = it.value();
+        for (const auto &name: it.value()) {
+            // add the items to the new screen, if they are on a disabled screen and their
+            // location is below the new screen's path
+            if (isEmpty || name.startsWith(screenPathWithScheme)) {
+                addMapping(name, screenId, DelayedSignal);
+                items.removeAll(name);
+            }
+        }
+        if (items.isEmpty()) {
+            m_itemsOnDisabledScreensMap.erase(it);
+        } else {
+            *it = items;
+        }
+    }
+
+    m_availableScreens.append(screenId);
+
+    // path is empty when a new screen appears that has no folderview base path associated with
+    if (!path.isEmpty()) {
+        auto it = m_screensPerPath.find(path);
+        int firstScreen = m_firstScreenForPath.value(path, -1);
+        if (firstScreen == -1 || screenId < firstScreen) {
+            m_firstScreenForPath[path] = screenId;
+        }
+        if (it == m_screensPerPath.end()) {
+            m_screensPerPath[path] = 1;
+        } else {
+            *it = it.value() + 1;
+        }
+    }
+
+    emit screensChanged();
+}
+
+void ScreenMapper::addMapping(const QString &name, int screen, MappingSignalBehavior behavior)
+{
+    m_screenItemMap[name] = screen;
+    if (behavior == DelayedSignal) {
+        m_screenMappingChangedTimer->start();
+    } else {
+        emit screenMappingChanged();
+    }
+}
+
+void ScreenMapper::removeFromMap(const QString &name)
+{
+    m_screenItemMap.remove(name);
+    m_screenMappingChangedTimer->start();
+}
+
+int ScreenMapper::firstAvailableScreen(const QString &path) const
+{
+    return m_firstScreenForPath.value(path, -1);
+}
+
+void ScreenMapper::removeItemFromDisabledScreen(const QString &name)
+{
+    for (auto it = m_itemsOnDisabledScreensMap.begin();
+         it != m_itemsOnDisabledScreensMap.end(); ++it) {
+        auto names = &(*it);
+        names->removeAll(name);
+    }
+}
+
+#ifdef BUILD_TESTING
+void ScreenMapper::cleanup()
+{
+    m_screenItemMap.clear();
+    m_itemsOnDisabledScreensMap.clear();
+    m_firstScreenForPath.clear();
+    m_screensPerPath.clear();
+    m_availableScreens.clear();
+}
+#endif
+
+void ScreenMapper::setCorona(Plasma::Corona *corona)
+{
+    if (m_corona != corona) {
+        Q_ASSERT(!m_corona);
+
+        m_corona = corona;
+        if (m_corona) {
+            connect(m_corona, &Plasma::Corona::screenRemoved, this, [this] (int screenId) {
+                removeScreen(screenId, {});
+            });
+            connect(m_corona, &Plasma::Corona::screenAdded, this, [this] (int screenId) {
+                addScreen(screenId, {});
+            });
+
+            auto config = m_corona->config();
+            KConfigGroup group(config, QLatin1String("ScreenMapping"));
+            const QStringList mapping = group.readEntry(QLatin1String("screenMapping"), QStringList{});
+            setScreenMapping(mapping);
+        }
+    }
+}
+
+QStringList ScreenMapper::screenMapping() const
+{
+    QStringList result;
+    result.reserve(m_screenItemMap.count() * 2);
+    auto it = m_screenItemMap.constBegin();
+    while (it != m_screenItemMap.constEnd()) {
+        result.append(it.key());
+        result.append(QString::number(it.value()));
+        ++it;
+    }
+
+    return result;
+}
+
+void ScreenMapper::setScreenMapping(const QStringList &mapping)
+{
+    QHash<QString, int> newMap;
+    const int count = mapping.count();
+    newMap.reserve(count / 2);
+    for (int i = 0; i < count - 1; i += 2) {
+        if (i + 1 < count) {
+            newMap[mapping[i]] = mapping[i + 1].toInt();
+        }
+    }
+
+    if (m_screenItemMap != newMap) {
+        m_screenItemMap = newMap;
+        emit screenMappingChanged();
+    }
+}
+
+int ScreenMapper::screenForItem(const QString &name) const
+{
+    int screen = m_screenItemMap.value(name, -1);
+    if (!m_availableScreens.contains(screen))
+        screen = -1;
+
+    return screen;
+}
diff --git a/containments/desktop/plugins/folder/screenmapper.h b/containments/desktop/plugins/folder/screenmapper.h
new file mode 100644
index 00000000..afb55af1
--- /dev/null
+++ b/containments/desktop/plugins/folder/screenmapper.h
@@ -0,0 +1,84 @@
+/***************************************************************************
+ *   Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group company *
+ *                      <info at kdab.com>                                    *
+ *   Author: Andras Mantia <andras.mantia at kdab.com>                        *
+ *           Work sponsored by the LiMux project of the city of Munich.    *
+ *                                                                         *
+ *   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 SCREENMAPPER_H
+#define SCREENMAPPER_H
+
+#include <QObject>
+#include <QVariantHash>
+#include <QVector>
+
+#include "folderplugin_private_export.h"
+
+class QTimer;
+
+namespace Plasma {
+    class Corona;
+}
+
+class FOLDERPLUGIN_TESTS_EXPORT ScreenMapper : public QObject
+{
+    Q_OBJECT
+    Q_PROPERTY(QStringList screenMapping READ screenMapping WRITE setScreenMapping NOTIFY screenMappingChanged)
+
+public:
+    enum MappingSignalBehavior {
+        DelayedSignal = 0,
+        ImmediateSignal
+    };
+
+    static ScreenMapper *instance();
+    ~ScreenMapper() override = default;
+
+    QStringList screenMapping() const;
+    void setScreenMapping(const QStringList &mapping);
+
+    int screenForItem(const QString &name) const;
+    void addMapping(const QString &name, int screen, MappingSignalBehavior behavior = ImmediateSignal);
+    void removeFromMap(const QString &name);
+    void setCorona(Plasma::Corona *corona);
+
+    void addScreen(int screenId, const QString &path);
+    void removeScreen(int screenId, const QString &path);
+    int firstAvailableScreen(const QString &path) const;
+    void removeItemFromDisabledScreen(const QString &name);
+
+#ifdef BUILD_TESTING
+    void cleanup();
+#endif
+
+Q_SIGNALS:
+    void screenMappingChanged() const;
+    void screensChanged() const;
+
+private:
+    ScreenMapper(QObject *parent = nullptr);
+
+    QHash<QString, int> m_screenItemMap;
+    QHash<int, QStringList> m_itemsOnDisabledScreensMap;
+    QHash<QString, int> m_firstScreenForPath; // first available screen for a path
+    QHash<QString, int> m_screensPerPath; // screen per registered path
+    QVector<int> m_availableScreens;
+    Plasma::Corona *m_corona = nullptr;
+    QTimer *m_screenMappingChangedTimer = nullptr;
+};
+
+#endif // SCREENMAPPER_H
diff --git a/containments/panel/contents/ui/main.qml b/containments/panel/contents/ui/main.qml
index 5bb52832..a3f25766 100644
--- a/containments/panel/contents/ui/main.qml
+++ b/containments/panel/contents/ui/main.qml
@@ -246,7 +246,9 @@ function checkLastSpacer() {
 //BEGIN components
     Component {
         id: appletContainerComponent
-        Item {
+        // This loader conditionally manages the BusyIndicator, it's not
+        // loading the applet. The applet becomes a regular child item.
+        Loader {
             id: container
             visible: false
             property bool animationsEnabled: true
@@ -281,27 +283,21 @@ function checkLastSpacer() {
             property int oldY: y
 
             property Item applet
+
             onAppletChanged: {
                 if (!applet) {
                     destroy();
                 }
             }
 
+            active: applet && applet.busy
+            sourceComponent: PlasmaComponents.BusyIndicator {}
+
             Layout.onMinimumWidthChanged: movingForResize = true;
             Layout.onMinimumHeightChanged: movingForResize = true;
             Layout.onMaximumWidthChanged: movingForResize = true;
             Layout.onMaximumHeightChanged: movingForResize = true;
 
-            Loader {
-                z: 1000
-                anchors.centerIn: parent
-                active: applet && applet.busy
-                sourceComponent: PlasmaComponents.BusyIndicator {
-                    width: Math.min(container.width, container.height)
-                    height: width
-                }
-            }
-
             onXChanged: {
                 if (movingForResize) {
                     movingForResize = false;
diff --git a/desktoppackage/contents/configuration/ConfigCategoryDelegate.qml b/desktoppackage/contents/configuration/ConfigCategoryDelegate.qml
index 0d4a0cda..65eb7001 100644
--- a/desktoppackage/contents/configuration/ConfigCategoryDelegate.qml
+++ b/desktoppackage/contents/configuration/ConfigCategoryDelegate.qml
@@ -58,7 +58,7 @@ MouseArea {
 //END functions
 
 //BEGIN connections
-    onClicked: {
+    onPressed: {
         categoriesScroll.forceActiveFocus()
 
         if (current) {
diff --git a/desktoppackage/contents/views/Panel.qml b/desktoppackage/contents/views/Panel.qml
index 7594c283..22f23f50 100644
--- a/desktoppackage/contents/views/Panel.qml
+++ b/desktoppackage/contents/views/Panel.qml
@@ -54,7 +54,7 @@ PlasmaCore.FrameSvgItem {
             prefix = "";
             return;
         }
-        prefix = [prefix, ""];
+        prefix = [pre, ""];
     }
 
     onContainmentChanged: {
diff --git a/doc/kcontrol/colors/index.docbook b/doc/kcontrol/colors/index.docbook
index cd392e3c..436168ef 100644
--- a/doc/kcontrol/colors/index.docbook
+++ b/doc/kcontrol/colors/index.docbook
@@ -14,8 +14,8 @@
 <!-- TRANS:ROLES_OF_TRANSLATORS -->
 </authorgroup>
 
-<date>2016-09-20</date>
-<releaseinfo>Plasma 5.8</releaseinfo>
+<date>2017-11-07</date>
+<releaseinfo>Plasma 5.11</releaseinfo>
 
 <keywordset>
 <keyword>KDE</keyword>
@@ -80,7 +80,7 @@
   assigning colors.</para>
 
   <itemizedlist>
-    <listitem><para><guilabel>Apply inactive window color effects</guilabel>
+    <listitem><para><guilabel>Apply effects to inactive windows</guilabel>
       — If checked, state effects (see below) will be applied to inactive
       windows. This can help visually identify active versus inactive windows,
       and may have aesthetic value, depending on your taste. However, some
@@ -89,7 +89,7 @@
       effects, color state effects do not require compositing support and will
       work on all systems, however they will only work on &kde; applications.
     </para></listitem>
-    <listitem><para><guilabel>Inactive selection changes color</guilabel>
+    <listitem><para><guilabel>Use different colors for inactive selections</guilabel>
       — If checked, the current selection in elements which do not have
       input focus will be drawn using a different color. This can assist visual
       identification of the element with input focus in some applications,
diff --git a/doc/kcontrol/icons/index.docbook b/doc/kcontrol/icons/index.docbook
index da65b1bf..942c4331 100644
--- a/doc/kcontrol/icons/index.docbook
+++ b/doc/kcontrol/icons/index.docbook
@@ -15,8 +15,8 @@
 <!-- TRANS:ROLES_OF_TRANSLATORS -->
 </authorgroup>
 
-<date>2016-09-21</date>
-<releaseinfo>Plasma 5.8</releaseinfo>
+<date>2017-11-07</date>
+<releaseinfo>Plasma 5.11</releaseinfo>
 
 <keywordset>
 <keyword>KDE</keyword>
@@ -221,7 +221,7 @@ a loss of quality.</para>
 
 <para>You can also choose animated icons. Many of the icons have
 animations associated with them.  Enable the checkbox labelled
-<guilabel>Animate Icons</guilabel>, to enable this effect, but note
+<guilabel>Enable icon animations</guilabel>, to enable this effect, but note
 that it may appear slow or jerky if your graphics card is old or you
 are low on memory.</para>
 
diff --git a/doc/kcontrol/kcmaccess/index.docbook b/doc/kcontrol/kcmaccess/index.docbook
index 728424e7..b1feff68 100644
--- a/doc/kcontrol/kcmaccess/index.docbook
+++ b/doc/kcontrol/kcmaccess/index.docbook
@@ -69,14 +69,14 @@ to find the exact file.
 
 <para>
 For those users who have difficulty hearing the System bell, or those
-users who have a silent computer, &kde; offers the <emphasis>visible bell</emphasis>.  This
+users who have a silent computer, &kde; offers the <emphasis>visual bell</emphasis>.  This
 provides a visual signal (inverting the screen or flashing a color
 across it) when the system bell would normally sound.
 </para>
 
 <para>
-To use the visible bell, first place a mark in the check box labeled
-<guilabel>Use visible bell</guilabel>.
+To use the visual bell, first place a mark in the check box labeled
+<guilabel>Use visual bell</guilabel>.
 </para>
 
 <para>
diff --git a/doc/kcontrol/kcmstyle/index.docbook b/doc/kcontrol/kcmstyle/index.docbook
index 1820ef57..e3d79ffa 100644
--- a/doc/kcontrol/kcmstyle/index.docbook
+++ b/doc/kcontrol/kcmstyle/index.docbook
@@ -14,8 +14,8 @@
 <!-- TRANS:ROLES_OF_TRANSLATORS -->
 </authorgroup>
 
-<date>2017-04-01</date>
-<releaseinfo>Plasma 5.9</releaseinfo>
+<date>2017-11-07</date>
+<releaseinfo>Plasma 5.11</releaseinfo>
 
 <keywordset>
 <keyword>KDE</keyword>
@@ -73,12 +73,12 @@ a dialog to select further settings.</para>
 <variablelist>
 
 <varlistentry> 
-<term><guilabel>Show icons on buttons</guilabel></term>
+<term><guilabel>Show icons in buttons</guilabel></term>
 <listitem>
 <para>If this option is selected, action buttons (like <guibutton>OK</guibutton> and 
 <guibutton>Apply</guibutton>) will have a small icon located within them to act
 as a visual reference.  If this option is not selected, then only text
-will appear on the button.</para>
+will appear in the button.</para>
 </listitem> 
 </varlistentry> 
 
@@ -93,7 +93,7 @@ applications.</para>
 </varlistentry> 
 
 <varlistentry> 
-<term><guilabel>Main toolbar text</guilabel>, <guilabel>Secondary toolbar text</guilabel></term>
+<term><guilabel>Main toolbar text location</guilabel>, <guilabel>Secondary toolbar text location</guilabel></term>
 <listitem>
 <para>These drop down boxes lets you determine where on the button in both toolbars the 
 text name of the button will appear as the default.  
diff --git a/kaccess/kaccess.notifyrc b/kaccess/kaccess.notifyrc
index e250dc2d..0fcd4001 100644
--- a/kaccess/kaccess.notifyrc
+++ b/kaccess/kaccess.notifyrc
@@ -177,7 +177,7 @@ Comment[be at latin]=Klavišny madyfikatar (naprykład, „Shift” ci „Ctrl”)
 Comment[bg]=Клавиш-модификатор (напр. Shift или Ctrl) промени състоянието си и е активен
 Comment[bn]=একটি মডিফায়ার কী (e.g. Shift বা Ctrl) অবস্থা পরিবর্তন করে এখন সক্রিয় হয়েছে
 Comment[bs]=Modifikatorski taster (npr. Shift ili Ctrl) promijenio je stanje i sada je aktivan
-Comment[ca]=Ha canviat l'estat d'una tecla modificadora (p.ex. Maj o Ctrl) i ara està activa
+Comment[ca]=Ha canviat l'estat d'una tecla modificadora (p. ex. Maj o Ctrl) i ara està activa
 Comment[ca at valencia]=Ha canviat l'estat d'una tecla modificadora (p.ex. Maj o Ctrl) i ara està activa
 Comment[cs]=Modifikátor klávesnice (Shift nebo Ctrl) změnil stav a je právě aktivní
 Comment[csb]=Klawisza zjinaczi (Shift abò Control) zmienia swój sztatus ë je aktiwòwónô
@@ -334,7 +334,7 @@ Comment[be at latin]=Klavišny madyfikatar (naprykład, „Shift” ci „Ctrl”)
 Comment[bg]=Клавиш-модификатор (напр. Shift или Ctrl) промени състоянието си и е изключен
 Comment[bn]=একটি মডিফায়ার কী (e.g. Shift বা Ctrl) অবস্থা পরিবর্তন করে এখন নিষ্ক্রীয় হয়েছে
 Comment[bs]=Modifikatorski taster (npr. Shift ili Ctrl) je promijenio stanje i nije više aktivan
-Comment[ca]=Ha canviat l'estat d'una tecla modificadora (p.ex. Maj o Ctrl) i ara està inactiva
+Comment[ca]=Ha canviat l'estat d'una tecla modificadora (p. ex. Maj o Ctrl) i ara està inactiva
 Comment[ca at valencia]=Ha canviat l'estat d'una tecla modificadora (p.ex. Maj o Ctrl) i ara està inactiva
 Comment[cs]=Modifikátor klávesnice (Shift nebo Ctrl) změnil stav a je právě neaktivní
 Comment[csb]=Klawisza zjinaczi (Shift abò Control) zmienia swój sztatus ë nie je ju aktiwnô
@@ -491,7 +491,7 @@ Comment[be at latin]=Klavišny madyfikatar (naprykład, „Shift” ci „Ctrl”)
 Comment[bg]=Клавиш-модификатор (напр. Shift или Ctrl) е заключен и е активен за всички последващи натискания на клавиши
 Comment[bn]=একটি মডিফায়ার কী (e.g. Shift বা Ctrl) লক করা হয়েছে এবং পরবর্তী সবকটি কী-র (key) জন্য সক্রিয় থাকবে
 Comment[bs]=Modifikatorski taster (npr. Shift ili Ctrl) upravo je zaključan i od sada aktivan za sve pritiske na tastere
-Comment[ca]=S'ha fixat alguna tecla modificadora (p.ex. Maj o Ctrl) i ara està activa per a totes les tecles que es premin a continuació
+Comment[ca]=S'ha fixat alguna tecla modificadora (p. ex. Maj o Ctrl) i ara està activa per a totes les tecles que es premin a continuació
 Comment[ca at valencia]=S'ha fixat alguna tecla modificadora (p.ex. Maj o Ctrl) i ara està activa per a totes les tecles que es premen a continuació
 Comment[cs]=Modifikátor klávesnice (např. Shift nebo Ctrl) je zamčený a je nyní aktivní pro všechny následující stisknuté klávesy
 Comment[csb]=Klawisza zjinaczi (Shift abò Control) òsta zablokòwónô ë je terô dlô pòsobnegò wcësniącô klawiszów aktiwnô
@@ -649,7 +649,7 @@ Comment[be at latin]=Klaviša macavańnia (naprykład, „Caps Lock” ci „Num Lo
 Comment[bg]=Клавиш за превключване на режим (напр. Caps Lock или Num Lock) промени състоянието си и е активен
 Comment[bn]=একটি লক কী (e.g. Caps Lock বা Num Lock) অবস্থা পরিবর্তন করে এখন সক্রিয় হয়েছে
 Comment[bs]=Zaključavajući taster (npr. CapsLock ili NumLock) promijenio je stanje i sada je aktivan
-Comment[ca]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està activa
+Comment[ca]=Alguna tecla de fixació (p. ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està activa
 Comment[ca at valencia]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està activa
 Comment[cs]=Klávesa pro přepnutí stavu (např. CapsLock nebo NumLock) byla stisknuta a je nyní aktivní
 Comment[csb]=Klawisza blokadë (Caps Lock abò Num Lock) zmienia swój sztatus ë je terô aktiwnô
@@ -807,7 +807,7 @@ Comment[be at latin]=Klaviša macavańnia (naprykład, „Caps Lock” ci „Num Lo
 Comment[bg]=Клавиш за превключване на режим (напр. Caps Lock или Num Lock) промени състоянието си и е неактивен
 Comment[bn]=একটি লক কী (e.g. Caps Lock বা Num Lock) অবস্থা পরিবর্তন করে এখন নিষ্ক্রীয় হয়েছে
 Comment[bs]=Zaključavajući taster (npr. CapsLock ili NumLock) promijenio je stanje i više nije aktivan
-Comment[ca]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està inactiva
+Comment[ca]=Alguna tecla de fixació (p. ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està inactiva
 Comment[ca at valencia]=Alguna tecla de fixació (p.ex. Bloq Maj o Bloq Núm) ha canviat el seu estat i ara està inactiva
 Comment[cs]=Klávesa pro přepnutí stavu (např. CapsLock nebo NumLock) byla stisknuta a je nyní neaktivní
 Comment[csb]=Klawisza blokadë (Caps Lock abò Num Lock) zmienia swój sztatus ë nie je ju aktiwnô
@@ -893,7 +893,7 @@ Name[de]=Klebende Tasten sind aktiviert oder deaktiviert worden
 Name[el]=Τα κολλημένα πλήκτρα ενεργοποιήθηκαν ή απενεργοποιήθηκαν
 Name[en_GB]=Sticky keys has been enabled or disabled
 Name[eo]=Fiksaj klavoj validiĝis aŭ malvalidiĝis
-Name[es]=Las teclas pegajosas se han activado o desactivado
+Name[es]=Las teclas adhesivas se han activado o desactivado
 Name[et]=Kleepuvad klahvid on keelatud või lubatud
 Name[eu]=Tekla itsaskorrak gaitu edo desgaitu dira
 Name[fi]=Alas jäävät näppäimet on otettu käyttöön tai poistettu käytöstä
@@ -969,7 +969,7 @@ Comment[de]=Die Funktion „Klebende Tasten“ ist aktiviert oder deaktiviert wo
 Comment[el]=Τα κολλημένα πλήκτρα ενεργοποιήθηκαν ή απενεργοποιήθηκαν
 Comment[en_GB]=Sticky keys has been enabled or disabled
 Comment[eo]=Fiksaj klavoj validiĝis aŭ malvalidiĝis
-Comment[es]=Las teclas pegajosas se han activado o desactivado
+Comment[es]=Las teclas adhesivas se han activado o desactivado
 Comment[et]=Kleepuvad klahvid on keelatud või lubatud
 Comment[eu]=Tekla itsaskorrak gaitu edo desgaitu dira
 Comment[fi]=Alas jäävät näppäimet on otettu käyttöön tai poistettu käytöstä
diff --git a/kcms/CMakeLists.txt b/kcms/CMakeLists.txt
index c4dced21..f59b2d7f 100644
--- a/kcms/CMakeLists.txt
+++ b/kcms/CMakeLists.txt
@@ -14,7 +14,7 @@ if(X11_Xkb_FOUND AND XCB_XKB_FOUND)
     add_subdirectory( keyboard )
 endif()
 
-if (EVDEV_FOUND AND X11_Xinput_FOUND)
+if (EVDEV_FOUND AND XORGLIBINPUT_FOUND AND X11_Xinput_FOUND)
     add_subdirectory( input )
 endif()
 
@@ -32,6 +32,7 @@ add_subdirectory( standard_actions )
 add_subdirectory( keys )
 add_subdirectory( ksmserver )
 add_subdirectory( lookandfeel )
+add_subdirectory( nightcolor )
 
 add_subdirectory( hardware )
 add_subdirectory( desktoppaths )
diff --git a/kcms/access/accessibility.ui b/kcms/access/accessibility.ui
index 1a57ae50..9e22faa9 100644
--- a/kcms/access/accessibility.ui
+++ b/kcms/access/accessibility.ui
@@ -103,16 +103,16 @@
        <item>
         <widget class="QGroupBox" name="groupBox_2">
          <property name="title">
-          <string>Visible Bell</string>
+          <string>Visual Bell</string>
          </property>
          <layout class="QGridLayout" name="gridLayout">
           <item row="0" column="0" colspan="4">
            <widget class="QCheckBox" name="visibleBell">
             <property name="toolTip">
-             <string>This option will turn on the "visible bell", i.e. a visible notification shown every time that normally just a bell would occur. This is especially useful for deaf people.</string>
+             <string>This option will turn on the "visual bell", i.e. a visual notification shown every time that normally just a bell would occur. This is especially useful for deaf people.</string>
             </property>
             <property name="text">
-             <string>&Use visible bell</string>
+             <string>&Use visual bell</string>
             </property>
            </widget>
           </item>
diff --git a/kcms/access/kcmaccess.cpp b/kcms/access/kcmaccess.cpp
index 9c3e31d2..536f86c1 100644
--- a/kcms/access/kcmaccess.cpp
+++ b/kcms/access/kcmaccess.cpp
@@ -508,7 +508,6 @@ extern "C"
      */
     Q_DECL_EXPORT void kcminit_access()
     {
-        KConfig config(QStringLiteral("kaccessrc"), KConfig::NoGlobals);
         KToolInvocation::startServiceByDesktopName(QStringLiteral("kaccess"));
     }
 }
diff --git a/kcms/access/kcmaccess.desktop b/kcms/access/kcmaccess.desktop
index 87964d16..83250ee8 100644
--- a/kcms/access/kcmaccess.desktop
+++ b/kcms/access/kcmaccess.desktop
@@ -154,48 +154,28 @@ Comment[x-test]=xxAccessibility Optionsxx
 Comment[zh_CN]=辅助功能选项
 Comment[zh_TW]=無障礙輔助選項
 
-X-KDE-Keywords=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
-X-KDE-Keywords[bs]=pristup,pristupačnost,gluh,oštećen,sluh,gubitak sluha,zvono,zvučno zvono,vidljivo zvono,tastatura,tipke,ljepljive tipke,odskočne tipke,usporene tipke,navigacija uz pomoć miša,numerički dio,
-X-KDE-Keywords[ca]=accés,accessibilitat,sord,discapacitat,oïda,pèrdua d'oïda,campana,campana audible,campana visible,Teclat,tecles apegaloses,repetició de tecles,tecles lentes,navegació de ratolí,teclat numèric,activació de gestos,gestors,apegalós,tecles modificadores,modificador,tecles bloquejadores
-X-KDE-Keywords[ca at valencia]=accés,accessibilitat,sord,discapacitat,oïda,pèrdua d'oïda,campana,campana audible,campana visible,Teclat,tecles apegaloses,repetició de tecles,tecles lentes,navegació de ratolí,teclat numèric,activació de gestos,gestors,apegalós,tecles modificadores,modificador,tecles bloquejadores
-X-KDE-Keywords[da]=tilgang,tilgængelighed,døv,hæmmet,handicappet,hørelse,hørehæmmet,klokke,hørbar klokke,synlig klokke,tastatur,taster,sticky keys,elastiske taster,bounce,langsomme taster,musenavigation,numerisk tastatur,aktiveringsgestusser,gestusser,klæbende,ændringstaster,låsetaster
+X-KDE-Keywords=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
+X-KDE-Keywords[ca]=accés,accessibilitat,sord,discapacitat,oïda,pèrdua d'oïda,timbre,timbre audible,timbre visual,Teclat,tecles apegaloses,repetició de tecles,tecles lentes,navegació de ratolí,teclat numèric,activació de gestos,gestors,apegalós,tecles modificadores,modificador,tecles bloquejadores
+X-KDE-Keywords[ca at valencia]=accés,accessibilitat,sord,discapacitat,oïda,pèrdua d'oïda,timbre,timbre audible,timbre visual,Teclat,tecles apegaloses,repetició de tecles,tecles lentes,navegació de ratolí,teclat numèric,activació de gestos,gestors,apegalós,tecles modificadores,modificador,tecles bloquejadores
 X-KDE-Keywords[de]=Behinderung,Maussteuerung,Signale,Tastatur,Tasten,Klebende Tasten,Taubheit,Verlangsamte Tasten,Zahlenblock,Zugang,Zugangshilfen,Zahlentasten,Gesten aktivieren,Sondertasten,Sperrtasten
-X-KDE-Keywords[el]=πρόσβαση,προσβασιμότητα,βαρήκοος,πρόβλημα,ακοής,απώλεια ακοής,κουδούνι,ηχητικό κουδούνι,οπτικό κουδούνι,πληκτρολόγιο,πλήκτρα,κολλημένα πλήκτρα,πλήκτρα αναπήδησης,αργά πλήκτρα,πλοήγηση με ποντίκι,αριθμητικό πληκτρολόγιο,numpad,νεύματα ενεργοποίησης,νεύματα,κολλημένο,πλήκτρα τροποποιητή,τροποποιητής,πλήκτρα κλειδώματος
-X-KDE-Keywords[en_GB]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
-X-KDE-Keywords[es]=acceso,accesibilidad,sordera,descapacitado,oído,pérdida de oído,campana,campana audible,campana visible,teclado,teclas,teclas pegajosas,repetición de teclas,teclas lentas,navegación con ratón,teclado numérico,gestos de activación,gestos,pegajoso,teclas modificadoras,modificador,teclas de bloqueo
-X-KDE-Keywords[et]=hõlbustus,kasutusmugavus,kurdid,tummad,kuulmine,kuulmiskaotus,puuetega,kell,kuuldav kell,nähtav kell,klaviatuur,klahvid,kleepuvad klahvid,põrkuvad klahvid,aeglased klahvid,hiirega liikumine,numbriklahvistik,aktiveerimisžestid,žestid,muuteklahvid,lukustusklahvid
-X-KDE-Keywords[eu]=sarbide,irisgarritasuna,gor,baliaezintasun,entzumen,entzumena galdu,kanpai,kanpai entzungarri,kanpai ikusgarri,teklatu,tekla,tekla itsaskor,errebote-teklak,tekla motel,sagu bidezko nabigazio,zenbakizko teklatu,zk teklatu,aktibazio-keinu,keinu,itsaskor,tekla aldatzaile,aldatzaile,blokeo-tekla
-X-KDE-Keywords[fi]=esteettömyys,kuuro,heikentynyt,heikko,kuulo,varoitus,äänimerkki,visuaalinen äänimerkki,näppäimistö,näppäimet,alas jäävät näppäimet,tahmeat näppäimet,ponnahdusnäppäimet,hitaat näppäimet,hiirinäppäimet,numeronäppäimistö
+X-KDE-Keywords[en_GB]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
+X-KDE-Keywords[es]=acceso,accesibilidad,sordera,descapacitado,oído,pérdida de oído,campana,campana audible,campana visible,campana visual,teclado,teclas,teclas adhesivas,repetición de teclas,teclas lentas,navegación con ratón,teclado numérico,gestos de activación,gestos,adhesivo,teclas modificadoras,modificador,teclas de bloqueo
+X-KDE-Keywords[eu]=sarbide,irisgarritasuna,gor,baliaezintasun,entzumen,entzumena galdu,kanpai,kanpai entzungarri,kanpai ikusgarri,kanpai ikusgaia,teklatu,tekla,tekla itsaskor, errebote-teklak,tekla motel,sagu bidezko nabigazio,zenbakizko teklatu,zk teklatu,aktibazio-keinu,keinu,itsaskor,tekla aldatzaile,aldatzaile,blokeo-tekla
 X-KDE-Keywords[fr]=accès, accessibilité, sourd, affaiblis, audition, perte d'audition, cloche, cloche audible, cloche visuelle, clavier, touches, touches collantes, touche rebondissante, touches lentes, navigation de la souris, pavé numérique, gestes d'activation, gestes, collant, touches modifiantes, modificateur, touche de verrouillage
-X-KDE-Keywords[ga]=rochtain,inrochtaineacht,bodhar,lagaithe,cloigín,cloigín inchloiste,clog infheicthe,Méarchlár,eochracha,eochracha greamaitheacha,eochracha preabtha,eochracha go mall,nascleanúint luiche,eochaircheap uimhriúil,gothaí,greamaitheach,mionthraitheoir,eochracha glasála
-X-KDE-Keywords[gl]=acceso, accesibilidade, xordo, discapacitado, minusválido, audición, auditiva, campá audíbel, campá visíbel, teclado, tecla pegañentas, teclas lentas, navegación co rato, teclado numérico, acenos, teclas modificadoras
-X-KDE-Keywords[hu]=kezelés,akadálymentesítés,süket,károsodott,hallás,halláskárosodás,csengő,hallható csengő,látható csengő,Billentyűzet,billentyűk,ragadós billentyűk,pattogó billentyűk,lassú billentyűk,egérnavigáció,numerikus billentyűzet
-X-KDE-Keywords[ia]=accesso,accessibilitate,surde,debilitate,audito, perdita de audito,campana,campana audibile,campana visibile,Claviero,claves,claves collose,claves saltante,claves lente,navigation de mus,pad numeric, gestos de activation,gestos,collose, claves modificator, modificator, claves blocante 
-X-KDE-Keywords[id]=akses,aksesibilitas,tuli,gangguan,pendengaran,kehilangan pendengaran,bel,bel terdengar,bel tampak,Papan Ketik,tombol,tombol lekat,tombol pantul,tombol pelan,navigasi tetikus,papan numerik,numpad,gerakan aktivasi,gerakan,gerakan,lengket,tombol pemodifikasi,pemodifikasi,tombol mengunci
+X-KDE-Keywords[hu]=kezelés,akadálymentesítés,süket,károsodott,hallás,halláskárosodás,csengő,hallható csengő,látható csengő,vizuális csengő,Billentyűzet,billentyűk,ragadós billentyűk,pattogó billentyűk,lassú billentyűk,egérnavigáció,numerikus billentyűzet
 X-KDE-Keywords[it]=accesso,accessibilità,sordo,handicap,udito,sordità,campanella,campanella udibile,campanella visiva,tastiera,tasti,permanenza dei tasti,pressione ravvicinata dei tasti,rallentamento dei tasti,navigazione col mouse,tastierino numerico,attivazione gesti,gesti,tasti modificatori,modificatore,tasti di blocco
-X-KDE-Keywords[kk]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
-X-KDE-Keywords[km]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
-X-KDE-Keywords[ko]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,접근,접근성,청각장애,청각 장애,시각장애,시각 장애,키보드,키,고정키,튕김키,느린키,마우스키,숫자패드
-X-KDE-Keywords[mr]=एक्सेस, एक्सेसिबिलिटी, कर्णबधीर, विकलांग, ऐकणे, कमी ऐकू येणे, घंटा, घंटानाद , दृश्यघंटा, कि-बोर्ड, कीज, स्टिकी किज, बाउन्स किज, स्लो किज, माऊस दिशानिर्देश, न्यूम पॅड, एक्टिव्हेशन गेस्चर्स, गेस्चर्स, स्टिकी, मॉडीफायर कीज, मॉडीफायर, लॉकिंग किज, 
-X-KDE-Keywords[nb]=tilgang,tilgjengelighet,døv,hemmet,hørsel, hørselstap,bjelle,hørbar bjelle,synlig bjelle,Tastatur,låsetaster,faste taster,trege taster,musnavigering, talltastatur,tallboks,aktiveringsbevegelser,bevegelser,valgtaster
-X-KDE-Keywords[nds]=Togang,Toganghülp,doof,kiekbehinnert,Hören,Pingel,Ogenpingel,Tastatuur,Tasten,backige Tasten,jumpen Tasten,langsame Tasten,Muusstüern,Tallenblock,Tekens,Anmaaktekens,backig,Sünnertasten,Wesseltekens,Fastsetttasten
-X-KDE-Keywords[nl]=toegang,toegankelijkheid,doof,gehandicapt,gehoor,gehoorverlies,bel,hoorbare bel,zichtbare bel,toetsenbord,toetsen,dode toetsen,herhaaltoetsen,langzame toetsen,muisnavigatie,numeriek toetsenbord,activeringsgebaren,gebaren,plakkerig,modificatietoetsen,modificator,vergrendeltoets
-X-KDE-Keywords[nn]=tilgjenge,tilgjengelegheit,døv,funksjonshemma,handikappa,høyrsle,høyrsletap,bjølle,høyrbar bjølle,synleg bjølle,tastatur,låsetastar,faste tastar,trege tastar,musnavigering,taltastatur,numerisk tastatur,aktiveringsrørsler,musrørsler,muserørsler,rørsler,valtastar,låsetastar
-X-KDE-Keywords[pl]=dostęp,dostępność,głuchota,upośledzenie,dzwonek,słyszalny dzwonek,widoczny dzwonek,Klawiatura,klawisze,lepkie klawisze,odbijające klawisze,powolne klawisze, ruchy myszą,klawiatura numeryczna
+X-KDE-Keywords[ko]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,접근,접근성,청각장애,청각 장애,시각장애,시각 장애,키보드,키,고정키,튕김키,느린키,마우스키,숫자패드,제스처
+X-KDE-Keywords[nl]=toegang,toegankelijkheid,doof,gehandicapt,gehoor,gehoorverlies,bel,hoorbare bel,zichtbare bel,toetsenbord,toetsen,dode toetsen,herhaaltoetsen,langzame toetsen,muisnavigatie,numeriek toetsenbord,activeringsgebaren,gebaren,plakkerig,modificatietoetsen,samensteltoets,vergrendeltoetsen
+X-KDE-Keywords[pl]=dostęp,dostępność,głuchota,upośledzenie,dzwonek,słyszalny dzwonek,widoczny dzwonek,słyszalny dzwonek,Klawiatura,klawisze,lepkie klawisze,odbijające klawisze,powolne klawisze, ruchy myszą,klawiatura numeryczna
 X-KDE-Keywords[pt]=acesso,acessibilidade,surdo,deficiente,campainha,campainha audível,campainha visível,teclado,teclas,teclas fixas,teclas lentas,teclas sonoras,navegação do rato,teclado numérico,numérico,gestos de activação,gestos,fixo,teclas modificadoras,modificadora,teclas de bloqueio
-X-KDE-Keywords[pt_BR]=acesso,acessibilidade,surdo,deficiente,audição,campainha,campainha audível,campainha visível,Teclado,teclas,teclas de aderência,teclas lentas,teclas de repercussão,navegação do mouse,teclado numérico numérico,gestos de ativação,gestos,fixo,teclas modificadoras,modificadora,teclas de bloqueio
-X-KDE-Keywords[ru]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,доступ,доступность,глухота,слух,ослабленный,слабый,потеря слуха,звонок,сигнал,звуковой сигнал,визуальный сигнал,видимый сигнал,клавиатура,кнопки,клавиши,залипание,залипающие клавиши,липкие клавиши,прыгающие клавиши,«прыгающие» клавиши,замедленные клавиши,навигация с помощью мыши,управление мышью,цифровая клавиатура,жесты активации,жесты,клавиши-модификаторы,модификаторы,модификатор,клавиши индикаторов
-X-KDE-Keywords[sk]=prístup,prístupnosť,hluchý,opitý,sluch,strata sluchu,zvonček,hlasný zvonček,viditeľný zvonček,Klávesnica,klávesy,lepkavé klávesy,skákajúce klávesy,pomalé klávesy,navigácia myšou,numerická klávesnica,numpad,aktivačné gestá,lepkavé,modifikačné klávesy,modifikátor,zamykacie klávesy
-X-KDE-Keywords[sl]=dostop,dostopnost,gluh,oviran,sluh,slušno,izguba sluha,zvonec,slišen zvonec,viden zvonec,tipkovnica,tipke,lepljive tipke,odbijajoče tipke,počasne tipke,krmarjenje z miško,številčnica,številske tipke,kretnje za vklop,kretnje,lepljivo,spremenilne tipke,zaklepne tipke
-X-KDE-Keywords[sr]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,приступ,приступачност,глув,оштећен,слух,губитак,звоно,чујно,видно,тастатура,тастери,лепљиви,одскачући,спори,нумеричка,активација,гестови,лепљив,модификаторски,тастери,закључавање
-X-KDE-Keywords[sr at ijekavian]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,приступ,приступачност,глув,оштећен,слух,губитак,звоно,чујно,видно,тастатура,тастери,лепљиви,одскачући,спори,нумеричка,активација,гестови,лепљив,модификаторски,тастери,закључавање
-X-KDE-Keywords[sr at ijekavianlatin]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,pristup,pristupačnost,gluv,oštećen,sluh,gubitak,zvono,čujno,vidno,tastatura,tasteri,lepljivi,odskačući,spori,numerička,aktivacija,gestovi,lepljiv,modifikatorski,tasteri,zaključavanje
-X-KDE-Keywords[sr at latin]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,pristup,pristupačnost,gluv,oštećen,sluh,gubitak,zvono,čujno,vidno,tastatura,tasteri,lepljivi,odskačući,spori,numerička,aktivacija,gestovi,lepljiv,modifikatorski,tasteri,zaključavanje
-X-KDE-Keywords[sv]=åtkomst,handikappstöd,döva,funktionshindrade,hörsel,hörselförlust,summer,hörbar summer,synlig summer,Tangentbord,tangenter,klistriga tangenter,studsande tangenter,långsamma tangenter,musnavigering,numeriskt tangentbord,aktiveringsgester,gester,klistrig,väljartangenter,väljare,låstangenter
-X-KDE-Keywords[tr]=erişim,erişebilirlik,sağır,bozukluk,işitme,kayıp,zil,işitilebilir zil,görünen zil,Klayve,tuşlar,yapışkan tuşlar,sıçrama tuşları,yavaş tuşlar,fare gezinmesi,rakamlar klavyesi,jestler,yapışkan,hızlandırma tuşları,hızlandırıcı,kilitleme tuşları
-X-KDE-Keywords[uk]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,доступ,доступність,спеціальні можливості,глухий,слух,враження,вади,звук,сповіщення,видиме сповіщення,візуальне сповіщення,клавіатура,клавіші,клавіша,липкі клавіші,утримування,повільні клавіші,миша,навігація,цифри,цифровий блок,слух,втрата слуху,жести активування,жести,липка,липкі клавіші,клавіші-модифікатори,модифікатори,клавіші фіксування,фіксування,блокування
-X-KDE-Keywords[x-test]=xxaccessxx,xxaccessibilityxx,xxdeafxx,xximpairedxx,xxhearingxx,xxhearing lossxx,xxbellxx,xxaudible bellxx,xxvisible bellxx,xxKeyboardxx,xxkeysxx,xxsticky keysxx,xxbounce keysxx,xxslow keysxx,xxmouse navigationxx,xxnum padxx,xxnumpadxx,xxactivation gesturesxx,xxgesturesxx,xxstickyxx,xxmodifier keysxx,xxmodifierxx,xxlocking keysxx
-X-KDE-Keywords[zh_CN]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,访问,可访问性,耳聋,聋,听力,听力丧失,铃声,可视铃声,按键,残疾人,残疾,聋哑,键盘,粘滞键,鼠标,小键盘,撞击键,鼠标导航,数字键盘,激活手势,手势,粘滞,修饰键,锁定键
-X-KDE-Keywords[zh_TW]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys
+X-KDE-Keywords[pt_BR]=acesso,acessibilidade,surdo,deficiente,audição,campainha,campainha audível,campainha visível,campainha visual,Teclado,teclas,teclas de aderência,teclas lentas,teclas de repercussão,navegação do mouse,teclado numérico numérico,gestos de ativação,gestos,fixo,teclas modificadoras,modificadora,teclas de bloqueio
+X-KDE-Keywords[sr]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,приступ,приступачност,глув,оштећен,слух,губитак,звоно,чујно,видно,тастатура,тастери,лепљиви,одскачући,спори,нумеричка,активација,гестови,лепљив,модификаторски,тастери,закључавање
+X-KDE-Keywords[sr at ijekavian]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,приступ,приступачност,глув,оштећен,слух,губитак,звоно,чујно,видно,тастатура,тастери,лепљиви,одскачући,спори,нумеричка,активација,гестови,лепљив,модификаторски,тастери,закључавање
+X-KDE-Keywords[sr at ijekavianlatin]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,pristup,pristupačnost,gluv,oštećen,sluh,gubitak,zvono,čujno,vidno,tastatura,tasteri,lepljivi,odskačući,spori,numerička,aktivacija,gestovi,lepljiv,modifikatorski,tasteri,zaključavanje
+X-KDE-Keywords[sr at latin]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,pristup,pristupačnost,gluv,oštećen,sluh,gubitak,zvono,čujno,vidno,tastatura,tasteri,lepljivi,odskačući,spori,numerička,aktivacija,gestovi,lepljiv,modifikatorski,tasteri,zaključavanje
+X-KDE-Keywords[sv]=åtkomst,handikappstöd,döva,funktionshindrade,hörsel,hörselförlust,summer,hörbar summer,visuellt alarm,Tangentbord,tangenter,klistriga tangenter,studsande tangenter,långsamma tangenter,musnavigering,numeriskt tangentbord,aktiveringsgester,gester,klistrig,väljartangenter,väljare,låstangenter
+X-KDE-Keywords[uk]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,доступ,доступність,спеціальні можливості,глухий,слух,враження,вади,звук,сповіщення,видиме сповіщення,візуальне сповіщення,видимий дзвінок,візуальний дзвінок,клавіатура,клавіші,клавіша,липкі клавіші,утримування,повільні клавіші,миша,навігація,цифри,цифровий блок,слух,втрата слуху,жести активування,жести,липка,липкі клавіші,клавіші-модифікатори,модифікатори,клавіші фіксування,фіксування,блокування
+X-KDE-Keywords[x-test]=xxaccessxx,xxaccessibilityxx,xxdeafxx,xximpairedxx,xxhearingxx,xxhearing lossxx,xxbellxx,xxaudible bellxx,xxvisible bellxx,xxvisual bellxx,xxKeyboardxx,xxkeysxx,xxsticky keysxx,xxbounce keysxx,xxslow keysxx,xxmouse navigationxx,xxnum padxx,xxnumpadxx,xxactivation gesturesxx,xxgesturesxx,xxstickyxx,xxmodifier keysxx,xxmodifierxx,xxlocking keysxx
+X-KDE-Keywords[zh_CN]=access,accessibility,deaf,impaired,hearing,hearing loss,bell,audible bell,visible bell,visual bell,Keyboard,keys,sticky keys,bounce keys,slow keys,mouse navigation,num pad,numpad,activation gestures,gestures,sticky,modifier keys,modifier,locking keys,通用辅助,聋,听力受损,响铃,视觉铃声,键盘,按键,粘滞键,鼠标导航,数字键盘,手势,修饰键,锁定键
 
 Categories=Qt;KDE;X-KDE-settings-accessibility;
diff --git a/kcms/activities/qml/activitiesTab/ActivitiesView.qml b/kcms/activities/qml/activitiesTab/ActivitiesView.qml
index 53f61977..5713be4f 100644
--- a/kcms/activities/qml/activitiesTab/ActivitiesView.qml
+++ b/kcms/activities/qml/activitiesTab/ActivitiesView.qml
@@ -45,6 +45,7 @@ Item {
         onClicked: ActivitySettings.newActivity();
 
         enabled: !dialogCreateActivityLoader.itemVisible
+        visible: ActivitySettings.newActivityAuthorized
     }
 
     Loader {
@@ -159,6 +160,8 @@ Item {
                             iconName: "edit-delete"
 
                             onClicked: ActivitySettings.deleteActivity(model.id);
+
+                            visible: ActivitySettings.newActivityAuthorized
                         }
 
                         visible: !dialogDeleteLoader.itemVisible
diff --git a/kcms/autostart/autostart.desktop b/kcms/autostart/autostart.desktop
index 5843414e..c5334588 100644
--- a/kcms/autostart/autostart.desktop
+++ b/kcms/autostart/autostart.desktop
@@ -151,11 +151,15 @@ X-KDE-Keywords=Autostart Manager,autostart,startup,system startup,plasma start,c
 X-KDE-Keywords[ca]=Gestor de l'inici automàtic,inici automàtic,inici,inici del sistema,inici del plasma,cron
 X-KDE-Keywords[ca at valencia]=Gestor de l'inici automàtic,inici automàtic,inici,inici del sistema,inici del plasma,cron
 X-KDE-Keywords[da]=autostart,opstart,systemstart,plasma start,cron
+X-KDE-Keywords[de]=Autostartverwaltung,Autostart,Startvorgang,Systemstart,Plasma-Start,Cron
+X-KDE-Keywords[en_GB]=Autostart Manager,autostart,startup,system startup,plasma start,cron
 X-KDE-Keywords[es]=Gestor de inicio automático,inicio automático,inicio,inicio del sistema,inicio de plasma,cron
 X-KDE-Keywords[eu]=Hasiera automatikoaren kudeatzailea,hasiera automatikoa,abioa,sistemaren abioa,plasma abiatu,cron
 X-KDE-Keywords[fr]=Gestionnaire de démarrage, démarrage automatique, démarrage, démarrage du système, démarrage de plasma, cron
+X-KDE-Keywords[hu]=Automatikus indítás kezelő,automatikus indítás,indulás,rendszerindulás,plasma indulás,cron
 X-KDE-Keywords[id]=Pengelola Start Otomatis,start otomatis,jalankan,jalankan sistem,jalankan plasma,cron
 X-KDE-Keywords[it]=Gestore avvio automatico,avvio automatico,avvio,avvio del sistema,avvio di plasma,cron
+X-KDE-Keywords[ko]=Autostart Manager,autostart,startup,system startup,plasma start,cron,자동 시작,자동시작,시작프로그램,시스템 시작,plasma 시작
 X-KDE-Keywords[nl]=Autostartbeheerder,autostarten,opstarten,opstarten systeem,opstarten plasma,cron
 X-KDE-Keywords[pl]=Menadżer autostartu,autostart,uruchamianie,uruchamianie systemu,plasma,kde start,cron
 X-KDE-Keywords[pt]=Gestor de arranque,arranque,início,arranque do sistema,início do plasma,cron
diff --git a/kcms/colors/colors.desktop b/kcms/colors/colors.desktop
index 23b9650c..04565846 100644
--- a/kcms/colors/colors.desktop
+++ b/kcms/colors/colors.desktop
@@ -121,6 +121,7 @@ Comment[hu]=Alkalmazások színsémái
 Comment[id]=Skema Warna Aplikasi
 Comment[it]=Schema di colore delle applicazioni
 Comment[ja]=アプリケーションカラースキーム
+Comment[ko]=프로그램 색 배열
 Comment[lt]=Programos spalvų derinys
 Comment[nb]=Fargeoppsett for program
 Comment[nl]=Toepassing Kleurenschema
diff --git a/kcms/colors/scmeditoroptions.ui b/kcms/colors/scmeditoroptions.ui
index 790b48b6..47f51615 100644
--- a/kcms/colors/scmeditoroptions.ui
+++ b/kcms/colors/scmeditoroptions.ui
@@ -14,14 +14,14 @@
    <item>
     <widget class="QCheckBox" name="useInactiveEffects">
      <property name="text">
-      <string>Apply inactive window color &effects</string>
+      <string>Apply &effects to inactive windows</string>
      </property>
     </widget>
    </item>
    <item>
     <widget class="QCheckBox" name="inactiveSelectionEffect">
      <property name="text">
-      <string>In&active selection changes color</string>
+      <string>Use different colors for in&active selections</string>
      </property>
     </widget>
    </item>
diff --git a/kcms/componentchooser/componentchooser.desktop b/kcms/componentchooser/componentchooser.desktop
index 7d5dcac9..1d250e70 100644
--- a/kcms/componentchooser/componentchooser.desktop
+++ b/kcms/componentchooser/componentchooser.desktop
@@ -151,7 +151,7 @@ X-KDE-Keywords[bs]=default applications,components,component chooser,resources,e
 X-KDE-Keywords[ca]=aplicacions per omissió,components,selector de components,recursos,e-mail,client de correu electrònic,editor de text,missatgeria instantània,emulador de terminal,navegador web,URL,hiperenllaços
 X-KDE-Keywords[ca at valencia]=aplicacions per omissió,components,selector de components,recursos,e-mail,client de correu electrònic,editor de text,missatgeria instantània,emulador de terminal,navegador web,URL,hiperenllaços
 X-KDE-Keywords[cs]=výchozí aplikace,komponenty,výběr komponent,zdroje,e-mail,emailový klient,editor textu,komunikátor,emulátor terminálů,webový prohlížeč,URL,odkazy
-X-KDE-Keywords[da]=standardprogrammer,komponenter,komponentvælger,ressourcer,e-mail,email klient,tekst-editor,instant messenger,terminal-emulator,webbrowser,URL,hyperlinks
+X-KDE-Keywords[da]=standardprogrammer,komponenter,komponentvælger,ressourcer,e-mail,email klient,teksteditor,instant messenger,terminalemulator,webbrowser,URL,hyperlinks
 X-KDE-Keywords[de]=Standard-Anwendungen,Standard-Komponenten,Komponenten,Ressourcen,E-Mail,E-Mail-Programm,Terminal-Emulation,Programme,Anwendungen,Web,Browser,URL
 X-KDE-Keywords[el]=προκαθορισμένες εφαρμογές,συστατικά,επιλογέας συστατικών,πόροι,αλληλογραφία,εφαρμογή αλληλογραφίας,επεξεργαστής κειμένου,εφαρμογή στιγμιαίων μηνυμάτων,εξομοιωτής τερματικού,περιηγητής ιστού,URL,υπερσύνδεσμοι
 X-KDE-Keywords[en_GB]=default applications,components,component chooser,resources,e-mail,email client,text editor,instant messenger,terminal emulator,web browser,URL,hyperlinks
diff --git a/kcms/desktoptheme/kcm.cpp b/kcms/desktoptheme/kcm.cpp
index 94c9fd09..20da2f17 100644
--- a/kcms/desktoptheme/kcm.cpp
+++ b/kcms/desktoptheme/kcm.cpp
@@ -44,6 +44,7 @@ K_PLUGIN_FACTORY_WITH_JSON(KCMDesktopThemeFactory, "kcm_desktoptheme.json", regi
 KCMDesktopTheme::KCMDesktopTheme(QObject *parent, const QVariantList &args)
     : KQuickAddons::ConfigModule(parent, args)
     , m_defaultTheme(new Plasma::Theme(this))
+    , m_haveThemeExplorerInstalled(false)
 {
     //This flag seems to be needed in order for QQuickWidget to work
     //see https://bugreports.qt-project.org/browse/QTBUG-40765
@@ -63,6 +64,8 @@ KCMDesktopTheme::KCMDesktopTheme(QObject *parent, const QVariantList &args)
     roles[ThemeNameRole] = QByteArrayLiteral("themeName");
     roles[IsLocalRole] = QByteArrayLiteral("isLocal");
     m_model->setItemRoleNames(roles);
+
+    m_haveThemeExplorerInstalled = !QStandardPaths::findExecutable(QStringLiteral("plasmathemeexplorer")).isEmpty();
 }
 
 KCMDesktopTheme::~KCMDesktopTheme()
@@ -243,6 +246,16 @@ void KCMDesktopTheme::defaults()
     setSelectedPlugin(QStringLiteral("default"));
 }
 
+bool KCMDesktopTheme::canEditThemes() const
+{
+    return m_haveThemeExplorerInstalled;
+}
+
+void KCMDesktopTheme::editTheme(const QString &theme)
+{
+    QProcess::startDetached(QStringLiteral("plasmathemeexplorer -t ") % theme);
+}
+
 void KCMDesktopTheme::updateNeedsSave()
 {
     setNeedsSave(!m_pendingRemoval.isEmpty() || m_selectedPlugin != m_defaultTheme->themeName());
diff --git a/kcms/desktoptheme/kcm.h b/kcms/desktoptheme/kcm.h
index a14f4cf8..2509e9fb 100644
--- a/kcms/desktoptheme/kcm.h
+++ b/kcms/desktoptheme/kcm.h
@@ -35,6 +35,7 @@ class KCMDesktopTheme : public KQuickAddons::ConfigModule
     Q_OBJECT
     Q_PROPERTY(QStandardItemModel *desktopThemeModel READ desktopThemeModel CONSTANT)
     Q_PROPERTY(QString selectedPlugin READ selectedPlugin WRITE setSelectedPlugin NOTIFY selectedPluginChanged)
+    Q_PROPERTY(bool canEditThemes READ canEditThemes CONSTANT)
 
 public:
     enum Roles {
@@ -51,6 +52,7 @@ public:
 
     QString selectedPlugin() const;
     void setSelectedPlugin(const QString &plugin);
+    bool canEditThemes() const;
 
     Q_INVOKABLE void getNewThemes();
     Q_INVOKABLE void installThemeFromFile(const QUrl &file);
@@ -60,6 +62,8 @@ public:
 
     Q_INVOKABLE int indexOf(const QString &themeName) const;
 
+    Q_INVOKABLE void editTheme(const QString &themeName);
+
 Q_SIGNALS:
     void selectedPluginChanged(const QString &plugin);
     void showInfoMessage(const QString &infoMessage);
@@ -78,6 +82,7 @@ private:
     QStringList m_pendingRemoval;
     Plasma::Theme *m_defaultTheme;
     QHash<QString, Plasma::Theme*> m_themes;
+    bool m_haveThemeExplorerInstalled;
 };
 
 Q_DECLARE_LOGGING_CATEGORY(KCM_DESKTOP_THEME)
diff --git a/kcms/desktoptheme/package/contents/ui/main.qml b/kcms/desktoptheme/package/contents/ui/main.qml
index e58a15c0..93fdf0bd 100644
--- a/kcms/desktoptheme/package/contents/ui/main.qml
+++ b/kcms/desktoptheme/package/contents/ui/main.qml
@@ -25,6 +25,7 @@ import QtQuick.Controls 1.0 as QtControls
 
 import org.kde.kcm 1.0
 import org.kde.kirigami 2.0 // for units
+import org.kde.plasma.components 2.0 as PlasmaComponents //the round toolbutton
 
 Item {
     implicitWidth: Units.gridUnit * 20
@@ -77,11 +78,25 @@ Item {
                             }
                         }
 
-                        Item {
+                        MouseArea {
                             anchors {
                                 fill: parent
                                 margins: Units.smallSpacing * 2
                             }
+                            hoverEnabled: true
+                            onClicked: {
+                                grid.currentIndex = index
+                                kcm.selectedPlugin = model.pluginName
+                            }
+
+                            Timer {
+                                interval: 1000
+                                running: parent.containsMouse && !parent.pressedButtons
+                                onTriggered: {
+                                    Tooltip.showText(parent, Qt.point(parent.mouseX, parent.mouseY), model.themeName);
+                                }
+                            }
+
                             ThemePreview {
                                 id: preview
                                 anchors {
@@ -92,6 +107,27 @@ Item {
                                 }
                                 themeName: model.pluginName
                             }
+
+                            PlasmaComponents.ToolButton {
+                                anchors {
+                                    bottom: preview.bottom
+                                    right: preview.right
+                                    margins: units.smallSpacing
+                                }
+                                iconSource: "document-edit"
+                                tooltip: i18("Edit theme")
+                                flat: false
+                                onClicked: kcm.editTheme(model.pluginName)
+                                visible: kcm.canEditThemes
+                                opacity: parent.containsMouse ? 1 : 0
+                                Behavior on opacity {
+                                    PropertyAnimation {
+                                        duration: units.longDuration
+                                        easing.type: Easing.OutQuad
+                                    }
+                                }
+                            }
+
                             QtControls.Label {
                                 id: label
                                 anchors {
@@ -122,21 +158,6 @@ Item {
                                 }
                             }
                         }
-                        MouseArea {
-                            anchors.fill: parent
-                            hoverEnabled: true
-                            onClicked: {
-                                grid.currentIndex = index
-                                kcm.selectedPlugin = model.pluginName
-                            }
-                            Timer {
-                                interval: 1000
-                                running: parent.containsMouse && !parent.pressedButtons
-                                onTriggered: {
-                                    Tooltip.showText(parent, Qt.point(parent.mouseX, parent.mouseY), model.themeName);
-                                }
-                            }
-                        }
                     }
                 }
                 Timer {
diff --git a/kcms/formats/kcmformats.cpp b/kcms/formats/kcmformats.cpp
index 0a0a72dc..d40e35ed 100644
--- a/kcms/formats/kcmformats.cpp
+++ b/kcms/formats/kcmformats.cpp
@@ -330,7 +330,7 @@ void KCMFormats::updateExample()
     const QString numberExample = nloc.toString(1000.01);
     const QString timeExample = i18n("%1 (long format)", tloc.toString(QDateTime::currentDateTime())) + QStringLiteral("\n") +
             i18n("%1 (short format)", tloc.toString(QDateTime::currentDateTime(), QLocale::ShortFormat));
-    const QString currencyExample = cloc.toCurrencyString(24);
+    const QString currencyExample = cloc.toCurrencyString(24.00);
 
     QString measurementSetting;
     if (mloc.measurementSystem() == QLocale::ImperialUKSystem) {
diff --git a/kcms/formats/kcmformatswidget.ui b/kcms/formats/kcmformatswidget.ui
index dfe90648..938b5856 100644
--- a/kcms/formats/kcmformatswidget.ui
+++ b/kcms/formats/kcmformatswidget.ui
@@ -235,7 +235,7 @@
        <item row="8" column="0">
         <widget class="QLabel" name="labelMeasurement_2">
          <property name="text">
-          <string><b>Examples</b></string>
+          <string><b>Description</b></string>
          </property>
          <property name="alignment">
           <set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
diff --git a/kcms/icons/icons.cpp b/kcms/icons/icons.cpp
index 586306d0..bd83c0b4 100644
--- a/kcms/icons/icons.cpp
+++ b/kcms/icons/icons.cpp
@@ -99,7 +99,7 @@ KIconConfig::KIconConfig(QWidget *parent)
     lbl->setBuddy(mpSizeBox);
     grid->addWidget(mpSizeBox, 0, 1, Qt::AlignLeft);
 
-    mpAnimatedCheck = new QCheckBox(i18n("Animate icons"), m_pTab1);
+    mpAnimatedCheck = new QCheckBox(i18n("Enable icon animations"), m_pTab1);
     connect(mpAnimatedCheck, &QCheckBox::toggled, this, &KIconConfig::slotAnimatedCheck);
     grid->addWidget(mpAnimatedCheck, 2, 0, 1, 2, Qt::AlignLeft);
     grid->setRowStretch(3, 10);
diff --git a/kcms/input/CMakeLists.txt b/kcms/input/CMakeLists.txt
index eef23321..b271e001 100644
--- a/kcms/input/CMakeLists.txt
+++ b/kcms/input/CMakeLists.txt
@@ -7,55 +7,39 @@ add_definitions(-DTRANSLATION_DOMAIN=\"kcminput\")
 
 add_subdirectory( pics )
 
-
-########### next target ###############
-
-set(kapplymousetheme_SRCS kapplymousetheme.cpp )
-
-
-add_executable(kapplymousetheme ${kapplymousetheme_SRCS})
-
-target_link_libraries(kapplymousetheme ${X11_Xrender_LIB} ${X11_X11_LIB})
-if (X11_Xcursor_FOUND)
-   target_link_libraries(kapplymousetheme ${X11_Xcursor_LIB})
-   target_include_directories(kapplymousetheme PRIVATE ${X11_Xcursor_INCLUDE_PATH})
-endif ()
-
-install(TARGETS kapplymousetheme ${INSTALL_TARGETS_DEFAULT_ARGS})
+## Add common files here.
+set(kcminput_backend_SRCS
+    mousebackend.cpp
+    mousesettings.cpp
+    logging.cpp)
+set(kcminput_backend_LIBS)
+include(backends/x11.cmake)
 
 
 ########### next target ###############
 
-set(kcm_input_PART_SRCS mouse.cpp main.cpp)
+set(kcm_input_PART_SRCS
+    mouse.cpp
+    main.cpp
+    ${kcminput_backend_SRCS}
+)
 
 set(klauncher_xml ${KINIT_DBUS_INTERFACES_DIR}/kf5_org.kde.KLauncher.xml)
 
 ki18n_wrap_ui(kcm_input_PART_SRCS kcmmouse.ui)
 qt5_add_dbus_interface(kcm_input_PART_SRCS ${klauncher_xml} klauncher_iface)
 
-add_library(kcm_input MODULE ${kcm_input_PART_SRCS})
-
-include_directories(${X11_X11_INCLUDE_PATH}
-                    ${X11_Xinput_INCLUDE_PATH}
-                    ${Evdev_INCLUDE_DIRS})
+add_library(kcm_input MODULE ${kcm_input_PART_SRCS} ${kcminput_backend_SRCS})
 
 target_link_libraries(kcm_input
     Qt5::DBus
-    Qt5::X11Extras
     KF5::KCMUtils
     KF5::I18n
     KF5::KIOCore
     KF5::KIOWidgets
     KF5::KDELibs4Support
-    ${X11_X11_LIB}
-    ${X11_Xinput_LIB}
+    ${kcminput_backend_LIBS}
 )
-if (X11_Xcursor_FOUND)
-   target_link_libraries(kcm_input ${X11_Xcursor_LIB})
-endif ()
-if (X11_Xfixes_FOUND)
-   target_link_libraries(kcm_input ${X11_Xfixes_LIB})
-endif ()
 
 install(TARGETS kcm_input  DESTINATION ${PLUGIN_INSTALL_DIR} )
 
diff --git a/kcms/input/backends/x11.cmake b/kcms/input/backends/x11.cmake
new file mode 100644
index 00000000..a7c3e480
--- /dev/null
+++ b/kcms/input/backends/x11.cmake
@@ -0,0 +1,43 @@
+# // krazy:excludeall=copyright,license
+
+set(kcminput_backend_SRCS
+    ${kcminput_backend_SRCS}
+    backends/x11/x11mousebackend.cpp
+)
+
+set(kcminput_backend_LIBS
+    Qt5::X11Extras
+    ${X11_X11_LIB}
+    ${X11_Xinput_LIB}
+    ${kcminput_backend_LIBS}
+)
+
+include_directories(${X11_X11_INCLUDE_PATH}
+                    ${X11_Xinput_INCLUDE_PATH}
+                    ${Evdev_INCLUDE_DIRS}
+                    ${XORGLIBINPUT_INCLUDE_DIRS})
+
+if (X11_Xcursor_FOUND)
+    set(kcminput_backend_LIBS
+        ${X11_Xcursor_LIB}
+        ${kcminput_backend_LIBS}
+    )
+    include_directories(${X11_Xcursor_INCLUDE_PATH})
+endif ()
+
+
+set(kapplymousetheme_SRCS
+    backends/x11/kapplymousetheme.cpp)
+
+add_executable(kapplymousetheme ${kapplymousetheme_SRCS} ${kcminput_backend_SRCS})
+
+target_link_libraries(kapplymousetheme
+    Qt5::Gui
+    Qt5::DBus
+    KF5::CoreAddons
+    KF5::ConfigCore
+    KF5::I18n
+    ${kcminput_backend_LIBS}
+)
+
+install(TARGETS kapplymousetheme ${INSTALL_TARGETS_DEFAULT_ARGS})
diff --git a/kcms/input/backends/x11/kapplymousetheme.cpp b/kcms/input/backends/x11/kapplymousetheme.cpp
new file mode 100644
index 00000000..e520207f
--- /dev/null
+++ b/kcms/input/backends/x11/kapplymousetheme.cpp
@@ -0,0 +1,54 @@
+/*
+ * main.cpp
+ *
+ * Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer at kde.org>
+ * Copyright (c) 2005 Lubos Lunak <l.lunak at kde.org>
+ * Copyright (c) 2017 Xuetian Weng <wengxt at gmail.com>
+ *
+ * Requires the Qt widget libraries, available at no cost at
+ * http://www.troll.no/
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+#include <QGuiApplication>
+#include <QFile>
+
+#include "mousebackend.h"
+
+int main( int argc, char* argv[] )
+{
+    int ret = 0;
+    QGuiApplication app(argc, argv);
+    if( argc != 3 )
+        return 1;
+    QString theme = QFile::decodeName(argv[ 1 ]);
+    QString size = QFile::decodeName(argv[ 2 ]);
+    auto backend = MouseBackend::implementation();
+    if (!backend || !backend->isValid()) {
+        return 2;
+    }
+
+    // Note: If you update this code, update main.cpp as well.
+
+    // use a default value for theme only if it's not configured at all, not even in X resources
+    if(theme.isEmpty() && backend->currentCursorTheme().isEmpty())
+    {
+        theme = "breeze_cursors";
+        ret = 10; // means to switch to default
+    }
+
+    backend->applyCursorTheme(theme, size.toInt());
+    return ret;
+}
diff --git a/kcms/input/backends/x11/x11mousebackend.cpp b/kcms/input/backends/x11/x11mousebackend.cpp
new file mode 100644
index 00000000..5b5c7163
--- /dev/null
+++ b/kcms/input/backends/x11/x11mousebackend.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 "x11mousebackend.h"
+#include "mousesettings.h"
+#include <config-X11.h>
+
+#include <QFile>
+#include <QX11Info>
+#include <KLocalizedString>
+#include <evdev-properties.h>
+#include <libinput-properties.h>
+
+#include <X11/X.h>
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/extensions/XInput2.h>
+#include <X11/extensions/XI.h>
+#include <X11/Xutil.h>
+#ifdef HAVE_XCURSOR
+#  include <X11/Xcursor/Xcursor.h>
+#include <X11/extensions/XInput.h>
+#endif
+
+static const char PROFILE_NONE[] = I18N_NOOP("None");
+static const char PROFILE_ADAPTIVE[] = I18N_NOOP("Adaptive");
+static const char PROFILE_FLAT[] = I18N_NOOP("Flat");
+
+struct ScopedXDeleter {
+    static inline void cleanup(void* pointer)
+    {
+        if (pointer) {
+            XFree(pointer);
+        }
+    }
+};
+
+template<typename Callback>
+static void XI2ForallPointerDevices(Display* dpy, const Callback& callback)
+{
+    int ndevices_return;
+    XIDeviceInfo* info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return);
+    if (!info) {
+        return;
+    }
+    for (int i = 0; i < ndevices_return; ++i) {
+        if ((info + i)->use == XISlavePointer) {
+            callback(info + i);
+        }
+    }
+    XIFreeDeviceInfo(info);
+}
+
+template<typename Callback>
+static void XIForallPointerDevices(Display* dpy, const Callback& callback)
+{
+    int ndevices_return;
+    XDeviceInfo* info = XListInputDevices(dpy, &ndevices_return);
+    if (!info) {
+        return;
+    }
+    for (int i = 0; i < ndevices_return; ++i) {
+        if (info[i].use == IsXPointer || info[i].use == IsXExtensionPointer) {
+            callback(info + i);
+        }
+    }
+    XFreeDeviceList(info);
+}
+
+X11MouseBackend::X11MouseBackend(QObject* parent) : MouseBackend(parent), m_dpy(nullptr)
+{
+    m_platformX11 = QX11Info::isPlatformX11();
+    if (m_platformX11) {
+        m_dpy = QX11Info::display();
+    } else {
+        // let's hope we have a compatibility system like Xwayland ready
+        m_dpy = XOpenDisplay(nullptr);
+    }
+    initAtom();
+}
+
+void X11MouseBackend::initAtom()
+{
+    if (!m_dpy) {
+        return;
+    }
+
+    m_libinputAccelProfileAvailableAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILES_AVAILABLE, True);
+    m_libinputAccelProfileEnabledAtom = XInternAtom(m_dpy, LIBINPUT_PROP_ACCEL_PROFILE_ENABLED, True);
+    m_libinputNaturalScrollAtom = XInternAtom(m_dpy, LIBINPUT_PROP_NATURAL_SCROLL, True);
+
+    m_evdevScrollDistanceAtom = XInternAtom(m_dpy, EVDEV_PROP_SCROLL_DISTANCE, True);
+    m_evdevWheelEmulationAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL, True);
+    m_evdevWheelEmulationAxesAtom = XInternAtom(m_dpy, EVDEV_PROP_WHEEL_AXES, True);
+
+    m_touchpadAtom = XInternAtom(m_dpy, XI_TOUCHPAD, True);
+}
+
+
+X11MouseBackend::~X11MouseBackend()
+{
+    if (!m_platformX11 && m_dpy) {
+        XCloseDisplay(m_dpy);
+    }
+}
+
+bool X11MouseBackend::supportScrollPolarity()
+{
+    return m_numButtons >= 5;
+}
+
+QStringList X11MouseBackend::supportedAccelerationProfiles()
+{
+    return m_supportedAccelerationProfiles;
+}
+
+QString X11MouseBackend::accelerationProfile()
+{
+    return m_accelerationProfile;
+}
+
+double X11MouseBackend::accelRate()
+{
+    return m_accelRate;
+}
+
+MouseHanded X11MouseBackend::handed()
+{
+    return m_handed;
+}
+
+int X11MouseBackend::threshold()
+{
+    return m_threshold;
+}
+
+void X11MouseBackend::load()
+{
+    if (!m_dpy) {
+        return;
+    }
+
+    m_accelRate = 1.0;
+    int accel_num, accel_den;
+    XGetPointerControl(m_dpy, &accel_num, &accel_den, &m_threshold);
+    m_accelRate = double(accel_num) / double(accel_den);
+
+    // get settings from X server
+    unsigned char map[256];
+    m_numButtons = XGetPointerMapping(m_dpy, map, 256);
+    m_middleButton = -1;
+
+    m_handed = MouseHanded::NotSupported;
+    // ## keep this in sync with KGlobalSettings::mouseSettings
+    if (m_numButtons == 2) {
+        if (map[0] == 1 && map[1] == 2) {
+            m_handed = MouseHanded::Right;
+        } else if (map[0] == 2 && map[1] == 1) {
+            m_handed = MouseHanded::Left;
+        }
+    } else if (m_numButtons >= 3) {
+        m_middleButton = map[1];
+        if (map[0] == 1 && map[2] == 3) {
+            m_handed = MouseHanded::Right;
+        } else if (map[0] == 3 && map[2] == 1) {
+            m_handed = MouseHanded::Left;
+        }
+    }
+
+    m_supportedAccelerationProfiles.clear();
+    bool adaptiveAvailable = false;
+    bool flatAvailable = false;
+    bool adaptiveEnabled = false;
+    bool flatEnabled = false;
+    XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) {
+        int deviceid = info->deviceid;
+        Status status;
+        Atom type_return;
+        int format_return;
+        unsigned long num_items_return;
+        unsigned long bytes_after_return;
+
+        unsigned char *_data = nullptr;
+        //data returned is an 2 byte boolean
+        status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2,
+                                False, XA_INTEGER, &type_return, &format_return,
+                                &num_items_return, &bytes_after_return, &_data);
+        QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data);
+        _data = nullptr;
+        if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) {
+            return;
+        }
+        adaptiveAvailable = adaptiveAvailable || data[0];
+        flatAvailable = flatAvailable || data[1];
+
+        //data returned is an 2 byte boolean
+        status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, 0, 2,
+                                False, XA_INTEGER, &type_return, &format_return,
+                                &num_items_return, &bytes_after_return, &_data);
+        data.reset(_data);
+        _data = nullptr;
+        if (status != Success || type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) {
+            return;
+        }
+        adaptiveEnabled = adaptiveEnabled || data[0];
+        flatEnabled = flatEnabled || data[1];
+    });
+
+    if (adaptiveAvailable) {
+        m_supportedAccelerationProfiles << PROFILE_ADAPTIVE;
+    }
+    if (flatAvailable) {
+        m_supportedAccelerationProfiles << PROFILE_FLAT;
+    }
+    if (adaptiveAvailable || flatAvailable) {
+        m_supportedAccelerationProfiles << PROFILE_NONE;
+    }
+
+    m_accelerationProfile = PROFILE_NONE;
+    if (adaptiveEnabled) {
+        m_accelerationProfile = PROFILE_ADAPTIVE;
+    } else if (flatEnabled) {
+        m_accelerationProfile = PROFILE_FLAT;
+    }
+}
+
+void X11MouseBackend::apply(const MouseSettings& settings, bool force)
+{
+    // 256 might seems extreme, but X has already been known to return 32,
+    // and we don't want to truncate things. Xlib limits the table to 256 bytes,
+    // so it's a good upper bound..
+    unsigned char map[256];
+    XGetPointerMapping(m_dpy, map, 256);
+
+    if (settings.handedEnabled && (settings.handedNeedsApply || force)) {
+        if (m_numButtons == 1) {
+            map[0] = (unsigned char) 1;
+        } else if (m_numButtons == 2) {
+            if (settings.handed == MouseHanded::Right) {
+                map[0] = (unsigned char) 1;
+                map[1] = (unsigned char) 3;
+            } else {
+                map[0] = (unsigned char) 3;
+                map[1] = (unsigned char) 1;
+            }
+        } else { // 3 buttons and more
+            if (settings.handed == MouseHanded::Right) {
+                map[0] = (unsigned char) 1;
+                map[1] = (unsigned char) m_middleButton;
+                map[2] = (unsigned char) 3;
+            } else {
+                map[0] = (unsigned char) 3;
+                map[1] = (unsigned char) m_middleButton;
+                map[2] = (unsigned char) 1;
+            }
+        }
+
+        int retval;
+        if (m_numButtons >= 1) {
+            while ((retval = XSetPointerMapping(m_dpy, map,
+                                                m_numButtons)) == MappingBusy)
+                /* keep trying until the pointer is free */
+            { };
+        }
+
+        // apply reverseScrollPolarity for all non-touchpad pointer, touchpad
+        // are belong to kcm touchpad.
+        XIForallPointerDevices(m_dpy, [this, &settings](XDeviceInfo * info) {
+            int deviceid = info->id;
+            if (info->type == m_touchpadAtom) {
+                return;
+            }
+            if (libinputApplyReverseScroll(deviceid, settings.reverseScrollPolarity)) {
+                return;
+            }
+            evdevApplyReverseScroll(deviceid, settings.reverseScrollPolarity);
+        });
+
+    }
+
+    XI2ForallPointerDevices(m_dpy, [&] (XIDeviceInfo *info) {
+        libinputApplyAccelerationProfile(info->deviceid, settings.currentAccelProfile);
+    });
+
+    XChangePointerControl(m_dpy,
+                          true, true, int(qRound(settings.accelRate * 10)), 10, settings.thresholdMove);
+
+    XFlush(m_dpy);
+}
+
+QString X11MouseBackend::currentCursorTheme()
+{
+    if (!m_dpy) {
+        return QString();
+    }
+
+    QByteArray name = XGetDefault(m_dpy, "Xcursor", "theme");
+#ifdef HAVE_XCURSOR
+    if (name.isEmpty()) {
+        name = QByteArray(XcursorGetTheme(m_dpy));
+    }
+#endif
+    return QFile::decodeName(name);
+}
+
+void X11MouseBackend::applyCursorTheme(const QString& theme, int size)
+{
+#ifdef HAVE_XCURSOR
+
+    // Apply the KDE cursor theme to ourselves
+    if (m_dpy) {
+        return;
+    }
+    if (!theme.isEmpty()) {
+        XcursorSetTheme(m_dpy, QFile::encodeName(theme));
+    }
+
+    if (size >= 0) {
+        XcursorSetDefaultSize(m_dpy, size);
+    }
+
+    // Load the default cursor from the theme and apply it to the root window.
+    Cursor handle = XcursorLibraryLoadCursor(m_dpy, "left_ptr");
+    XDefineCursor(m_dpy, DefaultRootWindow(m_dpy), handle);
+    XFreeCursor(m_dpy, handle); // Don't leak the cursor
+    XFlush(m_dpy);
+#endif
+}
+
+bool X11MouseBackend::evdevApplyReverseScroll(int deviceid, bool reverse)
+{
+    // Check atom availability first.
+    if (m_evdevWheelEmulationAtom == None || m_evdevScrollDistanceAtom == None ||
+        m_evdevWheelEmulationAxesAtom == None) {
+        return false;
+    }
+    Status status;
+    Atom type_return;
+    int format_return;
+    unsigned long num_items_return;
+    unsigned long bytes_after_return;
+
+    unsigned char* _data = nullptr;
+    //data returned is an 1 byte boolean
+    status = XIGetProperty(m_dpy, deviceid, m_evdevWheelEmulationAtom, 0, 1,
+                           False, XA_INTEGER, &type_return, &format_return,
+                           &num_items_return, &bytes_after_return, &_data);
+    QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data);
+    _data = nullptr;
+    if (status != Success) {
+        return false;
+    }
+
+    // pointer device without wheel emulation
+    if (type_return != XA_INTEGER || data == NULL || *data == False) {
+        status = XIGetProperty(m_dpy, deviceid, m_evdevScrollDistanceAtom, 0, 3,
+                               False, XA_INTEGER, &type_return, &format_return,
+                               &num_items_return, &bytes_after_return, &_data);
+        data.reset(_data);
+        _data = nullptr;
+        // negate scroll distance
+        if (status == Success && type_return == XA_INTEGER &&
+                format_return == 32 && num_items_return == 3) {
+            int32_t* vals = (int32_t*)data.data();
+            for (unsigned long i = 0; i < num_items_return; ++i) {
+                int32_t val = *(vals + i);
+                *(vals + i) = (int32_t)(reverse ? -abs(val) : abs(val));
+            }
+            XIChangeProperty(m_dpy, deviceid, m_evdevScrollDistanceAtom, XA_INTEGER,
+                             32, XIPropModeReplace, data.data(), 3);
+        }
+    } else { // wheel emulation used, reverse wheel axes
+        status = XIGetProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, 0, 4,
+                               False, XA_INTEGER, &type_return, &format_return,
+                               &num_items_return, &bytes_after_return, &_data);
+        data.reset(_data);
+        _data = nullptr;
+        if (status == Success && type_return == XA_INTEGER &&
+                format_return == 8 && num_items_return == 4) {
+            // when scroll direction is not reversed,
+            // up button id should be smaller than down button id,
+            // up/left are odd elements, down/right are even elements
+            for (int i = 0; i < 2; ++i) {
+                unsigned char odd = data[i * 2];
+                unsigned char even = data[i * 2 + 1];
+                unsigned char max_elem = std::max(odd, even);
+                unsigned char min_elem = std::min(odd, even);
+                data[i * 2] = reverse ? max_elem : min_elem;
+                data[i * 2 + 1] = reverse ? min_elem : max_elem;
+            }
+            XIChangeProperty(m_dpy, deviceid, m_evdevWheelEmulationAxesAtom, XA_INTEGER,
+                             8, XIPropModeReplace, data.data(), 4);
+        }
+    }
+
+    return true;
+}
+
+bool X11MouseBackend::libinputApplyReverseScroll(int deviceid, bool reverse)
+{
+    // Check atom availability first.
+    if (m_libinputNaturalScrollAtom == None) {
+        return false;
+    }
+    Status status;
+    Atom type_return;
+    int format_return;
+    unsigned long num_items_return;
+    unsigned long bytes_after_return;
+
+    unsigned char *_data = nullptr;
+    //data returned is an 1 byte boolean
+    status = XIGetProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, 0, 1,
+                            False, XA_INTEGER, &type_return, &format_return,
+                            &num_items_return, &bytes_after_return, &_data);
+    if (status != Success) {
+        return false;
+    }
+    QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data);
+    _data = nullptr;
+    if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 1) {
+        return false;
+    }
+    unsigned char natural = reverse ? 1 : 0;
+    XIChangeProperty(m_dpy, deviceid, m_libinputNaturalScrollAtom, XA_INTEGER,
+                        8, XIPropModeReplace, &natural, 1);
+    return true;
+}
+
+void X11MouseBackend::libinputApplyAccelerationProfile(int deviceid, QString profile)
+{
+    unsigned char profileData[2];
+    if (profile == PROFILE_NONE) {
+        profileData[0] = profileData[1] = 0;
+    } else if (profile == PROFILE_ADAPTIVE) {
+        profileData[0] = 1;
+        profileData[1] = 0;
+    } else if (profile == PROFILE_FLAT) {
+        profileData[0] = 0;
+        profileData[1] = 1;
+    }
+    Status status;
+    Atom type_return;
+    int format_return;
+    unsigned long num_items_return;
+    unsigned long bytes_after_return;
+
+    unsigned char *_data = nullptr;
+    //data returned is an 1 byte boolean
+    status = XIGetProperty(m_dpy, deviceid, m_libinputAccelProfileAvailableAtom, 0, 2,
+                            False, XA_INTEGER, &type_return, &format_return,
+                            &num_items_return, &bytes_after_return, &_data);
+    if (status != Success) {
+        return;
+    }
+    QScopedArrayPointer<unsigned char, ScopedXDeleter> data(_data);
+    _data = nullptr;
+    if (type_return != XA_INTEGER || !data || format_return != 8 || num_items_return != 2) {
+        return;
+    }
+    // Check availability for profile.
+    if (profileData[0] > data[0] || profileData[1] > data[1]) {
+        return;
+    }
+    XIChangeProperty(m_dpy, deviceid, m_libinputAccelProfileEnabledAtom, XA_INTEGER,
+                        8, XIPropModeReplace, profileData, 2);
+}
diff --git a/kcms/input/backends/x11/x11mousebackend.h b/kcms/input/backends/x11/x11mousebackend.h
new file mode 100644
index 00000000..b58d90e6
--- /dev/null
+++ b/kcms/input/backends/x11/x11mousebackend.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 XLIBMOUSEBACKEND_H
+#define XLIBMOUSEBACKEND_H
+
+#include "mousebackend.h"
+
+#include <QX11Info>
+#include <X11/Xdefs.h>
+
+class X11MouseBackend : public MouseBackend
+{
+    Q_OBJECT
+public:
+    X11MouseBackend(QObject *parent = nullptr);
+    ~X11MouseBackend();
+
+    bool isValid() const override { return m_dpy != nullptr; }
+
+    void load() override;
+    bool supportScrollPolarity() override;
+    QStringList supportedAccelerationProfiles() override;
+    QString accelerationProfile() override;
+    double accelRate() override;
+    MouseHanded handed() override;
+    int threshold() override;
+    void apply(const MouseSettings & settings, bool force) override;
+
+    QString currentCursorTheme() override;
+    void applyCursorTheme(const QString &name, int size) override;
+
+private:
+    void initAtom();
+    bool evdevApplyReverseScroll(int deviceid, bool reverse);
+    bool libinputApplyReverseScroll(int deviceid, bool reverse);
+    void libinputApplyAccelerationProfile(int deviceid, QString profile);
+
+    Atom m_libinputAccelProfileAvailableAtom;
+    Atom m_libinputAccelProfileEnabledAtom;
+    Atom m_libinputNaturalScrollAtom;
+
+    Atom m_evdevWheelEmulationAtom;
+    Atom m_evdevScrollDistanceAtom;
+    Atom m_evdevWheelEmulationAxesAtom;
+
+    Atom m_touchpadAtom;
+    // We may still need to do something on non-X11 platform due to Xwayland.
+    Display* m_dpy;
+    bool m_platformX11;
+    int m_numButtons = 1;
+    MouseHanded m_handed = MouseHanded::NotSupported;
+    double m_accelRate = 1.0;
+    int m_threshold = 0;
+    int m_middleButton = -1;
+    QStringList m_supportedAccelerationProfiles;
+    QString m_accelerationProfile;
+};
+
+#endif // XLIBMOUSEBACKEND_H
diff --git a/kcms/input/kapplymousetheme.cpp b/kcms/input/kapplymousetheme.cpp
deleted file mode 100644
index ad3db05e..00000000
--- a/kcms/input/kapplymousetheme.cpp
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * main.cpp
- *
- * Copyright (c) 1999 Matthias Hoelzer-Kluepfel <hoelzer at kde.org>
- * Copyright (c) 2005 Lubos Lunak <l.lunak at kde.org>
- *
- * Requires the Qt widget libraries, available at no cost at
- * http://www.troll.no/
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
- */
-
-#include <config-X11.h>
-
-#include <stdlib.h>
-#include <ctype.h>
-#include <X11/Xlib.h>
-
-#ifdef HAVE_XCURSOR
-#  include <X11/Xcursor/Xcursor.h>
-#endif
-
-static Display* dpy;
-Display* display() { return dpy; }
-Window appRootWindow() { return DefaultRootWindow( dpy ); }
-
-static bool isEmpty( const char* str )
-    {
-    if( str == NULL )
-        return true;
-    while( isspace( *str ))
-        ++str;
-    return *str == '\0';
-    }
-
-int main( int argc, char* argv[] )
-    {
-    if( argc != 3 )
-        return 1;
-    dpy = XOpenDisplay( NULL );
-    if( dpy == NULL )
-        return 2;
-    int ret = 0;
-#ifdef HAVE_XCURSOR
-    const char* theme = argv[ 1 ];
-    const char* size = argv[ 2 ];
-
-    // Note: If you update this code, update kapplymousetheme as well.
-
-    // use a default value for theme only if it's not configured at all, not even in X resources
-    if( isEmpty( theme )
-        && isEmpty( XGetDefault( display(), "Xcursor", "theme" ))
-        && isEmpty( XcursorGetTheme( display())))
-    {
-        theme = "breeze_cursors";
-        ret = 10; // means to switch to default
-    }
-
-     // Apply the KDE cursor theme to ourselves
-    if( !isEmpty( theme ))
-        XcursorSetTheme(display(), theme );
-
-    if (!isEmpty( size ))
-        XcursorSetDefaultSize(display(), atoi( size ));
-
-    // Load the default cursor from the theme and apply it to the root window.
-    Cursor handle = XcursorLibraryLoadCursor(display(), "left_ptr");
-    XDefineCursor(display(), appRootWindow(), handle);
-    XFreeCursor(display(), handle); // Don't leak the cursor
-
-#else
-    ( void ) argv;
-#endif
-    XCloseDisplay( dpy );
-    return ret;
-    }
diff --git a/kcms/input/kcmmouse.ui b/kcms/input/kcmmouse.ui
index d4357f7d..2f0c897a 100644
--- a/kcms/input/kcmmouse.ui
+++ b/kcms/input/kcmmouse.ui
@@ -202,7 +202,7 @@
       <layout class="QHBoxLayout" name="horizontalLayout" stretch="0,1">
        <item>
         <layout class="QFormLayout" name="formLayout">
-         <item row="0" column="0">
+         <item row="1" column="0">
           <widget class="QLabel" name="label">
            <property name="text">
             <string>Pointer acceleration:</string>
@@ -212,7 +212,7 @@
            </property>
           </widget>
          </item>
-         <item row="1" column="0">
+         <item row="2" column="0">
           <widget class="QLabel" name="label_2">
            <property name="text">
             <string>Pointer threshold:</string>
@@ -222,7 +222,7 @@
            </property>
           </widget>
          </item>
-         <item row="2" column="0">
+         <item row="3" column="0">
           <widget class="QLabel" name="label_3">
            <property name="text">
             <string>Double click interval:</string>
@@ -232,7 +232,7 @@
            </property>
           </widget>
          </item>
-         <item row="3" column="0">
+         <item row="4" column="0">
           <widget class="QLabel" name="label_4">
            <property name="text">
             <string>Drag start time:</string>
@@ -242,7 +242,7 @@
            </property>
           </widget>
          </item>
-         <item row="4" column="0">
+         <item row="5" column="0">
           <widget class="QLabel" name="label_5">
            <property name="text">
             <string>Drag start distance:</string>
@@ -252,7 +252,7 @@
            </property>
           </widget>
          </item>
-         <item row="5" column="0">
+         <item row="6" column="0">
           <widget class="QLabel" name="label_6">
            <property name="text">
             <string>Mouse wheel scrolls by:</string>
@@ -262,7 +262,7 @@
            </property>
           </widget>
          </item>
-         <item row="0" column="1">
+         <item row="1" column="1">
           <widget class="QDoubleSpinBox" name="accel">
            <property name="sizePolicy">
             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -293,7 +293,7 @@
            </property>
           </widget>
          </item>
-         <item row="1" column="1">
+         <item row="2" column="1">
           <widget class="QSpinBox" name="thresh">
            <property name="sizePolicy">
             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -312,7 +312,7 @@
            </property>
           </widget>
          </item>
-         <item row="2" column="1">
+         <item row="3" column="1">
           <widget class="QSpinBox" name="doubleClickInterval">
            <property name="sizePolicy">
             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -340,7 +340,7 @@
            </property>
           </widget>
          </item>
-         <item row="3" column="1">
+         <item row="4" column="1">
           <widget class="QSpinBox" name="dragStartTime">
            <property name="sizePolicy">
             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -365,7 +365,7 @@
            </property>
           </widget>
          </item>
-         <item row="4" column="1">
+         <item row="5" column="1">
           <widget class="QSpinBox" name="dragStartDist">
            <property name="sizePolicy">
             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -387,7 +387,7 @@
            </property>
           </widget>
          </item>
-         <item row="5" column="1">
+         <item row="6" column="1">
           <widget class="QSpinBox" name="wheelScrollLines">
            <property name="sizePolicy">
             <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
@@ -409,6 +409,26 @@
            </property>
           </widget>
          </item>
+         <item row="0" column="0">
+          <widget class="QLabel" name="accelerationProfileLabel">
+           <property name="text">
+            <string>Acceleration Profile:</string>
+           </property>
+           <property name="buddy">
+            <cstring>accelProfileComboBox</cstring>
+           </property>
+          </widget>
+         </item>
+         <item row="0" column="1">
+          <widget class="QComboBox" name="accelProfileComboBox">
+           <property name="sizePolicy">
+            <sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
+             <horstretch>0</horstretch>
+             <verstretch>0</verstretch>
+            </sizepolicy>
+           </property>
+          </widget>
+         </item>
         </layout>
        </item>
        <item>
diff --git a/kcms/input/logging.cpp b/kcms/input/logging.cpp
new file mode 100644
index 00000000..31752cfd
--- /dev/null
+++ b/kcms/input/logging.cpp
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 "logging.h"
+
+Q_LOGGING_CATEGORY(KCM_INPUT, "kcm_input")
diff --git a/kcms/input/logging.h b/kcms/input/logging.h
new file mode 100644
index 00000000..3b699280
--- /dev/null
+++ b/kcms/input/logging.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 KCM_INPUT_LOGGING_H
+#define KCM_INPUT_LOGGING_H
+
+#include <QLoggingCategory>
+
+Q_DECLARE_LOGGING_CATEGORY(KCM_INPUT)
+#endif
diff --git a/kcms/input/main.cpp b/kcms/input/main.cpp
index ec2372c1..8cd67c68 100644
--- a/kcms/input/main.cpp
+++ b/kcms/input/main.cpp
@@ -21,89 +21,60 @@
  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 
-#include <config-X11.h>
-
-#include <kconfig.h>
+#include <KConfig>
+#include <KConfigGroup>
 #include <QFile>
 
-#include "mouse.h"
-#include <QX11Info>
+#include "mousesettings.h"
+#include "mousebackend.h"
 
 #include <klauncher_iface.h>
 
-#include <X11/Xlib.h>
-#ifdef HAVE_XCURSOR
-#  include <X11/Xcursor/Xcursor.h>
-#endif
-
 extern "C"
 {
-  Q_DECL_EXPORT void kcminit_mouse()
-  {
-      KConfig *config = new KConfig("kcminputrc", KConfig::NoGlobals );
-
-    Display *dpy = nullptr;
-    const bool platformX11 = QX11Info::isPlatformX11();
-    if (platformX11) {
-        dpy = QX11Info::display();
-    } else {
-        // let's hope we have a compatibility system like Xwayland ready
-        dpy = XOpenDisplay(nullptr);
-    }
-
-    MouseSettings settings;
-    settings.load(config, dpy);
-    settings.apply(true); // force
-
-#ifdef HAVE_XCURSOR
-    KConfigGroup group = config->group("Mouse");
-    QString theme = group.readEntry("cursorTheme", QString());
-    QString size = group.readEntry("cursorSize", QString());
-
-    // Note: If you update this code, update kapplymousetheme as well.
-
-    // use a default value for theme only if it's not configured at all, not even in X resources
-    if( theme.isEmpty()
-        && (!dpy ||
-                (QByteArray( XGetDefault( dpy, "Xcursor", "theme" )).isEmpty()
-                 && QByteArray( XcursorGetTheme( dpy)).isEmpty())))
+    Q_DECL_EXPORT void kcminit_mouse()
     {
-        theme = "breeze_cursors";
+        KConfig* config = new KConfig("kcminputrc", KConfig::NoGlobals);
+
+        auto backend = MouseBackend::implementation();
+
+        MouseSettings settings;
+        settings.load(config, backend);
+        settings.apply(backend, true);    // force
+
+        KConfigGroup group = config->group("Mouse");
+        QString theme = group.readEntry("cursorTheme", QString());
+        QString size = group.readEntry("cursorSize", QString());
+        if (backend) {
+            int intSize = -1;
+            if (size.isEmpty()) {
+                bool ok;
+                uint value = size.toUInt(&ok);
+                if (ok) {
+                    intSize = value;
+                }
+            }
+            // Note: If you update this code, update kapplymousetheme as well.
+
+            // use a default value for theme only if it's not configured at all, not even in X resources
+            if (theme.isEmpty() && backend->currentCursorTheme().isEmpty()) {
+                theme = "breeze_cursors";
+            }
+            backend->applyCursorTheme(theme, intSize);
+        }
+
+        // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment
+        // variables when launching applications.
+        OrgKdeKLauncherInterface klauncher(QStringLiteral("org.kde.klauncher5"),
+                                           QStringLiteral("/KLauncher"),
+                                           QDBusConnection::sessionBus());
+        if (!theme.isEmpty()) {
+            klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), theme);
+        }
+        if (!size.isEmpty()) {
+            klauncher.setLaunchEnv(QStringLiteral("XCURSOR_SIZE"), size);
+        }
+
+        delete config;
     }
-
-     // Apply the KDE cursor theme to ourselves
-    if (dpy) {
-        if( !theme.isEmpty())
-            XcursorSetTheme(dpy, QFile::encodeName(theme));
-
-        if (!size.isEmpty())
-            XcursorSetDefaultSize(dpy, size.toUInt());
-
-        // Load the default cursor from the theme and apply it to the root window.
-        Cursor handle = XcursorLibraryLoadCursor(dpy, "left_ptr");
-        XDefineCursor(dpy, QX11Info::appRootWindow(), handle);
-        XFreeCursor(dpy, handle); // Don't leak the cursor
-    }
-
-    // Tell klauncher to set the XCURSOR_THEME and XCURSOR_SIZE environment
-    // variables when launching applications.
-    OrgKdeKLauncherInterface klauncher(QStringLiteral("org.kde.klauncher5"),
-                                       QStringLiteral("/KLauncher"),
-                                       QDBusConnection::sessionBus());
-    if(!theme.isEmpty())
-        klauncher.setLaunchEnv(QStringLiteral("XCURSOR_THEME"), theme);
-    if( !size.isEmpty())
-        klauncher.setLaunchEnv(QStringLiteral("XCURSOR_SIZE"), size);
-
-#endif
-
-    if (!platformX11) {
-        XFlush(dpy);
-        XCloseDisplay(dpy);
-    }
-
-    delete config;
-  }
 }
-
-
diff --git a/kcms/input/mouse.cpp b/kcms/input/mouse.cpp
index cf6412eb..c857eca6 100644
--- a/kcms/input/mouse.cpp
+++ b/kcms/input/mouse.cpp
@@ -65,15 +65,10 @@
 #include <config-workspace.h>
 
 #include "mouse.h"
+#include "mousebackend.h"
+#include "mousesettings.h"
 
-#include <X11/X.h>
-#include <X11/Xlib.h>
-#include <X11/Xatom.h>
-#include <X11/extensions/XInput2.h>
-#include <X11/Xutil.h>
 #include <kglobalsettings.h>
-#include <QX11Info>
-#include <evdev-properties.h>
 
 #undef Below
 
@@ -82,39 +77,28 @@
 K_PLUGIN_FACTORY(MouseConfigFactory,
         registerPlugin<MouseConfig>(); // mouse
         )
-K_EXPORT_PLUGIN(MouseConfigFactory("kcminput"))
 
 MouseConfig::MouseConfig(QWidget *parent, const QVariantList &args)
-  : KCModule(parent, args)
+  : KCModule(parent, args),
+    backend(MouseBackend::implementation())
 {
     setupUi(this);
 
-    handedGroup->setId(rightHanded, 0);
-    handedGroup->setId(leftHanded, 1);
+    handedGroup->setId(rightHanded, static_cast<int>(MouseHanded::Right));
+    handedGroup->setId(leftHanded, static_cast<int>(MouseHanded::Left));
 
     connect(handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(changed()));
     connect(handedGroup, SIGNAL(buttonClicked(int)), this, SLOT(slotHandedChanged(int)));
     connect(doubleClick, SIGNAL(clicked()), SLOT(changed()));
-    connect(singleClick, SIGNAL(clicked()), this, SLOT(changed()));
 
-    // Only allow setting reversing scroll polarity if we have scroll buttons
-    unsigned char map[20];
-    if (QX11Info::isPlatformX11() && XGetPointerMapping(QX11Info::display(), map, 20) >= 5)
-    {
-      cbScrollPolarity->setEnabled(true);
-      cbScrollPolarity->show();
-    }
-    else
-    {
-      cbScrollPolarity->setEnabled(false);
-      cbScrollPolarity->hide();
-    }
+    connect(singleClick, SIGNAL(clicked()), this, SLOT(changed()));
     connect(cbScrollPolarity, SIGNAL(clicked()), this, SLOT(changed()));
     connect(cbScrollPolarity, SIGNAL(clicked()), this, SLOT(slotScrollPolarityChanged()));
 
     connect(accel, SIGNAL(valueChanged(double)), this, SLOT(changed()));
     connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(changed()));
     connect(thresh, SIGNAL(valueChanged(int)), this, SLOT(slotThreshChanged(int)));
+    connect(accelProfileComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(changed()));
     slotThreshChanged(thresh->value());
 
     // It would be nice if the user had a test field.
@@ -192,19 +176,19 @@ void MouseConfig::setThreshold(int val)
 }
 
 
-int MouseConfig::getHandedness()
+MouseHanded MouseConfig::getHandedness()
 {
     if (rightHanded->isChecked())
-        return RIGHT_HANDED;
+        return MouseHanded::Right;
     else
-        return LEFT_HANDED;
+        return MouseHanded::Left;
 }
 
-void MouseConfig::setHandedness(int val)
+void MouseConfig::setHandedness(MouseHanded val)
 {
     rightHanded->setChecked(false);
     leftHanded->setChecked(false);
-    if (val == RIGHT_HANDED) {
+    if (val == MouseHanded::Right) {
         rightHanded->setChecked(true);
         mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png"));
     }
@@ -212,13 +196,45 @@ void MouseConfig::setHandedness(int val)
         leftHanded->setChecked(true);
         mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png"));
     }
-    settings->m_handedNeedsApply = true;
+    settings->handedNeedsApply = true;
 }
 
 void MouseConfig::load()
 {
     KConfig config("kcminputrc");
-    settings->load(&config);
+    settings->load(&config, backend);
+
+    // settings->load will trigger backend->load so information will be avaialbe
+    // here.
+    // Only allow setting reversing scroll polarity if we have scroll buttons
+    if (backend) {
+        if (backend->supportScrollPolarity())
+        {
+            cbScrollPolarity->setEnabled(true);
+            cbScrollPolarity->show();
+        }
+        else
+        {
+            cbScrollPolarity->setEnabled(false);
+            cbScrollPolarity->hide();
+        }
+    }
+
+    auto accelerationProfiles = backend->supportedAccelerationProfiles();
+    accelProfileComboBox->setEnabled(!accelerationProfiles.isEmpty());
+    accelProfileComboBox->setVisible(!accelerationProfiles.isEmpty());
+    accelerationProfileLabel->setEnabled(!accelerationProfiles.isEmpty());
+    accelerationProfileLabel->setVisible(!accelerationProfiles.isEmpty());
+    accelProfileComboBox->clear();
+    int idx = 0;
+    for (const auto &profile : accelerationProfiles) {
+        accelProfileComboBox->addItem(i18n(profile.toUtf8().constData()), profile);
+        if (profile == settings->currentAccelProfile) {
+            accelProfileComboBox->setCurrentIndex(idx);
+        }
+        idx++;
+    }
+
 
     rightHanded->setEnabled(settings->handedEnabled);
     leftHanded->setEnabled(settings->handedEnabled);
@@ -280,8 +296,9 @@ void MouseConfig::save()
     settings->wheelScrollLines = wheelScrollLines->value();
     settings->singleClick = !doubleClick->isChecked();
     settings->reverseScrollPolarity = cbScrollPolarity->isChecked();
+    settings->currentAccelProfile = accelProfileComboBox->itemData(accelProfileComboBox->currentIndex()).toString();
 
-    settings->apply();
+    settings->apply(backend);
     KConfig config("kcminputrc");
     settings->save(&config);
 
@@ -310,7 +327,7 @@ void MouseConfig::defaults()
 {
     setThreshold(2);
     setAccel(2);
-    setHandedness(RIGHT_HANDED);
+    setHandedness(MouseHanded::Right);
     cbScrollPolarity->setChecked(false);
     doubleClickInterval->setValue(400);
     dragStartTime->setValue(500);
@@ -325,7 +342,7 @@ void MouseConfig::defaults()
     mk_time_to_max->setValue(5000);
     mk_max_speed->setValue(1000);
     mk_curve->setValue(0);
-  
+
     checkAccess();
     changed();
 }
@@ -333,99 +350,11 @@ void MouseConfig::defaults()
 /** No descriptions */
 void MouseConfig::slotHandedChanged(int val)
 {
-    if (val==RIGHT_HANDED)
+    if (val == static_cast<int>(MouseHanded::Right))
         mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_rh.png"));
     else
         mousePix->setPixmap(KStandardDirs::locate("data", "kcminput/pics/mouse_lh.png"));
-    settings->m_handedNeedsApply = true;
-}
-
-void MouseSettings::load(KConfig *config, Display *dpy)
-{
-    // TODO: what's a good threshold default value
-    int threshold = 0;
-    int h = RIGHT_HANDED;
-    double accel = 1.0;
-    if (QX11Info::isPlatformX11()) {
-        int accel_num, accel_den;
-
-        XGetPointerControl(dpy, &accel_num, &accel_den, &threshold);
-        accel = float(accel_num) / float(accel_den);
-
-        // get settings from X server
-        unsigned char map[20];
-        num_buttons = XGetPointerMapping(dpy, map, 20);
-
-        handedEnabled = true;
-
-        // ## keep this in sync with KGlobalSettings::mouseSettings
-        if (num_buttons == 1)
-        {
-            /* disable button remapping */
-            handedEnabled = false;
-        }
-        else if (num_buttons == 2)
-        {
-            if ((int)map[0] == 1 && (int)map[1] == 2)
-                h = RIGHT_HANDED;
-            else if ((int)map[0] == 2 && (int)map[1] == 1)
-                h = LEFT_HANDED;
-            else
-                /* custom button setup: disable button remapping */
-                handedEnabled = false;
-        }
-        else
-        {
-            middle_button = (int)map[1];
-            if ((int)map[0] == 1 && (int)map[2] == 3)
-            h = RIGHT_HANDED;
-            else if ((int)map[0] == 3 && (int)map[2] == 1)
-            h = LEFT_HANDED;
-            else
-            {
-            /* custom button setup: disable button remapping */
-            handedEnabled = false;
-            }
-        }
-    } else {
-        // other platforms
-        handedEnabled = true;
-    }
-
-    KConfigGroup group = config->group("Mouse");
-    double a = group.readEntry("Acceleration", -1.0);
-    if (a == -1)
-        accelRate = accel;
-    else
-        accelRate = a;
-
-    int t = group.readEntry("Threshold", -1);
-    if (t == -1)
-        thresholdMove = threshold;
-    else
-        thresholdMove = t;
-
-    QString key = group.readEntry("MouseButtonMapping");
-    if (key == "RightHanded")
-        handed = RIGHT_HANDED;
-    else if (key == "LeftHanded")
-        handed = LEFT_HANDED;
-#ifdef __GNUC__
-#warning was key == NULL how was this working? is key.isNull() what the coder meant?
-#endif
-    else if (key.isNull())
-        handed = h;
-    reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false);
-    m_handedNeedsApply = false;
-
-    // SC/DC/AutoSelect/ChangeCursor
-    group = config->group("KDE");
-    doubleClickInterval = group.readEntry("DoubleClickInterval", 400);
-    dragStartTime = group.readEntry("StartDragTime", 500);
-    dragStartDist = group.readEntry("StartDragDist", 4);
-    wheelScrollLines = group.readEntry("WheelScrollLines", 3);
-
-    singleClick = group.readEntry("SingleClick", KDE_DEFAULT_SINGLECLICK);
+    settings->handedNeedsApply = true;
 }
 
 void MouseConfig::slotThreshChanged(int value)
@@ -443,172 +372,9 @@ void MouseConfig::slotWheelScrollLinesChanged(int value)
     wheelScrollLines->setSuffix(i18np(" line", " lines", value));
 }
 
-void MouseSettings::apply(bool force)
-{
-    if (!QX11Info::isPlatformX11()) {
-        return;
-    }
-    XChangePointerControl(QX11Info::display(),
-                          true, true, int(qRound(accelRate*10)), 10, thresholdMove);
-
-    // 256 might seems extreme, but X has already been known to return 32,
-    // and we don't want to truncate things. Xlib limits the table to 256 bytes,
-    // so it's a good upper bound..
-    unsigned char map[256];
-    num_buttons = XGetPointerMapping(QX11Info::display(), map, 256);
-
-    int remap=(num_buttons>=1);
-    if (handedEnabled && (m_handedNeedsApply || force)) {
-        if (num_buttons == 1)
-        {
-            map[0] = (unsigned char) 1;
-        }
-        else if (num_buttons == 2)
-        {
-            if (handed == RIGHT_HANDED)
-            {
-                map[0] = (unsigned char) 1;
-                map[1] = (unsigned char) 3;
-            }
-            else
-            {
-                map[0] = (unsigned char) 3;
-                map[1] = (unsigned char) 1;
-            }
-        }
-        else // 3 buttons and more
-        {
-            if (handed == RIGHT_HANDED)
-            {
-                map[0] = (unsigned char) 1;
-                map[1] = (unsigned char) middle_button;
-                map[2] = (unsigned char) 3;
-            }
-            else
-            {
-                map[0] = (unsigned char) 3;
-                map[1] = (unsigned char) middle_button;
-                map[2] = (unsigned char) 1;
-            }
-        }
-
-        int retval;
-        if (remap) {
-            while ((retval=XSetPointerMapping(QX11Info::display(), map,
-                                              num_buttons)) == MappingBusy)
-              /* keep trying until the pointer is free */
-            { };
-        }
-
-        // apply reverseScrollPolarity
-        Display *dpy = QX11Info::display();
-        Atom prop_wheel_emulation = XInternAtom(dpy, EVDEV_PROP_WHEEL, True);
-        Atom prop_scroll_distance = XInternAtom(dpy, EVDEV_PROP_SCROLL_DISTANCE, True);
-        Atom prop_wheel_emulation_axes = XInternAtom(dpy, EVDEV_PROP_WHEEL_AXES, True);
-        int ndevices_return;
-        XIDeviceInfo *info = XIQueryDevice(dpy, XIAllDevices, &ndevices_return);
-        if (!info) {
-            return;
-        }
-        for (int i = 0; i < ndevices_return; ++i) {
-            if ((info + i)->use == XISlavePointer) {
-                int deviceid = (info + i)->deviceid;
-                Status status;
-                Atom type_return;
-                int format_return;
-                unsigned long num_items_return;
-                unsigned long bytes_after_return;
-
-                unsigned char *data = nullptr;
-                unsigned char *data2 = nullptr;
-                //data returned is an 1 byte boolean
-                status = XIGetProperty(dpy, deviceid, prop_wheel_emulation, 0, 1,
-                                       False, XA_INTEGER, &type_return, &format_return,
-                                       &num_items_return, &bytes_after_return, &data);
-                if (status != Success) {
-                    continue;
-                }
-
-                // pointer device without wheel emulation
-                if (type_return != XA_INTEGER || data == NULL || *data == False) {
-                    status = XIGetProperty(dpy, deviceid, prop_scroll_distance, 0, 3,
-                                           False, XA_INTEGER, &type_return, &format_return,
-                                           &num_items_return, &bytes_after_return, &data2);
-                    // negate scroll distance
-                    if (status == Success && type_return == XA_INTEGER &&
-                          format_return == 32 && num_items_return == 3) {
-                        int32_t *vals = (int32_t*)data2;
-                        for (unsigned long i=0; i<num_items_return; ++i) {
-                            int32_t val = *(vals+i);
-                            *(vals+i) = (int32_t) (reverseScrollPolarity ? -abs(val) : abs(val));
-                        }
-                        XIChangeProperty(dpy, deviceid, prop_scroll_distance, XA_INTEGER,
-                                         32, XIPropModeReplace, data2, 3);
-                    }
-                } else { // wheel emulation used, reverse wheel axes
-                    status = XIGetProperty(dpy, deviceid, prop_wheel_emulation_axes, 0, 4,
-                                           False, XA_INTEGER, &type_return, &format_return,
-                                           &num_items_return, &bytes_after_return, &data2);
-                    if (status == Success && type_return == XA_INTEGER &&
-                          format_return == 8 && num_items_return == 4) {
-                        // when scroll direction is not reversed,
-                        // up button id should be smaller than down button id,
-                        // up/left are odd elements, down/right are even elements
-                        for (int i=0; i<2; ++i) {
-                            unsigned char odd = *(data2 + i*2);
-                            unsigned char even = *(data2 + i*2+1);
-                            unsigned char max_elem = std::max(odd, even);
-                            unsigned char min_elem = std::min(odd, even);
-                            *(data2 + i * 2) = reverseScrollPolarity ? max_elem : min_elem;
-                            *(data2 + i * 2 + 1) = reverseScrollPolarity ? min_elem : max_elem;
-                        }
-                        XIChangeProperty(dpy, deviceid, prop_wheel_emulation_axes, XA_INTEGER,
-                                         8, XIPropModeReplace, data2, 4);
-                    }
-                }
-
-                if (data != NULL) { XFree(data); }
-                if (data2 != NULL) { XFree(data2); }
-            }
-        }
-        XIFreeDeviceInfo(info);
-        m_handedNeedsApply = false;
-    }
-}
-
-void MouseSettings::save(KConfig *config)
-{
-    KSharedConfig::Ptr kcminputProfile = KSharedConfig::openConfig("kcminputrc");
-    KConfigGroup kcminputGroup(kcminputProfile, "Mouse");
-    kcminputGroup.writeEntry("Acceleration",accelRate);
-    kcminputGroup.writeEntry("Threshold",thresholdMove);
-    if (handed == RIGHT_HANDED)
-        kcminputGroup.writeEntry("MouseButtonMapping",QString("RightHanded"));
-    else
-        kcminputGroup.writeEntry("MouseButtonMapping",QString("LeftHanded"));
-    kcminputGroup.writeEntry("ReverseScrollPolarity", reverseScrollPolarity);
-    kcminputGroup.sync();
-
-    KSharedConfig::Ptr profile = KSharedConfig::openConfig("kdeglobals");
-    KConfigGroup group(profile, "KDE");
-    group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent);
-    group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent);
-    group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent);
-    group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent);
-    group.writeEntry("SingleClick", singleClick, KConfig::Persistent);
-
-    group.sync();
-    config->sync();
-
-    Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Mouse"), "kcminputrc");
-    Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("KDE"), "kdeglobals");
-
-    KGlobalSettings::self()->emitChange(KGlobalSettings::SettingsChanged, KGlobalSettings::SETTINGS_MOUSE);
-}
-
 void MouseConfig::slotScrollPolarityChanged()
 {
-    settings->m_handedNeedsApply = true;
+    settings->handedNeedsApply = true;
 }
 
 #include "mouse.moc"
diff --git a/kcms/input/mouse.desktop b/kcms/input/mouse.desktop
index 1cb8fbfc..c71a0ae5 100644
--- a/kcms/input/mouse.desktop
+++ b/kcms/input/mouse.desktop
@@ -152,8 +152,8 @@ Comment[zh_TW]=滑鼠控制
 
 X-KDE-Keywords=Mouse,Mouse acceleration,Mouse threshold,Mouse buttons,Selection,Cursor Shape,Input Devices,Button Mapping,Click,icons,feedback,Pointers,Drag,Double Click,Single Click,mapping,right handed,left handed,Pointer Device,Mouse Wheel,Mouse Emulation,Mouse Navigation,Mouse Drag and Drop,Mouse Scrolling,Mouse Sensitivity,Move Mouse with Num Pad,Mouse Num Pad Emulation
 X-KDE-Keywords[bs]=Miš, Brzina kretanja miša, Prag osjetljivosti miša, Tasteri miša, Oblik kursora, Ulazni Uređaji, Mapiranje tastera, Klik, Ikone, feedback (povratna veza), Pokazivači, Vuči (drag), Dupli klik, Jedan Klik, Mapiranje, Dešnjak, Ljevak, Uređaj koji je Pokazivač (miš, Trackball, Joystick), Točkić za pomicanje (gore ili dolje), Emulatija Miša, Navigacija Miša, Miš Povucite i ispustite(drag and drop), Skrolanje Mišem, Osjetljivost Miša, Pomjeranje miša pomoću brojevne tastature, Emulacija miša pomoću brojevne tastature
-X-KDE-Keywords[ca]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de boton,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensitivitat de ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric
-X-KDE-Keywords[ca at valencia]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de boton,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensitivitat de ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric
+X-KDE-Keywords[ca]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de botó,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensibilitat del ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric
+X-KDE-Keywords[ca at valencia]=Ratolí,Acceleració de ratolí,Llindar de ratolí,Botons de ratolí,Selecció,Ombra de cursor,Dispositius d'entrada,Mapatge de boton,Clic,icones,reacció,Apuntadors,Arrossegar,Clic doble,Clic normal,mapatge,dretà,esquerrà,Dispositiu apuntador,Roda de ratolí,Emulació de ratolí,Navegació amb ratolí,Arrossegar i deixar anar de ratolí,Desplaçament amb ratolí,Sensibilitat del ratolí,Moure el ratolí amb teclat numèric,Emulació de ratolí amb teclat numèric
 X-KDE-Keywords[da]=Mus,Museacceleration,musetærskel,museknapper,markering,markørform,Input-enheder,knapkobling,klik,ikoner,feedback,Pointers,træk,dobbeltklik,enkeltklik,kobling,højrehåndet,venstrehåndet,pegeenhed,musehjul,museemulering,musenavigation,træk og slip,muserulning,scrolling,musefølsomhed,bevæg mus med numerisk tastatur,markører,cursor,rulning
 X-KDE-Keywords[de]=Maus,Mausbeschleunigung,Mausschwellwert,Maustasten,Auswahl,Cursor,Cursor-Form,Eingabegeräte,Knöpfe,Buttons,Zuordnungen,Klicks,Zeigegeräte,Doppelklick,Rechtshänder,Linkshänder,Ziehen,Mausrad,Maus-Emulation,Maus-Navigation,Ziehen und Ablegen mit der Maus,Blättern mit der Maus,Maus-Empfindlichkeit,Mauszeiger mit der Zahlentastatur verschieben,Maus-Emulation mit der Zahlentastatur
 X-KDE-Keywords[el]=ποντίκι,επιτάχυνση ποντικιού,κατώφλι ποντικιού,κουμπιά ποντικιού,επιλογή,σχήμα δρομέα,συσκευές εισόδου,χαρτογράφηση κουμπιών,κλικ,εικονίδια,ανάδραση,δείκτες,έλξη,διπλό κλικ,μονό κλικ,χαρτογράφηση,δεξιόχειρας,αριστερόχειρας,συσκευή δείκτη,τροχός ποντικιού,εξομοίωση ποντικιού,πλοήγηση ποντικιού,έλξη και απόθεση ποντικιού,κύλιση ποντικιού,ευαισθησία ποντικιού,κίνηση ποντικιού με το αριθμητικό πληκτρολόγιο,εξομοίωση ποντικιού αριθμητικού πληκτρολογίου
diff --git a/kcms/input/mouse.h b/kcms/input/mouse.h
index 6599a3a7..3b7b03e8 100644
--- a/kcms/input/mouse.h
+++ b/kcms/input/mouse.h
@@ -31,16 +31,11 @@
 #ifndef __MOUSECONFIG_H__
 #define __MOUSECONFIG_H__
 
-#include <QX11Info>
-
 #include <config-workspace.h>
 
 #include <kcmodule.h>
-#include <KConfigGroup>
 #include "ui_kcmmouse.h"
-
-#define RIGHT_HANDED 0
-#define LEFT_HANDED  1
+#include "mousesettings.h"
 
 class QCheckBox;
 class QDoubleSpinBox;
@@ -48,28 +43,8 @@ class QSlider;
 class QSpinBox;
 class QTabWidget;
 
-class MouseSettings
-{
-public:
-    void save(KConfig *);
-    void load(KConfig *, Display *dpy = QX11Info::display());
-    void apply(bool force=false);
-
-public:
-    int num_buttons;
-    int middle_button;
-    bool handedEnabled;
-    bool m_handedNeedsApply;
-    int handed;
-    double accelRate;
-    int thresholdMove;
-    int doubleClickInterval;
-    int dragStartTime;
-    int dragStartDist;
-    bool singleClick;
-    int wheelScrollLines;
-    bool reverseScrollPolarity;
-};
+class MouseSettings;
+class MouseBackend;
 
 class MouseConfig : public KCModule, public Ui::KCMMouse
 {
@@ -93,14 +68,15 @@ private Q_SLOTS:
 private:
     double getAccel();
     int getThreshold();
-    int getHandedness();
+    MouseHanded getHandedness();
 
     void setAccel(double);
     void setThreshold(int);
-    void setHandedness(int);
+    void setHandedness(MouseHanded);
 
     MouseSettings *settings;
+
+    MouseBackend *backend;
 };
 
 #endif
-
diff --git a/kcms/input/mousebackend.cpp b/kcms/input/mousebackend.cpp
new file mode 100644
index 00000000..f1a0054a
--- /dev/null
+++ b/kcms/input/mousebackend.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 "mousebackend.h"
+
+#include "backends/x11/x11mousebackend.h"
+#include "logging.h"
+
+#include <QThreadStorage>
+#include <QSharedPointer>
+
+#include <QGuiApplication>
+
+MouseBackend *MouseBackend::implementation()
+{
+    //There are multiple possible backends, always use X11 backend for now.
+    static QThreadStorage<QSharedPointer<X11MouseBackend>> backend;
+    if (!backend.hasLocalData()) {
+        qCDebug(KCM_INPUT) << "Using X11 backend";
+        backend.setLocalData(QSharedPointer<X11MouseBackend>(new X11MouseBackend));
+    }
+    return backend.localData().data();
+
+#if 0
+    qCCritical(KCM_INPUT) << "Not able to select appropriate backend.";
+    return nullptr;
+#endif
+}
diff --git a/kcms/input/mousebackend.h b/kcms/input/mousebackend.h
new file mode 100644
index 00000000..062bd128
--- /dev/null
+++ b/kcms/input/mousebackend.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 MOUSEBACKEND_H
+#define MOUSEBACKEND_H
+
+#include <QObject>
+#include "mousesettings.h"
+
+class MouseBackend : public QObject
+{
+    Q_OBJECT
+protected:
+    explicit MouseBackend(QObject *parent) : QObject(parent) {}
+
+public:
+    static MouseBackend *implementation();
+
+    virtual bool isValid() const = 0;
+
+    // This function will be called before query any property below, thus it
+    // can be used to save some round trip.
+    virtual void load() = 0;
+    virtual void apply(const MouseSettings &settings, bool force) = 0;
+
+    // Return the value from display server or compositor if applicable.
+    virtual bool supportScrollPolarity() = 0;
+    virtual QStringList supportedAccelerationProfiles() = 0;
+    virtual QString accelerationProfile() = 0;
+    virtual double accelRate() = 0;
+    virtual int threshold() = 0;
+    virtual MouseHanded handed() = 0;
+
+    virtual QString currentCursorTheme() = 0;
+    virtual void applyCursorTheme(const QString &name, int size) = 0;
+};
+
+#endif // MOUSEBACKEND_H
diff --git a/kcms/input/mousesettings.cpp b/kcms/input/mousesettings.cpp
new file mode 100644
index 00000000..96f84e03
--- /dev/null
+++ b/kcms/input/mousesettings.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 "mousesettings.h"
+
+#include "mousebackend.h"
+#include <QDBusMessage>
+#include <QDBusConnection>
+#include <KSharedConfig>
+#include <KConfigGroup>
+
+#include "../migrationlib/kdelibs4config.h"
+
+void MouseSettings::apply(MouseBackend* backend, bool force)
+{
+    if (!backend) {
+        return;
+    }
+
+    backend->apply(*this, force);
+    handedNeedsApply = false;
+}
+
+void MouseSettings::load(KConfig *config, MouseBackend *backend)
+{
+    // TODO: what's a good threshold default value
+    int threshold = 0;
+    handed = MouseHanded::Right;
+    double accel = 1.0;
+    QString profile;
+    if (backend) {
+        backend->load();
+        auto handedOnServer = backend->handed();
+        handedEnabled = handedOnServer != MouseHanded::NotSupported;
+        if (handedEnabled) {
+            handed = handedOnServer;
+        }
+        accel = backend->accelRate();
+        threshold = backend->threshold();
+        profile = backend->accelerationProfile();
+    }
+
+    KConfigGroup group = config->group("Mouse");
+    double a = group.readEntry("Acceleration", -1.0);
+    if (a == -1)
+        accelRate = accel;
+    else
+        accelRate = a;
+
+    int t = group.readEntry("Threshold", -1);
+    if (t == -1)
+        thresholdMove = threshold;
+    else
+        thresholdMove = t;
+
+    QString key = group.readEntry("MouseButtonMapping");
+    if (key == "RightHanded")
+        handed = MouseHanded::Right;
+    else if (key == "LeftHanded")
+        handed = MouseHanded::Left;
+    reverseScrollPolarity = group.readEntry("ReverseScrollPolarity", false);
+    currentAccelProfile = group.readEntry("AccelerationProfile");
+    if (currentAccelProfile.isEmpty()) {
+        currentAccelProfile = profile;
+    }
+    handedNeedsApply = false;
+
+    // SC/DC/AutoSelect/ChangeCursor
+    group = config->group("KDE");
+    doubleClickInterval = group.readEntry("DoubleClickInterval", 400);
+    dragStartTime = group.readEntry("StartDragTime", 500);
+    dragStartDist = group.readEntry("StartDragDist", 4);
+    wheelScrollLines = group.readEntry("WheelScrollLines", 3);
+
+    singleClick = group.readEntry("SingleClick", true);
+}
+
+// see KGlobalSettings::emitChange
+enum ChangeType { PaletteChanged = 0, FontChanged, StyleChanged,
+                  SettingsChanged, IconChanged, CursorChanged,
+                  ToolbarStyleChanged, ClipboardConfigChanged,
+                  BlockShortcuts, NaturalSortingChanged
+                };
+enum SettingsCategory { SETTINGS_MOUSE, SETTINGS_COMPLETION, SETTINGS_PATHS,
+                        SETTINGS_POPUPMENU, SETTINGS_QT, SETTINGS_SHORTCUTS,
+                        SETTINGS_LOCALE, SETTINGS_STYLE
+                      };
+
+static void emitChange(ChangeType changeType, int arg)
+{
+    // see KGlobalSettings::emitChange
+    QDBusMessage message = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
+    QList<QVariant> args;
+    args.append(static_cast<int>(changeType));
+    args.append(arg);
+    message.setArguments(args);
+    QDBusConnection::sessionBus().send(message);
+}
+
+void MouseSettings::save(KConfig *config)
+{
+    KSharedConfig::Ptr kcminputProfile = KSharedConfig::openConfig("kcminputrc");
+    KConfigGroup kcminputGroup(kcminputProfile, "Mouse");
+    kcminputGroup.writeEntry("Acceleration",accelRate);
+    kcminputGroup.writeEntry("Threshold",thresholdMove);
+    if (handed == MouseHanded::Right) {
+        kcminputGroup.writeEntry("MouseButtonMapping",QString("RightHanded"));
+    } else {
+        kcminputGroup.writeEntry("MouseButtonMapping",QString("LeftHanded"));
+    }
+    kcminputGroup.writeEntry("ReverseScrollPolarity", reverseScrollPolarity);
+    kcminputGroup.writeEntry("AccelerationProfile", currentAccelProfile);
+    kcminputGroup.sync();
+
+    KSharedConfig::Ptr profile = KSharedConfig::openConfig("kdeglobals");
+    KConfigGroup group(profile, "KDE");
+    group.writeEntry("DoubleClickInterval", doubleClickInterval, KConfig::Persistent);
+    group.writeEntry("StartDragTime", dragStartTime, KConfig::Persistent);
+    group.writeEntry("StartDragDist", dragStartDist, KConfig::Persistent);
+    group.writeEntry("WheelScrollLines", wheelScrollLines, KConfig::Persistent);
+    group.writeEntry("SingleClick", singleClick, KConfig::Persistent);
+
+    group.sync();
+    config->sync();
+
+    Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("Mouse"), "kcminputrc");
+    Kdelibs4SharedConfig::syncConfigGroup(QLatin1String("KDE"), "kdeglobals");
+
+    emitChange(SettingsChanged, SETTINGS_MOUSE);
+}
diff --git a/kcms/input/mousesettings.h b/kcms/input/mousesettings.h
new file mode 100644
index 00000000..68c149e1
--- /dev/null
+++ b/kcms/input/mousesettings.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2017 Xuetian Weng <wengxt at 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 MOUSESETTINGS_H
+#define MOUSESETTINGS_H
+
+#include <KConfig>
+
+class MouseBackend;
+
+enum class MouseHanded {
+    Right = 0,
+    Left = 1,
+    NotSupported = -1
+};
+
+struct MouseSettings
+{
+    void save(KConfig *);
+    void load(KConfig *, MouseBackend*);
+    void apply(MouseBackend*, bool force = false);
+
+    bool handedEnabled;
+    bool handedNeedsApply;
+    MouseHanded handed;
+    double accelRate;
+    int thresholdMove;
+    int doubleClickInterval;
+    int dragStartTime;
+    int dragStartDist;
+    bool singleClick;
+    int wheelScrollLines;
+    bool reverseScrollPolarity;
+    QString currentAccelProfile;
+};
+
+#endif // MOUSESETTINGS_H
diff --git a/kcms/keyboard/kcm_keyboard.desktop b/kcms/keyboard/kcm_keyboard.desktop
index 9b8283c3..9692e4d4 100644
--- a/kcms/keyboard/kcm_keyboard.desktop
+++ b/kcms/keyboard/kcm_keyboard.desktop
@@ -154,7 +154,7 @@ Comment[zh_TW]=鍵盤硬體與佈局
 
 X-KDE-Keywords=Keyboard,Keyboard repeat,Click volume,Input Devices,repeat,volume,NumLock,NumPad,Keyboard type,Keyboard model,Keyboard layout,Key layout,Language,Alternate Keyboard,Keyboard switching,Ctrl Key,Caps Lock,Esperanto,Circumflex,Kill X Server,LED Keyboard,Compose Key
 X-KDE-Keywords[bs]=Tastatura,ponavljanje tastature,kliknute glasnoću,umetnuti uređaj,ponoviti,glasnoća,NumLock,NumPad,tip tastature,model tastature,izgled tastature,izgled tipki,jezik,rezervna tastatura,uključivanje tastature,Ctrl tipka,velika slova,esperanto,cirkumfleks,ukloniti X server,LED tastatura,sastavljene tipke
-X-KDE-Keywords[ca]=Teclat,Repetició de teclat,Volum de clic,Dispositius d'entrada,repetició,volum,Bloq Núm,NumPad,Tipus de teclat,Model de teclat,Disposició de teclat,Idioma,Teclat alternatiu,Commutació de teclat,Tecla Ctrl,Bloq Maj,Esperanto,Circumflex,Matar servidor X,LED de teclat,Tecla compose
+X-KDE-Keywords[ca]=Teclat,Repetició de teclat,Volum de clic,Dispositius d'entrada,repetició,volum,Bloq Núm,NumPad,Tipus de teclat,Model de teclat,Disposició de teclat,Idioma,Teclat alternatiu,Commutació de teclat,Tecla Ctrl,Bloq Maj,Esperanto,Circumflex,Matar servidor X,LED de teclat,Tecla de composició
 X-KDE-Keywords[ca at valencia]=Teclat,Repetició de teclat,Volum de clic,Dispositius d'entrada,repetició,volum,Bloq Núm,NumPad,Tipus de teclat,Model de teclat,Disposició de teclat,Idioma,Teclat alternatiu,Commutació de teclat,Tecla Ctrl,Bloq Maj,Esperanto,Circumflex,Matar servidor X,LED de teclat,Tecla compose
 X-KDE-Keywords[da]=Tastatur,keyboard,tastaturgentagelse,klikvolume,inputenheder,gentag,lydstyrke,NumLock,numerisk tastatur,tastaturtype,tastaturmodel,tastaturlayout,tastelayout,sprog,alternativt tastatur,skift af tastatur,Ctrl-tast,lås skift,caps lock,Esperanto,Circumflex,dræb X Server,LED-tastatur,Compose-tast
 X-KDE-Keywords[de]=Tastatur,Tastenwiederholung,Klicklautstärke,Eingabegeräte,Wiederholung,Lautstärke,Zahlen-Feststelltaste,Zahlenblock,Tastaturtyp,Tastaturmodell,Tastaturlayout,Tastenlayout,Sprache,Alternative Tastatur,Tastaturwechsel,Tastaturbelegung,Strg-Taste,Feststelltaste,Esperanto,Zirkumflex,X-Server beenden,Tastatur LED,Compose-Taste
diff --git a/kcms/kfontinst/apps/org.kde.kfontview.desktop b/kcms/kfontinst/apps/org.kde.kfontview.desktop
index c112557d..aa001a6b 100755
--- a/kcms/kfontinst/apps/org.kde.kfontview.desktop
+++ b/kcms/kfontinst/apps/org.kde.kfontview.desktop
@@ -108,7 +108,7 @@ GenericName[ca at valencia]=Visor de tipus de lletra
 GenericName[cs]=Prohlížeč písem
 GenericName[csb]=Przezérnik fòntów
 GenericName[cy]=Gwelydd Wynebfathau
-GenericName[da]=Skrifttype-fremviser
+GenericName[da]=Skrifttypevisning
 GenericName[de]=Schriftartenbetrachter
 GenericName[el]=Προβολέας γραμματοσειρών
 GenericName[en_GB]=Font Viewer
diff --git a/kcms/kfontinst/kcmfontinst/fontinst.desktop b/kcms/kfontinst/kcmfontinst/fontinst.desktop
index 0574581f..49bb5a5b 100644
--- a/kcms/kfontinst/kcmfontinst/fontinst.desktop
+++ b/kcms/kfontinst/kcmfontinst/fontinst.desktop
@@ -116,7 +116,7 @@ X-KDE-Keywords[ar]=خط,خطوط,مثبّت,مثبت,ترو.تايب,تايب1,
 X-KDE-Keywords[bs]=slovo,slova,instalacijski program,truetype,tip1,bitna mapa
 X-KDE-Keywords[ca]=tipus de lletra,tipus de lletres,instal·lador,truetype,type1,mapa de bits
 X-KDE-Keywords[ca at valencia]=tipus de lletra,tipus de lletres,instal·lador,truetype,type1,mapa de bits
-X-KDE-Keywords[da]=font,fonte,skrifttype,skrifttyper,truetype,type1, bitmap
+X-KDE-Keywords[da]=font,fonts,skrifttype,skrifttyper,installer,truetype,type1,bitmap
 X-KDE-Keywords[de]=Schrift,Fonts,Schriftarten,Installation,TrueType,Type1,Bitmapschriften
 X-KDE-Keywords[el]=γραμματοσειρά,γραμματοσειρές,πρόγραμμα εγκατάστασης,truetype,type1,bitmap
 X-KDE-Keywords[en_GB]=font,fonts,installer,truetype,type1,bitmap
diff --git a/kcms/krdb/krdb_libpathwipe.upd b/kcms/krdb/krdb_libpathwipe.upd
index d884115c..cfde58fd 100644
--- a/kcms/krdb/krdb_libpathwipe.upd
+++ b/kcms/krdb/krdb_libpathwipe.upd
@@ -1,3 +1,3 @@
+Version=5
 Id=LibraryPathWipeOut
 Script=krdb_clearlibrarypath
-Version=5
\ No newline at end of file
diff --git a/kcms/lookandfeel/CMakeLists.txt b/kcms/lookandfeel/CMakeLists.txt
index 60d9431c..d854eb9d 100644
--- a/kcms/lookandfeel/CMakeLists.txt
+++ b/kcms/lookandfeel/CMakeLists.txt
@@ -73,18 +73,13 @@ qt5_add_dbus_interface(lookandfeeltool_SRCS ${klauncher_xml} klauncher_iface)
 add_executable(lookandfeeltool ${lookandfeeltool_SRCS})
 
 target_link_libraries(lookandfeeltool
-#     Qt5::Gui
-#     Qt5::Widgets
-#     KF5::Package
-#     KF5::I18n
-    
-    KF5::KIOWidgets
+  KF5::KIOWidgets
   KF5::CoreAddons
   KF5::KCMUtils
   KF5::I18n
   #TODO:kpackage
-KF5::Plasma
-KF5::PlasmaQuick
+  KF5::Plasma
+  KF5::PlasmaQuick
   KF5::KDELibs4Support
   KF5::Declarative
   KF5::QuickAddons
diff --git a/kcms/lookandfeel/kcm.cpp b/kcms/lookandfeel/kcm.cpp
index 6ea3d050..0b5dd559 100644
--- a/kcms/lookandfeel/kcm.cpp
+++ b/kcms/lookandfeel/kcm.cpp
@@ -35,6 +35,8 @@
 #include <QQuickView>
 #include <KGlobalSettings>
 #include <KIconLoader>
+#include <KAutostart>
+#include <KRun>
 
 #include <QVBoxLayout>
 #include <QPushButton>
@@ -369,6 +371,41 @@ void KCMLookandFeel::save()
                                                     QStringLiteral("reloadConfig"));
             QDBusConnection::sessionBus().send(message);
         }
+
+        //autostart
+        if (m_resetDefaultLayout) {
+            //remove all the old package to autostart
+            {
+                KSharedConfigPtr oldConf = KSharedConfig::openConfig(m_package.filePath("defaults"));
+                cg = KConfigGroup(oldConf, QStringLiteral("Autostart"));
+                const QStringList autostartServices = cg.readEntry("Services", QStringList());
+
+                if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) {
+                    for (const QString &serviceFile : autostartServices) {
+                        KService service(serviceFile + QStringLiteral(".desktop"));
+                        KAutostart as(serviceFile);
+                        as.setAutostarts(false);
+                        //FIXME: quite ugly way to stop things, and what about non KDE things?
+                        QProcess::startDetached(QStringLiteral("kquitapp5"), {QStringLiteral("--service"), service.property(QStringLiteral("X-DBUS-ServiceName")).toString()});
+                    }
+                }
+            }
+            //Set all the stuff in the new lnf to autostart
+            {
+                cg = KConfigGroup(conf, QStringLiteral("Autostart"));
+                const QStringList autostartServices = cg.readEntry("Services", QStringList());
+
+                for (const QString &serviceFile : autostartServices) {
+                    KService service(serviceFile + QStringLiteral(".desktop"));
+                    KAutostart as(serviceFile);
+                    as.setCommand(service.exec());
+                    as.setAutostarts(true);
+                    if (qEnvironmentVariableIsSet("KDE_FULL_SESSION")) {
+                        KRun::runApplication(service, {}, nullptr);
+                    }
+                }
+            }
+        }
     }
 
     //TODO: option to enable/disable apply? they don't seem required by UI design
diff --git a/kcms/lookandfeel/lnftool.cpp b/kcms/lookandfeel/lnftool.cpp
index df5fa277..65619d4e 100644
--- a/kcms/lookandfeel/lnftool.cpp
+++ b/kcms/lookandfeel/lnftool.cpp
@@ -91,6 +91,7 @@ int main(int argc, char **argv)
         kcm->setResetDefaultLayout(parser.isSet(_resetLayout));
         kcm->setSelectedPlugin(parser.value(_apply));
         kcm->save();
+        delete kcm;
     }
 
     return 0;
diff --git a/kcms/nightcolor/CMakeLists.txt b/kcms/nightcolor/CMakeLists.txt
new file mode 100644
index 00000000..8789c3c3
--- /dev/null
+++ b/kcms/nightcolor/CMakeLists.txt
@@ -0,0 +1,24 @@
+# KI18N Translation Domain for this library
+add_definitions(-DTRANSLATION_DOMAIN=\"kcm_nightcolor\")
+
+set(kcm_nightcolor_SRCS
+    kcm.cpp
+)
+
+add_library(kcm_nightcolor MODULE ${kcm_nightcolor_SRCS})
+
+target_link_libraries(kcm_nightcolor
+    KF5::QuickAddons
+    KF5::I18n
+
+    PW::LibColorCorrect
+)
+
+kcoreaddons_desktop_to_json(kcm_nightcolor "kcm_nightcolor.desktop" SERVICE_TYPES kcmodule.desktop)
+
+#this desktop file is installed only for retrocompatibility with sycoca
+install(FILES kcm_nightcolor.desktop DESTINATION ${SERVICES_INSTALL_DIR})
+
+install(TARGETS kcm_nightcolor DESTINATION ${PLUGIN_INSTALL_DIR}/kcms)
+
+kpackage_install_package(package kcm_nightcolor kcms)
diff --git a/kcms/nightcolor/Messages.sh b/kcms/nightcolor/Messages.sh
new file mode 100644
index 00000000..0a8bafc7
--- /dev/null
+++ b/kcms/nightcolor/Messages.sh
@@ -0,0 +1,2 @@
+#! /usr/bin/env bash
+$XGETTEXT `find . -name "*.cpp" -o -name "*.qml"` -o $podir/kcm_nightcolor.pot
diff --git a/kcms/nightcolor/kcm.cpp b/kcms/nightcolor/kcm.cpp
new file mode 100644
index 00000000..5445b0bf
--- /dev/null
+++ b/kcms/nightcolor/kcm.cpp
@@ -0,0 +1,55 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#include "kcm.h"
+
+#include <KPluginFactory>
+#include <KPluginLoader>
+#include <KAboutData>
+#include <KLocalizedString>
+
+K_PLUGIN_FACTORY_WITH_JSON(KCMNightColorFactory, "kcm_nightcolor.json", registerPlugin<ColorCorrect::KCMNightColor>();)
+
+namespace ColorCorrect {
+
+KCMNightColor::KCMNightColor(QObject *parent, const QVariantList& args)
+    : KQuickAddons::ConfigModule(parent, args)
+{
+    KAboutData* about = new KAboutData(QStringLiteral("kcm_nightcolor"), i18n("Night Color"),
+                                       QStringLiteral("0.1"), QString(), KAboutLicense::LGPL);
+    about->addAuthor(i18n("Roman Gilg"), QString(), QStringLiteral("subdiff at gmail.com"));
+    setAboutData(about);
+    setButtons(Apply | Default);
+}
+
+void KCMNightColor::load()
+{
+    emit loadRelay();
+}
+
+void KCMNightColor::defaults()
+{
+    emit defaultsRelay();
+}
+
+void KCMNightColor::save()
+{
+    emit saveRelay();
+}
+
+}
+
+#include "kcm.moc"
diff --git a/kcms/nightcolor/kcm.h b/kcms/nightcolor/kcm.h
new file mode 100644
index 00000000..53a8c198
--- /dev/null
+++ b/kcms/nightcolor/kcm.h
@@ -0,0 +1,44 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+#ifndef _KCM_NIGHTCOLOR_H
+#define _KCM_NIGHTCOLOR_H
+
+#include <KQuickAddons/ConfigModule>
+
+namespace ColorCorrect {
+
+class KCMNightColor : public KQuickAddons::ConfigModule
+{
+    Q_OBJECT
+public:
+    KCMNightColor(QObject* parent, const QVariantList& args);
+    ~KCMNightColor() {}
+
+public Q_SLOTS:
+    void load();
+    void save();
+    void defaults();
+
+Q_SIGNALS:
+    void loadRelay();
+    void saveRelay();
+    void defaultsRelay();
+};
+
+}
+
+#endif  // _KCM_NIGHTCOLOR_H
diff --git a/kcms/nightcolor/kcm_nightcolor.desktop b/kcms/nightcolor/kcm_nightcolor.desktop
new file mode 100644
index 00000000..b2407a5c
--- /dev/null
+++ b/kcms/nightcolor/kcm_nightcolor.desktop
@@ -0,0 +1,65 @@
+[Desktop Entry]
+Icon=preferences-desktop-display-nightcolor
+Exec=kcmshell5 kcm_nightcolor
+
+Type=Service
+X-KDE-ServiceTypes=KCModule
+
+X-DocPath=https://userbase.kde.org/TODOX
+
+X-KDE-Library=kcm_nightcolor
+X-KDE-ParentApp=kcontrol
+
+X-KDE-System-Settings-Parent-Category=display
+X-KDE-Weight=120
+
+X-KDE-OnlyShowOnQtPlatforms=wayland
+
+Name=Night Color
+Name[ca]=Color de nit
+Name[ca at valencia]=Color de nit
+Name[es]=Color nocturno
+Name[fr]=Couleur de nuit
+Name[it]=Colore notturno
+Name[nl]=Nachtkleur
+Name[pt]=Cor Nocturna
+Name[pt_BR]=Cor noturna
+Name[sr]=Ноћна боја
+Name[sr at ijekavian]=Ноћна боја
+Name[sr at ijekavianlatin]=Noćna boja
+Name[sr at latin]=Noćna boja
+Name[sv]=Nattfärg
+Name[uk]=Нічні кольори
+Name[x-test]=xxNight Colorxx
+Comment=Adjust color temperature at night to reduce eye strain
+Comment[ca]=Ajusta la temperatura del color per la nit per reduir la tensió ocular
+Comment[ca at valencia]=Ajusta la temperatura del color per la nit per reduir la tensió ocular
+Comment[es]=Ajustar la temperatura del color durante la noche para reducir la fatiga visual
+Comment[fr]=Ajuster la température des couleurs durant la nuit pour réduire la fatigue des yeux
+Comment[nl]=Kleurtemperatuur bij nacht aanpassen on vermoeidheid van de ogen te vermijden
+Comment[pt]=Ajustar a temperatura da cor à noite para reduzir o cansaço dos olhos
+Comment[sr]=Подесите температуру боје током ноћи ради мањег напрезања очију
+Comment[sr at ijekavian]=Подесите температуру боје током ноћи ради мањег напрезања очију
+Comment[sr at ijekavianlatin]=Podesite temperaturu boje tokom noći radi manjeg naprezanja očiju
+Comment[sr at latin]=Podesite temperaturu boje tokom noći radi manjeg naprezanja očiju
+Comment[sv]=Justera färgtemperatur på natten för att reducera ögonbelastning
+Comment[uk]=Коригування температури кольорів для зменшення навантаження на очі вночі
+Comment[x-test]=xxAdjust color temperature at night to reduce eye strainxx
+
+X-KDE-Keywords=kwin,window,manager,night,colors,redshift,eyes
+X-KDE-Keywords[ca]=kwin,finestra,gestor,nit,colors,desplaçament cap al roig,ulls
+X-KDE-Keywords[ca at valencia]=kwin,finestra,gestor,nit,colors,desplaçament cap al roig,ulls
+X-KDE-Keywords[es]=kwin,ventana,gestor,noche,colores,corrimiento al rojo,ojos
+X-KDE-Keywords[fr]=kwin, gestionnaire, fenêtres, couleurs, nuit, colors, redshift, yeux
+X-KDE-Keywords[it]=kwin,finestra,gestore,notte,colori,spostamento verso il rosso,occhi
+X-KDE-Keywords[nl]=kwin,venster,manager,nacht,kleuren,roodverschuiving,ogen
+X-KDE-Keywords[pt]=kwin,janela,gestor,noite,cores,desvio do vermelho,olhos
+X-KDE-Keywords[pt_BR]=kwin,janela,gerenciador,noite,noturno,cores,deslocamento de vermelho,olhos
+X-KDE-Keywords[sr]=kwin,window,manager,night,colors,redshift,eyes,К‑вин,прозор,менаџер,ноћ,ноћни,боја,црвени помак,очи
+X-KDE-Keywords[sr at ijekavian]=kwin,window,manager,night,colors,redshift,eyes,К‑вин,прозор,менаџер,ноћ,ноћни,боја,црвени помак,очи
+X-KDE-Keywords[sr at ijekavianlatin]=kwin,window,manager,night,colors,redshift,eyes,KWin,prozor,menadžer,noć,noćni,boja,crveni pomak,oči
+X-KDE-Keywords[sr at latin]=kwin,window,manager,night,colors,redshift,eyes,KWin,prozor,menadžer,noć,noćni,boja,crveni pomak,oči
+X-KDE-Keywords[sv]=kwin,fönster,hanterare,natt,färger,rödskift,ögon
+X-KDE-Keywords[uk]=kwin,window,manager,night,colors,redshift,eyes,вікно,керування,ніч,кольори,очі
+X-KDE-Keywords[x-test]=xxkwinxx,xxwindowxx,xxmanagerxx,xxnightxx,xxcolorsxx,xxredshiftxx,xxeyesxx
+Categories=Qt;KDE;X-KDE-settings-nightcolor
diff --git a/kcms/nightcolor/package/contents/ui/LocationsAutoView.qml b/kcms/nightcolor/package/contents/ui/LocationsAutoView.qml
new file mode 100644
index 00000000..eed893e3
--- /dev/null
+++ b/kcms/nightcolor/package/contents/ui/LocationsAutoView.qml
@@ -0,0 +1,53 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+import QtQuick 2.1
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 1.4 as Controls
+
+GridLayout {
+    columns: 2
+    rowSpacing: units.smallSpacing
+    columnSpacing: units.smallSpacing
+    enabled: activator.checked
+
+    property double latitude
+    property double longitude
+
+    onLatitudeChanged: latitudeField.backend = latitude;
+    onLongitudeChanged: longitudeField.backend = longitude;
+
+    Controls.Label {
+        text: i18n("Latitude")
+        Layout.alignment: Qt.AlignRight
+        enabled: false
+    }
+    NumberField {
+        id: latitudeField
+        backend: locator.latitude
+        enabled: false
+    }
+    Controls.Label {
+        text: i18n("Longitude")
+        Layout.alignment: Qt.AlignRight
+        enabled: false
+    }
+    NumberField {
+        id: longitudeField
+        backend: locator.longitude
+        enabled: false
+    }
+}
diff --git a/kcms/nightcolor/package/contents/ui/LocationsFixedView.qml b/kcms/nightcolor/package/contents/ui/LocationsFixedView.qml
new file mode 100644
index 00000000..2ed1d984
--- /dev/null
+++ b/kcms/nightcolor/package/contents/ui/LocationsFixedView.qml
@@ -0,0 +1,75 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+import QtQuick 2.1
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 1.4 as Controls
+
+GridLayout {
+    columns: 2
+    rowSpacing: units.smallSpacing
+    columnSpacing: units.smallSpacing
+    enabled: activator.checked
+
+    Connections {
+        target: root
+        onReset: reset()
+    }
+
+    function reset() {
+        latitudeFixedField.backend = cA.latitudeFixed;
+        longitudeFixedField.backend = cA.longitudeFixed;
+    }
+
+    Controls.Label {
+        text: i18n("Latitude")
+        Layout.alignment: Qt.AlignRight
+    }
+    NumberField {
+        id: latitudeFixedField
+        backend: cA.latitudeFixedStaged
+        validator: DoubleValidator {bottom: -90; top: 90; decimals: 10}
+        onBackendChanged: {
+            cA.latitudeFixedStaged = backend;
+            manualLocationsViewRow.change();
+            calcNeedsSave();
+        }
+    }
+
+    Controls.Label {
+        text: i18n("Longitude")
+        Layout.alignment: Qt.AlignRight
+    }
+    NumberField {
+        id: longitudeFixedField
+        backend: cA.longitudeFixedStaged
+        validator: DoubleValidator {bottom: -180; top: 180; decimals: 10}
+        onBackendChanged: {
+            cA.longitudeFixedStaged = backend;
+            manualLocationsViewRow.change();
+            calcNeedsSave();
+        }
+    }
+    Controls.Button {
+        Layout.columnSpan: 2
+        Layout.alignment: Qt.AlignHCenter
+        text: i18n("Detect location")
+        onClicked: {
+            latitudeFixedField.backend = locator.latitude;
+            longitudeFixedField.backend = locator.longitude;
+        }
+    }
+}
diff --git a/kcms/nightcolor/package/contents/ui/NumberField.qml b/kcms/nightcolor/package/contents/ui/NumberField.qml
new file mode 100644
index 00000000..a678c7cb
--- /dev/null
+++ b/kcms/nightcolor/package/contents/ui/NumberField.qml
@@ -0,0 +1,48 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+import QtQuick 2.1
+import QtQuick.Controls 1.4 as Controls
+
+Controls.TextField {
+    property double backend
+
+    maximumLength: 10
+    horizontalAlignment: TextInput.AlignHCenter
+
+    inputMethodHints: Qt.ImhFormattedNumbersOnly
+
+    text: backend
+
+    onBackendChanged: {
+        text = backend;
+    }
+
+    onTextChanged: {
+        var textFloat = parseFloat(text);
+        if (textFloat == undefined || isNaN(textFloat)) {
+            return;
+        }
+        backend = textFloat;
+    }
+
+    onFocusChanged: {
+        var textFloat = parseFloat(text);
+        if (!focus && (textFloat == undefined || isNaN(textFloat))) {
+            text = backend;
+        }
+    }
+}
diff --git a/kcms/nightcolor/package/contents/ui/TimeField.qml b/kcms/nightcolor/package/contents/ui/TimeField.qml
new file mode 100644
index 00000000..f160f063
--- /dev/null
+++ b/kcms/nightcolor/package/contents/ui/TimeField.qml
@@ -0,0 +1,71 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+import QtQuick 2.1
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 1.4 as Controls
+
+Controls.TextField {
+    id: field
+
+    property date backend
+    horizontalAlignment: TextInput.AlignHCenter
+
+    onBackendChanged: readIn()
+
+    function getNormedDate() {
+        var nD = new Date();
+        nD.setHours(backend.getHours());
+        nD.setMinutes(backend.getMinutes());
+        return nD;
+    }
+
+    function readIn() {
+        if (!backend) {
+            return;
+        }
+
+        var hours = backend.getHours();
+        var minutes = backend.getMinutes();
+        if (hours < 10) {
+            hours = "0" + hours;
+        }
+        if (minutes < 10) {
+            minutes = "0" + minutes;
+        }
+
+        text = hours + ":" + minutes;
+    }
+
+    function submit() {
+        if (text.length != 5) {
+            return;
+        }
+        var hours = text.slice(0, 2);
+        var minutes = text.slice(3, 5);
+
+        var date = new Date();
+        date.setHours(hours);
+        date.setMinutes(minutes);
+
+        backend = date;
+    }
+
+    inputMethodHints: Qt.ImhPreferNumbers
+    validator: RegExpValidator { regExp: /^([0-1]?[0-9]|2[0-3]):[0-5][0-9]$/ }
+
+    onEditingFinished: submit()
+}
diff --git a/kcms/nightcolor/package/contents/ui/TimingsView.qml b/kcms/nightcolor/package/contents/ui/TimingsView.qml
new file mode 100644
index 00000000..2d14f3c5
--- /dev/null
+++ b/kcms/nightcolor/package/contents/ui/TimingsView.qml
@@ -0,0 +1,78 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+import QtQuick 2.1
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 1.4 as Controls
+
+GridLayout {
+    columns: 2
+    rowSpacing: units.smallSpacing
+    columnSpacing: units.smallSpacing
+    enabled: activator.checked
+
+    property double latitude
+    property double longitude
+
+    property var morningTimings: sunCalc.getMorningTimings(latitude, longitude)
+    property var eveningTimings: sunCalc.getEveningTimings(latitude, longitude)
+
+    function reset() {
+        morningTimings = sunCalc.getMorningTimings(latitude, longitude);
+        eveningTimings = sunCalc.getEveningTimings(latitude, longitude);
+    }
+
+    Controls.Label {
+        text: i18n("Sunrise begins")
+        Layout.alignment: Qt.AlignRight
+        enabled: false
+    }
+    TimeField {
+        id: mornBeginField
+        backend: morningTimings.begin
+        enabled: false
+    }
+    Controls.Label {
+        text: i18n("and ends")
+        Layout.alignment: Qt.AlignRight
+        enabled: false
+    }
+    TimeField {
+        id: mornEndField
+        backend: morningTimings.end
+        enabled: false
+    }
+    Controls.Label {
+        text: i18n("Sunset begins")
+        Layout.alignment: Qt.AlignRight
+        enabled: false
+    }
+    TimeField {
+        id: evenBeginField
+        backend: eveningTimings.begin
+        enabled: false
+    }
+    Controls.Label {
+        text: i18n("and ends")
+        Layout.alignment: Qt.AlignRight
+        enabled: false
+    }
+    TimeField {
+        id: evenEndField
+        backend: eveningTimings.end
+        enabled: false
+    }
+}
diff --git a/kcms/nightcolor/package/contents/ui/main.qml b/kcms/nightcolor/package/contents/ui/main.qml
new file mode 100644
index 00000000..6dfeae87
--- /dev/null
+++ b/kcms/nightcolor/package/contents/ui/main.qml
@@ -0,0 +1,362 @@
+/********************************************************************
+Copyright 2017 Roman Gilg <subdiff at 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, see <http://www.gnu.org/licenses/>.
+*********************************************************************/
+import QtQuick 2.1
+import QtQuick.Layouts 1.1
+import QtQuick.Controls 1.4 as Controls
+
+import org.kde.kquickcontrolsaddons 2.0
+import org.kde.plasma.core 2.0 as PlasmaCore
+import org.kde.plasma.extras 2.0 as PlasmaExtras
+
+import org.kde.colorcorrect 0.1 as CC
+
+Item {
+    id: root
+
+    implicitHeight: units.gridUnit * 20
+
+    property int error: cA.error
+
+    property bool defaultRequested: false
+
+    CC.CompositorAdaptor {
+        id: cA
+    }
+
+    CC.Geolocator {
+        id: locator
+    }
+
+    CC.SunCalc {
+        id: sunCalc
+    }
+
+    function calcNeedsSave() {
+        kcm.needsSave = cA.checkStaged();
+        // If the user changes something manually again after
+        // Default was triggered, only allow a normal
+        // configuration change again:
+        defaultRequested = false;
+    }
+
+    Connections {
+        target: kcm
+        onLoadRelay: cA.reloadData()
+        onSaveRelay: defaultRequested ? cA.sendConfigurationAll() : cA.sendConfiguration();
+        onDefaultsRelay: {
+            if (!cA.nightColorAvailable) {
+                return;
+            }
+            activator.checked = cA.activeDefault;
+            tempSlider.value = cA.nightTemperatureDefault;
+            modeSwitcher.currentIndex = cA.modeDefault;
+
+            // set everything else to default as well
+            cA.latitudeFixedStaged = cA.latitudeFixedDefault;
+            cA.longitudeFixedStaged = cA.longitudeFixedDefault;
+
+            cA.morningBeginFixedStaged = cA.morningBeginFixedDefault;
+            cA.eveningBeginFixedStaged = cA.eveningBeginFixedDefault;
+            cA.transitionTimeStaged = cA.transitionTimeDefault;
+
+            kcm.needsSave = cA.checkStagedAll();
+            defaultRequested = true;
+        }
+    }
+
+    Connections {
+        target: cA
+        onDataUpdated: calcNeedsSave()
+        onStagedDataReset: {
+            activator.checked = cA.active;
+            tempSlider.value = cA.nightTemperature;
+            modeSwitcher.currentIndex = cA.mode;
+            reset();
+            calcNeedsSave();
+        }
+    }
+    signal reset()
+
+    Item {
+        id: main
+        width: childrenRect.width
+        height: childrenRect.height
+
+        enabled: cA.nightColorAvailable
+
+        Controls.CheckBox {
+            id: activator
+            text: i18n("Activate Night Color")
+            checked: cA.active
+
+            onCheckedChanged: {
+                cA.activeStaged = checked;
+                calcNeedsSave();
+            }
+        }
+
+        ColumnLayout {
+            id: mainControls
+            anchors.top: activator.bottom
+            anchors.topMargin: units.largeSpacing
+
+            enabled: activator.checked
+
+            Controls.Label {
+                text: i18n("Night Color Temperature: ") + tempSlider.value + i18n(" K")
+            }
+
+            Controls.Slider {
+                id: tempSlider
+                implicitWidth: units.gridUnit * 15
+
+                minimumValue: cA.minimalTemperature
+                maximumValue: cA.neutralTemperature
+                value: cA.nightTemperature
+                stepSize: 100
+
+                onValueChanged: {
+                    cA.nightTemperatureStaged = value;
+                    calcNeedsSave();
+                }
+            }
+
+            RowLayout {
+                spacing: units.largeSpacing
+                Controls.Label {
+                    text: i18n("Operation mode:")
+                }
+                Controls.ComboBox {
+                    id: modeSwitcher
+                    width: theme.mSize(theme.defaultFont).width * 9
+                    model: [i18n("Automatic"),
+                    i18n("Location"),
+                    i18n("Times")]
+                    currentIndex: cA.mode
+                    onCurrentIndexChanged: {
+                        cA.modeStaged = currentIndex;
+                        advancedControlLoader.updatePage(currentIndex);
+                        calcNeedsSave();
+                    }
+                }
+            }
+        }
+
+        Loader {
+            id: advancedControlLoader
+
+            anchors.top: mainControls.bottom
+            anchors.topMargin: units.largeSpacing
+
+            function updatePage(index) {
+                sourceComponent = undefined;
+                var page;
+                if (index == CC.CompositorAdaptor.ModeLocation) {
+                    page = manualLocationsView;
+                } else if (index == CC.CompositorAdaptor.ModeTimings) {
+                    page = manualTimingsView;
+                } else {
+                    page = automaticView;
+                }
+
+                sourceComponent = page;
+            }
+        }
+
+        Component {
+            id: automaticView
+            Row {
+                spacing: units.largeSpacing
+
+                Loader {
+                    sourceComponent: TimingsView {
+                        latitude: locator.latitude
+                        longitude: locator.longitude
+                    }
+                }
+                Loader {
+                    sourceComponent: LocationsAutoView {
+                        latitude: locator.latitude
+                        longitude: locator.longitude
+                    }
+                }
+            }
+        }
+
+        Component {
+            id: manualLocationsView
+
+            Row {
+                id: manualLocationsViewRow
+                spacing: units.largeSpacing
+
+                signal change()
+
+                Loader {
+                    sourceComponent: TimingsView {
+                        latitude: cA.latitudeFixedStaged
+                        longitude: cA.longitudeFixedStaged
+
+                        Connections {
+                            target: manualLocationsViewRow
+                            onChange: {
+                                reset();
+                            }
+                        }
+                    }
+                }
+                Loader {
+                    sourceComponent: LocationsFixedView {}
+                }
+            }
+        }
+
+        Component {
+            id: manualTimingsView
+            Column {
+                spacing: units.smallSpacing
+
+                GridLayout {
+                    id: manualTimingsViewGrid
+
+                    columns: 3
+                    rowSpacing: units.smallSpacing
+                    columnSpacing: units.smallSpacing
+                    enabled: activator.checked && cA.timingsEnabled
+
+                    Connections {
+                        target: root
+                        onReset: {
+                            mornBeginManField.backend = cA.morningBeginFixed;
+                            evenBeginManField.backend = cA.eveningBeginFixed;
+                            transTimeField.backend = cA.transitionTime;
+                        }
+                    }
+
+                    Controls.Label {
+                        text: i18n("Sunrise begins")
+                        Layout.alignment: Qt.AlignRight
+                    }
+                    TimeField {
+                        id: mornBeginManField
+                        backend: cA.morningBeginFixedStaged
+                        onBackendChanged: {cA.morningBeginFixedStaged = backend;
+                            calcNeedsSave();
+                        }
+                    }
+                    Controls.Label {
+                        enabled: false
+                        text: i18n("(HH:MM)")
+                    }
+                    Controls.Label {
+                        text: i18n("Sunset begins")
+                        Layout.alignment: Qt.AlignRight
+                    }
+                    TimeField {
+                        id: evenBeginManField
+                        backend: cA.eveningBeginFixedStaged
+                        onBackendChanged: {cA.eveningBeginFixedStaged = backend;
+                            calcNeedsSave();
+                        }
+                    }
+                    Controls.Label {
+                        enabled: false
+                        text: i18n("(HH:MM)")
+                    }
+                    Controls.Label {
+                        text: i18n("Transition duration")
+                        Layout.alignment: Qt.AlignRight
+                    }
+                    NumberField {
+                        id: transTimeField
+                        backend: cA.transitionTimeStaged
+                        onBackendChanged: {cA.transitionTimeStaged = backend;
+                            calcNeedsSave();
+                        }
+
+                        inputMethodHints: Qt.ImhDigitsOnly
+                        validator: IntValidator {bottom: 1; top: 600;}  // less than 12 hours (in minutes: 720)
+                    }
+                    Controls.Label {
+                        enabled: false
+                        text: i18n("(In minutes - min. 1, max. 600)")
+                    }
+                }
+                Controls.Label {
+                    id: manualTimingsError1
+                    anchors.horizontalCenter: manualTimingsViewGrid.horizontalCenter
+                    visible: evenBeginManField.getNormedDate() - mornBeginManField.getNormedDate() <= 0
+
+                    font.italic: true
+                    text: i18n("Error: Morning not before evening.")
+                }
+                Controls.Label {
+                    id: manualTimingsError2
+                    anchors.horizontalCenter: manualTimingsViewGrid.horizontalCenter
+                    visible: {
+                        if (manualTimingsError1.visible) {
+                            return false;
+                        }
+                        var trTime = transTimeField.backend * 60 * 1000;
+                        var mor = mornBeginManField.getNormedDate();
+                        var eve = evenBeginManField.getNormedDate();
+
+                        return eve - mor <= trTime || eve - mor >= 86400000 - trTime;
+                    }
+                    font.italic: true
+                    text: i18n("Error: Transition time overlaps.")
+                }
+            }
+        }
+    }
+
+    // error message as overlay
+    Item {
+        width: 0.8 * main.width
+        height: 0.8 * main.height
+        anchors.centerIn: main
+
+        visible: error != CC.CompositorAdaptor.ErrorCodeSuccess
+
+        Rectangle {
+            anchors.centerIn: parent
+            width: errorMessage.contentWidth * 1.1
+            height: errorMessage.contentHeight * 1.1
+            color: theme.backgroundColor
+            opacity: 0.8
+
+            border {
+                width: units.devicePixelRatio
+                color: theme.textColor
+            }
+        }
+
+        PlasmaExtras.Heading {
+            id: errorMessage
+            anchors.fill: parent
+
+            level: 4
+            text: cA.errorText
+
+            horizontalAlignment: Text.AlignHCenter
+            verticalAlignment: Text.AlignVCenter
+
+            wrapMode: Text.Wrap
+            textFormat: Text.PlainText
+        }
+    }
+}
diff --git a/kcms/nightcolor/package/metadata.desktop b/kcms/nightcolor/package/metadata.desktop
new file mode 100644
index 00000000..f78b20d1
--- /dev/null
+++ b/kcms/nightcolor/package/metadata.desktop
@@ -0,0 +1,50 @@
+[Desktop Entry]
+Name=Night Color
+Name[ca]=Color de nit
+Name[ca at valencia]=Color de nit
+Name[es]=Color nocturno
+Name[fr]=Couleur de nuit
+Name[it]=Colore notturno
+Name[nl]=Nachtkleur
+Name[pt]=Cor Nocturna
+Name[pt_BR]=Cor noturna
+Name[sr]=Ноћна боја
+Name[sr at ijekavian]=Ноћна боја
+Name[sr at ijekavianlatin]=Noćna boja
+Name[sr at latin]=Noćna boja
+Name[sv]=Nattfärg
+Name[uk]=Нічні кольори
+Name[x-test]=xxNight Colorxx
+Comment=Adjust color temperatur at night to reduce eye strain
+Comment[ca]=Ajusta la temperatura del color per la nit per reduir la tensió ocular.
+Comment[ca at valencia]=Ajusta la temperatura del color per la nit per reduir la tensió ocular.
+Comment[es]=Ajustar la temperatura del color durante la noche para reducir la fatiga visual
+Comment[fr]=Ajuster la température des couleurs durant la nuit pour réduire la fatigue des yeux
+Comment[it]=Regola la temperatura dei colori di notte per ridurre l'affaticamento degli occhi
+Comment[nl]=Kleurtemperatuur bij nacht aanpassen on vermoeidheid van de ogen te vermijden
+Comment[pt]=Ajusta a temperatura da cor à noite para reduzir o cansaço dos olhos
+Comment[pt_BR]=Ajustar a temperatura de cor a noite para reduzir a tensão visual
+Comment[sr]=Подесите температуру боје током ноћи ради мањег напрезања очију
+Comment[sr at ijekavian]=Подесите температуру боје током ноћи ради мањег напрезања очију
+Comment[sr at ijekavianlatin]=Podesite temperaturu boje tokom noći radi manjeg naprezanja očiju
+Comment[sr at latin]=Podesite temperaturu boje tokom noći radi manjeg naprezanja očiju
+Comment[sv]=Justera färgtemperatur på natten för att reducera ögonbelastning
+Comment[uk]=Коригування температури кольорів для зменшення навантаження на очі вночі
+Comment[x-test]=xxAdjust color temperatur at night to reduce eye strainxx
+
+Icon=preferences-desktop
+Encoding=UTF-8
+Keywords=
+Type=Service
+X-KDE-ParentApp=
+X-KDE-PluginInfo-Author=Roman Gilg
+X-KDE-PluginInfo-Email=subdiff at gmail.com
+X-KDE-PluginInfo-License=GPL
+X-KDE-PluginInfo-Name=kcm_nightcolor
+X-KDE-PluginInfo-Version=
+X-KDE-PluginInfo-Website=
+X-KDE-ServiceTypes=Plasma/Generic
+X-Plasma-API=declarativeappletscript
+
+X-Plasma-MainScript=ui/main.qml
+X-Plasma-RemoteLocation=
diff --git a/kcms/phonon/CMakeLists.txt b/kcms/phonon/CMakeLists.txt
index b07d8611..49c28282 100644
--- a/kcms/phonon/CMakeLists.txt
+++ b/kcms/phonon/CMakeLists.txt
@@ -43,7 +43,7 @@ if(GLIB2_FOUND AND PULSEAUDIO_FOUND AND CANBERRA_FOUND)
 
   include_directories(${GLIB2_INCLUDE_DIR} ${PULSEAUDIO_INCLUDE_DIR} ${CANBERRA_INCLUDE_DIRS})
 
-  set(kcmphonon_LIBS ${kcmphonon_LIBS} ${GLIB2_LIBRARIES} ${PULSEAUDIO_LIBRARY} ${PULSEAUDIO_MAINLOOP_LIBRARY} ${CANBERRA_LIBRARIES})
+  set(kcmphonon_LIBS ${kcmphonon_LIBS} ${GLIB2_LIBRARIES} ${PulseAudio_LIBRARIES} ${PulseAudio_MAINLOOP_LIBRARY} ${CANBERRA_LIBRARIES})
 endif()
 
 add_library(kcm_phonon MODULE ${kcmphonon_SRCS})
diff --git a/kcms/runners/kcm_plasmasearch.desktop b/kcms/runners/kcm_plasmasearch.desktop
index cfe22eb0..769522d6 100644
--- a/kcms/runners/kcm_plasmasearch.desktop
+++ b/kcms/runners/kcm_plasmasearch.desktop
@@ -58,10 +58,19 @@ Name[zh_TW]=Plasma 搜尋
 Comment=Configure Search Bar
 Comment[ca]=Configura la barra de cerca
 Comment[ca at valencia]=Configura la barra de busca
+Comment[cs]=Nastavit panel vyhledávání
+Comment[da]=Indstil søgelinje
+Comment[de]=Suchleiste einrichten
+Comment[en_GB]=Configure Search Bar
 Comment[es]=Configurar la barra de búsqueda
+Comment[eu]=Konfiguratu bilaketa-barra
+Comment[fr]=Configurer la barre de recherche
+Comment[hu]=Keresősáv beállítása
 Comment[id]=Konfigurasi Bilah Pencarian
 Comment[it]=Configura la barra di ricerca
+Comment[ko]=검색 표시줄 설정
 Comment[nl]=Zoekbalk configureren
+Comment[pl]=Ustawienia paska wyszukiwania
 Comment[pt]=Configurar a Barra de Pesquisa
 Comment[pt_BR]=Configura a barra de pesquisa
 Comment[ru]=Настройка строки поиска и запуска
@@ -71,8 +80,10 @@ Comment[sr at ijekavian]=Подешавање траке претраге
 Comment[sr at ijekavianlatin]=Podešavanje trake pretrage
 Comment[sr at latin]=Podešavanje trake pretrage
 Comment[sv]=Anpassa sökrad
+Comment[tr]=Arama Çubuğunu Yapılandır
 Comment[uk]=Налаштування панелі пошуку
 Comment[x-test]=xxConfigure Search Barxx
+Comment[zh_CN]=配置搜索栏
 X-KDE-Keywords=Search, File, Baloo, Runner, krunner
 X-KDE-Keywords[ar]=ابحث,ملف,بالو,مشغّل,مشغّلك
 X-KDE-Keywords[bs]=Pretraži,fajl,Baloo,Trkač,krunner
diff --git a/kcms/solid_actions/device-actions/solid-device-OpticalDisc.desktop b/kcms/solid_actions/device-actions/solid-device-OpticalDisc.desktop
index 43a20930..274b96dd 100644
--- a/kcms/solid_actions/device-actions/solid-device-OpticalDisc.desktop
+++ b/kcms/solid_actions/device-actions/solid-device-OpticalDisc.desktop
@@ -332,7 +332,7 @@ Name[nds]=Schiev-Typ
 Name[nl]=Schijftype
 Name[nn]=Disktype
 Name[pa]=ਡਿਸਕ ਕਿਸਮ
-Name[pl]=Typ dysku
+Name[pl]=Rodzaj dysku
 Name[pt]=Tipo de Disco
 Name[pt_BR]=Tipo de disco
 Name[ro]=Tipul discului
@@ -404,7 +404,7 @@ Name[nds]=Dateisysteem-Typ
 Name[nl]=FS-type
 Name[nn]=Filsystemtype
 Name[pa]=Fs ਕਿਸਮ
-Name[pl]=Typ systemu plików
+Name[pl]=Rodzaj systemu plików
 Name[pt]=Tipo de SF
 Name[pt_BR]=Tipo de sistema de arquivos
 Name[ro]=Tipul SF
diff --git a/kcms/solid_actions/device-actions/solid-device-StorageVolume.desktop b/kcms/solid_actions/device-actions/solid-device-StorageVolume.desktop
index 0194cf6d..be8aae33 100644
--- a/kcms/solid_actions/device-actions/solid-device-StorageVolume.desktop
+++ b/kcms/solid_actions/device-actions/solid-device-StorageVolume.desktop
@@ -46,7 +46,7 @@ Name[nds]=Dateisysteem-Typ
 Name[nl]=FS-type
 Name[nn]=Filsystemtype
 Name[pa]=Fs ਕਿਸਮ
-Name[pl]=Typ systemu plików
+Name[pl]=Rodzaj systemu plików
 Name[pt]=Tipo de SF
 Name[pt_BR]=Tipo de sistema de arquivos
 Name[ro]=Tipul SF
diff --git a/kcms/solid_actions/solid-device-type.desktop b/kcms/solid_actions/solid-device-type.desktop
index cd7fcef4..817ac68c 100644
--- a/kcms/solid_actions/solid-device-type.desktop
+++ b/kcms/solid_actions/solid-device-type.desktop
@@ -45,7 +45,7 @@ Name[nds]=Solid-Reedschaptyp
 Name[nl]=Solid-apparaattype
 Name[nn]=Type Solid-eining
 Name[pa]=ਸਾਲਡ ਜੰਤਰ ਕਿਸਮ
-Name[pl]=Typ urządzenia Solid
+Name[pl]=Rodzaj urządzenia Solid
 Name[pt]=Tipo de Dispositivo do Solid
 Name[pt_BR]=Tipo de dispositivo do Solid
 Name[ro]=Tip dispozitiv solid
diff --git a/kcms/style/finetuning.ui b/kcms/style/finetuning.ui
index 9da7716a..084a1bbd 100644
--- a/kcms/style/finetuning.ui
+++ b/kcms/style/finetuning.ui
@@ -25,7 +25,7 @@
      </property>
     </widget>
    </item>
-   <item row="5" column="0">
+   <item row="3" column="0">
     <spacer name="verticalSpacer">
      <property name="orientation">
       <enum>Qt::Vertical</enum>
@@ -41,7 +41,7 @@
    <item row="0" column="0">
     <widget class="QLabel" name="label_3">
      <property name="text">
-      <string>Show icons on buttons:</string>
+      <string>Show icons in b&uttons:</string>
      </property>
      <property name="alignment">
       <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -60,7 +60,7 @@
       <item row="0" column="0">
        <widget class="QLabel" name="label">
         <property name="text">
-         <string>Main toolbar text:</string>
+         <string>Main &toolbar text location:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -97,7 +97,7 @@
       <item row="1" column="0">
        <widget class="QLabel" name="label_2">
         <property name="text">
-         <string>Secondary toolbar text:</string>
+         <string>Secondary toolbar text &location:</string>
         </property>
         <property name="alignment">
          <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
@@ -147,60 +147,6 @@
      </layout>
     </widget>
    </item>
-   <item row="4" column="0" colspan="3">
-    <widget class="QGroupBox" name="menubarBox">
-     <property name="title">
-      <string>Menubar</string>
-     </property>
-     <layout class="QGridLayout" name="gridLayout1">
-      <item row="0" column="0">
-       <widget class="QLabel" name="labelMenubarStyle">
-        <property name="text">
-         <string>Menubar style:</string>
-        </property>
-        <property name="alignment">
-         <set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
-        </property>
-        <property name="buddy">
-         <cstring>comboMenubarStyle</cstring>
-        </property>
-       </widget>
-      </item>
-      <item row="0" column="1">
-       <widget class="KComboBox" name="comboMenubarStyle">
-        <item>
-         <property name="text">
-          <string>In application</string>
-         </property>
-        </item>
-        <item>
-         <property name="text">
-          <string>Title bar button</string>
-         </property>
-        </item>
-        <item>
-         <property name="text">
-          <string>Application Menu widget</string>
-         </property>
-        </item>
-       </widget>
-      </item>
-      <item row="0" column="2">
-       <spacer name="horizontalSpacer_3">
-        <property name="orientation">
-         <enum>Qt::Horizontal</enum>
-        </property>
-        <property name="sizeHint" stdset="0">
-         <size>
-          <width>40</width>
-          <height>20</height>
-         </size>
-        </property>
-       </spacer>
-      </item>
-     </layout>
-    </widget>
-   </item>
    <item row="1" column="0">
     <widget class="QLabel" name="label_5">
      <property name="text">
@@ -214,9 +160,6 @@
      </property>
     </widget>
    </item>
-   <item row="3" column="0">
-    <widget class="KMessageWidget" name="menuBarMessageWidget" native="true"/>
-   </item>
   </layout>
  </widget>
  <customwidgets>
@@ -225,11 +168,6 @@
    <extends>QComboBox</extends>
    <header>kcombobox.h</header>
   </customwidget>
-  <customwidget>
-   <class>KMessageWidget</class>
-   <extends>QFrame</extends>
-   <header>kmessagewidget.h</header>
-  </customwidget>
  </customwidgets>
  <resources/>
  <connections/>
diff --git a/kcms/style/kcmstyle.cpp b/kcms/style/kcmstyle.cpp
index 560555c1..92870521 100644
--- a/kcms/style/kcmstyle.cpp
+++ b/kcms/style/kcmstyle.cpp
@@ -242,12 +242,9 @@ KCMStyle::KCMStyle( QWidget* parent, const QVariantList& )
     connect(fineTuningUi.cbIconsInMenus,     &QAbstractButton::toggled,   this, &KCMStyle::setEffectsDirty);
     connect(fineTuningUi.comboToolbarIcons,    SIGNAL(activated(int)), this, SLOT(setEffectsDirty()));
     connect(fineTuningUi.comboSecondaryToolbarIcons,    SIGNAL(activated(int)), this, SLOT(setEffectsDirty()));
-    connect(fineTuningUi.comboMenubarStyle,    SIGNAL(activated(int)), this, SLOT(setEffectsDirty()));
 
     addWhatsThis();
 
-    fineTuningUi.menuBarMessageWidget->hide();
-
     // Insert the pages into the tabWidget
     tabWidget->addTab(page1, i18nc("@title:tab", "&Applications"));
     tabWidget->addTab(page2, i18nc("@title:tab", "&Fine Tuning"));
@@ -377,50 +374,6 @@ void KCMStyle::save()
     toolbarStyleGroup.writeEntry("ToolButtonStyleOtherToolbars",
                             toolbarButtonText(fineTuningUi.comboSecondaryToolbarIcons->currentIndex()));
 
-    // menubar page
-    KConfigGroup menuBarStyleGroup(&_config, "Appmenu Style");
-
-    QString style = menuBarStyleText(fineTuningUi.comboMenubarStyle->currentIndex());
-
-    QString previous = menuBarStyleGroup.readEntry("Style", "InApplication");
-    menuBarStyleGroup.writeEntry("Style", style);
-    _config.sync();
-
-    // The old KCM used to mess with autoloading depending on whether menu was enabled or not
-    // since it was always disabled, the kded module would never autoload breaking global menu
-    // for users without an obvious reason why it won't work.
-    QDBusMessage method = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded5"),
-                                                         QStringLiteral("/kded"),
-                                                         QStringLiteral("org.kde.kded5"),
-                                                         QStringLiteral("setModuleAutoloading"));
-    method.setArguments({QStringLiteral("appmenu"), true});
-    QDBusConnection::sessionBus().asyncCall(method);
-
-    method = QDBusMessage::createMethodCall(QStringLiteral("org.kde.kded5"),
-                                            QStringLiteral("/kded"),
-                                            QStringLiteral("org.kde.kded5"),
-                                            QStringLiteral("loadModule"));
-    method.setArguments({QStringLiteral("appmenu")});
-    QDBusConnection::sessionBus().asyncCall(method);
-
-    // since we load the module async, this call will fail if the module wasn't loaded
-    // but since it will init itself when it loads, this isn't too bad
-    QDBusConnection::sessionBus().asyncCall(
-        QDBusMessage::createMethodCall(QStringLiteral("org.kde.kappmenu"),
-                                       QStringLiteral("/KAppMenu"),
-                                       QStringLiteral("org.kde.kappmenu"),
-                                       QStringLiteral("reconfigure")
-        )
-    );
-
-    const bool showMenuInApplication = (style == QLatin1String("InApplication"));
-
-    if (previous == QLatin1String("InApplication") && !showMenuInApplication) {
-        fineTuningUi.menuBarMessageWidget->setMessageType(KMessageWidget::Information);
-        fineTuningUi.menuBarMessageWidget->setText(i18n("Your changes will take effect only on application restart."));
-        fineTuningUi.menuBarMessageWidget->animatedShow();
-    }
-
     // Export the changes we made to qtrc, and update all qt-only
     // applications on the fly, ensuring that we still follow the user's
     // export fonts/colors settings.
@@ -508,7 +461,6 @@ void KCMStyle::defaults()
     // Effects
     fineTuningUi.comboToolbarIcons->setCurrentIndex(toolbarButtonIndex(QStringLiteral("TextBesideIcon")));
     fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex(QStringLiteral("TextBesideIcon")));
-    fineTuningUi.comboMenubarStyle->setCurrentIndex(menuBarStyleIndex(QStringLiteral("InApplication")));
     fineTuningUi.cbIconsOnButtons->setChecked(true);
     fineTuningUi.cbIconsInMenus->setChecked(true);
     emit changed(true);
@@ -762,10 +714,6 @@ void KCMStyle::loadEffects( KConfig& config )
     tbIcon = configGroup.readEntry("ToolButtonStyleOtherToolbars", "TextBesideIcon");
     fineTuningUi.comboSecondaryToolbarIcons->setCurrentIndex(toolbarButtonIndex(tbIcon));
 
-    configGroup = config.group("Appmenu Style");
-    QString menuBarStyle = configGroup.readEntry("Style", "InApplication");
-    fineTuningUi.comboMenubarStyle->setCurrentIndex(menuBarStyleIndex(menuBarStyle));
-
     configGroup = config.group("KDE");
     fineTuningUi.cbIconsOnButtons->setChecked(configGroup.readEntry("ShowIconsOnPushButtons", true));
     fineTuningUi.cbIconsInMenus->setChecked(configGroup.readEntry("ShowIconsInMenuItems", true));
diff --git a/kcms/style/style.desktop b/kcms/style/style.desktop
index f3f2173a..01b73d71 100644
--- a/kcms/style/style.desktop
+++ b/kcms/style/style.desktop
@@ -108,10 +108,15 @@ X-KDE-Keywords=style,styles,look,widget,icons,toolbars,text,highlight,apps,KDE a
 X-KDE-Keywords[ca]=estil,estils,aparença,estri,icones,barres d'eines,text,ressaltat,aplicacions,aplicacions del KDE,tema,plasma,menu,menu global
 X-KDE-Keywords[ca at valencia]=estil,estils,aparença,estri,icones,barres d'eines,text,ressaltat,aplicacions,aplicacions del KDE,tema,plasma,menu,menu global
 X-KDE-Keywords[da]=stil,style,udseende,kontrol,widget,ikoner,værktøjslinjer,tekst,fremhævning,programmer,KDE-programmer,tema,plasma,menu,global menu
+X-KDE-Keywords[de]=Stile,Design,Themes,Schema,Elemente,Bildschirmelemente,Icons,Bedienelemente,Schriften,Symbole,Werkzeugleisten,Text,Hervorhebungen,Knöpfe,Anwendungen,Programme,KDE-Programme,Menü,Globales Menü
+X-KDE-Keywords[en_GB]=style,styles,look,widget,icons,toolbars,text,highlight,apps,KDE applications,theme,plasma,menu,global menu
 X-KDE-Keywords[es]=estilo,estilos,apariencia,controles,iconos,barras de herramientas,texto,resaltado,aplicaciones,aplicaciones de KDE,tema,plasma,menú,menú global
+X-KDE-Keywords[eu]=estilo,estiloak,itxura,trepeta,ikonoak,tresna-barrak,testua,nabarmentzea,aplikazioak,KDE aplikazioak,gaia,plasma,menu,menu orokorra
 X-KDE-Keywords[fr]=style, styles, apparence, composant graphique, icônes, barres d'outil, texte, mise en valeur, applications, applications KDE, thème, plasma, menu, menu global
+X-KDE-Keywords[hu]=stílus,stílusok,kinézet,widget,ikonok,eszköztárak,szöveg,kiemelés,alkalmazások,KDe alkalmazások,téma,plazma,menü,globális menü
 X-KDE-Keywords[id]=gaya,gaya,look,widget,ikon,bilah alat,teks,sorot,apl,aplikasi KDE,tema,plasma,menu,menu global
 X-KDE-Keywords[it]=stile,stili,aspetto,oggetto,icone,barre degli strumenti,testo,evidenziazione,applicazioni,applicazioni KDE,tema,plasma,menu,menu globale
+X-KDE-Keywords[ko]=style,styles,look,widget,icons,toolbars,text,highlight,apps,KDE applications,theme,plasma,menu,global menu,스타일,모양,위젯,아이콘,툴바,도구 모음,강조,프로그램,앱,KDE 프로그램,테마,전역 메뉴,메뉴
 X-KDE-Keywords[nl]=stijl,stijlen,uiterlijk,widget,pictogrammen,werkbalk,tekst,accentuering,apps,KDE-toepassingen,thema,plasma, menu,globaal menu
 X-KDE-Keywords[pl]=style,styl,wygląd,element interfejsu,ikony,paski narzędzi,tekst,podświetlenie,programy,programy KDE,motyw,plazma,menu,globalne menu
 X-KDE-Keywords[pt]=estilo,estilos,aparência,elemento,item,ícones,barras de ferramentas,texto,realce,aplicações,aplicações do KDE,tema,plasma,menu global
diff --git a/kcms/touchpad/src/kcm/kcm_touchpad.desktop b/kcms/touchpad/src/kcm/kcm_touchpad.desktop
index a99bac23..4aa06ac4 100644
--- a/kcms/touchpad/src/kcm/kcm_touchpad.desktop
+++ b/kcms/touchpad/src/kcm/kcm_touchpad.desktop
@@ -7,7 +7,7 @@ OnlyShowIn=KDE;
 
 X-KDE-ServiceTypes=KCModule,KCModuleInit
 X-KDE-Init-Symbol=touchpad
-X-KDE-Init-Phase=0
+X-KDE-Init-Phase=1
 X-KDE-Library=kded_touchpad
 X-KDE-PluginKeyword=kcm
 X-KDE-ParentApp=kcontrol
diff --git a/kcms/workspaceoptions/mainpage.ui b/kcms/workspaceoptions/mainpage.ui
index 59ab0e01..800c4736 100644
--- a/kcms/workspaceoptions/mainpage.ui
+++ b/kcms/workspaceoptions/mainpage.ui
@@ -17,7 +17,7 @@
    <item row="0" column="1">
     <widget class="QCheckBox" name="showToolTips">
      <property name="text">
-      <string>Show Informational Tips</string>
+      <string>Display informational tooltips on mouse hover</string>
      </property>
      <property name="checked">
       <bool>true</bool>
@@ -40,7 +40,7 @@
    <item row="1" column="1">
     <widget class="QCheckBox" name="showOsd">
      <property name="text">
-      <string>Visual feedback for status changes</string>
+      <string>Display visual feedback for status changes</string>
      </property>
     </widget>
    </item>
diff --git a/org.kde.plasmashell.metainfo.xml b/org.kde.plasmashell.metainfo.xml
index b0b1e7da..ef68c806 100644
--- a/org.kde.plasmashell.metainfo.xml
+++ b/org.kde.plasmashell.metainfo.xml
@@ -42,17 +42,18 @@
   <name xml:lang="zh-CN">KDE Plasma 桌面</name>
   <name xml:lang="zh-TW">KDE Plasma 桌面</name>
   <summary>KDE's complete desktop experience. Simple by default, powerful when needed</summary>
-  <summary xml:lang="ca">Experiència completa d'escriptori del KDE. Senzilla per omissió, potent quan cal</summary>
-  <summary xml:lang="ca-valencia">Experiència completa d'escriptori del KDE. Senzilla per omissió, potent quan cal</summary>
+  <summary xml:lang="ca">Experiència completa de l'escriptori KDE. Senzilla per omissió, potent quan cal</summary>
+  <summary xml:lang="ca-valencia">Experiència completa de l'escriptori KDE. Senzilla per omissió, potent quan cal</summary>
   <summary xml:lang="da">KDE's komplette desktop-oplevelse. Simpelt som standard, kraftfuldt når det behøves</summary>
+  <summary xml:lang="de">Das umfassende Arbeitsflächen-Erlebnis von KDE. Standardmäßig einfach, bei Bedarf leistungsstark</summary>
   <summary xml:lang="el">Η πλήρης εμπειρία επιφάνειας εργασίας του KDE. Προκαθορισμένα απλή, πανίσχυρη όταν χρειάζεται.</summary>
   <summary xml:lang="en-GB">KDE's complete desktop experience. Simple by default, powerful when needed</summary>
   <summary xml:lang="es">Experiencia completa de escritorio de KDE. Sencillo por omisión, potente cuando es necesario.</summary>
   <summary xml:lang="fi">KDE:n täydellinen työpöytäkokemus. Oletuksena yksinkertainen, tarvittaessa tehokas</summary>
-  <summary xml:lang="fr">L'expérience de bureau complète de KDE. Simple par défaut, puissant si nécessaire.</summary>
+  <summary xml:lang="fr">L'expérience de bureau complète de KDE. Simple par défaut, puissant si nécessaire</summary>
   <summary xml:lang="gl">Experiencia de escritorio completa de KDE. Simple de primeiras, potente cando cómpre.</summary>
   <summary xml:lang="it">L'esperienza completa del desktop da KDE. Semplice nelle scelte predefinite, potente quando c'è bisogno</summary>
-  <summary xml:lang="ko">KDE 데스크톱 사용자 환경입니다. 첫 시작은 간단하게, 필요할 때에는 강력하게.</summary>
+  <summary xml:lang="ko">KDE 데스크톱 사용자 환경입니다. 첫 시작은 간단하게, 필요할 때에는 강력하게</summary>
   <summary xml:lang="nl">De complete bureaubladervaring van KDE. Standaard eenvoudig, krachtig indien nodig</summary>
   <summary xml:lang="nn">Komplett KDE-oppleving. Enkel som standard og kraftig når nødvendig.</summary>
   <summary xml:lang="pl">Całkowite wrażenie pulpitu KDE. Prosty z natury, zaawansowany gdy potrzeba</summary>
@@ -60,13 +61,13 @@
   <summary xml:lang="pt-BR">A experiência da área de trabalho do KDE completa. Simples por padrão, potente quando necessário</summary>
   <summary xml:lang="sk">Kompletná pracovná plocha KDE. Predvolene jednoduchá, pri potrebe silná</summary>
   <summary xml:lang="sl">KDE-jeva popolna namizna izkušnja. Privzeto preprosta, a tudi zmogljiva, če je to zahtevano</summary>
-  <summary xml:lang="sr">КДЕ‑ово потпуно искуство површи. Подразумевано једноставно, моћно кад затреба.</summary>
-  <summary xml:lang="sr-Latn">KDE‑ovo potpuno iskustvo površi. Podrazumevano jednostavno, moćno kad zatreba.</summary>
-  <summary xml:lang="sr-ijekavian">КДЕ‑ово потпуно искуство површи. Подразумевано једноставно, моћно кад затреба.</summary>
-  <summary xml:lang="sr-ijekavianlatin">KDE‑ovo potpuno iskustvo površi. Podrazumevano jednostavno, moćno kad zatreba.</summary>
+  <summary xml:lang="sr">КДЕ‑ово потпуно искуство површи, подразумевано једноставно а моћно кад затреба</summary>
+  <summary xml:lang="sr-Latn">KDE‑ovo potpuno iskustvo površi, podrazumevano jednostavno a moćno kad zatreba</summary>
+  <summary xml:lang="sr-ijekavian">КДЕ‑ово потпуно искуство површи, подразумевано једноставно а моћно кад затреба</summary>
+  <summary xml:lang="sr-ijekavianlatin">KDE‑ovo potpuno iskustvo površi, podrazumevano jednostavno a moćno kad zatreba</summary>
   <summary xml:lang="sv">KDE:s fullständiga skrivbordsupplevelse. Normalt enkel, kraftfull vid behov</summary>
   <summary xml:lang="tr">KDE'nin tam masaüstü deneyimi. Özünde sade, gerektiğinde güçlü</summary>
-  <summary xml:lang="uk">Повноцінне стільничне середовище KDE. Типово просте, але потужне, якщо це потрібно.</summary>
+  <summary xml:lang="uk">Повноцінне стільничне середовище KDE. Типово просте, але потужне, якщо це потрібно</summary>
   <summary xml:lang="x-test">xxKDE's complete desktop experience. Simple by default, powerful when neededxx</summary>
   <summary xml:lang="zh-CN">KDE 的完整桌面体验。默认简单,需要时强大。</summary>
   <summary xml:lang="zh-TW">KDE 的完整桌面體驗。預設簡潔,需要時足夠強大</summary>
@@ -81,10 +82,15 @@
       <caption>Plasma being used as a desktop</caption>
       <caption xml:lang="ca">Fa servir el Plasma com a escriptori</caption>
       <caption xml:lang="ca-valencia">Fa servir el Plasma com a escriptori</caption>
+      <caption xml:lang="da">Plasma bruges som skrivebord</caption>
+      <caption xml:lang="de">Plasma als eine Arbeitsfläche benutzt</caption>
       <caption xml:lang="el">Χρήση Plasma ως επιφάνεια εργασίας</caption>
+      <caption xml:lang="en-GB">Plasma being used as a desktop</caption>
       <caption xml:lang="es">Plasma usado como escritorio</caption>
+      <caption xml:lang="fi">Plasma on käytössä työpöytänä</caption>
       <caption xml:lang="fr">Plasma utilisé comme bureau</caption>
       <caption xml:lang="it">Plasma usato come desktop</caption>
+      <caption xml:lang="ko">Plasma를 데스크톱으로 사용함</caption>
       <caption xml:lang="nl">Plasma gebruikt wordend als een bureaublad</caption>
       <caption xml:lang="pl">Plazma wykorzystywana jako pulpit</caption>
       <caption xml:lang="pt">O Plasma em uso como ambiente de trabalho</caption>
diff --git a/runners/kwin/plasma-runner-kwin.desktop b/runners/kwin/plasma-runner-kwin.desktop
index 7f1de79a..8a91a714 100644
--- a/runners/kwin/plasma-runner-kwin.desktop
+++ b/runners/kwin/plasma-runner-kwin.desktop
@@ -72,7 +72,7 @@ Comment[sr at ijekavian]=Позабавите се Плазминим слагач
 Comment[sr at ijekavianlatin]=Pozabavite se Plasminim slagačem
 Comment[sr at latin]=Pozabavite se Plasminim slagačem
 Comment[sv]=Interaktion med Plasma sammansättning
-Comment[tr]=Plazma Oluşturucusu Etkileş
+Comment[tr]=Plasma Dizgicisi ile Etileşim
 Comment[uk]=Взаємодія із засобом композиції Плазми
 Comment[x-test]=xxInteract with the Plasma Compositorxx
 Comment[zh_CN]=和 Plasma 混成器进行交互
diff --git a/runners/plasma-desktop/plasma-runner-plasma-desktop.desktop b/runners/plasma-desktop/plasma-runner-plasma-desktop.desktop
index 6b6e62d1..bf7c4e7b 100644
--- a/runners/plasma-desktop/plasma-runner-plasma-desktop.desktop
+++ b/runners/plasma-desktop/plasma-runner-plasma-desktop.desktop
@@ -6,7 +6,7 @@ Name[bs]=Plazma školjka površi
 Name[ca]=Intèrpret d'ordres de l'escriptori Plasma
 Name[ca at valencia]=Intèrpret d'ordes de l'escriptori Plasma
 Name[cs]=Pracovní plocha Plasma
-Name[da]=Plasma Desktop Shell
+Name[da]=Plasma-skrivebordets skal
 Name[de]=Plasma-Umgebung
 Name[el]=Κέλυφος επιφάνειας εργασίας Plasma
 Name[en_GB]=Plasma Desktop Shell
@@ -70,7 +70,7 @@ Comment[bs]=Pozabavite se plazma školjkom površi
 Comment[ca]=Interactua amb l'intèrpret d'ordres de l'escriptori Plasma
 Comment[ca at valencia]=Interactua amb l'intèrpret d'ordes de l'escriptori Plasma
 Comment[cs]=Interakce se shellem pracovní plochy plasmy
-Comment[da]=Interaktion med Plasma desktop-skal
+Comment[da]=Interaktion med Plasma-skrivebordets skal
 Comment[de]=Interaktion mit der Plasma-Shell
 Comment[el]=Αλληλεπίδραση με το κέλυφος επιφάνειας εργασίας Plasma
 Comment[en_GB]=Interact with the Plasma desktop shell
diff --git a/toolboxes/plasma-toolbox-paneltoolbox.desktop b/toolboxes/plasma-toolbox-paneltoolbox.desktop
index 7f2c2a8a..7b42dcf3 100644
--- a/toolboxes/plasma-toolbox-paneltoolbox.desktop
+++ b/toolboxes/plasma-toolbox-paneltoolbox.desktop
@@ -6,7 +6,7 @@ Comment[bs]=Podrazumijevana alatnica panela za plazma školjku površi
 Comment[ca]=Quadre d'eines per defecte del plafó per a l'àrea de treball de l'escriptori Plasma
 Comment[ca at valencia]=Quadre d'eines per defecte del plafó per a l'àrea de treball de l'escriptori Plasma
 Comment[cs]=Výchozí nástroje panelu pro Plasma shell pracovní plochy
-Comment[da]=Standard panelværktøjskasse til Plasma desktop-skal
+Comment[da]=Standard panelværktøjskasse til Plasma-skrivebordets skal
 Comment[de]=Standard-Werkzeugkasten für die Plasma-Kontrollleiste
 Comment[el]=Η προκαθορισμένη εργαλειοθήκη πίνακα για το κέλυφος της επιφάνειας εργασίας Plasma
 Comment[en_GB]=Default panel toolbox for the Plasma desktop shell


More information about the kde-doc-english mailing list