From a2518b4140ed88a674bf4a4fcf4576e35c698bb9 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Wed, 7 Dec 2022 17:37:09 +0100 Subject: [PATCH] Overwrite dark system palette in Vista style MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The Vista style uses system assets for controls, and those are never dark. Because of that we cannot support dark appearance with that style, and applications using the Vista style should always use the light system palette. Override QStyle::polish(QPalette &) in the vista style to do that. To make that palette available, move the code reading the light palette into QWindowsApplication, and call that method from both the platform theme (if the system is running in light mode) and from the Vista style (only if the system is running in dark mode). If the system is dark mode and another style is used (e.g. Fusion, which works well with a dark palette), then the palette returned by the platform theme gets used without any modifications. This requires duplicating some small inline helper functions in QWindowsTheme and QWindowsApplication. We can clean this up once the implementation is complete for both Qt Widgets and Qt Quick. Change-Id: Ia13f59a2d8414642603f9708926718daf9e8954d Reviewed-by: Tor Arne Vestbø Reviewed-by: Santhosh Kumar --- src/gui/kernel/qguiapplication_p.h | 2 + .../platforms/windows/qwindowsapplication.cpp | 82 ++++++++++++++++++- .../platforms/windows/qwindowsapplication.h | 2 + .../platforms/windows/qwindowstheme.cpp | 54 ++---------- .../windowsvista/qwindowsvistastyle.cpp | 15 +++- 5 files changed, 101 insertions(+), 54 deletions(-) diff --git a/src/gui/kernel/qguiapplication_p.h b/src/gui/kernel/qguiapplication_p.h index 9d8e292445a..46bc504f5f6 100644 --- a/src/gui/kernel/qguiapplication_p.h +++ b/src/gui/kernel/qguiapplication_p.h @@ -396,6 +396,8 @@ struct Q_GUI_EXPORT QWindowsApplication virtual QVariant gpu() const = 0; // internal, used by qtdiag virtual QVariant gpuList() const = 0; + + virtual void lightSystemPalette(QPalette &pal) const = 0; }; #endif // Q_OS_WIN diff --git a/src/plugins/platforms/windows/qwindowsapplication.cpp b/src/plugins/platforms/windows/qwindowsapplication.cpp index f0bce353365..5d1b6d348b1 100644 --- a/src/plugins/platforms/windows/qwindowsapplication.cpp +++ b/src/plugins/platforms/windows/qwindowsapplication.cpp @@ -8,8 +8,25 @@ #include "qwin10helpers.h" #include "qwindowsopengltester.h" #include "qwindowswindow.h" +#include "qwindowsintegration.h" -#include +#include +#include + +#include + +#if QT_CONFIG(cpp_winrt) +# include +# include +// Workaround for Windows SDK bug. +// See https://github.com/microsoft/Windows.UI.Composition-Win32-Samples/issues/47 +namespace winrt::impl +{ + template + auto wait_for(Async const& async, Windows::Foundation::TimeSpan const& timeout); +} +# include +#endif // QT_CONFIG(cpp_winrt) QT_BEGIN_NAMESPACE @@ -138,4 +155,67 @@ QVariant QWindowsApplication::gpuList() const return result; } +static inline QColor getSysColor(int index) +{ + COLORREF cr = GetSysColor(index); + return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr)); +} + +#if QT_CONFIG(cpp_winrt) +static constexpr QColor getSysColor(winrt::Windows::UI::Color &&color) +{ + return QColor(color.R, color.G, color.B, color.A); +} +#endif + +static inline QColor placeHolderColor(QColor textColor) +{ + textColor.setAlpha(128); + return textColor; +} + +void QWindowsApplication::lightSystemPalette(QPalette &result) const +{ + QColor background = getSysColor(COLOR_BTNFACE); + QColor textColor = getSysColor(COLOR_WINDOWTEXT); + QColor accent = getSysColor(COLOR_HIGHLIGHT); + +#if QT_CONFIG(cpp_winrt) + // respect the Windows 11 accent color + using namespace winrt::Windows::UI::ViewManagement; + const auto settings = UISettings(); + + accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); +#endif + + const QColor btnFace = background; + const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT); + + result.setColor(QPalette::Highlight, accent); + result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT)); + result.setColor(QPalette::Button, btnFace); + result.setColor(QPalette::Light, btnHighlight); + result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW)); + result.setColor(QPalette::Mid, result.button().color().darker(150)); + result.setColor(QPalette::Text, textColor); + result.setColor(QPalette::PlaceholderText, placeHolderColor(textColor)); + result.setColor(QPalette::BrightText, btnHighlight); + result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW)); + result.setColor(QPalette::Window, btnFace); + result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT)); + result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT)); + result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW)); + result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); + + result.setColor(QPalette::Link, Qt::blue); + result.setColor(QPalette::LinkVisited, Qt::magenta); + result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); + result.setColor(QPalette::Inactive, QPalette::Window, result.window().color()); + result.setColor(QPalette::Inactive, QPalette::Light, result.light().color()); + result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color()); + + if (result.midlight() == result.button()) + result.setColor(QPalette::Midlight, result.button().color().lighter(110)); +} + QT_END_NAMESPACE diff --git a/src/plugins/platforms/windows/qwindowsapplication.h b/src/plugins/platforms/windows/qwindowsapplication.h index a969e3c8673..8b74b47f3d1 100644 --- a/src/plugins/platforms/windows/qwindowsapplication.h +++ b/src/plugins/platforms/windows/qwindowsapplication.h @@ -43,6 +43,8 @@ public: QVariant gpu() const override; QVariant gpuList() const override; + void lightSystemPalette(QPalette &palette) const override; + private: WindowActivationBehavior m_windowActivationBehavior = DefaultActivateWindow; TouchWindowTouchTypes m_touchWindowTouchTypes = NormalTouch; diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 8e931b1ed88..b9d02a43742 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -63,11 +63,6 @@ QT_BEGIN_NAMESPACE using namespace Qt::StringLiterals; -static inline QColor COLORREFToQColor(COLORREF cr) -{ - return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr)); -} - static inline bool booleanSystemParametersInfo(UINT what, bool defaultValue) { BOOL result; @@ -93,7 +88,8 @@ static inline QColor mixColors(const QColor &c1, const QColor &c2) static inline QColor getSysColor(int index) { - return COLORREFToQColor(GetSysColor(index)); + COLORREF cr = GetSysColor(index); + return QColor(GetRValue(cr), GetGValue(cr), GetBValue(cr)); } #if QT_CONFIG(cpp_winrt) @@ -238,49 +234,9 @@ static QColor placeHolderColor(QColor textColor) */ static void populateLightSystemBasePalette(QPalette &result) { - QColor background = getSysColor(COLOR_BTNFACE); - QColor textColor = getSysColor(COLOR_WINDOWTEXT); - QColor accent = getSysColor(COLOR_HIGHLIGHT); - -#if QT_CONFIG(cpp_winrt) - if (QWindowsIntegration::instance()->darkModeHandling().testFlag(QWindowsApplication::DarkModeStyle)) { - using namespace winrt::Windows::UI::ViewManagement; - const auto settings = UISettings(); - - background = getSysColor(settings.GetColorValue(UIColorType::Background)); - textColor = getSysColor(settings.GetColorValue(UIColorType::Foreground)); - accent = getSysColor(settings.GetColorValue(UIColorType::Accent)); - } -#endif - - const QColor btnFace = background; - const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT); - - result.setColor(QPalette::Highlight, accent); - result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT)); - result.setColor(QPalette::Button, btnFace); - result.setColor(QPalette::Light, btnHighlight); - result.setColor(QPalette::Dark, getSysColor(COLOR_BTNSHADOW)); - result.setColor(QPalette::Mid, result.button().color().darker(150)); - result.setColor(QPalette::Text, textColor); - result.setColor(QPalette::PlaceholderText, placeHolderColor(textColor)); - result.setColor(QPalette::BrightText, btnHighlight); - result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW)); - result.setColor(QPalette::Window, btnFace); - result.setColor(QPalette::ButtonText, getSysColor(COLOR_BTNTEXT)); - result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT)); - result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW)); - result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); - - result.setColor(QPalette::Link, Qt::blue); - result.setColor(QPalette::LinkVisited, Qt::magenta); - result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); - result.setColor(QPalette::Inactive, QPalette::Window, result.window().color()); - result.setColor(QPalette::Inactive, QPalette::Light, result.light().color()); - result.setColor(QPalette::Inactive, QPalette::Dark, result.dark().color()); - - if (result.midlight() == result.button()) - result.setColor(QPalette::Midlight, result.button().color().lighter(110)); + using QWindowsApplication = QNativeInterface::Private::QWindowsApplication; + if (auto nativeWindowsApp = dynamic_cast(QGuiApplicationPrivate::platformIntegration())) + nativeWindowsApp->lightSystemPalette(result); } static void populateDarkSystemBasePalette(QPalette &result) diff --git a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp index 5533a194ac8..969e53b8e10 100644 --- a/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsvistastyle.cpp @@ -6,6 +6,7 @@ #include "qwindowsvistaanimation_p.h" #include #include +#include #include #include #include @@ -172,10 +173,8 @@ static QRegion scaleRegion(const QRegion ®ion, qreal factor) */ bool QWindowsVistaStylePrivate::useVista(bool update) { - if (update) { - useVistaTheme = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance()) - && !QWindowsStylePrivate::isDarkMode(); - } + if (update) + useVistaTheme = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance()); return useVistaTheme; } @@ -4791,6 +4790,14 @@ void QWindowsVistaStyle::polish(QPalette &pal) { Q_D(QWindowsVistaStyle); + if (qApp->styleHints()->appearance() == Qt::Appearance::Dark) { + // System runs in dark mode, but the Vista style cannot use a dark palette. + // Overwrite with the light system palette. + using QWindowsApplication = QNativeInterface::Private::QWindowsApplication; + if (auto nativeWindowsApp = dynamic_cast(QGuiApplicationPrivate::platformIntegration())) + nativeWindowsApp->lightSystemPalette(pal); + } + QPixmapCache::clear(); d->alphaCache.clear(); d->hasInitColors = false;