Commit 42246b78 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Simplify how infinite input regions are handled

Some input related code in kwin is mislead by the fact that when the
input region is infinite, SurfaceInterface::input() is going to return
an empty QRegion object.

We cannot really do that because the client could have just set a valid
empty wl_region object to ignore all input events.

This change makes SurfaceInterface assign an actually infinite region
when a NULL input region has been passed to set_input_region().
parent cd72d896
......@@ -479,14 +479,12 @@ void TestWaylandSurface::testAttachBuffer()
// commit a different value shouldn't change our buffer
QCOMPARE(serverSurface->buffer(), buffer3);
QVERIFY(serverSurface->input().isNull());
damageSpy.clear();
s->setInputRegion(m_compositor->createRegion(QRegion(0, 0, 24, 24)).get());
s->commit(KWayland::Client::Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCoreApplication::processEvents();
QCOMPARE(serverSurface->input(), QRegion(0, 0, 24, 24));
QCOMPARE(serverSurface->buffer(), buffer3);
QVERIFY(damageSpy.isEmpty());
QCOMPARE(mappedSpy.count(), 1);
......@@ -669,53 +667,59 @@ void TestWaylandSurface::testInput()
QVERIFY(serverSurface);
QSignalSpy inputRegionChangedSpy(serverSurface, SIGNAL(inputChanged(QRegion)));
QVERIFY(inputRegionChangedSpy.isValid());
QSignalSpy committedSpy(serverSurface, &SurfaceInterface::committed);
QVERIFY(committedSpy.isValid());
// by default there should be an empty == infinite input region
// the input region should be empty if the surface has no buffer
QVERIFY(!serverSurface->isMapped());
QCOMPARE(serverSurface->input(), QRegion());
QCOMPARE(serverSurface->inputIsInfinite(), true);
// the default input region is infinite
QImage black(100, 50, QImage::Format_RGB32);
black.fill(Qt::black);
QSharedPointer<KWayland::Client::Buffer> buffer1 = m_shm->createBuffer(black).toStrongRef();
QVERIFY(buffer1);
s->attachBuffer(buffer1);
s->commit(Surface::CommitFlag::None);
QVERIFY(committedSpy.wait());
QVERIFY(serverSurface->isMapped());
QCOMPARE(inputRegionChangedSpy.count(), 1);
QCOMPARE(serverSurface->input(), QRegion(0, 0, 100, 50));
// let's install an input region
s->setInputRegion(m_compositor->createRegion(QRegion(0, 10, 20, 30)).get());
// the region should only be applied after the surface got committed
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSurface->input(), QRegion());
QCOMPARE(serverSurface->inputIsInfinite(), true);
QCOMPARE(inputRegionChangedSpy.count(), 0);
QCOMPARE(inputRegionChangedSpy.count(), 1);
QCOMPARE(serverSurface->input(), QRegion(0, 0, 100, 50));
// so let's commit to get the new region
s->commit(Surface::CommitFlag::None);
QVERIFY(inputRegionChangedSpy.wait());
QCOMPARE(inputRegionChangedSpy.count(), 1);
QCOMPARE(inputRegionChangedSpy.last().first().value<QRegion>(), QRegion(0, 10, 20, 30));
QVERIFY(committedSpy.wait());
QCOMPARE(inputRegionChangedSpy.count(), 2);
QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30));
QCOMPARE(serverSurface->inputIsInfinite(), false);
// committing without setting a new region shouldn't change
s->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(inputRegionChangedSpy.count(), 1);
QCOMPARE(inputRegionChangedSpy.count(), 2);
QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30));
QCOMPARE(serverSurface->inputIsInfinite(), false);
// let's change the input region
// let's change the input region, note that the new input region is cropped
s->setInputRegion(m_compositor->createRegion(QRegion(10, 20, 30, 40)).get());
s->commit(Surface::CommitFlag::None);
QVERIFY(inputRegionChangedSpy.wait());
QCOMPARE(inputRegionChangedSpy.count(), 2);
QCOMPARE(inputRegionChangedSpy.last().first().value<QRegion>(), QRegion(10, 20, 30, 40));
QCOMPARE(serverSurface->input(), QRegion(10, 20, 30, 40));
QCOMPARE(serverSurface->inputIsInfinite(), false);
QVERIFY(committedSpy.wait());
QCOMPARE(inputRegionChangedSpy.count(), 3);
QCOMPARE(serverSurface->input(), QRegion(10, 20, 30, 30));
// and let's go back to an empty region
s->setInputRegion();
s->commit(Surface::CommitFlag::None);
QVERIFY(inputRegionChangedSpy.wait());
QCOMPARE(inputRegionChangedSpy.count(), 3);
QCOMPARE(inputRegionChangedSpy.last().first().value<QRegion>(), QRegion());
QCOMPARE(serverSurface->input(), QRegion());
QCOMPARE(serverSurface->inputIsInfinite(), true);
QVERIFY(committedSpy.wait());
QCOMPARE(inputRegionChangedSpy.count(), 4);
QCOMPARE(serverSurface->input(), QRegion(0, 0, 100, 50));
}
void TestWaylandSurface::testScale()
......
......@@ -430,6 +430,7 @@ set(SERVER_LIB_HEADERS
textinput_v2_interface.h
textinput_v3_interface.h
touch_interface.h
utils.h
viewporter_interface.h
xdgdecoration_v1_interface.h
xdgforeign_v2_interface.h
......
......@@ -158,7 +158,6 @@ void SubSurfaceInterface::Private::create(ClientConnection *client, quint32 vers
surfacePrivate->cached.contrastIsSet = false;
surfacePrivate->cached.frameCallbacks.clear();
surfacePrivate->cached.inputIsSet = false;
surfacePrivate->cached.inputIsInfinite = true;
surfacePrivate->cached.opaqueIsSet = false;
surfacePrivate->cached.shadowIsSet = false;
surfacePrivate->cached.slideIsSet = false;
......
......@@ -358,8 +358,7 @@ void SurfaceInterfacePrivate::surface_set_input_region(Resource *resource, struc
{
Q_UNUSED(resource)
RegionInterface *r = RegionInterface::get(region);
pending.input = r ? r->region() : QRegion();
pending.inputIsInfinite = !r;
pending.input = r ? r->region() : infiniteRegion();
pending.inputIsSet = true;
}
......@@ -522,6 +521,7 @@ void SurfaceInterfacePrivate::swapStates(State *source, State *target, bool emit
const QSize oldSize = target->size;
const QSize oldBufferSize = bufferSize;
const QMatrix4x4 oldSurfaceToBufferMatrix = surfaceToBufferMatrix;
const QRegion oldInputRegion = inputRegion;
if (bufferChanged) {
// TODO: is the reffing correct for subsurfaces?
if (target->buffer) {
......@@ -574,7 +574,6 @@ void SurfaceInterfacePrivate::swapStates(State *source, State *target, bool emit
}
if (inputRegionChanged) {
target->input = source->input;
target->inputIsInfinite = source->inputIsInfinite;
target->inputIsSet = true;
}
if (opaqueRegionChanged) {
......@@ -631,11 +630,12 @@ void SurfaceInterfacePrivate::swapStates(State *source, State *target, bool emit
}
surfaceToBufferMatrix = buildSurfaceToBufferMatrix(target);
bufferToSurfaceMatrix = surfaceToBufferMatrix.inverted();
inputRegion = target->input & QRect(QPoint(0, 0), target->size);
if (opaqueRegionChanged) {
emit q->opaqueChanged(target->opaque);
}
if (inputRegionChanged) {
emit q->inputChanged(target->input);
if (oldInputRegion != inputRegion) {
emit q->inputChanged(inputRegion);
}
if (scaleFactorChanged) {
emit q->bufferScaleChanged(target->bufferScale);
......@@ -748,12 +748,7 @@ QRegion SurfaceInterface::opaque() const
QRegion SurfaceInterface::input() const
{
return d->current.input;
}
bool SurfaceInterface::inputIsInfinite() const
{
return d->current.inputIsInfinite;
return d->inputRegion;
}
qint32 SurfaceInterface::bufferScale() const
......@@ -951,7 +946,7 @@ SurfaceInterface *SurfaceInterface::inputSurfaceAt(const QPointF &position)
}
// check whether the geometry and input region contain the pos
if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position) &&
(inputIsInfinite() || input().contains(position.toPoint()))) {
input().contains(position.toPoint())) {
return this;
}
return nullptr;
......
......@@ -163,7 +163,6 @@ public:
QRegion damage() const;
QRegion opaque() const;
QRegion input() const;
bool inputIsInfinite() const;
qint32 bufferScale() const;
/**
* Returns the buffer transform that had been applied to the buffer to compensate for
......
......@@ -8,6 +8,7 @@
#define WAYLAND_SERVER_SURFACE_INTERFACE_P_H
#include "surface_interface.h"
#include "utils.h"
// Qt
#include <QHash>
#include <QVector>
......@@ -41,7 +42,7 @@ public:
QRegion damage = QRegion();
QRegion bufferDamage = QRegion();
QRegion opaque = QRegion();
QRegion input = QRegion();
QRegion input = infiniteRegion();
QRectF sourceGeometry = QRectF();
QSize destinationSize = QSize();
QSize size = QSize();
......@@ -54,7 +55,6 @@ public:
bool blurIsSet = false;
bool contrastIsSet = false;
bool slideIsSet = false;
bool inputIsInfinite = true;
bool childrenChanged = false;
bool bufferScaleIsSet = false;
bool bufferTransformIsSet = false;
......@@ -104,6 +104,7 @@ public:
QMatrix4x4 surfaceToBufferMatrix;
QMatrix4x4 bufferToSurfaceMatrix;
QSize bufferSize;
QRegion inputRegion;
// workaround for https://bugreports.qt.io/browse/QTBUG-52192
// A subsurface needs to be considered mapped even if it doesn't have a buffer attached
......
/*
SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org>
SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
*/
#pragma once
#include <KWaylandServer/kwaylandserver_export.h>
#include <QRegion>
#include <limits>
namespace KWaylandServer
{
/**
* Returns an infinite region.
*/
inline QRegion KWAYLANDSERVER_EXPORT infiniteRegion()
{
return QRegion(std::numeric_limits<int>::min() / 2, // "/ 2" is to avoid integer overflows
std::numeric_limits<int>::min() / 2,
std::numeric_limits<int>::max(),
std::numeric_limits<int>::max());
}
} // namespace KWaylandServer
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment