diff --git a/app/app.pri b/app/app.pri
index 768f484af6d2e4fc61a3a97b4aa3bf55ea26fa3c..3dc35f887cf0401f44e57cf58edb9467911bb100 100644
--- a/app/app.pri
+++ b/app/app.pri
@@ -27,4 +27,16 @@ INCLUDEPATH += $${PWD}/src
 
 unix:!ios:!android {
     QT += dbus
+
+    HEADERS += \
+        $${PWD}/src/handlers/desktopthemehandler.h \
+        $${PWD}/src/desktopthemes/kdetheme.h \
+        $${PWD}/src/desktopthemes/gnometheme.h \
+        $${PWD}/src/desktopthemes/xfcetheme.h
+
+    SOURCES += \
+        $${PWD}/src/handlers/desktopthemehandler.cpp \
+        $${PWD}/src/desktopthemes/kdetheme.cpp \
+        $${PWD}/src/desktopthemes/gnometheme.cpp \
+        $${PWD}/src/desktopthemes/xfcetheme.cpp
 }
diff --git a/app/src/desktopthemes/gnometheme.cpp b/app/src/desktopthemes/gnometheme.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..118efc1437cf0a32fc7fe0c38e63630f7c673fc3
--- /dev/null
+++ b/app/src/desktopthemes/gnometheme.cpp
@@ -0,0 +1,41 @@
+#include "gnometheme.h"
+
+#include <QStringList>
+#include <QDir>
+#include <QProcess>
+
+GnomeTheme::GnomeTheme(const QString &path, QObject *parent)
+    : QObject(parent), path_(path)
+{
+    themeName_ = QDir(path_).dirName();
+}
+
+bool GnomeTheme::applyAsWallpaper() const
+{
+    return setConfig("org.gnome.desktop.background", "picture-uri", "file://" + path_);
+}
+
+bool GnomeTheme::applyAsIcon() const
+{
+    return setConfig("org.gnome.desktop.interface", "icon-theme", themeName_);
+}
+
+bool GnomeTheme::applyAsCursor() const
+{
+    return setConfig("org.gnome.desktop.interface", "cursor-theme", themeName_);
+}
+
+bool GnomeTheme::applyAsGtk3Theme() const
+{
+    return setConfig("org.gnome.desktop.interface", "gtk-theme", themeName_);
+}
+
+bool GnomeTheme::applyAsGnomeShellTheme() const
+{
+    return setConfig("org.gnome.shell.extensions.user-theme", "name", themeName_);
+}
+
+bool GnomeTheme::setConfig(const QString &schema, const QString &key, const QString &value) const
+{
+    return QProcess::startDetached("gsettings", QStringList() << "set" << schema << key << value);
+}
diff --git a/app/src/desktopthemes/gnometheme.h b/app/src/desktopthemes/gnometheme.h
new file mode 100644
index 0000000000000000000000000000000000000000..c27e7fea22fa9e50733900cfd207bcfd3b763485
--- /dev/null
+++ b/app/src/desktopthemes/gnometheme.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <QObject>
+
+class GnomeTheme : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit GnomeTheme(const QString &path, QObject *parent = nullptr);
+
+    bool applyAsWallpaper() const;
+    bool applyAsIcon() const;
+    bool applyAsCursor() const;
+    bool applyAsGtk3Theme() const;
+    bool applyAsGnomeShellTheme() const;
+
+private:
+    bool setConfig(const QString &schema, const QString &key, const QString &value) const;
+
+    QString path_;
+    QString themeName_;
+};
diff --git a/app/src/desktopthemes/kdetheme.cpp b/app/src/desktopthemes/kdetheme.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..023fae9ae6d98ff68606215e4ad8bde210855fea
--- /dev/null
+++ b/app/src/desktopthemes/kdetheme.cpp
@@ -0,0 +1,119 @@
+#include "kdetheme.h"
+
+#include <QVariantList>
+#include <QTextStream>
+#include <QDir>
+#include <QProcess>
+#include <QDBusMessage>
+#include <QDBusConnection>
+#include <QDebug>
+
+KdeTheme::KdeTheme(const QString &path, QObject *parent)
+    : QObject(parent), path_(path)
+{
+    themeName_ = QDir(path_).dirName();
+}
+
+bool KdeTheme::applyAsWallpaper() const
+{
+    QString script;
+    QTextStream out(&script);
+    out << "for (var key in desktops()) {"
+        << "var d = desktops()[key];"
+        << "d.wallpaperPlugin = 'org.kde.image';"
+        << "d.currentConfigGroup = ['Wallpaper', 'org.kde.image', 'General'];"
+        << "d.writeConfig('Image', 'file://" + path_ + "');"
+        << "}";
+
+    return evaluateScript(script);
+}
+
+bool KdeTheme::applyAsIcon() const
+{
+    QString script;
+    QTextStream out(&script);
+    out << "var c = ConfigFile('kdeglobals');"
+        << "c.group = 'Icons';"
+        << "c.writeEntry('Theme', '" + themeName_ + "');";
+
+    if (evaluateScript(script)) {
+        auto iconChanged = QDBusMessage::createSignal("/KIconLoader", "org.kde.KIconLoader", "iconChanged");
+        iconChanged.setArguments(QVariantList() << QVariant(qint32(0)));
+        QDBusConnection::sessionBus().send(iconChanged);
+
+        auto notifyChange = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
+        notifyChange.setArguments(QVariantList() << QVariant(qint32(4)) << QVariant(qint32(0)));
+        QDBusConnection::sessionBus().send(notifyChange);
+
+        return true;
+    }
+    return false;
+}
+
+bool KdeTheme::applyAsCursor() const
+{
+    QString script;
+    QTextStream out(&script);
+    out << "var c = ConfigFile('kcminputrc');"
+        << "c.group = 'Mouse';"
+        << "c.writeEntry('cursorTheme', '" + themeName_ + "');";
+
+    if (evaluateScript(script)) {
+        auto setLaunchEnv = QDBusMessage::createMethodCall("org.kde.klauncher5", "/KLauncher", "org.kde.KLauncher", "setLaunchEnv");
+        setLaunchEnv.setArguments(QVariantList() << QVariant(QString("XCURSOR_THEME")) << QVariant(themeName_));
+        QDBusConnection::sessionBus().call(setLaunchEnv);
+
+        auto notifyChange = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
+        notifyChange.setArguments(QVariantList() << QVariant(qint32(5)) << QVariant(qint32(0)));
+        QDBusConnection::sessionBus().send(notifyChange);
+
+        return true;
+    }
+    return false;
+}
+
+bool KdeTheme::applyAsPlasma5Desktoptheme() const
+{
+    QString script;
+    QTextStream out(&script);
+    out << "var c = ConfigFile('plasmarc');"
+        << "c.group = 'Theme';"
+        << "c.writeEntry('name', '" + themeName_ + "');";
+
+    if (evaluateScript(script)) {
+        QProcess::startDetached("kquitapp5 plasmashell");
+        QProcess::startDetached("kstart5 plasmashell");
+        return true;
+    }
+    return false;
+}
+
+bool KdeTheme::applyAsAuroraeTheme() const
+{
+    QString script;
+    QTextStream out(&script);
+    out << "var c = ConfigFile('kwinrc');"
+        << "c.group = 'org.kde.kdecoration2';"
+        << "c.writeEntry('library', 'org.kde.kwin.aurorae');"
+        << "c.writeEntry('theme', '__aurorae__svg__" + themeName_ + "');";
+
+    if (evaluateScript(script)) {
+        auto reloadConfig = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
+        QDBusConnection::sessionBus().send(reloadConfig);
+        return true;
+    }
+    return false;
+}
+
+bool KdeTheme::evaluateScript(const QString &script) const
+{
+    auto message = QDBusMessage::createMethodCall("org.kde.plasmashell", "/PlasmaShell", "org.kde.PlasmaShell", "evaluateScript");
+    message.setArguments(QVariantList() << QVariant(script));
+    auto reply = QDBusConnection::sessionBus().call(message);
+
+    if (reply.type() == QDBusMessage::ErrorMessage) {
+        qWarning() << reply.errorMessage();
+        return false;
+    }
+    return true;
+}
diff --git a/app/src/desktopthemes/kdetheme.h b/app/src/desktopthemes/kdetheme.h
new file mode 100644
index 0000000000000000000000000000000000000000..b3f0e7cb53a9538fa69bae8c02ed0996c473c86b
--- /dev/null
+++ b/app/src/desktopthemes/kdetheme.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <QObject>
+
+class KdeTheme : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit KdeTheme(const QString &path, QObject *parent = nullptr);
+
+    bool applyAsWallpaper() const;
+    bool applyAsIcon() const;
+    bool applyAsCursor() const;
+    bool applyAsPlasma5Desktoptheme() const;
+    bool applyAsAuroraeTheme() const;
+
+private:
+    bool evaluateScript(const QString &script) const;
+
+    QString path_;
+    QString themeName_;
+};
diff --git a/app/src/desktopthemes/xfcetheme.cpp b/app/src/desktopthemes/xfcetheme.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..6937bd88c833cdc8c9c4a85686efb9016c98a4d2
--- /dev/null
+++ b/app/src/desktopthemes/xfcetheme.cpp
@@ -0,0 +1,53 @@
+#include "xfcetheme.h"
+
+#include <QVariantList>
+#include <QDir>
+#include <QProcess>
+#include <QDBusMessage>
+#include <QDBusConnection>
+#include <QDBusVariant>
+#include <QDebug>
+
+XfceTheme::XfceTheme(const QString &path, QObject *parent)
+    : QObject(parent), path_(path)
+{
+    themeName_ = QDir(path_).dirName();
+}
+
+bool XfceTheme::applyAsWallpaper() const
+{
+    return setConfig("xfce4-desktop", "/backdrop/screen0/monitor0/workspace0/last-image", path_);
+}
+
+bool XfceTheme::applyAsIcon() const
+{
+    return setConfig("xsettings", "/Net/IconThemeName", themeName_);
+}
+
+bool XfceTheme::applyAsCursor() const
+{
+    return setConfig("xsettings", "/Gtk/CursorThemeName", themeName_);
+}
+
+bool XfceTheme::applyAsGtk2Theme() const
+{
+    return setConfig("xsettings", "/Net/ThemeName", themeName_);
+}
+
+bool XfceTheme::applyAsXfwm4Theme() const
+{
+    return setConfig("xfwm4", "/general/theme", themeName_);
+}
+
+bool XfceTheme::setConfig(const QString &channel, const QString &property, const QString &value) const
+{
+    auto message = QDBusMessage::createMethodCall("org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "SetProperty");
+    message.setArguments(QVariantList() << QVariant(channel) << QVariant(property) << QVariant::fromValue(QDBusVariant(value)));
+    auto reply = QDBusConnection::sessionBus().call(message);
+
+    if (reply.type() == QDBusMessage::ErrorMessage) {
+        qWarning() << reply.errorMessage();
+        return false;
+    }
+    return true;
+}
diff --git a/app/src/desktopthemes/xfcetheme.h b/app/src/desktopthemes/xfcetheme.h
new file mode 100644
index 0000000000000000000000000000000000000000..4cb1a3e268ed229a34f5dde3035d2e56db93f356
--- /dev/null
+++ b/app/src/desktopthemes/xfcetheme.h
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <QObject>
+
+class XfceTheme : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit XfceTheme(const QString &path, QObject *parent = nullptr);
+
+    bool applyAsWallpaper() const;
+    bool applyAsIcon() const;
+    bool applyAsCursor() const;
+    bool applyAsGtk2Theme() const;
+    bool applyAsXfwm4Theme() const;
+
+private:
+    bool setConfig(const QString &channel, const QString &property, const QString &value) const;
+
+    QString path_;
+    QString themeName_;
+};
diff --git a/app/src/handlers/desktopthemehandler.cpp b/app/src/handlers/desktopthemehandler.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..923883c7b30801416ab45c0819ee4c7dc897d01b
--- /dev/null
+++ b/app/src/handlers/desktopthemehandler.cpp
@@ -0,0 +1,140 @@
+#include "desktopthemehandler.h"
+
+#include <QStringList>
+
+#ifdef QTLIB_UNIX
+#include <QFileInfo>
+
+#include "desktopthemes/kdetheme.h"
+#include "desktopthemes/gnometheme.h"
+#include "desktopthemes/xfcetheme.h"
+#endif
+
+DesktopThemeHandler::DesktopThemeHandler(QObject *parent)
+    : QObject(parent)
+{}
+
+QString DesktopThemeHandler::desktopEnvironment() const
+{
+    QString desktop;
+    QString currentDesktop;
+
+    if (!qgetenv("XDG_CURRENT_DESKTOP").isEmpty()) {
+        currentDesktop = QString::fromLocal8Bit(qgetenv("XDG_CURRENT_DESKTOP").constData()).toLower();
+    }
+    else if (!qgetenv("XDG_SESSION_DESKTOP").isEmpty()) {
+        currentDesktop = QString::fromLocal8Bit(qgetenv("XDG_SESSION_DESKTOP").constData()).toLower();
+    }
+    else if (!qgetenv("DESKTOP_SESSION").isEmpty()) {
+        currentDesktop = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION").constData()).toLower();
+    }
+
+    if (currentDesktop.contains("kde") || currentDesktop.contains("plasma")) {
+        desktop = "kde";
+    }
+    else if (currentDesktop.contains("gnome") || currentDesktop.contains("unity")) {
+        desktop = "gnome";
+    }
+    else if (currentDesktop.contains("xfce")) {
+        desktop = "xfce";
+    }
+
+    return desktop;
+}
+
+bool DesktopThemeHandler::isApplicableType(const QString &installType) const
+{
+    auto desktop = desktopEnvironment();
+
+    QStringList applicableTypes;
+
+    if (desktop == "kde") {
+        applicableTypes << "wallpapers"
+                        << "icons"
+                        << "cursors"
+                        << "plasma5_desktopthemes"
+                        << "aurorae_themes";
+    }
+    else if (desktop == "gnome") {
+        applicableTypes << "wallpapers"
+                        << "icons"
+                        << "cursors"
+                        << "gtk3_themes"
+                        << "gnome_shell_themes";
+    }
+    else if (desktop == "xfce") {
+        applicableTypes << "wallpapers"
+                        << "icons"
+                        << "cursors"
+                        << "gtk2_themes"
+                        << "xfwm4_themes";
+    }
+
+    return applicableTypes.contains(installType);
+}
+
+#ifdef QTLIB_UNIX
+bool DesktopThemeHandler::applyTheme(const QString &path, const QString &installType) const
+{
+    if (QFileInfo::exists(path) && isApplicableType(installType)) {
+        auto desktop = desktopEnvironment();
+
+        if (desktop == "kde") {
+            KdeTheme kdeTheme(path);
+            if (installType == "wallpapers") {
+                return kdeTheme.applyAsWallpaper();
+            }
+            else if (installType == "icons") {
+                return kdeTheme.applyAsIcon();
+            }
+            else if (installType == "cursors") {
+                return kdeTheme.applyAsCursor();
+            }
+            else if (installType == "plasma5_desktopthemes") {
+                return kdeTheme.applyAsPlasma5Desktoptheme();
+            }
+            else if (installType == "aurorae_themes") {
+                return kdeTheme.applyAsAuroraeTheme();
+            }
+        }
+        else if (desktop == "gnome") {
+            GnomeTheme gnomeTheme(path);
+            if (installType == "wallpapers") {
+                return gnomeTheme.applyAsWallpaper();
+            }
+            else if (installType == "icons") {
+                return gnomeTheme.applyAsIcon();
+            }
+            else if (installType == "cursors") {
+                return gnomeTheme.applyAsCursor();
+            }
+            else if (installType == "gtk3_themes") {
+                return gnomeTheme.applyAsGtk3Theme();
+            }
+            else if (installType == "gnome_shell_themes") {
+                return gnomeTheme.applyAsGnomeShellTheme();
+            }
+        }
+        else if (desktop == "xfce") {
+            XfceTheme xfceTheme(path);
+            if (installType == "wallpapers") {
+                return xfceTheme.applyAsWallpaper();
+            }
+            else if (installType == "icons") {
+                return xfceTheme.applyAsIcon();
+            }
+            else if (installType == "cursors") {
+                return xfceTheme.applyAsCursor();
+            }
+            else if (installType == "gtk2_themes") {
+                return xfceTheme.applyAsGtk2Theme();
+            }
+            else if (installType == "xfwm4_themes") {
+                return xfceTheme.applyAsXfwm4Theme();
+            }
+        }
+    }
+
+    return false;
+}
+#endif
diff --git a/app/src/handlers/desktopthemehandler.h b/app/src/handlers/desktopthemehandler.h
new file mode 100644
index 0000000000000000000000000000000000000000..9ba1f4a06416c033d02c02246df7d248cd446659
--- /dev/null
+++ b/app/src/handlers/desktopthemehandler.h
@@ -0,0 +1,19 @@
+#pragma once
+
+#include <QObject>
+
+class DesktopThemeHandler : public QObject
+{
+    Q_OBJECT
+
+public:
+    explicit DesktopThemeHandler(QObject *parent = nullptr);
+
+public slots:
+    QString desktopEnvironment() const;
+    bool isApplicableType(const QString &installType) const;
+
+#ifdef QTLIB_UNIX
+    bool applyTheme(const QString &path, const QString &installType) const;
+#endif
+};
diff --git a/app/src/handlers/systemhandler.cpp b/app/src/handlers/systemhandler.cpp
index 0042520afe58ce8ef1d97379cce2775fdc1d2b21..32cc9110eb2b45e227edd1d257b6296068b9ebef 100644
--- a/app/src/handlers/systemhandler.cpp
+++ b/app/src/handlers/systemhandler.cpp
@@ -6,10 +6,6 @@
 #ifdef QTLIB_UNIX
 #include <QFileInfo>
 #include <QProcess>
