[server] Add a method SurfaceInterface::surfaceAt(const QPointF&) -> SurfaceInterface*
Summary: The new method returns the (child) surface at a given surface position taking care of stacking order, whether surfaces are mapped, etc. Reviewers: #plasma Subscribers: plasma-devel Projects: #plasma Differential Revision: https://phabricator.kde.org/D1319
This commit is contained in:
parent
a2a888bc76
commit
37851e2e08
4 changed files with 158 additions and 0 deletions
|
@ -57,6 +57,7 @@ private Q_SLOTS:
|
|||
void testMainSurfaceFromTree();
|
||||
void testRemoveSurface();
|
||||
void testMappingOfSurfaceTree();
|
||||
void testSurfaceAt();
|
||||
|
||||
private:
|
||||
KWayland::Server::Display *m_display;
|
||||
|
@ -920,5 +921,84 @@ void TestSubSurface::testMappingOfSurfaceTree()
|
|||
QVERIFY(!child3->surface()->isMapped());
|
||||
}
|
||||
|
||||
void TestSubSurface::testSurfaceAt()
|
||||
{
|
||||
// this test verifies that the correct surface is picked in a sub-surface tree
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWayland::Server;
|
||||
// first create a parent surface and map it
|
||||
QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||
QVERIFY(serverSurfaceCreated.isValid());
|
||||
QScopedPointer<Surface> parent(m_compositor->createSurface());
|
||||
QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::red);
|
||||
parent->attachBuffer(m_shm->createBuffer(image));
|
||||
parent->damage(QRect(0, 0, 100, 100));
|
||||
parent->commit(Surface::CommitFlag::None);
|
||||
QVERIFY(serverSurfaceCreated.wait());
|
||||
SurfaceInterface *parentServerSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
||||
|
||||
// create two child sub surfaces, those won't be mapped, just added to the parent
|
||||
// this is to simulate the behavior of QtWayland
|
||||
QScopedPointer<Surface> directChild1(m_compositor->createSurface());
|
||||
QVERIFY(serverSurfaceCreated.wait());
|
||||
SurfaceInterface *directChild1ServerSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
||||
QScopedPointer<Surface> directChild2(m_compositor->createSurface());
|
||||
QVERIFY(serverSurfaceCreated.wait());
|
||||
SurfaceInterface *directChild2ServerSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
||||
|
||||
// create the sub surfaces for them
|
||||
QScopedPointer<SubSurface> directChild1SubSurface(m_subCompositor->createSubSurface(directChild1.data(), parent.data()));
|
||||
directChild1SubSurface->setMode(SubSurface::Mode::Desynchronized);
|
||||
QScopedPointer<SubSurface> directChild2SubSurface(m_subCompositor->createSubSurface(directChild2.data(), parent.data()));
|
||||
directChild2SubSurface->setMode(SubSurface::Mode::Desynchronized);
|
||||
|
||||
// each of the children gets a child
|
||||
QScopedPointer<Surface> childFor1(m_compositor->createSurface());
|
||||
QVERIFY(serverSurfaceCreated.wait());
|
||||
SurfaceInterface *childFor1ServerSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
||||
QScopedPointer<Surface> childFor2(m_compositor->createSurface());
|
||||
QVERIFY(serverSurfaceCreated.wait());
|
||||
SurfaceInterface *childFor2ServerSurface = serverSurfaceCreated.last().first().value<KWayland::Server::SurfaceInterface*>();
|
||||
|
||||
// create sub surfaces for them
|
||||
QScopedPointer<SubSurface> childFor1SubSurface(m_subCompositor->createSubSurface(childFor1.data(), directChild1.data()));
|
||||
childFor1SubSurface->setMode(SubSurface::Mode::Desynchronized);
|
||||
QScopedPointer<SubSurface> childFor2SubSurface(m_subCompositor->createSubSurface(childFor2.data(), directChild2.data()));
|
||||
childFor2SubSurface->setMode(SubSurface::Mode::Desynchronized);
|
||||
|
||||
// both get a quarter of the grand-parent surface
|
||||
childFor2SubSurface->setPosition(QPoint(50, 50));
|
||||
childFor2->commit(Surface::CommitFlag::None);
|
||||
directChild2->commit(Surface::CommitFlag::None);
|
||||
parent->commit(Surface::CommitFlag::None);
|
||||
|
||||
// now let's render both grand children
|
||||
QImage partImage(QSize(50, 50), QImage::Format_ARGB32_Premultiplied);
|
||||
partImage.fill(Qt::green);
|
||||
childFor1->attachBuffer(m_shm->createBuffer(partImage));
|
||||
childFor1->damage(QRect(0, 0, 50, 50));
|
||||
childFor1->commit(Surface::CommitFlag::None);
|
||||
partImage.fill(Qt::blue);
|
||||
childFor2->attachBuffer(m_shm->createBuffer(partImage));
|
||||
childFor2->damage(QRect(0, 0, 50, 50));
|
||||
childFor2->commit(Surface::CommitFlag::None);
|
||||
|
||||
QSignalSpy treeChangedSpy(parentServerSurface, &SurfaceInterface::subSurfaceTreeChanged);
|
||||
QVERIFY(treeChangedSpy.isValid());
|
||||
QVERIFY(treeChangedSpy.wait());
|
||||
|
||||
// now let's test a few positions
|
||||
QCOMPARE(parentServerSurface->surfaceAt(QPointF(0, 0)), childFor1ServerSurface);
|
||||
QCOMPARE(parentServerSurface->surfaceAt(QPointF(49, 49)), childFor1ServerSurface);
|
||||
QCOMPARE(parentServerSurface->surfaceAt(QPointF(50, 50)), childFor2ServerSurface);
|
||||
QCOMPARE(parentServerSurface->surfaceAt(QPointF(100, 100)), childFor2ServerSurface);
|
||||
QCOMPARE(parentServerSurface->surfaceAt(QPointF(25, 75)), parentServerSurface);
|
||||
QCOMPARE(parentServerSurface->surfaceAt(QPointF(75, 25)), parentServerSurface);
|
||||
// outside the geometries should be no surface
|
||||
QVERIFY(!parentServerSurface->surfaceAt(QPointF(-1, -1)));
|
||||
QVERIFY(!parentServerSurface->surfaceAt(QPointF(101, 101)));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestSubSurface)
|
||||
#include "test_wayland_subsurface.moc"
|
||||
|
|
|
@ -56,6 +56,7 @@ private Q_SLOTS:
|
|||
void testDestroy();
|
||||
void testUnmapOfNotMappedSurface();
|
||||
void testDamageTracking();
|
||||
void testSurfaceAt();
|
||||
|
||||
private:
|
||||
KWayland::Server::Display *m_display;
|
||||
|
@ -797,5 +798,40 @@ void TestWaylandSurface::testDamageTracking()
|
|||
QCOMPARE(serverSurface->damage(), QRegion(50, 40, 20, 30));
|
||||
}
|
||||
|
||||
void TestWaylandSurface::testSurfaceAt()
|
||||
{
|
||||
// this test verifies that surfaceAt(const QPointF&) works as expected for the case of no children
|
||||
using namespace KWayland::Client;
|
||||
using namespace KWayland::Server;
|
||||
// create surface
|
||||
QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated);
|
||||
QVERIFY(serverSurfaceCreated.isValid());
|
||||
QScopedPointer<Surface> s(m_compositor->createSurface());
|
||||
QVERIFY(serverSurfaceCreated.wait());
|
||||
SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value<KWayland::Server::SurfaceInterface*>();
|
||||
|
||||
// a newly created surface should not be mapped and not provide a surface at a position
|
||||
QVERIFY(!serverSurface->isMapped());
|
||||
QVERIFY(!serverSurface->surfaceAt(QPointF(0, 0)));
|
||||
|
||||
// let's damage this surface
|
||||
QSignalSpy sizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged);
|
||||
QVERIFY(sizeChangedSpy.isValid());
|
||||
QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied);
|
||||
image.fill(Qt::red);
|
||||
s->attachBuffer(m_shm->createBuffer(image));
|
||||
s->damage(QRect(0, 0, 100, 100));
|
||||
s->commit(Surface::CommitFlag::None);
|
||||
QVERIFY(sizeChangedSpy.wait());
|
||||
|
||||
// now the surface is mapped and surfaceAt should give the surface
|
||||
QVERIFY(serverSurface->isMapped());
|
||||
QCOMPARE(serverSurface->surfaceAt(QPointF(0, 0)), serverSurface);
|
||||
QCOMPARE(serverSurface->surfaceAt(QPointF(100, 100)), serverSurface);
|
||||
// outside the geometry it should not give a surface
|
||||
QVERIFY(!serverSurface->surfaceAt(QPointF(101, 101)));
|
||||
QVERIFY(!serverSurface->surfaceAt(QPointF(-1, -1)));
|
||||
}
|
||||
|
||||
QTEST_GUILESS_MAIN(TestWaylandSurface)
|
||||
#include "test_wayland_surface.moc"
|
||||
|
|
|
@ -25,6 +25,8 @@ License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
|||
#include "region_interface.h"
|
||||
#include "subcompositor_interface.h"
|
||||
#include "subsurface_interface_p.h"
|
||||
// Qt
|
||||
#include <QListIterator>
|
||||
// Wayland
|
||||
#include <wayland-server.h>
|
||||
// std
|
||||
|
@ -692,6 +694,32 @@ void SurfaceInterface::resetTrackedDamage()
|
|||
d->trackedDamage = QRegion();
|
||||
}
|
||||
|
||||
SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position)
|
||||
{
|
||||
if (!isMapped()) {
|
||||
return nullptr;
|
||||
}
|
||||
Q_D();
|
||||
// go from top to bottom. Top most child is last in list
|
||||
QListIterator<QPointer<SubSurfaceInterface>> it(d->current.children);
|
||||
it.toBack();
|
||||
while (it.hasPrevious()) {
|
||||
const auto ¤t = it.previous();
|
||||
auto surface = current->surface();
|
||||
if (surface.isNull()) {
|
||||
continue;
|
||||
}
|
||||
if (auto s = surface->surfaceAt(position - current->position())) {
|
||||
return s;
|
||||
}
|
||||
}
|
||||
// check whether the geometry contains the pos
|
||||
if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position)) {
|
||||
return this;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
SurfaceInterface::Private *SurfaceInterface::d_func() const
|
||||
{
|
||||
return reinterpret_cast<Private*>(d.data());
|
||||
|
|
|
@ -191,6 +191,20 @@ public:
|
|||
**/
|
||||
void resetTrackedDamage();
|
||||
|
||||
/**
|
||||
* Finds the SurfaceInterface at the given @p position in surface-local coordinates.
|
||||
* This can be either a descendant SurfaceInterface honoring the stacking order or
|
||||
* the SurfaceInterface itself if its geometry contains the given @p position.
|
||||
*
|
||||
* If no such SurfaceInterface is found, e.g. because the SurfaceInterface is unmapped,
|
||||
* @c nullptr is returned.
|
||||
*
|
||||
* @param position The position in surface-local coordinates
|
||||
* @returns Child surface at the given @p position or surface itself at the position, might be @c nullptr
|
||||
* @since 5.7
|
||||
**/
|
||||
SurfaceInterface *surfaceAt(const QPointF &position);
|
||||
|
||||
/**
|
||||
* @returns The SurfaceInterface for the @p native resource.
|
||||
**/
|
||||
|
|
Loading…
Reference in a new issue