1/*
2 * SPDX-FileCopyrightText: 2018 Marco Martin <mart@kde.org>
3 * SPDX-FileCopyrightText: 2021 Arjen Hiemstra <ahiemstra@heimr.nl>
4 * SPDX-FileCopyrightText: 2023 Harald Sitter <sitter@kde.org>
5 *
6 * SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8
9#include "virtualkeyboardwatcher.h"
10
11#ifdef KIRIGAMI_ENABLE_DBUS
12#include "settings_interface.h"
13#include <QDBusConnection>
14#include <QDBusPendingCallWatcher>
15#endif
16
17#include "kirigamiplatform_logging.h"
18
19using namespace Qt::Literals::StringLiterals;
20
21namespace Kirigami
22{
23namespace Platform
24{
25Q_GLOBAL_STATIC(VirtualKeyboardWatcher, virtualKeyboardWatcherSelf)
26
27class KIRIGAMIPLATFORM_NO_EXPORT VirtualKeyboardWatcher::Private
28{
29 static constexpr auto serviceName = "org.freedesktop.portal.Desktop"_L1;
30 static constexpr auto objectName = "/org/freedesktop/portal/desktop"_L1;
31 static constexpr auto interfaceName = "org.kde.kwin.VirtualKeyboard"_L1;
32
33 static constexpr auto GROUP = "org.kde.VirtualKeyboard"_L1;
34 static constexpr auto KEY_AVAILABLE = "available"_L1;
35 static constexpr auto KEY_ENABLED = "enabled"_L1;
36 static constexpr auto KEY_ACTIVE = "active"_L1;
37 static constexpr auto KEY_VISIBLE = "visible"_L1;
38 static constexpr auto KEY_WILL_SHOW_ON_ACTIVE = "willShowOnActive"_L1;
39
40public:
41 Private(VirtualKeyboardWatcher *qq)
42 : q(qq)
43 {
44#ifdef KIRIGAMI_ENABLE_DBUS
45 qDBusRegisterMetaType<VariantMapMap>();
46 settingsInterface = new OrgFreedesktopPortalSettingsInterface(serviceName, objectName, QDBusConnection::sessionBus(), q);
47
48 QObject::connect(sender: settingsInterface,
49 signal: &OrgFreedesktopPortalSettingsInterface::SettingChanged,
50 context: q,
51 slot: [this](const QString &group, const QString &key, const QDBusVariant &value) {
52 if (group != GROUP) {
53 return;
54 }
55
56 if (key == KEY_AVAILABLE) {
57 available = value.variant().toBool();
58 Q_EMIT q->availableChanged();
59 } else if (key == KEY_ENABLED) {
60 enabled = value.variant().toBool();
61 Q_EMIT q->enabledChanged();
62 } else if (key == KEY_ACTIVE) {
63 active = value.variant().toBool();
64 Q_EMIT q->activeChanged();
65 } else if (key == KEY_VISIBLE) {
66 visible = value.variant().toBool();
67 Q_EMIT q->visibleChanged();
68 } else if (key == KEY_WILL_SHOW_ON_ACTIVE) {
69 willShowOnActive = value.variant().toBool();
70 }
71 });
72
73 getAllProperties();
74#endif
75 }
76
77 VirtualKeyboardWatcher *q;
78
79#ifdef KIRIGAMI_ENABLE_DBUS
80 void getAllProperties();
81 void updateWillShowOnActive();
82
83 OrgFreedesktopPortalSettingsInterface *settingsInterface = nullptr;
84
85 QDBusPendingCallWatcher *willShowOnActiveCall = nullptr;
86#endif
87
88 bool available = false;
89 bool enabled = false;
90 bool active = false;
91 bool visible = false;
92 bool willShowOnActive = false;
93};
94
95VirtualKeyboardWatcher::VirtualKeyboardWatcher(QObject *parent)
96 : QObject(parent)
97 , d(std::make_unique<Private>(args: this))
98{
99}
100
101VirtualKeyboardWatcher::~VirtualKeyboardWatcher() = default;
102
103bool VirtualKeyboardWatcher::available() const
104{
105 return d->available;
106}
107
108bool VirtualKeyboardWatcher::enabled() const
109{
110 return d->enabled;
111}
112
113bool VirtualKeyboardWatcher::active() const
114{
115 return d->active;
116}
117
118bool VirtualKeyboardWatcher::visible() const
119{
120 return d->visible;
121}
122
123bool VirtualKeyboardWatcher::willShowOnActive() const
124{
125#ifdef KIRIGAMI_ENABLE_DBUS
126 d->updateWillShowOnActive();
127#endif
128 return d->willShowOnActive;
129}
130
131VirtualKeyboardWatcher *VirtualKeyboardWatcher::self()
132{
133 return virtualKeyboardWatcherSelf();
134}
135
136#ifdef KIRIGAMI_ENABLE_DBUS
137
138void VirtualKeyboardWatcher::Private::updateWillShowOnActive()
139{
140 if (willShowOnActiveCall) {
141 return;
142 }
143
144 willShowOnActiveCall = new QDBusPendingCallWatcher(settingsInterface->Read(group: GROUP, key: KEY_WILL_SHOW_ON_ACTIVE), q);
145 connect(sender: willShowOnActiveCall, signal: &QDBusPendingCallWatcher::finished, context: q, slot: [this](auto call) {
146 QDBusPendingReply<bool> reply = *call;
147 if (reply.isError()) {
148 qCDebug(KirigamiPlatform) << reply.error().message();
149 } else {
150 if (reply.value() != willShowOnActive) {
151 willShowOnActive = reply.value();
152 Q_EMIT q->willShowOnActiveChanged();
153 }
154 }
155 call->deleteLater();
156 willShowOnActiveCall = nullptr;
157 });
158}
159
160void VirtualKeyboardWatcher::Private::getAllProperties()
161{
162 auto call = new QDBusPendingCallWatcher(settingsInterface->ReadAll(groups: {GROUP}), q);
163 connect(sender: call, signal: &QDBusPendingCallWatcher::finished, context: q, slot: [this](auto call) {
164 QDBusPendingReply<VariantMapMap> reply = *call;
165 if (reply.isError()) {
166 qCDebug(KirigamiPlatform) << reply.error().message();
167 } else {
168 const auto groupValues = reply.value().value(key: GROUP);
169 available = groupValues.value(key: KEY_AVAILABLE).toBool();
170 enabled = groupValues.value(key: KEY_ENABLED).toBool();
171 active = groupValues.value(key: KEY_ACTIVE).toBool();
172 visible = groupValues.value(key: KEY_VISIBLE).toBool();
173 willShowOnActive = groupValues.value(key: KEY_WILL_SHOW_ON_ACTIVE).toBool();
174 }
175 call->deleteLater();
176
177 Q_EMIT q->availableChanged();
178 Q_EMIT q->enabledChanged();
179 Q_EMIT q->activeChanged();
180 Q_EMIT q->visibleChanged();
181 });
182}
183
184#endif
185
186}
187}
188
189#include "moc_virtualkeyboardwatcher.cpp"
190

source code of kirigami/src/platform/virtualkeyboardwatcher.cpp