From 2fe9eed3fdd5e7a7a3ebd16f5f683dc84a1eab4c Mon Sep 17 00:00:00 2001 From: MohammadHossein Qanbari Date: Wed, 23 Apr 2025 16:04:55 +0200 Subject: [PATCH] QGnomeTheme, QGtk3Theme: Refactor and Simplify DBus Interactions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This patch refactors the DBus integration in both QGnomeTheme and QGtk3Theme to centralize and simplify the portal and settings access logic. Previously, the codebase contained duplicated and scattered DBus logic for querying GNOME/GTK appearance settings, such as color scheme and contrast, which were implemented separately in both QGnomeTheme and QGtk3Theme. The patch introduces a new QGnomePortalInterface class which encapsulates all DBus interactions related to GNOME/GTK appearance settings. The old DBus interface logic is removed from QGtk3Theme and QGnomeTheme, and replaced with calls to the unified QGnomePortalInterface. The update also ensures signal-based updates for theme and appearance changes via the new interface. Change-Id: I5440f7ac00f956b846b18bd890113af0044482f0 Reviewed-by: Oliver Eftevaag Reviewed-by: Morten Johan Sørvig --- src/gui/CMakeLists.txt | 6 + src/gui/platform/unix/qdbuslistener.cpp | 50 +-- src/gui/platform/unix/qdbussettings.cpp | 47 +++ src/gui/platform/unix/qdbussettings_p.h | 46 +++ .../platform/unix/qgnomeportalinterface.cpp | 175 +++++++++++ .../platform/unix/qgnomeportalinterface_p.h | 63 ++++ src/gui/platform/unix/qgnometheme.cpp | 291 ++++-------------- src/gui/platform/unix/qgnometheme_p.h | 52 ++-- src/gui/platform/unix/qkdetheme.cpp | 2 +- .../platformthemes/gtk3/CMakeLists.txt | 2 - .../gtk3/qgtk3portalinterface.cpp | 123 -------- .../gtk3/qgtk3portalinterface_p.h | 49 --- .../platformthemes/gtk3/qgtk3storage.cpp | 7 +- .../platformthemes/gtk3/qgtk3storage_p.h | 11 +- .../platformthemes/gtk3/qgtk3theme.cpp | 63 ++-- src/plugins/platformthemes/gtk3/qgtk3theme.h | 5 +- 16 files changed, 504 insertions(+), 488 deletions(-) create mode 100644 src/gui/platform/unix/qdbussettings.cpp create mode 100644 src/gui/platform/unix/qdbussettings_p.h create mode 100644 src/gui/platform/unix/qgnomeportalinterface.cpp create mode 100644 src/gui/platform/unix/qgnomeportalinterface_p.h delete mode 100644 src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp delete mode 100644 src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h diff --git a/src/gui/CMakeLists.txt b/src/gui/CMakeLists.txt index 024bcfab426..db7c0590611 100644 --- a/src/gui/CMakeLists.txt +++ b/src/gui/CMakeLists.txt @@ -1059,6 +1059,11 @@ qt_internal_extend_target(Gui CONDITION UNIX AND (QT_FEATURE_xcb OR NOT MACOS) A platform/unix/qgnometheme_p.h platform/unix/qgnometheme.cpp ) +qt_internal_extend_target(Gui CONDITION UNIX AND QT_FEATURE_dbus AND (QT_FEATURE_xcb OR QT_FEATURE_wayland) + SOURCES + platform/unix/qgnomeportalinterface.cpp platform/unix/qgnomeportalinterface_p.h +) + qt_internal_extend_target(Gui CONDITION TARGET Qt::DBus AND UNIX AND (QT_FEATURE_xcb OR NOT MACOS) AND (QT_FEATURE_xcb OR NOT UIKIT) SOURCES platform/unix/dbusmenu/qdbusmenuadaptor.cpp platform/unix/dbusmenu/qdbusmenuadaptor_p.h @@ -1068,6 +1073,7 @@ qt_internal_extend_target(Gui CONDITION TARGET Qt::DBus AND UNIX AND (QT_FEATURE platform/unix/dbusmenu/qdbusmenutypes.cpp platform/unix/dbusmenu/qdbusmenutypes_p.h platform/unix/dbusmenu/qdbusplatformmenu.cpp platform/unix/dbusmenu/qdbusplatformmenu_p.h platform/unix/qdbuslistener_p.h platform/unix/qdbuslistener.cpp + platform/unix/qdbussettings_p.h platform/unix/qdbussettings.cpp ) qt_internal_extend_target(Gui CONDITION QT_FEATURE_systemtrayicon AND TARGET Qt::DBus AND UNIX AND (QT_FEATURE_xcb OR NOT MACOS) AND (QT_FEATURE_xcb OR NOT UIKIT) diff --git a/src/gui/platform/unix/qdbuslistener.cpp b/src/gui/platform/unix/qdbuslistener.cpp index 374b3a0f8ec..5057931b12d 100644 --- a/src/gui/platform/unix/qdbuslistener.cpp +++ b/src/gui/platform/unix/qdbuslistener.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only #include "qdbuslistener_p.h" +#include "qdbussettings_p.h" #include #include #include @@ -48,38 +49,6 @@ constexpr auto setting() { return "Setting"_L1; } constexpr auto dbusSignals() { return "DbusSignals"_L1; } constexpr auto root() { return "Q_L1.qpa.DBusSignals"_L1; } } // namespace JsonKeys - -namespace XdgSettings { -// XDG Desktop Portal Settings (Preferred) -// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html -constexpr auto contrastNamespace = "org.freedesktop.appearance"_L1; -constexpr auto contrastKey = "contrast"_L1; -// XDG portal provides the contrast preference value as uint: -// 0 for no-preference, and, 1 for high-contrast. -Qt::ContrastPreference convertContrastPreference(const QVariant &value) -{ - if (!value.isValid()) - return Qt::ContrastPreference::NoPreference; - return static_cast(value.toUInt()); -} -} // namespace XdgSettings - -namespace GSettings { -// GNOME Destop Settings (Alternative) -// https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2069 -// https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas/-/commit/0e97f1f571c495184f80d875c68f241261a50e30 -constexpr auto contrastNamespace = "org.gnome.desktop.a11y.interface"_L1; -constexpr auto contrastKey = "high-contrast"_L1; -// GSetting provides the contrast value as boolean: -// true for enabled high-contrast, and, false for disabled high-contrast. -Qt::ContrastPreference convertContrastPreference(const QVariant &value) -{ - if (!value.isValid()) - return Qt::ContrastPreference::NoPreference; - return value.toBool() ? Qt::ContrastPreference::HighContrast - : Qt::ContrastPreference::NoPreference; -} -} // namespace GSettings } // namespace void QDBusListener::init(const QString &service, const QString &path, @@ -237,14 +206,15 @@ void QDBusListener::populateSignalMap() m_signalMap.insert(DBusKey("org.gnome.desktop.interface"_L1, "gtk-theme"_L1), ChangeSignal(Provider::Gtk, Setting::Theme)); - m_signalMap.insert(DBusKey("org.freedesktop.appearance"_L1, "color-scheme"_L1), + using namespace QDBusSettings; + m_signalMap.insert(DBusKey(XdgSettings::AppearanceNamespace, XdgSettings::ColorSchemeKey), ChangeSignal(Provider::Gnome, Setting::ColorScheme)); - m_signalMap.insert(DBusKey(XdgSettings::contrastNamespace, XdgSettings::contrastKey), + m_signalMap.insert(DBusKey(XdgSettings::AppearanceNamespace, XdgSettings::ContrastKey), ChangeSignal(Provider::Gnome, Setting::Contrast)); // Alternative solution if XDG desktop portal setting is not accessible, // e.g. when using the XDG portal version 1. - m_signalMap.insert(DBusKey(GSettings::contrastNamespace, GSettings::contrastKey), + m_signalMap.insert(DBusKey(GnomeSettings::AllyNamespace, GnomeSettings::ContrastKey), ChangeSignal(Provider::Gnome, Setting::Contrast)); const QString &saveJsonFile = qEnvironmentVariable("QT_QPA_DBUS_SIGNALS_SAVE"); @@ -274,13 +244,17 @@ void QDBusListener::onSettingChanged(const QString &location, const QString &key QVariant settingValue = value.variant(); switch (setting) { + case Setting::ColorScheme: + settingValue.setValue(QDBusSettings::XdgSettings::convertColorScheme(settingValue)); + break; case Setting::Contrast: + using namespace QDBusSettings; // To unify the value, it's necessary to convert the DBus value to Qt::ContrastPreference. // Then the users of the value don't need to parse the raw value. - if (key == XdgSettings::contrastKey) + if (key == XdgSettings::ContrastKey) settingValue.setValue(XdgSettings::convertContrastPreference(settingValue)); - else if (key == GSettings::contrastKey) - settingValue.setValue(GSettings::convertContrastPreference(settingValue)); + else if (key == GnomeSettings::ContrastKey) + settingValue.setValue(GnomeSettings::convertContrastPreference(settingValue)); else Q_UNREACHABLE_IMPL(); break; diff --git a/src/gui/platform/unix/qdbussettings.cpp b/src/gui/platform/unix/qdbussettings.cpp new file mode 100644 index 00000000000..8d5f5d972bc --- /dev/null +++ b/src/gui/platform/unix/qdbussettings.cpp @@ -0,0 +1,47 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qdbussettings_p.h" +#include + +QT_BEGIN_NAMESPACE + +namespace QDBusSettings::XdgSettings { +// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html +enum class ColorScheme : uint { NoPreference, PreferDark, PreferLight }; +} // namespace QDBusSettings::XdgSettings + +Qt::ContrastPreference QDBusSettings::XdgSettings::convertContrastPreference(const QVariant &value) +{ + // XDG portal provides the contrast preference value as uint: + // 0 for no-preference, and, 1 for high-contrast. + if (!value.isValid()) + return Qt::ContrastPreference::NoPreference; + return static_cast(value.toUInt()); +} + +Qt::ColorScheme QDBusSettings::XdgSettings::convertColorScheme(const QVariant &value) +{ + switch (ColorScheme{ value.toUInt() }) { + case ColorScheme::NoPreference: + return Qt::ColorScheme::Unknown; + case ColorScheme::PreferDark: + return Qt::ColorScheme::Dark; + case ColorScheme::PreferLight: + return Qt::ColorScheme::Light; + } + Q_UNREACHABLE_RETURN(Qt::ColorScheme::Unknown); +} + +Qt::ContrastPreference +QDBusSettings::GnomeSettings::convertContrastPreference(const QVariant &value) +{ + // GSetting provides the contrast value as boolean: + // true for enabled high-contrast, and, false for disabled high-contrast. + if (!value.isValid()) + return Qt::ContrastPreference::NoPreference; + return value.toBool() ? Qt::ContrastPreference::HighContrast + : Qt::ContrastPreference::NoPreference; +} + +QT_END_NAMESPACE diff --git a/src/gui/platform/unix/qdbussettings_p.h b/src/gui/platform/unix/qdbussettings_p.h new file mode 100644 index 00000000000..7d7ea476464 --- /dev/null +++ b/src/gui/platform/unix/qdbussettings_p.h @@ -0,0 +1,46 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QDBUSSETTINGS_P_H +#define QDBUSSETTINGS_P_H + +#include +#include +QT_REQUIRE_CONFIG(dbus); + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +QT_BEGIN_NAMESPACE + +namespace QDBusSettings { +// XDG Desktop Portal Settings (Preferred) +// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html +namespace XdgSettings { +static constexpr QLatin1StringView AppearanceNamespace{ "org.freedesktop.appearance" }; +static constexpr QLatin1StringView ColorSchemeKey{ "color-scheme" }; +static constexpr QLatin1StringView ContrastKey{ "contrast" }; +Qt::ContrastPreference convertContrastPreference(const QVariant &value); +Qt::ColorScheme convertColorScheme(const QVariant &value); +} // namespace XdgSettings + +namespace GnomeSettings { +// GNOME Destop Settings (Alternative) +// https://gitlab.gnome.org/GNOME/gnome-shell/-/merge_requests/2069 +// https://gitlab.gnome.org/GNOME/gsettings-desktop-schemas/-/commit/0e97f1f571c495184f80d875c68f241261a50e30 +static constexpr QLatin1StringView AllyNamespace{ "org.gnome.desktop.a11y.interface" }; +static constexpr QLatin1StringView ContrastKey{ "high-contrast" }; +Qt::ContrastPreference convertContrastPreference(const QVariant &value); +} // namespace GnomeSettings +} // namespace QDBusSettings + +QT_END_NAMESPACE +#endif // QDBUSSETTINGS_P_H diff --git a/src/gui/platform/unix/qgnomeportalinterface.cpp b/src/gui/platform/unix/qgnomeportalinterface.cpp new file mode 100644 index 00000000000..8528ed19328 --- /dev/null +++ b/src/gui/platform/unix/qgnomeportalinterface.cpp @@ -0,0 +1,175 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "qgnomeportalinterface_p.h" +#include "qdbussettings_p.h" +#include +#include +#include +#include +#include + +QT_BEGIN_NAMESPACE + +#if QT_CONFIG(dbus) +Q_STATIC_LOGGING_CATEGORY(lcQpaThemeGnome, "qt.qpa.theme.gnome") +#endif // QT_CONFIG(dbus) + +using namespace Qt::StringLiterals; + +QGnomePortalInterface::QGnomePortalInterface(QObject *parent) + : QObject(parent), m_dbus{ new QDBusListener } +{ + QObject::connect(m_dbus.get(), &QDBusListener::settingChanged, this, + &QGnomePortalInterface::dbusSettingChanged); + + querySettings(); +} + +/*! + \internal + \brief QGnomePortalInterface::colorScheme + This is a getter method for the color-scheme loaded from the DBus portal. + \param fallback indicates the fallback color-scheme. + \return returns the cached color-scheme. If the color-scheme was not loaded + it returns the \a fallback color-scheme. + */ +Qt::ColorScheme QGnomePortalInterface::colorScheme(Qt::ColorScheme fallback) const +{ + if (!m_colorScheme.has_value()) + return fallback; + return m_colorScheme.value(); +} + +/*! + \internal + \brief QGnomePortalInterface::contrastPreference + This is a getter method for the contrast-preference loaded from the DBus portal. + \param fallback indicates the fallback contrast-preference. + \return returns the cached contrast-preference if it was loaded. Otherwise, + returns the \a fallback contrast-preference. + */ +Qt::ContrastPreference +QGnomePortalInterface::contrastPreference(Qt::ContrastPreference fallback) const +{ + if (!m_contrast.has_value()) + return fallback; + return m_contrast.value(); +} + +void QGnomePortalInterface::querySettings() +{ + QDBusConnection dbus = QDBusConnection::sessionBus(); + if (!dbus.isConnected()) { + qCWarning(lcQpaThemeGnome) << "dbus connection failed. Last error: " << dbus.lastError(); + return; + } + + constexpr auto method = "ReadAll"_L1; + auto message = QDBusMessage::createMethodCall(s_service, s_path, s_interface, method); + + message << QStringList{ QDBusSettings::XdgSettings::AppearanceNamespace, + QDBusSettings::GnomeSettings::AllyNamespace }; + + QDBusPendingCall pendingCall = dbus.asyncCall(message); + QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this); + + auto onWatcherFinished = [&](QDBusPendingCallWatcher *watcher) { + const QDBusMessage reply = watcher->reply(); + if (QDBusMessage::ErrorMessage == reply.type()) { + qCWarning(lcQpaThemeGnome) + << "dbus reply error: [" << reply.errorName() << "]" << reply.errorMessage(); + watcher->deleteLater(); + return; + } + + const auto convertXdgColorScheme = [](const QVariant &value) { + using namespace QDBusSettings::XdgSettings; + return QVariant::fromValue(convertColorScheme(value)); + }; + + constexpr auto XdgContrastKey = QDBusSettings::XdgSettings::ContrastKey; + const auto convertXdgContrast = [](const QVariant &value) { + using namespace QDBusSettings::XdgSettings; + return QVariant::fromValue(convertContrastPreference(value)); + }; + + constexpr auto GnomeContrastKey = QDBusSettings::GnomeSettings::ContrastKey; + const auto convrtGnomeContrast = [](const QVariant &value) { + using namespace QDBusSettings::GnomeSettings; + return QVariant::fromValue(convertContrastPreference(value)); + }; + + const QVariantList &args = reply.arguments(); + for (const QVariant &arg_ : args) { + const QMap arg = qdbus_cast>(arg_); + for (auto aIt = arg.begin(); aIt != arg.end(); ++aIt) { + const QString &namespace_ = aIt.key(); + const QVariantMap &settings = aIt.value(); + for (auto sIt = settings.begin(); sIt != settings.end(); ++sIt) { + const QString &key = sIt.key(); + const QVariant &value = sIt.value(); + if ((key == QDBusSettings::XdgSettings::ColorSchemeKey) + && (namespace_ == QDBusSettings::XdgSettings::AppearanceNamespace)) + dbusSettingChanged(QDBusListener::Provider::Gnome, + QDBusListener::Setting::ColorScheme, + convertXdgColorScheme(value)); + else if ((key == XdgContrastKey) + && (namespace_ == QDBusSettings::XdgSettings::AppearanceNamespace)) + dbusSettingChanged(QDBusListener::Provider::Gnome, + QDBusListener::Setting::Contrast, + convertXdgContrast(value)); + else if ((key == GnomeContrastKey) + && (namespace_ == QDBusSettings::GnomeSettings::AllyNamespace)) + dbusSettingChanged(QDBusListener::Provider::Gnome, + QDBusListener::Setting::Contrast, + convrtGnomeContrast(value)); + } + } + } + watcher->deleteLater(); + }; + connect(watcher, &QDBusPendingCallWatcher::finished, this, onWatcherFinished); +} + +void QGnomePortalInterface::updateColorScheme(Qt::ColorScheme colorScheme) +{ + if (m_colorScheme.has_value() && (m_colorScheme.value() == colorScheme)) + return; + m_colorScheme = colorScheme; + emit colorSchemeChanged(colorScheme); +} + +void QGnomePortalInterface::updateContrast(Qt::ContrastPreference contrast) +{ + if (m_contrast.has_value() && (m_contrast.value() == contrast)) + return; + m_contrast = contrast; + emit contrastChanged(contrast); +} + +void QGnomePortalInterface::dbusSettingChanged(QDBusListener::Provider provider, + QDBusListener::Setting setting, + const QVariant &value) +{ + if (provider != QDBusListener::Provider::Gnome && provider != QDBusListener::Provider::Gtk) + return; + + switch (setting) { + case QDBusListener::Setting::ColorScheme: + updateColorScheme(value.value()); + break; + case QDBusListener::Setting::Contrast: + updateContrast(value.value()); + break; + case QDBusListener::Setting::Theme: + emit themeNameChanged(value.toString()); + break; + default: + break; + } +} + +QT_END_NAMESPACE + +#include "moc_qgnomeportalinterface_p.cpp" diff --git a/src/gui/platform/unix/qgnomeportalinterface_p.h b/src/gui/platform/unix/qgnomeportalinterface_p.h new file mode 100644 index 00000000000..4dee4f310f5 --- /dev/null +++ b/src/gui/platform/unix/qgnomeportalinterface_p.h @@ -0,0 +1,63 @@ +// Copyright (C) 2025 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#ifndef QGNOMEPORTALINTERFACE_P_H +#define QGNOMEPORTALINTERFACE_P_H + +// +// W A R N I N G +// ------------- +// +// This file is not part of the Qt API. It exists purely as an +// implementation detail. This header file may change from version to +// version without notice, or even be removed. +// +// We mean it. +// + +#include +QT_REQUIRE_CONFIG(dbus); + +#include +#include + +QT_BEGIN_NAMESPACE + +class Q_GUI_EXPORT QGnomePortalInterface : public QObject +{ + Q_OBJECT + +public: + QGnomePortalInterface(QObject *parent = nullptr); + ~QGnomePortalInterface() = default; + + Qt::ColorScheme colorScheme(Qt::ColorScheme fallback = Qt::ColorScheme::Unknown) const; + Qt::ContrastPreference contrastPreference( + Qt::ContrastPreference fallback = Qt::ContrastPreference::NoPreference) const; + +private: + void querySettings(); + void updateColorScheme(Qt::ColorScheme colorScheme); + void updateContrast(Qt::ContrastPreference contrast); + +Q_SIGNALS: + void colorSchemeChanged(Qt::ColorScheme); + void contrastChanged(Qt::ContrastPreference); + void themeNameChanged(const QString &themeName); + +private Q_SLOTS: + void dbusSettingChanged(QDBusListener::Provider, QDBusListener::Setting, const QVariant &value); + +private: + mutable uint m_version = 0; // cached version value + std::optional m_colorScheme; + std::optional m_contrast; + std::unique_ptr m_dbus; + static constexpr QLatin1StringView s_service{ "org.freedesktop.portal.Desktop" }; + static constexpr QLatin1StringView s_path{ "/org/freedesktop/portal/desktop" }; + static constexpr QLatin1StringView s_interface{ "org.freedesktop.portal.Settings" }; +}; + +QT_END_NAMESPACE + +#endif // QGNOMEPORTALINTERFACE_P_H diff --git a/src/gui/platform/unix/qgnometheme.cpp b/src/gui/platform/unix/qgnometheme.cpp index 389ea0238aa..a9fb85e15bc 100644 --- a/src/gui/platform/unix/qgnometheme.cpp +++ b/src/gui/platform/unix/qgnometheme.cpp @@ -5,163 +5,13 @@ #include #include #if QT_CONFIG(dbus) -#include "qdbuslistener_p.h" -#include -#include -#include -#include -#include -#include -#include -#include +# include +# include #endif #include QT_BEGIN_NAMESPACE -#if QT_CONFIG(dbus) -Q_STATIC_LOGGING_CATEGORY(lcQpaThemeGnome, "qt.qpa.theme.gnome") - -using namespace Qt::StringLiterals; - -namespace { -// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html -enum class XDG_ColorScheme : uint { NoPreference, PreferDark, PreferLight }; - -constexpr Qt::ColorScheme convertColorScheme(XDG_ColorScheme colorScheme) -{ - switch (colorScheme) { - case XDG_ColorScheme::NoPreference: - return Qt::ColorScheme::Unknown; - case XDG_ColorScheme::PreferDark: - return Qt::ColorScheme::Dark; - case XDG_ColorScheme::PreferLight: - return Qt::ColorScheme::Light; - default: - Q_UNREACHABLE_RETURN(Qt::ColorScheme::Unknown); - break; - } -} - -constexpr XDG_ColorScheme convertColorScheme(Qt::ColorScheme colorScheme) -{ - switch (colorScheme) { - case Qt::ColorScheme::Unknown: - return XDG_ColorScheme::NoPreference; - case Qt::ColorScheme::Light: - return XDG_ColorScheme::PreferLight; - case Qt::ColorScheme::Dark: - return XDG_ColorScheme::PreferDark; - default: - Q_UNREACHABLE_RETURN(XDG_ColorScheme::NoPreference); - break; - } -} - -class DBusInterface -{ - DBusInterface() = delete; - - constexpr static auto Service = "org.freedesktop.portal.Desktop"_L1; - constexpr static auto Path = "/org/freedesktop/portal/desktop"_L1; - -public: - static inline QVariant query(QLatin1StringView interface, QLatin1StringView method, - QLatin1StringView name_space, QLatin1StringView key); - static inline uint queryPortalVersion(); - static inline QLatin1StringView readOneMethod(); - static inline std::optional queryColorScheme(); - static inline std::optional queryContrast(); -}; - -QVariant DBusInterface::query(QLatin1StringView interface, QLatin1StringView method, - QLatin1StringView name_space, QLatin1StringView key) -{ - QDBusConnection dbus = QDBusConnection::sessionBus(); - if (dbus.isConnected()) { - QDBusMessage message = QDBusMessage::createMethodCall( - DBusInterface::Service, DBusInterface::Path, interface, method); - message << name_space << key; - - QDBusReply reply = dbus.call(message); - if (Q_LIKELY(reply.isValid())) - return reply.value(); - } else { - qCWarning(lcQpaThemeGnome) << "dbus connection failed. Last error: " << dbus.lastError(); - } - - return {}; -} - -uint DBusInterface::queryPortalVersion() -{ - constexpr auto interface = "org.freedesktop.DBus.Properties"_L1; - constexpr auto method = "Get"_L1; - constexpr auto name_space = "org.freedesktop.portal.Settings"_L1; - constexpr auto key = "version"_L1; - - static uint version = 0; // cached version value - - if (version == 0) { - QVariant reply = query(interface, method, name_space, key); - if (reply.isValid()) - version = reply.toUInt(); // caches the value for the next calls - } - - return version; -} - -QLatin1StringView DBusInterface::readOneMethod() -{ - // Based on the documentation on flatpak: - // https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html - // The method name "Read" has changed to "ReadOne" since version 2. - const uint version = queryPortalVersion(); - if (version == 1) - return "Read"_L1; - return "ReadOne"_L1; -} - -std::optional DBusInterface::queryColorScheme() -{ - constexpr auto interface = "org.freedesktop.portal.Settings"_L1; - constexpr auto name_space = "org.freedesktop.appearance"_L1; - constexpr auto key = "color-scheme"_L1; - const auto method = readOneMethod(); - - QVariant reply = query(interface, method, name_space, key); - if (reply.isValid()) - return convertColorScheme( - XDG_ColorScheme{ reply.value().variant().toUInt() }); - - return {}; -} - -std::optional DBusInterface::queryContrast() -{ - constexpr auto interface = "org.freedesktop.portal.Settings"_L1; - const auto method = readOneMethod(); - - constexpr auto namespace_xdg_portal = "org.freedesktop.appearance"_L1; - constexpr auto key_xdg_portal = "contrast"_L1; - QVariant reply = query(interface, method, namespace_xdg_portal, key_xdg_portal); - if (reply.isValid()) - return static_cast(reply.toUInt()); - - // Fall back to desktop-specific methods (GSettings for GNOME) - constexpr auto namespace_gsettings = "org.gnome.desktop.a11y.interface"_L1; - constexpr auto key_gsettings = "high-contrast"_L1; - reply = query(interface, method, namespace_gsettings, key_gsettings); - if (reply.isValid()) - return reply.toBool() ? Qt::ContrastPreference::HighContrast - : Qt::ContrastPreference::NoPreference; - - return {}; -} -} // namespace - -#endif // QT_CONFIG(dbus) - /*! \class QGnomeTheme \brief QGnomeTheme is a theme implementation for the Gnome desktop. @@ -174,13 +24,8 @@ const char *QGnomeTheme::name = "gnome"; QGnomeThemePrivate::QGnomeThemePrivate() { #if QT_CONFIG(dbus) - initDbus(); - - if (auto value = DBusInterface::queryColorScheme(); value.has_value()) - updateColorScheme(value.value()); - - if (auto value = DBusInterface::queryContrast(); value.has_value()) - updateHighContrast(value.value()); + QObject::connect(&m_gnomePortal, &QGnomePortalInterface::themeNameChanged, &m_gnomePortal, + [this](const QString &themeName) { m_themeName = themeName; }); #endif // QT_CONFIG(dbus) } @@ -205,43 +50,15 @@ void QGnomeThemePrivate::configureFonts(const QString >kFontName) const qCDebug(lcQpaFonts) << "default fonts: system" << systemFont << "fixed" << fixedFont; } -#if QT_CONFIG(dbus) -bool QGnomeThemePrivate::initDbus() -{ - dbus.reset(new QDBusListener()); - Q_ASSERT(dbus); - - // Wrap slot in a lambda to avoid inheriting QGnomeThemePrivate from QObject - auto wrapper = [this](QDBusListener::Provider provider, - QDBusListener::Setting setting, - const QVariant &value) { - if (provider != QDBusListener::Provider::Gnome - && provider != QDBusListener::Provider::Gtk) { - return; - } - - switch (setting) { - case QDBusListener::Setting::ColorScheme: - updateColorScheme(convertColorScheme(XDG_ColorScheme{ value.toUInt() })); - break; - case QDBusListener::Setting::Theme: - m_themeName = value.toString(); - break; - case QDBusListener::Setting::Contrast: - updateHighContrast(value.value()); - break; - default: - break; - } - }; - - return QObject::connect(dbus.get(), &QDBusListener::settingChanged, dbus.get(), wrapper); -} - Qt::ColorScheme QGnomeThemePrivate::colorScheme() const { - if (m_colorScheme != Qt::ColorScheme::Unknown) - return m_colorScheme; + if (hasRequestedColorScheme()) + return m_requestedColorScheme; + +#if QT_CONFIG(dbus) + if (Qt::ColorScheme colorScheme = m_gnomePortal.colorScheme(); + colorScheme != Qt::ColorScheme::Unknown) + return colorScheme; // If the color scheme is set to Unknown by mistake or is not set at all, // then maybe the theme name contains a hint about the color scheme. @@ -251,31 +68,31 @@ Qt::ColorScheme QGnomeThemePrivate::colorScheme() const return Qt::ColorScheme::Light; else if (m_themeName.contains(QLatin1StringView("dark"), Qt::CaseInsensitive)) return Qt::ColorScheme::Dark; - else - return Qt::ColorScheme::Unknown; -} - -void QGnomeThemePrivate::updateColorScheme(Qt::ColorScheme colorScheme) -{ - if (m_colorScheme == colorScheme) - return; - m_colorScheme = colorScheme; - QWindowSystemInterface::handleThemeChange(); -} - -void QGnomeThemePrivate::updateHighContrast(Qt::ContrastPreference contrast) -{ - if (m_contrast == contrast) - return; - m_contrast = contrast; - QWindowSystemInterface::handleThemeChange(); -} - #endif // QT_CONFIG(dbus) + // Fallback to Unknown if no color scheme is set or detected + return Qt::ColorScheme::Unknown; +} + +bool QGnomeThemePrivate::hasRequestedColorScheme() const +{ + return m_requestedColorScheme != Qt::ColorScheme::Unknown; +} + QGnomeTheme::QGnomeTheme() : QGenericUnixTheme(new QGnomeThemePrivate()) { +#if QT_CONFIG(dbus) + Q_D(QGnomeTheme); + + QGnomePortalInterface *portal = &d->m_gnomePortal; + + QObject::connect(portal, &QGnomePortalInterface::colorSchemeChanged, portal, + [this](Qt::ColorScheme colorScheme) { updateColorScheme(colorScheme); }); + + QObject::connect(portal, &QGnomePortalInterface::contrastChanged, portal, + [this](Qt::ContrastPreference contrast) { updateHighContrast(contrast); }); +#endif // QT_CONFIG(dbus) } QVariant QGnomeTheme::themeHint(QPlatformTheme::ThemeHint hint) const @@ -352,7 +169,38 @@ QString QGnomeTheme::gtkFontName() const .arg(defaultSystemFontSize); } +void QGnomeTheme::requestColorScheme(Qt::ColorScheme scheme) +{ + Q_D(QGnomeTheme); + if (d->m_requestedColorScheme == scheme) + return; + QPlatformTheme::requestColorScheme(scheme); + d->m_requestedColorScheme = scheme; + QWindowSystemInterface::handleThemeChange(); +} + +Qt::ColorScheme QGnomeTheme::colorScheme() const +{ + Q_D(const QGnomeTheme); + if (auto colorScheme = d->colorScheme(); colorScheme != Qt::ColorScheme::Unknown) + return colorScheme; + // If the color scheme is not set or detected, fall back to the default + return QPlatformTheme::colorScheme(); +} + #if QT_CONFIG(dbus) +void QGnomeTheme::updateColorScheme(Qt::ColorScheme colorScheme) +{ + Q_UNUSED(colorScheme); + QWindowSystemInterface::handleThemeChange(); +} + +void QGnomeTheme::updateHighContrast(Qt::ContrastPreference contrast) +{ + Q_UNUSED(contrast); + QWindowSystemInterface::handleThemeChange(); +} + QPlatformMenuBar *QGnomeTheme::createPlatformMenuBar() const { if (isDBusGlobalMenuAvailable()) @@ -360,26 +208,21 @@ QPlatformMenuBar *QGnomeTheme::createPlatformMenuBar() const return nullptr; } -Qt::ColorScheme QGnomeTheme::colorScheme() const -{ - return d_func()->colorScheme(); -} - Qt::ContrastPreference QGnomeTheme::contrastPreference() const { - return d_func()->m_contrast; + Q_D(const QGnomeTheme); + return d->m_gnomePortal.contrastPreference(); } -#endif - -#if QT_CONFIG(dbus) && QT_CONFIG(systemtrayicon) +# if QT_CONFIG(systemtrayicon) QPlatformSystemTrayIcon *QGnomeTheme::createPlatformSystemTrayIcon() const { if (shouldUseDBusTray()) return new QDBusTrayIcon(); return nullptr; } -#endif +# endif // QT_CONFIG(systemtrayicon) +#endif // QT_CONFIG(dbus) QString QGnomeTheme::standardButtonText(int button) const { diff --git a/src/gui/platform/unix/qgnometheme_p.h b/src/gui/platform/unix/qgnometheme_p.h index 9c59646c715..17b91931876 100644 --- a/src/gui/platform/unix/qgnometheme_p.h +++ b/src/gui/platform/unix/qgnometheme_p.h @@ -19,17 +19,19 @@ #include #include #include +#if QT_CONFIG(dbus) +# include "qgnomeportalinterface_p.h" +#endif // QT_CONFIG(dbus) QT_BEGIN_NAMESPACE + class QGnomeThemePrivate; -#if QT_CONFIG(dbus) -class QDBusListener; -class QDBusPendingCallWatcher; -#endif class Q_GUI_EXPORT QGnomeTheme : public QGenericUnixTheme { +protected: Q_DECLARE_PRIVATE(QGnomeTheme) + public: QGnomeTheme(); QVariant themeHint(ThemeHint hint) const override; @@ -39,47 +41,51 @@ public: QString standardButtonText(int button) const override; virtual QString gtkFontName() const; + + virtual void requestColorScheme(Qt::ColorScheme) override; + virtual Qt::ColorScheme colorScheme() const override; + #if QT_CONFIG(dbus) +protected: + virtual void updateColorScheme(Qt::ColorScheme); + virtual void updateHighContrast(Qt::ContrastPreference); + +public: QPlatformMenuBar *createPlatformMenuBar() const override; - Qt::ColorScheme colorScheme() const override; Qt::ContrastPreference contrastPreference() const override; -#endif -#if QT_CONFIG(dbus) && QT_CONFIG(systemtrayicon) + +# if QT_CONFIG(systemtrayicon) QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override; -#endif +# endif // QT_CONFIG(systemtrayicon) +#endif // QT_CONFIG(dbus) static const char *name; }; -class QGnomeThemePrivate : public QGenericUnixThemePrivate +class Q_GUI_EXPORT QGnomeThemePrivate : public QGenericUnixThemePrivate { + friend QGnomeTheme; + public: QGnomeThemePrivate(); ~QGnomeThemePrivate(); void configureFonts(const QString >kFontName) const; + Qt::ColorScheme colorScheme() const; + bool hasRequestedColorScheme() const; + +private: mutable QFont *systemFont = nullptr; mutable QFont *fixedFont = nullptr; + Qt::ColorScheme m_requestedColorScheme = Qt::ColorScheme::Unknown; + #if QT_CONFIG(dbus) - Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown; - Qt::ContrastPreference m_contrast = Qt::ContrastPreference::NoPreference; -private: - std::unique_ptr dbus; - std::unique_ptr pendingCallWatcher; + QGnomePortalInterface m_gnomePortal; QString m_themeName; - -public: - Qt::ColorScheme colorScheme() const; - -private: - bool initDbus(); - void updateColorScheme(Qt::ColorScheme colorScheme); - void updateHighContrast(Qt::ContrastPreference contrast); #endif // QT_CONFIG(dbus) }; - QT_END_NAMESPACE #endif // QGNOMETHEME_P_H diff --git a/src/gui/platform/unix/qkdetheme.cpp b/src/gui/platform/unix/qkdetheme.cpp index c3de0213780..ef1f9b3455c 100644 --- a/src/gui/platform/unix/qkdetheme.cpp +++ b/src/gui/platform/unix/qkdetheme.cpp @@ -130,7 +130,7 @@ void QKdeThemePrivate::settingChangedHandler(QDBusListener::Provider provider, switch (setting) { case QDBusListener::Setting::ColorScheme: - qCDebug(lcQpaThemeKde) << "KDE color theme changed to:" << value.toUInt(); + qCDebug(lcQpaThemeKde) << "KDE color theme changed to:" << value.value(); break; case QDBusListener::Setting::Theme: qCDebug(lcQpaThemeKde) << "KDE global theme changed to:" << value.toString(); diff --git a/src/plugins/platformthemes/gtk3/CMakeLists.txt b/src/plugins/platformthemes/gtk3/CMakeLists.txt index 40c425d367a..6b0613b42fb 100644 --- a/src/plugins/platformthemes/gtk3/CMakeLists.txt +++ b/src/plugins/platformthemes/gtk3/CMakeLists.txt @@ -37,8 +37,6 @@ qt_internal_add_plugin(QGtk3ThemePlugin ) qt_internal_extend_target(QGtk3ThemePlugin CONDITION QT_FEATURE_dbus - SOURCES - qgtk3portalinterface.cpp LIBRARIES Qt::DBus ) diff --git a/src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp b/src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp deleted file mode 100644 index 1ffdda74fa8..00000000000 --- a/src/plugins/platformthemes/gtk3/qgtk3portalinterface.cpp +++ /dev/null @@ -1,123 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include "qgtk3portalinterface_p.h" -#include "qgtk3storage_p.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -QT_BEGIN_NAMESPACE - -Q_LOGGING_CATEGORY(lcQGtk3PortalInterface, "qt.qpa.gtk"); - -using namespace Qt::StringLiterals; - -static constexpr QLatin1StringView appearanceInterface("org.freedesktop.appearance"); -static constexpr QLatin1StringView colorSchemeKey("color-scheme"); - -const QDBusArgument &operator>>(const QDBusArgument &argument, QMap &map) -{ - argument.beginMap(); - map.clear(); - - while (!argument.atEnd()) { - QString key; - QVariantMap value; - argument.beginMapEntry(); - argument >> key >> value; - argument.endMapEntry(); - map.insert(key, value); - } - - argument.endMap(); - return argument; -} - -QGtk3PortalInterface::QGtk3PortalInterface(QGtk3Storage *s) - : m_storage(s) { - qRegisterMetaType(); - qDBusRegisterMetaType>(); - - queryColorScheme(); - - if (!s) { - qCDebug(lcQGtk3PortalInterface) << "QGtk3PortalInterface instantiated without QGtk3Storage." - << "No reaction to runtime theme changes."; - } -} - -Qt::ColorScheme QGtk3PortalInterface::colorScheme() const -{ - return m_colorScheme; -} - -void QGtk3PortalInterface::queryColorScheme() { - QDBusConnection connection = QDBusConnection::sessionBus(); - QDBusMessage message = QDBusMessage::createMethodCall( - "org.freedesktop.portal.Desktop"_L1, - "/org/freedesktop/portal/desktop"_L1, - "org.freedesktop.portal.Settings"_L1, "ReadAll"_L1); - message << QStringList{ appearanceInterface }; - - QDBusPendingCall pendingCall = connection.asyncCall(message); - QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this); - QObject::connect( - watcher, &QDBusPendingCallWatcher::finished, this, - [this](QDBusPendingCallWatcher *watcher) { - QDBusPendingReply> reply = *watcher; - if (reply.isValid()) { - QMap settings = reply.value(); - if (!settings.isEmpty()) { - settingChanged(appearanceInterface, colorSchemeKey, - QDBusVariant(settings.value(appearanceInterface).value(colorSchemeKey))); - } - } else { - qCDebug(lcQGtk3PortalInterface) << "Failed to query org.freedesktop.portal.Settings: " - << reply.error().message(); - } - watcher->deleteLater(); - }); - - QDBusConnection::sessionBus().connect( - "org.freedesktop.portal.Desktop"_L1, "/org/freedesktop/portal/desktop"_L1, - "org.freedesktop.portal.Settings"_L1, "SettingChanged"_L1, this, - SLOT(settingChanged(QString, QString, QDBusVariant))); -} - -void QGtk3PortalInterface::settingChanged(const QString &group, const QString &key, - const QDBusVariant &value) -{ - if (group == appearanceInterface && key == colorSchemeKey) { - const uint colorScheme = value.variant().toUInt(); - // From org.freedesktop.portal.Settings.xml - // "1" - Prefer dark appearance - Qt::ColorScheme newColorScheme = colorScheme == 1 ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light; - if (m_colorScheme != newColorScheme) { - m_colorScheme = newColorScheme; - if (m_storage) - m_storage->handleThemeChange(); - } - } -} - -QT_END_NAMESPACE - -#include "moc_qgtk3portalinterface_p.cpp" diff --git a/src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h b/src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h deleted file mode 100644 index 25a5f58ab1a..00000000000 --- a/src/plugins/platformthemes/gtk3/qgtk3portalinterface_p.h +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (C) 2024 The Qt Company Ltd. -// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only - -#ifndef QGTK3PORTALINTERFACE_H -#define QGTK3PORTALINTERFACE_H - -// -// W A R N I N G -// ------------- -// -// This file is not part of the Qt API. It exists purely as an -// implementation detail. This header file may change from version to -// version without notice, or even be removed. -// -// We mean it. -// - -#include -#include - -QT_BEGIN_NAMESPACE - -class QDBusVariant; -class QGtk3Storage; - -Q_DECLARE_LOGGING_CATEGORY(lcQGtk3PortalInterface); - -class QGtk3PortalInterface : public QObject -{ - Q_OBJECT -public: - QGtk3PortalInterface(QGtk3Storage *s); - ~QGtk3PortalInterface() = default; - - Qt::ColorScheme colorScheme() const; - -private Q_SLOTS: - void settingChanged(const QString &group, const QString &key, - const QDBusVariant &value); -private: - void queryColorScheme(); - - Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown; - QGtk3Storage *m_storage = nullptr; -}; - -QT_END_NAMESPACE - -#endif // QGTK3PORTALINTERFACE_H diff --git a/src/plugins/platformthemes/gtk3/qgtk3storage.cpp b/src/plugins/platformthemes/gtk3/qgtk3storage.cpp index 2991212d033..ae4502183da 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3storage.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3storage.cpp @@ -15,6 +15,9 @@ #include "qgtk3json_p.h" #include "qgtk3storage_p.h" #include +#if QT_CONFIG(dbus) +# include +#endif QT_BEGIN_NAMESPACE @@ -22,11 +25,13 @@ QGtk3Storage::QGtk3Storage() { m_interface.reset(new QGtk3Interface(this)); #if QT_CONFIG(dbus) - m_portalInterface.reset(new QGtk3PortalInterface(this)); + m_portalInterface.reset(new QGnomePortalInterface); #endif populateMap(); } +QGtk3Storage::~QGtk3Storage() { } + /*! \internal \enum QGtk3Storage::SourceType diff --git a/src/plugins/platformthemes/gtk3/qgtk3storage_p.h b/src/plugins/platformthemes/gtk3/qgtk3storage_p.h index 002e916377e..d0668a97216 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3storage_p.h +++ b/src/plugins/platformthemes/gtk3/qgtk3storage_p.h @@ -16,9 +16,6 @@ // #include "qgtk3interface_p.h" -#if QT_CONFIG(dbus) -#include "qgtk3portalinterface_p.h" -#endif #include #include @@ -30,11 +27,17 @@ #include QT_BEGIN_NAMESPACE + +#if QT_CONFIG(dbus) +class QGnomePortalInterface; +#endif + class QGtk3Storage { Q_GADGET public: QGtk3Storage(); + ~QGtk3Storage(); // Enum documented in cpp file. Please keep it in line with updates made here. enum class SourceType { @@ -242,7 +245,7 @@ private: std::unique_ptr m_interface; #if QT_CONFIG(dbus) - std::unique_ptr m_portalInterface; + std::unique_ptr m_portalInterface; #endif Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown; diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp index c1c1e623a27..c720fc41dbd 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp +++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp @@ -163,29 +163,34 @@ QString QGtk3Theme::gtkFontName() const return QGnomeTheme::gtkFontName(); } -void QGtk3Theme::requestColorScheme(Qt::ColorScheme scheme) -{ - if (m_requestedColorScheme == scheme) - return; - qCDebug(lcQGtk3Interface) << scheme << "has been requested. Theme supports color scheme:" - << m_storage->colorScheme(); - QPlatformTheme::requestColorScheme(scheme); - m_requestedColorScheme = scheme; - m_storage->handleThemeChange(); -} - Qt::ColorScheme QGtk3Theme::colorScheme() const { Q_ASSERT(m_storage); + + Q_D(const QGnomeTheme); + const Qt::ColorScheme colorScheme = d->colorScheme(); + const bool hasRequestedColorScheme = d->hasRequestedColorScheme(); + #ifdef QT_DEBUG - if (m_requestedColorScheme != Qt::ColorScheme::Unknown - && m_requestedColorScheme != m_storage->colorScheme()) { - qCDebug(lcQGtk3Interface) << "Requested color scheme" << m_requestedColorScheme + if (hasRequestedColorScheme && colorScheme != m_storage->colorScheme()) { + qCDebug(lcQGtk3Interface) << "Requested color scheme" << colorScheme << "differs from theme color scheme" << m_storage->colorScheme(); } #endif - return m_requestedColorScheme == Qt::ColorScheme::Unknown ? m_storage->colorScheme() - : m_requestedColorScheme; + + return hasRequestedColorScheme ? colorScheme : m_storage->colorScheme(); +} + +void QGtk3Theme::requestColorScheme(Qt::ColorScheme scheme) +{ + const Qt::ColorScheme oldColorScheme = colorScheme(); + QGnomeTheme::requestColorScheme(scheme); + if (oldColorScheme == colorScheme()) + return; + qCDebug(lcQGtk3Interface) << scheme << "has been requested. Theme supports color scheme:" + << m_storage->colorScheme(); + m_storage->handleThemeChange(); + QWindowSystemInterface::sendWindowSystemEvents(QEventLoop::AllEvents); } bool QGtk3Theme::usePlatformNativeDialog(DialogType type) const @@ -234,18 +239,22 @@ bool QGtk3Theme::useNativeFileDialog() const QPalette *QGtk3Theme::palette(Palette type) const { Q_ASSERT(m_storage); + + Q_D(const QGnomeTheme); + const Qt::ColorScheme colorScheme = d->colorScheme(); + const bool hasRequestedColorScheme = d->hasRequestedColorScheme(); + #ifdef QT_DEBUG - if (m_requestedColorScheme != Qt::ColorScheme::Unknown - && m_requestedColorScheme != m_storage->colorScheme()) { + if (hasRequestedColorScheme && colorScheme != m_storage->colorScheme()) { qCDebug(lcQGtk3Interface) << "Current KDE theme doesn't support requested color scheme" - << m_requestedColorScheme << "Falling back to fusion palette."; + << colorScheme << "Falling back to fusion palette."; return QPlatformTheme::palette(type); } #endif - return (m_requestedColorScheme != Qt::ColorScheme::Unknown - && m_requestedColorScheme != m_storage->colorScheme()) - ? QPlatformTheme::palette(type) : m_storage->palette(type); + return (hasRequestedColorScheme && colorScheme != m_storage->colorScheme()) + ? QPlatformTheme::palette(type) + : m_storage->palette(type); } QPixmap QGtk3Theme::standardPixmap(StandardPixmap sp, const QSizeF &size) const @@ -268,4 +277,14 @@ QIcon QGtk3Theme::fileIcon(const QFileInfo &fileInfo, return m_storage->fileIcon(fileInfo); } +#if QT_CONFIG(dbus) +void QGtk3Theme::updateColorScheme(Qt::ColorScheme newColorScheme) +{ + if (newColorScheme == colorScheme()) + QGnomeTheme::updateColorScheme(newColorScheme); + else + m_storage->handleThemeChange(); +} +#endif // QT_CONFIG(dbus) + QT_END_NAMESPACE diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.h b/src/plugins/platformthemes/gtk3/qgtk3theme.h index d2f2efff51f..ce7dc9c9dc8 100644 --- a/src/plugins/platformthemes/gtk3/qgtk3theme.h +++ b/src/plugins/platformthemes/gtk3/qgtk3theme.h @@ -31,8 +31,11 @@ public: QPlatformTheme::IconOptions iconOptions = { }) const override; static const char *name; + private: - Qt::ColorScheme m_requestedColorScheme = Qt::ColorScheme::Unknown; +#if QT_CONFIG(dbus) + void updateColorScheme(Qt::ColorScheme) override; +#endif // QT_CONFIG(dbus) static bool useNativeFileDialog(); std::unique_ptr m_storage; };