File indexing completed on 2024-05-05 17:36:01

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