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.0-only
5  */
6 
7 #include "kidletime.h"
8 
9 #include <config-kidletime.h>
10 
11 #include "abstractsystempoller.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 
21 class KIdleTimeHelper
22 {
23 public:
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 
37 Q_GLOBAL_STATIC(KIdleTimeHelper, s_globalKIdleTime)
38 
39 KIdleTime *KIdleTime::instance()
40 {
41  if (!s_globalKIdleTime()->q) {
42  new KIdleTime;
43  }
44 
45  return s_globalKIdleTime()->q;
46 }
47 
48 class KIdleTimePrivate
49 {
50  Q_DECLARE_PUBLIC(KIdleTime)
51  KIdleTime *q_ptr;
52 
53 public:
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 
72 KIdleTime::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 
81  Q_D(KIdleTime);
82  d->loadSystem();
83 
84  connect(d->poller.data(), &AbstractSystemPoller::resumingFromIdle, this, [d]() {
85  d->resumingFromIdle();
86  });
87  connect(d->poller.data(), &AbstractSystemPoller::timeoutReached, this, [d](int msec) {
88  d->timeoutReached(msec);
89  });
90 }
91 
93 {
94  Q_D(KIdleTime);
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(!d->poller)) {
122  return 0;
123  }
124 
125  d->poller.data()->addTimeout(msec);
126 
127  ++d->currentId;
128  d->associations[d->currentId] = msec;
129 
130  return d->currentId;
131 }
132 
133 void KIdleTime::removeIdleTimeout(int identifier)
134 {
135  Q_D(KIdleTime);
136 
137  if (!d->associations.contains(identifier) || !d->poller) {
138  return;
139  }
140 
141  int msec = d->associations[identifier];
142 
143  d->associations.remove(identifier);
144 
145  if (!d->associations.values().contains(msec)) {
146  d->poller.data()->removeTimeout(msec);
147  }
148 }
149 
151 {
152  Q_D(KIdleTime);
153 
154  QHash<int, int>::iterator i = d->associations.begin();
155  QSet<int> removed;
156  removed.reserve(d->associations.size());
157 
158  while (i != d->associations.end()) {
159  int msec = d->associations[i.key()];
160 
161  i = d->associations.erase(i);
162 
163  if (!removed.contains(msec) && d->poller) {
164  d->poller.data()->removeTimeout(msec);
165  removed.insert(msec);
166  }
167  }
168 }
169 
170 static QStringList pluginCandidates()
171 {
172  QStringList ret;
174  for (const QString &path : libPath) {
175  const QDir pluginDir(path + QLatin1String("/kf5/org.kde.kidletime.platforms"));
176  if (!pluginDir.exists()) {
177  continue;
178  }
179  for (const QString &entry : pluginDir.entryList(QDir::Files | QDir::NoDotAndDotDot)) {
180  ret << pluginDir.absoluteFilePath(entry);
181  }
182  }
183  return ret;
184 }
185 
186 static bool checkPlatform(const QJsonObject &metadata, const QString &platformName)
187 {
188  const QJsonArray platforms = metadata.value(QStringLiteral("MetaData")).toObject().value(QStringLiteral("platforms")).toArray();
189  return std::any_of(platforms.begin(), platforms.end(), [&platformName](const QJsonValue &value) {
190  return QString::compare(platformName, value.toString(), Qt::CaseInsensitive) == 0;
191  });
192 }
193 
194 static AbstractSystemPoller *loadPoller()
195 {
196  const QString platformName = QGuiApplication::platformName();
197 
199  for (const QStaticPlugin &staticPlugin : staticPlugins) {
200  const QJsonObject metadata = staticPlugin.metaData();
201  if (metadata.value(QLatin1String("IID")) != QLatin1String(AbstractSystemPoller_iid)) {
202  continue;
203  }
204  if (checkPlatform(metadata, platformName)) {
205  AbstractSystemPoller *poller = qobject_cast<AbstractSystemPoller *>(staticPlugin.instance());
206  if (poller) {
207  if (poller->isAvailable()) {
208  qCDebug(KIDLETIME) << "Loaded system poller from a static plugin";
209  return poller;
210  }
211  delete poller;
212  }
213  }
214  }
215 
216  const QStringList lstPlugins = pluginCandidates();
217  for (const QString &candidate : lstPlugins) {
218  if (!QLibrary::isLibrary(candidate)) {
219  continue;
220  }
221  QPluginLoader loader(candidate);
222  if (checkPlatform(loader.metaData(), platformName)) {
223  AbstractSystemPoller *poller = qobject_cast<AbstractSystemPoller *>(loader.instance());
224  if (poller) {
225  qCDebug(KIDLETIME) << "Trying plugin" << candidate;
226  if (poller->isAvailable()) {
227  qCDebug(KIDLETIME) << "Using" << candidate << "for platform" << platformName;
228  return poller;
229  }
230  delete poller;
231  }
232  }
233  }
234 
235  qCWarning(KIDLETIME) << "Could not find any system poller plugin";
236  return nullptr;
237 }
238 
239 void KIdleTimePrivate::loadSystem()
240 {
241  if (!poller.isNull()) {
242  unloadCurrentSystem();
243  }
244 
245  // load plugin
246  poller = loadPoller();
247 
248  if (poller && !poller->isAvailable()) {
249  poller = nullptr;
250  }
251  if (!poller.isNull()) {
252  poller.data()->setUpPoller();
253  }
254 }
255 
256 void KIdleTimePrivate::unloadCurrentSystem()
257 {
258  if (!poller.isNull()) {
259  poller.data()->unloadPoller();
260  poller.data()->deleteLater();
261  }
262 }
263 
264 void KIdleTimePrivate::resumingFromIdle()
265 {
266  Q_Q(KIdleTime);
267 
268  if (catchResume) {
269  Q_EMIT q->resumingFromIdle();
270  q->stopCatchingResumeEvent();
271  }
272 }
273 
274 void KIdleTimePrivate::timeoutReached(int msec)
275 {
276  Q_Q(KIdleTime);
277 
278  if (associations.values().contains(msec)) {
279  const auto listKeys = associations.keys(msec);
280  for (int key : listKeys) {
281 #if KIDLETIME_BUILD_DEPRECATED_SINCE(5, 76)
282  Q_EMIT q->timeoutReached(key);
283 #endif
284  Q_EMIT q->timeoutReached(key, msec);
285  }
286  }
287 }
288 
290 {
291  Q_D(KIdleTime);
292 
293  if (Q_LIKELY(d->poller)) {
294  d->poller.data()->simulateUserActivity();
295  }
296 }
297 
299 {
300  Q_D(const KIdleTime);
301  if (Q_LIKELY(d->poller)) {
302  return d->poller.data()->forcePollRequest();
303  }
304  return 0;
305 }
306 
308 {
309  Q_D(const KIdleTime);
310 
311  return d->associations;
312 }
313 
314 #include "moc_kidletime.cpp"
KIdleTime is a singleton reporting information on idle time.
Definition: kidletime.h:36
void removeAllIdleTimeouts()
Stops catching every set timeout (if any).
Definition: kidletime.cpp:150
QJsonArray::iterator begin()
const Key key(const T &value) const const
void stopCatchingResumeEvent()
Stops listening for resume event.
Definition: kidletime.cpp:108
QVector< QStaticPlugin > staticPlugins()
virtual ~KIdleTime()
The destructor.
Definition: kidletime.cpp:92
QHash::iterator erase(QHash::iterator pos)
QSet::iterator insert(const T &value)
QJsonObject metaData() const const
bool exists() const const
void simulateUserActivity()
Attempts to simulate user activity.
Definition: kidletime.cpp:289
void catchNextResumeEvent()
Catches the next resume from idle event.
Definition: kidletime.cpp:98
QJsonObject toObject() const const
CaseInsensitive
QJsonArray toArray() const const
QHash::iterator begin()
QObject * instance()
QHash< int, int > idleTimeouts() const
Returns the list of timeout identifiers associated with their duration, in milliseconds, the library is currently listening to.
Definition: kidletime.cpp:307
QJsonArray::iterator end()
void removeIdleTimeout(int identifier)
Stops catching the idle timeout identified by the token identifier, if it was registered earlier with...
Definition: kidletime.cpp:133
QStringList libraryPaths()
bool contains(const T &value) const const
int idleTime() const
Retrieves the idle time of the system, in milliseconds.
Definition: kidletime.cpp:298
QStringList entryList(QDir::Filters filters, QDir::SortFlags sort) const const
QString absoluteFilePath(const QString &fileName) const const
void reserve(int size)
QJsonValue value(const QString &key) const const
QHash::iterator end()
int compare(const QString &other, Qt::CaseSensitivity cs) const const
int addIdleTimeout(int msec)
Adds a new timeout to catch.
Definition: kidletime.cpp:118
QString platformName()
bool isLibrary(const QString &fileName)
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Fri Jul 30 2021 22:50:06 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.