[backends/drm] Use an InputEventFilter to reenable outputs
So far the DrmOutput connected to all input events when going into power saving. As we now have the input filters it's better to just install a filter when an output goes into powersave and remove the input filter again when all outputs are enabled again. To make this work InputRedirection gains a new method to add a new filter as the first filter. This is a potentially dangerous method as it allows to have a filter before LockScreenFilter gets the events. But in case of DPMS it's something we actually want. A nice new feature possible with the input filter is that we can filter out the event which re-enables the outputs. Thus when getting on a system with output off and screen locked, the first key hit doesn't go to the lock screen. Reviewed-By: Bhushan Shah BUG: 341201 Fixed-in: 5.6.0 (Wayland-only)
This commit is contained in:
parent
4e32dcfbfe
commit
57b11f8429
4 changed files with 115 additions and 16 deletions
|
@ -20,7 +20,6 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#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 <http://www.gnu.org/licenses/>.
|
|||
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) {
|
||||
|
|
|
@ -20,6 +20,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|||
#ifndef KWIN_DRM_BACKEND_H
|
||||
#define KWIN_DRM_BACKEND_H
|
||||
#include "abstract_backend.h"
|
||||
#include "input.h"
|
||||
|
||||
#include <QImage>
|
||||
#include <QPointer>
|
||||
|
@ -45,6 +46,7 @@ class UdevMonitor;
|
|||
|
||||
class DrmBuffer;
|
||||
class DrmOutput;
|
||||
class DpmsInputEventFilter;
|
||||
|
||||
template <typename Pointer, void (*cleanupFunc)(Pointer*)>
|
||||
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<DrmBuffer*> m_buffers;
|
||||
QScopedPointer<DpmsInputEventFilter> 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*)
|
||||
|
|
|
@ -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);
|
||||
|
|
10
input.h
10
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();
|
||||
|
|
Loading…
Reference in a new issue