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-server.h>
16 #include <wayland-idle-server-protocol.h>
17 
18 namespace KWayland
19 {
20 namespace Server
21 {
22 
23 class IdleInterface::Private : public Global::Private
24 {
25 public:
26  Private(IdleInterface *q, Display *d);
27 
28  int inhibitCount = 0;
29  QVector<IdleTimeoutInterface*> idleTimeouts;
30 
31 private:
32  void bind(wl_client *client, uint32_t version, uint32_t id) override;
33  static void getIdleTimeoutCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat, uint32_t timeout);
34 
35  static void unbind(wl_resource *resource);
36  static Private *cast(wl_resource *r) {
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();
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  return reinterpret_cast<IdleTimeoutInterface*>(q);
61  }
62  static const struct org_kde_kwin_idle_timeout_interface s_interface;
63 };
64 
65 const quint32 IdleInterface::Private::s_version = 1;
66 
67 #ifndef K_DOXYGEN
68 const struct org_kde_kwin_idle_interface IdleInterface::Private::s_interface = {
69  getIdleTimeoutCallback
70 };
71 #endif
72 
73 IdleInterface::Private::Private(IdleInterface *q, Display *d)
74  : Global::Private(d, &org_kde_kwin_idle_interface, s_version)
75  , q(q)
76 {
77 }
78 
79 void IdleInterface::Private::getIdleTimeoutCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat, uint32_t timeout)
80 {
81  Private *p = cast(resource);
82  SeatInterface *s = SeatInterface::get(seat);
83  Q_ASSERT(s);
84  IdleTimeoutInterface *idleTimeout = new IdleTimeoutInterface(s, p->q, resource);
85  idleTimeout->create(p->display->getConnection(client), wl_resource_get_version(resource), id);
86  if (!idleTimeout->resource()) {
87  wl_resource_post_no_memory(resource);
88  delete idleTimeout;
89  return;
90  }
91  p->idleTimeouts << idleTimeout;
92  QObject::connect(idleTimeout, &IdleTimeoutInterface::aboutToBeUnbound, p->q, [p, idleTimeout]() {
93  p->idleTimeouts.removeOne(idleTimeout);
94  });
95  idleTimeout->d_func()->setup(timeout);
96 }
97 
98 void IdleInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
99 {
100  auto c = display->getConnection(client);
101  wl_resource *resource = c->createResource(&org_kde_kwin_idle_interface, qMin(version, s_version), id);
102  if (!resource) {
103  wl_client_post_no_memory(client);
104  return;
105  }
106  wl_resource_set_implementation(resource, &s_interface, this, unbind);
107  // TODO: should we track?
108 }
109 
110 void IdleInterface::Private::unbind(wl_resource *resource)
111 {
112  Q_UNUSED(resource)
113 }
114 
115 IdleInterface::IdleInterface(Display *display, QObject *parent)
116  : Global(new Private(this, display), parent)
117 {
118 }
119 
120 IdleInterface::~IdleInterface() = default;
121 
122 void IdleInterface::inhibit()
123 {
124  Q_D();
125  d->inhibitCount++;
126  if (d->inhibitCount == 1) {
127  emit inhibitedChanged();
128  }
129 }
130 
131 void IdleInterface::uninhibit()
132 {
133  Q_D();
134  d->inhibitCount--;
135  if (d->inhibitCount == 0) {
136  emit inhibitedChanged();
137  }
138 }
139 
140 bool IdleInterface::isInhibited() const
141 {
142  Q_D();
143  return d->inhibitCount > 0;
144 }
145 
146 void IdleInterface::simulateUserActivity()
147 {
148  Q_D();
149  for (auto i : qAsConst(d->idleTimeouts)) {
150  i->d_func()->simulateUserActivity();
151  }
152 }
153 
154 IdleInterface::Private *IdleInterface::d_func() const
155 {
156  return reinterpret_cast<Private*>(d.data());
157 }
158 
159 #ifndef K_DOXYGEN
160 const struct org_kde_kwin_idle_timeout_interface IdleTimeoutInterface::Private::s_interface = {
161  resourceDestroyedCallback,
162  simulateUserActivityCallback
163 };
164 #endif
165 
166 IdleTimeoutInterface::Private::Private(SeatInterface *seat, IdleTimeoutInterface *q, IdleInterface *manager, wl_resource *parentResource)
167  : Resource::Private(q, manager, parentResource, &org_kde_kwin_idle_timeout_interface, &s_interface)
168  , seat(seat)
169 {
170 }
171 
172 IdleTimeoutInterface::Private::~Private() = default;
173 
174 void IdleTimeoutInterface::Private::simulateUserActivityCallback(wl_client *client, wl_resource *resource)
175 {
176  Q_UNUSED(client);
177  Private *p = reinterpret_cast<Private*>(wl_resource_get_user_data(resource));
178  p->simulateUserActivity();
179 }
180 
181 void IdleTimeoutInterface::Private::simulateUserActivity()
182 {
183  if (!timer) {
184  // not yet configured
185  return;
186  }
187  if (qobject_cast<IdleInterface*>(global)->isInhibited()) {
188  // ignored while inhibited
189  return;
190  }
191  if (!timer->isActive() && resource) {
192  org_kde_kwin_idle_timeout_send_resumed(resource);
193  }
194  timer->start();
195 }
196 
197 void IdleTimeoutInterface::Private::setup(quint32 timeout)
198 {
199  if (timer) {
200  return;
201  }
202  timer = new QTimer(q);
203  timer->setSingleShot(true);
204  // less than 5 sec is not idle by definition
205  timer->setInterval(qMax(timeout, 5000u));
207  [this] {
208  if (resource) {
209  org_kde_kwin_idle_timeout_send_idle(resource);
210  }
211  }
212  );
213  if (qobject_cast<IdleInterface*>(global)->isInhibited()) {
214  // don't start if inhibited
215  return;
216  }
217  timer->start();
218 }
219 
220 IdleTimeoutInterface::IdleTimeoutInterface(SeatInterface *seat, IdleInterface *parent, wl_resource *parentResource)
221  : Resource(new Private(seat, this, parent, parentResource))
222 {
223  connect(seat, &SeatInterface::timestampChanged, this,
224  [this] {
225  Q_D();
226  d->simulateUserActivity();
227  }
228  );
229  connect(parent, &IdleInterface::inhibitedChanged, this,
230  [this] {
231  Q_D();
232  if (!d->timer) {
233  // not yet configured
234  return;
235  }
236  if (qobject_cast<IdleInterface*>(d->global)->isInhibited()) {
237  if (!d->timer->isActive() && d->resource) {
238  org_kde_kwin_idle_timeout_send_resumed(d->resource);
239  }
240  d->timer->stop();
241  } else {
242  d->timer->start();
243  }
244  }
245  );
246 }
247 
248 IdleTimeoutInterface::~IdleTimeoutInterface() = default;
249 
250 IdleTimeoutInterface::Private *IdleTimeoutInterface::d_func() const
251 {
252  return reinterpret_cast<IdleTimeoutInterface::Private*>(d.data());
253 }
254 
255 }
256 }
void simulateUserActivity()
Calling this method allows the Compositor to simulate user activity.
void timeout()
Represents a Seat on the Wayland Display.
T * data() const const
Global representing the org_kde_kwin_idle interface.
Represents a bound Resource.
Definition: resource.h:32
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QObject * parent() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Wed Jul 1 2020 22:48:35 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.