Warning, file /plasma/kwin/autotests/integration/transient_placement.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
0001 /* 0002 KWin - the KDE window manager 0003 This file is part of the KDE project. 0004 0005 SPDX-FileCopyrightText: 2016 Martin Gräßlin <mgraesslin@kde.org> 0006 0007 SPDX-License-Identifier: GPL-2.0-or-later 0008 */ 0009 #include "kwin_wayland_test.h" 0010 0011 #include "core/output.h" 0012 #include "core/outputbackend.h" 0013 #include "cursor.h" 0014 #include "wayland/seat_interface.h" 0015 #include "wayland/surface_interface.h" 0016 #include "wayland_server.h" 0017 #include "window.h" 0018 #include "workspace.h" 0019 #include <kwineffects.h> 0020 0021 #include <KWayland/Client/compositor.h> 0022 #include <KWayland/Client/connection_thread.h> 0023 #include <KWayland/Client/event_queue.h> 0024 #include <KWayland/Client/keyboard.h> 0025 #include <KWayland/Client/plasmashell.h> 0026 #include <KWayland/Client/pointer.h> 0027 #include <KWayland/Client/registry.h> 0028 #include <KWayland/Client/seat.h> 0029 #include <KWayland/Client/server_decoration.h> 0030 #include <KWayland/Client/shm_pool.h> 0031 #include <KWayland/Client/surface.h> 0032 #include <KWayland/Client/touch.h> 0033 0034 struct PopupLayout 0035 { 0036 QRect anchorRect; 0037 QSize size; 0038 quint32 anchor = 0; 0039 quint32 gravity = 0; 0040 quint32 constraint = 0; 0041 }; 0042 Q_DECLARE_METATYPE(PopupLayout) 0043 0044 namespace KWin 0045 { 0046 0047 static const QString s_socketName = QStringLiteral("wayland_test_kwin_transient_placement-0"); 0048 0049 class TransientPlacementTest : public QObject 0050 { 0051 Q_OBJECT 0052 private Q_SLOTS: 0053 void initTestCase(); 0054 void init(); 0055 void cleanup(); 0056 void testXdgPopup_data(); 0057 void testXdgPopup(); 0058 void testXdgPopupWithPanel(); 0059 }; 0060 0061 void TransientPlacementTest::initTestCase() 0062 { 0063 qRegisterMetaType<KWin::Window *>(); 0064 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0065 QVERIFY(waylandServer()->init(s_socketName)); 0066 QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); 0067 0068 kwinApp()->start(); 0069 QVERIFY(applicationStartedSpy.wait()); 0070 const auto outputs = workspace()->outputs(); 0071 QCOMPARE(outputs.count(), 2); 0072 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0073 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0074 setenv("QT_QPA_PLATFORM", "wayland", true); 0075 } 0076 0077 void TransientPlacementTest::init() 0078 { 0079 QVERIFY(Test::setupWaylandConnection(Test::AdditionalWaylandInterface::Decoration | Test::AdditionalWaylandInterface::PlasmaShell)); 0080 0081 workspace()->setActiveOutput(QPoint(640, 512)); 0082 Cursors::self()->mouse()->setPos(QPoint(640, 512)); 0083 } 0084 0085 void TransientPlacementTest::cleanup() 0086 { 0087 Test::destroyWaylandConnection(); 0088 } 0089 0090 void TransientPlacementTest::testXdgPopup_data() 0091 { 0092 QTest::addColumn<QSize>("parentSize"); 0093 QTest::addColumn<QPoint>("parentPosition"); 0094 QTest::addColumn<PopupLayout>("layout"); 0095 QTest::addColumn<QRect>("expectedGeometry"); 0096 0097 // parent window is 500,500, starting at 300,300, anchorRect is therefore between 350->750 in both dirs 0098 0099 // ---------------------------------------------------------------- 0100 // window in the middle, plenty of room either side: Changing anchor 0101 0102 const PopupLayout layoutAnchorCenter{ 0103 .anchorRect = QRect(50, 50, 400, 400), 0104 .size = QSize(200, 200), 0105 .anchor = Test::XdgPositioner::anchor_none, 0106 .gravity = Test::XdgPositioner::gravity_bottom_right, 0107 }; 0108 QTest::newRow("anchorCentre") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorCenter << QRect(550, 550, 200, 200); 0109 0110 const PopupLayout layoutAnchorTopLeft{ 0111 .anchorRect = QRect(50, 50, 400, 400), 0112 .size = QSize(200, 200), 0113 .anchor = Test::XdgPositioner::anchor_top_left, 0114 .gravity = Test::XdgPositioner::gravity_bottom_right, 0115 }; 0116 QTest::newRow("anchorTopLeft") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorTopLeft << QRect(350, 350, 200, 200); 0117 0118 const PopupLayout layoutAnchorTop{ 0119 .anchorRect = QRect(50, 50, 400, 400), 0120 .size = QSize(200, 200), 0121 .anchor = Test::XdgPositioner::anchor_top, 0122 .gravity = Test::XdgPositioner::gravity_bottom_right, 0123 }; 0124 QTest::newRow("anchorTop") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorTop << QRect(550, 350, 200, 200); 0125 0126 const PopupLayout layoutAnchorTopRight{ 0127 .anchorRect = QRect(50, 50, 400, 400), 0128 .size = QSize(200, 200), 0129 .anchor = Test::XdgPositioner::anchor_top_right, 0130 .gravity = Test::XdgPositioner::gravity_bottom_right, 0131 }; 0132 QTest::newRow("anchorTopRight") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorTopRight << QRect(750, 350, 200, 200); 0133 0134 const PopupLayout layoutAnchorRight{ 0135 .anchorRect = QRect(50, 50, 400, 400), 0136 .size = QSize(200, 200), 0137 .anchor = Test::XdgPositioner::anchor_right, 0138 .gravity = Test::XdgPositioner::gravity_bottom_right, 0139 }; 0140 QTest::newRow("anchorRight") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorRight << QRect(750, 550, 200, 200); 0141 0142 const PopupLayout layoutAnchorBottomRight{ 0143 .anchorRect = QRect(50, 50, 400, 400), 0144 .size = QSize(200, 200), 0145 .anchor = Test::XdgPositioner::anchor_bottom_right, 0146 .gravity = Test::XdgPositioner::gravity_bottom_right, 0147 }; 0148 QTest::newRow("anchorBottomRight") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorBottomRight << QRect(750, 750, 200, 200); 0149 0150 const PopupLayout layoutAnchorBottom{ 0151 .anchorRect = QRect(50, 50, 400, 400), 0152 .size = QSize(200, 200), 0153 .anchor = Test::XdgPositioner::anchor_bottom, 0154 .gravity = Test::XdgPositioner::gravity_bottom_right, 0155 }; 0156 QTest::newRow("anchorBottom") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorBottom << QRect(550, 750, 200, 200); 0157 0158 const PopupLayout layoutAnchorBottomLeft{ 0159 .anchorRect = QRect(50, 50, 400, 400), 0160 .size = QSize(200, 200), 0161 .anchor = Test::XdgPositioner::anchor_bottom_left, 0162 .gravity = Test::XdgPositioner::gravity_bottom_right, 0163 }; 0164 QTest::newRow("anchorBottomLeft") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorBottomLeft << QRect(350, 750, 200, 200); 0165 0166 const PopupLayout layoutAnchorLeft{ 0167 .anchorRect = QRect(50, 50, 400, 400), 0168 .size = QSize(200, 200), 0169 .anchor = Test::XdgPositioner::anchor_left, 0170 .gravity = Test::XdgPositioner::gravity_bottom_right, 0171 }; 0172 QTest::newRow("anchorLeft") << QSize(500, 500) << QPoint(300, 300) << layoutAnchorLeft << QRect(350, 550, 200, 200); 0173 0174 // ---------------------------------------------------------------- 0175 // window in the middle, plenty of room either side: Changing gravity around the bottom right anchor 0176 0177 const PopupLayout layoutGravityCenter{ 0178 .anchorRect = QRect(50, 50, 400, 400), 0179 .size = QSize(200, 200), 0180 .anchor = Test::XdgPositioner::anchor_bottom_right, 0181 .gravity = Test::XdgPositioner::gravity_none, 0182 }; 0183 QTest::newRow("gravityCentre") << QSize(500, 500) << QPoint(300, 300) << layoutGravityCenter << QRect(650, 650, 200, 200); 0184 0185 const PopupLayout layoutGravityTopLeft{ 0186 .anchorRect = QRect(50, 50, 400, 400), 0187 .size = QSize(200, 200), 0188 .anchor = Test::XdgPositioner::anchor_bottom_right, 0189 .gravity = Test::XdgPositioner::gravity_top_left, 0190 }; 0191 QTest::newRow("gravityTopLeft") << QSize(500, 500) << QPoint(300, 300) << layoutGravityTopLeft << QRect(550, 550, 200, 200); 0192 0193 const PopupLayout layoutGravityTop{ 0194 .anchorRect = QRect(50, 50, 400, 400), 0195 .size = QSize(200, 200), 0196 .anchor = Test::XdgPositioner::anchor_bottom_right, 0197 .gravity = Test::XdgPositioner::gravity_top, 0198 }; 0199 QTest::newRow("gravityTop") << QSize(500, 500) << QPoint(300, 300) << layoutGravityTop << QRect(650, 550, 200, 200); 0200 0201 const PopupLayout layoutGravityTopRight{ 0202 .anchorRect = QRect(50, 50, 400, 400), 0203 .size = QSize(200, 200), 0204 .anchor = Test::XdgPositioner::anchor_bottom_right, 0205 .gravity = Test::XdgPositioner::gravity_top_right, 0206 }; 0207 QTest::newRow("gravityTopRight") << QSize(500, 500) << QPoint(300, 300) << layoutGravityTopRight << QRect(750, 550, 200, 200); 0208 0209 const PopupLayout layoutGravityRight{ 0210 .anchorRect = QRect(50, 50, 400, 400), 0211 .size = QSize(200, 200), 0212 .anchor = Test::XdgPositioner::anchor_bottom_right, 0213 .gravity = Test::XdgPositioner::gravity_right, 0214 }; 0215 QTest::newRow("gravityRight") << QSize(500, 500) << QPoint(300, 300) << layoutGravityRight << QRect(750, 650, 200, 200); 0216 0217 const PopupLayout layoutGravityBottomRight{ 0218 .anchorRect = QRect(50, 50, 400, 400), 0219 .size = QSize(200, 200), 0220 .anchor = Test::XdgPositioner::anchor_bottom_right, 0221 .gravity = Test::XdgPositioner::gravity_bottom_right, 0222 }; 0223 QTest::newRow("gravityBottomRight") << QSize(500, 500) << QPoint(300, 300) << layoutGravityBottomRight << QRect(750, 750, 200, 200); 0224 0225 const PopupLayout layoutGravityBottom{ 0226 .anchorRect = QRect(50, 50, 400, 400), 0227 .size = QSize(200, 200), 0228 .anchor = Test::XdgPositioner::anchor_bottom_right, 0229 .gravity = Test::XdgPositioner::gravity_bottom, 0230 }; 0231 QTest::newRow("gravityBottom") << QSize(500, 500) << QPoint(300, 300) << layoutGravityBottom << QRect(650, 750, 200, 200); 0232 0233 const PopupLayout layoutGravityBottomLeft{ 0234 .anchorRect = QRect(50, 50, 400, 400), 0235 .size = QSize(200, 200), 0236 .anchor = Test::XdgPositioner::anchor_bottom_right, 0237 .gravity = Test::XdgPositioner::gravity_bottom_left, 0238 }; 0239 QTest::newRow("gravityBottomLeft") << QSize(500, 500) << QPoint(300, 300) << layoutGravityBottomLeft << QRect(550, 750, 200, 200); 0240 0241 const PopupLayout layoutGravityLeft{ 0242 .anchorRect = QRect(50, 50, 400, 400), 0243 .size = QSize(200, 200), 0244 .anchor = Test::XdgPositioner::anchor_bottom_right, 0245 .gravity = Test::XdgPositioner::gravity_left, 0246 }; 0247 QTest::newRow("gravityLeft") << QSize(500, 500) << QPoint(300, 300) << layoutGravityLeft << QRect(550, 650, 200, 200); 0248 0249 // ---------------------------------------------------------------- 0250 // constrain and slide 0251 // popup is still 200,200. window moved near edge of screen, popup always comes out towards the screen edge 0252 0253 const PopupLayout layoutSlideTop{ 0254 .anchorRect = QRect(50, 50, 400, 400), 0255 .size = QSize(200, 200), 0256 .anchor = Test::XdgPositioner::anchor_top, 0257 .gravity = Test::XdgPositioner::gravity_top, 0258 .constraint = Test::XdgPositioner::constraint_adjustment_slide_x | Test::XdgPositioner::constraint_adjustment_slide_y, 0259 }; 0260 QTest::newRow("constraintSlideTop") << QSize(500, 500) << QPoint(80, 80) << layoutSlideTop << QRect(80 + 250 - 100, 0, 200, 200); 0261 0262 const PopupLayout layoutSlideLeft{ 0263 .anchorRect = QRect(50, 50, 400, 400), 0264 .size = QSize(200, 200), 0265 .anchor = Test::XdgPositioner::anchor_left, 0266 .gravity = Test::XdgPositioner::gravity_left, 0267 .constraint = Test::XdgPositioner::constraint_adjustment_slide_x | Test::XdgPositioner::constraint_adjustment_slide_y, 0268 }; 0269 QTest::newRow("constraintSlideLeft") << QSize(500, 500) << QPoint(80, 80) << layoutSlideLeft << QRect(0, 80 + 250 - 100, 200, 200); 0270 0271 const PopupLayout layoutSlideRight{ 0272 .anchorRect = QRect(50, 50, 400, 400), 0273 .size = QSize(200, 200), 0274 .anchor = Test::XdgPositioner::anchor_right, 0275 .gravity = Test::XdgPositioner::gravity_right, 0276 .constraint = Test::XdgPositioner::constraint_adjustment_slide_x | Test::XdgPositioner::constraint_adjustment_slide_y, 0277 }; 0278 QTest::newRow("constraintSlideRight") << QSize(500, 500) << QPoint(700, 80) << layoutSlideRight << QRect(1280 - 200, 80 + 250 - 100, 200, 200); 0279 0280 const PopupLayout layoutSlideBottom{ 0281 .anchorRect = QRect(50, 50, 400, 400), 0282 .size = QSize(200, 200), 0283 .anchor = Test::XdgPositioner::anchor_bottom, 0284 .gravity = Test::XdgPositioner::gravity_bottom, 0285 .constraint = Test::XdgPositioner::constraint_adjustment_slide_x | Test::XdgPositioner::constraint_adjustment_slide_y, 0286 }; 0287 QTest::newRow("constraintSlideBottom") << QSize(500, 500) << QPoint(80, 500) << layoutSlideBottom << QRect(80 + 250 - 100, 1024 - 200, 200, 200); 0288 0289 const PopupLayout layoutSlideBottomRight{ 0290 .anchorRect = QRect(50, 50, 400, 400), 0291 .size = QSize(200, 200), 0292 .anchor = Test::XdgPositioner::anchor_bottom_right, 0293 .gravity = Test::XdgPositioner::gravity_bottom_right, 0294 .constraint = Test::XdgPositioner::constraint_adjustment_slide_x | Test::XdgPositioner::constraint_adjustment_slide_y, 0295 }; 0296 QTest::newRow("constraintSlideBottomRight") << QSize(500, 500) << QPoint(700, 1000) << layoutSlideBottomRight << QRect(1280 - 200, 1024 - 200, 200, 200); 0297 0298 // ---------------------------------------------------------------- 0299 // constrain and flip 0300 0301 const PopupLayout layoutFlipTop{ 0302 .anchorRect = QRect(50, 50, 400, 400), 0303 .size = QSize(200, 200), 0304 .anchor = Test::XdgPositioner::anchor_top, 0305 .gravity = Test::XdgPositioner::gravity_top, 0306 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0307 }; 0308 QTest::newRow("constraintFlipTop") << QSize(500, 500) << QPoint(80, 80) << layoutFlipTop << QRect(230, 80 + 500 - 50, 200, 200); 0309 0310 const PopupLayout layoutFlipLeft{ 0311 .anchorRect = QRect(50, 50, 400, 400), 0312 .size = QSize(200, 200), 0313 .anchor = Test::XdgPositioner::anchor_left, 0314 .gravity = Test::XdgPositioner::gravity_left, 0315 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0316 }; 0317 QTest::newRow("constraintFlipLeft") << QSize(500, 500) << QPoint(80, 80) << layoutFlipLeft << QRect(80 + 500 - 50, 230, 200, 200); 0318 0319 const PopupLayout layoutFlipRight{ 0320 .anchorRect = QRect(50, 50, 400, 400), 0321 .size = QSize(200, 200), 0322 .anchor = Test::XdgPositioner::anchor_right, 0323 .gravity = Test::XdgPositioner::gravity_right, 0324 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0325 }; 0326 QTest::newRow("constraintFlipRight") << QSize(500, 500) << QPoint(700, 80) << layoutFlipRight << QRect(700 + 50 - 200, 230, 200, 200); 0327 0328 const PopupLayout layoutFlipBottom{ 0329 .anchorRect = QRect(50, 50, 400, 400), 0330 .size = QSize(200, 200), 0331 .anchor = Test::XdgPositioner::anchor_bottom, 0332 .gravity = Test::XdgPositioner::gravity_bottom, 0333 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0334 }; 0335 QTest::newRow("constraintFlipBottom") << QSize(500, 500) << QPoint(80, 500) << layoutFlipBottom << QRect(230, 500 + 50 - 200, 200, 200); 0336 0337 const PopupLayout layoutFlipBottomRight{ 0338 .anchorRect = QRect(50, 50, 400, 400), 0339 .size = QSize(200, 200), 0340 .anchor = Test::XdgPositioner::anchor_bottom_right, 0341 .gravity = Test::XdgPositioner::gravity_bottom_right, 0342 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0343 }; 0344 QTest::newRow("constraintFlipBottomRight") << QSize(500, 500) << QPoint(700, 500) << layoutFlipBottomRight << QRect(700 + 50 - 200, 500 + 50 - 200, 200, 200); 0345 0346 const PopupLayout layoutFlipRightNoAnchor{ 0347 .anchorRect = QRect(50, 50, 400, 400), 0348 // as popup is positioned in the middle of the parent we need a massive popup to be able to overflow 0349 .size = QSize(400, 400), 0350 .anchor = Test::XdgPositioner::anchor_top, 0351 .gravity = Test::XdgPositioner::gravity_right, 0352 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0353 }; 0354 QTest::newRow("constraintFlipRightNoAnchor") << QSize(500, 500) << QPoint(700, 80) << layoutFlipRightNoAnchor << QRect(700 + 250 - 400, 330, 400, 400); 0355 0356 const PopupLayout layoutFlipRightNoGravity{ 0357 .anchorRect = QRect(50, 50, 400, 400), 0358 .size = QSize(300, 200), 0359 .anchor = Test::XdgPositioner::anchor_right, 0360 .gravity = Test::XdgPositioner::gravity_top, 0361 .constraint = Test::XdgPositioner::constraint_adjustment_flip_x | Test::XdgPositioner::constraint_adjustment_flip_y, 0362 }; 0363 QTest::newRow("constraintFlipRightNoGravity") << QSize(500, 500) << QPoint(700, 80) << layoutFlipRightNoGravity << QRect(700 + 50 - 150, 130, 300, 200); 0364 0365 // ---------------------------------------------------------------- 0366 // resize 0367 0368 const PopupLayout layoutResizeTop{ 0369 .anchorRect = QRect(50, 50, 400, 400), 0370 .size = QSize(200, 200), 0371 .anchor = Test::XdgPositioner::anchor_top, 0372 .gravity = Test::XdgPositioner::gravity_top, 0373 .constraint = Test::XdgPositioner::constraint_adjustment_resize_x | Test::XdgPositioner::constraint_adjustment_resize_y, 0374 }; 0375 QTest::newRow("resizeTop") << QSize(500, 500) << QPoint(80, 80) << layoutResizeTop << QRect(80 + 250 - 100, 0, 200, 130); 0376 0377 const PopupLayout layoutResizeLeft{ 0378 .anchorRect = QRect(50, 50, 400, 400), 0379 .size = QSize(200, 200), 0380 .anchor = Test::XdgPositioner::anchor_left, 0381 .gravity = Test::XdgPositioner::gravity_left, 0382 .constraint = Test::XdgPositioner::constraint_adjustment_resize_x | Test::XdgPositioner::constraint_adjustment_resize_y, 0383 }; 0384 QTest::newRow("resizeLeft") << QSize(500, 500) << QPoint(80, 80) << layoutResizeLeft << QRect(0, 80 + 250 - 100, 130, 200); 0385 0386 const PopupLayout layoutResizeRight{ 0387 .anchorRect = QRect(50, 50, 400, 400), 0388 .size = QSize(200, 200), 0389 .anchor = Test::XdgPositioner::anchor_right, 0390 .gravity = Test::XdgPositioner::gravity_right, 0391 .constraint = Test::XdgPositioner::constraint_adjustment_resize_x | Test::XdgPositioner::constraint_adjustment_resize_y, 0392 }; 0393 QTest::newRow("resizeRight") << QSize(500, 500) << QPoint(700, 80) << layoutResizeRight << QRect(700 + 50 + 400, 80 + 250 - 100, 130, 200); 0394 0395 const PopupLayout layoutResizeBottom{ 0396 .anchorRect = QRect(50, 50, 400, 400), 0397 .size = QSize(200, 200), 0398 .anchor = Test::XdgPositioner::anchor_bottom, 0399 .gravity = Test::XdgPositioner::gravity_bottom, 0400 .constraint = Test::XdgPositioner::constraint_adjustment_resize_x | Test::XdgPositioner::constraint_adjustment_resize_y, 0401 }; 0402 QTest::newRow("resizeBottom") << QSize(500, 500) << QPoint(80, 500) << layoutResizeBottom << QRect(80 + 250 - 100, 500 + 50 + 400, 200, 74); 0403 } 0404 0405 void TransientPlacementTest::testXdgPopup() 0406 { 0407 // this test verifies that the position of a transient window is taken from the passed position 0408 // there are no further constraints like window too large to fit screen, cascading transients, etc 0409 // some test cases also verify that the transient fits on the screen 0410 QFETCH(QSize, parentSize); 0411 QFETCH(QPoint, parentPosition); 0412 QFETCH(QRect, expectedGeometry); 0413 const QRect expectedRelativeGeometry = expectedGeometry.translated(-parentPosition); 0414 0415 std::unique_ptr<KWayland::Client::Surface> surface = Test::createSurface(); 0416 QVERIFY(surface); 0417 auto parentShellSurface = Test::createXdgToplevelSurface(surface.get(), Test::waylandCompositor()); 0418 QVERIFY(parentShellSurface); 0419 auto parent = Test::renderAndWaitForShown(surface.get(), parentSize, Qt::blue); 0420 QVERIFY(parent); 0421 0422 QVERIFY(!parent->isDecorated()); 0423 parent->move(parentPosition); 0424 QCOMPARE(parent->frameGeometry(), QRect(parentPosition, parentSize)); 0425 0426 // create popup 0427 QFETCH(PopupLayout, layout); 0428 0429 std::unique_ptr<KWayland::Client::Surface> transientSurface = Test::createSurface(); 0430 QVERIFY(transientSurface); 0431 0432 std::unique_ptr<Test::XdgPositioner> positioner(Test::createXdgPositioner()); 0433 positioner->set_anchor_rect(layout.anchorRect.x(), layout.anchorRect.y(), layout.anchorRect.width(), layout.anchorRect.height()); 0434 positioner->set_size(layout.size.width(), layout.size.height()); 0435 positioner->set_anchor(layout.anchor); 0436 positioner->set_gravity(layout.gravity); 0437 positioner->set_constraint_adjustment(layout.constraint); 0438 std::unique_ptr<Test::XdgPopup> popup(Test::createXdgPopupSurface(transientSurface.get(), parentShellSurface->xdgSurface(), positioner.get(), Test::CreationSetup::CreateOnly)); 0439 QSignalSpy popupConfigureRequestedSpy(popup.get(), &Test::XdgPopup::configureRequested); 0440 QSignalSpy surfaceConfigureRequestedSpy(popup->xdgSurface(), &Test::XdgSurface::configureRequested); 0441 transientSurface->commit(KWayland::Client::Surface::CommitFlag::None); 0442 0443 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0444 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); 0445 QCOMPARE(popupConfigureRequestedSpy.last()[0].value<QRect>(), expectedRelativeGeometry); 0446 popup->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last()[0].toUInt()); 0447 0448 auto transient = Test::renderAndWaitForShown(transientSurface.get(), expectedRelativeGeometry.size(), Qt::red); 0449 QVERIFY(transient); 0450 0451 QVERIFY(!transient->isDecorated()); 0452 QVERIFY(transient->hasTransientPlacementHint()); 0453 QCOMPARE(transient->frameGeometry(), expectedGeometry); 0454 0455 QCOMPARE(surfaceConfigureRequestedSpy.count(), 1); // check that we did not get reconfigured 0456 } 0457 0458 void TransientPlacementTest::testXdgPopupWithPanel() 0459 { 0460 const Output *output = workspace()->activeOutput(); 0461 0462 std::unique_ptr<KWayland::Client::Surface> surface{Test::createSurface()}; 0463 QVERIFY(surface != nullptr); 0464 std::unique_ptr<Test::XdgToplevel> dockShellSurface{Test::createXdgToplevelSurface(surface.get())}; 0465 QVERIFY(dockShellSurface != nullptr); 0466 std::unique_ptr<KWayland::Client::PlasmaShellSurface> plasmaSurface(Test::waylandPlasmaShell()->createSurface(surface.get())); 0467 QVERIFY(plasmaSurface != nullptr); 0468 plasmaSurface->setRole(KWayland::Client::PlasmaShellSurface::Role::Panel); 0469 plasmaSurface->setPosition(QPoint(0, output->geometry().height() - 50)); 0470 plasmaSurface->setPanelBehavior(KWayland::Client::PlasmaShellSurface::PanelBehavior::AlwaysVisible); 0471 0472 // now render and map the window 0473 auto dock = Test::renderAndWaitForShown(surface.get(), QSize(1280, 50), Qt::blue); 0474 QVERIFY(dock); 0475 QCOMPARE(dock->windowType(), NET::Dock); 0476 QVERIFY(dock->isDock()); 0477 QCOMPARE(dock->frameGeometry(), QRect(0, output->geometry().height() - 50, 1280, 50)); 0478 QCOMPARE(dock->hasStrut(), true); 0479 QCOMPARE(workspace()->clientArea(PlacementArea, dock), QRect(0, 0, 1280, 1024 - 50)); 0480 QCOMPARE(workspace()->clientArea(FullScreenArea, dock), QRect(0, 0, 1280, 1024)); 0481 0482 // create parent 0483 std::unique_ptr<KWayland::Client::Surface> parentSurface(Test::createSurface()); 0484 QVERIFY(parentSurface); 0485 auto parentShellSurface = Test::createXdgToplevelSurface(parentSurface.get()); 0486 QVERIFY(parentShellSurface); 0487 auto parent = Test::renderAndWaitForShown(parentSurface.get(), {800, 600}, Qt::blue); 0488 QVERIFY(parent); 0489 0490 QVERIFY(!parent->isDecorated()); 0491 parent->move(QPointF(0, output->geometry().height() - 600)); 0492 parent->keepInArea(workspace()->clientArea(PlacementArea, parent)); 0493 QCOMPARE(parent->frameGeometry(), QRect(0, output->geometry().height() - 600 - 50, 800, 600)); 0494 0495 std::unique_ptr<KWayland::Client::Surface> transientSurface(Test::createSurface()); 0496 QVERIFY(transientSurface); 0497 0498 std::unique_ptr<Test::XdgPositioner> positioner(Test::createXdgPositioner()); 0499 positioner->set_size(200, 200); 0500 positioner->set_anchor_rect(50, 500, 200, 200); 0501 0502 std::unique_ptr<Test::XdgPopup> transientShellSurface(Test::createXdgPopupSurface(transientSurface.get(), parentShellSurface->xdgSurface(), positioner.get())); 0503 auto transient = Test::renderAndWaitForShown(transientSurface.get(), QSize(200, 200), Qt::red); 0504 QVERIFY(transient); 0505 0506 QVERIFY(!transient->isDecorated()); 0507 QVERIFY(transient->hasTransientPlacementHint()); 0508 0509 QCOMPARE(transient->frameGeometry(), QRect(50, output->geometry().height() - 200 - 50, 200, 200)); 0510 0511 transientShellSurface.reset(); 0512 transientSurface.reset(); 0513 QVERIFY(Test::waitForWindowDestroyed(transient)); 0514 0515 // now parent to fullscreen - on fullscreen the panel is ignored 0516 QSignalSpy toplevelConfigureRequestedSpy(parentShellSurface, &Test::XdgToplevel::configureRequested); 0517 QSignalSpy surfaceConfigureRequestedSpy(parentShellSurface->xdgSurface(), &Test::XdgSurface::configureRequested); 0518 parent->setFullScreen(true); 0519 QVERIFY(surfaceConfigureRequestedSpy.wait()); 0520 parentShellSurface->xdgSurface()->ack_configure(surfaceConfigureRequestedSpy.last().at(0).value<quint32>()); 0521 QSignalSpy frameGeometryChangedSpy{parent, &Window::frameGeometryChanged}; 0522 Test::render(parentSurface.get(), toplevelConfigureRequestedSpy.last().at(0).toSize(), Qt::red); 0523 QVERIFY(frameGeometryChangedSpy.wait()); 0524 QCOMPARE(parent->frameGeometry(), output->geometry()); 0525 QVERIFY(parent->isFullScreen()); 0526 0527 // another transient, with same hints as before from bottom of window 0528 transientSurface = Test::createSurface(); 0529 QVERIFY(transientSurface); 0530 0531 const QRect anchorRect2(50, output->geometry().height() - 100, 200, 200); 0532 std::unique_ptr<Test::XdgPositioner> positioner2(Test::createXdgPositioner()); 0533 positioner2->set_size(200, 200); 0534 positioner2->set_anchor_rect(anchorRect2.x(), anchorRect2.y(), anchorRect2.width(), anchorRect2.height()); 0535 transientShellSurface.reset(Test::createXdgPopupSurface(transientSurface.get(), parentShellSurface->xdgSurface(), positioner2.get())); 0536 transient = Test::renderAndWaitForShown(transientSurface.get(), QSize(200, 200), Qt::red); 0537 QVERIFY(transient); 0538 0539 QVERIFY(!transient->isDecorated()); 0540 QVERIFY(transient->hasTransientPlacementHint()); 0541 0542 QCOMPARE(transient->frameGeometry(), QRect(50, output->geometry().height() - 200, 200, 200)); 0543 } 0544 0545 } 0546 0547 WAYLANDTEST_MAIN(KWin::TransientPlacementTest) 0548 #include "transient_placement.moc"