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 <oliver.wolff@qt.io>
This commit is contained in:
Friedemann Kleint 2019-09-25 15:04:36 +02:00
parent eb26563dd5
commit 859307d7a5
6 changed files with 118 additions and 27 deletions

View File

@ -1226,6 +1226,11 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
for (QWindowsWindow *w : d->m_windows) for (QWindowsWindow *w : d->m_windows)
w->setDarkBorder(QWindowsContextPrivate::m_darkMode); 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(); return d->m_screenManager.handleScreenChanges();
} }

View File

@ -243,6 +243,15 @@ static bool shGetFileInfoBackground(const QString &fileName, DWORD attributes,
return result; return result;
} }
// Dark Mode constants
enum DarkModeColors : QRgb {
darkModeBtnHighlightRgb = 0xc0c0c0,
darkModeBtnShadowRgb = 0x808080,
darkModeHighlightRgb = 0x0055ff, // deviating from 0x800080
darkModeMenuHighlightRgb = darkModeHighlightRgb,
darkModeGrayTextRgb = 0x00ff00
};
// from QStyle::standardPalette // from QStyle::standardPalette
static inline QPalette standardPalette() static inline QPalette standardPalette()
{ {
@ -260,23 +269,55 @@ static inline QPalette standardPalette()
return palette; return palette;
} }
static inline QPalette systemPalette() static void populateLightSystemBasePalette(QPalette &result)
{ {
QPalette result = standardPalette();
result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT)); result.setColor(QPalette::WindowText, getSysColor(COLOR_WINDOWTEXT));
result.setColor(QPalette::Button, getSysColor(COLOR_BTNFACE)); const QColor btnFace = getSysColor(COLOR_BTNFACE);
result.setColor(QPalette::Light, getSysColor(COLOR_BTNHIGHLIGHT)); 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::Dark, getSysColor(COLOR_BTNSHADOW));
result.setColor(QPalette::Mid, result.button().color().darker(150)); result.setColor(QPalette::Mid, result.button().color().darker(150));
result.setColor(QPalette::Text, getSysColor(COLOR_WINDOWTEXT)); 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::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::ButtonText, getSysColor(COLOR_BTNTEXT));
result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT)); result.setColor(QPalette::Midlight, getSysColor(COLOR_3DLIGHT));
result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW)); result.setColor(QPalette::Shadow, getSysColor(COLOR_3DDKSHADOW));
result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT)); result.setColor(QPalette::Highlight, getSysColor(COLOR_HIGHLIGHT));
result.setColor(QPalette::HighlightedText, getSysColor(COLOR_HIGHLIGHTTEXT)); 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::Link, Qt::blue);
result.setColor(QPalette::LinkVisited, Qt::magenta); result.setColor(QPalette::LinkVisited, Qt::magenta);
result.setColor(QPalette::Inactive, QPalette::Button, result.button().color()); 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::Text, disabled);
result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled); result.setColor(QPalette::Disabled, QPalette::ButtonText, disabled);
result.setColor(QPalette::Disabled, QPalette::Highlight, result.setColor(QPalette::Disabled, QPalette::Highlight,
getSysColor(COLOR_HIGHLIGHT)); light ? getSysColor(COLOR_HIGHLIGHT) : QColor(darkModeHighlightRgb));
result.setColor(QPalette::Disabled, QPalette::HighlightedText, result.setColor(QPalette::Disabled, QPalette::HighlightedText,
getSysColor(COLOR_HIGHLIGHTTEXT)); light ? getSysColor(COLOR_HIGHLIGHTTEXT) : QColor(Qt::white));
result.setColor(QPalette::Disabled, QPalette::Base, result.setColor(QPalette::Disabled, QPalette::Base,
result.window().color()); result.window().color());
return result; return result;
} }
static inline QPalette toolTipPalette(const QPalette &systemPalette) static inline QPalette toolTipPalette(const QPalette &systemPalette, bool light)
{ {
QPalette result(systemPalette); QPalette result(systemPalette);
const QColor tipBgColor(getSysColor(COLOR_INFOBK)); const QColor tipBgColor = light ? getSysColor(COLOR_INFOBK) : QColor(Qt::black);
const QColor tipTextColor(getSysColor(COLOR_INFOTEXT)); const QColor tipTextColor = light ? getSysColor(COLOR_INFOTEXT) : QColor(Qt::white);
result.setColor(QPalette::All, QPalette::Button, tipBgColor); result.setColor(QPalette::All, QPalette::Button, tipBgColor);
result.setColor(QPalette::All, QPalette::Window, tipBgColor); result.setColor(QPalette::All, QPalette::Window, tipBgColor);
@ -339,12 +380,13 @@ static inline QPalette toolTipPalette(const QPalette &systemPalette)
return result; return result;
} }
static inline QPalette menuPalette(const QPalette &systemPalette) static inline QPalette menuPalette(const QPalette &systemPalette, bool light)
{ {
QPalette result(systemPalette); QPalette result(systemPalette);
const QColor menuColor(getSysColor(COLOR_MENU)); const QColor menuColor = light ? getSysColor(COLOR_MENU) : QColor(Qt::black);
const QColor menuTextColor(getSysColor(COLOR_MENUTEXT)); const QColor menuTextColor = light ? getSysColor(COLOR_MENUTEXT) : QColor(Qt::white);
const QColor disabled(getSysColor(COLOR_GRAYTEXT)); const QColor disabled = light
? getSysColor(COLOR_GRAYTEXT) : QColor(darkModeGrayTextRgb);
// we might need a special color group for the result. // we might need a special color group for the result.
result.setColor(QPalette::Active, QPalette::Button, menuColor); result.setColor(QPalette::Active, QPalette::Button, menuColor);
result.setColor(QPalette::Active, QPalette::Text, menuTextColor); 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::WindowText, disabled);
result.setColor(QPalette::Disabled, QPalette::Text, disabled); result.setColor(QPalette::Disabled, QPalette::Text, disabled);
const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false); const bool isFlat = booleanSystemParametersInfo(SPI_GETFLATMENU, false);
result.setColor(QPalette::Disabled, QPalette::Highlight, const QColor highlightColor = light
getSysColor(isFlat ? COLOR_MENUHILIGHT : COLOR_HIGHLIGHT)); ? (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::HighlightedText, disabled);
result.setColor(QPalette::Disabled, QPalette::Button, result.setColor(QPalette::Disabled, QPalette::Button,
result.color(QPalette::Active, QPalette::Button)); result.color(QPalette::Active, QPalette::Button));
@ -375,12 +419,12 @@ static inline QPalette menuPalette(const QPalette &systemPalette)
return result; return result;
} }
static inline QPalette *menuBarPalette(const QPalette &menuPalette) static inline QPalette *menuBarPalette(const QPalette &menuPalette, bool light)
{ {
QPalette *result = nullptr; QPalette *result = nullptr;
if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) { if (booleanSystemParametersInfo(SPI_GETFLATMENU, false)) {
result = new QPalette(menuPalette); 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::Active, QPalette::Button, menubar);
result->setColor(QPalette::Disabled, QPalette::Button, menubar); result->setColor(QPalette::Disabled, QPalette::Button, menubar);
result->setColor(QPalette::Inactive, QPalette::Button, menubar); result->setColor(QPalette::Inactive, QPalette::Button, menubar);
@ -487,10 +531,26 @@ void QWindowsTheme::refreshPalettes()
if (!QGuiApplication::desktopSettingsAware()) if (!QGuiApplication::desktopSettingsAware())
return; return;
m_palettes[SystemPalette] = new QPalette(systemPalette()); const bool light =
m_palettes[ToolTipPalette] = new QPalette(toolTipPalette(*m_palettes[SystemPalette])); !QWindowsContext::isDarkMode()
m_palettes[MenuPalette] = new QPalette(menuPalette(*m_palettes[SystemPalette])); || (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) == 0;
m_palettes[MenuBarPalette] = menuBarPalette(*m_palettes[MenuPalette]); 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() void QWindowsTheme::clearFonts()
@ -499,6 +559,12 @@ void QWindowsTheme::clearFonts()
std::fill(m_fonts, m_fonts + NFonts, nullptr); std::fill(m_fonts, m_fonts + NFonts, nullptr);
} }
void QWindowsTheme::refresh()
{
refreshPalettes();
refreshFonts();
}
void QWindowsTheme::refreshFonts() void QWindowsTheme::refreshFonts()
{ {
clearFonts(); clearFonts();

View File

@ -88,11 +88,11 @@ public:
static bool queryHighContrast(); static bool queryHighContrast();
void refreshFonts(); void refreshFonts();
void refresh();
static const char *name; static const char *name;
private: private:
void refresh() { refreshPalettes(); refreshFonts(); }
void clearPalettes(); void clearPalettes();
void refreshPalettes(); void refreshPalettes();
void clearFonts(); void clearFonts();

View File

@ -225,9 +225,11 @@ static HRGN qt_hrgn_from_qregion(const QRegion &region)
*/ */
bool QWindowsXPStylePrivate::useXP(bool update) bool QWindowsXPStylePrivate::useXP(bool update)
{ {
if (!update) if (update) {
use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance())
&& !QWindowsStylePrivate::isDarkMode();
}
return use_xp; return use_xp;
return use_xp = IsThemeActive() && (IsAppThemed() || !QCoreApplication::instance());
} }
/* \internal /* \internal

View File

@ -84,6 +84,7 @@
#include <qpa/qplatformscreen.h> #include <qpa/qplatformscreen.h>
#include <private/qguiapplication_p.h> #include <private/qguiapplication_p.h>
#include <private/qhighdpiscaling_p.h> #include <private/qhighdpiscaling_p.h>
#include <qpa/qplatformnativeinterface.h>
#include <private/qwidget_p.h> #include <private/qwidget_p.h>
#include <private/qstylehelper_p.h> #include <private/qstylehelper_p.h>
@ -127,6 +128,22 @@ qreal QWindowsStylePrivate::appDevicePixelRatio()
return qApp->devicePixelRatio(); 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<bool>()
&& ni->property("darkMode").value<bool>();
}
#endif
return result;
}
// Returns \c true if the toplevel parent of \a widget has seen the Alt-key // Returns \c true if the toplevel parent of \a widget has seen the Alt-key
bool QWindowsStylePrivate::hasSeenAlt(const QWidget *widget) const bool QWindowsStylePrivate::hasSeenAlt(const QWidget *widget) const
{ {

View File

@ -74,6 +74,7 @@ public:
static qreal devicePixelRatio(const QWidget *widget = nullptr) static qreal devicePixelRatio(const QWidget *widget = nullptr)
{ return widget ? widget->devicePixelRatioF() : QWindowsStylePrivate::appDevicePixelRatio(); } { return widget ? widget->devicePixelRatioF() : QWindowsStylePrivate::appDevicePixelRatio(); }
static qreal nativeMetricScaleFactor(const QWidget *widget = nullptr); static qreal nativeMetricScaleFactor(const QWidget *widget = nullptr);
static bool isDarkMode();
bool hasSeenAlt(const QWidget *widget) const; bool hasSeenAlt(const QWidget *widget) const;
bool altDown() const { return alt_down; } bool altDown() const { return alt_down; }