KWayland

idle_interface.cpp
1 /*
2  SPDX-FileCopyrightText: 2015 Martin Gräßlin <[email protected]>
3 
4  SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
5 */
6 #include "idle_interface.h"
7 #include "display.h"
8 #include "global_p.h"
9 #include "resource_p.h"
10 #include "seat_interface.h"
11 
12 #include <QTimer>
13 
14 #include <functional>
15 #include <wayland-idle-server-protocol.h>
16 #include <wayland-server.h>
17 
18 namespace KWayland
19 {
20 namespace Server
21 {
22 class IdleInterface::Private : public Global::Private
23 {
24 public:
25  Private(IdleInterface *q, Display *d);
26 
27  int inhibitCount = 0;
29 
30 private:
31  void bind(wl_client *client, uint32_t version, uint32_t id) override;
32  static void getIdleTimeoutCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat, uint32_t timeout);
33 
34  static void unbind(wl_resource *resource);
35  static Private *cast(wl_resource *r)
36  {
37  return reinterpret_cast<Private *>(wl_resource_get_user_data(r));
38  }
39 
40  IdleInterface *q;
41  static const struct org_kde_kwin_idle_interface s_interface;
42  static const quint32 s_version;
43 };
44 
45 class IdleTimeoutInterface::Private : public Resource::Private
46 {
47 public:
48  Private(SeatInterface *seat, IdleTimeoutInterface *q, IdleInterface *manager, wl_resource *parentResource);
49  ~Private() override;
50  void setup(quint32 timeout);
51 
52  void simulateUserActivity();
53 
54  SeatInterface *seat;
55  QTimer *timer = nullptr;
56 
57 private:
58  static void simulateUserActivityCallback(wl_client *client, wl_resource *resource);
59  IdleTimeoutInterface *q_func()
60  {
61  return reinterpret_cast<IdleTimeoutInterface *>(q);
62  }
63  static const struct org_kde_kwin_idle_timeout_interface s_interface;
64 };
65 
66 const quint32 IdleInterface::Private::s_version = 1;
67 
68 #ifndef K_DOXYGEN
69 const struct org_kde_kwin_idle_interface IdleInterface::Private::s_interface = {getIdleTimeoutCallback};
70 #endif
71 
72 IdleInterface::Private::Private(IdleInterface *q, Display *d)
73  : Global::Private(d, &org_kde_kwin_idle_interface, s_version)
74  , q(q)
75 {
76 }
77 
78 void IdleInterface::Private::getIdleTimeoutCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat, uint32_t timeout)
79 {
80  Private *p = cast(resource);
81  SeatInterface *s = SeatInterface::get(seat);
82  Q_ASSERT(s);
83  IdleTimeoutInterface *idleTimeout = new IdleTimeoutInterface(s, p->q, resource);
84  idleTimeout->create(p->display->getConnection(client), wl_resource_get_version(resource), id);
85  if (!idleTimeout->resource()) {
86  wl_resource_post_no_memory(resource);
87  delete idleTimeout;
88  return;
89  }
90  p->idleTimeouts << idleTimeout;
91  QObject::connect(idleTimeout, &IdleTimeoutInterface::aboutToBeUnbound, p->q, [p, idleTimeout]() {
92  p->idleTimeouts.removeOne(idleTimeout);
93  });
94  idleTimeout->d_func()->setup(timeout);
95 }
96 
97 void IdleInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
98 {
99  auto c = display->getConnection(client);
100  wl_resource *resource = c->createResource(&org_kde_kwin_idle_interface, qMin(version, s_version), id);
101  if (!resource) {
102  wl_client_post_no_memory(client);
103  return;
104  }
105  wl_resource_set_implementation(resource, &s_interface, this, unbind);
106  // TODO: should we track?
107 }
108 
109 void IdleInterface::Private::unbind(wl_resource *resource)
110 {
111  Q_UNUSED(resource)
112 }
113 
114 IdleInterface::IdleInterface(Display *display, QObject *parent)
115  : Global(new Private(this, display), parent)
116 {
117 }
118 
119 IdleInterface::~IdleInterface() = default;
120 
121 void IdleInterface::inhibit()
122 {
123  Q_D();
124  d->inhibitCount++;
125  if (d->inhibitCount == 1) {
126  Q_EMIT inhibitedChanged();
127  }
128 }
129 
130 void IdleInterface::uninhibit()
131 {
132  Q_D();
133  d->inhibitCount--;
134  if (d->inhibitCount == 0) {
135  Q_EMIT inhibitedChanged();
136  }
137 }
138 
139 bool IdleInterface::isInhibited() const
140 {
141  Q_D();
142  return d->inhibitCount > 0;
143 }
144 
145 void IdleInterface::simulateUserActivity()
146 {
147  Q_D();
148  for (auto i : std::as_const(d->idleTimeouts)) {
149  i->d_func()->simulateUserActivity();
150  }
151 }
152 
153 IdleInterface::Private *IdleInterface::d_func() const
154 {
155  return reinterpret_cast<Private *>(d.data());
156 }
157 
158 #ifndef K_DOXYGEN
159 const struct org_kde_kwin_idle_timeout_interface IdleTimeoutInterface::Private::s_interface = {resourceDestroyedCallback, simulateUserActivityCallback};
160 #endif
161 
162 IdleTimeoutInterface::Private::Private(SeatInterface *seat, IdleTimeoutInterface *q, IdleInterface *manager, wl_resource *parentResource)
163  : Resource::Private(q, manager, parentResource, &org_kde_kwin_idle_timeout_interface, &s_interface)
164  , seat(seat)
165 {
166 }
167 
168 IdleTimeoutInterface::Private::~Private() = default;
169 
170 void IdleTimeoutInterface::Private::simulateUserActivityCallback(wl_client *client, wl_resource *resource)
171 {
172  Q_UNUSED(client);
173  Private *p = reinterpret_cast<Private *>(wl_resource_get_user_data(resource));
174  p->simulateUserActivity();
175 }
176 
177 void IdleTimeoutInterface::Private::simulateUserActivity()
178 {
179  if (!timer) {
180  // not yet configured
181  return;
182  }
183  if (qobject_cast<IdleInterface *>(global)->isInhibited()) {
184  // ignored while inhibited
185  return;
186  }
187  if (!timer->isActive() && resource) {
188  org_kde_kwin_idle_timeout_send_resumed(resource);
189  }
190  timer->start();
191 }
192 
193 void IdleTimeoutInterface::Private::setup(quint32 timeout)
194 {
195  if (timer) {
196  return;
197  }
198  timer = new QTimer(q);
199  timer->setSingleShot(true);
200  // less than 5 sec is not idle by definition
201  timer->setInterval(qMax(timeout, 5000u));
202  QObject::connect(timer, &QTimer::timeout, q, [this] {
203  if (resource) {
204  org_kde_kwin_idle_timeout_send_idle(resource);
205  }
206  });
207  if (qobject_cast<IdleInterface *>(global)->isInhibited()) {
208  // don't start if inhibited
209  return;
210  }
211  timer->start();
212 }
213 
214 IdleTimeoutInterface::IdleTimeoutInterface(SeatInterface *seat, IdleInterface *parent, wl_resource *parentResource)
215  : Resource(new Private(seat, this, parent, parentResource))
216 {
217  connect(seat, &SeatInterface::timestampChanged, this, [this] {
218  Q_D();
219  d->simulateUserActivity();
220  });
222  Q_D();
223  if (!d->timer) {
224  // not yet configured
225  return;
226  }
227  if (qobject_cast<IdleInterface *>(d->global)->isInhibited()) {
228  if (!d->timer->isActive() && d->resource) {
229  org_kde_kwin_idle_timeout_send_resumed(d->resource);
230  }
231  d->timer->stop();
232  } else {
233  d->timer->start();
234  }
235  });
236 }
237 
238 IdleTimeoutInterface::~IdleTimeoutInterface() = default;
239 
240 IdleTimeoutInterface::Private *IdleTimeoutInterface::d_func() const
241 {
242  return reinterpret_cast<IdleTimeoutInterface::Private *>(d.data());
243 }
244 
245 }
246 }
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
void timeout()
void inhibitedChanged()
Emitted when the system gets inhibited or uninhibited.
QObject * parent() const const
Q_D(Todo)
virtual QVariant get(ScriptableExtension *callerPrincipal, quint64 objId, const QString &propName)
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Tue Feb 7 2023 03:56:21 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.