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ø <tor.arne.vestbo@qt.io>
This commit is contained in:
parent
8c943392ae
commit
4ac89dad78
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
};
|
||||
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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 ?
|
||||
|
@ -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;
|
||||
|
@ -33,6 +33,7 @@ public:
|
||||
|
||||
Qt::ColorScheme colorScheme() const override;
|
||||
void requestColorScheme(Qt::ColorScheme scheme) override;
|
||||
Qt::ContrastPreference contrastPreference() const override;
|
||||
|
||||
static void handleSettingsChanged();
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user