File indexing completed on 2024-05-12 05:30:42

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"