diff --git a/src/plugins/platforms/wasm/qwasmtheme.cpp b/src/plugins/platforms/wasm/qwasmtheme.cpp index 37abb309bff..b9340f31275 100644 --- a/src/plugins/platforms/wasm/qwasmtheme.cpp +++ b/src/plugins/platforms/wasm/qwasmtheme.cpp @@ -5,32 +5,55 @@ #include #include #include +#include #include #include -#include - #include #include #include Q_GUI_EXPORT QPalette qt_fusionPalette(); -Qt::ColorScheme QWasmTheme::s_autoColorScheme = Qt::ColorScheme::Unknown; -bool QWasmTheme::s_autoPaletteIsDirty = false; - QT_BEGIN_NAMESPACE +Q_STATIC_LOGGING_CATEGORY(lcQpaThemeWasm, "qt.qpa.theme.wasm") + +namespace { +bool matchMedia(std::string mediaQueryString) +{ + return emscripten::val::global("window") + .call("matchMedia", mediaQueryString)["matches"] + .as(); +} + +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; QWasmTheme::QWasmTheme() { - if (emscripten::val::global("window").call( - "matchMedia", - std::string("(prefers-color-scheme:dark)"))["matches"].as()) - s_autoColorScheme = Qt::ColorScheme::Dark; - else - s_autoColorScheme = Qt::ColorScheme::Light; + m_colorScheme = getColorSchemeFromMedia(); + qCDebug(lcQpaThemeWasm) << "Initializing Wasm theme. Color scheme: " << m_colorScheme; + m_contrastPreference = getContrastPreferenceFromMedia(); + qCDebug(lcQpaThemeWasm) << "Initializing Wasm theme. Contrast preference: " << m_contrastPreference; for (auto family : QFontDatabase::families()) if (QFontDatabase::isFixedPitch(family)) @@ -39,15 +62,15 @@ QWasmTheme::QWasmTheme() m_palette = std::make_unique(); m_paletteIsDirty = true; // Force update later - const auto callback = [=](emscripten::val event) { QWasmTheme::onColorSchemeChange(event); }; - const emscripten::val window = emscripten::val::global("window"); - if (!window.isUndefined()) { - const emscripten::val matchMedia = window.call("matchMedia", emscripten::val("(prefers-color-scheme: dark)")); - if (!matchMedia.isUndefined()) { - static auto changeEvent = - std::make_unique(matchMedia, "change", callback); - } - } + registerCallbacks( + { colorSchemePreferenceDark }, + [this](emscripten::val) { QWasmTheme::onColorSchemeChange(); }, + m_colorSchemeChangeCallback); + registerCallbacks( + { contrastPreferenceNoPreference, contrastPreferenceMore, contrastPreferenceLess, + contrastPreferenceCustom }, + [this](emscripten::val) { QWasmTheme::onContrastPreferenceChange(); }, + m_contrastPreferenceChangeCallbacks); } QWasmTheme::~QWasmTheme() @@ -59,9 +82,8 @@ QWasmTheme::~QWasmTheme() const QPalette *QWasmTheme::palette(Palette type) const { if (type == SystemPalette) { - if (m_paletteIsDirty || s_autoPaletteIsDirty) { + if (m_paletteIsDirty) { m_paletteIsDirty = false; - s_autoPaletteIsDirty = false; *m_palette = qt_fusionPalette(); } return m_palette.get(); @@ -71,9 +93,7 @@ const QPalette *QWasmTheme::palette(Palette type) const Qt::ColorScheme QWasmTheme::colorScheme() const { - if (m_colorScheme != Qt::ColorScheme::Unknown) - return m_colorScheme; - return s_autoColorScheme; + return m_colorScheme; } 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 { if (hint == QPlatformTheme::StyleNames) @@ -102,20 +127,25 @@ const QFont *QWasmTheme::font(Font type) const return nullptr; } -void QWasmTheme::onColorSchemeChange(emscripten::val event) +void QWasmTheme::onColorSchemeChange() { - const emscripten::val matches = event["matches"]; - if (!matches.isUndefined()) { - const auto oldAutoColorScheme = s_autoColorScheme; - if (matches.as()) - s_autoColorScheme = Qt::ColorScheme::Dark; - else - s_autoColorScheme = Qt::ColorScheme::Light; + auto colorScheme = getColorSchemeFromMedia(); + if (m_colorScheme != colorScheme) { + qCDebug(lcQpaThemeWasm) << "Color scheme changed to " << colorScheme; + m_colorScheme = colorScheme; + m_paletteIsDirty = true; + QWindowSystemInterface::handleThemeChange(); + } +} - if (oldAutoColorScheme != s_autoColorScheme) { - s_autoPaletteIsDirty = true; - QWindowSystemInterface::handleThemeChange(); - } +void QWasmTheme::onContrastPreferenceChange() +{ + auto contrastPreference = getContrastPreferenceFromMedia(); + if (m_contrastPreference != contrastPreference) { + qCDebug(lcQpaThemeWasm) << "Contrast preference changed to " << contrastPreference; + m_contrastPreference = contrastPreference; + m_paletteIsDirty = true; + QWindowSystemInterface::handleThemeChange(); } } diff --git a/src/plugins/platforms/wasm/qwasmtheme.h b/src/plugins/platforms/wasm/qwasmtheme.h index dce1632a5e3..4eaad874c76 100644 --- a/src/plugins/platforms/wasm/qwasmtheme.h +++ b/src/plugins/platforms/wasm/qwasmtheme.h @@ -7,6 +7,10 @@ #include #include +#include + +#include + QT_BEGIN_NAMESPACE class QWasmEventTranslator; @@ -17,6 +21,30 @@ class QWasmScreen; class QWasmCompositor; 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 +void registerCallbacks(std::initializer_list mediaNames, CallbackFn callback, Container &callbacksContainer) +{ + emscripten::val window = emscripten::val::global("window"); + if (!window.isUndefined()) { + for (auto &&mediaName : mediaNames) { + auto media = window.call("matchMedia", emscripten::val(mediaName)); + if constexpr (std::is_same_v>) { + callbacksContainer.emplace_back(media, "change", callback); + } else { + Q_ASSERT(mediaNames.size() == 1); + callbacksContainer = QWasmEventHandler(media, "change", callback); + } + } + } +} + class QWasmTheme : public QPlatformTheme { public: @@ -26,19 +54,21 @@ public: const QPalette *palette(Palette type = SystemPalette) const override; Qt::ColorScheme colorScheme() const override; void requestColorScheme(Qt::ColorScheme scheme) override; + Qt::ContrastPreference contrastPreference() const override; QVariant themeHint(ThemeHint hint) const override; const QFont *font(Font type) const override; QFont *fixedFont = nullptr; - static void onColorSchemeChange(emscripten::val event); + void onColorSchemeChange(); + void onContrastPreferenceChange(); private: Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown; + QWasmEventHandler m_colorSchemeChangeCallback; std::unique_ptr m_palette; mutable bool m_paletteIsDirty = false; - - static Qt::ColorScheme s_autoColorScheme; - static bool s_autoPaletteIsDirty; + Qt::ContrastPreference m_contrastPreference; + std::vector m_contrastPreferenceChangeCallbacks; }; QT_END_NAMESPACE