KIdleTime

kidletime.cpp
1/* This file is part of the KDE libraries
2 * SPDX-FileCopyrightText: 2009 Dario Freddi <drf at kde.org>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-or-later
5 */
6
7#include "kidletime.h"
8
9#include <config-kidletime.h>
10
11#include "kabstractidletimepoller_p.h"
12#include "logging.h"
13
14#include <QDir>
15#include <QGuiApplication>
16#include <QJsonArray>
17#include <QPluginLoader>
18#include <QPointer>
19#include <QSet>
20
21class KIdleTimeHelper
22{
23public:
24 KIdleTimeHelper()
25 : q(nullptr)
26 {
27 }
28 ~KIdleTimeHelper()
29 {
30 delete q;
31 }
32 KIdleTimeHelper(const KIdleTimeHelper &) = delete;
33 KIdleTimeHelper &operator=(const KIdleTimeHelper &) = delete;
34 KIdleTime *q;
35};
36
37Q_GLOBAL_STATIC(KIdleTimeHelper, s_globalKIdleTime)
38
39KIdleTime *KIdleTime::instance()
40{
41 if (!s_globalKIdleTime()->q) {
42 new KIdleTime;
43 }
44
45 return s_globalKIdleTime()->q;
46}
47
48class KIdleTimePrivate
49{
50 Q_DECLARE_PUBLIC(KIdleTime)
51 KIdleTime *q_ptr;
52
53public:
54 KIdleTimePrivate()
55 : catchResume(false)
56 , currentId(0)
57 {
58 }
59
60 void loadSystem();
61 void unloadCurrentSystem();
62 void resumingFromIdle();
63 void timeoutReached(int msec);
64
66 bool catchResume;
67
68 int currentId;
69 QHash<int, int> associations;
70};
71
72KIdleTime::KIdleTime()
73 : QObject(nullptr)
74 , d_ptr(new KIdleTimePrivate())
75{
76 Q_ASSERT(!s_globalKIdleTime()->q);
77 s_globalKIdleTime()->q = this;
78
79 d_ptr->q_ptr = this;
80
82 d->loadSystem();
83
84 connect(d->poller.data(), &KAbstractIdleTimePoller::resumingFromIdle, this, [d]() {
85 d->resumingFromIdle();
86 });
87 connect(d->poller.data(), &KAbstractIdleTimePoller::timeoutReached, this, [d](int msec) {
88 d->timeoutReached(msec);
89 });
90}
91
93{
95 d->unloadCurrentSystem();
96}
97
99{
100 Q_D(KIdleTime);
101
102 if (!d->catchResume && d->poller) {
103 d->catchResume = true;
104 d->poller.data()->catchIdleEvent();
105 }
106}
107
109{
110 Q_D(KIdleTime);
111
112 if (d->catchResume && d->poller) {
113 d->catchResume = false;
114 d->poller.data()->stopCatchingIdleEvents();
115 }
116}
117
119{
120 Q_D(KIdleTime);
121 if (Q_UNLIKELY(msec < 0)) {
122 qCWarning(KIDLETIME, "KIdleTime::addIdleTimeout: invalid timeout: %d", msec);
123 return 0;
124 }
125 if (Q_UNLIKELY(!d->poller)) {
126 return 0;
127 }
128
129 d->poller.data()->addTimeout(msec);
130
131 ++d->currentId;
132 d->associations[d->currentId] = msec;
133
134 return d->currentId;
135}
136
138{
139 Q_D(KIdleTime);
140
141 const auto it = d->associations.constFind(identifier);
142 if (it == d->associations.cend() || !d->poller) {
143 return;
144 }
145
146 const int msec = it.value();
147
148 d->associations.erase(it);
149
150 const bool isFound = std::any_of(d->associations.cbegin(), d->associations.cend(), [msec](int i) {
151 return i == msec;
152 });
153
154 if (!isFound) {
155 d->poller.data()->removeTimeout(msec);
156 }
157}
158
160{
161 Q_D(KIdleTime);
162
163 std::vector<int> removed;
164
165 for (auto it = d->associations.cbegin(); it != d->associations.cend(); ++it) {
166 const int msec = it.value();
167 const bool alreadyIns = std::find(removed.cbegin(), removed.cend(), msec) != removed.cend();
168 if (!alreadyIns && d->poller) {
169 removed.push_back(msec);
170 d->poller.data()->removeTimeout(msec);
171 }
172 }
173
174 d->associations.clear();
175}
176
177static QStringList pluginCandidates()
178{
179 QStringList ret;
180
182 for (const QString &path : libPath) {
183#ifdef Q_OS_MACOS
184 const QDir pluginDir(path + QStringLiteral("/kf6/kidletime"));
185#else
186 const QDir pluginDir(path + QStringLiteral("/kf6/org.kde.kidletime.platforms"));
187#endif
188 if (!pluginDir.exists()) {
189 continue;
190 }
191
192 const auto entries = pluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot);
193
194 ret.reserve(ret.size() + entries.size());
195 for (const QString &entry : entries) {
196 ret << pluginDir.absoluteFilePath(entry);
197 }
198 }
199
200 return ret;
201}
202
203static bool checkPlatform(const QJsonObject &metadata, const QString &platformName)
204{
205 const QJsonArray platforms = metadata.value(QStringLiteral("MetaData")).toObject().value(QStringLiteral("platforms")).toArray();
206 return std::any_of(platforms.begin(), platforms.end(), [&platformName](const QJsonValue &value) {
207 return QString::compare(platformName, value.toString(), Qt::CaseInsensitive) == 0;
208 });
209}
210
211static KAbstractIdleTimePoller *loadPoller()
212{
213 const QString platformName = QGuiApplication::platformName();
214
216 for (const QStaticPlugin &staticPlugin : staticPlugins) {
217 const QJsonObject metadata = staticPlugin.metaData();
218 if (metadata.value(QLatin1String("IID")) != QLatin1String(KAbstractIdleTimePoller_iid)) {
219 continue;
220 }
221 if (checkPlatform(metadata, platformName)) {
222 auto *poller = qobject_cast<KAbstractIdleTimePoller *>(staticPlugin.instance());
223 if (poller) {
224 if (poller->isAvailable()) {
225 qCDebug(KIDLETIME) << "Loaded system poller from a static plugin";
226 return poller;
227 }
228 delete poller;
229 }
230 }
231 }
232
233 const QStringList lstPlugins = pluginCandidates();
234 for (const QString &candidate : lstPlugins) {
235 if (!QLibrary::isLibrary(candidate)) {
236 continue;
237 }
238 QPluginLoader loader(candidate);
239 if (checkPlatform(loader.metaData(), platformName)) {
240 auto *poller = qobject_cast<KAbstractIdleTimePoller *>(loader.instance());
241 if (poller) {
242 qCDebug(KIDLETIME) << "Trying plugin" << candidate;
243 if (poller->isAvailable()) {
244 qCDebug(KIDLETIME) << "Using" << candidate << "for platform" << platformName;
245 return poller;
246 }
247 delete poller;
248 }
249 }
250 }
251
252 qCWarning(KIDLETIME) << "Could not find any system poller plugin";
253 return nullptr;
254}
255
256void KIdleTimePrivate::loadSystem()
257{
258 if (!poller.isNull()) {
259 unloadCurrentSystem();
260 }
261
262 // load plugin
263 poller = loadPoller();
264
265 if (poller && !poller->isAvailable()) {
266 poller = nullptr;
267 }
268 if (!poller.isNull()) {
269 poller.data()->setUpPoller();
270 }
271}
272
273void KIdleTimePrivate::unloadCurrentSystem()
274{
275 if (!poller.isNull()) {
276 poller.data()->unloadPoller();
277 poller.data()->deleteLater();
278 }
279}
280
281void KIdleTimePrivate::resumingFromIdle()
282{
283 Q_Q(KIdleTime);
284
285 if (catchResume) {
286 Q_EMIT q->resumingFromIdle();
287 q->stopCatchingResumeEvent();
288 }
289}
290
291void KIdleTimePrivate::timeoutReached(int msec)
292{
293 Q_Q(KIdleTime);
294
295 const auto listKeys = associations.keys(msec);
296
297 for (const auto key : listKeys) {
298 Q_EMIT q->timeoutReached(key, msec);
299 }
300}
301
303{
304 Q_D(KIdleTime);
305
306 if (Q_LIKELY(d->poller)) {
307 d->poller.data()->simulateUserActivity();
308 }
309}
310
312{
313 Q_D(const KIdleTime);
314 if (Q_LIKELY(d->poller)) {
315 return d->poller.data()->forcePollRequest();
316 }
317 return 0;
318}
319
321{
322 Q_D(const KIdleTime);
323
324 return d->associations;
325}
326
327#include "moc_kidletime.cpp"
KIdleTime is a singleton reporting information on idle time.
Definition kidletime.h:37
void catchNextResumeEvent()
Catches the next resume from idle event.
Definition kidletime.cpp:98
int addIdleTimeout(int msec)
Adds a new timeout to catch.
int idleTime() const
Retrieves the idle time of the system, in milliseconds.
~KIdleTime() override
The destructor.
Definition kidletime.cpp:92
void simulateUserActivity()
Attempts to simulate user activity.
void stopCatchingResumeEvent()
Stops listening for resume event.
void removeIdleTimeout(int identifier)
Stops catching the idle timeout identified by the token identifier, if it was registered earlier with...
void removeAllIdleTimeouts()
Stops catching every set timeout (if any).
QHash< int, int > idleTimeouts() const
Returns the list of timeout identifiers associated with their duration, in milliseconds,...
QStringList libraryPaths()
QList< Key > keys() const const
iterator begin()
iterator end()
QJsonValue value(QLatin1StringView key) const const
QJsonArray toArray() const const
QJsonObject toObject() const const
bool isLibrary(const QString &fileName)
void reserve(qsizetype size)
qsizetype size() const const
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QList< QStaticPlugin > staticPlugins()
T * data() const const
bool isNull() const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:46:43 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.