Commit 17cccfa2 authored by Vlad Zahorodnii's avatar Vlad Zahorodnii
Browse files

Allow placing subsurfaces below parent surface

According to the spec, if the parent surface is specified in the
wl_subsurface.place_below(), the subsurface has to be rendered below the
parent surface.

At the moment, kwaylandserver doesn't handle that case properly. It is
not possible for sub-surfaces to go below the parent surface.

Another issue is that we wrongly assume that the place_above request
will put the subsurface on top of the stack if the parent surface is
specified as sibling. It doesn't seem like that's the case, not
according to the spec.

This change splits the child sub-surface list in two lists - below and
above. The alternative solution is to store the parent surface in the
children list, but it's an error prone solution and it's conceptually
weird.
parent 9d8b387d
......@@ -199,14 +199,16 @@ void TestSubSurface::testCreate()
QCOMPARE(serverSurface->subSurface(), serverSubSurface);
QCOMPARE(serverSubSurface->mainSurface(), serverParentSurface);
// children are only added after committing the surface
QCOMPARE(serverParentSurface->below().count(), 0);
QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue);
QCOMPARE(serverParentSurface->childSubSurfaces().count(), 0);
QCOMPARE(serverParentSurface->above().count(), 0);
// so let's commit the surface, to apply the stacking change
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverParentSurface->childSubSurfaces().count(), 1);
QCOMPARE(serverParentSurface->childSubSurfaces().first(), serverSubSurface);
QCOMPARE(serverParentSurface->below().count(), 0);
QCOMPARE(serverParentSurface->above().count(), 1);
QCOMPARE(serverParentSurface->above().constFirst(), serverSubSurface);
// and let's destroy it again
QSignalSpy destroyedSpy(serverSubSurface, &QObject::destroyed);
......@@ -215,17 +217,19 @@ void TestSubSurface::testCreate()
QVERIFY(destroyedSpy.wait());
QCOMPARE(serverSurface->subSurface(), QPointer<SubSurfaceInterface>());
// only applied after next commit
QCOMPARE(serverParentSurface->below().count(), 0);
QEXPECT_FAIL("", "Incorrect removing of child windows to workaround QtWayland behavior", Continue);
QCOMPARE(serverParentSurface->childSubSurfaces().count(), 1);
QCOMPARE(serverParentSurface->above().count(), 1);
// but the surface should be invalid
if (!serverParentSurface->childSubSurfaces().isEmpty()) {
QVERIFY(!serverParentSurface->childSubSurfaces().first());
if (!serverParentSurface->above().isEmpty()) {
QVERIFY(!serverParentSurface->above().constFirst());
}
// committing the state should solve it
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverParentSurface->childSubSurfaces().count(), 0);
QCOMPARE(serverParentSurface->below().count(), 0);
QCOMPARE(serverParentSurface->above().count(), 0);
}
void TestSubSurface::testMode()
......@@ -368,74 +372,76 @@ void TestSubSurface::testPlaceAbove()
subSurfaceCreatedSpy.clear();
// so far the stacking order should still be empty
QVERIFY(serverSubSurface1->parentSurface()->below().isEmpty());
QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue);
QVERIFY(serverSubSurface1->parentSurface()->childSubSurfaces().isEmpty());
QVERIFY(serverSubSurface1->parentSurface()->above().isEmpty());
// committing the parent should create the stacking order
parent->commit(Surface::CommitFlag::None);
// ensure it's processed on server side
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 0);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3);
// raising subsurface1 should place it to top of stack
subSurface1->raise();
subSurface1->placeAbove(subSurface3.data());
// ensure it's processed on server side
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
// but as long as parent is not committed it shouldn't change on server side
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
// after commit it's changed
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
// try placing 3 above 1, should result in 2, 1, 3
subSurface3->placeAbove(QPointer<SubSurface>(subSurface1.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3);
// try placing 3 above 2, should result in 2, 3, 1
subSurface3->placeAbove(QPointer<SubSurface>(subSurface2.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
// try placing 1 above 3 - shouldn't change
subSurface1->placeAbove(QPointer<SubSurface>(subSurface3.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
// and 2 above 3 - > 3, 2, 1
subSurface2->placeAbove(QPointer<SubSurface>(subSurface3.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface1);
}
void TestSubSurface::testPlaceBelow()
......@@ -469,18 +475,19 @@ void TestSubSurface::testPlaceBelow()
subSurfaceCreatedSpy.clear();
// so far the stacking order should still be empty
QVERIFY(serverSubSurface1->parentSurface()->below().isEmpty());
QEXPECT_FAIL("", "Incorrect adding of child windows to workaround QtWayland behavior", Continue);
QVERIFY(serverSubSurface1->parentSurface()->childSubSurfaces().isEmpty());
QVERIFY(serverSubSurface1->parentSurface()->above().isEmpty());
// committing the parent should create the stacking order
parent->commit(Surface::CommitFlag::None);
// ensure it's processed on server side
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(2), serverSubSurface3);
// lowering subsurface3 should place it to the bottom of stack
subSurface3->lower();
......@@ -488,55 +495,60 @@ void TestSubSurface::testPlaceBelow()
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
// but as long as parent is not committed it shouldn't change on server side
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
// after commit it's changed
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 1);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 2);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(1), serverSubSurface2);
// place 1 below 3 -> 1, 3, 2
subSurface1->placeBelow(QPointer<SubSurface>(subSurface3.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 2);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 1);
QCOMPARE(serverSubSurface1->parentSurface()->above().at(0), serverSubSurface2);
// 2 below 3 -> 1, 2, 3
subSurface2->placeBelow(QPointer<SubSurface>(subSurface3.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0);
// 1 below 2 -> shouldn't change
subSurface1->placeBelow(QPointer<SubSurface>(subSurface2.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0);
// and 3 below 1 -> 3, 1, 2
subSurface3->placeBelow(QPointer<SubSurface>(subSurface1.data()));
parent->commit(Surface::CommitFlag::None);
wl_display_flush(m_connection->display());
QCoreApplication::processEvents();
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(0), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(1), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->childSubSurfaces().at(2), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->below().count(), 3);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(0), serverSubSurface3);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(1), serverSubSurface1);
QCOMPARE(serverSubSurface1->parentSurface()->below().at(2), serverSubSurface2);
QCOMPARE(serverSubSurface1->parentSurface()->above().count(), 0);
}
void TestSubSurface::testDestroy()
......@@ -728,19 +740,23 @@ void TestSubSurface::testMainSurfaceFromTree()
parentSurface->commit(Surface::CommitFlag::None);
QVERIFY(parentCommittedSpy.wait());
QCOMPARE(parentServerSurface->childSubSurfaces().count(), 1);
auto child = parentServerSurface->childSubSurfaces().first();
QCOMPARE(parentServerSurface->below().count(), 0);
QCOMPARE(parentServerSurface->above().count(), 1);
auto child = parentServerSurface->above().constFirst();
QCOMPARE(child->parentSurface(), parentServerSurface);
QCOMPARE(child->mainSurface(), parentServerSurface);
QCOMPARE(child->surface()->childSubSurfaces().count(), 1);
auto child2 = child->surface()->childSubSurfaces().first();
QCOMPARE(child->surface()->below().count(), 0);
QCOMPARE(child->surface()->above().count(), 1);
auto child2 = child->surface()->above().constFirst();
QCOMPARE(child2->parentSurface(), child->surface());
QCOMPARE(child2->mainSurface(), parentServerSurface);
QCOMPARE(child2->surface()->childSubSurfaces().count(), 1);
auto child3 = child2->surface()->childSubSurfaces().first();
QCOMPARE(child2->surface()->below().count(), 0);
QCOMPARE(child2->surface()->above().count(), 1);
auto child3 = child2->surface()->above().constFirst();
QCOMPARE(child3->parentSurface(), child2->surface());
QCOMPARE(child3->mainSurface(), parentServerSurface);
QCOMPARE(child3->surface()->childSubSurfaces().count(), 0);
QCOMPARE(child3->surface()->below().count(), 0);
QCOMPARE(child3->surface()->above().count(), 0);
}
void TestSubSurface::testRemoveSurface()
......@@ -768,12 +784,14 @@ void TestSubSurface::testRemoveSurface()
parentSurface->commit(Surface::CommitFlag::None);
QVERIFY(childrenChangedSpy.wait());
QCOMPARE(parentServerSurface->childSubSurfaces().count(), 1);
QCOMPARE(parentServerSurface->below().count(), 0);
QCOMPARE(parentServerSurface->above().count(), 1);
// destroy surface, takes place immediately
childSurface.reset();
QVERIFY(childrenChangedSpy.wait());
QCOMPARE(parentServerSurface->childSubSurfaces().count(), 0);
QCOMPARE(parentServerSurface->below().count(), 0);
QCOMPARE(parentServerSurface->above().count(), 0);
}
void TestSubSurface::testMappingOfSurfaceTree()
......@@ -810,15 +828,19 @@ void TestSubSurface::testMappingOfSurfaceTree()
parentSurface->commit(Surface::CommitFlag::None);
QVERIFY(parentCommittedSpy.wait());
QCOMPARE(parentServerSurface->childSubSurfaces().count(), 1);
auto child = parentServerSurface->childSubSurfaces().first();
QCOMPARE(child->surface()->childSubSurfaces().count(), 1);
auto child2 = child->surface()->childSubSurfaces().first();
QCOMPARE(child2->surface()->childSubSurfaces().count(), 1);
auto child3 = child2->surface()->childSubSurfaces().first();
QCOMPARE(parentServerSurface->below().count(), 0);
QCOMPARE(parentServerSurface->above().count(), 1);
auto child = parentServerSurface->above().constFirst();
QCOMPARE(child->surface()->below().count(), 0);
QCOMPARE(child->surface()->above().count(), 1);
auto child2 = child->surface()->above().constFirst();
QCOMPARE(child2->surface()->below().count(), 0);
QCOMPARE(child2->surface()->above().count(), 1);
auto child3 = child2->surface()->above().constFirst();
QCOMPARE(child3->parentSurface(), child2->surface());
QCOMPARE(child3->mainSurface(), parentServerSurface);
QCOMPARE(child3->surface()->childSubSurfaces().count(), 0);
QCOMPARE(child3->surface()->below().count(), 0);
QCOMPARE(child3->surface()->above().count(), 0);
// so far no surface is mapped
QVERIFY(!parentServerSurface->isMapped());
......
......@@ -193,8 +193,11 @@ void SubSurfaceInterfacePrivate::commit()
surfacePrivate->swapStates(&surfacePrivate->pending, &surfacePrivate->current, true);
}
const QList<SubSurfaceInterface *> children = surfacePrivate->current.children;
for (SubSurfaceInterface *subsurface : children) {
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.below)) {
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit();
}
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.above)) {
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit();
}
......@@ -219,8 +222,11 @@ void SubSurfaceInterfacePrivate::synchronizedCommit()
const SurfaceInterfacePrivate *surfacePrivate = SurfaceInterfacePrivate::get(surface);
commitFromCache();
const QList<SubSurfaceInterface *> children = surfacePrivate->current.children;
for (SubSurfaceInterface *subsurface : children) {
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.below)) {
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit(true);
}
for (SubSurfaceInterface *subsurface : qAsConst(surfacePrivate->current.above)) {
SubSurfaceInterfacePrivate *subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit(true);
}
......
......@@ -80,9 +80,9 @@ SurfaceInterfacePrivate::~SurfaceInterfacePrivate()
void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child)
{
// protocol is not precise on how to handle the addition of new sub surfaces
pending.children.append(child);
cached.children.append(child);
current.children.append(child);
pending.above.append(child);
cached.above.append(child);
current.above.append(child);
child->surface()->setOutputs(outputs);
Q_EMIT q->childSubSurfaceAdded(child);
Q_EMIT q->childSubSurfacesChanged();
......@@ -91,80 +91,66 @@ void SurfaceInterfacePrivate::addChild(SubSurfaceInterface *child)
void SurfaceInterfacePrivate::removeChild(SubSurfaceInterface *child)
{
// protocol is not precise on how to handle the addition of new sub surfaces
pending.children.removeAll(child);
cached.children.removeAll(child);
current.children.removeAll(child);
pending.below.removeAll(child);
pending.above.removeAll(child);
cached.below.removeAll(child);
cached.above.removeAll(child);
current.below.removeAll(child);
current.above.removeAll(child);
Q_EMIT q->childSubSurfaceRemoved(child);
Q_EMIT q->childSubSurfacesChanged();
}
bool SurfaceInterfacePrivate::raiseChild(SubSurfaceInterface *subsurface, SurfaceInterface *sibling)
bool SurfaceInterfacePrivate::raiseChild(SubSurfaceInterface *subsurface, SurfaceInterface *anchor)
{
auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
if (it == pending.children.end()) {
return false;
}
if (pending.children.count() == 1) {
// nothing to do
return true;
}
if (sibling == q) {
// it's to the parent, so needs to become last item
pending.children.erase(it);
pending.children.append(subsurface);
pending.childrenChanged = true;
return true;
}
if (!sibling->subSurface()) {
// not a sub surface
return false;
}
auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
if (siblingIt == pending.children.end() || siblingIt == it) {
// not a sibling
return false;
Q_ASSERT(subsurface->parentSurface() == q);
QList<SubSurfaceInterface *> *anchorList;
int anchorIndex;
pending.below.removeOne(subsurface);
pending.above.removeOne(subsurface);
if (anchor == q) {
// Pretend as if the parent surface were before the first child in the above list.
anchorList = &pending.above;
anchorIndex = -1;
} else if (anchorIndex = pending.above.indexOf(anchor->subSurface()); anchorIndex != -1) {
anchorList = &pending.above;
} else if (anchorIndex = pending.below.indexOf(anchor->subSurface()); anchorIndex != -1) {
anchorList = &pending.below;
} else {
return false; // The anchor belongs to other sub-surface tree.
}
auto value = (*it);
pending.children.erase(it);
// find the iterator again
siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
pending.children.insert(++siblingIt, value);
anchorList->insert(anchorIndex + 1, subsurface);
pending.childrenChanged = true;
return true;
}
bool SurfaceInterfacePrivate::lowerChild(SubSurfaceInterface *subsurface, SurfaceInterface *sibling)
bool SurfaceInterfacePrivate::lowerChild(SubSurfaceInterface *subsurface, SurfaceInterface *anchor)
{
auto it = std::find(pending.children.begin(), pending.children.end(), subsurface);
if (it == pending.children.end()) {
return false;
}
if (pending.children.count() == 1) {
// nothing to do
return true;
}
if (sibling == q) {
// it's to the parent, so needs to become first item
auto value = *it;
pending.children.erase(it);
pending.children.prepend(value);
pending.childrenChanged = true;
return true;
}
if (!sibling->subSurface()) {
// not a sub surface
return false;
}
auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
if (siblingIt == pending.children.end() || siblingIt == it) {
// not a sibling
return false;
Q_ASSERT(subsurface->parentSurface() == q);
QList<SubSurfaceInterface *> *anchorList;
int anchorIndex;
pending.below.removeOne(subsurface);
pending.above.removeOne(subsurface);
if (anchor == q) {
// Pretend as if the parent surface were after the last child in the below list.
anchorList = &pending.below;
anchorIndex = pending.below.count();
} else if (anchorIndex = pending.above.indexOf(anchor->subSurface()); anchorIndex != -1) {
anchorList = &pending.above;
} else if (anchorIndex = pending.below.indexOf(anchor->subSurface()); anchorIndex != -1) {
anchorList = &pending.below;
} else {
return false; // The anchor belongs to other sub-surface tree.
}
auto value = (*it);
pending.children.erase(it);
// find the iterator again
siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface());
pending.children.insert(siblingIt, value);
anchorList->insert(anchorIndex, subsurface);
pending.childrenChanged = true;
return true;
}
......@@ -409,8 +395,11 @@ void SurfaceInterface::frameRendered(quint32 msec)
frameCallback->send_done(msec);
frameCallback->destroy();
}
for (auto it = d->current.children.constBegin(); it != d->current.children.constEnd(); ++it) {
(*it)->surface()->frameRendered(msec);
for (SubSurfaceInterface *subsurface : qAsConst(d->current.below)) {
subsurface->surface()->frameRendered(msec);
}
for (SubSurfaceInterface *subsurface : qAsConst(d->current.above)) {
subsurface->surface()->frameRendered(msec);
}
}
......@@ -524,7 +513,8 @@ void SurfaceInterfacePrivate::swapStates(SurfaceState *source, SurfaceState *tar
}
if (childrenChanged) {
target->childrenChanged = source->childrenChanged;
target->children = source->children;
target->below = source->below;
target->above = source->above;
}
target->frameCallbacks.append(source->frameCallbacks);
......@@ -570,7 +560,8 @@ void SurfaceInterfacePrivate::swapStates(SurfaceState *source, SurfaceState *tar
}
*source = SurfaceState{};
source->children = target->children;
source->below = target->below;
source->above = target->above;
if (!emitChanged) {
return;
......@@ -666,8 +657,11 @@ void SurfaceInterfacePrivate::commit()
swapStates(&pending, &current, true);
// The position of a sub-surface is applied when its parent is committed.
const QList<SubSurfaceInterface *> children = current.children;
for (SubSurfaceInterface *subsurface : children) {
for (SubSurfaceInterface *subsurface : qAsConst(current.below)) {
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit();
}
for (SubSurfaceInterface *subsurface : qAsConst(current.above)) {
auto subsurfacePrivate = SubSurfaceInterfacePrivate::get(subsurface);
subsurfacePrivate->parentCommit();
}
......@@ -734,9 +728,14 @@ SurfaceInterface *SurfaceInterface::get(quint32 id, const ClientConnection *clie
return nullptr;
}
QList<SubSurfaceInterface *> SurfaceInterface::childSubSurfaces() const
QList<SubSurfaceInterface *> SurfaceInterface::below() const
{
return d->current.children;
return d->current.below;
}
QList<SubSurfaceInterface *> SurfaceInterface::above() const
{
return d->current.above;
}
SubSurfaceInterface *SurfaceInterface::subSurface() const
......@@ -753,8 +752,11 @@ QRect SurfaceInterface::boundingRect() const
{
QRect rect(QPoint(0, 0), size());
const QList<SubSurfaceInterface *> subSurfaces = childSubSurfaces();
for (const SubSurfaceInterface *subSurface : subSurfaces) {