File indexing completed on 2024-11-10 04:56:12
0001 /* 0002 SPDX-FileCopyrightText: 2020 Vlad Zahorodnii <vlad.zahorodnii@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-or-later 0005 */ 0006 0007 #include "kwin_wayland_test.h" 0008 0009 #include "compositor.h" 0010 #include "core/output.h" 0011 #include "main.h" 0012 #include "scene/workspacescene.h" 0013 #include "wayland_server.h" 0014 #include "workspace.h" 0015 #include "x11window.h" 0016 #include "xwayland/xwayland.h" 0017 #include "xwayland/xwaylandlauncher.h" 0018 0019 #include <xcb/xcb_icccm.h> 0020 0021 namespace KWin 0022 { 0023 0024 static const QString s_socketName = QStringLiteral("wayland_test_kwin_xwayland_server_crash-0"); 0025 0026 class XwaylandServerCrashTest : public QObject 0027 { 0028 Q_OBJECT 0029 0030 private Q_SLOTS: 0031 void initTestCase(); 0032 void testCrash(); 0033 }; 0034 0035 void XwaylandServerCrashTest::initTestCase() 0036 { 0037 qRegisterMetaType<X11Window *>(); 0038 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0039 QVERIFY(waylandServer()->init(s_socketName)); 0040 Test::setOutputConfig({ 0041 QRect(0, 0, 1280, 1024), 0042 QRect(1280, 0, 1280, 1024), 0043 }); 0044 0045 KSharedConfig::Ptr config = KSharedConfig::openConfig(QString(), KConfig::SimpleConfig); 0046 KConfigGroup xwaylandGroup = config->group(QStringLiteral("Xwayland")); 0047 xwaylandGroup.writeEntry(QStringLiteral("XwaylandCrashPolicy"), QStringLiteral("Stop")); 0048 xwaylandGroup.sync(); 0049 kwinApp()->setConfig(config); 0050 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 } 0058 0059 void XwaylandServerCrashTest::testCrash() 0060 { 0061 // This test verifies that all connected X11 clients get destroyed when Xwayland crashes. 0062 0063 // Create a normal window. 0064 Test::XcbConnectionPtr c = Test::createX11Connection(); 0065 QVERIFY(!xcb_connection_has_error(c.get())); 0066 const QRect windowGeometry(0, 0, 100, 200); 0067 xcb_window_t windowId1 = xcb_generate_id(c.get()); 0068 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId1, rootWindow(), 0069 windowGeometry.x(), 0070 windowGeometry.y(), 0071 windowGeometry.width(), 0072 windowGeometry.height(), 0073 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0, nullptr); 0074 xcb_size_hints_t hints; 0075 memset(&hints, 0, sizeof(hints)); 0076 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0077 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0078 xcb_icccm_size_hints_set_min_size(&hints, windowGeometry.width(), windowGeometry.height()); 0079 xcb_icccm_set_wm_normal_hints(c.get(), windowId1, &hints); 0080 xcb_map_window(c.get(), windowId1); 0081 xcb_flush(c.get()); 0082 0083 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0084 QVERIFY(windowCreatedSpy.wait()); 0085 QPointer<X11Window> window = windowCreatedSpy.last().first().value<X11Window *>(); 0086 QVERIFY(window); 0087 QVERIFY(window->isDecorated()); 0088 0089 // Create an override-redirect window. 0090 xcb_window_t windowId2 = xcb_generate_id(c.get()); 0091 const uint32_t values[] = {true}; 0092 xcb_create_window(c.get(), XCB_COPY_FROM_PARENT, windowId2, rootWindow(), 0093 windowGeometry.x(), windowGeometry.y(), 0094 windowGeometry.width(), windowGeometry.height(), 0, 0095 XCB_WINDOW_CLASS_INPUT_OUTPUT, XCB_COPY_FROM_PARENT, 0096 XCB_CW_OVERRIDE_REDIRECT, values); 0097 xcb_map_window(c.get(), windowId2); 0098 xcb_flush(c.get()); 0099 0100 QSignalSpy unmanagedAddedSpy(workspace(), &Workspace::windowAdded); 0101 QVERIFY(unmanagedAddedSpy.wait()); 0102 QPointer<X11Window> unmanaged = unmanagedAddedSpy.last().first().value<X11Window *>(); 0103 QVERIFY(unmanaged); 0104 0105 // Let's pretend that the Xwayland process has crashed. 0106 QSignalSpy x11ConnectionChangedSpy(kwinApp(), &Application::x11ConnectionChanged); 0107 Xwl::Xwayland *xwayland = static_cast<Xwl::Xwayland *>(kwinApp()->xwayland()); 0108 xwayland->xwaylandLauncher()->process()->terminate(); 0109 QVERIFY(x11ConnectionChangedSpy.wait()); 0110 0111 // When Xwayland crashes, the compositor should tear down the XCB connection and destroy 0112 // all connected X11 clients. 0113 QTRY_VERIFY(!window); 0114 QTRY_VERIFY(!unmanaged); 0115 QCOMPARE(kwinApp()->x11Connection(), nullptr); 0116 QCOMPARE(kwinApp()->x11RootWindow(), XCB_WINDOW_NONE); 0117 0118 // Render a frame to ensure that the compositor doesn't crash. 0119 Compositor::self()->scene()->addRepaintFull(); 0120 QSignalSpy frameRenderedSpy(Compositor::self()->scene(), &WorkspaceScene::frameRendered); 0121 QVERIFY(frameRenderedSpy.wait()); 0122 } 0123 0124 } // namespace KWin 0125 0126 WAYLANDTEST_MAIN(KWin::XwaylandServerCrashTest) 0127 #include "xwaylandserver_crash_test.moc"