Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qxdgdesktopportaltheme.cpp
Go to the documentation of this file.
1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
7
8#include <private/qguiapplication_p.h>
9#include <qpa/qplatformtheme_p.h>
10#include <qpa/qplatformthemefactory_p.h>
11#include <qpa/qplatformintegration.h>
12
13#include <QDBusConnection>
14#include <QDBusMessage>
15#include <QDBusPendingCall>
16#include <QDBusPendingCallWatcher>
17#include <QDBusPendingReply>
18#include <QDBusReply>
19
20QT_BEGIN_NAMESPACE
21
22using namespace Qt::StringLiterals;
23
24static constexpr QLatin1StringView appearanceInterface("org.freedesktop.appearance");
25static constexpr QLatin1StringView colorSchemeKey("color-scheme");
26static constexpr QLatin1StringView contrastKey("contrast");
27
29 {
31public:
37
41
43 {
44 delete baseTheme;
45 }
46
47 /*! \internal
48
49 Converts the given Freedesktop color scheme setting \a colorschemePref to a Qt::ColorScheme value.
50 Specification: https://github.com/flatpak/xdg-desktop-portal/blob/d7a304a00697d7d608821253cd013f3b97ac0fb6/data/org.freedesktop.impl.portal.Settings.xml#L33-L45
51
52 Unfortunately the enum numerical values are not defined identically, so we have to convert them.
53
54 The mapping is as follows:
55
56 Enum Index: Freedesktop definition | Qt definition
57 ----------------------------------- | -------------
58 0: No preference | 0: Unknown
59 1: Prefer dark appearance | 2: Dark
60 2: Prefer light appearance | 1: Light
61 */
62 static Qt::ColorScheme colorSchemeFromXdgPref(const XdgColorschemePref colorschemePref)
63 {
64 switch (colorschemePref) {
65 case PreferDark: return Qt::ColorScheme::Dark;
66 case PreferLight: return Qt::ColorScheme::Light;
67 default: return Qt::ColorScheme::Unknown;
68 }
69 }
70
71public Q_SLOTS:
85
86public:
91};
92
93QXdgDesktopPortalTheme::QXdgDesktopPortalTheme()
94 : d_ptr(new QXdgDesktopPortalThemePrivate)
95{
96 Q_D(QXdgDesktopPortalTheme);
97
98 const QStringList themeNames = QGuiApplicationPrivate::platform_integration->themeNames();
99 for (const QString &themeName : themeNames) {
100 if (QXdgDesktopPortalTheme::isXdgPlugin(themeName))
101 continue;
102 // 1) Look for a theme plugin.
103 d->baseTheme = QPlatformThemeFactory::create(themeName, nullptr);
104 if (d->baseTheme)
105 break;
106
107 // 2) If no theme plugin was found ask the platform integration to create a theme
108 d->baseTheme = QGuiApplicationPrivate::platform_integration->createPlatformTheme(themeName);
109 if (d->baseTheme)
110 break;
111 }
112
113 // 3) Fall back on the built-in "null" platform theme.
114 if (!d->baseTheme)
115 d->baseTheme = new QPlatformTheme;
116
117 // Get information about portal version
118 QDBusMessage message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
119 "/org/freedesktop/portal/desktop"_L1,
120 "org.freedesktop.DBus.Properties"_L1,
121 "Get"_L1);
122 message << "org.freedesktop.portal.FileChooser"_L1 << "version"_L1;
123 QDBusPendingCall pendingCall = QDBusConnection::sessionBus().asyncCall(message);
124 QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall);
125 QObject::connect(watcher, &QDBusPendingCallWatcher::finished, watcher, [d] (QDBusPendingCallWatcher *watcher) {
126 QDBusPendingReply<QVariant> reply = *watcher;
127 if (reply.isValid()) {
128 d->fileChooserPortalVersion = reply.value().toUInt();
129 } else {
130 qWarning() << "Call for getting org.freedesktop.portal.FileChooser version failed"
131 << reply.error();
132 }
133 watcher->deleteLater();
134 });
135
136 // Get information about system theme preference
137 message = QDBusMessage::createMethodCall("org.freedesktop.portal.Desktop"_L1,
138 "/org/freedesktop/portal/desktop"_L1,
139 "org.freedesktop.portal.Settings"_L1,
140 "ReadAll"_L1);
141
142 QStringList namespaces = { appearanceInterface };
143 message << namespaces;
144
145 // this must not be asyncCall() because we have to set appearance now
146 QDBusReply<QMap<QString, QVariantMap>> reply = QDBusConnection::sessionBus().call(message);
147 if (reply.isValid()) {
148 const QMap<QString, QVariantMap> settingsMap = reply.value();
149 if (!settingsMap.isEmpty()) {
150 const auto xdgColorSchemePref = static_cast<QXdgDesktopPortalThemePrivate::XdgColorschemePref>(settingsMap.value(appearanceInterface).value(colorSchemeKey).toUInt());
151 d->colorScheme = QXdgDesktopPortalThemePrivate::colorSchemeFromXdgPref(xdgColorSchemePref);
152 d->contrast = static_cast<Qt::ContrastPreference>(settingsMap.value(appearanceInterface).value(contrastKey).toUInt());
153 }
154 } else {
155 qWarning() << "Call to org.freedesktop.portal.Settings.ReadAll failed" << reply.error();
156 }
157
158 QDBusConnection::sessionBus().connect(
159 "org.freedesktop.portal.Desktop"_L1, "/org/freedesktop/portal/desktop"_L1,
160 "org.freedesktop.portal.Settings"_L1, "SettingChanged"_L1, d_ptr.get(),
161 SLOT(settingChanged(QString,QString,QDBusVariant)));
162}
163
165{
166 Q_D(const QXdgDesktopPortalTheme);
167 return d->baseTheme->createPlatformMenuItem();
168}
169
171{
172 Q_D(const QXdgDesktopPortalTheme);
173 return d->baseTheme->createPlatformMenu();
174}
175
177{
178 Q_D(const QXdgDesktopPortalTheme);
179 return d->baseTheme->createPlatformMenuBar();
180}
181
183{
184 Q_D(const QXdgDesktopPortalTheme);
185 return d->baseTheme->showPlatformMenuBar();
186}
187
189{
190 Q_D(const QXdgDesktopPortalTheme);
191
192 if (type == FileDialog)
193 return true;
194
195 return d->baseTheme->usePlatformNativeDialog(type);
196}
197
199{
200 Q_D(const QXdgDesktopPortalTheme);
201
202 if (type == FileDialog && d->fileChooserPortalVersion) {
203 // Older versions of FileChooser portal don't support opening directories, therefore we fallback
204 // to native file dialog opened inside the sandbox to open a directory.
205 if (d->baseTheme->usePlatformNativeDialog(type))
206 return new QXdgDesktopPortalFileDialog(static_cast<QPlatformFileDialogHelper*>(d->baseTheme->createPlatformDialogHelper(type)),
207 d->fileChooserPortalVersion);
208
210 }
211
212 return d->baseTheme->createPlatformDialogHelper(type);
213}
214
215#ifndef QT_NO_SYSTEMTRAYICON
217{
218 Q_D(const QXdgDesktopPortalTheme);
219 return d->baseTheme->createPlatformSystemTrayIcon();
220}
221#endif
222
223const QPalette *QXdgDesktopPortalTheme::palette(Palette type) const
224{
225 Q_D(const QXdgDesktopPortalTheme);
226 return d->baseTheme->palette(type);
227}
228
229const QFont* QXdgDesktopPortalTheme::font(Font type) const
230{
231 Q_D(const QXdgDesktopPortalTheme);
232 return d->baseTheme->font(type);
233}
234
236{
237 Q_D(const QXdgDesktopPortalTheme);
238 return d->baseTheme->themeHint(hint);
239}
240
242{
243 Q_D(const QXdgDesktopPortalTheme);
244 if (d->colorScheme == Qt::ColorScheme::Unknown)
245 return d->baseTheme->colorScheme();
246 return d->colorScheme;
247}
248
250{
251 Q_D(const QXdgDesktopPortalTheme);
252 return d->contrast;
253}
254
255QPixmap QXdgDesktopPortalTheme::standardPixmap(StandardPixmap sp, const QSizeF &size) const
256{
257 Q_D(const QXdgDesktopPortalTheme);
258 return d->baseTheme->standardPixmap(sp, size);
259}
260
261QIcon QXdgDesktopPortalTheme::fileIcon(const QFileInfo &fileInfo,
262 QPlatformTheme::IconOptions iconOptions) const
263{
264 Q_D(const QXdgDesktopPortalTheme);
265 return d->baseTheme->fileIcon(fileInfo, iconOptions);
266}
267
268QIconEngine * QXdgDesktopPortalTheme::createIconEngine(const QString &iconName) const
269{
270 Q_D(const QXdgDesktopPortalTheme);
271 return d->baseTheme->createIconEngine(iconName);
272}
273
274#if QT_CONFIG(shortcut)
275QList<QKeySequence> QXdgDesktopPortalTheme::keyBindings(QKeySequence::StandardKey key) const
276{
277 Q_D(const QXdgDesktopPortalTheme);
278 return d->baseTheme->keyBindings(key);
279}
280#endif
281
283{
284 Q_D(const QXdgDesktopPortalTheme);
285 return d->baseTheme->standardButtonText(button);
286}
287
288bool QXdgDesktopPortalTheme::isXdgPlugin(const QString &key)
289{
290 return key.compare("xdgdesktopportal"_L1, Qt::CaseInsensitive) == 0 ||
291 key.compare("flatpak"_L1, Qt::CaseInsensitive) == 0 ||
292 key.compare("snap"_L1, Qt::CaseInsensitive) == 0;
293}
294
295QT_END_NAMESPACE
296
297#include "qxdgdesktopportaltheme.moc"
static Qt::ColorScheme colorSchemeFromXdgPref(const XdgColorschemePref colorschemePref)
Qt::ColorScheme colorScheme() const override
Qt::ContrastPreference contrastPreference() const override
QPlatformMenuItem * createPlatformMenuItem() const override
QPixmap standardPixmap(StandardPixmap sp, const QSizeF &size) const override
Return a pixmap for standardPixmap, at the given size.
QIcon fileIcon(const QFileInfo &fileInfo, QPlatformTheme::IconOptions iconOptions={ }) const override
Return an icon for fileInfo, observing iconOptions.
QString standardButtonText(int button) const override
Returns the text of a standard button.
bool usePlatformNativeDialog(DialogType type) const override
QPlatformSystemTrayIcon * createPlatformSystemTrayIcon() const override
Factory function for QSystemTrayIcon.
QIconEngine * createIconEngine(const QString &iconName) const override
Factory function for the QIconEngine used by QIcon::fromTheme().
QPlatformDialogHelper * createPlatformDialogHelper(DialogType type) const override
const QPalette * palette(Palette type=SystemPalette) const override
Return a color palette for type type.
const QFont * font(Font type=SystemFont) const override
QPlatformMenuBar * createPlatformMenuBar() const override
QPlatformMenu * createPlatformMenu() const override
QVariant themeHint(ThemeHint hint) const override
static constexpr QLatin1StringView contrastKey("contrast")
static constexpr QLatin1StringView colorSchemeKey("color-scheme")
static constexpr QLatin1StringView appearanceInterface("org.freedesktop.appearance")