File indexing completed on 2024-11-10 04:56:08
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"