13
13
#include < QtDBus/QDBusMessage>
14
14
#include < QtDBus/QDBusPendingCall>
15
15
#include < QtDBus/QDBusReply>
16
+ #include < QtDBus/QDBusVariant>
16
17
#endif
17
18
#include < qpa/qwindowsysteminterface.h>
18
19
@@ -21,6 +22,8 @@ QT_BEGIN_NAMESPACE
21
22
#if QT_CONFIG(dbus)
22
23
Q_STATIC_LOGGING_CATEGORY (lcQpaThemeGnome, " qt.qpa.theme.gnome" )
23
24
25
+ using namespace Qt::StringLiterals;
26
+
24
27
namespace {
25
28
// https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html
26
29
enum class XDG_ColorScheme : uint { NoPreference, PreferDark, PreferLight };
@@ -54,6 +57,107 @@ constexpr XDG_ColorScheme convertColorScheme(Qt::ColorScheme colorScheme)
54
57
break ;
55
58
}
56
59
}
60
+
61
+ class DBusInterface
62
+ {
63
+ DBusInterface () = delete ;
64
+
65
+ constexpr static auto Service = " org.freedesktop.portal.Desktop" _L1;
66
+ constexpr static auto Path = " /org/freedesktop/portal/desktop" _L1;
67
+
68
+ public:
69
+ static inline QVariant query (QLatin1StringView interface, QLatin1StringView method,
70
+ QLatin1StringView name_space, QLatin1StringView key);
71
+ static inline uint queryPortalVersion ();
72
+ static inline QLatin1StringView readOneMethod ();
73
+ static inline std::optional<Qt::ColorScheme> queryColorScheme ();
74
+ static inline std::optional<Qt::ContrastPreference> queryContrast ();
75
+ };
76
+
77
+ QVariant DBusInterface::query (QLatin1StringView interface, QLatin1StringView method,
78
+ QLatin1StringView name_space, QLatin1StringView key)
79
+ {
80
+ QDBusConnection dbus = QDBusConnection::sessionBus ();
81
+ if (dbus.isConnected ()) {
82
+ QDBusMessage message = QDBusMessage::createMethodCall (
83
+ DBusInterface::Service, DBusInterface::Path, interface, method);
84
+ message << name_space << key;
85
+
86
+ QDBusReply<QVariant> reply = dbus.call (message);
87
+ if (Q_LIKELY (reply.isValid ()))
88
+ return reply.value ();
89
+ } else {
90
+ qCWarning (lcQpaThemeGnome) << " dbus connection failed. Last error: " << dbus.lastError ();
91
+ }
92
+
93
+ return {};
94
+ }
95
+
96
+ uint DBusInterface::queryPortalVersion ()
97
+ {
98
+ constexpr auto interface = " org.freedesktop.DBus.Properties" _L1;
99
+ constexpr auto method = " Get" _L1;
100
+ constexpr auto name_space = " org.freedesktop.portal.Settings" _L1;
101
+ constexpr auto key = " version" _L1;
102
+
103
+ static uint version = 0 ; // cached version value
104
+
105
+ if (version == 0 ) {
106
+ QVariant reply = query (interface, method, name_space, key);
107
+ if (reply.isValid ())
108
+ version = reply.toUInt (); // caches the value for the next calls
109
+ }
110
+
111
+ return version;
112
+ }
113
+
114
+ QLatin1StringView DBusInterface::readOneMethod ()
115
+ {
116
+ // Based on the documentation on flatpak:
117
+ // https://flatpak.github.io/xdg-desktop-portal/docs/doc-org.freedesktop.portal.Settings.html
118
+ // The method name "Read" has changed to "ReadOne" since version 2.
119
+ const uint version = queryPortalVersion ();
120
+ if (version == 1 )
121
+ return " Read" _L1;
122
+ return " ReadOne" _L1;
123
+ }
124
+
125
+ std::optional<Qt::ColorScheme> DBusInterface::queryColorScheme ()
126
+ {
127
+ constexpr auto interface = " org.freedesktop.portal.Settings" _L1;
128
+ constexpr auto name_space = " org.freedesktop.appearance" _L1;
129
+ constexpr auto key = " color-scheme" _L1;
130
+ const auto method = readOneMethod ();
131
+
132
+ QVariant reply = query (interface, method, name_space, key);
133
+ if (reply.isValid ())
134
+ return convertColorScheme (
135
+ XDG_ColorScheme{ reply.value <QDBusVariant>().variant ().toUInt () });
136
+
137
+ return {};
138
+ }
139
+
140
+ std::optional<Qt::ContrastPreference> DBusInterface::queryContrast ()
141
+ {
142
+ constexpr auto interface = " org.freedesktop.portal.Settings" _L1;
143
+ const auto method = readOneMethod ();
144
+
145
+ constexpr auto namespace_xdg_portal = " org.freedesktop.appearance" _L1;
146
+ constexpr auto key_xdg_portal = " contrast" _L1;
147
+ QVariant reply = query (interface, method, namespace_xdg_portal, key_xdg_portal);
148
+ if (reply.isValid ())
149
+ return static_cast <Qt::ContrastPreference>(reply.toUInt ());
150
+
151
+ // Fall back to desktop-specific methods (GSettings for GNOME)
152
+ constexpr auto namespace_gsettings = " org.gnome.desktop.a11y.interface" _L1;
153
+ constexpr auto key_gsettings = " high-contrast" _L1;
154
+ reply = query (interface, method, namespace_gsettings, key_gsettings);
155
+ if (reply.isValid ())
156
+ return reply.toBool () ? Qt::ContrastPreference::HighContrast
157
+ : Qt::ContrastPreference::NoPreference;
158
+
159
+ return {};
160
+ }
57
161
} // namespace
58
162
59
163
#endif // QT_CONFIG(dbus)
@@ -70,41 +174,16 @@ const char *QGnomeTheme::name = "gnome";
70
174
QGnomeThemePrivate::QGnomeThemePrivate ()
71
175
{
72
176
#if QT_CONFIG(dbus)
73
- static constexpr QLatin1String appearanceNamespace (" org.freedesktop.appearance" );
74
- static constexpr QLatin1String colorSchemeKey (" color-scheme" );
75
- static constexpr QLatin1String contrastKey (" contrast" );
177
+ initDbus ();
76
178
77
- QDBusConnection dbus = QDBusConnection::sessionBus ();
78
- if (dbus.isConnected ()) {
79
- // ReadAll appears to omit the contrast setting on Ubuntu.
80
- QDBusMessage message = QDBusMessage::createMethodCall (QLatin1String (" org.freedesktop.portal.Desktop" ),
81
- QLatin1String (" /org/freedesktop/portal/desktop" ),
82
- QLatin1String (" org.freedesktop.portal.Settings" ),
83
- QLatin1String (" ReadOne" ));
84
-
85
- message << appearanceNamespace << colorSchemeKey;
86
- QDBusReply<QVariant> reply = dbus.call (message);
87
- if (Q_LIKELY (reply.isValid ())) {
88
- m_colorScheme = convertColorScheme (XDG_ColorScheme{ reply.value ().toUInt () });
89
- QWindowSystemInterface::handleThemeChange ();
90
- }
179
+ if (auto value = DBusInterface::queryColorScheme (); value.has_value ())
180
+ updateColorScheme (value.value ());
91
181
92
- message.setArguments ({});
93
- message << appearanceNamespace << contrastKey;
94
- pendingCallWatcher = std::make_unique<QDBusPendingCallWatcher>(dbus.asyncCall (message));
95
- QObject::connect (pendingCallWatcher.get (), &QDBusPendingCallWatcher::finished, pendingCallWatcher.get (), [this ](QDBusPendingCallWatcher *watcher) {
96
- if (!watcher->isError ()) {
97
- QDBusPendingReply<QVariant> reply = *watcher;
98
- if (Q_LIKELY (reply.isValid ()))
99
- updateHighContrast (static_cast <Qt::ContrastPreference>(reply.value ().toUInt ()));
100
- }
101
- initDbus ();
102
- });
103
- } else {
104
- qCWarning (lcQpaThemeGnome) << " dbus connection failed. Last error: " << dbus.lastError ();
105
- }
182
+ if (auto value = DBusInterface::queryContrast (); value.has_value ())
183
+ updateHighContrast (value.value ());
106
184
#endif // QT_CONFIG(dbus)
107
185
}
186
+
108
187
QGnomeThemePrivate::~QGnomeThemePrivate ()
109
188
{
110
189
if (systemFont)
@@ -149,7 +228,7 @@ bool QGnomeThemePrivate::initDbus()
149
228
m_themeName = value.toString ();
150
229
break ;
151
230
case QDBusListener::Setting::Contrast:
152
- updateHighContrast (static_cast <Qt::ContrastPreference>(value. toUInt () ));
231
+ updateHighContrast (value. value <Qt::ContrastPreference>());
153
232
break ;
154
233
default :
155
234
break ;
0 commit comments