253 lines
6.8 KiB
C++
253 lines
6.8 KiB
C++
/*
|
|
SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
|
|
|
|
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
|
|
*/
|
|
#include "idle_interface.h"
|
|
#include "display.h"
|
|
#include "global_p.h"
|
|
#include "resource_p.h"
|
|
#include "seat_interface.h"
|
|
|
|
#include <QTimer>
|
|
|
|
#include <functional>
|
|
#include <wayland-server.h>
|
|
#include <wayland-idle-server-protocol.h>
|
|
|
|
namespace KWaylandServer
|
|
{
|
|
|
|
class IdleInterface::Private : public Global::Private
|
|
{
|
|
public:
|
|
Private(IdleInterface *q, Display *d);
|
|
|
|
int inhibitCount = 0;
|
|
QVector<IdleTimeoutInterface*> idleTimeouts;
|
|
|
|
private:
|
|
void bind(wl_client *client, uint32_t version, uint32_t id) override;
|
|
static void getIdleTimeoutCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat, uint32_t timeout);
|
|
|
|
static void unbind(wl_resource *resource);
|
|
static Private *cast(wl_resource *r) {
|
|
return reinterpret_cast<Private*>(wl_resource_get_user_data(r));
|
|
}
|
|
|
|
IdleInterface *q;
|
|
static const struct org_kde_kwin_idle_interface s_interface;
|
|
static const quint32 s_version;
|
|
};
|
|
|
|
class IdleTimeoutInterface::Private : public Resource::Private
|
|
{
|
|
public:
|
|
Private(SeatInterface *seat, IdleTimeoutInterface *q, IdleInterface *manager, wl_resource *parentResource);
|
|
~Private();
|
|
void setup(quint32 timeout);
|
|
|
|
void simulateUserActivity();
|
|
|
|
SeatInterface *seat;
|
|
QTimer *timer = nullptr;
|
|
|
|
private:
|
|
static void simulateUserActivityCallback(wl_client *client, wl_resource *resource);
|
|
IdleTimeoutInterface *q_func() {
|
|
return reinterpret_cast<IdleTimeoutInterface*>(q);
|
|
}
|
|
static const struct org_kde_kwin_idle_timeout_interface s_interface;
|
|
};
|
|
|
|
const quint32 IdleInterface::Private::s_version = 1;
|
|
|
|
#ifndef K_DOXYGEN
|
|
const struct org_kde_kwin_idle_interface IdleInterface::Private::s_interface = {
|
|
getIdleTimeoutCallback
|
|
};
|
|
#endif
|
|
|
|
IdleInterface::Private::Private(IdleInterface *q, Display *d)
|
|
: Global::Private(d, &org_kde_kwin_idle_interface, s_version)
|
|
, q(q)
|
|
{
|
|
}
|
|
|
|
void IdleInterface::Private::getIdleTimeoutCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *seat, uint32_t timeout)
|
|
{
|
|
Private *p = cast(resource);
|
|
SeatInterface *s = SeatInterface::get(seat);
|
|
Q_ASSERT(s);
|
|
IdleTimeoutInterface *idleTimeout = new IdleTimeoutInterface(s, p->q, resource);
|
|
idleTimeout->create(p->display->getConnection(client), wl_resource_get_version(resource), id);
|
|
if (!idleTimeout->resource()) {
|
|
wl_resource_post_no_memory(resource);
|
|
delete idleTimeout;
|
|
return;
|
|
}
|
|
p->idleTimeouts << idleTimeout;
|
|
QObject::connect(idleTimeout, &IdleTimeoutInterface::aboutToBeUnbound, p->q, [p, idleTimeout]() {
|
|
p->idleTimeouts.removeOne(idleTimeout);
|
|
});
|
|
idleTimeout->d_func()->setup(timeout);
|
|
}
|
|
|
|
void IdleInterface::Private::bind(wl_client *client, uint32_t version, uint32_t id)
|
|
{
|
|
auto c = display->getConnection(client);
|
|
wl_resource *resource = c->createResource(&org_kde_kwin_idle_interface, qMin(version, s_version), id);
|
|
if (!resource) {
|
|
wl_client_post_no_memory(client);
|
|
return;
|
|
}
|
|
wl_resource_set_implementation(resource, &s_interface, this, unbind);
|
|
// TODO: should we track?
|
|
}
|
|
|
|
void IdleInterface::Private::unbind(wl_resource *resource)
|
|
{
|
|
Q_UNUSED(resource)
|
|
}
|
|
|
|
IdleInterface::IdleInterface(Display *display, QObject *parent)
|
|
: Global(new Private(this, display), parent)
|
|
{
|
|
}
|
|
|
|
IdleInterface::~IdleInterface() = default;
|
|
|
|
void IdleInterface::inhibit()
|
|
{
|
|
Q_D();
|
|
d->inhibitCount++;
|
|
if (d->inhibitCount == 1) {
|
|
emit inhibitedChanged();
|
|
}
|
|
}
|
|
|
|
void IdleInterface::uninhibit()
|
|
{
|
|
Q_D();
|
|
d->inhibitCount--;
|
|
if (d->inhibitCount == 0) {
|
|
emit inhibitedChanged();
|
|
}
|
|
}
|
|
|
|
bool IdleInterface::isInhibited() const
|
|
{
|
|
Q_D();
|
|
return d->inhibitCount > 0;
|
|
}
|
|
|
|
void IdleInterface::simulateUserActivity()
|
|
{
|
|
Q_D();
|
|
for (auto i : qAsConst(d->idleTimeouts)) {
|
|
i->d_func()->simulateUserActivity();
|
|
}
|
|
}
|
|
|
|
IdleInterface::Private *IdleInterface::d_func() const
|
|
{
|
|
return reinterpret_cast<Private*>(d.data());
|
|
}
|
|
|
|
#ifndef K_DOXYGEN
|
|
const struct org_kde_kwin_idle_timeout_interface IdleTimeoutInterface::Private::s_interface = {
|
|
resourceDestroyedCallback,
|
|
simulateUserActivityCallback
|
|
};
|
|
#endif
|
|
|
|
IdleTimeoutInterface::Private::Private(SeatInterface *seat, IdleTimeoutInterface *q, IdleInterface *manager, wl_resource *parentResource)
|
|
: Resource::Private(q, manager, parentResource, &org_kde_kwin_idle_timeout_interface, &s_interface)
|
|
, seat(seat)
|
|
{
|
|
}
|
|
|
|
IdleTimeoutInterface::Private::~Private() = default;
|
|
|
|
void IdleTimeoutInterface::Private::simulateUserActivityCallback(wl_client *client, wl_resource *resource)
|
|
{
|
|
Q_UNUSED(client);
|
|
Private *p = reinterpret_cast<Private*>(wl_resource_get_user_data(resource));
|
|
p->simulateUserActivity();
|
|
}
|
|
|
|
void IdleTimeoutInterface::Private::simulateUserActivity()
|
|
{
|
|
if (!timer) {
|
|
// not yet configured
|
|
return;
|
|
}
|
|
if (qobject_cast<IdleInterface*>(global)->isInhibited()) {
|
|
// ignored while inhibited
|
|
return;
|
|
}
|
|
if (!timer->isActive() && resource) {
|
|
org_kde_kwin_idle_timeout_send_resumed(resource);
|
|
}
|
|
timer->start();
|
|
}
|
|
|
|
void IdleTimeoutInterface::Private::setup(quint32 timeout)
|
|
{
|
|
if (timer) {
|
|
return;
|
|
}
|
|
timer = new QTimer(q);
|
|
timer->setSingleShot(true);
|
|
// less than 5 sec is not idle by definition
|
|
timer->setInterval(qMax(timeout, 5000u));
|
|
QObject::connect(timer, &QTimer::timeout, q,
|
|
[this] {
|
|
if (resource) {
|
|
org_kde_kwin_idle_timeout_send_idle(resource);
|
|
}
|
|
}
|
|
);
|
|
if (qobject_cast<IdleInterface*>(global)->isInhibited()) {
|
|
// don't start if inhibited
|
|
return;
|
|
}
|
|
timer->start();
|
|
}
|
|
|
|
IdleTimeoutInterface::IdleTimeoutInterface(SeatInterface *seat, IdleInterface *parent, wl_resource *parentResource)
|
|
: Resource(new Private(seat, this, parent, parentResource))
|
|
{
|
|
connect(seat, &SeatInterface::timestampChanged, this,
|
|
[this] {
|
|
Q_D();
|
|
d->simulateUserActivity();
|
|
}
|
|
);
|
|
connect(parent, &IdleInterface::inhibitedChanged, this,
|
|
[this] {
|
|
Q_D();
|
|
if (!d->timer) {
|
|
// not yet configured
|
|
return;
|
|
}
|
|
if (qobject_cast<IdleInterface*>(d->global)->isInhibited()) {
|
|
if (!d->timer->isActive() && d->resource) {
|
|
org_kde_kwin_idle_timeout_send_resumed(d->resource);
|
|
}
|
|
d->timer->stop();
|
|
} else {
|
|
d->timer->start();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
IdleTimeoutInterface::~IdleTimeoutInterface() = default;
|
|
|
|
IdleTimeoutInterface::Private *IdleTimeoutInterface::d_func() const
|
|
{
|
|
return reinterpret_cast<IdleTimeoutInterface::Private*>(d.data());
|
|
}
|
|
|
|
}
|