Windows QPA: Add detection of dark mode

Read the dark mode setting and make it accessible
via native interface.
Add a command line option to set the support level.

Task-number: QTBUG-72028
Change-Id: I1e9fe296a6b1bda81512d003183038b866b67545
Reviewed-by: Oliver Wolff <oliver.wolff@qt.io>
This commit is contained in:
Friedemann Kleint 2019-10-21 16:01:47 +02:00
parent 1278995778
commit 12f085e538
9 changed files with 84 additions and 2 deletions

View File

@ -592,6 +592,21 @@ static QWindowGeometrySpecification windowGeometrySpecification = Q_WINDOW_GEOME
\list \list
\li \c {altgr}, detect the key \c {AltGr} found on some keyboards as \li \c {altgr}, detect the key \c {AltGr} found on some keyboards as
Qt::GroupSwitchModifier (since Qt 5.12). Qt::GroupSwitchModifier (since Qt 5.12).
\li \c {darkmode=[1|2]} controls how Qt responds to the activation
of the \e{Dark Mode for applications} introduced in Windows 10
1903 (since Qt 5.15).
A value of 1 causes Qt to switch the window borders to black
when \e{Dark Mode for applications} is activated and no High
Contrast Theme is in use. This is intended for applications
that implement their own theming.
A value of 2 will in addition cause the Windows Vista style to
be deactivated and switch to the Windows style using a
simplified palette in dark mode. This is currently
experimental pending the introduction of new style that
properly adapts to dark mode.
\li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and \li \c {dialogs=[xp|none]}, \c xp uses XP-style native dialogs and
\c none disables them. \c none disables them.

View File

@ -42,6 +42,7 @@
#include "qwindowsintegration.h" #include "qwindowsintegration.h"
#include "qwindowswindow.h" #include "qwindowswindow.h"
#include "qwindowskeymapper.h" #include "qwindowskeymapper.h"
#include "qwindowsnativeinterface.h"
#include "qwindowsmousehandler.h" #include "qwindowsmousehandler.h"
#include "qwindowspointerhandler.h" #include "qwindowspointerhandler.h"
#include "qtwindowsglobal.h" #include "qtwindowsglobal.h"
@ -277,8 +278,11 @@ struct QWindowsContextPrivate {
bool m_asyncExpose = false; bool m_asyncExpose = false;
HPOWERNOTIFY m_powerNotification = nullptr; HPOWERNOTIFY m_powerNotification = nullptr;
HWND m_powerDummyWindow = nullptr; HWND m_powerDummyWindow = nullptr;
static bool m_darkMode;
}; };
bool QWindowsContextPrivate::m_darkMode = false;
QWindowsContextPrivate::QWindowsContextPrivate() QWindowsContextPrivate::QWindowsContextPrivate()
: m_oleInitializeResult(OleInitialize(nullptr)) : m_oleInitializeResult(OleInitialize(nullptr))
{ {
@ -293,6 +297,7 @@ QWindowsContextPrivate::QWindowsContextPrivate()
m_systemInfo |= QWindowsContext::SI_RTL_Extensions; m_systemInfo |= QWindowsContext::SI_RTL_Extensions;
m_keyMapper.setUseRTLExtensions(true); m_keyMapper.setUseRTLExtensions(true);
} }
m_darkMode = QWindowsTheme::queryDarkMode();
if (FAILED(m_oleInitializeResult)) { if (FAILED(m_oleInitializeResult)) {
qWarning() << "QWindowsContext: OleInitialize() failed: " qWarning() << "QWindowsContext: OleInitialize() failed: "
<< QWindowsContext::comErrorString(m_oleInitializeResult); << QWindowsContext::comErrorString(m_oleInitializeResult);
@ -485,6 +490,11 @@ void QWindowsContext::setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiA
} }
} }
bool QWindowsContext::isDarkMode()
{
return QWindowsContextPrivate::m_darkMode;
}
QWindowsContext *QWindowsContext::instance() QWindowsContext *QWindowsContext::instance()
{ {
return m_instance; return m_instance;
@ -1203,9 +1213,17 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
t->displayChanged(); t->displayChanged();
QWindowsWindow::displayChanged(); QWindowsWindow::displayChanged();
return d->m_screenManager.handleDisplayChange(wParam, lParam); return d->m_screenManager.handleDisplayChange(wParam, lParam);
case QtWindows::SettingChangedEvent: case QtWindows::SettingChangedEvent: {
QWindowsWindow::settingsChanged(); QWindowsWindow::settingsChanged();
const bool darkMode = QWindowsTheme::queryDarkMode();
if (darkMode != QWindowsContextPrivate::m_darkMode) {
QWindowsContextPrivate::m_darkMode = darkMode;
auto nativeInterface =
static_cast<QWindowsNativeInterface *>(QWindowsIntegration::instance()->nativeInterface());
emit nativeInterface->darkModeChanged(darkMode);
}
return d->m_screenManager.handleScreenChanges(); return d->m_screenManager.handleScreenChanges();
}
default: default:
break; break;
} }

View File

@ -226,6 +226,8 @@ public:
void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness); void setProcessDpiAwareness(QtWindows::ProcessDpiAwareness dpiAwareness);
static int processDpiAwareness(); static int processDpiAwareness();
static bool isDarkMode();
void setDetectAltGrModifier(bool a); void setDetectAltGrModifier(bool a);
// Returns a combination of SystemInfoFlags // Returns a combination of SystemInfoFlags

View File

