Add support for opaque and input region to Surface

Implemented on both Client and Server side.
This commit is contained in:
Martin Gräßlin 2014-10-16 14:59:01 +02:00
parent 7fce72b7d1
commit 5debfb6832
4 changed files with 157 additions and 10 deletions

View file

@ -24,6 +24,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "../../src/client/compositor.h"
#include "../../src/client/connection_thread.h"
#include "../../src/client/surface.h"
#include "../../src/client/region.h"
#include "../../src/client/registry.h"
#include "../../src/client/shm_pool.h"
#include "../../src/server/buffer_interface.h"
@ -46,6 +47,8 @@ private Q_SLOTS:
void testDamage();
void testFrameCallback();
void testAttachBuffer();
void testOpaque();
void testInput();
void testDestroy();
private:
@ -344,6 +347,122 @@ void TestWaylandSurface::testAttachBuffer()
buffer->unref();
}
void TestWaylandSurface::testOpaque()
{
using namespace KWayland::Client;
using namespace KWayland::Server;
QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
Surface *s = m_compositor->createSurface();
QVERIFY(serverSurfaceCreated.wait());
SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
QVERIFY(serverSurface);
QSignalSpy opaqueRegionChangedSpy(serverSurface, SIGNAL(opaqueChanged(QRegion)));
QVERIFY(opaqueRegionChangedSpy.isValid());
// by default there should be an empty opaque region
QCOMPARE(serverSurface->opaque(), QRegion());
// let's install an opaque region
s->setOpaqueRegion(m_compositor->createRegion(QRegion(0, 10, 20, 30)).get());
// the region should only be applied after the surface got commited
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSurface->opaque(), QRegion());
QCOMPARE(opaqueRegionChangedSpy.count(), 0);
// so let's commit to get the new region
s->commit(Surface::CommitFlag::None);
QVERIFY(opaqueRegionChangedSpy.wait());
QCOMPARE(opaqueRegionChangedSpy.count(), 1);
QCOMPARE(opaqueRegionChangedSpy.last().first().value<QRegion>(), QRegion(0, 10, 20, 30));
QCOMPARE(serverSurface->opaque(), QRegion(0, 10, 20, 30));
// committing without setting a new region shouldn't change
s->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(opaqueRegionChangedSpy.count(), 1);
QCOMPARE(serverSurface->opaque(), QRegion(0, 10, 20, 30));
// let's change the opaque region
s->setOpaqueRegion(m_compositor->createRegion(QRegion(10, 20, 30, 40)).get());
s->commit(Surface::CommitFlag::None);
QVERIFY(opaqueRegionChangedSpy.wait());
QCOMPARE(opaqueRegionChangedSpy.count(), 2);
QCOMPARE(opaqueRegionChangedSpy.last().first().value<QRegion>(), QRegion(10, 20, 30, 40));
QCOMPARE(serverSurface->opaque(), QRegion(10, 20, 30, 40));
// and let's go back to an empty region
s->setOpaqueRegion();
s->commit(Surface::CommitFlag::None);
QVERIFY(opaqueRegionChangedSpy.wait());
QCOMPARE(opaqueRegionChangedSpy.count(), 3);
QCOMPARE(opaqueRegionChangedSpy.last().first().value<QRegion>(), QRegion());
QCOMPARE(serverSurface->opaque(), QRegion());
}
void TestWaylandSurface::testInput()
{
using namespace KWayland::Client;
using namespace KWayland::Server;
QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*)));
QVERIFY(serverSurfaceCreated.isValid());
Surface *s = m_compositor->createSurface();
QVERIFY(serverSurfaceCreated.wait());
SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
QVERIFY(serverSurface);
QSignalSpy inputRegionChangedSpy(serverSurface, SIGNAL(inputChanged(QRegion)));
QVERIFY(inputRegionChangedSpy.isValid());
// by default there should be an empty == infinite input region
QCOMPARE(serverSurface->input(), QRegion());
QCOMPARE(serverSurface->inputIsInfitine(), true);
// 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 commited
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSurface->input(), QRegion());
QCOMPARE(serverSurface->inputIsInfitine(), true);
QCOMPARE(inputRegionChangedSpy.count(), 0);
// 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));
QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30));
QCOMPARE(serverSurface->inputIsInfitine(), 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(serverSurface->input(), QRegion(0, 10, 20, 30));
QCOMPARE(serverSurface->inputIsInfitine(), false);
// let's change the input region
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->inputIsInfitine(), false);
// 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->inputIsInfitine(), true);
}
void TestWaylandSurface::testDestroy()
{
using namespace KWayland::Client;

View file

@ -21,6 +21,7 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
#include "surface_interface_p.h"
#include "buffer_interface.h"
#include "compositor_interface.h"
#include "region_interface.h"
#include "subcompositor_interface.h"
#include "subsurface_interface_p.h"
// Wayland
@ -217,8 +218,8 @@ void SurfaceInterface::Private::commit()
for (wl_resource *c : current.callbacks) {
wl_resource_destroy(c);
}
const bool opaqueRegionChanged = current.opaque != pending.opaque;
const bool inputRegionChanged = current.input != pending.input;
const bool opaqueRegionChanged = pending.opaqueIsSet;
const bool inputRegionChanged = pending.inputIsSet;
const bool scaleFactorChanged = current.scale != pending.scale;
const bool transformFactorChanged = current.transform != pending.transform;
if (current.buffer) {
@ -231,6 +232,9 @@ void SurfaceInterface::Private::commit()
current = pending;
pending = State{};
pending.children = current.children;
pending.input = current.input;
pending.inputIsInfinite = current.inputIsInfinite;
pending.opaque = current.opaque;
// commit all subSurfaces to apply position changes
for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) {
if (!(*it)) {
@ -325,18 +329,31 @@ void SurfaceInterface::Private::frameCallaback(wl_client *client, wl_resource *r
void SurfaceInterface::Private::opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
{
Q_UNUSED(client)
Q_UNUSED(resource)
Q_UNUSED(region)
// TODO: implement me
auto s = cast(resource);
Q_ASSERT(client == s->client);
auto r = RegionInterface::get(region);
s->setOpaque(r ? r->region() : QRegion());
}
void SurfaceInterface::Private::setOpaque(const QRegion &region)
{
pending.opaqueIsSet = true;
pending.opaque = region;
}
void SurfaceInterface::Private::inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region)
{
Q_UNUSED(client)
Q_UNUSED(resource)
Q_UNUSED(region)
// TODO: implement me
auto s = cast(resource);
Q_ASSERT(client == s->client);
auto r = RegionInterface::get(region);
s->setInput(r ? r->region() : QRegion(), !r);
}
void SurfaceInterface::Private::setInput(const QRegion &region, bool isInfinite)
{
pending.inputIsSet = true;
pending.inputIsInfinite = isInfinite;
pending.input = region;
}
void SurfaceInterface::Private::commitCallback(wl_client *client, wl_resource *resource)
@ -382,6 +399,11 @@ QRegion SurfaceInterface::input() const
return d->current.input;
}
bool SurfaceInterface::inputIsInfitine() const
{
return d->current.inputIsInfinite;
}
qint32 SurfaceInterface::scale() const
{
return d->current.scale;

View file

@ -57,6 +57,7 @@ public:
QRegion damage() const;
QRegion opaque() const;
QRegion input() const;
bool inputIsInfitine() const;
qint32 scale() const;
OutputInterface::Transform transform() const;
BufferInterface *buffer();

View file

@ -36,6 +36,9 @@ public:
QRegion damage = QRegion();
QRegion opaque = QRegion();
QRegion input = QRegion();
bool inputIsSet = false;
bool opaqueIsSet = false;
bool inputIsInfinite = true;
qint32 scale = 1;
OutputInterface::Transform transform = OutputInterface::Transform::Normal;
QList<wl_resource*> callbacks = QList<wl_resource*>();
@ -71,6 +74,8 @@ private:
void setTransform(OutputInterface::Transform transform);
void addFrameCallback(uint32_t callback);
void attachBuffer(wl_resource *buffer, const QPoint &offset);
void setOpaque(const QRegion &region);
void setInput(const QRegion &region, bool isInfinite);
static Private *cast(wl_resource *r);