File indexing completed on 2024-05-19 09:23:03

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_server.h"
0014 #include "workspace.h"
0015 #include "x11window.h"
0016 
0017 #include <KDecoration2/Decoration>
0018 
0019 #include <linux/input.h>
0020 
0021 namespace KWin
0022 {
0023 
0024 static const QString s_socketName = QStringLiteral("wayland_test_kwin_dont_crash_empty_decoration-0");
0025 
0026 class DontCrashEmptyDecorationTest : public QObject
0027 {
0028     Q_OBJECT
0029 private Q_SLOTS:
0030     void initTestCase();
0031     void init();
0032     void testBug361551();
0033 };
0034 
0035 void DontCrashEmptyDecorationTest::initTestCase()
0036 {
0037     if (!Test::renderNodeAvailable()) {
0038         QSKIP("no render node available");
0039         return;
0040     }
0041     qRegisterMetaType<KWin::Window *>();
0042     QSignalSpy applicationStartedSpy(kwinApp(), &Application::started);
0043     QVERIFY(waylandServer()->init(s_socketName));
0044     Test::setOutputConfig({
0045         QRect(0, 0, 1280, 1024),
0046         QRect(1280, 0, 1280, 1024),
0047     });
0048 
0049     // this test needs to enforce OpenGL compositing to get into the crashy condition
0050     qputenv("KWIN_COMPOSE", QByteArrayLiteral("O2"));
0051     kwinApp()->start();
0052     QVERIFY(applicationStartedSpy.wait());
0053     const auto outputs = workspace()->outputs();
0054     QCOMPARE(outputs.count(), 2);
0055     QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024));
0056     QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024));
0057     setenv("QT_QPA_PLATFORM", "wayland", true);
0058 }
0059 
0060 void DontCrashEmptyDecorationTest::init()
0061 {
0062     workspace()->setActiveOutput(QPoint(640, 512));
0063     input()->pointer()->warp(QPoint(640, 512));
0064 }
0065 
0066 void DontCrashEmptyDecorationTest::testBug361551()
0067 {
0068     // this test verifies that resizing an X11 window to an invalid size does not result in crash on unmap
0069     // when the DecorationRenderer gets copied to the Deleted
0070     // there a repaint is scheduled and the resulting texture is invalid if the window size is invalid
0071 
0072     // create an xcb window
0073     Test::XcbConnectionPtr connection = Test::createX11Connection();
0074     auto c = connection.get();
0075 
0076     QVERIFY(c);
0077     QVERIFY(!xcb_connection_has_error(c));
0078 
0079     xcb_window_t windowId = xcb_generate_id(c);
0080     xcb_create_window(c, XCB_COPY_FROM_PARENT, windowId, rootWindow(), 0, 0, 10, 10, 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr);
0081     xcb_map_window(c, windowId);
0082     xcb_flush(c);
0083 
0084     // we should get a window for it
0085     QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded);
0086     QVERIFY(windowCreatedSpy.wait());
0087     X11Window *window = windowCreatedSpy.first().first().value<X11Window *>();
0088     QVERIFY(window);
0089     QCOMPARE(window->window(), windowId);
0090     QVERIFY(window->isDecorated());
0091 
0092     // let's set a stupid geometry
0093     window->moveResize({0, 0, 0, 0});
0094     QCOMPARE(window->frameGeometry(), QRect(0, 0, 0, 0));
0095 
0096     // and destroy the window again
0097     xcb_unmap_window(c, windowId);
0098     xcb_destroy_window(c, windowId);
0099     xcb_flush(c);
0100 
0101     QSignalSpy windowClosedSpy(window, &X11Window::closed);
0102     QVERIFY(windowClosedSpy.wait());
0103 }
0104 
0105 }
0106 
0107 WAYLANDTEST_MAIN(KWin::DontCrashEmptyDecorationTest)
0108 #include "dont_crash_empty_deco.moc"