fix: notice input on the lock screen despite idle inhibitors
This commit is contained in:
1 parent
7c87adb733
commit
77ae883b98
12 files changed
+280
-38
No files matched your search
@@ -0,0 +1,87 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "inputwatcher.h"
|
||||
|
||||
#include <QGuiApplication>
|
||||
#include <QWaylandClientExtensionTemplate>
|
||||
#include <QtGui/qguiapplication_platform.h>
|
||||
|
||||
#include <functional>
|
||||
|
||||
#include "qwayland-ext-idle-notify-v1.h"
|
||||
|
||||
class IdleNotifier : public QWaylandClientExtensionTemplate<IdleNotifier>, public QtWayland::ext_idle_notifier_v1
|
||||
{
|
||||
public:
|
||||
IdleNotifier()
|
||||
: QWaylandClientExtensionTemplate<IdleNotifier>(2)
|
||||
{
|
||||
initialize();
|
||||
}
|
||||
~IdleNotifier() override
|
||||
{
|
||||
if (isActive()) {
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class IdleNotification : public QtWayland::ext_idle_notification_v1
|
||||
{
|
||||
public:
|
||||
IdleNotification(::ext_idle_notification_v1 *object, std::function<void()> resumed)
|
||||
: QtWayland::ext_idle_notification_v1(object)
|
||||
, m_resumed(std::move(resumed))
|
||||
{
|
||||
}
|
||||
~IdleNotification() override
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
protected:
|
||||
// Only ever sent after idled: calm first, then this.
|
||||
void ext_idle_notification_v1_resumed() override
|
||||
{
|
||||
if (!m_fired) {
|
||||
m_fired = true;
|
||||
m_resumed();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::function<void()> m_resumed;
|
||||
bool m_fired = false;
|
||||
};
|
||||
|
||||
InputWatcher::InputWatcher(QObject *parent)
|
||||
: QObject(parent)
|
||||
, m_notifier(std::make_unique<IdleNotifier>())
|
||||
{
|
||||
}
|
||||
|
||||
InputWatcher::~InputWatcher() = default;
|
||||
|
||||
void InputWatcher::watch(int calmMs)
|
||||
{
|
||||
m_notification.reset();
|
||||
auto *wayland = qGuiApp->nativeInterface<QNativeInterface::QWaylandApplication>();
|
||||
if (!m_notifier->isActive() || !wayland || !wayland->seat()) {
|
||||
qWarning("no ext_idle_notifier_v1, so no telling when somebody comes back");
|
||||
return;
|
||||
}
|
||||
// Version 1 has only the notification that inhibitors hold back.
|
||||
::ext_idle_notification_v1 *object = m_notifier->QWaylandClientExtension::version() >= 2
|
||||
? m_notifier->get_input_idle_notification(uint32_t(calmMs), wayland->seat())
|
||||
: m_notifier->get_idle_notification(uint32_t(calmMs), wayland->seat());
|
||||
// Queued: not from inside the Wayland event, which the receiver might
|
||||
// answer by watching anew and so destroying the notification.
|
||||
m_notification = std::make_unique<IdleNotification>(object, [this] {
|
||||
QMetaObject::invokeMethod(this, &InputWatcher::input, Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
|
||||
void InputWatcher::stop()
|
||||
{
|
||||
m_notification.reset();
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
//
|
||||
// Somebody touching the machine: a key, a click, the mouse, the touchpad.
|
||||
//
|
||||
// From ext_idle_notifier_v1, like KIdleTime, but with the input notification
|
||||
// of version 2. KIdleTime's own honours idle inhibitors: with a video playing
|
||||
// or an app keeping the screen on, no key reached it and the lock screen never
|
||||
// scanned.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class IdleNotifier;
|
||||
class IdleNotification;
|
||||
|
||||
class InputWatcher : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit InputWatcher(QObject *parent = nullptr);
|
||||
~InputWatcher() override;
|
||||
|
||||
// Emit input() once, for the first input after nothing was touched for
|
||||
// calmMs. 0: the next input. Replaces what was watched before.
|
||||
void watch(int calmMs);
|
||||
void stop();
|
||||
|
||||
Q_SIGNALS:
|
||||
void input();
|
||||
|
||||
private:
|
||||
std::unique_ptr<IdleNotifier> m_notifier;
|
||||
std::unique_ptr<IdleNotification> m_notification;
|
||||
};
|
||||
@@ -6,8 +6,6 @@
|
||||
#include "daemonclient.h"
|
||||
#include "userconfig.h"
|
||||
|
||||
#include <KIdleTime>
|
||||
|
||||
#include <QDBusConnection>
|
||||
#include <QDBusMessage>
|
||||
#include <QDBusPendingCallWatcher>
|
||||
@@ -38,7 +36,10 @@ LockController::LockController(BubbleController *bubble, UserConfig *config, QOb
|
||||
, m_config(config)
|
||||
{
|
||||
m_armTimer.setSingleShot(true);
|
||||
connect(&m_armTimer, &QTimer::timeout, this, &LockController::arm);
|
||||
connect(&m_armTimer, &QTimer::timeout, this, [this] {
|
||||
arm(0);
|
||||
});
|
||||
connect(&m_input, &InputWatcher::input, this, &LockController::onResume);
|
||||
|
||||
QDBusConnection session = QDBusConnection::sessionBus();
|
||||
session.connect(QStringLiteral("org.freedesktop.ScreenSaver"),
|
||||
@@ -55,17 +56,6 @@ LockController::LockController(BubbleController *bubble, UserConfig *config, QOb
|
||||
this,
|
||||
SLOT(onPrepareForSleep(bool)));
|
||||
|
||||
KIdleTime *idle = KIdleTime::instance();
|
||||
connect(idle, &KIdleTime::resumingFromIdle, this, &LockController::onResume);
|
||||
connect(idle, qOverload<int, int>(&KIdleTime::timeoutReached), this, [this, idle](int id, int) {
|
||||
if (id != m_idleId) {
|
||||
return;
|
||||
}
|
||||
idle->removeIdleTimeout(id);
|
||||
m_idleId = -1;
|
||||
arm();
|
||||
});
|
||||
|
||||
// Started while the screen is already locked (the agent restarted).
|
||||
const QDBusMessage get = QDBusMessage::createMethodCall(QStringLiteral("org.freedesktop.ScreenSaver"),
|
||||
QStringLiteral("/ScreenSaver"),
|
||||
@@ -86,16 +76,10 @@ void LockController::onActiveChanged(bool active)
|
||||
if (active == m_locked) {
|
||||
return;
|
||||
}
|
||||
KIdleTime *idle = KIdleTime::instance();
|
||||
|
||||
if (!active) {
|
||||
m_locked = false;
|
||||
m_armTimer.stop();
|
||||
if (m_idleId >= 0) {
|
||||
idle->removeIdleTimeout(m_idleId);
|
||||
m_idleId = -1;
|
||||
}
|
||||
idle->stopCatchingResumeEvent();
|
||||
m_input.stop();
|
||||
if (m_scan) {
|
||||
m_scan->abort();
|
||||
m_scan->deleteLater();
|
||||
@@ -148,12 +132,12 @@ void LockController::onPrepareForSleep(bool sleeping)
|
||||
}
|
||||
}
|
||||
|
||||
void LockController::arm()
|
||||
void LockController::arm(int calmMs)
|
||||
{
|
||||
if (!m_locked || m_stopped || !m_config->scanOnWake()) {
|
||||
return;
|
||||
}
|
||||
KIdleTime::instance()->catchNextResumeEvent();
|
||||
m_input.watch(calmMs);
|
||||
}
|
||||
|
||||
void LockController::onResume()
|
||||
@@ -221,9 +205,7 @@ void LockController::onScanFinished(const QJsonObject &result)
|
||||
m_armTimer.start(GraceAfterLockMs);
|
||||
return;
|
||||
}
|
||||
if (m_idleId < 0) {
|
||||
m_idleId = KIdleTime::instance()->addIdleTimeout(CalmBeforeRetryMs);
|
||||
}
|
||||
arm(CalmBeforeRetryMs);
|
||||
}
|
||||
|
||||
void LockController::unlock()
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "inputwatcher.h"
|
||||
|
||||
#include <QElapsedTimer>
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
@@ -44,7 +46,8 @@ private Q_SLOTS:
|
||||
void onPrepareForSleep(bool sleeping);
|
||||
|
||||
private:
|
||||
void arm();
|
||||
// Scan at the next input after calmMs without any.
|
||||
void arm(int calmMs);
|
||||
void onResume();
|
||||
void startScan(const QString &why);
|
||||
void onScanFinished(const QJsonObject &result);
|
||||
@@ -58,5 +61,5 @@ private:
|
||||
QElapsedTimer m_lockedFor;
|
||||
QPointer<DaemonRequest> m_scan;
|
||||
QTimer m_armTimer;
|
||||
int m_idleId = -1;
|
||||
InputWatcher m_input;
|
||||
};
|
||||
Reference in new issue
Block a user