@ -219,6 +219,10 @@ static inline unsigned parseOptions(const QStringList &paramList,
options |= QWindowsIntegration::DontUseWMPointer; options |= QWindowsIntegration::DontUseWMPointer;
} else if (param == u"reverse") { } else if (param == u"reverse") {
options |= QWindowsIntegration::RtlEnabled; options |= QWindowsIntegration::RtlEnabled;
} else if (param == u"darkmode=1") {
options |= QWindowsIntegration::DarkModeWindowFrames;
} else if (param == u"darkmode=2") {
options |= QWindowsIntegration::DarkModeWindowFrames | QWindowsIntegration::DarkModeStyle;
} else { } else {
qWarning() << "Unknown option" << param; qWarning() << "Unknown option" << param;
} }

View File

@ -70,7 +70,9 @@ public:
NoNativeMenus = 0x200, NoNativeMenus = 0x200,
DontUseWMPointer = 0x400, DontUseWMPointer = 0x400,
DetectAltGrModifier = 0x800, DetectAltGrModifier = 0x800,
RtlEnabled = 0x1000 RtlEnabled = 0x1000,
DarkModeWindowFrames = 0x2000,
DarkModeStyle = 0x4000
}; };
explicit QWindowsIntegration(const QStringList &paramList); explicit QWindowsIntegration(const QStringList &paramList);

View File

@ -47,6 +47,7 @@
#include "qwindowsopengltester.h" #include "qwindowsopengltester.h"
#include "qwindowsintegration.h" #include "qwindowsintegration.h"
#include "qwindowsmime.h" #include "qwindowsmime.h"
#include "qwindowstheme.h"
#include "qwin10helpers.h" #include "qwin10helpers.h"
#include <QtGui/qwindow.h> #include <QtGui/qwindow.h>
@ -316,4 +317,15 @@ QVariant QWindowsNativeInterface::gpuList() const
return result; return result;
} }
bool QWindowsNativeInterface::isDarkMode() const
{
return QWindowsContext::isDarkMode();
}
// Dark mode support level 2 (style)
bool QWindowsNativeInterface::isDarkModeStyle() const
{
return (QWindowsIntegration::instance()->options() & QWindowsIntegration::DarkModeStyle) != 0;
}
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -65,6 +65,8 @@ class QWindowsNativeInterface : public QPlatformNativeInterface
{ {
Q_OBJECT Q_OBJECT
Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose) Q_PROPERTY(bool asyncExpose READ asyncExpose WRITE setAsyncExpose)
Q_PROPERTY(bool darkMode READ isDarkMode STORED false NOTIFY darkModeChanged)
Q_PROPERTY(bool darkModeStyle READ isDarkModeStyle STORED false)
Q_PROPERTY(QVariant gpu READ gpu STORED false) Q_PROPERTY(QVariant gpu READ gpu STORED false)
Q_PROPERTY(QVariant gpuList READ gpuList STORED false) Q_PROPERTY(QVariant gpuList READ gpuList STORED false)
@ -92,6 +94,9 @@ public:
bool asyncExpose() const; bool asyncExpose() const;
void setAsyncExpose(bool value); void setAsyncExpose(bool value);
bool isDarkMode() const;
bool isDarkModeStyle() const;
QVariant gpu() const; QVariant gpu() const;
QVariant gpuList() const; QVariant gpuList() const;
@ -109,6 +114,9 @@ public:
QFunctionPointer platformFunction(const QByteArray &function) const override; QFunctionPointer platformFunction(const QByteArray &function) const override;
Q_SIGNALS:
void darkModeChanged(bool);
private: private:
static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior; static QWindowsWindowFunctions::WindowActivationBehavior m_windowActivationBehavior;
}; };

View File

@ -63,6 +63,7 @@
#include <QtCore/qcoreapplication.h> #include <QtCore/qcoreapplication.h>
#include <QtCore/qdebug.h> #include <QtCore/qdebug.h>
#include <QtCore/qtextstream.h> #include <QtCore/qtextstream.h>
#include <QtCore/qoperatingsystemversion.h>
#include <QtCore/qsysinfo.h> #include <QtCore/qsysinfo.h>
#include <QtCore/qcache.h> #include <QtCore/qcache.h>
#include <QtCore/qthread.h> #include <QtCore/qthread.h>
@ -78,6 +79,7 @@
#include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h> #include <QtFontDatabaseSupport/private/qwindowsfontdatabase_p.h>
#include <private/qhighdpiscaling_p.h> #include <private/qhighdpiscaling_p.h>
#include <private/qsystemlibrary_p.h> #include <private/qsystemlibrary_p.h>
#include <private/qwinregistry_p.h>
#include <algorithm> #include <algorithm>
@ -946,6 +948,23 @@ bool QWindowsTheme::useNativeMenus()
return result; return result;
} }
bool QWindowsTheme::queryDarkMode()
{
if (QOperatingSystemVersion::current()
< QOperatingSystemVersion(QOperatingSystemVersion::Windows, 10, 0, 17763)
|| queryHighContrast()) {
return false;
}
const auto setting = QWinRegistryKey(HKEY_CURRENT_USER, LR"(Software\Microsoft\Windows\CurrentVersion\Themes\Personalize)")
.dwordValue(L"AppsUseLightTheme");
return setting.second && setting.first == 0;
}
bool QWindowsTheme::queryHighContrast()
{
return booleanSystemParametersInfo(SPI_GETHIGHCONTRAST, false);
}
QPlatformMenuItem *QWindowsTheme::createPlatformMenuItem() const QPlatformMenuItem *QWindowsTheme::createPlatformMenuItem() const
{ {
qCDebug(lcQpaMenus) << __FUNCTION__; qCDebug(lcQpaMenus) << __FUNCTION__;

View File

@ -84,6 +84,8 @@ public:
void showPlatformMenuBar() override; void showPlatformMenuBar() override;
static bool useNativeMenus(); static bool useNativeMenus();
static bool queryDarkMode();
static bool queryHighContrast();
void refreshFonts(); void refreshFonts();