diff --git a/backends/drm/drm_backend.cpp b/backends/drm/drm_backend.cpp
index add296badb..06cc0d1274 100644
--- a/backends/drm/drm_backend.cpp
+++ b/backends/drm/drm_backend.cpp
@@ -20,7 +20,6 @@ along with this program. If not, see .
#include "drm_backend.h"
#include "composite.h"
#include "cursor.h"
-#include "input.h"
#include "logging.h"
#include "logind.h"
#include "scene_qpainter_drm_backend.h"
@@ -64,10 +63,47 @@ along with this program. If not, see .
namespace KWin
{
+DpmsInputEventFilter::DpmsInputEventFilter(DrmBackend *backend)
+ : InputEventFilter()
+ , m_backend(backend)
+{
+}
+
+DpmsInputEventFilter::~DpmsInputEventFilter() = default;
+
+bool DpmsInputEventFilter::pointerEvent(QMouseEvent *event, quint32 nativeButton)
+{
+ Q_UNUSED(event)
+ Q_UNUSED(nativeButton)
+ notify();
+ return true;
+}
+
+bool DpmsInputEventFilter::wheelEvent(QWheelEvent *event)
+{
+ Q_UNUSED(event)
+ notify();
+ return true;
+}
+
+bool DpmsInputEventFilter::keyEvent(QKeyEvent *event)
+{
+ Q_UNUSED(event)
+ notify();
+ return true;
+}
+
+void DpmsInputEventFilter::notify()
+{
+ // queued to not modify the list of event filters while filtering
+ QMetaObject::invokeMethod(m_backend, "turnOututsOn", Qt::QueuedConnection);
+}
+
DrmBackend::DrmBackend(QObject *parent)
: AbstractBackend(parent)
, m_udev(new Udev)
, m_udevMonitor(m_udev->monitor())
+ , m_dpmsFilter()
{
handleOutputs();
m_cursor[0] = nullptr;
@@ -108,6 +144,40 @@ void DrmBackend::init()
connect(v, &VirtualTerminal::activeChanged, this, &DrmBackend::activate);
}
+void DrmBackend::outputWentOff()
+{
+ if (!m_dpmsFilter.isNull()) {
+ // already another output is off
+ return;
+ }
+ m_dpmsFilter.reset(new DpmsInputEventFilter(this));
+ input()->prepandInputEventFilter(m_dpmsFilter.data());
+}
+
+void DrmBackend::turnOututsOn()
+{
+ m_dpmsFilter.reset();
+ for (auto it = m_outputs.constBegin(), end = m_outputs.constEnd(); it != end; it++) {
+ (*it)->setDpms(DrmOutput::DpmsMode::On);
+ }
+}
+
+void DrmBackend::checkOutputsAreOn()
+{
+ if (m_dpmsFilter.isNull()) {
+ // already disabled, all outputs are on
+ return;
+ }
+ for (auto it = m_outputs.constBegin(), end = m_outputs.constEnd(); it != end; it++) {
+ if (!(*it)->isDpmsEnabled()) {
+ // dpms still disabled, need to keep the filter
+ return;
+ }
+ }
+ // all outputs are on, disable the filter
+ m_dpmsFilter.reset();
+}
+
void DrmBackend::activate(bool active)
{
if (active) {
@@ -996,6 +1066,9 @@ void DrmOutput::setDpms(DrmOutput::DpmsMode mode)
if (m_dpms.isNull()) {
return;
}
+ if (mode == m_dpmsMode) {
+ return;
+ }
if (drmModeConnectorSetProperty(m_backend->fd(), m_connector, m_dpms->prop_id, uint64_t(mode)) != 0) {
qCWarning(KWIN_DRM) << "Setting DPMS failed";
return;
@@ -1006,15 +1079,9 @@ void DrmOutput::setDpms(DrmOutput::DpmsMode mode)
}
emit dpmsChanged();
if (m_dpmsMode != DpmsMode::On) {
- connect(input(), &InputRedirection::globalPointerChanged, this, &DrmOutput::reenableDpms);
- connect(input(), &InputRedirection::pointerButtonStateChanged, this, &DrmOutput::reenableDpms);
- connect(input(), &InputRedirection::pointerAxisChanged, this, &DrmOutput::reenableDpms);
- connect(input(), &InputRedirection::keyStateChanged, this, &DrmOutput::reenableDpms);
+ m_backend->outputWentOff();
} else {
- disconnect(input(), &InputRedirection::globalPointerChanged, this, &DrmOutput::reenableDpms);
- disconnect(input(), &InputRedirection::pointerButtonStateChanged, this, &DrmOutput::reenableDpms);
- disconnect(input(), &InputRedirection::pointerAxisChanged, this, &DrmOutput::reenableDpms);
- disconnect(input(), &InputRedirection::keyStateChanged, this, &DrmOutput::reenableDpms);
+ m_backend->checkOutputsAreOn();
blank();
if (Compositor *compositor = Compositor::self()) {
compositor->addRepaintFull();
@@ -1022,11 +1089,6 @@ void DrmOutput::setDpms(DrmOutput::DpmsMode mode)
}
}
-void DrmOutput::reenableDpms()
-{
- setDpms(DpmsMode::On);
-}
-
QString DrmOutput::name() const
{
if (!m_waylandOutput) {
diff --git a/backends/drm/drm_backend.h b/backends/drm/drm_backend.h
index b247776b72..daa3167cfe 100644
--- a/backends/drm/drm_backend.h
+++ b/backends/drm/drm_backend.h
@@ -20,6 +20,7 @@ along with this program. If not, see .
#ifndef KWIN_DRM_BACKEND_H
#define KWIN_DRM_BACKEND_H
#include "abstract_backend.h"
+#include "input.h"
#include
#include
@@ -45,6 +46,7 @@ class UdevMonitor;
class DrmBuffer;
class DrmOutput;
+class DpmsInputEventFilter;
template
struct DrmCleanup
@@ -88,6 +90,13 @@ public:
}
void bufferDestroyed(DrmBuffer *b);
+ void outputWentOff();
+ void checkOutputsAreOn();
+
+public Q_SLOTS:
+ void turnOututsOn();
+
+
Q_SIGNALS:
void outputRemoved(KWin::DrmOutput *output);
void outputAdded(KWin::DrmOutput *output);
@@ -120,6 +129,7 @@ private:
int m_pageFlipsPending = 0;
bool m_active = false;
QVector m_buffers;
+ QScopedPointer m_dpmsFilter;
};
class DrmOutput : public QObject
@@ -172,7 +182,6 @@ private:
void initEdid(drmModeConnector *connector);
void initDpms(drmModeConnector *connector);
bool isCurrentMode(const drmModeModeInfo *mode) const;
- void reenableDpms();
void initUuid();
void setGlobalPos(const QPoint &pos);
@@ -243,6 +252,21 @@ private:
QImage *m_image = nullptr;
};
+class DpmsInputEventFilter : public InputEventFilter
+{
+public:
+ DpmsInputEventFilter(DrmBackend *backend);
+ ~DpmsInputEventFilter();
+
+ bool pointerEvent(QMouseEvent *event, quint32 nativeButton) override;
+ bool wheelEvent(QWheelEvent *event) override;
+ bool keyEvent(QKeyEvent *event) override;
+
+private:
+ void notify();
+ DrmBackend *m_backend;
+};
+
}
Q_DECLARE_METATYPE(KWin::DrmOutput*)
diff --git a/input.cpp b/input.cpp
index 97af259e7c..18aa8203a6 100644
--- a/input.cpp
+++ b/input.cpp
@@ -626,6 +626,11 @@ void InputRedirection::installInputEventFilter(InputEventFilter *filter)
m_filters << filter;
}
+void InputRedirection::prepandInputEventFilter(InputEventFilter *filter)
+{
+ m_filters.prepend(filter);
+}
+
void InputRedirection::uninstallInputEventFilter(InputEventFilter *filter)
{
m_filters.removeAll(filter);
diff --git a/input.h b/input.h
index 466b9bee01..1de4d9f9a0 100644
--- a/input.h
+++ b/input.h
@@ -128,6 +128,14 @@ public:
bool supportsPointerWarping() const;
void warpPointer(const QPointF &pos);
+ /**
+ * Adds the @p filter to the list of event filters and makes it the first
+ * event filter in processing.
+ *
+ * Note: the event filter will get events before the lock screen can get them, thus
+ * this is a security relevant method.
+ **/
+ void prepandInputEventFilter(InputEventFilter *filter);
void uninstallInputEventFilter(InputEventFilter *filter);
Toplevel *findToplevel(const QPoint &pos);
GlobalShortcutsManager *shortcuts() const {
@@ -230,7 +238,7 @@ private:
* Deleting an instance of InputEventFilter automatically uninstalls it from
* InputRedirection.
**/
-class InputEventFilter
+class KWIN_EXPORT InputEventFilter
{
public:
InputEventFilter();