File indexing completed on 2024-05-05 17:35:45

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"