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