-#include <QDBusMessage>
-#include <QDBusConnection>
-#include <QDBusVariant>
-#include <QDebug>
 #endif
 
 #ifdef Q_OS_ANDROID
@@ -61,299 +57,3 @@ bool SystemHandler::openUrl(const QString &url) const
 
     return QDesktopServices::openUrl(QUrl(url));
 }
-
-QString SystemHandler::desktopEnvironment() const
-{
-    QString desktop;
-    QString currentDesktop;
-
-    if (!qgetenv("XDG_CURRENT_DESKTOP").isEmpty()) {
-        currentDesktop = QString::fromLocal8Bit(qgetenv("XDG_CURRENT_DESKTOP").constData()).toLower();
-    }
-    else if (!qgetenv("XDG_SESSION_DESKTOP").isEmpty()) {
-        currentDesktop = QString::fromLocal8Bit(qgetenv("XDG_SESSION_DESKTOP").constData()).toLower();
-    }
-    else if (!qgetenv("DESKTOP_SESSION").isEmpty()) {
-        currentDesktop = QString::fromLocal8Bit(qgetenv("DESKTOP_SESSION").constData()).toLower();
-    }
-
-    if (currentDesktop.contains("kde") || currentDesktop.contains("plasma")) {
-        desktop = "kde";
-    }
-    else if (currentDesktop.contains("gnome") || currentDesktop.contains("unity")) {
-        desktop = "gnome";
-    }
-    else if (currentDesktop.contains("xfce")) {
-        desktop = "xfce";
-    }
-    return desktop;
-}
-
-bool SystemHandler::isApplicableType(const QString &installType) const
-{
-    auto desktop = desktopEnvironment();
-
-    QStringList applicableTypes;
-
-    if (desktop == "kde") {
-        applicableTypes << "wallpapers"
-                        << "icons"
-                        << "cursors"
-                        << "plasma5_desktopthemes"
-                        << "aurorae_themes";
-    }
-    else if (desktop == "gnome") {
-        applicableTypes << "wallpapers"
-                        << "icons"
-                        << "cursors"
-                        << "gtk3_themes"
-                        << "gnome_shell_themes";
-    }
-    else if (desktop == "xfce") {
-        applicableTypes << "wallpapers"
-                        << "icons"
-                        << "cursors"
-                        << "gtk2_themes"
-                        << "xfwm4_themes";
-    }
-
-    return applicableTypes.contains(installType);
-}
-
-#ifdef QTLIB_UNIX
-bool SystemHandler::applyFile(const QString &path, const QString &installType) const
-{
-    if (QFileInfo::exists(path) && isApplicableType(installType)) {
-        auto desktop = desktopEnvironment();
-        auto themeName = QFileInfo(path).fileName();
-
-        if (desktop == "kde") {
-            if (installType == "wallpapers") {
-                return applyKdeWallpaper(path);
-            }
-            else if (installType == "icons") {
-                return applyKdeIcon(themeName);
-            }
-            else if (installType == "cursors") {
-                return applyKdeCursor(themeName);
-            }
-            else if (installType == "plasma5_desktopthemes") {
-                return applyKdePlasmaDesktoptheme(themeName);
-            }
-            else if (installType == "aurorae_themes") {
-                return applyKdeAuroraeTheme(themeName);
-            }
-        }
-        else if (desktop == "gnome") {
-            if (installType == "wallpapers") {
-                return applyGnomeWallpaper(path);
-            }
-            else if (installType == "icons") {
-                return applyGnomeIcon(themeName);
-            }
-            else if (installType == "cursors") {
-                return applyGnomeCursor(themeName);
-            }
-            else if (installType == "gtk3_themes") {
-                return applyGnomeGtk3Theme(themeName);
-            }
-            else if (installType == "gnome_shell_themes") {
-                return applyGnomeGnomeShellTheme(themeName);
-            }
-        }
-        else if (desktop == "xfce") {
-            if (installType == "wallpapers") {
-                return applyXfceWallpaper(path);
-            }
-            else if (installType == "icons") {
-                return applyXfceIcon(themeName);
-            }
-            else if (installType == "cursors") {
-                return applyXfceCursor(themeName);
-            }
-            else if (installType == "gtk2_themes") {
-                return applyXfceGtk2Theme(themeName);
-            }
-            else if (installType == "xfwm4_themes") {
-                return applyXfceXfwm4Theme(themeName);
-            }
-        }
-    }
-
-    return false;
-}
-#endif
-
-#ifdef QTLIB_UNIX
-bool SystemHandler::setConfigWithPlasmaShell(const QString &script) const
-{
-    auto message = QDBusMessage::createMethodCall("org.kde.plasmashell", "/PlasmaShell", "org.kde.PlasmaShell", "evaluateScript");
-    message.setArguments(QVariantList() << QVariant(script));
-    auto reply = QDBusConnection::sessionBus().call(message);
-
-    if (reply.type() == QDBusMessage::ErrorMessage) {
-        qWarning() << reply.errorMessage();
-        return false;
-    }
-    return true;
-}
-
-bool SystemHandler::applyKdeWallpaper(const QString &path) const
-{
-    QString script;
-    QTextStream out(&script);
-    out << "for (var key in desktops()) {"
-        << "var d = desktops()[key];"
-        << "d.wallpaperPlugin = 'org.kde.image';"
-        << "d.currentConfigGroup = ['Wallpaper', 'org.kde.image', 'General'];"
-        << "d.writeConfig('Image', 'file://" + path + "');"
-        << "}";
-
-    return setConfigWithPlasmaShell(script);
-}
-
-bool SystemHandler::applyKdeIcon(const QString &themeName) const
-{
-    QString script;
-    QTextStream out(&script);
-    out << "var c = ConfigFile('kdeglobals');"
-        << "c.group = 'Icons';"
-        << "c.writeEntry('Theme', '" + themeName + "');";
-
-    if (setConfigWithPlasmaShell(script)) {
-        auto iconChanged = QDBusMessage::createSignal("/KIconLoader", "org.kde.KIconLoader", "iconChanged");
-        iconChanged.setArguments(QVariantList() << QVariant(qint32(0)));
-        QDBusConnection::sessionBus().send(iconChanged);
-
-        auto notifyChange = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
-        notifyChange.setArguments(QVariantList() << QVariant(qint32(4)) << QVariant(qint32(0)));
-        QDBusConnection::sessionBus().send(notifyChange);
-
-        return true;
-    }
-    return false;
-}
-
-bool SystemHandler::applyKdeCursor(const QString &themeName) const
-{
-    QString script;
-    QTextStream out(&script);
-    out << "var c = ConfigFile('kcminputrc');"
-        << "c.group = 'Mouse';"
-        << "c.writeEntry('cursorTheme', '" + themeName + "');";
-
-    if (setConfigWithPlasmaShell(script)) {
-        auto setLaunchEnv = QDBusMessage::createMethodCall("org.kde.klauncher5", "/KLauncher", "org.kde.KLauncher", "setLaunchEnv");
-        setLaunchEnv.setArguments(QVariantList() << QVariant(QString("XCURSOR_THEME")) << QVariant(themeName));
-        QDBusConnection::sessionBus().call(setLaunchEnv);
-
-        auto notifyChange = QDBusMessage::createSignal("/KGlobalSettings", "org.kde.KGlobalSettings", "notifyChange");
-        notifyChange.setArguments(QVariantList() << QVariant(qint32(5)) << QVariant(qint32(0)));
-        QDBusConnection::sessionBus().send(notifyChange);
-
-        return true;
-    }
-    return false;
-}
-
-bool SystemHandler::applyKdePlasmaDesktoptheme(const QString &themeName) const
-{
-    QString script;
-    QTextStream out(&script);
-    out << "var c = ConfigFile('plasmarc');"
-        << "c.group = 'Theme';"
-        << "c.writeEntry('name', '" + themeName + "');";
-
-    if (setConfigWithPlasmaShell(script)) {
-        QProcess::startDetached("kquitapp5 plasmashell");
-        QProcess::startDetached("kstart5 plasmashell");
-        return true;
-    }
-    return false;
-}
-
-bool SystemHandler::applyKdeAuroraeTheme(const QString &themeName) const
-{
-    QString script;
-    QTextStream out(&script);
-    out << "var c = ConfigFile('kwinrc');"
-        << "c.group = 'org.kde.kdecoration2';"
-        << "c.writeEntry('library', 'org.kde.kwin.aurorae');"
-        << "c.writeEntry('theme', '__aurorae__svg__" + themeName + "');";
-
-    if (setConfigWithPlasmaShell(script)) {
-        auto reloadConfig = QDBusMessage::createSignal("/KWin", "org.kde.KWin", "reloadConfig");
-        QDBusConnection::sessionBus().send(reloadConfig);
-        return true;
-    }
-    return false;
-}
-
-bool SystemHandler::setConfigWithGsettings(const QString &schema, const QString &key, const QString &value) const
-{
-    return QProcess::startDetached("gsettings", QStringList() << "set" << schema << key << value);
-}
-
-bool SystemHandler::applyGnomeWallpaper(const QString &path) const
-{
-    return setConfigWithGsettings("org.gnome.desktop.background", "picture-uri", "file://" + path);
-}
-
-bool SystemHandler::applyGnomeIcon(const QString &themeName) const
-{
-    return setConfigWithGsettings("org.gnome.desktop.interface", "icon-theme", themeName);
-}
-
-bool SystemHandler::applyGnomeCursor(const QString &themeName) const
-{
-    return setConfigWithGsettings("org.gnome.desktop.interface", "cursor-theme", themeName);
-}
-
-bool SystemHandler::applyGnomeGtk3Theme(const QString &themeName) const
-{
-    return setConfigWithGsettings("org.gnome.desktop.interface", "gtk-theme", themeName);
-}
-
-bool SystemHandler::applyGnomeGnomeShellTheme(const QString &themeName) const
-{
-    return setConfigWithGsettings("org.gnome.shell.extensions.user-theme", "name", themeName);
-}
-
-bool SystemHandler::setConfigWithXfconf(const QString &channel, const QString &property, const QString &value) const
-{
-    auto message = QDBusMessage::createMethodCall("org.xfce.Xfconf", "/org/xfce/Xfconf", "org.xfce.Xfconf", "SetProperty");
-    message.setArguments(QVariantList() << QVariant(channel) << QVariant(property) << QVariant::fromValue(QDBusVariant(value)));
-    auto reply = QDBusConnection::sessionBus().call(message);
-
-    if (reply.type() == QDBusMessage::ErrorMessage) {
-        qWarning() << reply.errorMessage();
-        return false;
-    }
-    return true;
-}
-
-bool SystemHandler::applyXfceWallpaper(const QString &path) const
-{
-    return setConfigWithXfconf("xfce4-desktop", "/backdrop/screen0/monitor0/workspace0/last-image", path);
-}
-
-bool SystemHandler::applyXfceIcon(const QString &themeName) const
-{
-    return setConfigWithXfconf("xsettings", "/Net/IconThemeName", themeName);
-}
-
-bool SystemHandler::applyXfceCursor(const QString &themeName) const
-{
-    return setConfigWithXfconf("xsettings", "/Gtk/CursorThemeName", themeName);
-}
-
-bool SystemHandler::applyXfceGtk2Theme(const QString &themeName) const
-{
-    return setConfigWithXfconf("xsettings", "/Net/ThemeName", themeName);
-}
-
-bool SystemHandler::applyXfceXfwm4Theme(const QString &themeName) const
-{
-    return setConfigWithXfconf("xfwm4", "/general/theme", themeName);
-}
-#endif
diff --git a/app/src/handlers/systemhandler.h b/app/src/handlers/systemhandler.h
index 8a346191ae947cd31c3533d7ebf1e9af01e5c1e5..ab7118369b8b0001e5be16d934140b727ec75efd 100644
--- a/app/src/handlers/systemhandler.h
+++ b/app/src/handlers/systemhandler.h
@@ -13,35 +13,4 @@ public slots:
     bool isUnix() const;
     bool isMobileDevice() const;
     bool openUrl(const QString &url) const;
