File indexing completed on 2025-03-23 13:47:55
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 "core/outputbackend.h" 0013 #include "cursor.h" 0014 #include "deleted.h" 0015 #include "utils/xcbutils.h" 0016 #include "wayland_server.h" 0017 #include "window.h" 0018 #include "workspace.h" 0019 #include "x11window.h" 0020 #include <kwineffects.h> 0021 0022 #include <netwm.h> 0023 #include <xcb/xcb_icccm.h> 0024 0025 namespace KWin 0026 { 0027 0028 static const QString s_socketName = QStringLiteral("wayland_test_kwin_x11_desktop_window-0"); 0029 0030 class X11DesktopWindowTest : public QObject 0031 { 0032 Q_OBJECT 0033 private Q_SLOTS: 0034 void initTestCase(); 0035 void init(); 0036 void cleanup(); 0037 void testDesktopWindow(); 0038 0039 private: 0040 }; 0041 0042 void X11DesktopWindowTest::initTestCase() 0043 { 0044 qRegisterMetaType<KWin::Window *>(); 0045 qRegisterMetaType<KWin::Deleted *>(); 0046 QSignalSpy applicationStartedSpy(kwinApp(), &Application::started); 0047 QVERIFY(waylandServer()->init(s_socketName)); 0048 QMetaObject::invokeMethod(kwinApp()->outputBackend(), "setVirtualOutputs", Qt::DirectConnection, Q_ARG(QVector<QRect>, QVector<QRect>() << QRect(0, 0, 1280, 1024) << QRect(1280, 0, 1280, 1024))); 0049 0050 kwinApp()->start(); 0051 QVERIFY(applicationStartedSpy.wait()); 0052 const auto outputs = workspace()->outputs(); 0053 QCOMPARE(outputs.count(), 2); 0054 QCOMPARE(outputs[0]->geometry(), QRect(0, 0, 1280, 1024)); 0055 QCOMPARE(outputs[1]->geometry(), QRect(1280, 0, 1280, 1024)); 0056 setenv("QT_QPA_PLATFORM", "wayland", true); 0057 } 0058 0059 void X11DesktopWindowTest::init() 0060 { 0061 workspace()->setActiveOutput(QPoint(640, 512)); 0062 Cursors::self()->mouse()->setPos(QPoint(640, 512)); 0063 } 0064 0065 void X11DesktopWindowTest::cleanup() 0066 { 0067 } 0068 0069 struct XcbConnectionDeleter 0070 { 0071 void operator()(xcb_connection_t *pointer) 0072 { 0073 xcb_disconnect(pointer); 0074 } 0075 }; 0076 0077 void X11DesktopWindowTest::testDesktopWindow() 0078 { 0079 // this test creates a desktop window with an RGBA visual and verifies that it's only considered 0080 // as an RGB (opaque) window in KWin 0081 0082 // create an xcb window 0083 std::unique_ptr<xcb_connection_t, XcbConnectionDeleter> c(xcb_connect(nullptr, nullptr)); 0084 QVERIFY(!xcb_connection_has_error(c.get())); 0085 0086 xcb_window_t windowId = xcb_generate_id(c.get()); 0087 const QRect windowGeometry(0, 0, 1280, 1024); 0088 0089 // helper to find the visual 0090 auto findDepth = [&c]() -> xcb_visualid_t { 0091 // find a visual with 32 depth 0092 const xcb_setup_t *setup = xcb_get_setup(c.get()); 0093 0094 for (auto screen = xcb_setup_roots_iterator(setup); screen.rem; xcb_screen_next(&screen)) { 0095 for (auto depth = xcb_screen_allowed_depths_iterator(screen.data); depth.rem; xcb_depth_next(&depth)) { 0096 if (depth.data->depth != 32) { 0097 continue; 0098 } 0099 const int len = xcb_depth_visuals_length(depth.data); 0100 const xcb_visualtype_t *visuals = xcb_depth_visuals(depth.data); 0101 0102 for (int i = 0; i < len; i++) { 0103 return visuals[0].visual_id; 0104 } 0105 } 0106 } 0107 return 0; 0108 }; 0109 auto visualId = findDepth(); 0110 auto colormapId = xcb_generate_id(c.get()); 0111 auto cmCookie = xcb_create_colormap_checked(c.get(), XCB_COLORMAP_ALLOC_NONE, colormapId, rootWindow(), visualId); 0112 QVERIFY(!xcb_request_check(c.get(), cmCookie)); 0113 0114 const uint32_t values[] = {XCB_PIXMAP_NONE, Xcb::defaultScreen()->black_pixel, colormapId}; 0115 auto cookie = xcb_create_window_checked(c.get(), 32, windowId, rootWindow(), 0116 windowGeometry.x(), 0117 windowGeometry.y(), 0118 windowGeometry.width(), 0119 windowGeometry.height(), 0120 0, XCB_WINDOW_CLASS_INPUT_OUTPUT, visualId, XCB_CW_BACK_PIXMAP | XCB_CW_BORDER_PIXEL | XCB_CW_COLORMAP, values); 0121 QVERIFY(!xcb_request_check(c.get(), cookie)); 0122 xcb_size_hints_t hints; 0123 memset(&hints, 0, sizeof(hints)); 0124 xcb_icccm_size_hints_set_position(&hints, 1, windowGeometry.x(), windowGeometry.y()); 0125 xcb_icccm_size_hints_set_size(&hints, 1, windowGeometry.width(), windowGeometry.height()); 0126 xcb_icccm_set_wm_normal_hints(c.get(), windowId, &hints); 0127 NETWinInfo info(c.get(), windowId, rootWindow(), NET::WMAllProperties, NET::WM2AllProperties); 0128 info.setWindowType(NET::Desktop); 0129 xcb_map_window(c.get(), windowId); 0130 xcb_flush(c.get()); 0131 0132 // verify through a geometry request that it's depth 32 0133 Xcb::WindowGeometry geo(windowId); 0134 QCOMPARE(geo->depth, uint8_t(32)); 0135 0136 // we should get a window for it 0137 QSignalSpy windowCreatedSpy(workspace(), &Workspace::windowAdded); 0138 QVERIFY(windowCreatedSpy.wait()); 0139 X11Window *window = windowCreatedSpy.first().first().value<X11Window *>(); 0140 QVERIFY(window); 0141 QCOMPARE(window->window(), windowId); 0142 QVERIFY(!window->isDecorated()); 0143 QCOMPARE(window->windowType(), NET::Desktop); 0144 QCOMPARE(window->frameGeometry(), windowGeometry); 0145 QVERIFY(window->isDesktop()); 0146 QCOMPARE(window->depth(), 24); 0147 QVERIFY(!window->hasAlpha()); 0148 0149 // and destroy the window again 0150 xcb_unmap_window(c.get(), windowId); 0151 xcb_destroy_window(c.get(), windowId); 0152 xcb_flush(c.get()); 0153 c.reset(); 0154 0155 QSignalSpy windowClosedSpy(window, &X11Window::windowClosed); 0156 QVERIFY(windowClosedSpy.wait()); 0157 } 0158 0159 } 0160 0161 WAYLANDTEST_MAIN(KWin::X11DesktopWindowTest) 0162 #include "desktop_window_x11_test.moc"