diff --git a/autotests/client/test_idle.cpp b/autotests/client/test_idle.cpp --- a/autotests/client/test_idle.cpp +++ b/autotests/client/test_idle.cpp @@ -42,6 +42,7 @@ void testTimeout(); void testSimulateUserActivity(); + void testServerSimulateUserActivity(); void testIdleInhibit(); void testIdleInhibitBlocksTimeout(); @@ -188,6 +189,34 @@ m_display->dispatchEvents(); } +void IdleTest::testServerSimulateUserActivity() +{ + // this test verifies that simulate user activity doesn't fire the timer + QScopedPointer timeout(m_idle->getTimeout(6000, m_seat)); + QVERIFY(timeout->isValid()); + QSignalSpy idleSpy(timeout.data(), &IdleTimeout::idle); + QVERIFY(idleSpy.isValid()); + QSignalSpy resumedFormIdleSpy(timeout.data(), &IdleTimeout::resumeFromIdle); + QVERIFY(resumedFormIdleSpy.isValid()); + m_connection->flush(); + + QTest::qWait(4000); + m_idleInterface->simulateUserActivity(); + // waiting default five sec should fail + QVERIFY(!idleSpy.wait()); + // another 2 sec should fire + QVERIFY(idleSpy.wait(2000)); + + // now simulating user activity should emit a resumedFromIdle + QVERIFY(resumedFormIdleSpy.isEmpty()); + m_idleInterface->simulateUserActivity(); + QVERIFY(resumedFormIdleSpy.wait()); + + timeout.reset(); + m_connection->flush(); + m_display->dispatchEvents(); +} + void IdleTest::testIdleInhibit() { QCOMPARE(m_idleInterface->isInhibited(), false); diff --git a/src/server/idle_interface.h b/src/server/idle_interface.h --- a/src/server/idle_interface.h +++ b/src/server/idle_interface.h @@ -94,6 +94,15 @@ **/ bool isInhibited() const; + /** + * Calling this method allows the Compositor to simulate user activity. + * This means the same action is performed as if the user interacted with + * an input device on the SeatInterface. + * Idle timeouts are resumed and the idle time gets restarted. + * @since 5.42 + **/ + void simulateUserActivity(); + Q_SIGNALS: /** * Emitted when the system gets inhibited or uninhibited. diff --git a/src/server/idle_interface.cpp b/src/server/idle_interface.cpp --- a/src/server/idle_interface.cpp +++ b/src/server/idle_interface.cpp @@ -39,6 +39,7 @@ Private(IdleInterface *q, Display *d); int inhibitCount = 0; + QVector idleTimeouts; private: void bind(wl_client *client, uint32_t version, uint32_t id) override; @@ -61,6 +62,8 @@ ~Private(); void setup(quint32 timeout); + void simulateUserActivity(); + SeatInterface *seat; QTimer *timer = nullptr; @@ -98,6 +101,9 @@ delete idleTimeout; return; } + p->idleTimeouts << idleTimeout; + QObject::connect(idleTimeout, &IdleTimeoutInterface::aboutToBeUnbound, p->q, + std::bind(&QVector::removeOne, p->idleTimeouts, idleTimeout)); idleTimeout->d_func()->setup(timeout); } @@ -149,6 +155,14 @@ 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(d.data()); @@ -173,18 +187,23 @@ { Q_UNUSED(client); Private *p = reinterpret_cast(wl_resource_get_user_data(resource)); - if (!p->timer) { + p->simulateUserActivity(); +} + +void IdleTimeoutInterface::Private::simulateUserActivity() +{ + if (!timer) { // not yet configured return; } - if (qobject_cast(p->global)->isInhibited()) { + if (qobject_cast(global)->isInhibited()) { // ignored while inhibited return; } - if (!p->timer->isActive() && p->resource) { - org_kde_kwin_idle_timeout_send_resumed(p->resource); + if (!timer->isActive() && resource) { + org_kde_kwin_idle_timeout_send_resumed(resource); } - p->timer->start(); + timer->start(); } void IdleTimeoutInterface::Private::setup(quint32 timeout) @@ -216,18 +235,7 @@ connect(seat, &SeatInterface::timestampChanged, this, [this] { Q_D(); - if (!d->timer) { - // not yet configured - return; - } - if (qobject_cast(d->global)->isInhibited()) { - // ignored while inhibited - return; - } - if (!d->timer->isActive() && d->resource) { - org_kde_kwin_idle_timeout_send_resumed(d->resource); - } - d->timer->start(); + d->simulateUserActivity(); } ); connect(parent, &IdleInterface::inhibitedChanged, this,