-
-    QString desktopEnvironment() const;
-    bool isApplicableType(const QString &installType) const;
-
-#ifdef QTLIB_UNIX
-    bool applyFile(const QString &path, const QString &installType) const;
-#endif
-
-private:
-#ifdef QTLIB_UNIX
-    bool setConfigWithPlasmaShell(const QString &script) const;
-    bool applyKdeWallpaper(const QString &path) const;
-    bool applyKdeIcon(const QString &themeName) const;
-    bool applyKdeCursor(const QString &themeName) const;
-    bool applyKdePlasmaDesktoptheme(const QString &themeName) const;
-    bool applyKdeAuroraeTheme(const QString &themeName) const;
-
-    bool setConfigWithGsettings(const QString &schema, const QString &key, const QString &value) const;
-    bool applyGnomeWallpaper(const QString &path) const;
-    bool applyGnomeIcon(const QString &themeName) const;
-    bool applyGnomeCursor(const QString &themeName) const;
-    bool applyGnomeGtk3Theme(const QString &themeName) const;
-    bool applyGnomeGnomeShellTheme(const QString &themeName) const;
-
-    bool setConfigWithXfconf(const QString &channel, const QString &property, const QString &value) const;
-    bool applyXfceWallpaper(const QString &path) const;
-    bool applyXfceIcon(const QString &themeName) const;
-    bool applyXfceCursor(const QString &themeName) const;
-    bool applyXfceGtk2Theme(const QString &themeName) const;
-    bool applyXfceXfwm4Theme(const QString &themeName) const;
-#endif
 };
