Re-polish on theme change

Took 2 minutes
This commit is contained in:
Lukas Brübach 2026-05-08 11:23:05 +02:00
parent 4568f4b501
commit 85c2cda284

View file

@ -15,6 +15,7 @@
#include <QStyle> #include <QStyle>
#include <QStyleFactory> #include <QStyleFactory>
#include <QStyleHints> #include <QStyleHints>
#include <QWidget>
#include <Qt> #include <Qt>
#define NONE_THEME_NAME "Default" #define NONE_THEME_NAME "Default"
@ -91,6 +92,10 @@ struct PaletteColorInfo
ThemeManager::ThemeManager(QObject *parent) : QObject(parent) ThemeManager::ThemeManager(QObject *parent) : QObject(parent)
{ {
defaultStyleName = qApp->style()->objectName(); defaultStyleName = qApp->style()->objectName();
// FIXME workaround for windows11 style being broken
if (defaultStyleName == "windows11") {
defaultStyleName = "windowsvista";
}
ensureThemeDirectoryExists(); ensureThemeDirectoryExists();
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot); connect(QGuiApplication::styleHints(), &QStyleHints::colorSchemeChanged, this, &ThemeManager::themeChangedSlot);
@ -364,26 +369,55 @@ void ThemeManager::themeChangedSlot()
qApp->setStyleSheet(""); qApp->setStyleSheet("");
} }
QStyle *newStyle = nullptr;
QPalette newPalette;
if (themeName == FUSION_THEME_NAME) { if (themeName == FUSION_THEME_NAME) {
QStyle *fusionStyle = QStyleFactory::create("Fusion"); newStyle = QStyleFactory::create("Fusion");
qApp->setStyle(fusionStyle);
#if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)) #if (QT_VERSION >= QT_VERSION_CHECK(6, 5, 0))
// Start from Fusion's own palette so dark mode is handled correctly, // Start from Fusion's own palette so dark mode is handled correctly,
// then apply any tweaks on top of it. // then apply any tweaks on top of it.
QPalette palette = fusionStyle->standardPalette(); newPalette = newStyle->standardPalette();
if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) { if (QGuiApplication::styleHints()->colorScheme() == Qt::ColorScheme::Dark) {
palette.setColor(QPalette::AlternateBase, QColor(53, 53, 53)); newPalette.setColor(QPalette::AlternateBase, QColor(53, 53, 53));
} }
qApp->setPalette(palette); #else
newPalette = qApp->palette();
#endif #endif
} else if (themeName == FUSION_THEME_NAME_LIGHT) { } else if (themeName == FUSION_THEME_NAME_LIGHT) {
qApp->setStyle(QStyleFactory::create("Fusion")); newStyle = QStyleFactory::create("Fusion");
qApp->setPalette(createLightGreenFusionPalette()); newPalette = createLightGreenFusionPalette();
} else if (themeName == FUSION_THEME_NAME_DARK) { } else if (themeName == FUSION_THEME_NAME_DARK) {
qApp->setStyle(QStyleFactory::create("Fusion")); newStyle = QStyleFactory::create("Fusion");
qApp->setPalette(createDarkGreenFusionPalette()); newPalette = createDarkGreenFusionPalette();
} else { } else {
qApp->setStyle(QStyleFactory::create(defaultStyleName)); // setting the style also sets the palette newStyle = QStyleFactory::create(defaultStyleName);
// Use the style's default palette.
newPalette = newStyle->standardPalette();
}
// Apply palette FIRST.
qApp->setPalette(newPalette);
// Then apply style.
qApp->setStyle(newStyle);
// Force every widget to re-polish and repaint immediately rather than
// waiting for natural expose events, which produces a patchwork of old
// and new colours during a live preview.
// Note: we do NOT call widget->setPalette(base) here — qApp->setPalette()
// already propagates to all widgets that haven't explicitly overridden their
// palette (WA_SetPalette not set). Calling it unconditionally would clobber
// intentional per-widget palette customisations across the whole app.
for (QWidget *widget : qApp->allWidgets()) {
newStyle->unpolish(widget);
newStyle->polish(widget);
widget->style()->unpolish(widget);
widget->style()->polish(widget);
widget->update();
widget->repaint();
} }
if (dirPath.isEmpty()) { if (dirPath.isEmpty()) {