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 2 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
85 changes: 85 additions & 0 deletions src/mumble/MainWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@
# include <dbt.h>
#endif


#include <QFile>
#include <QGuiApplication>
#include <QPalette>
#include <QSettings>
#include <QStyleHints>
#include <QTextStream>



#include <algorithm>

MessageBoxEvent::MessageBoxEvent(QString m) : QEvent(static_cast< QEvent::Type >(MB_QEVENT)) {
Expand Down Expand Up @@ -198,6 +208,78 @@ MainWindow::MainWindow(QWidget *p)
&PluginManager::on_serverSynchronized);

QAccessible::installFactory(AccessibleSlider::semanticSliderFactory);

applyTheme();
}

void MainWindow::applyTheme() {
Hartmnt marked this conversation as resolved.
Show resolved Hide resolved
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() {
Hartmnt marked this conversation as resolved.
Show resolved Hide resolved
#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() {
Expand Down Expand Up @@ -756,6 +838,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
applyTheme();
}
}

void MainWindow::keyPressEvent(QKeyEvent *e) {
Expand Down
3 changes: 3 additions & 0 deletions src/mumble/MainWindow.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,9 @@ 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();
Expand Down
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