diff --git a/src/UI/Theme/Theme.cc b/src/UI/Theme/Theme.cc
index ef144f86e833f69cfd721255eaaf42e5c5cb1e96..60d5a103b79b7e8b1d60b5e9a099911dd5fd6848 100644
--- a/src/UI/Theme/Theme.cc
+++ b/src/UI/Theme/Theme.cc
@@ -7,7 +7,65 @@
 
 namespace Vivy
 {
-Theme::ThemePrivate::ThemePrivate() noexcept
+struct Theme::Private {
+    Private() noexcept;
+
+    Theme::Type classType{ Theme::Type::System };
+    Theme::VivyTheme preferedColor{ Theme::VivyTheme::Dark };
+
+    QString id;
+    QString fileName;
+    QString displayName;
+    QStringList preferredStyles;
+    QString defaultTextEditorColorScheme;
+    QVector<QPair<QColor, QString>> colors;
+    QVector<QString> imageFiles;
+    QVector<QGradientStops> gradients;
+    QVector<bool> flags;
+    QMap<QString, QColor> palette;
+};
+
+// If you copy QPalette, default values stay at default, even if that default is different
+// within the context of different widgets. Create deep copy.
+static QPalette
+copyPalette(const QPalette &p) noexcept
+{
+    QPalette res;
+    for (int group = 0; group < QPalette::NColorGroups; ++group) {
+        for (int role = 0; role < QPalette::NColorRoles; ++role) {
+            res.setBrush(QPalette::ColorGroup(group), QPalette::ColorRole(role),
+                         p.brush(QPalette::ColorGroup(group), QPalette::ColorRole(role)));
+        }
+    }
+    return res;
+}
+
+[[maybe_unused]] static bool
+systemUsesDarkMode() noexcept
+{
+    if (Utils::HostOsInfo::isWindowsHost()) {
+        constexpr char regkey[] =
+            "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
+        bool ok;
+        const auto setting =
+            QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok);
+        return ok && setting == 0;
+    } else if (Utils::HostOsInfo::isMacHost()) {
+        return false;
+    } else if (Utils::HostOsInfo::isLinuxHost()) {
+        return true;
+    }
+    return false;
+}
+
+static QPalette
+initialPalette() noexcept
+{
+    static QPalette palette = copyPalette(QApplication::palette());
+    return palette;
+}
+
+Theme::Private::Private() noexcept
 {
     const QMetaObject &m = Theme::staticMetaObject;
     colors.resize(m.enumerator(m.indexOfEnumerator("Color")).keyCount());
@@ -43,7 +101,7 @@ Theme::applyToApplication() const noexcept
 
 Theme::Theme(const QString &id, QObject *parent) noexcept
     : QObject(parent)
-    , d(new ThemePrivate)
+    , d(new Private)
 {
     d->id = id;
 }
@@ -133,6 +191,7 @@ Theme::fromQssFile(const QString &id, const QString &file) noexcept
     Theme *ret        = new Theme(id);
     ret->d->fileName  = file;
     ret->d->classType = Type::QssFile;
+    ret->setDisplayName(QFileInfo(file).baseName());
     return ret;
 }
 
@@ -147,9 +206,11 @@ Theme::fromSettings(const QString &id, QSettings *const settings) noexcept
 Theme *
 Theme::fromVivyTheme(const QString &id, const VivyTheme which) noexcept
 {
-    return fromQssFile(id, which == VivyTheme::Dark
-                               ? QStringLiteral(":qdarkstyle/dark/style.qss")
-                               : QStringLiteral(":qdarkstyle/light/style.qss"));
+    Theme *ret =
+        fromQssFile(id, which == VivyTheme::Dark ? QStringLiteral(":qdarkstyle/dark/style.qss")
+                                                 : QStringLiteral(":qdarkstyle/light/style.qss"));
+    ret->setDisplayName(QStringLiteral("Vivy Theme"));
+    return ret;
 }
 
 const Theme::HighlightingTheme &
@@ -236,46 +297,6 @@ Theme::readSettings(QSettings *const settings) noexcept
     }
 }
 
-bool
-Theme::systemUsesDarkMode() noexcept
-{
-    if (Utils::HostOsInfo::isWindowsHost()) {
-        constexpr char regkey[] =
-            "HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
-        bool ok;
-        const auto setting =
-            QSettings(regkey, QSettings::NativeFormat).value("AppsUseLightTheme").toInt(&ok);
-        return ok && setting == 0;
-    } else if (Utils::HostOsInfo::isMacHost()) {
-        return false;
-    } else if (Utils::HostOsInfo::isLinuxHost()) {
-        return true;
-    }
-    return false;
-}
-
-// If you copy QPalette, default values stay at default, even if that default is different
-// within the context of different widgets. Create deep copy.
-static QPalette
-copyPalette(const QPalette &p) noexcept
-{
-    QPalette res;
-    for (int group = 0; group < QPalette::NColorGroups; ++group) {
-        for (int role = 0; role < QPalette::NColorRoles; ++role) {
-            res.setBrush(QPalette::ColorGroup(group), QPalette::ColorRole(role),
-                         p.brush(QPalette::ColorGroup(group), QPalette::ColorRole(role)));
-        }
-    }
-    return res;
-}
-
-QPalette
-Theme::initialPalette() noexcept
-{
-    static QPalette palette = copyPalette(QApplication::palette());
-    return palette;
-}
-
 QPalette
 Theme::palette() const noexcept
 {
diff --git a/src/UI/Theme/Theme.hh b/src/UI/Theme/Theme.hh
index 887b87f98a943f7a40137177301eb3c8e8ad0d5b..d2adc518e0498e09423311741856ab5aff30baad 100644
--- a/src/UI/Theme/Theme.hh
+++ b/src/UI/Theme/Theme.hh
@@ -6,7 +6,7 @@
 
 namespace Vivy
 {
-class ThemePrivate;
+class Private;
 class Theme;
 
 class Theme final : public QObject {
@@ -26,26 +26,9 @@ public:
     };
 
 private:
-    struct ThemePrivate final {
-        ThemePrivate() noexcept;
-
-        Theme::Type classType{ Theme::Type::System };
-        Theme::VivyTheme preferedColor{ Theme::VivyTheme::Dark };
-
-        QString id;
-        QString fileName;
-        QString displayName;
-        QStringList preferredStyles;
-        QString defaultTextEditorColorScheme;
-        QVector<QPair<QColor, QString>> colors;
-        QVector<QString> imageFiles;
-        QVector<QGradientStops> gradients;
-        QVector<bool> flags;
-        QMap<QString, QColor> palette;
-    };
+    struct Private;
 
     Theme(const QString &id, QObject *parent = nullptr) noexcept;
-
     void readSettings(QSettings *const settings) noexcept;
 
 public:
@@ -490,12 +473,9 @@ public:
     QString displayName() const noexcept;
     void setDisplayName(const QString &displayName) noexcept;
 
-    static bool systemUsesDarkMode() noexcept;
-    static QPalette initialPalette() noexcept;
-
 private:
     QPair<QColor, QString> readNamedColor(const QString &color) const;
-    ThemePrivate *d;
+    Private *const d;
 
     const Theme::HighlightingTheme darkHighlightingTheme = {
         .functionForeground = Qt::darkCyan,