From 859307d7a590873d8df5f8094e13043370fccaa7 Mon Sep 17 00:00:00 2001 From: Friedemann Kleint Date: Wed, 25 Sep 2019 15:04:36 +0200 Subject: Windows QPA: Provide an experimental palette for dark mode Provide a simple palette for dark mode, implementing dark mode support level 2. Task-number: QTBUG-72028 Change-Id: I6f71870b251ccb7da30c01abb22c224e600f2b27 Reviewed-by: Oliver Wolff --- src/plugins/platforms/windows/qwindowscontext.cpp | 5 + src/plugins/platforms/windows/qwindowstheme.cpp | 112 ++++++++++++++++----- src/plugins/platforms/windows/qwindowstheme.h | 2 +- .../styles/windowsvista/qwindowsxpstyle.cpp | 8 +- src/widgets/styles/qwindowsstyle.cpp | 17 ++++ src/widgets/styles/qwindowsstyle_p_p.h | 1 + 6 files changed, 118 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 5578259399..2591966d54 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -1226,6 +1226,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message, for (QWindowsWindow *w : d->m_windows) w->setDarkBorder(QWindowsContextPrivate::m_darkMode); } + if ((options & QWindowsIntegration::DarkModeStyle) != 0) { + QWindowsTheme::instance()->refresh(); + for (QWindowsWindow *w : d->m_windows) + QWindowSystemInterface::handleThemeChange(w->window()); + } } return d->m_screenManager.handleScreenChanges(); } diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp index 2f9dd0b40b..325956b7ba 100644 --- a/src/plugins/platforms/windows/qwindowstheme.cpp +++ b/src/plugins/platforms/windows/qwindowstheme.cpp @@ -243,6 +243,15 @@ static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes, return result; } +// Dark Mode constants +enum DarkModeColors : QRgb { + darkModeBtnHighlightRgb = 0xc0c0c0, + darkModeBtnShadowRgb = 0x808080, + darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080 + darkModeMenuHighlightRgb = darkModeHighlightRgb, + darkModeGrayTextRgb = 0x00ff00 +}; + // from QStyle::standardPalette static inline QPalette standardPalette() { @@ -260,23 +269,55 @@ static inline QPalette standardPalette() return palette; } -static inline QPalette systemPalette() +static void populateLightSystemBasePalette(QPalette &result) { - QPalette result = standardPalette(); result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT)); - result.setColor(QPalette::Button, getSysColor(COLOR_BTNFACE)); - result.setColor(QPalette::Light, getSysColor(COLOR_BTNHIGHLIGHT)); + const QColor btnFace = getSysColor(COLOR_BTNFACE); + result.setColor(QPalette::Button, btnFace); + const QColor btnHighlight = getSysColor(COLOR_BTNHIGHLIGHT); + 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, getSysColor(COLOR_WINDOWTEXT)); - result.setColor(QPalette::BrightText, getSysColor(COLOR_BTNHIGHLIGHT)); + result.setColor(QPalette::BrightText, btnHighlight); result.setColor(QPalette::Base, getSysColor(COLOR_WINDOW)); - result.setColor(QPalette::Window, getSysColor(COLOR_BTNFACE)); + 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::Highlight, getSysColor(COLOR_HIGHLIGHT)); result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); +} + +static void populateDarkSystemBasePalette(QPalette &result) +{ + const QColor darkModeWindowText = Qt::white; + result.setColor(QPalette::WindowText, darkModeWindowText); + const QColor darkModebtnFace = Qt::black; + result.setColor(QPalette::Button, darkModebtnFace); + const QColor btnHighlight = QColor(darkModeBtnHighlightRgb); + result.setColor(QPalette::Light, btnHighlight); + result.setColor(QPalette::Dark, QColor(darkModeBtnShadowRgb)); + result.setColor(QPalette::Mid, result.button().color().darker(150)); + result.setColor(QPalette::Text, darkModeWindowText); + result.setColor(QPalette::BrightText, btnHighlight); + result.setColor(QPalette::Base, darkModebtnFace); + result.setColor(QPalette::Window, darkModebtnFace); + result.setColor(QPalette::ButtonText, darkModeWindowText); + result.setColor(QPalette::Midlight, darkModeWindowText); + result.setColor(QPalette::Shadow, darkModeWindowText); + result.setColor(QPalette::Highlight, QColor(darkModeHighlightRgb)); + result.setColor(QPalette::HighlightedText, darkModeWindowText); +} + +static QPalette systemPalette(bool light) +{ + QPalette result = standardPalette(); + if (light) + populateLightSystemBasePalette(result); + else + populateDarkSystemBasePalette(result); + result.setColor(QPalette::Link, Qt::blue); result.setColor(QPalette::LinkVisited, Qt::magenta); result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); @@ -302,19 +343,19 @@ static inline QPalette systemPalette() result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled); result.setColor(QPalette::Disabled, QPalette::Highlight, - getSysColor(COLOR_HIGHLIGHT)); + light ? getSysColor(COLOR_HIGHLIGHT) : QColor(darkModeHighlightRgb)); result.setColor(QPalette::Disabled, QPalette::HighlightedText, - getSysColor(COLOR_HIGHLIGHTTEXT)); + light ? getSysColor(COLOR_HIGHLIGHTTEXT) : QColor(Qt::white)); result.setColor(QPalette::Disabled, QPalette::Base, result.window().color()); return result; } -static inline QPalette toolTipPalette(const QPalette &systemPalette) +static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light) { QPalette result(systemPalette); - const QColor tipBgColor(getSysColor(COLOR_INFOBK)); - const QColor tipTextColor(getSysColor(COLOR_INFOTEXT)); + const QColor tipBgColor = light ? getSysColor(COLOR_INFOBK) : QColor(Qt::black); + const QColor tipTextColor = light ? getSysColor(COLOR_INFOTEXT) : QColor(Qt::white); result.setColor(QPalette::All, QPalette::Button, tipBgColor); result.setColor(QPalette::All, QPalette::Window, tipBgColor); @@ -339,12 +380,13 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette) return result; } -static inline QPalette menuPalette(const QPalette &systemPalette) +static inline QPalette menuPalette(const QPalette &systemPalette, bool light) { QPalette result(systemPalette); - const QColor menuColor(getSysColor(COLOR_MENU)); - const QColor menuTextColor(getSysColor(COLOR_MENUTEXT)); - const QColor disabled(getSysColor(COLOR_GRAYTEXT)); + const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black); + const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white); + const QColor disabled = light + ? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb); // we might need a special color group for the result. result.setColor(QPalette::Active, QPalette::Button, menuColor); result.setColor(QPalette::Active, QPalette::Text, menuTextColor); @@ -353,8 +395,10 @@ static inline QPalette menuPalette(const QPalette &systemPalette) result.setColor(QPalette::Disabled, QPalette::WindowText, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled); const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false); - result.setColor(QPalette::Disabled, QPalette::Highlight, - getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)); + const QColor highlightColor = light + ? (getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)) + : QColor(darkModeMenuHighlightRgb); + result.setColor(QPalette::Disabled, QPalette::Highlight, highlightColor); result.setColor(QPalette::Disabled, QPalette::HighlightedText, disabled); result.setColor(QPalette::Disabled, QPalette::Button, result.color(QPalette::Active, QPalette::Button)); @@ -375,12 +419,12 @@ static inline QPalette menuPalette(const QPalette &systemPalette) return result; } -static inline QPalette *menuBarPalette(const QPalette &menuPalette) +static inline QPalette *menuBarPalette(const QPalette &menuPalette, bool light) { QPalette *result = nullptr; if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) { result = new QPalette(menuPalette); - const QColor menubar(getSysColor(COLOR_MENUBAR)); + const QColor menubar(light ? getSysColor(COLOR_MENUBAR) : QColor(Qt::black)); result->setColor(QPalette::Active, QPalette::Button, menubar); result->setColor(QPalette::Disabled, QPalette::Button, menubar); result->setColor(QPalette::Inactive, QPalette::Button, menubar); @@ -487,10 +531,26 @@ void QWindowsTheme::refreshPalettes() if (!QGuiApplication::desktopSettingsAware()) return; - m_palettes[SystemPalette] = new QPalette(systemPalette()); - m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); - m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette])); - m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]); + const bool light = + !QWindowsContext::isDarkMode() + || (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) == 0; + m_palettes[SystemPalette] = new QPalette(systemPalette(light)); + m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette], light)); + m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette], light)); + m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette], light); + if (!light) { + m_palettes[ButtonPalette] = new QPalette(*m_palettes[SystemPalette]); + m_palettes[ButtonPalette]->setColor(QPalette::Button, QColor(0x666666u)); + const QColor checkBoxBlue(0x0078d7u); + const QColor white(Qt::white); + m_palettes[CheckBoxPalette] = new QPalette(*m_palettes[SystemPalette]); + m_palettes[CheckBoxPalette]->setColor(QPalette::Window, checkBoxBlue); + m_palettes[CheckBoxPalette]->setColor(QPalette::Base, checkBoxBlue); + m_palettes[CheckBoxPalette]->setColor(QPalette::Button, checkBoxBlue); + m_palettes[CheckBoxPalette]->setColor(QPalette::ButtonText, white); + m_palettes[RadioButtonPalette] = new QPalette(*m_palettes[CheckBoxPalette]); + + } } void QWindowsTheme::clearFonts() @@ -499,6 +559,12 @@ void QWindowsTheme::clearFonts() std::fill(m_fonts, m_fonts + NFonts, nullptr); } +void QWindowsTheme::refresh() +{ + refreshPalettes(); + refreshFonts(); +} + void QWindowsTheme::refreshFonts() { clearFonts(); diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h index d557c0b4fd..af28f2878c 100644 --- a/src/plugins/platforms/windows/qwindowstheme.h +++ b/src/plugins/platforms/windows/qwindowstheme.h @@ -88,11 +88,11 @@ public: static bool queryHighContrast(); void refreshFonts(); + void refresh(); static const char *name; private: - void refresh() { refreshPalettes(); refreshFonts(); } void clearPalettes(); void refreshPalettes(); void clearFonts(); diff --git a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp index 5d2e8efd68..899e7f7c17 100644 --- a/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp +++ b/src/plugins/styles/windowsvista/qwindowsxpstyle.cpp @@ -225,9 +225,11 @@ static HRGN qt_hrgn_from_qregion(const QRegion ®ion) */ bool QWindowsXPStylePrivate::useXP(bool update) { - if (!update) - return use_xp; - return use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance()); + if (update) { + use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance()) + && !QWindowsStylePrivate::isDarkMode(); + } + return use_xp; } /* \internal diff --git a/src/widgets/styles/qwindowsstyle.cpp b/src/widgets/styles/qwindowsstyle.cpp index 8496a2c223..497afd17e1 100644 --- a/src/widgets/styles/qwindowsstyle.cpp +++ b/src/widgets/styles/qwindowsstyle.cpp @@ -84,6 +84,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,22 @@ qreal QWindowsStylePrivate::appDevicePixelRatio() return qApp->devicePixelRatio(); } +bool QWindowsStylePrivate::isDarkMode() +{ + bool result = false; +#ifdef Q_OS_WIN + // Windows only: Return whether dark mode style support is desired and + // dark mode is in effect. + if (auto ni = QGuiApplication::platformNativeInterface()) { + const QVariant darkModeStyleP = ni->property("darkModeStyle"); + result = darkModeStyleP.type() == QVariant::Bool + && darkModeStyleP.value() + && ni->property("darkMode").value(); + } +#endif + return result; +} + // Returns \c true if the toplevel parent of \a widget has seen the Alt-key bool QWindowsStylePrivate::hasSeenAlt(const QWidget *widget) const { diff --git a/src/widgets/styles/qwindowsstyle_p_p.h b/src/widgets/styles/qwindowsstyle_p_p.h index 4f6ffcefc2..a25f5c4166 100644 --- a/src/widgets/styles/qwindowsstyle_p_p.h +++ b/src/widgets/styles/qwindowsstyle_p_p.h @@ -74,6 +74,7 @@ public: static qreal devicePixelRatio(const QWidget *widget = nullptr) { return widget ? widget->devicePixelRatioF() : QWindowsStylePrivate::appDevicePixelRatio(); } static qreal nativeMetricScaleFactor(const QWidget *widget = nullptr); + static bool isDarkMode(); bool hasSeenAlt(const QWidget *widget) const; bool altDown() const { return alt_down; } -- cgit v1.2.3