Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

FEAT(client): Automatically sync theme with OS color scheme #6619

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/mumble/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -756,6 +756,9 @@ void MainWindow::changeEvent(QEvent *e) {
QTimer::singleShot(0, this, SLOT(hide()));
}
#endif
if (e->type() == QEvent::ThemeChange) {
Hartmnt marked this conversation as resolved.
Show resolved Hide resolved
Themes::apply();
}
}

void MainWindow::keyPressEvent(QKeyEvent *e) {
Expand Down
59 changes: 55 additions & 4 deletions src/mumble/Themes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,14 @@
#include "MumbleApplication.h"
#include "Global.h"

#include <QFile>
#include <QGuiApplication>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also double check (at least when we are done here), if all of those includes are actually needed.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think only these includes are needed "QPalette, QSettings, QStyleHints", but not 100% sure.

#include <QPalette>
#include <QSettings>
#include <QStyleHints>

QString Themes::currentThemePath;

boost::optional< ThemeInfo::StyleInfo > Themes::getConfiguredStyle(const Settings &settings) {
if (settings.themeName.isEmpty() && settings.themeStyleName.isEmpty()) {
return boost::none;
Expand Down Expand Up @@ -55,25 +63,45 @@ void Themes::applyFallback() {
}

bool Themes::applyConfigured() {


boost::optional< ThemeInfo::StyleInfo > style = Themes::getConfiguredStyle(Global::get().s);
if (!style) {
return false;
}

const QFileInfo qssFile(style->getPlatformQss());
QString themePath = style->getPlatformQss().absoluteFilePath();
if (style->themeName == "Auto" || style->name == "Auto") {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Idea: If you move this to Themes::getConfiguredStyle, you will have access to the user setting strings. If you do this check with something like settings.themeName == "Auto", you could probably simply add the "Auto" to the ComboBox (further investigation required)

This would have the additional benefit of not having to hard-code the path, but rather - in the case of "Auto" - just selecting the appropriate ThemeMap with the name "Dark" or "Lite".

But if you run into any issues with this approach, be sure to let me know.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I tried that today, to no avail. I don't know if I implemented it wrong, in the wrong section, or it's something else. Furthermore, I have other tasks related to this git, but those only need to stay on my local machine, as well as other tasks from other subjects, so I don't know when I will be able to look at this specific issue again.


bool isDarkTheme = detectSystemTheme();
Hartmnt marked this conversation as resolved.
Show resolved Hide resolved
if (isDarkTheme) {
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());
Expand Down Expand Up @@ -105,6 +133,29 @@ bool Themes::apply() {
return result;
}

bool Themes::detectSystemTheme() {
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
return QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark;
#else
# 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());
}
Expand Down
6 changes: 6 additions & 0 deletions src/mumble/Themes.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand Down Expand Up @@ -63,6 +66,9 @@ class Themes {
/// If a the file is is available, the function returns true.
/// If no file is available, it returns false.
static bool readStylesheet(const QString &stylesheetFn, QString &stylesheetContent);

/// Member variable to store the current theme path
static QString currentThemePath;
};

#endif // MUMBLE_MUMBLE_THEMES_H_
6 changes: 5 additions & 1 deletion themes/Default/theme.ini
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[theme]
name=Mumble
styles=dark,lite
styles=dark,lite,auto
[dark]
name=Dark
qss=Dark.qss
Expand All @@ -9,3 +9,7 @@ qss_MAC=OSX Dark.qss
name=Lite
qss=Lite.qss
qss_MAC=OSX Lite.qss
[auto]
name=Auto
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess you added this "theme" as a placeholder dummy, right? Take a look at this:

qcbTheme->clear();
qcbTheme->addItem(tr("None"));

There we add the "None" theme. We could just as easily add the "Auto" theme there, so we do not need to have a dummy theme in theme.ini

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originily i tried to add the option with "qcbTheme->addItem(tr("Auto"));" , but it didnt work right as i think it didnt save/load properly. I tried to fix it by changing LookConfig::reloadThemes ,LookConfig::load and LookConfig::save, but to no avail. So I had to resort to doing with putting fake theme in theme.ini .

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You are right just adding qcbTheme->addItem(tr("Auto")); does not seem to be enough. However, from a maintainability point of view and general structure of this sort of this, I would insist that we solve this programmatically. I think that means modification to Themes::getConfiguredStyle and possibly a custom ThemeMap object.

(Please note that I do not have the time currently to properly 100% think this through, so that's also why I am very glad that someone else is taking this feature request 😅)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should figure this out programmatically. If you are stuck here, let us know what is failing and we can figure out a way together.

qss=Lite.qss
qss_MAC=OSX Lite.qss
Loading