diff --git a/src/mumble/MainWindow.cpp b/src/mumble/MainWindow.cpp index b53c1adce95..f66196dd3ac 100644 --- a/src/mumble/MainWindow.cpp +++ b/src/mumble/MainWindow.cpp @@ -209,77 +209,6 @@ MainWindow::MainWindow(QWidget *p) QAccessible::installFactory(AccessibleSlider::semanticSliderFactory); - applyTheme(); -} - -void MainWindow::applyTheme() { - boost::optional< ThemeInfo::StyleInfo > configuredStyle = Themes::getConfiguredStyle(Global::get().s); - - QString lightThemePath = ":/themes/Default/Lite.qss"; // Default light theme path - QString darkThemePath = ":/themes/Default/Dark.qss"; // Default dark theme path - - if (configuredStyle) { - if (configuredStyle->name == "Auto") { -#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) - auto colorScheme = QGuiApplication::styleHints()->colorScheme(); - - if (colorScheme == Qt::ColorScheme::Dark) { - setStyleSheet(loadStyleSheet(darkThemePath)); // Apply dark theme - } else { - setStyleSheet(loadStyleSheet(lightThemePath)); // Apply light theme - } -#else - bool isDarkTheme = detectSystemTheme(); - if (isDarkTheme) { - setStyleSheet(loadStyleSheet(darkThemePath)); // Apply dark theme - } else { - setStyleSheet(loadStyleSheet(lightThemePath)); // Apply light theme - } -#endif - } else if (configuredStyle->themeName == "none") { - setStyleSheet(""); // Clear the stylesheet if "None" is selected - } else { - QString themePath = - QString(":/themes/%1/%2.qss").arg(configuredStyle->themeName).arg(configuredStyle->name); - setStyleSheet(loadStyleSheet(themePath)); // Apply the selected theme and style - } - } else { - // Handle the case where no theme is configured (fallback to default behavior) - setStyleSheet(loadStyleSheet(lightThemePath)); // Default to light theme - } -} - -bool MainWindow::detectSystemTheme() { -#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) - return false; // This should not be called for Qt 6.5 and above -#else -// Custom method to detect dark theme for Qt 6.2 and below -# ifdef Q_OS_WIN - QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", - QSettings::NativeFormat); - return settings.value("AppsUseLightTheme", 1).toInt() == 0; // 0 means dark mode -# else - // Fallback for other OSes - QByteArray platform = qgetenv("QT_QPA_PLATFORM"); - if (platform.contains("darkmode=2")) { - return true; - } else if (platform.contains("darkmode=1")) { - QPalette defaultPalette; - return defaultPalette.color(QPalette::WindowText).lightness() - > defaultPalette.color(QPalette::Window).lightness(); - } - return false; -# endif -#endif -} - -QString MainWindow::loadStyleSheet(const QString &path) { - QFile file(path); - if (file.open(QFile::ReadOnly | QFile::Text)) { - QTextStream stream(&file); - return stream.readAll(); // Return the stylesheet content - } - return QString(); // Return empty if the file cannot be loaded } void MainWindow::createActions() { @@ -839,7 +768,7 @@ void MainWindow::changeEvent(QEvent *e) { } #endif if (e->type() == QEvent::ThemeChange) { - applyTheme(); + Themes::apply(); } } diff --git a/src/mumble/MainWindow.h b/src/mumble/MainWindow.h index 0e3bed2b1a5..30b9094da9b 100644 --- a/src/mumble/MainWindow.h +++ b/src/mumble/MainWindow.h @@ -220,9 +220,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindow { ContextMenuTarget getContextMenuTargets(); void autocompleteUsername(); - void applyTheme(); - bool detectSystemTheme(); - QString loadStyleSheet(const QString &path); public slots: void on_qmServer_aboutToShow(); diff --git a/src/mumble/Themes.cpp b/src/mumble/Themes.cpp index 4b1a121c44d..9512b1fe83b 100644 --- a/src/mumble/Themes.cpp +++ b/src/mumble/Themes.cpp @@ -8,6 +8,14 @@ #include "MumbleApplication.h" #include "Global.h" +#include +#include +#include +#include +#include +#include + + boost::optional< ThemeInfo::StyleInfo > Themes::getConfiguredStyle(const Settings &settings) { if (settings.themeName.isEmpty() && settings.themeStyleName.isEmpty()) { return boost::none; @@ -55,25 +63,59 @@ void Themes::applyFallback() { } bool Themes::applyConfigured() { + static QString currentThemePath; + + boost::optional< ThemeInfo::StyleInfo > style = Themes::getConfiguredStyle(Global::get().s); if (!style) { return false; } - const QFileInfo qssFile(style->getPlatformQss()); + QString themePath; + if (style->themeName == "Auto" || style->name == "Auto") { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + auto colorScheme = QGuiApplication::styleHints()->colorScheme(); + if (colorScheme == Qt::ColorScheme::Dark) { + themePath = ":/themes/Default/Dark.qss"; + } else { + themePath = ":/themes/Default/Lite.qss"; + } +#else + bool isDarkTheme = detectSystemTheme(); + if (isDarkTheme) { + themePath = ":/themes/Default/Dark.qss"; + } else { + themePath = ":/themes/Default/Lite.qss"; + } +#endif + } else { + if (style->name == "Dark") { + themePath = ":/themes/Default/Dark.qss"; + } else { + themePath = ":/themes/Default/Lite.qss"; + } + } + + // Early exit if the theme path is the same as the current one + if (themePath == currentThemePath) { + qWarning() << "Themes::applyConfigured(): Skipping redundant theme application for path:" << themePath; + return true; + } + + currentThemePath = themePath; // Update the current theme path qWarning() << "Theme:" << style->themeName; qWarning() << "Style:" << style->name; - qWarning() << "--> qss:" << qssFile.absoluteFilePath(); + qWarning() << "--> qss:" << themePath; - QFile file(qssFile.absoluteFilePath()); + QFile file(themePath); if (!file.open(QFile::ReadOnly)) { qWarning() << "Failed to open theme stylesheet:" << file.errorString(); return false; } QStringList skinPaths; - skinPaths << qssFile.path(); + skinPaths << QFileInfo(themePath).path(); skinPaths << QLatin1String(":/themes/Default"); // Some skins might want to fall-back on our built-in resources QString themeQss = QString::fromUtf8(file.readAll()); @@ -105,6 +147,30 @@ bool Themes::apply() { return result; } +bool Themes::detectSystemTheme() { +#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0) + return false; // This should not be called for Qt 6.5 and above +#else +// Custom method to detect dark theme for Qt 6.2 and below +# ifdef Q_OS_WIN + QSettings settings("HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize", + QSettings::NativeFormat); + return settings.value("AppsUseLightTheme", 1).toInt() == 0; // 0 means dark mode +# else + // Fallback for other OSes + QByteArray platform = qgetenv("QT_QPA_PLATFORM"); + if (platform.contains("darkmode=2")) { + return true; + } else if (platform.contains("darkmode=1")) { + QPalette defaultPalette; + return defaultPalette.color(QPalette::WindowText).lightness() + > defaultPalette.color(QPalette::Window).lightness(); + } + return false; +# endif +#endif +} + ThemeMap Themes::getThemes() { return ThemeInfo::scanDirectories(getSearchDirectories()); } diff --git a/src/mumble/Themes.h b/src/mumble/Themes.h index 000fd09b57c..6aa0dffceae 100644 --- a/src/mumble/Themes.h +++ b/src/mumble/Themes.h @@ -31,6 +31,9 @@ class Themes { /// @note Can only apply a theme before MainWindow etc. is opened static bool apply(); + /// Detects current OS theme + static bool detectSystemTheme(); + /// Return a theme name to theme map static ThemeMap getThemes();