summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorOliver Eftevaag <[email protected]>2025-02-20 18:27:50 +0100
committerOliver Eftevaag <[email protected]>2025-03-28 17:44:39 +0100
commit4ac89dad78772ce90649b9846efa17319deba28f (patch)
treee7a2b51b6d7a19e56b8efdb39f8629437ca67601
parent8c943392ae2ae554e496f11d9a3dd6c2c2e762e3 (diff)
Add virtual member QPlatformTheme::contrastPreference()
This function can be overridden by individual platform themes, in order to read contrast settings from the platform's system settings, and report the result back to Qt. This information is relevant for our styles, and can be used to determine color palette values, and additional elements like outline thickness for controls/widgets. Currently only the Windows, macOS, Gnome and Flatpak themes support this feature. Task-number: QTBUG-133595 Change-Id: I3aff519aa7f07c8b2fdcc1e7fb35ec719ab8efcc Reviewed-by: Tor Arne Vestbø <[email protected]>
-rw-r--r--src/corelib/global/qnamespace.h6
-rw-r--r--src/gui/kernel/qplatformtheme.cpp5
-rw-r--r--src/gui/kernel/qplatformtheme.h1
-rw-r--r--src/gui/platform/unix/qdbuslistener.cpp5
-rw-r--r--src/gui/platform/unix/qdbuslistener_p.h3
-rw-r--r--src/gui/platform/unix/qgnometheme.cpp57
-rw-r--r--src/gui/platform/unix/qgnometheme_p.h3
-rw-r--r--src/gui/platform/unix/qkdetheme.cpp14
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.h1
-rw-r--r--src/plugins/platforms/cocoa/qcocoatheme.mm6
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.cpp6
-rw-r--r--src/plugins/platforms/windows/qwindowstheme.h1
-rw-r--r--src/plugins/platformthemes/gtk3/qgtk3theme.cpp2
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp35
-rw-r--r--src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h1
15 files changed, 125 insertions, 21 deletions
diff --git a/src/corelib/global/qnamespace.h b/src/corelib/global/qnamespace.h
index f079a2fc83c..71ec627461c 100644
--- a/src/corelib/global/qnamespace.h
+++ b/src/corelib/global/qnamespace.h
@@ -54,6 +54,11 @@ namespace Qt {
Dark,
};
+ enum class ContrastPreference {
+ NoPreference,
+ HighContrast,
+ };
+
enum MouseButton {
NoButton = 0x00000000,
LeftButton = 0x00000001,
@@ -1786,6 +1791,7 @@ namespace Qt {
Q_ENUM_NS(CursorShape)
Q_ENUM_NS(GlobalColor)
Q_ENUM_NS(ColorScheme)
+ Q_ENUM_NS(ContrastPreference)
Q_ENUM_NS(AspectRatioMode)
Q_ENUM_NS(TransformationMode)
Q_FLAG_NS(ImageConversionFlags)
diff --git a/src/gui/kernel/qplatformtheme.cpp b/src/gui/kernel/qplatformtheme.cpp
index d2a1625bf71..6f840916448 100644
--- a/src/gui/kernel/qplatformtheme.cpp
+++ b/src/gui/kernel/qplatformtheme.cpp
@@ -484,6 +484,11 @@ void QPlatformTheme::requestColorScheme(Qt::ColorScheme scheme)
}
}
+Qt::ContrastPreference QPlatformTheme::contrastPreference() const
+{
+ return Qt::ContrastPreference::NoPreference;
+}
+
/*!
\internal
\brief Return a color palette for type \a type.
diff --git a/src/gui/kernel/qplatformtheme.h b/src/gui/kernel/qplatformtheme.h
index a81d0624db3..c39d1cdcded 100644
--- a/src/gui/kernel/qplatformtheme.h
+++ b/src/gui/kernel/qplatformtheme.h
@@ -319,6 +319,7 @@ public:
virtual QKeySequence standardButtonShortcut(int button) const;
#endif
virtual void requestColorScheme(Qt::ColorScheme scheme);
+ virtual Qt::ContrastPreference contrastPreference() const;
static QVariant defaultThemeHint(ThemeHint hint);
static QString defaultStandardButtonText(int button);
diff --git a/src/gui/platform/unix/qdbuslistener.cpp b/src/gui/platform/unix/qdbuslistener.cpp
index 213d190fa6b..3c8b6f741b2 100644
--- a/src/gui/platform/unix/qdbuslistener.cpp
+++ b/src/gui/platform/unix/qdbuslistener.cpp
@@ -209,6 +209,9 @@ void QDBusListener::populateSignalMap()
m_signalMap.insert(DBusKey("org.freedesktop.appearance"_L1, "color-scheme"_L1),
ChangeSignal(Provider::Gnome, Setting::ColorScheme));
+ m_signalMap.insert(DBusKey("org.freedesktop.appearance"_L1, "contrast"_L1),
+ ChangeSignal(Provider::Gnome, Setting::Contrast));
+
const QString &saveJsonFile = qEnvironmentVariable("QT_QPA_DBUS_SIGNALS_SAVE");
if (!saveJsonFile.isEmpty())
saveJson(saveJsonFile);
@@ -232,6 +235,6 @@ void QDBusListener::onSettingChanged(const QString &location, const QString &key
if (!sig.has_value())
return;
- emit settingChanged(sig.value().provider, sig.value().setting, value.variant().toString());
+ emit settingChanged(sig.value().provider, sig.value().setting, value.variant());
}
QT_END_NAMESPACE
diff --git a/src/gui/platform/unix/qdbuslistener_p.h b/src/gui/platform/unix/qdbuslistener_p.h
index cde62266177..9e06d20d839 100644
--- a/src/gui/platform/unix/qdbuslistener_p.h
+++ b/src/gui/platform/unix/qdbuslistener_p.h
@@ -38,6 +38,7 @@ public:
Theme,
ApplicationStyle,
ColorScheme,
+ Contrast,
};
Q_ENUM(Setting)
@@ -51,7 +52,7 @@ private Q_SLOTS:
Q_SIGNALS:
void settingChanged(QDBusListener::Provider provider,
QDBusListener::Setting setting,
- const QString &value);
+ const QVariant &value);
private:
struct DBusKey
diff --git a/src/gui/platform/unix/qgnometheme.cpp b/src/gui/platform/unix/qgnometheme.cpp
index 0ed01b5cf72..bce0eca0629 100644
--- a/src/gui/platform/unix/qgnometheme.cpp
+++ b/src/gui/platform/unix/qgnometheme.cpp
@@ -15,6 +15,10 @@
QT_BEGIN_NAMESPACE
+#ifndef QT_NO_DBUS
+Q_STATIC_LOGGING_CATEGORY(lcQpaThemeGnome, "qt.qpa.theme.gnome")
+#endif // QT_NO_DBUS
+
/*!
\class QGnomeTheme
\brief QGnomeTheme is a theme implementation for the Gnome desktop.
@@ -27,7 +31,30 @@ const char *QGnomeTheme::name = "gnome";
QGnomeThemePrivate::QGnomeThemePrivate()
{
#ifndef QT_NO_DBUS
- initDbus();
+ QDBusMessage message = QDBusMessage::createMethodCall(QLatin1String("org.freedesktop.portal.Desktop"),
+ QLatin1String("/org/freedesktop/portal/desktop"),
+ QLatin1String("org.freedesktop.portal.Settings"),
+ QLatin1String("ReadOne"));
+ static constexpr QLatin1String appearanceNamespace("org.freedesktop.appearance");
+ static constexpr QLatin1String contrastKey("contrast");
+
+ message << appearanceNamespace << contrastKey;
+
+ QDBusConnection dbus = QDBusConnection::sessionBus();
+ if (!dbus.isConnected())
+ qCWarning(lcQpaThemeGnome) << "dbus connection failed. Last error: " << dbus.lastError();
+
+ QDBusPendingCall pendingCall = dbus.asyncCall(message);
+ QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
+ QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, [this](QDBusPendingCallWatcher *watcher) {
+ if (!watcher->isError()) {
+ QDBusPendingReply<QVariant> reply = *watcher;
+ if (Q_LIKELY(reply.isValid()))
+ m_contrast = static_cast<Qt::ContrastPreference>(reply.value().toUInt());
+ }
+ watcher->deleteLater();
+ initDbus();
+ });
#endif // QT_NO_DBUS
}
QGnomeThemePrivate::~QGnomeThemePrivate()
@@ -60,14 +87,22 @@ bool QGnomeThemePrivate::initDbus()
// Wrap slot in a lambda to avoid inheriting QGnomeThemePrivate from QObject
auto wrapper = [this](QDBusListener::Provider provider,
QDBusListener::Setting setting,
- const QString &value) {
+ const QVariant &value) {
if (provider != QDBusListener::Provider::Gnome
&& provider != QDBusListener::Provider::Gtk) {
return;
}
- if (setting == QDBusListener::Setting::Theme)
- updateColorScheme(value);
+ switch (setting) {
+ case QDBusListener::Setting::Theme:
+ updateColorScheme(value.toString());
+ break;
+ case QDBusListener::Setting::Contrast:
+ updateHighContrast(static_cast<Qt::ContrastPreference>(value.toUInt()));
+ break;
+ default:
+ break;
+ }
};
return QObject::connect(dbus.get(), &QDBusListener::settingChanged, dbus.get(), wrapper);
@@ -87,6 +122,15 @@ void QGnomeThemePrivate::updateColorScheme(const QString &themeName)
if (oldColorScheme != m_colorScheme)
QWindowSystemInterface::handleThemeChange();
}
+
+void QGnomeThemePrivate::updateHighContrast(Qt::ContrastPreference contrast)
+{
+ if (m_contrast == contrast)
+ return;
+ m_contrast = contrast;
+ QWindowSystemInterface::handleThemeChange();
+}
+
#endif // QT_NO_DBUS
QGnomeTheme::QGnomeTheme()
@@ -181,6 +225,11 @@ Qt::ColorScheme QGnomeTheme::colorScheme() const
return d_func()->m_colorScheme;
}
+Qt::ContrastPreference QGnomeTheme::contrastPreference() const
+{
+ return d_func()->m_contrast;
+}
+
#endif
#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
diff --git a/src/gui/platform/unix/qgnometheme_p.h b/src/gui/platform/unix/qgnometheme_p.h
index 310af45ecb5..490aa2a4b16 100644
--- a/src/gui/platform/unix/qgnometheme_p.h
+++ b/src/gui/platform/unix/qgnometheme_p.h
@@ -41,6 +41,7 @@ public:
#ifndef QT_NO_DBUS
QPlatformMenuBar *createPlatformMenuBar() const override;
Qt::ColorScheme colorScheme() const override;
+ Qt::ContrastPreference contrastPreference() const override;
#endif
#if !defined(QT_NO_DBUS) && !defined(QT_NO_SYSTEMTRAYICON)
QPlatformSystemTrayIcon *createPlatformSystemTrayIcon() const override;
@@ -62,10 +63,12 @@ public:
#ifndef QT_NO_DBUS
Qt::ColorScheme m_colorScheme = Qt::ColorScheme::Unknown;
+ Qt::ContrastPreference m_contrast = Qt::ContrastPreference::NoPreference;
private:
std::unique_ptr<QDBusListener> dbus;
bool initDbus();
void updateColorScheme(const QString &themeName);
+ void updateHighContrast(Qt::ContrastPreference contrast);
#endif // QT_NO_DBUS
};
diff --git a/src/gui/platform/unix/qkdetheme.cpp b/src/gui/platform/unix/qkdetheme.cpp
index 07df7124430..af6edbc3f8f 100644
--- a/src/gui/platform/unix/qkdetheme.cpp
+++ b/src/gui/platform/unix/qkdetheme.cpp
@@ -114,7 +114,7 @@ private:
bool initDbus();
void settingChangedHandler(QDBusListener::Provider provider,
QDBusListener::Setting setting,
- const QString &value);
+ const QVariant &value);
Qt::ColorScheme colorSchemeFromPalette() const;
#endif // QT_NO_DBUS
void clearResources();
@@ -123,21 +123,23 @@ private:
#ifndef QT_NO_DBUS
void QKdeThemePrivate::settingChangedHandler(QDBusListener::Provider provider,
QDBusListener::Setting setting,
- const QString &value)
+ const QVariant &value)
{
if (provider != QDBusListener::Provider::Kde)
return;
switch (setting) {
case QDBusListener::Setting::ColorScheme:
- qCDebug(lcQpaThemeKde) << "KDE color theme changed to:" << value;
+ qCDebug(lcQpaThemeKde) << "KDE color theme changed to:" << value.toUInt();
break;
case QDBusListener::Setting::Theme:
- qCDebug(lcQpaThemeKde) << "KDE global theme changed to:" << value;
+ qCDebug(lcQpaThemeKde) << "KDE global theme changed to:" << value.toString();
break;
case QDBusListener::Setting::ApplicationStyle:
- qCDebug(lcQpaThemeKde) << "KDE application style changed to:" << value;
+ qCDebug(lcQpaThemeKde) << "KDE application style changed to:" << value.toString();
break;
+ case QDBusListener::Setting::Contrast:
+ qCDebug(lcQpaThemeKde) << "KDE contrast setting changed to: " << static_cast<Qt::ContrastPreference>(value.toUInt());
}
refresh();
@@ -158,7 +160,7 @@ bool QKdeThemePrivate::initDbus()
// Wrap slot in a lambda to avoid inheriting QKdeThemePrivate from QObject
auto wrapper = [this](QDBusListener::Provider provider,
QDBusListener::Setting setting,
- const QString &value) {
+ const QVariant &value) {
settingChangedHandler(provider, setting, value);
};
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.h b/src/plugins/platforms/cocoa/qcocoatheme.h
index 97e0f633a79..986901362b3 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.h
+++ b/src/plugins/platforms/cocoa/qcocoatheme.h
@@ -39,6 +39,7 @@ public:
QVariant themeHint(ThemeHint hint) const override;
Qt::ColorScheme colorScheme() const override;
+ Qt::ContrastPreference contrastPreference() const override;
QString standardButtonText(int button) const override;
QKeySequence standardButtonShortcut(int button) const override;
diff --git a/src/plugins/platforms/cocoa/qcocoatheme.mm b/src/plugins/platforms/cocoa/qcocoatheme.mm
index 507c5d775f9..2ce621c27aa 100644
--- a/src/plugins/platforms/cocoa/qcocoatheme.mm
+++ b/src/plugins/platforms/cocoa/qcocoatheme.mm
@@ -508,6 +508,12 @@ void QCocoaTheme::updateColorScheme()
m_colorScheme = qt_mac_applicationIsInDarkMode() ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light;
}
+Qt::ContrastPreference QCocoaTheme::contrastPreference() const
+{
+ return NSWorkspace.sharedWorkspace.accessibilityDisplayShouldIncreaseContrast ? Qt::ContrastPreference::HighContrast
+ : Qt::ContrastPreference::NoPreference;
+}
+
QString QCocoaTheme::standardButtonText(int button) const
{
return button == QPlatformDialogHelper::Discard ?
diff --git a/src/plugins/platforms/windows/qwindowstheme.cpp b/src/plugins/platforms/windows/qwindowstheme.cpp
index 7881720d338..fd09fc5f00d 100644
--- a/src/plugins/platforms/windows/qwindowstheme.cpp
+++ b/src/plugins/platforms/windows/qwindowstheme.cpp
@@ -597,6 +597,12 @@ void QWindowsTheme::requestColorScheme(Qt::ColorScheme scheme)
handleSettingsChanged();
}
+Qt::ContrastPreference QWindowsTheme::contrastPreference() const
+{
+ return queryHighContrast() ? Qt::ContrastPreference::HighContrast
+ : Qt::ContrastPreference::NoPreference;
+}
+
void QWindowsTheme::handleSettingsChanged()
{
const auto oldColorScheme = s_colorScheme;
diff --git a/src/plugins/platforms/windows/qwindowstheme.h b/src/plugins/platforms/windows/qwindowstheme.h
index a89fb1e5bd1..5901b14dce2 100644
--- a/src/plugins/platforms/windows/qwindowstheme.h
+++ b/src/plugins/platforms/windows/qwindowstheme.h
@@ -33,6 +33,7 @@ public:
Qt::ColorScheme colorScheme() const override;
void requestColorScheme(Qt::ColorScheme scheme) override;
+ Qt::ContrastPreference contrastPreference() const override;
static void handleSettingsChanged();
diff --git a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
index 25decb235b7..93aa9f33eb7 100644
--- a/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
+++ b/src/plugins/platformthemes/gtk3/qgtk3theme.cpp
@@ -233,7 +233,7 @@ const QPalette *QGtk3Theme::palette(Palette type) const
#ifdef QT_DEBUG
if (m_requestedColorScheme != Qt::ColorScheme::Unknown
&& m_requestedColorScheme != m_storage->colorScheme()) {
- qCDebug(lcQGtk3Interface) << "Current KDE theme doesn't support reuqested color scheme"
+ qCDebug(lcQGtk3Interface) << "Current KDE theme doesn't support requested color scheme"
<< m_requestedColorScheme << "Falling back to fusion palette.";
return QPlatformTheme::palette(type);
}
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
index 2b3fb2b9494..951c1833106 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.cpp
@@ -20,6 +20,10 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+static constexpr QLatin1StringView appearanceInterface("org.freedesktop.appearance");
+static constexpr QLatin1StringView colorSchemeKey("color-scheme");
+static constexpr QLatin1StringView contrastKey("contrast");
+
class QXdgDesktopPortalThemePrivate : public QObject
{
Q_OBJECT
@@ -67,9 +71,14 @@ public Q_SLOTS:
void settingChanged(const QString &group, const QString &key,
const QDBusVariant &value)
{
- if (group == "org.freedesktop.appearance"_L1 && key == "color-scheme"_L1) {
- colorScheme = colorSchemeFromXdgPref(static_cast<XdgColorschemePref>(value.variant().toUInt()));
- QWindowSystemInterface::handleThemeChange();
+ if (group == appearanceInterface) {
+ if (key == colorSchemeKey) {
+ colorScheme = colorSchemeFromXdgPref(static_cast<XdgColorschemePref>(value.variant().toUInt()));
+ QWindowSystemInterface::handleThemeChange();
+ } else if (key == contrastKey) {
+ contrast = static_cast<Qt::ContrastPreference>(value.variant().toUInt());
+ QWindowSystemInterface::handleThemeChange();
+ }
}
}
@@ -77,6 +86,7 @@ public:
QPlatformTheme *baseTheme = nullptr;
uint fileChooserPortalVersion = 0;
Qt::ColorScheme colorScheme = Qt::ColorScheme::Unknown;
+ Qt::ContrastPreference contrast = Qt::ContrastPreference::NoPreference;
};
QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
@@ -123,15 +133,18 @@ QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
"/org/freedesktop/portal/desktop"_L1,
"org.freedesktop.portal.Settings"_L1,
- "Read"_L1);
- message << "org.freedesktop.appearance"_L1 << "color-scheme"_L1;
+ "ReadAll"_L1);
+ message << appearanceInterface;
// this must not be asyncCall() because we have to set appearance now
QDBusReply<QVariant> reply = QDBusConnection::sessionBus().call(message);
if (reply.isValid()) {
- const QDBusVariant dbusVariant = qvariant_cast<QDBusVariant>(reply.value());
- const QXdgDesktopPortalThemePrivate::XdgColorschemePref xdgPref = static_cast<QXdgDesktopPortalThemePrivate::XdgColorschemePref>(dbusVariant.variant().toUInt());
- d->colorScheme = QXdgDesktopPortalThemePrivate::colorSchemeFromXdgPref(xdgPref);
+ const QMap<QString, QVariantMap> settingsMap = qvariant_cast<QMap<QString, QVariantMap>>(reply.value());
+ if (!settingsMap.isEmpty()) {
+ const auto xdgColorSchemePref = static_cast<QXdgDesktopPortalThemePrivate::XdgColorschemePref>(settingsMap.value(appearanceInterface).value(colorSchemeKey).toUInt());
+ d->colorScheme = QXdgDesktopPortalThemePrivate::colorSchemeFromXdgPref(xdgColorSchemePref);
+ d->contrast = static_cast<Qt::ContrastPreference>(settingsMap.value(appearanceInterface).value(contrastKey).toUInt());
+ }
}
QDBusConnection::sessionBus().connect(
@@ -225,6 +238,12 @@ Qt::ColorScheme QXdgDesktopPortalTheme::colorScheme() const
return d->colorScheme;
}
+Qt::ContrastPreference QXdgDesktopPortalTheme::contrastPreference() const
+{
+ Q_D(const QXdgDesktopPortalTheme);
+ return d->contrast;
+}
+
QPixmap QXdgDesktopPortalTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
{
Q_D(const QXdgDesktopPortalTheme);
diff --git a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
index 19329f53a4e..ca2f83fddb9 100644
--- a/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
+++ b/src/plugins/platformthemes/xdgdesktopportal/qxdgdesktopportaltheme.h
@@ -35,6 +35,7 @@ public:
QVariant themeHint(ThemeHint hint) const override;
Qt::ColorScheme colorScheme() const override;
+ Qt::ContrastPreference contrastPreference() const override;
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override;
QIcon fileIcon(const QFileInfo &fileInfo,