1 | // Copyright (C) 2024 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 | |
4 | // |
5 | // W A R N I N G |
6 | // ------------- |
7 | // |
8 | // This file is not part of the Qt API. It exists purely as an |
9 | // implementation detail. This header file may change from version to |
10 | // version without notice, or even be removed. |
11 | // |
12 | // We mean it. |
13 | // |
14 | |
15 | #include "qgtk3portalinterface_p.h" |
16 | #include "qgtk3storage_p.h" |
17 | |
18 | #include <QtDBus/QDBusArgument> |
19 | #include <QtDBus/QDBusConnection> |
20 | #include <QtDBus/QDBusMessage> |
21 | #include <QtDBus/QDBusPendingCall> |
22 | #include <QtDBus/QDBusPendingCallWatcher> |
23 | #include <QtDBus/QDBusPendingReply> |
24 | #include <QtDBus/QDBusVariant> |
25 | #include <QtDBus/QtDBus> |
26 | |
27 | QT_BEGIN_NAMESPACE |
28 | |
29 | Q_LOGGING_CATEGORY(lcQGtk3PortalInterface, "qt.qpa.gtk" ); |
30 | |
31 | using namespace Qt::StringLiterals; |
32 | |
33 | static constexpr QLatin1StringView appearanceInterface("org.freedesktop.appearance" ); |
34 | static constexpr QLatin1StringView colorSchemeKey("color-scheme" ); |
35 | |
36 | const QDBusArgument &operator>>(const QDBusArgument &argument, QMap<QString, QVariantMap> &map) |
37 | { |
38 | argument.beginMap(); |
39 | map.clear(); |
40 | |
41 | while (!argument.atEnd()) { |
42 | QString key; |
43 | QVariantMap value; |
44 | argument.beginMapEntry(); |
45 | argument >> key >> value; |
46 | argument.endMapEntry(); |
47 | map.insert(key, value); |
48 | } |
49 | |
50 | argument.endMap(); |
51 | return argument; |
52 | } |
53 | |
54 | QGtk3PortalInterface::QGtk3PortalInterface(QGtk3Storage *s) |
55 | : m_storage(s) { |
56 | qRegisterMetaType<QDBusVariant>(); |
57 | qDBusRegisterMetaType<QMap<QString, QVariantMap>>(); |
58 | |
59 | queryColorScheme(); |
60 | |
61 | if (!s) { |
62 | qCDebug(lcQGtk3PortalInterface) << "QGtk3PortalInterface instantiated without QGtk3Storage." |
63 | << "No reaction to runtime theme changes." ; |
64 | } |
65 | } |
66 | |
67 | Qt::ColorScheme QGtk3PortalInterface::colorScheme() const |
68 | { |
69 | return m_colorScheme; |
70 | } |
71 | |
72 | void QGtk3PortalInterface::queryColorScheme() { |
73 | QDBusConnection connection = QDBusConnection::sessionBus(); |
74 | QDBusMessage message = QDBusMessage::createMethodCall( |
75 | destination: "org.freedesktop.portal.Desktop"_L1 , |
76 | path: "/org/freedesktop/portal/desktop"_L1 , |
77 | interface: "org.freedesktop.portal.Settings"_L1 , method: "ReadAll"_L1 ); |
78 | message << QStringList{ appearanceInterface }; |
79 | |
80 | QDBusPendingCall pendingCall = connection.asyncCall(message); |
81 | QDBusPendingCallWatcher *watcher = new QDBusPendingCallWatcher(pendingCall, this); |
82 | QObject::connect( |
83 | sender: watcher, signal: &QDBusPendingCallWatcher::finished, context: this, |
84 | slot: [this](QDBusPendingCallWatcher *watcher) { |
85 | QDBusPendingReply<QMap<QString, QVariantMap>> reply = *watcher; |
86 | if (reply.isValid()) { |
87 | QMap<QString, QVariantMap> settings = reply.value(); |
88 | if (!settings.isEmpty()) { |
89 | settingChanged(group: appearanceInterface, key: colorSchemeKey, |
90 | value: QDBusVariant(settings.value(key: appearanceInterface).value(key: colorSchemeKey))); |
91 | } |
92 | } else { |
93 | qCDebug(lcQGtk3PortalInterface) << "Failed to query org.freedesktop.portal.Settings: " |
94 | << reply.error().message(); |
95 | } |
96 | watcher->deleteLater(); |
97 | }); |
98 | |
99 | QDBusConnection::sessionBus().connect( |
100 | service: "org.freedesktop.portal.Desktop"_L1 , path: "/org/freedesktop/portal/desktop"_L1 , |
101 | interface: "org.freedesktop.portal.Settings"_L1 , name: "SettingChanged"_L1 , receiver: this, |
102 | SLOT(settingChanged(QString, QString, QDBusVariant))); |
103 | } |
104 | |
105 | void QGtk3PortalInterface::settingChanged(const QString &group, const QString &key, |
106 | const QDBusVariant &value) |
107 | { |
108 | if (group == appearanceInterface && key == colorSchemeKey) { |
109 | const uint colorScheme = value.variant().toUInt(); |
110 | // From org.freedesktop.portal.Settings.xml |
111 | // "1" - Prefer dark appearance |
112 | Qt::ColorScheme newColorScheme = colorScheme == 1 ? Qt::ColorScheme::Dark : Qt::ColorScheme::Light; |
113 | if (m_colorScheme != newColorScheme) { |
114 | m_colorScheme = newColorScheme; |
115 | if (m_storage) |
116 | m_storage->handleThemeChange(); |
117 | } |
118 | } |
119 | } |
120 | |
121 | QT_END_NAMESPACE |
122 | |
123 | #include "moc_qgtk3portalinterface_p.cpp" |
124 | |