wasm: Add support for contrastPreference detection to WASM theme
Task-number: QTBUG-133596 Change-Id: I4482fe5a3457579867bd870cb2c8d371dd08e1a0 Reviewed-by: Oliver Eftevaag <oliver.eftevaag@qt.io>
This commit is contained in:
parent
9302945ce3
commit
8f65024d84
@ -5,32 +5,55 @@
|
|||||||
#include <QtCore/qvariant.h>
|
#include <QtCore/qvariant.h>
|
||||||
#include <QFontDatabase>
|
#include <QFontDatabase>
|
||||||
#include <QList>
|
#include <QList>
|
||||||
|
#include <qloggingcategory.h>
|
||||||
#include <qpa/qwindowsysteminterface.h>
|
#include <qpa/qwindowsysteminterface.h>
|
||||||
#include <qpalette.h>
|
#include <qpalette.h>
|
||||||
|
|
||||||
#include <private/qstdweb_p.h>
|
|
||||||
|
|
||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <emscripten/bind.h>
|
#include <emscripten/bind.h>
|
||||||
#include <emscripten/val.h>
|
#include <emscripten/val.h>
|
||||||
|
|
||||||
Q_GUI_EXPORT QPalette qt_fusionPalette();
|
Q_GUI_EXPORT QPalette qt_fusionPalette();
|
||||||
|
|
||||||
Qt::ColorScheme QWasmTheme::s_autoColorScheme = Qt::ColorScheme::Unknown;
|
|
||||||
bool QWasmTheme::s_autoPaletteIsDirty = false;
|
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
Q_STATIC_LOGGING_CATEGORY(lcQpaThemeWasm, "qt.qpa.theme.wasm")
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
bool matchMedia(std::string mediaQueryString)
|
||||||
|
{
|
||||||
|
return emscripten::val::global("window")
|
||||||
|
.call<emscripten::val>("matchMedia", mediaQueryString)["matches"]
|
||||||
|
.as<bool>();
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ColorScheme getColorSchemeFromMedia()
|
||||||
|
{
|
||||||
|
if (matchMedia(colorSchemePreferenceDark)) {
|
||||||
|
return Qt::ColorScheme::Dark;
|
||||||
|
} else {
|
||||||
|
return Qt::ColorScheme::Light;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Qt::ContrastPreference getContrastPreferenceFromMedia()
|
||||||
|
{
|
||||||
|
if (matchMedia(contrastPreferenceMore)) {
|
||||||
|
return Qt::ContrastPreference::HighContrast;
|
||||||
|
} else {
|
||||||
|
return Qt::ContrastPreference::NoPreference;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
using namespace Qt::StringLiterals;
|
using namespace Qt::StringLiterals;
|
||||||
|
|
||||||
QWasmTheme::QWasmTheme()
|
QWasmTheme::QWasmTheme()
|
||||||
{
|
{
|
||||||
if (emscripten::val::global("window").call<emscripten::val>(
|
m_colorScheme = getColorSchemeFromMedia();
|
||||||
"matchMedia",
|
qCDebug(lcQpaThemeWasm) << "Initializing Wasm theme. Color scheme: " << m_colorScheme;
|
||||||
std::string("(prefers-color-scheme:dark)"))["matches"].as<bool>())
|
m_contrastPreference = getContrastPreferenceFromMedia();
|
||||||
s_autoColorScheme = Qt::ColorScheme::Dark;
|
qCDebug(lcQpaThemeWasm) << "Initializing Wasm theme. Contrast preference: " << m_contrastPreference;
|
||||||
else
|
|
||||||
s_autoColorScheme = Qt::ColorScheme::Light;
|
|
||||||
|
|
||||||
for (auto family : QFontDatabase::families())
|
for (auto family : QFontDatabase::families())
|
||||||
if (QFontDatabase::isFixedPitch(family))
|
if (QFontDatabase::isFixedPitch(family))
|
||||||
@ -39,15 +62,15 @@ QWasmTheme::QWasmTheme()
|
|||||||
m_palette = std::make_unique<QPalette>();
|
m_palette = std::make_unique<QPalette>();
|
||||||
m_paletteIsDirty = true; // Force update later
|
m_paletteIsDirty = true; // Force update later
|
||||||
|
|
||||||
const auto callback = [=](emscripten::val event) { QWasmTheme::onColorSchemeChange(event); };
|
registerCallbacks(
|
||||||
const emscripten::val window = emscripten::val::global("window");
|
{ colorSchemePreferenceDark },
|
||||||
if (!window.isUndefined()) {
|
[this](emscripten::val) { QWasmTheme::onColorSchemeChange(); },
|
||||||
const emscripten::val matchMedia = window.call<emscripten::val>("matchMedia", emscripten::val("(prefers-color-scheme: dark)"));
|
m_colorSchemeChangeCallback);
|
||||||
if (!matchMedia.isUndefined()) {
|
registerCallbacks(
|
||||||
static auto changeEvent =
|
{ contrastPreferenceNoPreference, contrastPreferenceMore, contrastPreferenceLess,
|
||||||
std::make_unique<qstdweb::EventCallback>(matchMedia, "change", callback);
|
contrastPreferenceCustom },
|
||||||
}
|
[this](emscripten::val) { QWasmTheme::onContrastPreferenceChange(); },
|
||||||
}
|
m_contrastPreferenceChangeCallbacks);
|
||||||
}
|
}
|
||||||
|
|
||||||
QWasmTheme::~QWasmTheme()
|
QWasmTheme::~QWasmTheme()
|
||||||
@ -59,9 +82,8 @@ QWasmTheme::~QWasmTheme()
|
|||||||
const QPalette *QWasmTheme::palette(Palette type) const
|
const QPalette *QWasmTheme::palette(Palette type) const
|
||||||
{
|
{
|
||||||
if (type == SystemPalette) {
|
if (type == SystemPalette) {
|
||||||
if (m_paletteIsDirty || s_autoPaletteIsDirty) {
|
if (m_paletteIsDirty) {
|
||||||
m_paletteIsDirty = false;
|
m_paletteIsDirty = false;
|
||||||
s_autoPaletteIsDirty = false;
|
|
||||||
*m_palette = qt_fusionPalette();
|
*m_palette = qt_fusionPalette();
|
||||||
}
|
}
|
||||||
return m_palette.get();
|
return m_palette.get();
|
||||||
@ -71,9 +93,7 @@ const QPalette *QWasmTheme::palette(Palette type) const
|
|||||||
|
|
||||||
Qt::ColorScheme QWasmTheme::colorScheme() const
|
Qt::ColorScheme QWasmTheme::colorScheme() const
|
||||||
{
|
{
|
||||||
if (m_colorScheme != Qt::ColorScheme::Unknown)
|
return m_colorScheme;
|
||||||
return m_colorScheme;
|
|
||||||
return s_autoColorScheme;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmTheme::requestColorScheme(Qt::ColorScheme scheme)
|
void QWasmTheme::requestColorScheme(Qt::ColorScheme scheme)
|
||||||
@ -85,6 +105,11 @@ void QWasmTheme::requestColorScheme(Qt::ColorScheme scheme)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Qt::ContrastPreference QWasmTheme::contrastPreference() const
|
||||||
|
{
|
||||||
|
return m_contrastPreference;
|
||||||
|
}
|
||||||
|
|
||||||
QVariant QWasmTheme::themeHint(ThemeHint hint) const
|
QVariant QWasmTheme::themeHint(ThemeHint hint) const
|
||||||
{
|
{
|
||||||
if (hint == QPlatformTheme::StyleNames)
|
if (hint == QPlatformTheme::StyleNames)
|
||||||
@ -102,20 +127,25 @@ const QFont *QWasmTheme::font(Font type) const
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void QWasmTheme::onColorSchemeChange(emscripten::val event)
|
void QWasmTheme::onColorSchemeChange()
|
||||||
{
|
{
|
||||||
const emscripten::val matches = event["matches"];
|
auto colorScheme = getColorSchemeFromMedia();
|
||||||
if (!matches.isUndefined()) {
|
if (m_colorScheme != colorScheme) {
|
||||||
const auto oldAutoColorScheme = s_autoColorScheme;
|
qCDebug(lcQpaThemeWasm) << "Color scheme changed to " << colorScheme;
|
||||||
if (matches.as<int>())
|
m_colorScheme = colorScheme;
|
||||||
s_autoColorScheme = Qt::ColorScheme::Dark;
|
m_paletteIsDirty = true;
|
||||||
else
|
QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
|
||||||
s_autoColorScheme = Qt::ColorScheme::Light;
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (oldAutoColorScheme != s_autoColorScheme) {
|
void QWasmTheme::onContrastPreferenceChange()
|
||||||
s_autoPaletteIsDirty = true;
|
{
|
||||||
QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
|
auto contrastPreference = getContrastPreferenceFromMedia();
|
||||||
}
|
if (m_contrastPreference != contrastPreference) {
|
||||||
|
qCDebug(lcQpaThemeWasm) << "Contrast preference changed to " << contrastPreference;
|
||||||
|
m_contrastPreference = contrastPreference;
|
||||||
|
m_paletteIsDirty = true;
|
||||||
|
QWindowSystemInterface::handleThemeChange<QWindowSystemInterface::SynchronousDelivery>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -7,6 +7,10 @@
|
|||||||
#include <qpa/qplatformtheme.h>
|
#include <qpa/qplatformtheme.h>
|
||||||
#include <QtGui/QFont>
|
#include <QtGui/QFont>
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
|
#include <private/qstdweb_p.h>
|
||||||
|
|
||||||
QT_BEGIN_NAMESPACE
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class QWasmEventTranslator;
|
class QWasmEventTranslator;
|
||||||
@ -17,6 +21,30 @@ class QWasmScreen;
|
|||||||
class QWasmCompositor;
|
class QWasmCompositor;
|
||||||
class QWasmBackingStore;
|
class QWasmBackingStore;
|
||||||
|
|
||||||
|
// this reflects @media/prefers-contrast
|
||||||
|
constexpr auto colorSchemePreferenceDark = "(prefers-color-scheme: dark)";
|
||||||
|
constexpr auto contrastPreferenceNoPreference = "(prefers-contrast: no-preference)";
|
||||||
|
constexpr auto contrastPreferenceMore = "(prefers-contrast: more)";
|
||||||
|
constexpr auto contrastPreferenceLess = "(prefers-contrast: less)";
|
||||||
|
constexpr auto contrastPreferenceCustom = "(prefers-contrast: custom)";
|
||||||
|
|
||||||
|
template <typename MediaName, typename CallbackFn, typename Container>
|
||||||
|
void registerCallbacks(std::initializer_list<MediaName> mediaNames, CallbackFn callback, Container &callbacksContainer)
|
||||||
|
{
|
||||||
|
emscripten::val window = emscripten::val::global("window");
|
||||||
|
if (!window.isUndefined()) {
|
||||||
|
for (auto &&mediaName : mediaNames) {
|
||||||
|
auto media = window.call<emscripten::val>("matchMedia", emscripten::val(mediaName));
|
||||||
|
if constexpr (std::is_same_v<Container, std::vector<QWasmEventHandler>>) {
|
||||||
|
callbacksContainer.emplace_back(media, "change", callback);
|
||||||
|
} else {
|
||||||
|
Q_ASSERT(mediaNames.size() == 1);
|
||||||
|
callbacksContainer = QWasmEventHandler(media, "change", callback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class QWasmTheme : public QPlatformTheme
|
class QWasmTheme : public QPlatformTheme
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
@ -26,19 +54,21 @@ public:
|
|||||||
const QPalette *palette(Palette type = SystemPalette) const override;
|
const QPalette *palette(Palette type = SystemPalette) const override;
|
||||||
Qt::ColorScheme colorScheme() const override;
|
Qt::ColorScheme colorScheme() const override;
|
||||||
void requestColorScheme(Qt::ColorScheme scheme) override;
|
void requestColorScheme(Qt::ColorScheme scheme) override;
|
||||||
|
Qt::ContrastPreference contrastPreference() const override;
|
||||||
QVariant themeHint(ThemeHint hint) const override;
|
QVariant themeHint(ThemeHint hint) const override;
|
||||||
const QFont *font(Font type) const override;
|
const QFont *font(Font type) const override;
|
||||||
QFont *fixedFont = nullptr;
|
QFont *fixedFont = nullptr;
|
||||||
|
|
||||||
static void onColorSchemeChange(emscripten::val event);
|
void onColorSchemeChange();
|
||||||
|
void onContrastPreferenceChange();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
|
Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
|
||||||
|
QWasmEventHandler m_colorSchemeChangeCallback;
|
||||||
std::unique_ptr<QPalette> m_palette;
|
std::unique_ptr<QPalette> m_palette;
|
||||||
mutable bool m_paletteIsDirty = false;
|
mutable bool m_paletteIsDirty = false;
|
||||||
|
Qt::ContrastPreference m_contrastPreference;
|
||||||
static Qt::ColorScheme s_autoColorScheme;
|
std::vector<QWasmEventHandler> m_contrastPreferenceChangeCallbacks;
|
||||||
static bool s_autoPaletteIsDirty;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
Loading…
x
Reference in New Issue
Block a user