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

0001 /*
0002     KWin - the KDE window manager
0003     This file is part of the KDE project.
0004 
0005     SPDX-FileCopyrightText: 2015 Martin Gräßlin <mgraesslin@kde.org>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 */
0009 #include <config-kwin.h>
0010 
0011 #include <QSignalSpy>
0012 
0013 #include "kwin_wayland_test.h"
0014 
0015 #if KWIN_BUILD_SCREENLOCKER
0016 #include "screenlockerwatcher.h"
0017 #endif
0018 #include "inputmethod.h"
0019 #include "wayland/display.h"
0020 #include "wayland_server.h"
0021 #include "workspace.h"
0022 #include <wayland-zkde-screencast-unstable-v1-client-protocol.h>
0023 
0024 #include <KWayland/Client/appmenu.h>
0025 #include <KWayland/Client/compositor.h>
0026 #include <KWayland/Client/connection_thread.h>
0027 #include <KWayland/Client/event_queue.h>
0028 #include <KWayland/Client/output.h>
0029 #include <KWayland/Client/plasmashell.h>
0030 #include <KWayland/Client/plasmawindowmanagement.h>
0031 #include <KWayland/Client/pointer.h>
0032 #include <KWayland/Client/pointerconstraints.h>
0033 #include <KWayland/Client/registry.h>
0034 #include <KWayland/Client/seat.h>
0035 #include <KWayland/Client/shadow.h>
0036 #include <KWayland/Client/shm_pool.h>
0037 #include <KWayland/Client/subcompositor.h>
0038 #include <KWayland/Client/subsurface.h>
0039 #include <KWayland/Client/surface.h>
0040 #include <KWayland/Client/textinput.h>
0041 
0042 // screenlocker
0043 #if KWIN_BUILD_SCREENLOCKER
0044 #include <KScreenLocker/KsldApp>
0045 #endif
0046 
0047 #include <QFutureWatcher>
0048 #include <QThread>
0049 #include <QtConcurrentRun>
0050 
0051 // system
0052 #include <sys/socket.h>
0053 #include <sys/types.h>
0054 #include <unistd.h>
0055 #include <xf86drm.h>
0056 
0057 namespace KWin
0058 {
0059 namespace Test
0060 {
0061 
0062 LayerShellV1::~LayerShellV1()
0063 {
0064     destroy();
0065 }
0066 
0067 LayerSurfaceV1::~LayerSurfaceV1()
0068 {
0069     destroy();
0070 }
0071 
0072 void LayerSurfaceV1::zwlr_layer_surface_v1_configure(uint32_t serial, uint32_t width, uint32_t height)
0073 {
0074     Q_EMIT configureRequested(serial, QSize(width, height));
0075 }
0076 
0077 void LayerSurfaceV1::zwlr_layer_surface_v1_closed()
0078 {
0079     Q_EMIT closeRequested();
0080 }
0081 
0082 XdgShell::~XdgShell()
0083 {
0084     destroy();
0085 }
0086 
0087 XdgSurface::XdgSurface(XdgShell *shell, KWayland::Client::Surface *surface, QObject *parent)
0088     : QObject(parent)
0089     , QtWayland::xdg_surface(shell->get_xdg_surface(*surface))
0090     , m_surface(surface)
0091 {
0092 }
0093 
0094 XdgSurface::~XdgSurface()
0095 {
0096     destroy();
0097 }
0098 
0099 KWayland::Client::Surface *XdgSurface::surface() const
0100 {
0101     return m_surface;
0102 }
0103 
0104 void XdgSurface::xdg_surface_configure(uint32_t serial)
0105 {
0106     Q_EMIT configureRequested(serial);
0107 }
0108 
0109 XdgToplevel::XdgToplevel(XdgSurface *surface, QObject *parent)
0110     : QObject(parent)
0111     , QtWayland::xdg_toplevel(surface->get_toplevel())
0112     , m_xdgSurface(surface)
0113 {
0114 }
0115 
0116 XdgToplevel::~XdgToplevel()
0117 {
0118     destroy();
0119 }
0120 
0121 XdgSurface *XdgToplevel::xdgSurface() const
0122 {
0123     return m_xdgSurface.get();
0124 }
0125 
0126 void XdgToplevel::xdg_toplevel_configure(int32_t width, int32_t height, wl_array *states)
0127 {
0128     States requestedStates;
0129 
0130     const uint32_t *stateData = static_cast<const uint32_t *>(states->data);
0131     const size_t stateCount = states->size / sizeof(uint32_t);
0132 
0133     for (size_t i = 0; i < stateCount; ++i) {
0134         switch (stateData[i]) {
0135         case QtWayland::xdg_toplevel::state_maximized:
0136             requestedStates |= State::Maximized;
0137             break;
0138         case QtWayland::xdg_toplevel::state_fullscreen:
0139             requestedStates |= State::Fullscreen;
0140             break;
0141         case QtWayland::xdg_toplevel::state_resizing:
0142             requestedStates |= State::Resizing;
0143             break;
0144         case QtWayland::xdg_toplevel::state_activated:
0145             requestedStates |= State::Activated;
0146             break;
0147         }
0148     }
0149 
0150     Q_EMIT configureRequested(QSize(width, height), requestedStates);
0151 }
0152 
0153 void XdgToplevel::xdg_toplevel_close()
0154 {
0155     Q_EMIT closeRequested();
0156 }
0157 
0158 XdgPositioner::XdgPositioner(XdgShell *shell)
0159     : QtWayland::xdg_positioner(shell->create_positioner())
0160 {
0161 }
0162 
0163 XdgPositioner::~XdgPositioner()
0164 {
0165     destroy();
0166 }
0167 
0168 XdgPopup::XdgPopup(XdgSurface *surface, XdgSurface *parentSurface, XdgPositioner *positioner, QObject *parent)
0169     : QObject(parent)
0170     , QtWayland::xdg_popup(surface->get_popup(parentSurface->object(), positioner->object()))
0171     , m_xdgSurface(surface)
0172 {
0173 }
0174 
0175 XdgPopup::~XdgPopup()
0176 {
0177     destroy();
0178 }
0179 
0180 XdgSurface *XdgPopup::xdgSurface() const
0181 {
0182     return m_xdgSurface.get();
0183 }
0184 
0185 void XdgPopup::xdg_popup_configure(int32_t x, int32_t y, int32_t width, int32_t height)
0186 {
0187     Q_EMIT configureRequested(QRect(x, y, width, height));
0188 }
0189 
0190 void XdgPopup::xdg_popup_popup_done()
0191 {
0192     Q_EMIT doneReceived();
0193 }
0194 
0195 XdgDecorationManagerV1::~XdgDecorationManagerV1()
0196 {
0197     destroy();
0198 }
0199 
0200 XdgToplevelDecorationV1::XdgToplevelDecorationV1(XdgDecorationManagerV1 *manager,
0201                                                  XdgToplevel *toplevel, QObject *parent)
0202     : QObject(parent)
0203     , QtWayland::zxdg_toplevel_decoration_v1(manager->get_toplevel_decoration(toplevel->object()))
0204 {
0205 }
0206 
0207 XdgToplevelDecorationV1::~XdgToplevelDecorationV1()
0208 {
0209     destroy();
0210 }
0211 
0212 void XdgToplevelDecorationV1::zxdg_toplevel_decoration_v1_configure(uint32_t m)
0213 {
0214     Q_EMIT configureRequested(mode(m));
0215 }
0216 
0217 IdleInhibitManagerV1::~IdleInhibitManagerV1()
0218 {
0219     destroy();
0220 }
0221 
0222 IdleInhibitorV1::IdleInhibitorV1(IdleInhibitManagerV1 *manager, KWayland::Client::Surface *surface)
0223     : QtWayland::zwp_idle_inhibitor_v1(manager->create_inhibitor(*surface))
0224 {
0225 }
0226 
0227 IdleInhibitorV1::~IdleInhibitorV1()
0228 {
0229     destroy();
0230 }
0231 
0232 ScreenEdgeManagerV1::~ScreenEdgeManagerV1()
0233 {
0234     destroy();
0235 }
0236 
0237 AutoHideScreenEdgeV1::AutoHideScreenEdgeV1(ScreenEdgeManagerV1 *manager, KWayland::Client::Surface *surface, uint32_t border)
0238     : QtWayland::kde_auto_hide_screen_edge_v1(manager->get_auto_hide_screen_edge(border, *surface))
0239 {
0240 }
0241 
0242 AutoHideScreenEdgeV1::~AutoHideScreenEdgeV1()
0243 {
0244     destroy();
0245 }
0246 
0247 CursorShapeManagerV1::~CursorShapeManagerV1()
0248 {
0249     destroy();
0250 }
0251 
0252 CursorShapeDeviceV1::CursorShapeDeviceV1(CursorShapeManagerV1 *manager, KWayland::Client::Pointer *pointer)
0253     : QtWayland::wp_cursor_shape_device_v1(manager->get_pointer(*pointer))
0254 {
0255 }
0256 
0257 CursorShapeDeviceV1::~CursorShapeDeviceV1()
0258 {
0259     destroy();
0260 }
0261 
0262 FakeInput::~FakeInput()
0263 {
0264     destroy();
0265 }
0266 
0267 SecurityContextManagerV1::~SecurityContextManagerV1()
0268 {
0269     destroy();
0270 }
0271 
0272 static struct
0273 {
0274     KWayland::Client::ConnectionThread *connection = nullptr;
0275     KWayland::Client::EventQueue *queue = nullptr;
0276     KWayland::Client::Compositor *compositor = nullptr;
0277     KWayland::Client::SubCompositor *subCompositor = nullptr;
0278     KWayland::Client::ShadowManager *shadowManager = nullptr;
0279     XdgShell *xdgShell = nullptr;
0280     KWayland::Client::ShmPool *shm = nullptr;
0281     KWayland::Client::Seat *seat = nullptr;
0282     KWayland::Client::PlasmaShell *plasmaShell = nullptr;
0283     KWayland::Client::PlasmaWindowManagement *windowManagement = nullptr;
0284     KWayland::Client::PointerConstraints *pointerConstraints = nullptr;
0285     KWayland::Client::Registry *registry = nullptr;
0286     WaylandOutputManagementV2 *outputManagementV2 = nullptr;
0287     QThread *thread = nullptr;
0288     QList<KWayland::Client::Output *> outputs;
0289     QList<WaylandOutputDeviceV2 *> outputDevicesV2;
0290     IdleInhibitManagerV1 *idleInhibitManagerV1 = nullptr;
0291     KWayland::Client::AppMenuManager *appMenu = nullptr;
0292     XdgDecorationManagerV1 *xdgDecorationManagerV1 = nullptr;
0293     KWayland::Client::TextInputManager *textInputManager = nullptr;
0294     QtWayland::zwp_input_panel_v1 *inputPanelV1 = nullptr;
0295     MockInputMethod *inputMethodV1 = nullptr;
0296     QtWayland::zwp_input_method_context_v1 *inputMethodContextV1 = nullptr;
0297     LayerShellV1 *layerShellV1 = nullptr;
0298     TextInputManagerV3 *textInputManagerV3 = nullptr;
0299     FractionalScaleManagerV1 *fractionalScaleManagerV1 = nullptr;
0300     ScreencastingV1 *screencastingV1 = nullptr;
0301     ScreenEdgeManagerV1 *screenEdgeManagerV1 = nullptr;
0302     CursorShapeManagerV1 *cursorShapeManagerV1 = nullptr;
0303     FakeInput *fakeInput = nullptr;
0304     SecurityContextManagerV1 *securityContextManagerV1 = nullptr;
0305 } s_waylandConnection;
0306 
0307 MockInputMethod *inputMethod()
0308 {
0309     return s_waylandConnection.inputMethodV1;
0310 }
0311 
0312 KWayland::Client::Surface *inputPanelSurface()
0313 {
0314     return s_waylandConnection.inputMethodV1->inputPanelSurface();
0315 }
0316 
0317 MockInputMethod::MockInputMethod(struct wl_registry *registry, int id, int version)
0318     : QtWayland::zwp_input_method_v1(registry, id, version)
0319 {
0320 }
0321 MockInputMethod::~MockInputMethod()
0322 {
0323 }
0324 
0325 void MockInputMethod::zwp_input_method_v1_activate(struct ::zwp_input_method_context_v1 *context)
0326 {
0327     if (!m_inputSurface) {
0328         m_inputSurface = Test::createSurface();
0329         m_inputMethodSurface = Test::createInputPanelSurfaceV1(m_inputSurface.get(), s_waylandConnection.outputs.first(), m_mode);
0330     }
0331     m_context = context;
0332 
0333     switch (m_mode) {
0334     case Mode::TopLevel:
0335         Test::render(m_inputSurface.get(), QSize(1280, 400), Qt::blue);
0336         break;
0337     case Mode::Overlay:
0338         Test::render(m_inputSurface.get(), QSize(200, 50), Qt::blue);
0339         break;
0340     }
0341 
0342     Q_EMIT activate();
0343 }
0344 
0345 void MockInputMethod::setMode(MockInputMethod::Mode mode)
0346 {
0347     m_mode = mode;
0348 }
0349 
0350 void MockInputMethod::zwp_input_method_v1_deactivate(struct ::zwp_input_method_context_v1 *context)
0351 {
0352     QCOMPARE(context, m_context);
0353     zwp_input_method_context_v1_destroy(context);
0354     m_context = nullptr;
0355 
0356     if (m_inputSurface) {
0357         m_inputSurface->release();
0358         m_inputSurface->destroy();
0359         m_inputSurface.reset();
0360         delete m_inputMethodSurface;
0361         m_inputMethodSurface = nullptr;
0362     }
0363 }
0364 
0365 bool setupWaylandConnection(AdditionalWaylandInterfaces flags)
0366 {
0367     if (s_waylandConnection.connection) {
0368         return false;
0369     }
0370 
0371     int sx[2];
0372     if (socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, sx) < 0) {
0373         return false;
0374     }
0375     KWin::waylandServer()->display()->createClient(sx[0]);
0376     // setup connection
0377     s_waylandConnection.connection = new KWayland::Client::ConnectionThread;
0378     QSignalSpy connectedSpy(s_waylandConnection.connection, &KWayland::Client::ConnectionThread::connected);
0379     if (!connectedSpy.isValid()) {
0380         return false;
0381     }
0382     s_waylandConnection.connection->setSocketFd(sx[1]);
0383 
0384     s_waylandConnection.thread = new QThread(kwinApp());
0385     s_waylandConnection.connection->moveToThread(s_waylandConnection.thread);
0386     s_waylandConnection.thread->start();
0387 
0388     s_waylandConnection.connection->initConnection();
0389     if (!connectedSpy.wait()) {
0390         return false;
0391     }
0392 
0393     s_waylandConnection.queue = new KWayland::Client::EventQueue;
0394     s_waylandConnection.queue->setup(s_waylandConnection.connection);
0395     if (!s_waylandConnection.queue->isValid()) {
0396         return false;
0397     }
0398 
0399     KWayland::Client::Registry *registry = new KWayland::Client::Registry;
0400     s_waylandConnection.registry = registry;
0401     registry->setEventQueue(s_waylandConnection.queue);
0402 
0403     QObject::connect(registry, &KWayland::Client::Registry::outputAnnounced, [=](quint32 name, quint32 version) {
0404         KWayland::Client::Output *output = registry->createOutput(name, version, s_waylandConnection.registry);
0405         s_waylandConnection.outputs << output;
0406         QObject::connect(output, &KWayland::Client::Output::removed, [=]() {
0407             output->deleteLater();
0408             s_waylandConnection.outputs.removeOne(output);
0409         });
0410         QObject::connect(output, &KWayland::Client::Output::destroyed, [=]() {
0411             s_waylandConnection.outputs.removeOne(output);
0412         });
0413     });
0414 
0415     QObject::connect(registry, &KWayland::Client::Registry::interfaceAnnounced, [=](const QByteArray &interface, quint32 name, quint32 version) {
0416         if (flags & AdditionalWaylandInterface::InputMethodV1) {
0417             if (interface == QByteArrayLiteral("zwp_input_method_v1")) {
0418                 s_waylandConnection.inputMethodV1 = new MockInputMethod(*registry, name, version);
0419             } else if (interface == QByteArrayLiteral("zwp_input_panel_v1")) {
0420                 s_waylandConnection.inputPanelV1 = new QtWayland::zwp_input_panel_v1(*registry, name, version);
0421             }
0422         }
0423         if (flags & AdditionalWaylandInterface::LayerShellV1) {
0424             if (interface == QByteArrayLiteral("zwlr_layer_shell_v1")) {
0425                 s_waylandConnection.layerShellV1 = new LayerShellV1();
0426                 s_waylandConnection.layerShellV1->init(*registry, name, version);
0427             }
0428         }
0429         if (flags & AdditionalWaylandInterface::TextInputManagerV3) {
0430             // do something
0431             if (interface == QByteArrayLiteral("zwp_text_input_manager_v3")) {
0432                 s_waylandConnection.textInputManagerV3 = new TextInputManagerV3();
0433                 s_waylandConnection.textInputManagerV3->init(*registry, name, version);
0434             }
0435         }
0436         if (interface == QByteArrayLiteral("xdg_wm_base")) {
0437             s_waylandConnection.xdgShell = new XdgShell();
0438             s_waylandConnection.xdgShell->init(*registry, name, version);
0439         }
0440         if (flags & AdditionalWaylandInterface::XdgDecorationV1) {
0441             if (interface == zxdg_decoration_manager_v1_interface.name) {
0442                 s_waylandConnection.xdgDecorationManagerV1 = new XdgDecorationManagerV1();
0443                 s_waylandConnection.xdgDecorationManagerV1->init(*registry, name, version);
0444                 return;
0445             }
0446         }
0447         if (flags & AdditionalWaylandInterface::IdleInhibitV1) {
0448             if (interface == zwp_idle_inhibit_manager_v1_interface.name) {
0449                 s_waylandConnection.idleInhibitManagerV1 = new IdleInhibitManagerV1();
0450                 s_waylandConnection.idleInhibitManagerV1->init(*registry, name, version);
0451                 return;
0452             }
0453         }
0454         if (flags & AdditionalWaylandInterface::OutputDeviceV2) {
0455             if (interface == kde_output_device_v2_interface.name) {
0456                 WaylandOutputDeviceV2 *device = new WaylandOutputDeviceV2(name);
0457                 device->init(*registry, name, version);
0458 
0459                 s_waylandConnection.outputDevicesV2 << device;
0460 
0461                 QObject::connect(device, &WaylandOutputDeviceV2::destroyed, [=]() {
0462                     s_waylandConnection.outputDevicesV2.removeOne(device);
0463                     device->deleteLater();
0464                 });
0465 
0466                 QObject::connect(registry, &KWayland::Client::Registry::interfaceRemoved, device, [name, device](const quint32 &interfaceName) {
0467                     if (name == interfaceName) {
0468                         s_waylandConnection.outputDevicesV2.removeOne(device);
0469                         device->deleteLater();
0470                     }
0471                 });
0472 
0473                 return;
0474             }
0475         }
0476         if (flags & AdditionalWaylandInterface::OutputManagementV2) {
0477             if (interface == kde_output_management_v2_interface.name) {
0478                 s_waylandConnection.outputManagementV2 = new WaylandOutputManagementV2(*registry, name, version);
0479                 return;
0480             }
0481         }
0482         if (flags & AdditionalWaylandInterface::FractionalScaleManagerV1) {
0483             if (interface == wp_fractional_scale_manager_v1_interface.name) {
0484                 s_waylandConnection.fractionalScaleManagerV1 = new FractionalScaleManagerV1();
0485                 s_waylandConnection.fractionalScaleManagerV1->init(*registry, name, version);
0486                 return;
0487             }
0488         }
0489         if (flags & AdditionalWaylandInterface::ScreencastingV1) {
0490             if (interface == zkde_screencast_unstable_v1_interface.name) {
0491                 s_waylandConnection.screencastingV1 = new ScreencastingV1();
0492                 s_waylandConnection.screencastingV1->init(*registry, name, version);
0493                 return;
0494             }
0495         }
0496         if (flags & AdditionalWaylandInterface::ScreenEdgeV1) {
0497             if (interface == kde_screen_edge_manager_v1_interface.name) {
0498                 s_waylandConnection.screenEdgeManagerV1 = new ScreenEdgeManagerV1();
0499                 s_waylandConnection.screenEdgeManagerV1->init(*registry, name, version);
0500                 return;
0501             }
0502         }
0503         if (flags & AdditionalWaylandInterface::CursorShapeV1) {
0504             if (interface == wp_cursor_shape_manager_v1_interface.name) {
0505                 s_waylandConnection.cursorShapeManagerV1 = new CursorShapeManagerV1();
0506                 s_waylandConnection.cursorShapeManagerV1->init(*registry, name, version);
0507             }
0508         }
0509         if (flags & AdditionalWaylandInterface::FakeInput) {
0510             if (interface == org_kde_kwin_fake_input_interface.name) {
0511                 s_waylandConnection.fakeInput = new FakeInput();
0512                 s_waylandConnection.fakeInput->init(*registry, name, version);
0513             }
0514         }
0515         if (flags & AdditionalWaylandInterface::SecurityContextManagerV1) {
0516             if (interface == wp_security_context_manager_v1_interface.name) {
0517                 s_waylandConnection.securityContextManagerV1 = new SecurityContextManagerV1();
0518                 s_waylandConnection.securityContextManagerV1->init(*registry, name, version);
0519             }
0520         }
0521     });
0522 
0523     QSignalSpy allAnnounced(registry, &KWayland::Client::Registry::interfacesAnnounced);
0524     if (!allAnnounced.isValid()) {
0525         return false;
0526     }
0527     registry->create(s_waylandConnection.connection);
0528     if (!registry->isValid()) {
0529         return false;
0530     }
0531     registry->setup();
0532     if (!allAnnounced.wait()) {
0533         return false;
0534     }
0535 
0536     s_waylandConnection.compositor = registry->createCompositor(registry->interface(KWayland::Client::Registry::Interface::Compositor).name, registry->interface(KWayland::Client::Registry::Interface::Compositor).version);
0537     if (!s_waylandConnection.compositor->isValid()) {
0538         return false;
0539     }
0540     s_waylandConnection.subCompositor = registry->createSubCompositor(registry->interface(KWayland::Client::Registry::Interface::SubCompositor).name, registry->interface(KWayland::Client::Registry::Interface::SubCompositor).version);
0541     if (!s_waylandConnection.subCompositor->isValid()) {
0542         return false;
0543     }
0544     s_waylandConnection.shm = registry->createShmPool(registry->interface(KWayland::Client::Registry::Interface::Shm).name, registry->interface(KWayland::Client::Registry::Interface::Shm).version);
0545     if (!s_waylandConnection.shm->isValid()) {
0546         return false;
0547     }
0548     if (flags.testFlag(AdditionalWaylandInterface::Seat)) {
0549         s_waylandConnection.seat = registry->createSeat(registry->interface(KWayland::Client::Registry::Interface::Seat).name, registry->interface(KWayland::Client::Registry::Interface::Seat).version);
0550         if (!s_waylandConnection.seat->isValid()) {
0551             return false;
0552         }
0553     }
0554     if (flags.testFlag(AdditionalWaylandInterface::ShadowManager)) {
0555         s_waylandConnection.shadowManager = registry->createShadowManager(registry->interface(KWayland::Client::Registry::Interface::Shadow).name,
0556                                                                           registry->interface(KWayland::Client::Registry::Interface::Shadow).version);
0557         if (!s_waylandConnection.shadowManager->isValid()) {
0558             return false;
0559         }
0560     }
0561     if (flags.testFlag(AdditionalWaylandInterface::PlasmaShell)) {
0562         s_waylandConnection.plasmaShell = registry->createPlasmaShell(registry->interface(KWayland::Client::Registry::Interface::PlasmaShell).name,
0563                                                                       registry->interface(KWayland::Client::Registry::Interface::PlasmaShell).version);
0564         if (!s_waylandConnection.plasmaShell->isValid()) {
0565             return false;
0566         }
0567     }
0568     if (flags.testFlag(AdditionalWaylandInterface::WindowManagement)) {
0569         s_waylandConnection.windowManagement = registry->createPlasmaWindowManagement(registry->interface(KWayland::Client::Registry::Interface::PlasmaWindowManagement).name,
0570                                                                                       registry->interface(KWayland::Client::Registry::Interface::PlasmaWindowManagement).version);
0571         if (!s_waylandConnection.windowManagement->isValid()) {
0572             return false;
0573         }
0574     }
0575     if (flags.testFlag(AdditionalWaylandInterface::PointerConstraints)) {
0576         s_waylandConnection.pointerConstraints = registry->createPointerConstraints(registry->interface(KWayland::Client::Registry::Interface::PointerConstraintsUnstableV1).name,
0577                                                                                     registry->interface(KWayland::Client::Registry::Interface::PointerConstraintsUnstableV1).version);
0578         if (!s_waylandConnection.pointerConstraints->isValid()) {
0579             return false;
0580         }
0581     }
0582     if (flags.testFlag(AdditionalWaylandInterface::AppMenu)) {
0583         s_waylandConnection.appMenu = registry->createAppMenuManager(registry->interface(KWayland::Client::Registry::Interface::AppMenu).name, registry->interface(KWayland::Client::Registry::Interface::AppMenu).version);
0584         if (!s_waylandConnection.appMenu->isValid()) {
0585             return false;
0586         }
0587     }
0588     if (flags.testFlag(AdditionalWaylandInterface::TextInputManagerV2)) {
0589         s_waylandConnection.textInputManager = registry->createTextInputManager(registry->interface(KWayland::Client::Registry::Interface::TextInputManagerUnstableV2).name, registry->interface(KWayland::Client::Registry::Interface::TextInputManagerUnstableV2).version);
0590         if (!s_waylandConnection.textInputManager->isValid()) {
0591             return false;
0592         }
0593     }
0594 
0595     return true;
0596 }
0597 
0598 void destroyWaylandConnection()
0599 {
0600     delete s_waylandConnection.compositor;
0601     s_waylandConnection.compositor = nullptr;
0602     delete s_waylandConnection.subCompositor;
0603     s_waylandConnection.subCompositor = nullptr;
0604     delete s_waylandConnection.windowManagement;
0605     s_waylandConnection.windowManagement = nullptr;
0606     delete s_waylandConnection.plasmaShell;
0607     s_waylandConnection.plasmaShell = nullptr;
0608     delete s_waylandConnection.seat;
0609     s_waylandConnection.seat = nullptr;
0610     delete s_waylandConnection.pointerConstraints;
0611     s_waylandConnection.pointerConstraints = nullptr;
0612     delete s_waylandConnection.xdgShell;
0613     s_waylandConnection.xdgShell = nullptr;
0614     delete s_waylandConnection.shadowManager;
0615     s_waylandConnection.shadowManager = nullptr;
0616     delete s_waylandConnection.idleInhibitManagerV1;
0617     s_waylandConnection.idleInhibitManagerV1 = nullptr;
0618     delete s_waylandConnection.shm;
0619     s_waylandConnection.shm = nullptr;
0620     delete s_waylandConnection.registry;
0621     s_waylandConnection.registry = nullptr;
0622     delete s_waylandConnection.appMenu;
0623     s_waylandConnection.appMenu = nullptr;
0624     delete s_waylandConnection.xdgDecorationManagerV1;
0625     s_waylandConnection.xdgDecorationManagerV1 = nullptr;
0626     delete s_waylandConnection.textInputManager;
0627     s_waylandConnection.textInputManager = nullptr;
0628     delete s_waylandConnection.inputPanelV1;
0629     s_waylandConnection.inputPanelV1 = nullptr;
0630     delete s_waylandConnection.layerShellV1;
0631     s_waylandConnection.layerShellV1 = nullptr;
0632     delete s_waylandConnection.outputManagementV2;
0633     s_waylandConnection.outputManagementV2 = nullptr;
0634     delete s_waylandConnection.fractionalScaleManagerV1;
0635     s_waylandConnection.fractionalScaleManagerV1 = nullptr;
0636     delete s_waylandConnection.screencastingV1;
0637     s_waylandConnection.screencastingV1 = nullptr;
0638     delete s_waylandConnection.screenEdgeManagerV1;
0639     s_waylandConnection.screenEdgeManagerV1 = nullptr;
0640     delete s_waylandConnection.cursorShapeManagerV1;
0641     s_waylandConnection.cursorShapeManagerV1 = nullptr;
0642     delete s_waylandConnection.fakeInput;
0643     s_waylandConnection.fakeInput = nullptr;
0644     delete s_waylandConnection.securityContextManagerV1;
0645     s_waylandConnection.securityContextManagerV1 = nullptr;
0646 
0647     delete s_waylandConnection.queue; // Must be destroyed last
0648     s_waylandConnection.queue = nullptr;
0649 
0650     if (s_waylandConnection.thread) {
0651         s_waylandConnection.connection->deleteLater();
0652         s_waylandConnection.thread->quit();
0653         s_waylandConnection.thread->wait();
0654         delete s_waylandConnection.thread;
0655         s_waylandConnection.thread = nullptr;
0656         s_waylandConnection.connection = nullptr;
0657     }
0658     s_waylandConnection.outputs.clear();
0659     s_waylandConnection.outputDevicesV2.clear();
0660 }
0661 
0662 KWayland::Client::ConnectionThread *waylandConnection()
0663 {
0664     return s_waylandConnection.connection;
0665 }
0666 
0667 KWayland::Client::Compositor *waylandCompositor()
0668 {
0669     return s_waylandConnection.compositor;
0670 }
0671 
0672 KWayland::Client::SubCompositor *waylandSubCompositor()
0673 {
0674     return s_waylandConnection.subCompositor;
0675 }
0676 
0677 KWayland::Client::ShadowManager *waylandShadowManager()
0678 {
0679     return s_waylandConnection.shadowManager;
0680 }
0681 
0682 KWayland::Client::ShmPool *waylandShmPool()
0683 {
0684     return s_waylandConnection.shm;
0685 }
0686 
0687 KWayland::Client::Seat *waylandSeat()
0688 {
0689     return s_waylandConnection.seat;
0690 }
0691 
0692 KWayland::Client::PlasmaShell *waylandPlasmaShell()
0693 {
0694     return s_waylandConnection.plasmaShell;
0695 }
0696 
0697 KWayland::Client::PlasmaWindowManagement *waylandWindowManagement()
0698 {
0699     return s_waylandConnection.windowManagement;
0700 }
0701 
0702 KWayland::Client::PointerConstraints *waylandPointerConstraints()
0703 {
0704     return s_waylandConnection.pointerConstraints;
0705 }
0706 
0707 KWayland::Client::AppMenuManager *waylandAppMenuManager()
0708 {
0709     return s_waylandConnection.appMenu;
0710 }
0711 
0712 KWin::Test::WaylandOutputManagementV2 *waylandOutputManagementV2()
0713 {
0714     return s_waylandConnection.outputManagementV2;
0715 }
0716 
0717 KWayland::Client::TextInputManager *waylandTextInputManager()
0718 {
0719     return s_waylandConnection.textInputManager;
0720 }
0721 
0722 TextInputManagerV3 *waylandTextInputManagerV3()
0723 {
0724     return s_waylandConnection.textInputManagerV3;
0725 }
0726 
0727 QList<KWayland::Client::Output *> waylandOutputs()
0728 {
0729     return s_waylandConnection.outputs;
0730 }
0731 
0732 KWayland::Client::Output *waylandOutput(const QString &name)
0733 {
0734     for (KWayland::Client::Output *output : std::as_const(s_waylandConnection.outputs)) {
0735         if (output->name() == name) {
0736             return output;
0737         }
0738     }
0739     return nullptr;
0740 }
0741 
0742 ScreencastingV1 *screencasting()
0743 {
0744     return s_waylandConnection.screencastingV1;
0745 }
0746 
0747 QList<KWin::Test::WaylandOutputDeviceV2 *> waylandOutputDevicesV2()
0748 {
0749     return s_waylandConnection.outputDevicesV2;
0750 }
0751 
0752 FakeInput *waylandFakeInput()
0753 {
0754     return s_waylandConnection.fakeInput;
0755 }
0756 
0757 SecurityContextManagerV1 *waylandSecurityContextManagerV1()
0758 {
0759     return s_waylandConnection.securityContextManagerV1;
0760 }
0761 
0762 bool waitForWaylandSurface(Window *window)
0763 {
0764     if (window->surface()) {
0765         return true;
0766     }
0767     QSignalSpy surfaceChangedSpy(window, &Window::surfaceChanged);
0768     return surfaceChangedSpy.wait();
0769 }
0770 
0771 bool waitForWaylandPointer()
0772 {
0773     if (!s_waylandConnection.seat) {
0774         return false;
0775     }
0776     QSignalSpy hasPointerSpy(s_waylandConnection.seat, &KWayland::Client::Seat::hasPointerChanged);
0777     if (!hasPointerSpy.isValid()) {
0778         return false;
0779     }
0780     return hasPointerSpy.wait();
0781 }
0782 
0783 bool waitForWaylandTouch()
0784 {
0785     if (!s_waylandConnection.seat) {
0786         return false;
0787     }
0788     QSignalSpy hasTouchSpy(s_waylandConnection.seat, &KWayland::Client::Seat::hasTouchChanged);
0789     if (!hasTouchSpy.isValid()) {
0790         return false;
0791     }
0792     return hasTouchSpy.wait();
0793 }
0794 
0795 bool waitForWaylandKeyboard()
0796 {
0797     if (!s_waylandConnection.seat) {
0798         return false;
0799     }
0800     QSignalSpy hasKeyboardSpy(s_waylandConnection.seat, &KWayland::Client::Seat::hasKeyboardChanged);
0801     if (!hasKeyboardSpy.isValid()) {
0802         return false;
0803     }
0804     return hasKeyboardSpy.wait();
0805 }
0806 
0807 void render(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format)
0808 {
0809     QImage img(size, format);
0810     img.fill(color);
0811     render(surface, img);
0812 }
0813 
0814 void render(KWayland::Client::Surface *surface, const QImage &img)
0815 {
0816     surface->attachBuffer(s_waylandConnection.shm->createBuffer(img));
0817     surface->damage(QRect(QPoint(0, 0), img.size()));
0818     surface->commit(KWayland::Client::Surface::CommitFlag::None);
0819 }
0820 
0821 Window *waitForWaylandWindowShown(int timeout)
0822 {
0823     QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
0824     if (!windowAddedSpy.isValid()) {
0825         return nullptr;
0826     }
0827     if (!windowAddedSpy.wait(timeout)) {
0828         return nullptr;
0829     }
0830     return windowAddedSpy.first().first().value<Window *>();
0831 }
0832 
0833 Window *renderAndWaitForShown(KWayland::Client::Surface *surface, const QSize &size, const QColor &color, const QImage::Format &format, int timeout)
0834 {
0835     QImage img(size, format);
0836     img.fill(color);
0837     return renderAndWaitForShown(surface, img, timeout);
0838 }
0839 
0840 Window *renderAndWaitForShown(KWayland::Client::Surface *surface, const QImage &img, int timeout)
0841 {
0842     QSignalSpy windowAddedSpy(workspace(), &Workspace::windowAdded);
0843     if (!windowAddedSpy.isValid()) {
0844         return nullptr;
0845     }
0846     render(surface, img);
0847     flushWaylandConnection();
0848     if (!windowAddedSpy.wait(timeout)) {
0849         return nullptr;
0850     }
0851     return windowAddedSpy.first().first().value<Window *>();
0852 }
0853 
0854 void flushWaylandConnection()
0855 {
0856     if (s_waylandConnection.connection) {
0857         s_waylandConnection.connection->flush();
0858     }
0859 }
0860 
0861 class WaylandSyncPoint : public QObject
0862 {
0863     Q_OBJECT
0864 
0865 public:
0866     explicit WaylandSyncPoint(KWayland::Client::ConnectionThread *connection, KWayland::Client::EventQueue *eventQueue)
0867     {
0868         static const wl_callback_listener listener = {
0869             .done = [](void *data, wl_callback *callback, uint32_t callback_data) {
0870                 auto syncPoint = static_cast<WaylandSyncPoint *>(data);
0871                 Q_EMIT syncPoint->done();
0872             },
0873         };
0874 
0875         m_callback = wl_display_sync(connection->display());
0876         eventQueue->addProxy(m_callback);
0877         wl_callback_add_listener(m_callback, &listener, this);
0878     }
0879 
0880     ~WaylandSyncPoint() override
0881     {
0882         wl_callback_destroy(m_callback);
0883     }
0884 
0885 Q_SIGNALS:
0886     void done();
0887 
0888 private:
0889     wl_callback *m_callback;
0890 };
0891 
0892 bool waylandSync()
0893 {
0894     WaylandSyncPoint syncPoint(s_waylandConnection.connection, s_waylandConnection.queue);
0895     QSignalSpy doneSpy(&syncPoint, &WaylandSyncPoint::done);
0896     return doneSpy.wait();
0897 }
0898 
0899 std::unique_ptr<KWayland::Client::Surface> createSurface()
0900 {
0901     if (!s_waylandConnection.compositor) {
0902         return nullptr;
0903     }
0904     std::unique_ptr<KWayland::Client::Surface> s{s_waylandConnection.compositor->createSurface()};
0905     return s->isValid() ? std::move(s) : nullptr;
0906 }
0907 
0908 KWayland::Client::SubSurface *createSubSurface(KWayland::Client::Surface *surface, KWayland::Client::Surface *parentSurface, QObject *parent)
0909 {
0910     if (!s_waylandConnection.subCompositor) {
0911         return nullptr;
0912     }
0913     auto s = s_waylandConnection.subCompositor->createSubSurface(surface, parentSurface, parent);
0914     if (!s->isValid()) {
0915         delete s;
0916         return nullptr;
0917     }
0918     return s;
0919 }
0920 
0921 LayerSurfaceV1 *createLayerSurfaceV1(KWayland::Client::Surface *surface, const QString &scope, KWayland::Client::Output *output, LayerShellV1::layer layer)
0922 {
0923     LayerShellV1 *shell = s_waylandConnection.layerShellV1;
0924     if (!shell) {
0925         qWarning() << "Could not create a layer surface because the layer shell global is not bound";
0926         return nullptr;
0927     }
0928 
0929     struct ::wl_output *nativeOutput = nullptr;
0930     if (output) {
0931         nativeOutput = *output;
0932     }
0933 
0934     LayerSurfaceV1 *shellSurface = new LayerSurfaceV1();
0935     shellSurface->init(shell->get_layer_surface(*surface, nativeOutput, layer, scope));
0936 
0937     return shellSurface;
0938 }
0939 
0940 QtWayland::zwp_input_panel_surface_v1 *createInputPanelSurfaceV1(KWayland::Client::Surface *surface, KWayland::Client::Output *output, MockInputMethod::Mode mode)
0941 {
0942     if (!s_waylandConnection.inputPanelV1) {
0943         qWarning() << "Unable to create the input panel surface. The interface input_panel global is not bound";
0944         return nullptr;
0945     }
0946     QtWayland::zwp_input_panel_surface_v1 *s = new QtWayland::zwp_input_panel_surface_v1(s_waylandConnection.inputPanelV1->get_input_panel_surface(*surface));
0947 
0948     if (!s->isInitialized()) {
0949         delete s;
0950         return nullptr;
0951     }
0952 
0953     switch (mode) {
0954     case MockInputMethod::Mode::TopLevel:
0955         s->set_toplevel(output->output(), QtWayland::zwp_input_panel_surface_v1::position_center_bottom);
0956         break;
0957     case MockInputMethod::Mode::Overlay:
0958         s->set_overlay_panel();
0959         break;
0960     }
0961 
0962     return s;
0963 }
0964 
0965 FractionalScaleV1 *createFractionalScaleV1(KWayland::Client::Surface *surface)
0966 {
0967     if (!s_waylandConnection.fractionalScaleManagerV1) {
0968         qWarning() << "Unable to create fractional scale surface. The global is not bound";
0969         return nullptr;
0970     }
0971     auto scale = new FractionalScaleV1();
0972     scale->init(s_waylandConnection.fractionalScaleManagerV1->get_fractional_scale(*surface));
0973 
0974     return scale;
0975 }
0976 
0977 static void waitForConfigured(XdgSurface *shellSurface)
0978 {
0979     QSignalSpy surfaceConfigureRequestedSpy(shellSurface, &XdgSurface::configureRequested);
0980 
0981     shellSurface->surface()->commit(KWayland::Client::Surface::CommitFlag::None);
0982     QVERIFY(surfaceConfigureRequestedSpy.wait());
0983 
0984     shellSurface->ack_configure(surfaceConfigureRequestedSpy.last().first().toUInt());
0985 }
0986 
0987 XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, QObject *parent)
0988 {
0989     return createXdgToplevelSurface(surface, CreationSetup::CreateAndConfigure, parent);
0990 }
0991 
0992 XdgToplevel *createXdgToplevelSurface(KWayland::Client::Surface *surface, CreationSetup configureMode, QObject *parent)
0993 {
0994     XdgShell *shell = s_waylandConnection.xdgShell;
0995 
0996     if (!shell) {
0997         qWarning() << "Could not create an xdg_toplevel surface because xdg_wm_base global is not bound";
0998         return nullptr;
0999     }
1000 
1001     XdgSurface *xdgSurface = new XdgSurface(shell, surface);
1002     XdgToplevel *xdgToplevel = new XdgToplevel(xdgSurface, parent);
1003 
1004     if (configureMode == CreationSetup::CreateAndConfigure) {
1005         waitForConfigured(xdgSurface);
1006     }
1007 
1008     return xdgToplevel;
1009 }
1010 
1011 XdgPositioner *createXdgPositioner()
1012 {
1013     XdgShell *shell = s_waylandConnection.xdgShell;
1014 
1015     if (!shell) {
1016         qWarning() << "Could not create an xdg_positioner object because xdg_wm_base global is not bound";
1017         return nullptr;
1018     }
1019 
1020     return new XdgPositioner(shell);
1021 }
1022 
1023 XdgPopup *createXdgPopupSurface(KWayland::Client::Surface *surface, XdgSurface *parentSurface, XdgPositioner *positioner,
1024                                 CreationSetup configureMode, QObject *parent)
1025 {
1026     XdgShell *shell = s_waylandConnection.xdgShell;
1027 
1028     if (!shell) {
1029         qWarning() << "Could not create an xdg_popup surface because xdg_wm_base global is not bound";
1030         return nullptr;
1031     }
1032 
1033     XdgSurface *xdgSurface = new XdgSurface(shell, surface);
1034     XdgPopup *xdgPopup = new XdgPopup(xdgSurface, parentSurface, positioner, parent);
1035 
1036     if (configureMode == CreationSetup::CreateAndConfigure) {
1037         waitForConfigured(xdgSurface);
1038     }
1039 
1040     return xdgPopup;
1041 }
1042 
1043 XdgToplevelDecorationV1 *createXdgToplevelDecorationV1(XdgToplevel *toplevel, QObject *parent)
1044 {
1045     XdgDecorationManagerV1 *manager = s_waylandConnection.xdgDecorationManagerV1;
1046 
1047     if (!manager) {
1048         qWarning() << "Could not create an xdg_toplevel_decoration_v1 because xdg_decoration_manager_v1 global is not bound";
1049         return nullptr;
1050     }
1051 
1052     return new XdgToplevelDecorationV1(manager, toplevel, parent);
1053 }
1054 
1055 IdleInhibitorV1 *createIdleInhibitorV1(KWayland::Client::Surface *surface)
1056 {
1057     IdleInhibitManagerV1 *manager = s_waylandConnection.idleInhibitManagerV1;
1058     if (!manager) {
1059         qWarning() << "Could not create an idle_inhibitor_v1 because idle_inhibit_manager_v1 global is not bound";
1060         return nullptr;
1061     }
1062 
1063     return new IdleInhibitorV1(manager, surface);
1064 }
1065 
1066 AutoHideScreenEdgeV1 *createAutoHideScreenEdgeV1(KWayland::Client::Surface *surface, uint32_t border)
1067 {
1068     ScreenEdgeManagerV1 *manager = s_waylandConnection.screenEdgeManagerV1;
1069     if (!manager) {
1070         qWarning() << "Could not create an kde_auto_hide_screen_edge_v1 because kde_screen_edge_manager_v1 global is not bound";
1071         return nullptr;
1072     }
1073 
1074     return new AutoHideScreenEdgeV1(manager, surface, border);
1075 }
1076 
1077 CursorShapeDeviceV1 *createCursorShapeDeviceV1(KWayland::Client::Pointer *pointer)
1078 {
1079     CursorShapeManagerV1 *manager = s_waylandConnection.cursorShapeManagerV1;
1080     if (!manager) {
1081         qWarning() << "Could not create a wp_cursor_shape_device_v1 because wp_cursor_shape_manager_v1 global is not bound";
1082         return nullptr;
1083     }
1084 
1085     return new CursorShapeDeviceV1(manager, pointer);
1086 }
1087 
1088 bool waitForWindowClosed(Window *window)
1089 {
1090     QSignalSpy closedSpy(window, &Window::closed);
1091     if (!closedSpy.isValid()) {
1092         return false;
1093     }
1094     return closedSpy.wait();
1095 }
1096 
1097 #if KWIN_BUILD_SCREENLOCKER
1098 bool lockScreen()
1099 {
1100     if (waylandServer()->isScreenLocked()) {
1101         return false;
1102     }
1103     QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged);
1104     if (!lockStateChangedSpy.isValid()) {
1105         return false;
1106     }
1107     ScreenLocker::KSldApp::self()->lock(ScreenLocker::EstablishLock::Immediate);
1108     if (lockStateChangedSpy.count() != 1) {
1109         return false;
1110     }
1111     if (!waylandServer()->isScreenLocked()) {
1112         return false;
1113     }
1114     if (!kwinApp()->screenLockerWatcher()->isLocked()) {
1115         QSignalSpy lockedSpy(kwinApp()->screenLockerWatcher(), &ScreenLockerWatcher::locked);
1116         if (!lockedSpy.isValid()) {
1117             return false;
1118         }
1119         if (!lockedSpy.wait()) {
1120             return false;
1121         }
1122         if (!kwinApp()->screenLockerWatcher()->isLocked()) {
1123             return false;
1124         }
1125     }
1126     return true;
1127 }
1128 
1129 bool unlockScreen()
1130 {
1131     QSignalSpy lockStateChangedSpy(ScreenLocker::KSldApp::self(), &ScreenLocker::KSldApp::lockStateChanged);
1132     if (!lockStateChangedSpy.isValid()) {
1133         return false;
1134     }
1135     using namespace ScreenLocker;
1136     const auto children = KSldApp::self()->children();
1137     for (auto it = children.begin(); it != children.end(); ++it) {
1138         if (qstrcmp((*it)->metaObject()->className(), "LogindIntegration") != 0) {
1139             continue;
1140         }
1141         QMetaObject::invokeMethod(*it, "requestUnlock");
1142         break;
1143     }
1144     if (waylandServer()->isScreenLocked()) {
1145         lockStateChangedSpy.wait();
1146     }
1147     if (waylandServer()->isScreenLocked()) {
1148         return true;
1149     }
1150     if (kwinApp()->screenLockerWatcher()->isLocked()) {
1151         QSignalSpy lockedSpy(kwinApp()->screenLockerWatcher(), &ScreenLockerWatcher::locked);
1152         if (!lockedSpy.isValid()) {
1153             return false;
1154         }
1155         if (!lockedSpy.wait()) {
1156             return false;
1157         }
1158         if (kwinApp()->screenLockerWatcher()->isLocked()) {
1159             return false;
1160         }
1161     }
1162     return true;
1163 }
1164 #endif // KWIN_BUILD_LOCKSCREEN
1165 
1166 bool renderNodeAvailable()
1167 {
1168     const int deviceCount = drmGetDevices2(0, nullptr, 0);
1169     if (deviceCount <= 0) {
1170         return false;
1171     }
1172 
1173     QList<drmDevice *> devices(deviceCount);
1174     if (drmGetDevices2(0, devices.data(), devices.size()) < 0) {
1175         return false;
1176     }
1177     auto deviceCleanup = qScopeGuard([&devices]() {
1178         drmFreeDevices(devices.data(), devices.size());
1179     });
1180 
1181     return std::any_of(devices.constBegin(), devices.constEnd(), [](drmDevice *device) {
1182         return device->available_nodes & (1 << DRM_NODE_RENDER);
1183     });
1184 }
1185 
1186 void XcbConnectionDeleter::operator()(xcb_connection_t *pointer)
1187 {
1188     xcb_disconnect(pointer);
1189 };
1190 
1191 Test::XcbConnectionPtr createX11Connection()
1192 {
1193     QFutureWatcher<xcb_connection_t *> watcher;
1194     QEventLoop e;
1195     e.connect(&watcher, &QFutureWatcher<xcb_connection_t *>::finished, &e, &QEventLoop::quit);
1196     QFuture<xcb_connection_t *> future = QtConcurrent::run([]() {
1197         return xcb_connect(nullptr, nullptr);
1198     });
1199     watcher.setFuture(future);
1200     e.exec();
1201     return Test::XcbConnectionPtr(future.result());
1202 }
1203 
1204 WaylandOutputManagementV2::WaylandOutputManagementV2(struct ::wl_registry *registry, int id, int version)
1205     : QObject()
1206     , QtWayland::kde_output_management_v2()
1207 {
1208     init(registry, id, version);
1209 }
1210 
1211 WaylandOutputConfigurationV2 *WaylandOutputManagementV2::createConfiguration()
1212 {
1213     return new WaylandOutputConfigurationV2(create_configuration());
1214 }
1215 
1216 WaylandOutputConfigurationV2::WaylandOutputConfigurationV2(struct ::kde_output_configuration_v2 *object)
1217     : QObject()
1218     , QtWayland::kde_output_configuration_v2()
1219 {
1220     init(object);
1221 }
1222 
1223 void WaylandOutputConfigurationV2::kde_output_configuration_v2_applied()
1224 {
1225     Q_EMIT applied();
1226 }
1227 void WaylandOutputConfigurationV2::kde_output_configuration_v2_failed()
1228 {
1229     Q_EMIT failed();
1230 }
1231 
1232 WaylandOutputDeviceV2Mode::WaylandOutputDeviceV2Mode(struct ::kde_output_device_mode_v2 *object)
1233     : QtWayland::kde_output_device_mode_v2(object)
1234 {
1235 }
1236 
1237 WaylandOutputDeviceV2Mode::~WaylandOutputDeviceV2Mode()
1238 {
1239     kde_output_device_mode_v2_destroy(object());
1240 }
1241 
1242 void WaylandOutputDeviceV2Mode::kde_output_device_mode_v2_size(int32_t width, int32_t height)
1243 {
1244     m_size = QSize(width, height);
1245 }
1246 
1247 void WaylandOutputDeviceV2Mode::kde_output_device_mode_v2_refresh(int32_t refresh)
1248 {
1249     m_refreshRate = refresh;
1250 }
1251 
1252 void WaylandOutputDeviceV2Mode::kde_output_device_mode_v2_preferred()
1253 {
1254     m_preferred = true;
1255 }
1256 
1257 void WaylandOutputDeviceV2Mode::kde_output_device_mode_v2_removed()
1258 {
1259     Q_EMIT removed();
1260 }
1261 
1262 int WaylandOutputDeviceV2Mode::refreshRate() const
1263 {
1264     return m_refreshRate;
1265 }
1266 
1267 QSize WaylandOutputDeviceV2Mode::size() const
1268 {
1269     return m_size;
1270 }
1271 
1272 bool WaylandOutputDeviceV2Mode::preferred() const
1273 {
1274     return m_preferred;
1275 }
1276 
1277 bool WaylandOutputDeviceV2Mode::operator==(const WaylandOutputDeviceV2Mode &other) const
1278 {
1279     return m_size == other.m_size && m_refreshRate == other.m_refreshRate && m_preferred == other.m_preferred;
1280 }
1281 
1282 WaylandOutputDeviceV2Mode *WaylandOutputDeviceV2Mode::get(struct ::kde_output_device_mode_v2 *object)
1283 {
1284     auto mode = QtWayland::kde_output_device_mode_v2::fromObject(object);
1285     return static_cast<WaylandOutputDeviceV2Mode *>(mode);
1286 }
1287 
1288 WaylandOutputDeviceV2::WaylandOutputDeviceV2(int id)
1289     : QObject()
1290     , kde_output_device_v2()
1291     , m_id(id)
1292 {
1293 }
1294 
1295 WaylandOutputDeviceV2::~WaylandOutputDeviceV2()
1296 {
1297     qDeleteAll(m_modes);
1298 
1299     kde_output_device_v2_destroy(object());
1300 }
1301 
1302 void WaylandOutputDeviceV2::kde_output_device_v2_geometry(int32_t x,
1303                                                           int32_t y,
1304                                                           int32_t physical_width,
1305                                                           int32_t physical_height,
1306                                                           int32_t subpixel,
1307                                                           const QString &make,
1308                                                           const QString &model,
1309                                                           int32_t transform)
1310 {
1311     m_pos = QPoint(x, y);
1312     m_physicalSize = QSize(physical_width, physical_height);
1313     m_subpixel = subpixel;
1314     m_manufacturer = make;
1315     m_model = model;
1316     m_transform = transform;
1317 }
1318 
1319 void WaylandOutputDeviceV2::kde_output_device_v2_current_mode(struct ::kde_output_device_mode_v2 *mode)
1320 {
1321     auto m = WaylandOutputDeviceV2Mode::get(mode);
1322 
1323     if (*m == *m_mode) {
1324         // unchanged
1325         return;
1326     }
1327     m_mode = m;
1328 }
1329 
1330 void WaylandOutputDeviceV2::kde_output_device_v2_mode(struct ::kde_output_device_mode_v2 *mode)
1331 {
1332     WaylandOutputDeviceV2Mode *m = new WaylandOutputDeviceV2Mode(mode);
1333     // last mode sent is the current one
1334     m_mode = m;
1335     m_modes.append(m);
1336 
1337     connect(m, &WaylandOutputDeviceV2Mode::removed, this, [this, m]() {
1338         m_modes.removeOne(m);
1339         if (m_mode == m) {
1340             if (!m_modes.isEmpty()) {
1341                 m_mode = m_modes.first();
1342             } else {
1343                 // was last mode
1344                 qFatal("KWaylandBackend: no output modes available anymore, this seems like a compositor bug");
1345             }
1346         }
1347 
1348         delete m;
1349     });
1350 }
1351 
1352 QString WaylandOutputDeviceV2::modeId() const
1353 {
1354     return QString::number(m_modes.indexOf(m_mode));
1355 }
1356 
1357 WaylandOutputDeviceV2Mode *WaylandOutputDeviceV2::deviceModeFromId(const int modeId) const
1358 {
1359     return m_modes.at(modeId);
1360 }
1361 
1362 QString WaylandOutputDeviceV2::modeName(const WaylandOutputDeviceV2Mode *m) const
1363 {
1364     return QString::number(m->size().width()) + QLatin1Char('x') + QString::number(m->size().height()) + QLatin1Char('@')
1365         + QString::number(qRound(m->refreshRate() / 1000.0));
1366 }
1367 
1368 QString WaylandOutputDeviceV2::name() const
1369 {
1370     return QStringLiteral("%1 %2").arg(m_manufacturer, m_model);
1371 }
1372 
1373 QDebug operator<<(QDebug dbg, const WaylandOutputDeviceV2 *output)
1374 {
1375     dbg << "WaylandOutput(Id:" << output->id() << ", Name:" << QString(output->manufacturer() + QLatin1Char(' ') + output->model()) << ")";
1376     return dbg;
1377 }
1378 
1379 void WaylandOutputDeviceV2::kde_output_device_v2_done()
1380 {
1381     Q_EMIT done();
1382 }
1383 
1384 void WaylandOutputDeviceV2::kde_output_device_v2_scale(wl_fixed_t factor)
1385 {
1386     m_factor = wl_fixed_to_double(factor);
1387 }
1388 
1389 void WaylandOutputDeviceV2::kde_output_device_v2_edid(const QString &edid)
1390 {
1391     m_edid = QByteArray::fromBase64(edid.toUtf8());
1392 }
1393 
1394 void WaylandOutputDeviceV2::kde_output_device_v2_enabled(int32_t enabled)
1395 {
1396     if (m_enabled != enabled) {
1397         m_enabled = enabled;
1398         Q_EMIT enabledChanged();
1399     }
1400 }
1401 
1402 void WaylandOutputDeviceV2::kde_output_device_v2_uuid(const QString &uuid)
1403 {
1404     m_uuid = uuid;
1405 }
1406 
1407 void WaylandOutputDeviceV2::kde_output_device_v2_serial_number(const QString &serialNumber)
1408 {
1409     m_serialNumber = serialNumber;
1410 }
1411 
1412 void WaylandOutputDeviceV2::kde_output_device_v2_eisa_id(const QString &eisaId)
1413 {
1414     m_eisaId = eisaId;
1415 }
1416 
1417 void WaylandOutputDeviceV2::kde_output_device_v2_capabilities(uint32_t flags)
1418 {
1419     m_flags = flags;
1420 }
1421 
1422 void WaylandOutputDeviceV2::kde_output_device_v2_overscan(uint32_t overscan)
1423 {
1424     m_overscan = overscan;
1425 }
1426 
1427 void WaylandOutputDeviceV2::kde_output_device_v2_vrr_policy(uint32_t vrr_policy)
1428 {
1429     m_vrr_policy = vrr_policy;
1430 }
1431 
1432 void WaylandOutputDeviceV2::kde_output_device_v2_rgb_range(uint32_t rgb_range)
1433 {
1434     m_rgbRange = rgb_range;
1435 }
1436 
1437 QByteArray WaylandOutputDeviceV2::edid() const
1438 {
1439     return m_edid;
1440 }
1441 
1442 bool WaylandOutputDeviceV2::enabled() const
1443 {
1444     return m_enabled;
1445 }
1446 
1447 int WaylandOutputDeviceV2::id() const
1448 {
1449     return m_id;
1450 }
1451 
1452 qreal WaylandOutputDeviceV2::scale() const
1453 {
1454     return m_factor;
1455 }
1456 
1457 QString WaylandOutputDeviceV2::manufacturer() const
1458 {
1459     return m_manufacturer;
1460 }
1461 
1462 QString WaylandOutputDeviceV2::model() const
1463 {
1464     return m_model;
1465 }
1466 
1467 QPoint WaylandOutputDeviceV2::globalPosition() const
1468 {
1469     return m_pos;
1470 }
1471 
1472 QSize WaylandOutputDeviceV2::pixelSize() const
1473 {
1474     return m_mode->size();
1475 }
1476 
1477 int WaylandOutputDeviceV2::refreshRate() const
1478 {
1479     return m_mode->refreshRate();
1480 }
1481 
1482 uint32_t WaylandOutputDeviceV2::vrrPolicy() const
1483 {
1484     return m_vrr_policy;
1485 }
1486 
1487 uint32_t WaylandOutputDeviceV2::overscan() const
1488 {
1489     return m_overscan;
1490 }
1491 
1492 uint32_t WaylandOutputDeviceV2::capabilities() const
1493 {
1494     return m_flags;
1495 }
1496 
1497 uint32_t WaylandOutputDeviceV2::rgbRange() const
1498 {
1499     return m_rgbRange;
1500 }
1501 
1502 VirtualInputDevice::VirtualInputDevice(QObject *parent)
1503     : InputDevice(parent)
1504 {
1505 }
1506 
1507 void VirtualInputDevice::setPointer(bool set)
1508 {
1509     m_pointer = set;
1510 }
1511 
1512 void VirtualInputDevice::setKeyboard(bool set)
1513 {
1514     m_keyboard = set;
1515 }
1516 
1517 void VirtualInputDevice::setTouch(bool set)
1518 {
1519     m_touch = set;
1520 }
1521 
1522 void VirtualInputDevice::setLidSwitch(bool set)
1523 {
1524     m_lidSwitch = set;
1525 }
1526 
1527 void VirtualInputDevice::setName(const QString &name)
1528 {
1529     m_name = name;
1530 }
1531 
1532 QString VirtualInputDevice::sysName() const
1533 {
1534     return QString();
1535 }
1536 
1537 QString VirtualInputDevice::name() const
1538 {
1539     return m_name;
1540 }
1541 
1542 bool VirtualInputDevice::isEnabled() const
1543 {
1544     return true;
1545 }
1546 
1547 void VirtualInputDevice::setEnabled(bool enabled)
1548 {
1549 }
1550 
1551 LEDs VirtualInputDevice::leds() const
1552 {
1553     return LEDs();
1554 }
1555 
1556 void VirtualInputDevice::setLeds(LEDs leds)
1557 {
1558 }
1559 
1560 bool VirtualInputDevice::isKeyboard() const
1561 {
1562     return m_keyboard;
1563 }
1564 
1565 bool VirtualInputDevice::isAlphaNumericKeyboard() const
1566 {
1567     return m_keyboard;
1568 }
1569 
1570 bool VirtualInputDevice::isPointer() const
1571 {
1572     return m_pointer;
1573 }
1574 
1575 bool VirtualInputDevice::isTouchpad() const
1576 {
1577     return false;
1578 }
1579 
1580 bool VirtualInputDevice::isTouch() const
1581 {
1582     return m_touch;
1583 }
1584 
1585 bool VirtualInputDevice::isTabletTool() const
1586 {
1587     return false;
1588 }
1589 
1590 bool VirtualInputDevice::isTabletPad() const
1591 {
1592     return false;
1593 }
1594 
1595 bool VirtualInputDevice::isTabletModeSwitch() const
1596 {
1597     return false;
1598 }
1599 
1600 bool VirtualInputDevice::isLidSwitch() const
1601 {
1602     return m_lidSwitch;
1603 }
1604 
1605 void keyboardKeyPressed(quint32 key, quint32 time)
1606 {
1607     auto virtualKeyboard = static_cast<WaylandTestApplication *>(kwinApp())->virtualKeyboard();
1608     Q_EMIT virtualKeyboard->keyChanged(key, InputRedirection::KeyboardKeyState::KeyboardKeyPressed, std::chrono::milliseconds(time), virtualKeyboard);
1609 }
1610 
1611 void keyboardKeyReleased(quint32 key, quint32 time)
1612 {
1613     auto virtualKeyboard = static_cast<WaylandTestApplication *>(kwinApp())->virtualKeyboard();
1614     Q_EMIT virtualKeyboard->keyChanged(key, InputRedirection::KeyboardKeyState::KeyboardKeyReleased, std::chrono::milliseconds(time), virtualKeyboard);
1615 }
1616 
1617 void pointerAxisHorizontal(qreal delta, quint32 time, qint32 discreteDelta, InputRedirection::PointerAxisSource source)
1618 {
1619     auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
1620     Q_EMIT virtualPointer->pointerAxisChanged(InputRedirection::PointerAxis::PointerAxisHorizontal, delta, discreteDelta, source, std::chrono::milliseconds(time), virtualPointer);
1621     Q_EMIT virtualPointer->pointerFrame(virtualPointer);
1622 }
1623 
1624 void pointerAxisVertical(qreal delta, quint32 time, qint32 discreteDelta, InputRedirection::PointerAxisSource source)
1625 {
1626     auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
1627     Q_EMIT virtualPointer->pointerAxisChanged(InputRedirection::PointerAxis::PointerAxisVertical, delta, discreteDelta, source, std::chrono::milliseconds(time), virtualPointer);
1628     Q_EMIT virtualPointer->pointerFrame(virtualPointer);
1629 }
1630 
1631 void pointerButtonPressed(quint32 button, quint32 time)
1632 {
1633     auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
1634     Q_EMIT virtualPointer->pointerButtonChanged(button, InputRedirection::PointerButtonState::PointerButtonPressed, std::chrono::milliseconds(time), virtualPointer);
1635     Q_EMIT virtualPointer->pointerFrame(virtualPointer);
1636 }
1637 
1638 void pointerButtonReleased(quint32 button, quint32 time)
1639 {
1640     auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
1641     Q_EMIT virtualPointer->pointerButtonChanged(button, InputRedirection::PointerButtonState::PointerButtonReleased, std::chrono::milliseconds(time), virtualPointer);
1642     Q_EMIT virtualPointer->pointerFrame(virtualPointer);
1643 }
1644 
1645 void pointerMotion(const QPointF &position, quint32 time)
1646 {
1647     auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
1648     Q_EMIT virtualPointer->pointerMotionAbsolute(position, std::chrono::milliseconds(time), virtualPointer);
1649     Q_EMIT virtualPointer->pointerFrame(virtualPointer);
1650 }
1651 
1652 void pointerMotionRelative(const QPointF &delta, quint32 time)
1653 {
1654     auto virtualPointer = static_cast<WaylandTestApplication *>(kwinApp())->virtualPointer();
1655     Q_EMIT virtualPointer->pointerMotion(delta, delta, std::chrono::milliseconds(time), virtualPointer);
1656     Q_EMIT virtualPointer->pointerFrame(virtualPointer);
1657 }
1658 
1659 void touchCancel()
1660 {
1661     auto virtualTouch = static_cast<WaylandTestApplication *>(kwinApp())->virtualTouch();
1662     Q_EMIT virtualTouch->touchCanceled(virtualTouch);
1663 }
1664 
1665 void touchDown(qint32 id, const QPointF &pos, quint32 time)
1666 {
1667     auto virtualTouch = static_cast<WaylandTestApplication *>(kwinApp())->virtualTouch();
1668     Q_EMIT virtualTouch->touchDown(id, pos, std::chrono::milliseconds(time), virtualTouch);
1669 }
1670 
1671 void touchMotion(qint32 id, const QPointF &pos, quint32 time)
1672 {
1673     auto virtualTouch = static_cast<WaylandTestApplication *>(kwinApp())->virtualTouch();
1674     Q_EMIT virtualTouch->touchMotion(id, pos, std::chrono::milliseconds(time), virtualTouch);
1675 }
1676 
1677 void touchUp(qint32 id, quint32 time)
1678 {
1679     auto virtualTouch = static_cast<WaylandTestApplication *>(kwinApp())->virtualTouch();
1680     Q_EMIT virtualTouch->touchUp(id, std::chrono::milliseconds(time), virtualTouch);
1681 }
1682 }
1683 }
1684 
1685 #include "test_helpers.moc"