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

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