File indexing completed on 2024-11-10 04:56:07
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 "screenedge.h" 0014 #include "virtualdesktops.h" 0015 #include "wayland_server.h" 0016 #include "workspace.h" 0017 #include "x11window.h" 0018 0019 #include <KWayland/Client/compositor.h> 0020 #include <KWayland/Client/surface.h> 0021 0022 #include <KDecoration2/Decoration> 0023 0024 #include <netwm.h> 0025 #include <xcb/xcb_icccm.h> 0026 0027 Q_DECLARE_METATYPE(KWin::StrutRects) 0028 0029 namespace KWin 0030 { 0031 0032 static const QString s_socketName = QStringLiteral("wayland_test_kwin_struts-0"); 0033 0034 class StrutsTest : public QObject 0035 { 0036 Q_OBJECT 0037 private Q_SLOTS: 0038 void initTestCase(); 0039 void init(); 0040 void cleanup(); 0041 void testX11Struts_data(); 0042 void testX11Struts(); 0043 void test363804(); 0044 void testLeftScreenSmallerBottomAligned(); 0045 void testWindowMoveWithPanelBetweenScreens(); 0046 0047 private: 0048 KWayland::Client::Compositor *m_compositor = nullptr; 0049 }; 0050 0051 void StrutsTest::initTestCase() 0052 { 0053 qRegisterMetaType<KWin::Window *>(); 0054 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0055 QVERIFY(waylandServer()->init(s_socketName)); 0056 Test::setOutputConfig({ 0057 QRect(0, 0, 1280, 1024), 0058 QRect(1280, 0, 1280, 1024), 0059 }); 0060 0061 // set custom config which disables the Outline 0062 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); 0063 KConfigGroup group = config->group(QStringLiteral("Outline")); 0064 group.writeEntry(QStringLiteral("QmlPath"), QString("/does/not/exist.qml")); 0065 group.sync(); 0066 0067 kwinApp()->setConfig(config); 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 StrutsTest::init() 0079 { 0080 QVERIFY(Test::setupWaylandConnection()); 0081 m_compositor = Test::waylandCompositor(); 0082 0083 workspace()->setActiveOutput(QPoint(640, 512)); 0084 input()->pointer()->warp(QPoint(640, 512)); 0085 QVERIFY(waylandServer()->windows().isEmpty()); 0086 } 0087 0088 void StrutsTest::cleanup() 0089 { 0090 Test::destroyWaylandConnection(); 0091 } 0092 0093 void StrutsTest::testX11Struts_data() 0094 { 0095 QTest::addColumn<QRect>("windowGeometry"); 0096 QTest::addColumn<int>("leftStrut"); 0097 QTest::addColumn<int>("rightStrut"); 0098 QTest::addColumn<int>("topStrut"); 0099 QTest::addColumn<int>("bottomStrut"); 0100 QTest::addColumn<int>("leftStrutStart"); 0101 QTest::addColumn<int>("leftStrutEnd"); 0102 QTest::addColumn<int>("rightStrutStart"); 0103 QTest::addColumn<int>("rightStrutEnd"); 0104 QTest::addColumn<int>("topStrutStart"); 0105 QTest::addColumn<int>("topStrutEnd"); 0106 QTest::addColumn<int>("bottomStrutStart"); 0107 QTest::addColumn<int>("bottomStrutEnd"); 0108 QTest::addColumn<QRectF>("screen0Maximized"); 0109 QTest::addColumn<QRectF>("screen1Maximized"); 0110 QTest::addColumn<QRectF>("workArea"); 0111 QTest::addColumn<StrutRects>("restrictedMoveArea"); 0112 0113 QTest::newRow("bottom panel/no strut") << QRect(0, 980, 1280, 44) 0114 << 0 << 0 << 0 << 0 0115 << 0 << 0 0116 << 0 << 0 0117 << 0 << 0 0118 << 0 << 0 0119 << QRectF(0, 0, 1280, 1024) 0120 << QRectF(1280, 0, 1280, 1024) 0121 << QRectF(0, 0, 2560, 1024) 0122 << StrutRects(); 0123 QTest::newRow("bottom panel/strut") << QRect(0, 980, 1280, 44) 0124 << 0 << 0 << 0 << 44 0125 << 0 << 0 0126 << 0 << 0 0127 << 0 << 0 0128 << 0 << 1279 0129 << QRectF(0, 0, 1280, 980) 0130 << QRectF(1280, 0, 1280, 1024) 0131 << QRectF(0, 0, 2560, 980) 0132 << StrutRects{StrutRect(0, 980, 1279, 44)}; 0133 QTest::newRow("top panel/no strut") << QRect(0, 0, 1280, 44) 0134 << 0 << 0 << 0 << 0 0135 << 0 << 0 0136 << 0 << 0 0137 << 0 << 0 0138 << 0 << 0 0139 << QRectF(0, 0, 1280, 1024) 0140 << QRectF(1280, 0, 1280, 1024) 0141 << QRectF(0, 0, 2560, 1024) 0142 << StrutRects(); 0143 QTest::newRow("top panel/strut") << QRect(0, 0, 1280, 44) 0144 << 0 << 0 << 44 << 0 0145 << 0 << 0 0146 << 0 << 0 0147 << 0 << 1279 0148 << 0 << 0 0149 << QRectF(0, 44, 1280, 980) 0150 << QRectF(1280, 0, 1280, 1024) 0151 << QRectF(0, 44, 2560, 980) 0152 << StrutRects{StrutRect(0, 0, 1279, 44)}; 0153 QTest::newRow("left panel/no strut") << QRect(0, 0, 60, 1024) 0154 << 0 << 0 << 0 << 0 0155 << 0 << 0 0156 << 0 << 0 0157 << 0 << 0 0158 << 0 << 0 0159 << QRectF(0, 0, 1280, 1024) 0160 << QRectF(1280, 0, 1280, 1024) 0161 << QRectF(0, 0, 2560, 1024) 0162 << StrutRects(); 0163 QTest::newRow("left panel/strut") << QRect(0, 0, 60, 1024) 0164 << 60 << 0 << 0 << 0 0165 << 0 << 1023 0166 << 0 << 0 0167 << 0 << 0 0168 << 0 << 0 0169 << QRectF(60, 0, 1220, 1024) 0170 << QRectF(1280, 0, 1280, 1024) 0171 << QRectF(60, 0, 2500, 1024) 0172 << StrutRects{StrutRect(0, 0, 60, 1023)}; 0173 QTest::newRow("right panel/no strut") << QRect(1220, 0, 60, 1024) 0174 << 0 << 0 << 0 << 0 0175 << 0 << 0 0176 << 0 << 0 0177 << 0 << 0 0178 << 0 << 0 0179 << QRectF(0, 0, 1280, 1024) 0180 << QRectF(1280, 0, 1280, 1024) 0181 << QRectF(0, 0, 2560, 1024) 0182 << StrutRects(); 0183 QTest::newRow("right panel/strut") << QRect(1220, 0, 60, 1024) 0184 << 0 << 1340 << 0 << 0 0185 << 0 << 0 0186 << 0 << 1023 0187 << 0 << 0 0188 << 0 << 0 0189 << QRectF(0, 0, 1220, 1024) 0190 << QRectF(1280, 0, 1280, 1024) 0191 << QRectF(0, 0, 2560, 1024) 0192 << StrutRects{StrutRect(1220, 0, 60, 1023)}; 0193 // second screen 0194 QTest::newRow("bottom panel 1/no strut") << QRect(1280, 980, 1280, 44) 0195 << 0 << 0 << 0 << 0 0196 << 0 << 0 0197 << 0 << 0 0198 << 0 << 0 0199 << 0 << 0 0200 << QRectF(0, 0, 1280, 1024) 0201 << QRectF(1280, 0, 1280, 1024) 0202 << QRectF(0, 0, 2560, 1024) 0203 << StrutRects(); 0204 QTest::newRow("bottom panel 1/strut") << QRect(1280, 980, 1280, 44) 0205 << 0 << 0 << 0 << 44 0206 << 0 << 0 0207 << 0 << 0 0208 << 0 << 0 0209 << 1280 << 2559 0210 << QRectF(0, 0, 1280, 1024) 0211 << QRectF(1280, 0, 1280, 980) 0212 << QRectF(0, 0, 2560, 980) 0213 << StrutRects{StrutRect(1280, 980, 1279, 44)}; 0214 QTest::newRow("top panel 1/no strut") << QRect(1280, 0, 1280, 44) 0215 << 0 << 0 << 0 << 0 0216 << 0 << 0 0217 << 0 << 0 0218 << 0 << 0 0219 << 0 << 0 0220 << QRectF(0, 0, 1280, 1024) 0221 << QRectF(1280, 0, 1280, 1024) 0222 << QRectF(0, 0, 2560, 1024) 0223 << StrutRects(); 0224 QTest::newRow("top panel 1 /strut") << QRect(1280, 0, 1280, 44) 0225 << 0 << 0 << 44 << 0 0226 << 0 << 0 0227 << 0 << 0 0228 << 1280 << 2559 0229 << 0 << 0 0230 << QRectF(0, 0, 1280, 1024) 0231 << QRectF(1280, 44, 1280, 980) 0232 << QRectF(0, 44, 2560, 980) 0233 << StrutRects{StrutRect(1280, 0, 1279, 44)}; 0234 QTest::newRow("left panel 1/no strut") << QRect(1280, 0, 60, 1024) 0235 << 0 << 0 << 0 << 0 0236 << 0 << 0 0237 << 0 << 0 0238 << 0 << 0 0239 << 0 << 0 0240 << QRectF(0, 0, 1280, 1024) 0241 << QRectF(1280, 0, 1280, 1024) 0242 << QRectF(0, 0, 2560, 1024) 0243 << StrutRects(); 0244 QTest::newRow("left panel 1/strut") << QRect(1280, 0, 60, 1024) 0245 << 1340 << 0 << 0 << 0 0246 << 0 << 1023 0247 << 0 << 0 0248 << 0 << 0 0249 << 0 << 0 0250 << QRectF(0, 0, 1280, 1024) 0251 << QRectF(1340, 0, 1220, 1024) 0252 << QRectF(0, 0, 2560, 1024) 0253 << StrutRects{StrutRect(1280, 0, 60, 1023)}; 0254 // invalid struts 0255 QTest::newRow("bottom panel/ invalid strut") << QRect(0, 980, 1280, 44) 0256 << 1280 << 0 << 0 << 44 0257 << 980 << 1024 0258 << 0 << 0 0259 << 0 << 0 0260 << 0 << 1279 0261 << QRectF(0, 0, 1280, 1024) 0262 << QRectF(1280, 0, 1280, 1024) 0263 << QRectF(0, 0, 2560, 1024) 0264 << StrutRects{StrutRect(0, 980, 1279, 44), StrutRect(0, 980, 1280, 44)}; 0265 QTest::newRow("top panel/ invalid strut") << QRect(0, 0, 1280, 44) 0266 << 1280 << 0 << 44 << 0 0267 << 0 << 44 0268 << 0 << 0 0269 << 0 << 1279 0270 << 0 << 0 0271 << QRectF(0, 0, 1280, 1024) 0272 << QRectF(1280, 0, 1280, 1024) 0273 << QRectF(0, 0, 2560, 1024) 0274 << StrutRects{StrutRect(0, 0, 1279, 44), StrutRect(0, 0, 1280, 44)}; 0275 QTest::newRow("top panel/invalid strut 2") << QRect(0, 0, 1280, 44) 0276 << 0 << 0 << 1024 << 0 0277 << 0 << 0 0278 << 0 << 0 0279 << 0 << 1279 0280 << 0 << 0 0281 << QRectF(0, 0, 1280, 1024) 0282 << QRectF(1280, 0, 1280, 1024) 0283 << QRectF(0, 0, 2560, 1024) 0284 << StrutRects(); 0285 } 0286 0287 void StrutsTest::testX11Struts() 0288 { 0289 // this test verifies that struts are applied correctly for X11 windows 0290 0291 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0292 const QList<Output *> outputs = workspace()->outputs(); 0293 0294 // no, struts yet 0295 // first screen 0296 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0297 QCOMPARE(workspace()->clientArea(MovementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0298 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0299 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0300 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0301 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0302 // second screen 0303 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0304 QCOMPARE(workspace()->clientArea(MovementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0305 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0306 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0307 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0308 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0309 // combined 0310 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 2560, 1024)); 0311 QCOMPARE(workspace()->clientArea(FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024)); 0312 QCOMPARE(workspace()->restrictedMoveArea(desktop), StrutRects()); 0313 0314 // create an xcb window 0315 Test::XcbConnectionPtr c = Test::createX11Connection(); 0316 QVERIFY(!xcb_connection_has_error(c.get())); 0317 0318 xcb_window_t windowId = xcb_generate_id(c.get()); 0319 QFETCH(QRect, windowGeometry); 0320 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0321 windowGeometry.x(), 0322 windowGeometry.y(), 0323 windowGeometry.width(), 0324 windowGeometry.height(), 0325 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0326 xcb_size_hints_t hints; 0327 memset(&hints, 0, sizeof(hints)); 0328 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0329 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0330 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0331 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties); 0332 info.setWindowType(NET::Dock); 0333 // set the extended strut 0334 QFETCH(int, leftStrut); 0335 QFETCH(int, rightStrut); 0336 QFETCH(int, topStrut); 0337 QFETCH(int, bottomStrut); 0338 QFETCH(int, leftStrutStart); 0339 QFETCH(int, leftStrutEnd); 0340 QFETCH(int, rightStrutStart); 0341 QFETCH(int, rightStrutEnd); 0342 QFETCH(int, topStrutStart); 0343 QFETCH(int, topStrutEnd); 0344 QFETCH(int, bottomStrutStart); 0345 QFETCH(int, bottomStrutEnd); 0346 NETExtendedStrut strut; 0347 strut.left_start = leftStrutStart; 0348 strut.left_end = leftStrutEnd; 0349 strut.left_width = leftStrut; 0350 strut.right_start = rightStrutStart; 0351 strut.right_end = rightStrutEnd; 0352 strut.right_width = rightStrut; 0353 strut.top_start = topStrutStart; 0354 strut.top_end = topStrutEnd; 0355 strut.top_width = topStrut; 0356 strut.bottom_start = bottomStrutStart; 0357 strut.bottom_end = bottomStrutEnd; 0358 strut.bottom_width = bottomStrut; 0359 info.setExtendedStrut(strut); 0360 xcb_map_window(c.get(), windowId); 0361 xcb_flush(c.get()); 0362 0363 // we should get a window for it 0364 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0365 QVERIFY(windowCreatedSpy.wait()); 0366 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0367 QVERIFY(window); 0368 QCOMPARE(window->window(), windowId); 0369 QVERIFY(!window->isDecorated()); 0370 QCOMPARE(window->windowType(), NET::Dock); 0371 QCOMPARE(window->frameGeometry(), windowGeometry); 0372 0373 // this should have affected the client area 0374 // some props are independent of struts - those first 0375 // screen 0 0376 QCOMPARE(workspace()->clientArea(MovementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0377 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0378 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0379 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0380 // screen 1 0381 QCOMPARE(workspace()->clientArea(MovementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0382 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0383 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0384 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0385 // combined 0386 QCOMPARE(workspace()->clientArea(FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024)); 0387 0388 // now verify the actual updated client areas 0389 QTEST(workspace()->clientArea(PlacementArea, outputs[0], desktop), "screen0Maximized"); 0390 QTEST(workspace()->clientArea(MaximizeArea, outputs[0], desktop), "screen0Maximized"); 0391 QTEST(workspace()->clientArea(PlacementArea, outputs[1], desktop), "screen1Maximized"); 0392 QTEST(workspace()->clientArea(MaximizeArea, outputs[1], desktop), "screen1Maximized"); 0393 QTEST(workspace()->clientArea(WorkArea, outputs[0], desktop), "workArea"); 0394 QTEST(workspace()->restrictedMoveArea(desktop), "restrictedMoveArea"); 0395 0396 // and destroy the window again 0397 xcb_unmap_window(c.get(), windowId); 0398 xcb_destroy_window(c.get(), windowId); 0399 xcb_flush(c.get()); 0400 c.reset(); 0401 0402 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0403 QVERIFY(windowClosedSpy.wait()); 0404 0405 // now struts should be removed again 0406 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0407 QCOMPARE(workspace()->clientArea(MovementArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0408 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0409 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0410 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0411 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[0], desktop), QRect(0, 0, 1280, 1024)); 0412 // second screen 0413 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0414 QCOMPARE(workspace()->clientArea(MovementArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0415 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0416 QCOMPARE(workspace()->clientArea(MaximizeFullArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0417 QCOMPARE(workspace()->clientArea(FullScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0418 QCOMPARE(workspace()->clientArea(ScreenArea, outputs[1], desktop), QRect(1280, 0, 1280, 1024)); 0419 // combined 0420 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 2560, 1024)); 0421 QCOMPARE(workspace()->clientArea(FullArea, outputs[0], desktop), QRect(0, 0, 2560, 1024)); 0422 QCOMPARE(workspace()->restrictedMoveArea(desktop), StrutRects()); 0423 } 0424 0425 void StrutsTest::test363804() 0426 { 0427 // this test verifies the condition described in BUG 363804 0428 // two screens in a vertical setup, aligned to right border with panel on the bottom screen 0429 const QList<QRect> geometries{QRect(0, 0, 1920, 1080), QRect(554, 1080, 1366, 768)}; 0430 Test::setOutputConfig(geometries); 0431 QCOMPARE(workspace()->geometry(), QRect(0, 0, 1920, 1848)); 0432 0433 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0434 const QList<Output *> outputs = workspace()->outputs(); 0435 QCOMPARE(outputs.count(), 2); 0436 QCOMPARE(outputs[0]->geometry(), geometries[0]); 0437 QCOMPARE(outputs[1]->geometry(), geometries[1]); 0438 0439 // create an xcb window 0440 Test::XcbConnectionPtr c = Test::createX11Connection(); 0441 QVERIFY(!xcb_connection_has_error(c.get())); 0442 0443 xcb_window_t windowId = xcb_generate_id(c.get()); 0444 const QRect windowGeometry(554, 1812, 1366, 36); 0445 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0446 windowGeometry.x(), 0447 windowGeometry.y(), 0448 windowGeometry.width(), 0449 windowGeometry.height(), 0450 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0451 xcb_size_hints_t hints; 0452 memset(&hints, 0, sizeof(hints)); 0453 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0454 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0455 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0456 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties); 0457 info.setWindowType(NET::Dock); 0458 NETExtendedStrut strut; 0459 strut.left_start = 0; 0460 strut.left_end = 0; 0461 strut.left_width = 0; 0462 strut.right_start = 0; 0463 strut.right_end = 0; 0464 strut.right_width = 0; 0465 strut.top_start = 0; 0466 strut.top_end = 0; 0467 strut.top_width = 0; 0468 strut.bottom_start = 554; 0469 strut.bottom_end = 1919; 0470 strut.bottom_width = 36; 0471 info.setExtendedStrut(strut); 0472 xcb_map_window(c.get(), windowId); 0473 xcb_flush(c.get()); 0474 0475 // we should get a window for it 0476 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0477 QVERIFY(windowCreatedSpy.wait()); 0478 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0479 QVERIFY(window); 0480 QCOMPARE(window->window(), windowId); 0481 QVERIFY(!window->isDecorated()); 0482 QCOMPARE(window->windowType(), NET::Dock); 0483 QCOMPARE(window->frameGeometry(), windowGeometry); 0484 0485 // now verify the actual updated client areas 0486 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), geometries.at(0)); 0487 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), geometries.at(0)); 0488 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(554, 1080, 1366, 732)); 0489 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(554, 1080, 1366, 732)); 0490 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 1920, 1812)); 0491 0492 // and destroy the window again 0493 xcb_unmap_window(c.get(), windowId); 0494 xcb_destroy_window(c.get(), windowId); 0495 xcb_flush(c.get()); 0496 c.reset(); 0497 0498 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0499 QVERIFY(windowClosedSpy.wait()); 0500 } 0501 0502 void StrutsTest::testLeftScreenSmallerBottomAligned() 0503 { 0504 // this test verifies a two screen setup with the left screen smaller than the right and bottom aligned 0505 // the panel is on the top of the left screen, thus not at 0/0 0506 const QList<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)}; 0507 Test::setOutputConfig(geometries); 0508 QCOMPARE(workspace()->geometry(), QRect(0, 0, 3046, 1050)); 0509 0510 const QList<Output *> outputs = workspace()->outputs(); 0511 QCOMPARE(outputs[0]->geometry(), geometries.at(0)); 0512 QCOMPARE(outputs[1]->geometry(), geometries.at(1)); 0513 0514 // the test window will be on the current desktop 0515 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0516 0517 // create the panel 0518 Test::XcbConnectionPtr c = Test::createX11Connection(); 0519 QVERIFY(!xcb_connection_has_error(c.get())); 0520 0521 xcb_window_t windowId = xcb_generate_id(c.get()); 0522 const QRect windowGeometry(0, 282, 1366, 24); 0523 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0524 windowGeometry.x(), 0525 windowGeometry.y(), 0526 windowGeometry.width(), 0527 windowGeometry.height(), 0528 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0529 xcb_size_hints_t hints; 0530 memset(&hints, 0, sizeof(hints)); 0531 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0532 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0533 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0534 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties); 0535 info.setWindowType(NET::Dock); 0536 NETExtendedStrut strut; 0537 strut.left_start = 0; 0538 strut.left_end = 0; 0539 strut.left_width = 0; 0540 strut.right_start = 0; 0541 strut.right_end = 0; 0542 strut.right_width = 0; 0543 strut.top_start = 0; 0544 strut.top_end = 1365; 0545 strut.top_width = 306; 0546 strut.bottom_start = 0; 0547 strut.bottom_end = 0; 0548 strut.bottom_width = 0; 0549 info.setExtendedStrut(strut); 0550 xcb_map_window(c.get(), windowId); 0551 xcb_flush(c.get()); 0552 0553 // we should get a window for it 0554 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0555 QVERIFY(windowCreatedSpy.wait()); 0556 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0557 QVERIFY(window); 0558 QCOMPARE(window->window(), windowId); 0559 QVERIFY(!window->isDecorated()); 0560 QCOMPARE(window->windowType(), NET::Dock); 0561 QCOMPARE(window->frameGeometry(), windowGeometry); 0562 0563 // now verify the actual updated client areas 0564 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 306, 1366, 744)); 0565 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 306, 1366, 744)); 0566 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), geometries.at(1)); 0567 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), geometries.at(1)); 0568 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 3046, 1050)); 0569 0570 // and destroy the window again 0571 xcb_unmap_window(c.get(), windowId); 0572 xcb_destroy_window(c.get(), windowId); 0573 xcb_flush(c.get()); 0574 c.reset(); 0575 0576 QSignalSpy windowClosedSpy(window, &X11Window::closed); 0577 QVERIFY(windowClosedSpy.wait()); 0578 } 0579 0580 void StrutsTest::testWindowMoveWithPanelBetweenScreens() 0581 { 0582 // this test verifies the condition of BUG 0583 // when moving a window with decorations in a restricted way it should pass from one screen 0584 // to the other even if there is a panel in between. 0585 0586 // left screen must be smaller than right screen 0587 const QList<QRect> geometries{QRect(0, 282, 1366, 768), QRect(1366, 0, 1680, 1050)}; 0588 Test::setOutputConfig(geometries); 0589 QCOMPARE(workspace()->geometry(), QRect(0, 0, 3046, 1050)); 0590 0591 const QList<Output *> outputs = workspace()->outputs(); 0592 QCOMPARE(outputs[0]->geometry(), geometries.at(0)); 0593 QCOMPARE(outputs[1]->geometry(), geometries.at(1)); 0594 0595 // all windows will be placed on the current desktop 0596 VirtualDesktop *desktop = VirtualDesktopManager::self()->currentDesktop(); 0597 0598 // create the panel on the right screen, left edge 0599 Test::XcbConnectionPtr c = Test::createX11Connection(); 0600 QVERIFY(!xcb_connection_has_error(c.get())); 0601 0602 xcb_window_t windowId = xcb_generate_id(c.get()); 0603 const QRect windowGeometry(1366, 0, 24, 1050); 0604 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0605 windowGeometry.x(), 0606 windowGeometry.y(), 0607 windowGeometry.width(), 0608 windowGeometry.height(), 0609 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0610 xcb_size_hints_t hints; 0611 memset(&hints, 0, sizeof(hints)); 0612 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0613 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0614 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0615 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties); 0616 info.setWindowType(NET::Dock); 0617 NETExtendedStrut strut; 0618 strut.left_start = 0; 0619 strut.left_end = 1050; 0620 strut.left_width = 1366 + 24; 0621 strut.right_start = 0; 0622 strut.right_end = 0; 0623 strut.right_width = 0; 0624 strut.top_start = 0; 0625 strut.top_end = 0; 0626 strut.top_width = 0; 0627 strut.bottom_start = 0; 0628 strut.bottom_end = 0; 0629 strut.bottom_width = 0; 0630 info.setExtendedStrut(strut); 0631 xcb_map_window(c.get(), windowId); 0632 xcb_flush(c.get()); 0633 0634 // we should get a window for it 0635 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0636 QVERIFY(windowCreatedSpy.wait()); 0637 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0638 QVERIFY(window); 0639 QCOMPARE(window->window(), windowId); 0640 QVERIFY(!window->isDecorated()); 0641 QCOMPARE(window->windowType(), NET::Dock); 0642 QCOMPARE(window->frameGeometry(), windowGeometry); 0643 0644 // now verify the actual updated client areas 0645 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[0], desktop), QRect(0, 282, 1366, 768)); 0646 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[0], desktop), QRect(0, 282, 1366, 768)); 0647 QCOMPARE(workspace()->clientArea(PlacementArea, outputs[1], desktop), QRect(1390, 0, 1656, 1050)); 0648 QCOMPARE(workspace()->clientArea(MaximizeArea, outputs[1], desktop), QRect(1390, 0, 1656, 1050)); 0649 QCOMPARE(workspace()->clientArea(WorkArea, outputs[0], desktop), QRect(0, 0, 3046, 1050)); 0650 QCOMPARE(workspace()->restrictedMoveArea(desktop), StrutRects{StrutRect(1366, 0, 24, 1050)}); 0651 0652 // create another window and try to move it 0653 0654 xcb_window_t w2 = xcb_generate_id(c.get()); 0655 const QRect windowGeometry2(1500, 400, 200, 300); 0656 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, w2, rootWindow(), 0657 windowGeometry2.x(), 0658 windowGeometry2.y(), 0659 windowGeometry2.width(), 0660 windowGeometry2.height(), 0661 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0662 xcb_size_hints_t hints2; 0663 memset(&hints2, 0, sizeof(hints2)); 0664 xcb_icccm_size_hints_set_position(&hints2, 1, windowGeometry2.x(), windowGeometry2.y()); 0665 xcb_icccm_size_hints_set_min_size(&hints2, 200, 300); 0666 xcb_icccm_set_wm_normal_hints(c.get(), w2, &hints2); 0667 xcb_map_window(c.get(), w2); 0668 xcb_flush(c.get()); 0669 QVERIFY(windowCreatedSpy.wait()); 0670 X11Window *window2 = windowCreatedSpy.last().first().value<X11Window *>(); 0671 QVERIFY(window2); 0672 QVERIFY(window2 != window); 0673 QVERIFY(window2->isDecorated()); 0674 QCOMPARE(window2->clientSize(), QSize(200, 300)); 0675 QCOMPARE(window2->pos(), QPoint(1500, 400)); 0676 0677 const QRectF origGeo = window2->frameGeometry(); 0678 input()->pointer()->warp(origGeo.center()); 0679 workspace()->performWindowOperation(window2, Options::MoveOp); 0680 QTRY_COMPARE(workspace()->moveResizeWindow(), window2); 0681 QVERIFY(window2->isInteractiveMove()); 0682 // move to next screen - step is 8 pixel, so 800 pixel 0683 for (int i = 0; i < 100; i++) { 0684 window2->keyPressEvent(Qt::Key_Left); 0685 } 0686 window2->keyPressEvent(Qt::Key_Enter); 0687 QCOMPARE(window2->isInteractiveMove(), false); 0688 QVERIFY(workspace()->moveResizeWindow() == nullptr); 0689 QCOMPARE(window2->frameGeometry(), QRectF(origGeo.translated(-800, 0))); 0690 } 0691 0692 } 0693 0694 WAYLANDTEST_MAIN(KWin::StrutsTest) 0695 #include "struts_test.moc"