diff --git a/autotests/integration/transient_placement.cpp b/autotests/integration/transient_placement.cpp
index c9621ede98..ad033827e3 100644
--- a/autotests/integration/transient_placement.cpp
+++ b/autotests/integration/transient_placement.cpp
@@ -33,6 +33,7 @@ along with this program. If not, see .
#include
#include
#include
+#include
#include
#include
#include
@@ -63,6 +64,7 @@ private Q_SLOTS:
void testDecorationPosition();
void testXdgPopup_data();
void testXdgPopup();
+ void testXdgPopupWithPanel();
private:
AbstractClient *showWlShellWindow(const QSize &size, bool decorated = false, KWayland::Client::Surface *parent = nullptr, const QPoint &offset = QPoint());
@@ -91,7 +93,7 @@ void TransientPlacementTest::initTestCase()
void TransientPlacementTest::init()
{
- QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration));
+ QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration | Test::AdditionalWaylandInterface::PlasmaShell));
screens()->setCurrent(0);
Cursor::setPos(QPoint(640, 512));
@@ -378,6 +380,88 @@ void TransientPlacementTest::testXdgPopup()
QTEST(transient->geometry(), "expectedGeometry");
}
+void TransientPlacementTest::testXdgPopupWithPanel()
+{
+ using namespace KWayland::Client;
+
+ QScopedPointer surface{Test::createSurface()};
+ QVERIFY(!surface.isNull());
+ QScopedPointer dockShellSurface{Test::createXdgShellStableSurface(surface.data(), surface.data())};
+ QVERIFY(!dockShellSurface.isNull());
+ QScopedPointer plasmaSurface(Test::waylandPlasmaShell()->createSurface(surface.data()));
+ QVERIFY(!plasmaSurface.isNull());
+ plasmaSurface->setRole(PlasmaShellSurface::Role::Panel);
+ plasmaSurface->setPosition(QPoint(0, screens()->geometry(0).height() - 50));
+ plasmaSurface->setPanelBehavior(PlasmaShellSurface::PanelBehavior::AlwaysVisible);
+
+ // now render and map the window
+ QVERIFY(workspace()->clientArea(PlacementArea, 0, 1) == workspace()->clientArea(FullScreenArea, 0, 1));
+ auto dock = Test::renderAndWaitForShown(surface.data(), QSize(1280, 50), Qt::blue);
+ QVERIFY(dock);
+ QCOMPARE(dock->windowType(), NET::Dock);
+ QVERIFY(dock->isDock());
+ QCOMPARE(dock->geometry(), QRect(0, screens()->geometry(0).height() - 50, 1280, 50));
+ QCOMPARE(dock->hasStrut(), true);
+ QVERIFY(workspace()->clientArea(PlacementArea, 0, 1) != workspace()->clientArea(FullScreenArea, 0, 1));
+
+ //create parent
+ Surface *parentSurface = Test::createSurface(Test::waylandCompositor());
+ QVERIFY(parentSurface);
+ auto parentShellSurface = Test::createXdgShellStableSurface(parentSurface, Test::waylandCompositor());
+ QVERIFY(parentShellSurface);
+ auto parent = Test::renderAndWaitForShown(parentSurface, {800, 600}, Qt::blue);
+ QVERIFY(parent);
+
+ QVERIFY(!parent->isDecorated());
+ parent->move({0, screens()->geometry(0).height() - 600});
+ parent->keepInArea(workspace()->clientArea(PlacementArea, parent));
+ QCOMPARE(parent->geometry(), QRect(0, screens()->geometry(0).height() - 600 - 50, 800, 600));
+
+ Surface *transientSurface = Test::createSurface(Test::waylandCompositor());
+ QVERIFY(transientSurface);
+ XdgPositioner positioner(QSize(200,200), QRect(50,500, 200,200));
+
+ auto transientShellSurface = Test::createXdgShellStablePopup(transientSurface, parentShellSurface, positioner, Test::waylandCompositor());
+ auto transient = Test::renderAndWaitForShown(transientSurface, positioner.initialSize(), Qt::red);
+ QVERIFY(transient);
+
+ QVERIFY(!transient->isDecorated());
+ QVERIFY(transient->hasTransientPlacementHint());
+
+ QCOMPARE(transient->geometry(), QRect(50, screens()->geometry(0).height() - 200 - 50, 200, 200));
+
+ transientShellSurface->deleteLater();
+ transientSurface->deleteLater();
+ QVERIFY(Test::waitForWindowDestroyed(transient));
+
+ // now parent to fullscreen - on fullscreen the panel is ignored
+ QSignalSpy fullscreenSpy{parentShellSurface, &XdgShellSurface::configureRequested};
+ QVERIFY(fullscreenSpy.isValid());
+ parent->setFullScreen(true);
+ QVERIFY(fullscreenSpy.wait());
+ parentShellSurface->ackConfigure(fullscreenSpy.first().at(2).value());
+ QSignalSpy geometryShapeChangedSpy{parent, &ShellClient::geometryShapeChanged};
+ QVERIFY(geometryShapeChangedSpy.isValid());
+ Test::render(parentSurface, fullscreenSpy.first().at(0).toSize(), Qt::red);
+ QVERIFY(geometryShapeChangedSpy.wait());
+ QCOMPARE(parent->geometry(), screens()->geometry(0));
+ QVERIFY(parent->isFullScreen());
+
+ // another transient, with same hints as before from bottom of window
+ transientSurface = Test::createSurface(Test::waylandCompositor());
+ QVERIFY(transientSurface);
+
+ XdgPositioner positioner2(QSize(200,200), QRect(50,screens()->geometry(0).height()-100, 200,200));
+ transientShellSurface = Test::createXdgShellStablePopup(transientSurface, parentShellSurface, positioner2, Test::waylandCompositor());
+ transient = Test::renderAndWaitForShown(transientSurface, positioner2.initialSize(), Qt::red);
+ QVERIFY(transient);
+
+ QVERIFY(!transient->isDecorated());
+ QVERIFY(transient->hasTransientPlacementHint());
+
+ QCOMPARE(transient->geometry(), QRect(50, screens()->geometry(0).height() - 200, 200, 200));
+}
+
}
WAYLANDTEST_MAIN(KWin::TransientPlacementTest)
diff --git a/placement.cpp b/placement.cpp
index d11c2eb837..c190b9f2c2 100644
--- a/placement.cpp
+++ b/placement.cpp
@@ -498,7 +498,8 @@ void Placement::placeOnScreenDisplay(AbstractClient* c, QRect& area)
void Placement::placeTransient(AbstractClient *c)
{
- const QRect screen = screens()->geometry(c->transientFor()->screen());
+ const auto parent = c->transientFor();
+ const QRect screen = Workspace::self()->clientArea(parent->isFullScreen() ? FullScreenArea : PlacementArea, parent);
const QPoint popupPos = c->transientPlacement(screen).topLeft();
c->move(popupPos);