diff --git a/app/src/main.cpp b/app/src/main.cpp
index 36827d1bdac104a676a7fbe926e4387c01158fc2..002530d3164fb42721084bcf25538a25e655a876 100644
--- a/app/src/main.cpp
+++ b/app/src/main.cpp
@@ -46,7 +46,7 @@ int main(int argc, char *argv[])
 
     // Setup websocket server
     auto *wsServer = new WebSocketServer(configHandler, appConfigApplication["id"].toString(), port, &app);
-    QObject::connect(wsServer, &WebSocketServer::stopped, &app, &QCoreApplication::quit);
+    QObject::connect(wsServer, &WebSocketServer::stopped, &app, &QGuiApplication::quit);
 
     if (wsServer->start()) {
         qDebug() << "Websocket server started at:" << wsServer->serverUrl().toString();
diff --git a/app/src/websockets/websocketserver.cpp b/app/src/websockets/websocketserver.cpp
index 59f8f78005f3951dc477efeb2c1ab091ed7fd18f..45c4b60b1f3e1ee1601144e2d23d36336839f5fa 100644
--- a/app/src/websockets/websocketserver.cpp
+++ b/app/src/websockets/websocketserver.cpp
@@ -8,6 +8,7 @@
 
 #include "handlers/confighandler.h"
 #include "handlers/systemhandler.h"
+#include "handlers/desktopthemehandler.h"
 #include "handlers/ocsapihandler.h"
 #include "handlers/itemhandler.h"
 
@@ -21,6 +22,7 @@ WebSocketServer::WebSocketServer(ConfigHandler *configHandler, const QString &se
 
     configHandler_->setParent(this);
     systemHandler_ = new SystemHandler(this);
+    desktopThemeHandler_ = new DesktopThemeHandler(this);
     ocsApiHandler_ = new OcsApiHandler(configHandler_, this);
     itemHandler_ = new ItemHandler(configHandler_, this);
 
@@ -276,15 +278,16 @@ void WebSocketServer::receiveMessage(const QString &id, const QString &func, con
     else if (func == "SystemHandler::openUrl") {
         resultData.append(systemHandler_->openUrl(data.at(0).toString()));
     }
-    else if (func == "SystemHandler::desktopEnvironment") {
-        resultData.append(systemHandler_->desktopEnvironment());
+    // DesktopThemeHandler
+    else if (func == "DesktopThemeHandler::desktopEnvironment") {
+        resultData.append(desktopThemeHandler_->desktopEnvironment());
     }
-    else if (func == "SystemHandler::isApplicableType") {
-        resultData.append(systemHandler_->isApplicableType(data.at(0).toString()));
+    else if (func == "DesktopThemeHandler::isApplicableType") {
+        resultData.append(desktopThemeHandler_->isApplicableType(data.at(0).toString()));
     }
-    else if (func == "SystemHandler::applyFile") {
+    else if (func == "DesktopThemeHandler::applyTheme") {
 #ifdef QTLIB_UNIX
-        resultData.append(systemHandler_->applyFile(data.at(0).toString(), data.at(1).toString()));
+        resultData.append(desktopThemeHandler_->applyTheme(data.at(0).toString(), data.at(1).toString()));
 #else
         resultData.append(false);
 #endif
diff --git a/app/src/websockets/websocketserver.h b/app/src/websockets/websocketserver.h
index cfd2bcacb99a42610e5c12f363e680dbedf0f723..66edab50cecefde77a54e4d3da791fd7b814c31e 100644
--- a/app/src/websockets/websocketserver.h
+++ b/app/src/websockets/websocketserver.h
@@ -10,6 +10,7 @@ class QWebSocket;
 
 class ConfigHandler;
 class SystemHandler;
+class DesktopThemeHandler;
 class OcsApiHandler;
 class ItemHandler;
 
@@ -55,6 +56,7 @@ private:
 
     ConfigHandler *configHandler_;
     SystemHandler *systemHandler_;
+    DesktopThemeHandler *desktopThemeHandler_;
     OcsApiHandler *ocsApiHandler_;
     ItemHandler *itemHandler_;