diff --git a/autotests/client/test_wayland_registry.cpp b/autotests/client/test_wayland_registry.cpp index d7804b5..d73baf6 100644 --- a/autotests/client/test_wayland_registry.cpp +++ b/autotests/client/test_wayland_registry.cpp @@ -1,850 +1,881 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ // Qt #include // KWin #include "../../src/client/blur.h" #include "../../src/client/contrast.h" #include "../../src/client/compositor.h" #include "../../src/client/connection_thread.h" #include "../../src/client/dpms.h" #include "../../src/client/event_queue.h" #include "../../src/client/registry.h" #include "../../src/client/output.h" #include "../../src/client/pointerconstraints.h" #include "../../src/client/pointergestures.h" +#include "../../src/client/idleinhibit.h" #include "../../src/client/seat.h" #include "../../src/client/relativepointer.h" #include "../../src/client/server_decoration.h" #include "../../src/client/shell.h" #include "../../src/client/surface.h" #include "../../src/client/subcompositor.h" #include "../../src/client/xdgshell.h" #include "../../src/server/compositor_interface.h" #include "../../src/server/datadevicemanager_interface.h" #include "../../src/server/display.h" #include "../../src/server/dpms_interface.h" +#include "../../src/server/idleinhibit_interface.h" #include "../../src/server/output_interface.h" #include "../../src/server/seat_interface.h" #include "../../src/server/shell_interface.h" #include "../../src/server/blur_interface.h" #include "../../src/server/contrast_interface.h" #include "../../src/server/server_decoration_interface.h" #include "../../src/server/slide_interface.h" #include "../../src/server/subcompositor_interface.h" #include "../../src/server/outputmanagement_interface.h" #include "../../src/server/outputdevice_interface.h" #include "../../src/server/pointerconstraints_interface.h" #include "../../src/server/pointergestures_interface.h" #include "../../src/server/textinput_interface.h" #include "../../src/server/xdgshell_interface.h" #include "../../src/server/relativepointer_interface.h" // Wayland #include #include +#include #include #include #include #include #include #include #include class TestWaylandRegistry : public QObject { Q_OBJECT public: explicit TestWaylandRegistry(QObject *parent = nullptr); private Q_SLOTS: void init(); void cleanup(); void testCreate(); void testBindCompositor(); void testBindShell(); void testBindOutput(); void testBindShm(); void testBindSeat(); void testBindSubCompositor(); void testBindDataDeviceManager(); void testBindBlurManager(); void testBindContrastManager(); void testBindSlideManager(); void testBindDpmsManager(); void testBindServerSideDecorationManager(); void testBindTextInputManagerUnstableV0(); void testBindTextInputManagerUnstableV2(); void testBindXdgShellUnstableV5(); void testBindRelativePointerManagerUnstableV1(); void testBindPointerGesturesUnstableV1(); void testBindPointerConstraintsUnstableV1(); + void testBindIdleIhibitManagerUnstableV1(); void testGlobalSync(); void testGlobalSyncThreaded(); void testRemoval(); void testOutOfSyncRemoval(); void testDestroy(); void testAnnounceMultiple(); void testAnnounceMultipleOutputDevices(); private: KWayland::Server::Display *m_display; KWayland::Server::CompositorInterface *m_compositor; KWayland::Server::OutputInterface *m_output; KWayland::Server::OutputDeviceInterface *m_outputDevice; KWayland::Server::SeatInterface *m_seat; KWayland::Server::ShellInterface *m_shell; KWayland::Server::SubCompositorInterface *m_subcompositor; KWayland::Server::DataDeviceManagerInterface *m_dataDeviceManager; KWayland::Server::OutputManagementInterface *m_outputManagement; KWayland::Server::ServerSideDecorationManagerInterface *m_serverSideDecorationManager; KWayland::Server::TextInputManagerInterface *m_textInputManagerV0; KWayland::Server::TextInputManagerInterface *m_textInputManagerV2; KWayland::Server::XdgShellInterface *m_xdgShellUnstableV5; KWayland::Server::RelativePointerManagerInterface *m_relativePointerV1; KWayland::Server::PointerGesturesInterface *m_pointerGesturesV1; KWayland::Server::PointerConstraintsInterface *m_pointerConstraintsV1; KWayland::Server::BlurManagerInterface *m_blur; KWayland::Server::ContrastManagerInterface *m_contrast; + KWayland::Server::IdleInhibitManagerInterface *m_idleInhibit; }; static const QString s_socketName = QStringLiteral("kwin-test-wayland-registry-0"); TestWaylandRegistry::TestWaylandRegistry(QObject *parent) : QObject(parent) , m_display(nullptr) , m_compositor(nullptr) , m_output(nullptr) , m_outputDevice(nullptr) , m_seat(nullptr) , m_shell(nullptr) , m_subcompositor(nullptr) , m_dataDeviceManager(nullptr) , m_outputManagement(nullptr) , m_serverSideDecorationManager(nullptr) , m_textInputManagerV0(nullptr) , m_textInputManagerV2(nullptr) , m_xdgShellUnstableV5(nullptr) , m_relativePointerV1(nullptr) , m_pointerGesturesV1(nullptr) , m_pointerConstraintsV1(nullptr) , m_blur(nullptr) , m_contrast(nullptr) + , m_idleInhibit(nullptr) { } void TestWaylandRegistry::init() { m_display = new KWayland::Server::Display(); m_display->setSocketName(s_socketName); m_display->start(); m_display->createShm(); m_compositor = m_display->createCompositor(); m_compositor->create(); m_output = m_display->createOutput(); m_output->create(); m_seat = m_display->createSeat(); m_seat->create(); m_shell = m_display->createShell(); m_shell->create(); m_subcompositor = m_display->createSubCompositor(); m_subcompositor->create(); m_dataDeviceManager = m_display->createDataDeviceManager(); m_dataDeviceManager->create(); m_outputManagement = m_display->createOutputManagement(); m_outputManagement->create(); m_outputDevice = m_display->createOutputDevice(); m_outputDevice->create(); QVERIFY(m_outputManagement->isValid()); m_blur = m_display->createBlurManager(this); m_blur->create(); m_contrast = m_display->createContrastManager(this); m_contrast->create(); m_display->createSlideManager(this)->create(); m_display->createDpmsManager()->create(); m_serverSideDecorationManager = m_display->createServerSideDecorationManager(); m_serverSideDecorationManager->create(); m_textInputManagerV0 = m_display->createTextInputManager(KWayland::Server::TextInputInterfaceVersion::UnstableV0); QCOMPARE(m_textInputManagerV0->interfaceVersion(), KWayland::Server::TextInputInterfaceVersion::UnstableV0); m_textInputManagerV0->create(); m_textInputManagerV2 = m_display->createTextInputManager(KWayland::Server::TextInputInterfaceVersion::UnstableV2); QCOMPARE(m_textInputManagerV2->interfaceVersion(), KWayland::Server::TextInputInterfaceVersion::UnstableV2); m_textInputManagerV2->create(); m_xdgShellUnstableV5 = m_display->createXdgShell(KWayland::Server::XdgShellInterfaceVersion::UnstableV5); m_xdgShellUnstableV5->create(); QCOMPARE(m_xdgShellUnstableV5->interfaceVersion(), KWayland::Server::XdgShellInterfaceVersion::UnstableV5); m_relativePointerV1 = m_display->createRelativePointerManager(KWayland::Server::RelativePointerInterfaceVersion::UnstableV1); m_relativePointerV1->create(); QCOMPARE(m_relativePointerV1->interfaceVersion(), KWayland::Server::RelativePointerInterfaceVersion::UnstableV1); m_pointerGesturesV1 = m_display->createPointerGestures(KWayland::Server::PointerGesturesInterfaceVersion::UnstableV1); m_pointerGesturesV1->create(); QCOMPARE(m_pointerGesturesV1->interfaceVersion(), KWayland::Server::PointerGesturesInterfaceVersion::UnstableV1); m_pointerConstraintsV1 = m_display->createPointerConstraints(KWayland::Server::PointerConstraintsInterfaceVersion::UnstableV1); m_pointerConstraintsV1->create(); QCOMPARE(m_pointerConstraintsV1->interfaceVersion(), KWayland::Server::PointerConstraintsInterfaceVersion::UnstableV1); + m_idleInhibit = m_display->createIdleInhibitManager(KWayland::Server::IdleInhibitManagerInterfaceVersion::UnstableV1); + m_idleInhibit->create(); + QCOMPARE(m_idleInhibit->interfaceVersion(), KWayland::Server::IdleInhibitManagerInterfaceVersion::UnstableV1); } void TestWaylandRegistry::cleanup() { delete m_display; m_display = nullptr; } void TestWaylandRegistry::testCreate() { KWayland::Client::ConnectionThread connection; QSignalSpy connectedSpy(&connection, SIGNAL(connected())); connection.setSocketName(s_socketName); connection.initConnection(); QVERIFY(connectedSpy.wait()); KWayland::Client::Registry registry; QVERIFY(!registry.isValid()); registry.create(connection.display()); QVERIFY(registry.isValid()); registry.release(); QVERIFY(!registry.isValid()); } #define TEST_BIND(iface, signalName, bindMethod, destroyFunction) \ KWayland::Client::ConnectionThread connection; \ QSignalSpy connectedSpy(&connection, SIGNAL(connected())); \ connection.setSocketName(s_socketName); \ connection.initConnection(); \ QVERIFY(connectedSpy.wait()); \ \ KWayland::Client::Registry registry; \ /* before registry is created, we cannot bind the interface*/ \ QVERIFY(!registry.bindMethod(0, 0)); \ \ QVERIFY(!registry.isValid()); \ registry.create(&connection); \ QVERIFY(registry.isValid()); \ /* created but not yet connected still results in no bind */ \ QVERIFY(!registry.bindMethod(0, 0)); \ /* interface information should be empty */ \ QVERIFY(registry.interfaces(iface).isEmpty()); \ QCOMPARE(registry.interface(iface).name, 0u); \ QCOMPARE(registry.interface(iface).version, 0u); \ \ /* now let's register */ \ QSignalSpy announced(®istry, signalName); \ QVERIFY(announced.isValid()); \ registry.setup(); \ wl_display_flush(connection.display()); \ QVERIFY(announced.wait()); \ const quint32 name = announced.first().first().value(); \ const quint32 version = announced.first().last().value(); \ QCOMPARE(registry.interfaces(iface).count(), 1); \ QCOMPARE(registry.interfaces(iface).first().name, name); \ QCOMPARE(registry.interfaces(iface).first().version, version); \ QCOMPARE(registry.interface(iface).name, name); \ QCOMPARE(registry.interface(iface).version, version); \ \ /* registry should know about the interface now */ \ QVERIFY(registry.hasInterface(iface)); \ QVERIFY(!registry.bindMethod(name+1, version)); \ QVERIFY(registry.bindMethod(name, version+1)); \ auto *c = registry.bindMethod(name, version); \ QVERIFY(c); \ destroyFunction(c); \ void TestWaylandRegistry::testBindCompositor() { TEST_BIND(KWayland::Client::Registry::Interface::Compositor, SIGNAL(compositorAnnounced(quint32,quint32)), bindCompositor, wl_compositor_destroy) } void TestWaylandRegistry::testBindShell() { TEST_BIND(KWayland::Client::Registry::Interface::Shell, SIGNAL(shellAnnounced(quint32,quint32)), bindShell, free) } void TestWaylandRegistry::testBindOutput() { TEST_BIND(KWayland::Client::Registry::Interface::Output, SIGNAL(outputAnnounced(quint32,quint32)), bindOutput, wl_output_destroy) } void TestWaylandRegistry::testBindSeat() { TEST_BIND(KWayland::Client::Registry::Interface::Seat, SIGNAL(seatAnnounced(quint32,quint32)), bindSeat, wl_seat_destroy) } void TestWaylandRegistry::testBindShm() { TEST_BIND(KWayland::Client::Registry::Interface::Shm, SIGNAL(shmAnnounced(quint32,quint32)), bindShm, wl_shm_destroy) } void TestWaylandRegistry::testBindSubCompositor() { TEST_BIND(KWayland::Client::Registry::Interface::SubCompositor, SIGNAL(subCompositorAnnounced(quint32,quint32)), bindSubCompositor, wl_subcompositor_destroy) } void TestWaylandRegistry::testBindDataDeviceManager() { TEST_BIND(KWayland::Client::Registry::Interface::DataDeviceManager, SIGNAL(dataDeviceManagerAnnounced(quint32,quint32)), bindDataDeviceManager, wl_data_device_manager_destroy) } void TestWaylandRegistry::testBindBlurManager() { TEST_BIND(KWayland::Client::Registry::Interface::Blur, SIGNAL(blurAnnounced(quint32,quint32)), bindBlurManager, free) } void TestWaylandRegistry::testBindContrastManager() { TEST_BIND(KWayland::Client::Registry::Interface::Contrast, SIGNAL(contrastAnnounced(quint32,quint32)), bindContrastManager, free) } void TestWaylandRegistry::testBindSlideManager() { TEST_BIND(KWayland::Client::Registry::Interface::Slide, SIGNAL(slideAnnounced(quint32,quint32)), bindSlideManager, free) } void TestWaylandRegistry::testBindDpmsManager() { TEST_BIND(KWayland::Client::Registry::Interface::Dpms, SIGNAL(dpmsAnnounced(quint32,quint32)), bindDpmsManager, org_kde_kwin_dpms_manager_destroy) } void TestWaylandRegistry::testBindServerSideDecorationManager() { TEST_BIND(KWayland::Client::Registry::Interface::ServerSideDecorationManager, SIGNAL(serverSideDecorationManagerAnnounced(quint32,quint32)), bindServerSideDecorationManager, org_kde_kwin_server_decoration_manager_destroy) } void TestWaylandRegistry::testBindTextInputManagerUnstableV0() { TEST_BIND(KWayland::Client::Registry::Interface::TextInputManagerUnstableV0, SIGNAL(textInputManagerUnstableV0Announced(quint32,quint32)), bindTextInputManagerUnstableV0, wl_text_input_manager_destroy) } void TestWaylandRegistry::testBindTextInputManagerUnstableV2() { TEST_BIND(KWayland::Client::Registry::Interface::TextInputManagerUnstableV2, SIGNAL(textInputManagerUnstableV2Announced(quint32,quint32)), bindTextInputManagerUnstableV2, zwp_text_input_manager_v2_destroy) } void TestWaylandRegistry::testBindXdgShellUnstableV5() { TEST_BIND(KWayland::Client::Registry::Interface::XdgShellUnstableV5, SIGNAL(xdgShellUnstableV5Announced(quint32,quint32)), bindXdgShellUnstableV5, xdg_shell_destroy) } void TestWaylandRegistry::testBindRelativePointerManagerUnstableV1() { TEST_BIND(KWayland::Client::Registry::Interface::RelativePointerManagerUnstableV1, SIGNAL(relativePointerManagerUnstableV1Announced(quint32,quint32)), bindRelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1_destroy) } void TestWaylandRegistry::testBindPointerGesturesUnstableV1() { TEST_BIND(KWayland::Client::Registry::Interface::PointerGesturesUnstableV1, SIGNAL(pointerGesturesUnstableV1Announced(quint32,quint32)), bindPointerGesturesUnstableV1, zwp_pointer_gestures_v1_destroy) } void TestWaylandRegistry::testBindPointerConstraintsUnstableV1() { TEST_BIND(KWayland::Client::Registry::Interface::PointerConstraintsUnstableV1, SIGNAL(pointerConstraintsUnstableV1Announced(quint32,quint32)), bindPointerConstraintsUnstableV1, zwp_pointer_constraints_v1_destroy) } +void TestWaylandRegistry::testBindIdleIhibitManagerUnstableV1() +{ + TEST_BIND(KWayland::Client::Registry::Interface::IdleInhibitManagerUnstableV1, SIGNAL(idleInhibitManagerUnstableV1Announced(quint32,quint32)), bindIdleInhibitManagerUnstableV1, zwp_idle_inhibit_manager_v1_destroy) +} + #undef TEST_BIND void TestWaylandRegistry::testRemoval() { using namespace KWayland::Client; KWayland::Client::ConnectionThread connection; QSignalSpy connectedSpy(&connection, SIGNAL(connected())); connection.setSocketName(s_socketName); connection.initConnection(); QVERIFY(connectedSpy.wait()); connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, &connection, [&connection] { wl_display_flush(connection.display()); } ); KWayland::Client::Registry registry; QSignalSpy shmAnnouncedSpy(®istry, SIGNAL(shmAnnounced(quint32,quint32))); QVERIFY(shmAnnouncedSpy.isValid()); QSignalSpy compositorAnnouncedSpy(®istry, SIGNAL(compositorAnnounced(quint32,quint32))); QVERIFY(compositorAnnouncedSpy.isValid()); QSignalSpy outputAnnouncedSpy(®istry, SIGNAL(outputAnnounced(quint32,quint32))); QVERIFY(outputAnnouncedSpy.isValid()); QSignalSpy outputDeviceAnnouncedSpy(®istry, SIGNAL(outputDeviceAnnounced(quint32,quint32))); QVERIFY(outputDeviceAnnouncedSpy.isValid()); QSignalSpy shellAnnouncedSpy(®istry, SIGNAL(shellAnnounced(quint32,quint32))); QVERIFY(shellAnnouncedSpy.isValid()); QSignalSpy seatAnnouncedSpy(®istry, SIGNAL(seatAnnounced(quint32,quint32))); QVERIFY(seatAnnouncedSpy.isValid()); QSignalSpy subCompositorAnnouncedSpy(®istry, SIGNAL(subCompositorAnnounced(quint32,quint32))); QVERIFY(subCompositorAnnouncedSpy.isValid()); QSignalSpy outputManagementAnnouncedSpy(®istry, SIGNAL(outputManagementAnnounced(quint32,quint32))); QVERIFY(outputManagementAnnouncedSpy.isValid()); QSignalSpy serverSideDecorationManagerAnnouncedSpy(®istry, &Registry::serverSideDecorationManagerAnnounced); QVERIFY(serverSideDecorationManagerAnnouncedSpy.isValid()); QSignalSpy blurAnnouncedSpy(®istry, &Registry::blurAnnounced); QVERIFY(blurAnnouncedSpy.isValid()); + QSignalSpy idleInhibitManagerUnstableV1AnnouncedSpy(®istry, &Registry::idleInhibitManagerUnstableV1Announced); + QVERIFY(idleInhibitManagerUnstableV1AnnouncedSpy.isValid()); QVERIFY(!registry.isValid()); registry.create(connection.display()); registry.setup(); QVERIFY(shmAnnouncedSpy.wait()); QVERIFY(!compositorAnnouncedSpy.isEmpty()); QVERIFY(!outputAnnouncedSpy.isEmpty()); QVERIFY(!outputDeviceAnnouncedSpy.isEmpty()); QVERIFY(!shellAnnouncedSpy.isEmpty()); QVERIFY(!seatAnnouncedSpy.isEmpty()); QVERIFY(!subCompositorAnnouncedSpy.isEmpty()); QVERIFY(!outputManagementAnnouncedSpy.isEmpty()); QVERIFY(!serverSideDecorationManagerAnnouncedSpy.isEmpty()); QVERIFY(!blurAnnouncedSpy.isEmpty()); + QVERIFY(!idleInhibitManagerUnstableV1AnnouncedSpy.isEmpty()); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Compositor)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Output)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::OutputDevice)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Seat)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Shell)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Shm)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::SubCompositor)); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::FullscreenShell)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::OutputManagement)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::ServerSideDecorationManager)); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Blur)); + QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::IdleInhibitManagerUnstableV1)); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Compositor).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Output).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::OutputDevice).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Seat).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Shell).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Shm).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::SubCompositor).isEmpty()); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::FullscreenShell).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::OutputManagement).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::ServerSideDecorationManager).isEmpty()); QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::Blur).isEmpty()); + QVERIFY(!registry.interfaces(KWayland::Client::Registry::Interface::IdleInhibitManagerUnstableV1).isEmpty()); QSignalSpy seatRemovedSpy(®istry, SIGNAL(seatRemoved(quint32))); QVERIFY(seatRemovedSpy.isValid()); Seat *seat = registry.createSeat(registry.interface(Registry::Interface::Seat).name, registry.interface(Registry::Interface::Seat).version, ®istry); Shell *shell = registry.createShell(registry.interface(Registry::Interface::Shell).name, registry.interface(Registry::Interface::Shell).version, ®istry); Output *output = registry.createOutput(registry.interface(Registry::Interface::Output).name, registry.interface(Registry::Interface::Output).version, ®istry); Compositor *compositor = registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, registry.interface(Registry::Interface::Compositor).version, ®istry); SubCompositor *subcompositor = registry.createSubCompositor(registry.interface(Registry::Interface::SubCompositor).name, registry.interface(Registry::Interface::SubCompositor).version, ®istry); ServerSideDecorationManager *serverSideDeco = registry.createServerSideDecorationManager(registry.interface(Registry::Interface::ServerSideDecorationManager).name, registry.interface(Registry::Interface::ServerSideDecorationManager).version, ®istry); BlurManager *blurManager = registry.createBlurManager(registry.interface(Registry::Interface::Blur).name, registry.interface(Registry::Interface::Blur).version, ®istry); + auto idleInhibitManager = registry.createIdleInhibitManager(registry.interface(Registry::Interface::IdleInhibitManagerUnstableV1).name, registry.interface(Registry::Interface::IdleInhibitManagerUnstableV1).version, ®istry); connection.flush(); m_display->dispatchEvents(); QSignalSpy seatObjectRemovedSpy(seat, &Seat::removed); QVERIFY(seatObjectRemovedSpy.isValid()); QSignalSpy shellObjectRemovedSpy(shell, &Shell::removed); QVERIFY(shellObjectRemovedSpy.isValid()); QSignalSpy outputObjectRemovedSpy(output, &Output::removed); QVERIFY(outputObjectRemovedSpy.isValid()); QSignalSpy compositorObjectRemovedSpy(compositor, &Compositor::removed); QVERIFY(compositorObjectRemovedSpy.isValid()); QSignalSpy subcompositorObjectRemovedSpy(subcompositor, &SubCompositor::removed); QVERIFY(subcompositorObjectRemovedSpy.isValid()); + QSignalSpy idleInhibitManagerObjectRemovedSpy(idleInhibitManager, &IdleInhibitManager::removed); + QVERIFY(idleInhibitManagerObjectRemovedSpy.isValid()); delete m_seat; QVERIFY(seatRemovedSpy.wait()); QCOMPARE(seatRemovedSpy.first().first(), seatAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::Seat)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::Seat).isEmpty()); QCOMPARE(seatObjectRemovedSpy.count(), 1); QSignalSpy shellRemovedSpy(®istry, SIGNAL(shellRemoved(quint32))); QVERIFY(shellRemovedSpy.isValid()); delete m_shell; QVERIFY(shellRemovedSpy.wait()); QCOMPARE(shellRemovedSpy.first().first(), shellAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::Shell)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::Shell).isEmpty()); QCOMPARE(shellObjectRemovedSpy.count(), 1); QSignalSpy outputRemovedSpy(®istry, SIGNAL(outputRemoved(quint32))); QVERIFY(outputRemovedSpy.isValid()); delete m_output; QVERIFY(outputRemovedSpy.wait()); QCOMPARE(outputRemovedSpy.first().first(), outputAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::Output)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::Output).isEmpty()); QCOMPARE(outputObjectRemovedSpy.count(), 1); QSignalSpy outputDeviceRemovedSpy(®istry, SIGNAL(outputDeviceRemoved(quint32))); QVERIFY(outputDeviceRemovedSpy.isValid()); delete m_outputDevice; QVERIFY(outputDeviceRemovedSpy.wait()); QCOMPARE(outputDeviceRemovedSpy.first().first(), outputDeviceAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::OutputDevice)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::OutputDevice).isEmpty()); QSignalSpy compositorRemovedSpy(®istry, SIGNAL(compositorRemoved(quint32))); QVERIFY(compositorRemovedSpy.isValid()); delete m_compositor; QVERIFY(compositorRemovedSpy.wait()); QCOMPARE(compositorRemovedSpy.first().first(), compositorAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::Compositor)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::Compositor).isEmpty()); QCOMPARE(compositorObjectRemovedSpy.count(), 1); QSignalSpy subCompositorRemovedSpy(®istry, SIGNAL(subCompositorRemoved(quint32))); QVERIFY(subCompositorRemovedSpy.isValid()); delete m_subcompositor; QVERIFY(subCompositorRemovedSpy.wait()); QCOMPARE(subCompositorRemovedSpy.first().first(), subCompositorAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::SubCompositor)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::SubCompositor).isEmpty()); QCOMPARE(subcompositorObjectRemovedSpy.count(), 1); QSignalSpy outputManagementRemovedSpy(®istry, SIGNAL(outputManagementRemoved(quint32))); QVERIFY(outputManagementRemovedSpy.isValid()); delete m_outputManagement; QVERIFY(outputManagementRemovedSpy.wait()); QCOMPARE(outputManagementRemovedSpy.first().first(), outputManagementAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::OutputManagement)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::OutputManagement).isEmpty()); QSignalSpy serverSideDecoManagerRemovedSpy(®istry, &Registry::serverSideDecorationManagerRemoved); QVERIFY(serverSideDecoManagerRemovedSpy.isValid()); QSignalSpy serverSideDecoManagerObjectRemovedSpy(serverSideDeco, &ServerSideDecorationManager::removed); QVERIFY(serverSideDecoManagerObjectRemovedSpy.isValid()); delete m_serverSideDecorationManager; QVERIFY(serverSideDecoManagerRemovedSpy.wait()); QCOMPARE(serverSideDecoManagerRemovedSpy.first().first(), serverSideDecorationManagerAnnouncedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::ServerSideDecorationManager)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::ServerSideDecorationManager).isEmpty()); QCOMPARE(serverSideDecoManagerObjectRemovedSpy.count(), 1); QSignalSpy blurRemovedSpy(®istry, &Registry::blurRemoved); QVERIFY(blurRemovedSpy.isValid()); QSignalSpy blurObjectRemovedSpy(blurManager, &BlurManager::removed); QVERIFY(blurObjectRemovedSpy.isValid()); delete m_blur; QVERIFY(blurRemovedSpy.wait()); QCOMPARE(blurRemovedSpy.first().first(), blurRemovedSpy.first().first()); QVERIFY(!registry.hasInterface(KWayland::Client::Registry::Interface::Blur)); QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::Blur).isEmpty()); QCOMPARE(blurObjectRemovedSpy.count(), 1); + QSignalSpy idleInhibitManagerUnstableV1RemovedSpy(®istry, &Registry::idleInhibitManagerUnstableV1Removed); + QVERIFY(idleInhibitManagerUnstableV1RemovedSpy.isValid()); + delete m_idleInhibit; + QVERIFY(idleInhibitManagerUnstableV1RemovedSpy.wait()); + QCOMPARE(idleInhibitManagerUnstableV1RemovedSpy.first().first(), idleInhibitManagerUnstableV1AnnouncedSpy.first().first()); + QVERIFY(registry.interfaces(KWayland::Client::Registry::Interface::IdleInhibitManagerUnstableV1).isEmpty()); + QCOMPARE(idleInhibitManagerObjectRemovedSpy.count(), 1); + // cannot test shmRemoved as there is no functionality for it // verify everything has been removed only once QCOMPARE(seatObjectRemovedSpy.count(), 1); QCOMPARE(shellObjectRemovedSpy.count(), 1); QCOMPARE(outputObjectRemovedSpy.count(), 1); QCOMPARE(compositorObjectRemovedSpy.count(), 1); QCOMPARE(subcompositorObjectRemovedSpy.count(), 1); QCOMPARE(serverSideDecoManagerObjectRemovedSpy.count(), 1); QCOMPARE(blurObjectRemovedSpy.count(), 1); + QCOMPARE(idleInhibitManagerObjectRemovedSpy.count(), 1); } void TestWaylandRegistry::testOutOfSyncRemoval() { //This tests the following sequence of events //server announces global //client binds to that global //server removes the global //(simultaneously) the client legimitely uses the bound resource to the global //client then gets the server events...it should no-op, not be a protcol error using namespace KWayland::Client; KWayland::Client::ConnectionThread connection; QSignalSpy connectedSpy(&connection, SIGNAL(connected())); connection.setSocketName(s_socketName); connection.initConnection(); QVERIFY(connectedSpy.wait()); connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, &connection, [&connection] { wl_display_flush(connection.display()); } ); KWayland::Client::Registry registry; QVERIFY(!registry.isValid()); registry.create(connection.display()); registry.setup(); QSignalSpy blurAnnouncedSpy(®istry, &Registry::blurAnnounced); QSignalSpy contrastAnnouncedSpy(®istry, &Registry::blurAnnounced); blurAnnouncedSpy.wait(); contrastAnnouncedSpy.wait(); BlurManager *blurManager = registry.createBlurManager(registry.interface(Registry::Interface::Blur).name, registry.interface(Registry::Interface::Blur).version, ®istry); ContrastManager *contrastManager = registry.createContrastManager(registry.interface(Registry::Interface::Contrast).name, registry.interface(Registry::Interface::Contrast).version, ®istry); connection.flush(); m_display->dispatchEvents(); QScopedPointer compositor(registry.createCompositor(registry.interface(Registry::Interface::Compositor).name, registry.interface(Registry::Interface::Compositor).version)); QScopedPointer surface(compositor->createSurface()); QVERIFY(surface); //remove blur QSignalSpy blurRemovedSpy(®istry, &Registry::blurRemoved); delete m_blur; //client hasn't processed the event yet QVERIFY(blurRemovedSpy.count() == 0); //use the in the client blurManager->createBlur(surface.data(), 0); //now process events, QVERIFY(blurRemovedSpy.wait()); QVERIFY(blurRemovedSpy.count() == 1); //remove background contrast QSignalSpy contrastRemovedSpy(®istry, &Registry::contrastRemoved); delete m_contrast; //client hasn't processed the event yet QVERIFY(contrastRemovedSpy.count() == 0); //use the in the client contrastManager->createContrast(surface.data(), 0); //now process events, QVERIFY(contrastRemovedSpy.wait()); QVERIFY(contrastRemovedSpy.count() == 1); } void TestWaylandRegistry::testDestroy() { using namespace KWayland::Client; KWayland::Client::ConnectionThread connection; QSignalSpy connectedSpy(&connection, SIGNAL(connected())); connection.setSocketName(s_socketName); connection.initConnection(); QVERIFY(connectedSpy.wait()); Registry registry; QSignalSpy shellAnnouncedSpy(®istry, SIGNAL(shellAnnounced(quint32,quint32))); QVERIFY(!registry.isValid()); registry.create(&connection); registry.setup(); QVERIFY(registry.isValid()); //create some arbitrary Interface shellAnnouncedSpy.wait(); QScopedPointer shell(registry.createShell(registry.interface(Registry::Interface::Shell).name, registry.interface(Registry::Interface::Shell).version, ®istry)); QSignalSpy connectionDiedSpy(&connection, SIGNAL(connectionDied())); QSignalSpy registryDiedSpy(®istry, SIGNAL(registryDestroyed())); QVERIFY(connectionDiedSpy.isValid()); QVERIFY(registryDiedSpy.isValid()); delete m_display; m_display = nullptr; QVERIFY(connectionDiedSpy.wait()); QVERIFY(connectionDiedSpy.count() == 1); QVERIFY(registryDiedSpy.count() == 1); // now the registry should be destroyed; QVERIFY(!registry.isValid()); // calling destroy again should not fail registry.destroy(); shell->destroy(); } void TestWaylandRegistry::testGlobalSync() { using namespace KWayland::Client; ConnectionThread connection; connection.setSocketName(s_socketName); QSignalSpy connectedSpy(&connection, SIGNAL(connected())); connection.initConnection(); QVERIFY(connectedSpy.wait()); Registry registry; QSignalSpy syncSpy(®istry, SIGNAL(interfacesAnnounced())); // Most simple case: don't even use the ConnectionThread, // just its display. registry.create(connection.display()); registry.setup(); QVERIFY(syncSpy.wait()); QCOMPARE(syncSpy.count(), 1); registry.destroy(); } void TestWaylandRegistry::testGlobalSyncThreaded() { // More complex case, use a ConnectionThread, in a different Thread, // and our own EventQueue using namespace KWayland::Client; ConnectionThread connection; connection.setSocketName(s_socketName); QThread thread; connection.moveToThread(&thread); thread.start(); QSignalSpy connectedSpy(&connection, SIGNAL(connected())); connection.initConnection(); QVERIFY(connectedSpy.wait()); EventQueue queue; queue.setup(&connection); Registry registry; QSignalSpy syncSpy(®istry, SIGNAL(interfacesAnnounced())); registry.setEventQueue(&queue); registry.create(&connection); registry.setup(); QVERIFY(syncSpy.wait()); QCOMPARE(syncSpy.count(), 1); registry.destroy(); thread.quit(); thread.wait(); } void TestWaylandRegistry::testAnnounceMultiple() { using namespace KWayland::Client; ConnectionThread connection; connection.setSocketName(s_socketName); QSignalSpy connectedSpy(&connection, &ConnectionThread::connected); QVERIFY(connectedSpy.isValid()); connection.initConnection(); QVERIFY(connectedSpy.wait()); connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, &connection, [&connection] { wl_display_flush(connection.display()); } ); Registry registry; QSignalSpy syncSpy(®istry, &Registry::interfacesAnnounced); QVERIFY(syncSpy.isValid()); // Most simple case: don't even use the ConnectionThread, // just its display. registry.create(connection.display()); registry.setup(); QVERIFY(syncSpy.wait()); QCOMPARE(syncSpy.count(), 1); // we should have one output now QCOMPARE(registry.interfaces(Registry::Interface::Output).count(), 1); QSignalSpy outputAnnouncedSpy(®istry, &Registry::outputAnnounced); QVERIFY(outputAnnouncedSpy.isValid()); m_display->createOutput()->create(); QVERIFY(outputAnnouncedSpy.wait()); QCOMPARE(registry.interfaces(Registry::Interface::Output).count(), 2); QCOMPARE(registry.interfaces(Registry::Interface::Output).last().name, outputAnnouncedSpy.first().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::Output).last().version, outputAnnouncedSpy.first().last().value()); QCOMPARE(registry.interface(Registry::Interface::Output).name, outputAnnouncedSpy.first().first().value()); QCOMPARE(registry.interface(Registry::Interface::Output).version, outputAnnouncedSpy.first().last().value()); auto output = m_display->createOutput(); output->create(); QVERIFY(outputAnnouncedSpy.wait()); QCOMPARE(registry.interfaces(Registry::Interface::Output).count(), 3); QCOMPARE(registry.interfaces(Registry::Interface::Output).last().name, outputAnnouncedSpy.last().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::Output).last().version, outputAnnouncedSpy.last().last().value()); QCOMPARE(registry.interface(Registry::Interface::Output).name, outputAnnouncedSpy.last().first().value()); QCOMPARE(registry.interface(Registry::Interface::Output).version, outputAnnouncedSpy.last().last().value()); QSignalSpy outputRemovedSpy(®istry, &Registry::outputRemoved); QVERIFY(outputRemovedSpy.isValid()); delete output; QVERIFY(outputRemovedSpy.wait()); QCOMPARE(outputRemovedSpy.first().first().value(), outputAnnouncedSpy.last().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::Output).count(), 2); QCOMPARE(registry.interfaces(Registry::Interface::Output).last().name, outputAnnouncedSpy.first().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::Output).last().version, outputAnnouncedSpy.first().last().value()); QCOMPARE(registry.interface(Registry::Interface::Output).name, outputAnnouncedSpy.first().first().value()); QCOMPARE(registry.interface(Registry::Interface::Output).version, outputAnnouncedSpy.first().last().value()); } void TestWaylandRegistry::testAnnounceMultipleOutputDevices() { using namespace KWayland::Client; ConnectionThread connection; connection.setSocketName(s_socketName); QSignalSpy connectedSpy(&connection, &ConnectionThread::connected); QVERIFY(connectedSpy.isValid()); connection.initConnection(); QVERIFY(connectedSpy.wait()); connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, &connection, [&connection] { wl_display_flush(connection.display()); } ); Registry registry; QSignalSpy syncSpy(®istry, &Registry::interfacesAnnounced); QVERIFY(syncSpy.isValid()); // Most simple case: don't even use the ConnectionThread, // just its display. registry.create(connection.display()); registry.setup(); QVERIFY(syncSpy.wait()); QCOMPARE(syncSpy.count(), 1); // we should have one output now QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).count(), 1); QSignalSpy outputDeviceAnnouncedSpy(®istry, &Registry::outputDeviceAnnounced); QVERIFY(outputDeviceAnnouncedSpy.isValid()); m_display->createOutputDevice()->create(); QVERIFY(outputDeviceAnnouncedSpy.wait()); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).count(), 2); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).last().name, outputDeviceAnnouncedSpy.first().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).last().version, outputDeviceAnnouncedSpy.first().last().value()); QCOMPARE(registry.interface(Registry::Interface::OutputDevice).name, outputDeviceAnnouncedSpy.first().first().value()); QCOMPARE(registry.interface(Registry::Interface::OutputDevice).version, outputDeviceAnnouncedSpy.first().last().value()); auto outputDevice = m_display->createOutputDevice(); outputDevice->create(); QVERIFY(outputDeviceAnnouncedSpy.wait()); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).count(), 3); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).last().name, outputDeviceAnnouncedSpy.last().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).last().version, outputDeviceAnnouncedSpy.last().last().value()); QCOMPARE(registry.interface(Registry::Interface::OutputDevice).name, outputDeviceAnnouncedSpy.last().first().value()); QCOMPARE(registry.interface(Registry::Interface::OutputDevice).version, outputDeviceAnnouncedSpy.last().last().value()); QSignalSpy outputDeviceRemovedSpy(®istry, &Registry::outputDeviceRemoved); QVERIFY(outputDeviceRemovedSpy.isValid()); delete outputDevice; QVERIFY(outputDeviceRemovedSpy.wait()); QCOMPARE(outputDeviceRemovedSpy.first().first().value(), outputDeviceAnnouncedSpy.last().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).count(), 2); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).last().name, outputDeviceAnnouncedSpy.first().first().value()); QCOMPARE(registry.interfaces(Registry::Interface::OutputDevice).last().version, outputDeviceAnnouncedSpy.first().last().value()); QCOMPARE(registry.interface(Registry::Interface::OutputDevice).name, outputDeviceAnnouncedSpy.first().first().value()); QCOMPARE(registry.interface(Registry::Interface::OutputDevice).version, outputDeviceAnnouncedSpy.first().last().value()); } QTEST_GUILESS_MAIN(TestWaylandRegistry) #include "test_wayland_registry.moc" diff --git a/autotests/client/test_wayland_surface.cpp b/autotests/client/test_wayland_surface.cpp index db24b64..9cd99bd 100644 --- a/autotests/client/test_wayland_surface.cpp +++ b/autotests/client/test_wayland_surface.cpp @@ -1,1095 +1,1158 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ // Qt #include #include #include // KWin #include "../../src/client/compositor.h" #include "../../src/client/connection_thread.h" #include "../../src/client/event_queue.h" +#include "../../src/client/idleinhibit.h" #include "../../src/client/output.h" #include "../../src/client/surface.h" #include "../../src/client/region.h" #include "../../src/client/registry.h" #include "../../src/client/shm_pool.h" #include "../../src/server/buffer_interface.h" #include "../../src/server/compositor_interface.h" #include "../../src/server/display.h" +#include "../../src/server/idleinhibit_interface.h" #include "../../src/server/surface_interface.h" // Wayland #include +using KWayland::Client::Registry; + class TestWaylandSurface : public QObject { Q_OBJECT public: explicit TestWaylandSurface(QObject *parent = nullptr); private Q_SLOTS: void init(); void cleanup(); void testStaticAccessor(); void testDamage(); void testFrameCallback(); void testAttachBuffer(); void testMultipleSurfaces(); void testOpaque(); void testInput(); void testScale(); void testDestroy(); void testUnmapOfNotMappedSurface(); void testDamageTracking(); void testSurfaceAt(); void testDestroyAttachedBuffer(); void testDestroyWithPendingCallback(); void testOutput(); void testDisconnect(); + void testInhibit(); private: KWayland::Server::Display *m_display; KWayland::Server::CompositorInterface *m_compositorInterface; + KWayland::Server::IdleInhibitManagerInterface *m_idleInhibitInterface = nullptr; KWayland::Client::ConnectionThread *m_connection; KWayland::Client::Compositor *m_compositor; KWayland::Client::ShmPool *m_shm; KWayland::Client::EventQueue *m_queue; + KWayland::Client::IdleInhibitManager *m_idleInhibitManager = nullptr; QThread *m_thread; }; static const QString s_socketName = QStringLiteral("kwin-test-wayland-surface-0"); TestWaylandSurface::TestWaylandSurface(QObject *parent) : QObject(parent) , m_display(nullptr) , m_compositorInterface(nullptr) , m_connection(nullptr) , m_compositor(nullptr) , m_thread(nullptr) { } void TestWaylandSurface::init() { using namespace KWayland::Server; delete m_display; m_display = new Display(this); m_display->setSocketName(s_socketName); m_display->start(); QVERIFY(m_display->isRunning()); m_display->createShm(); m_compositorInterface = m_display->createCompositor(m_display); QVERIFY(m_compositorInterface); m_compositorInterface->create(); QVERIFY(m_compositorInterface->isValid()); + m_idleInhibitInterface = m_display->createIdleInhibitManager(IdleInhibitManagerInterfaceVersion::UnstableV1, m_display); + QVERIFY(m_idleInhibitInterface); + m_idleInhibitInterface->create(); + QVERIFY(m_idleInhibitInterface->isValid()); + // setup connection m_connection = new KWayland::Client::ConnectionThread; QSignalSpy connectedSpy(m_connection, SIGNAL(connected())); m_connection->setSocketName(s_socketName); m_thread = new QThread(this); m_connection->moveToThread(m_thread); m_thread->start(); /*connect(QCoreApplication::eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, m_connection, [this]() { if (m_connection->display()) { wl_display_flush(m_connection->display()); } } );*/ m_connection->initConnection(); QVERIFY(connectedSpy.wait()); m_queue = new KWayland::Client::EventQueue(this); QVERIFY(!m_queue->isValid()); m_queue->setup(m_connection); QVERIFY(m_queue->isValid()); KWayland::Client::Registry registry; registry.setEventQueue(m_queue); QSignalSpy compositorSpy(®istry, SIGNAL(compositorAnnounced(quint32,quint32))); QSignalSpy shmSpy(®istry, SIGNAL(shmAnnounced(quint32,quint32))); QSignalSpy allAnnounced(®istry, SIGNAL(interfacesAnnounced())); QVERIFY(allAnnounced.isValid()); QVERIFY(shmSpy.isValid()); registry.create(m_connection->display()); QVERIFY(registry.isValid()); registry.setup(); QVERIFY(allAnnounced.wait()); QVERIFY(!compositorSpy.isEmpty()); QVERIFY(!shmSpy.isEmpty()); m_compositor = registry.createCompositor(compositorSpy.first().first().value(), compositorSpy.first().last().value(), this); QVERIFY(m_compositor->isValid()); m_shm = registry.createShmPool(shmSpy.first().first().value(), shmSpy.first().last().value(), this); QVERIFY(m_shm->isValid()); + + m_idleInhibitManager = registry.createIdleInhibitManager(registry.interface(Registry::Interface::IdleInhibitManagerUnstableV1).name, registry.interface(Registry::Interface::IdleInhibitManagerUnstableV1).version, this); + QVERIFY(m_idleInhibitManager->isValid()); } void TestWaylandSurface::cleanup() { if (m_compositor) { delete m_compositor; m_compositor = nullptr; } if (m_shm) { delete m_shm; m_shm = nullptr; } if (m_queue) { delete m_queue; m_queue = nullptr; } if (m_thread) { m_thread->quit(); m_thread->wait(); delete m_thread; m_thread = nullptr; } delete m_connection; m_connection = nullptr; delete m_compositorInterface; m_compositorInterface = nullptr; delete m_display; m_display = nullptr; } void TestWaylandSurface::testStaticAccessor() { QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); QVERIFY(!KWayland::Server::SurfaceInterface::get(nullptr)); QVERIFY(!KWayland::Server::SurfaceInterface::get(1, nullptr)); QVERIFY(KWayland::Client::Surface::all().isEmpty()); KWayland::Client::Surface *s1 = m_compositor->createSurface(); QVERIFY(s1->isValid()); QCOMPARE(KWayland::Client::Surface::all().count(), 1); QCOMPARE(KWayland::Client::Surface::all().first(), s1); QCOMPARE(KWayland::Client::Surface::get(*s1), s1); QVERIFY(serverSurfaceCreated.wait()); auto serverSurface1 = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface1); QCOMPARE(KWayland::Server::SurfaceInterface::get(serverSurface1->resource()), serverSurface1); QCOMPARE(KWayland::Server::SurfaceInterface::get(serverSurface1->id(), serverSurface1->client()), serverSurface1); QVERIFY(!s1->size().isValid()); QSignalSpy sizeChangedSpy(s1, SIGNAL(sizeChanged(QSize))); QVERIFY(sizeChangedSpy.isValid()); const QSize testSize(200, 300); s1->setSize(testSize); QCOMPARE(s1->size(), testSize); QCOMPARE(sizeChangedSpy.count(), 1); QCOMPARE(sizeChangedSpy.first().first().toSize(), testSize); // add another surface KWayland::Client::Surface *s2 = m_compositor->createSurface(); QVERIFY(s2->isValid()); QCOMPARE(KWayland::Client::Surface::all().count(), 2); QCOMPARE(KWayland::Client::Surface::all().first(), s1); QCOMPARE(KWayland::Client::Surface::all().last(), s2); QCOMPARE(KWayland::Client::Surface::get(*s1), s1); QCOMPARE(KWayland::Client::Surface::get(*s2), s2); serverSurfaceCreated.clear(); QVERIFY(serverSurfaceCreated.wait()); auto serverSurface2 = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface2); QCOMPARE(KWayland::Server::SurfaceInterface::get(serverSurface1->resource()), serverSurface1); QCOMPARE(KWayland::Server::SurfaceInterface::get(serverSurface1->id(), serverSurface1->client()), serverSurface1); QCOMPARE(KWayland::Server::SurfaceInterface::get(serverSurface2->resource()), serverSurface2); QCOMPARE(KWayland::Server::SurfaceInterface::get(serverSurface2->id(), serverSurface2->client()), serverSurface2); // delete s2 again delete s2; QCOMPARE(KWayland::Client::Surface::all().count(), 1); QCOMPARE(KWayland::Client::Surface::all().first(), s1); QCOMPARE(KWayland::Client::Surface::get(*s1), s1); // and finally delete the last one delete s1; QVERIFY(KWayland::Client::Surface::all().isEmpty()); QVERIFY(!KWayland::Client::Surface::get(nullptr)); QSignalSpy unboundSpy(serverSurface1, &KWayland::Server::Resource::unbound); QVERIFY(unboundSpy.isValid()); QVERIFY(unboundSpy.wait()); QVERIFY(!KWayland::Server::SurfaceInterface::get(nullptr)); QVERIFY(!KWayland::Server::SurfaceInterface::get(1, nullptr)); } void TestWaylandSurface::testDamage() { QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); KWayland::Client::Surface *s = m_compositor->createSurface(); QVERIFY(serverSurfaceCreated.wait()); KWayland::Server::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface); QCOMPARE(serverSurface->damage(), QRegion()); QVERIFY(serverSurface->parentResource()); QVERIFY(!serverSurface->isMapped()); QSignalSpy damageSpy(serverSurface, SIGNAL(damaged(QRegion))); QVERIFY(damageSpy.isValid()); // send damage without a buffer s->damage(QRect(0, 0, 100, 100)); s->commit(KWayland::Client::Surface::CommitFlag::None); wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); QCoreApplication::processEvents(); QVERIFY(damageSpy.isEmpty()); QVERIFY(!serverSurface->isMapped()); QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied); img.fill(Qt::black); auto b = m_shm->createBuffer(img); s->attachBuffer(b); s->damage(QRect(0, 0, 10, 10)); s->commit(KWayland::Client::Surface::CommitFlag::None); QVERIFY(damageSpy.wait()); QCOMPARE(serverSurface->damage(), QRegion(0, 0, 10, 10)); QCOMPARE(damageSpy.first().first().value(), QRegion(0, 0, 10, 10)); QVERIFY(serverSurface->isMapped()); // damage multiple times QRegion testRegion(5, 8, 3, 6); testRegion = testRegion.united(QRect(10, 20, 30, 15)); img = QImage(QSize(40, 35), QImage::Format_ARGB32_Premultiplied); img.fill(Qt::black); b = m_shm->createBuffer(img); s->attachBuffer(b); s->damage(testRegion); damageSpy.clear(); s->commit(KWayland::Client::Surface::CommitFlag::None); QVERIFY(damageSpy.wait()); QCOMPARE(serverSurface->damage(), testRegion); QCOMPARE(damageSpy.first().first().value(), testRegion); QVERIFY(serverSurface->isMapped()); } void TestWaylandSurface::testFrameCallback() { QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); KWayland::Client::Surface *s = m_compositor->createSurface(); QVERIFY(serverSurfaceCreated.wait()); KWayland::Server::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface); QSignalSpy damageSpy(serverSurface, SIGNAL(damaged(QRegion))); QVERIFY(damageSpy.isValid()); QSignalSpy frameRenderedSpy(s, SIGNAL(frameRendered())); QVERIFY(frameRenderedSpy.isValid()); QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied); img.fill(Qt::black); auto b = m_shm->createBuffer(img); s->attachBuffer(b); s->damage(QRect(0, 0, 10, 10)); s->commit(); QVERIFY(damageSpy.wait()); serverSurface->frameRendered(10); QVERIFY(frameRenderedSpy.isEmpty()); QVERIFY(frameRenderedSpy.wait()); QVERIFY(!frameRenderedSpy.isEmpty()); } void TestWaylandSurface::testAttachBuffer() { // create the surface QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); KWayland::Client::Surface *s = m_compositor->createSurface(); QVERIFY(serverSurfaceCreated.wait()); KWayland::Server::SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface); // create three images QImage black(24, 24, QImage::Format_RGB32); black.fill(Qt::black); QImage red(24, 24, QImage::Format_ARGB32); //Note - deliberately not premultiplied red.fill(QColor(255, 0, 0, 128)); QImage blue(24, 24, QImage::Format_ARGB32_Premultiplied); blue.fill(QColor(0, 0, 255, 128)); wl_buffer *blackBuffer = *(m_shm->createBuffer(black).data()); auto redBuffer = m_shm->createBuffer(red); auto blueBuffer = m_shm->createBuffer(blue).toStrongRef(); QCOMPARE(blueBuffer->format(), KWayland::Client::Buffer::Format::ARGB32); QCOMPARE(blueBuffer->size(), blue.size()); QVERIFY(!blueBuffer->isReleased()); QVERIFY(!blueBuffer->isUsed()); QCOMPARE(blueBuffer->stride(), blue.bytesPerLine()); s->attachBuffer(redBuffer.data()); s->attachBuffer(blackBuffer); s->damage(QRect(0, 0, 24, 24)); s->commit(KWayland::Client::Surface::CommitFlag::None); QSignalSpy damageSpy(serverSurface, SIGNAL(damaged(QRegion))); QVERIFY(damageSpy.isValid()); QSignalSpy unmappedSpy(serverSurface, SIGNAL(unmapped())); QVERIFY(unmappedSpy.isValid()); QVERIFY(damageSpy.wait()); QVERIFY(unmappedSpy.isEmpty()); // now the ServerSurface should have the black image attached as a buffer KWayland::Server::BufferInterface *buffer = serverSurface->buffer(); buffer->ref(); QVERIFY(buffer->shmBuffer()); QCOMPARE(buffer->data(), black); QCOMPARE(buffer->data().format(), QImage::Format_RGB32); // render another frame s->attachBuffer(redBuffer); s->damage(QRect(0, 0, 24, 24)); s->commit(KWayland::Client::Surface::CommitFlag::None); damageSpy.clear(); QVERIFY(damageSpy.wait()); QVERIFY(unmappedSpy.isEmpty()); KWayland::Server::BufferInterface *buffer2 = serverSurface->buffer(); buffer2->ref(); QVERIFY(buffer2->shmBuffer()); QCOMPARE(buffer2->data().format(), QImage::Format_ARGB32_Premultiplied); QCOMPARE(buffer2->data().width(), 24); QCOMPARE(buffer2->data().height(), 24); for (int i = 0; i < 24; ++i) { for (int j = 0; j < 24; ++j) { // it's premultiplied in the format QCOMPARE(buffer2->data().pixel(i, j), qRgba(128, 0, 0, 128)); } } buffer2->unref(); QVERIFY(buffer2->isReferenced()); QVERIFY(!redBuffer.data()->isReleased()); // render another frame blueBuffer->setUsed(true); QVERIFY(blueBuffer->isUsed()); s->attachBuffer(blueBuffer.data()); s->damage(QRect(0, 0, 24, 24)); QSignalSpy frameRenderedSpy(s, SIGNAL(frameRendered())); QVERIFY(frameRenderedSpy.isValid()); s->commit(); damageSpy.clear(); QVERIFY(damageSpy.wait()); QVERIFY(unmappedSpy.isEmpty()); QVERIFY(!buffer2->isReferenced()); delete buffer2; // TODO: we should have a signal on when the Buffer gets released QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); if (!redBuffer.data()->isReleased()) { QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents); } QVERIFY(redBuffer.data()->isReleased()); KWayland::Server::BufferInterface *buffer3 = serverSurface->buffer(); buffer3->ref(); QVERIFY(buffer3->shmBuffer()); QCOMPARE(buffer3->data().format(), QImage::Format_ARGB32_Premultiplied); QCOMPARE(buffer3->data().width(), 24); QCOMPARE(buffer3->data().height(), 24); for (int i = 0; i < 24; ++i) { for (int j = 0; j < 24; ++j) { // it's premultiplied in the format QCOMPARE(buffer3->data().pixel(i, j), qRgba(0, 0, 128, 128)); } } buffer3->unref(); QVERIFY(buffer3->isReferenced()); serverSurface->frameRendered(1); QVERIFY(frameRenderedSpy.wait()); // commit a different value shouldn't change our buffer QCOMPARE(serverSurface->buffer(), buffer3); QVERIFY(serverSurface->input().isNull()); damageSpy.clear(); s->setInputRegion(m_compositor->createRegion(QRegion(0, 0, 24, 24)).get()); s->commit(KWayland::Client::Surface::CommitFlag::None); wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); QCoreApplication::processEvents(); QCOMPARE(serverSurface->input(), QRegion(0, 0, 24, 24)); QCOMPARE(serverSurface->buffer(), buffer3); QVERIFY(damageSpy.isEmpty()); QVERIFY(unmappedSpy.isEmpty()); QVERIFY(serverSurface->isMapped()); // clear the surface s->attachBuffer(blackBuffer); s->damage(QRect(0, 0, 1, 1)); // TODO: better method s->attachBuffer((wl_buffer*)nullptr); s->damage(QRect(0, 0, 10, 10)); s->commit(KWayland::Client::Surface::CommitFlag::None); QVERIFY(unmappedSpy.wait()); QVERIFY(!unmappedSpy.isEmpty()); QCOMPARE(unmappedSpy.count(), 1); QVERIFY(damageSpy.isEmpty()); QVERIFY(!serverSurface->isMapped()); // TODO: add signal test on release buffer->unref(); } void TestWaylandSurface::testMultipleSurfaces() { using namespace KWayland::Client; using namespace KWayland::Server; Registry registry; QSignalSpy shmSpy(®istry, SIGNAL(shmAnnounced(quint32,quint32))); registry.create(m_connection->display()); QVERIFY(registry.isValid()); registry.setup(); QVERIFY(shmSpy.wait()); ShmPool pool1; ShmPool pool2; pool1.setup(registry.bindShm(shmSpy.first().first().value(), shmSpy.first().last().value())); pool2.setup(registry.bindShm(shmSpy.first().first().value(), shmSpy.first().last().value())); QVERIFY(pool1.isValid()); QVERIFY(pool2.isValid()); // create the surfaces QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer s1(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface1 = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface1); //second surface QScopedPointer s2(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface2 = serverSurfaceCreated.last().first().value(); QVERIFY(serverSurface2); QVERIFY(serverSurface1->resource() != serverSurface2->resource()); // create two images QImage black(24, 24, QImage::Format_RGB32); black.fill(Qt::black); QImage red(24, 24, QImage::Format_ARGB32_Premultiplied); red.fill(QColor(255, 0, 0, 128)); auto blackBuffer = pool1.createBuffer(black); auto redBuffer = pool2.createBuffer(red); s1->attachBuffer(blackBuffer); s1->damage(QRect(0, 0, 24, 24)); s1->commit(Surface::CommitFlag::None); QSignalSpy damageSpy1(serverSurface1, SIGNAL(damaged(QRegion))); QVERIFY(damageSpy1.isValid()); QVERIFY(damageSpy1.wait()); // now the ServerSurface should have the black image attached as a buffer BufferInterface *buffer1 = serverSurface1->buffer(); QVERIFY(buffer1); QImage buffer1Data = buffer1->data(); QCOMPARE(buffer1Data, black); // accessing the same buffer is OK QImage buffer1Data2 = buffer1->data(); QCOMPARE(buffer1Data2, buffer1Data); buffer1Data = QImage(); QVERIFY(buffer1Data.isNull()); buffer1Data2 = QImage(); QVERIFY(buffer1Data2.isNull()); // attach a buffer for the other surface s2->attachBuffer(redBuffer); s2->damage(QRect(0, 0, 24, 24)); s2->commit(Surface::CommitFlag::None); QSignalSpy damageSpy2(serverSurface2, SIGNAL(damaged(QRegion))); QVERIFY(damageSpy2.isValid()); QVERIFY(damageSpy2.wait()); BufferInterface *buffer2 = serverSurface2->buffer(); QVERIFY(buffer2); QImage buffer2Data = buffer2->data(); QCOMPARE(buffer2Data, red); // while buffer2 is accessed we cannot access buffer1 buffer1Data = buffer1->data(); QVERIFY(buffer1Data.isNull()); // a deep copy can be kept around QImage deepCopy = buffer2Data.copy(); QCOMPARE(deepCopy, red); buffer2Data = QImage(); QVERIFY(buffer2Data.isNull()); QCOMPARE(deepCopy, red); // now that buffer2Data is destroyed we can access buffer1 again buffer1Data = buffer1->data(); QVERIFY(!buffer1Data.isNull()); QCOMPARE(buffer1Data, black); } void TestWaylandSurface::testOpaque() { using namespace KWayland::Client; using namespace KWayland::Server; QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); Surface *s = m_compositor->createSurface(); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface); QSignalSpy opaqueRegionChangedSpy(serverSurface, SIGNAL(opaqueChanged(QRegion))); QVERIFY(opaqueRegionChangedSpy.isValid()); // by default there should be an empty opaque region QCOMPARE(serverSurface->opaque(), QRegion()); // let's install an opaque region s->setOpaqueRegion(m_compositor->createRegion(QRegion(0, 10, 20, 30)).get()); // the region should only be applied after the surface got committed wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); QCOMPARE(serverSurface->opaque(), QRegion()); QCOMPARE(opaqueRegionChangedSpy.count(), 0); // so let's commit to get the new region s->commit(Surface::CommitFlag::None); QVERIFY(opaqueRegionChangedSpy.wait()); QCOMPARE(opaqueRegionChangedSpy.count(), 1); QCOMPARE(opaqueRegionChangedSpy.last().first().value(), QRegion(0, 10, 20, 30)); QCOMPARE(serverSurface->opaque(), QRegion(0, 10, 20, 30)); // committing without setting a new region shouldn't change s->commit(Surface::CommitFlag::None); wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); QCOMPARE(opaqueRegionChangedSpy.count(), 1); QCOMPARE(serverSurface->opaque(), QRegion(0, 10, 20, 30)); // let's change the opaque region s->setOpaqueRegion(m_compositor->createRegion(QRegion(10, 20, 30, 40)).get()); s->commit(Surface::CommitFlag::None); QVERIFY(opaqueRegionChangedSpy.wait()); QCOMPARE(opaqueRegionChangedSpy.count(), 2); QCOMPARE(opaqueRegionChangedSpy.last().first().value(), QRegion(10, 20, 30, 40)); QCOMPARE(serverSurface->opaque(), QRegion(10, 20, 30, 40)); // and let's go back to an empty region s->setOpaqueRegion(); s->commit(Surface::CommitFlag::None); QVERIFY(opaqueRegionChangedSpy.wait()); QCOMPARE(opaqueRegionChangedSpy.count(), 3); QCOMPARE(opaqueRegionChangedSpy.last().first().value(), QRegion()); QCOMPARE(serverSurface->opaque(), QRegion()); } void TestWaylandSurface::testInput() { using namespace KWayland::Client; using namespace KWayland::Server; QSignalSpy serverSurfaceCreated(m_compositorInterface, SIGNAL(surfaceCreated(KWayland::Server::SurfaceInterface*))); QVERIFY(serverSurfaceCreated.isValid()); Surface *s = m_compositor->createSurface(); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface); QSignalSpy inputRegionChangedSpy(serverSurface, SIGNAL(inputChanged(QRegion))); QVERIFY(inputRegionChangedSpy.isValid()); // by default there should be an empty == infinite input region QCOMPARE(serverSurface->input(), QRegion()); QCOMPARE(serverSurface->inputIsInfinite(), true); // let's install an input region s->setInputRegion(m_compositor->createRegion(QRegion(0, 10, 20, 30)).get()); // the region should only be applied after the surface got committed wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); QCOMPARE(serverSurface->input(), QRegion()); QCOMPARE(serverSurface->inputIsInfinite(), true); QCOMPARE(inputRegionChangedSpy.count(), 0); // so let's commit to get the new region s->commit(Surface::CommitFlag::None); QVERIFY(inputRegionChangedSpy.wait()); QCOMPARE(inputRegionChangedSpy.count(), 1); QCOMPARE(inputRegionChangedSpy.last().first().value(), QRegion(0, 10, 20, 30)); QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30)); QCOMPARE(serverSurface->inputIsInfinite(), false); // committing without setting a new region shouldn't change s->commit(Surface::CommitFlag::None); wl_display_flush(m_connection->display()); QCoreApplication::processEvents(); QCOMPARE(inputRegionChangedSpy.count(), 1); QCOMPARE(serverSurface->input(), QRegion(0, 10, 20, 30)); QCOMPARE(serverSurface->inputIsInfinite(), false); // let's change the input region s->setInputRegion(m_compositor->createRegion(QRegion(10, 20, 30, 40)).get()); s->commit(Surface::CommitFlag::None); QVERIFY(inputRegionChangedSpy.wait()); QCOMPARE(inputRegionChangedSpy.count(), 2); QCOMPARE(inputRegionChangedSpy.last().first().value(), QRegion(10, 20, 30, 40)); QCOMPARE(serverSurface->input(), QRegion(10, 20, 30, 40)); QCOMPARE(serverSurface->inputIsInfinite(), false); // and let's go back to an empty region s->setInputRegion(); s->commit(Surface::CommitFlag::None); QVERIFY(inputRegionChangedSpy.wait()); QCOMPARE(inputRegionChangedSpy.count(), 3); QCOMPARE(inputRegionChangedSpy.last().first().value(), QRegion()); QCOMPARE(serverSurface->input(), QRegion()); QCOMPARE(serverSurface->inputIsInfinite(), true); } void TestWaylandSurface::testScale() { // this test verifies that updating the scale factor is correctly passed to the Wayland server using namespace KWayland::Client; using namespace KWayland::Server; // create surface QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer s(m_compositor->createSurface()); QCOMPARE(s->scale(), 1); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QVERIFY(serverSurface); QCOMPARE(serverSurface->scale(), 1); // let's change the scale factor QSignalSpy scaleChangedSpy(serverSurface, &SurfaceInterface::scaleChanged); //changing the scale implicitly changes the size QSignalSpy sizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged); QVERIFY(scaleChangedSpy.isValid()); s->setScale(2); QCOMPARE(s->scale(), 2); // needs a commit QVERIFY(!scaleChangedSpy.wait(100)); s->commit(Surface::CommitFlag::None); QVERIFY(scaleChangedSpy.wait()); QCOMPARE(scaleChangedSpy.count(), 1); QCOMPARE(scaleChangedSpy.first().first().toInt(), 2); QCOMPARE(serverSurface->scale(), 2); //even though we've changed the scale, if we don't have a buffer we //don't have a size. If we don't have a size it can't have changed QCOMPARE(sizeChangedSpy.count(), 0); QVERIFY(!serverSurface->size().isValid()); // let's try changing to same factor, should not emit changed on server s->setScale(2); s->commit(Surface::CommitFlag::None); QVERIFY(!scaleChangedSpy.wait(100)); // but changing to a different value should still work s->setScale(4); s->commit(Surface::CommitFlag::None); QVERIFY(scaleChangedSpy.wait()); QCOMPARE(scaleChangedSpy.count(), 2); QCOMPARE(scaleChangedSpy.first().first().toInt(), 2); QCOMPARE(scaleChangedSpy.last().first().toInt(), 4); QCOMPARE(serverSurface->scale(), 4); scaleChangedSpy.clear(); //attach a buffer of 100x100, our scale is 4, so this should be a size of 25x25 QImage red(100, 100, QImage::Format_ARGB32_Premultiplied); red.fill(QColor(255, 0, 0, 128)); auto redBuffer = m_shm->createBuffer(red); s->attachBuffer(redBuffer.data()); s->damage(QRect(0,0, 25,25)); s->commit(Surface::CommitFlag::None); QVERIFY(sizeChangedSpy.wait()); QCOMPARE(sizeChangedSpy.count(), 1); QCOMPARE(serverSurface->size(), QSize(25,25)); sizeChangedSpy.clear(); scaleChangedSpy.clear(); //set the scale to 1, buffer is still 100x100 so size should change to 100x100 s->setScale(1); s->commit(Surface::CommitFlag::None); QVERIFY(sizeChangedSpy.wait()); QCOMPARE(sizeChangedSpy.count(), 1); QCOMPARE(scaleChangedSpy.count(), 1); QCOMPARE(serverSurface->scale(), 1); QCOMPARE(serverSurface->size(), QSize(100,100)); sizeChangedSpy.clear(); scaleChangedSpy.clear(); //set scale and size in one commit, buffer is 50x50 at scale 2 so size should be 25x25 QImage blue(50, 50, QImage::Format_ARGB32_Premultiplied); red.fill(QColor(255, 0, 0, 128)); auto blueBuffer = m_shm->createBuffer(blue); s->attachBuffer(blueBuffer.data()); s->setScale(2); s->commit(Surface::CommitFlag::None); QVERIFY(sizeChangedSpy.wait()); QCOMPARE(sizeChangedSpy.count(), 1); QCOMPARE(scaleChangedSpy.count(), 1); QCOMPARE(serverSurface->scale(), 2); QCOMPARE(serverSurface->size(), QSize(25,25)); } void TestWaylandSurface::testDestroy() { using namespace KWayland::Client; Surface *s = m_compositor->createSurface(); connect(m_connection, &ConnectionThread::connectionDied, s, &Surface::destroy); connect(m_connection, &ConnectionThread::connectionDied, m_compositor, &Compositor::destroy); connect(m_connection, &ConnectionThread::connectionDied, m_shm, &ShmPool::destroy); connect(m_connection, &ConnectionThread::connectionDied, m_queue, &EventQueue::destroy); QVERIFY(s->isValid()); QSignalSpy connectionDiedSpy(m_connection, SIGNAL(connectionDied())); QVERIFY(connectionDiedSpy.isValid()); delete m_display; m_display = nullptr; m_compositorInterface = nullptr; QVERIFY(connectionDiedSpy.wait()); // now the Surface should be destroyed; QVERIFY(!s->isValid()); // calling destroy again should not fail s->destroy(); } void TestWaylandSurface::testUnmapOfNotMappedSurface() { // this test verifies that a surface which doesn't have a buffer attached doesn't trigger the unmapped signal using namespace KWayland::Client; using namespace KWayland::Server; // create surface QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer s(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); QSignalSpy unmappedSpy(serverSurface, &SurfaceInterface::unmapped); QVERIFY(unmappedSpy.isValid()); QSignalSpy scaleChanged(serverSurface, &SurfaceInterface::scaleChanged); // let's map a null buffer and change scale to trigger a signal we can wait for s->attachBuffer(Buffer::Ptr()); s->setScale(2); s->commit(Surface::CommitFlag::None); QVERIFY(scaleChanged.wait()); QVERIFY(unmappedSpy.isEmpty()); } void TestWaylandSurface::testDamageTracking() { // this tests the damage tracking feature using namespace KWayland::Client; using namespace KWayland::Server; // create surface QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer s(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); // before first commit, the tracked damage should be empty QVERIFY(serverSurface->trackedDamage().isEmpty()); // Now let's damage the surface QSignalSpy damagedSpy(serverSurface, &SurfaceInterface::damaged); QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::red); s->attachBuffer(m_shm->createBuffer(image)); s->damage(QRect(0, 0, 100, 100)); s->commit(Surface::CommitFlag::None); QVERIFY(damagedSpy.wait()); QCOMPARE(serverSurface->trackedDamage(), QRegion(0, 0, 100, 100)); QCOMPARE(serverSurface->damage(), QRegion(0, 0, 100, 100)); // resetting the tracked damage should empty it serverSurface->resetTrackedDamage(); QVERIFY(serverSurface->trackedDamage().isEmpty()); // but not affect the actual damage QCOMPARE(serverSurface->damage(), QRegion(0, 0, 100, 100)); // let's damage some parts of the surface QPainter p; p.begin(&image); p.fillRect(QRect(0, 0, 10, 10), Qt::blue); p.end(); s->attachBuffer(m_shm->createBuffer(image)); s->damage(QRect(0, 0, 10, 10)); s->commit(Surface::CommitFlag::None); QVERIFY(damagedSpy.wait()); QCOMPARE(serverSurface->trackedDamage(), QRegion(0, 0, 10, 10)); QCOMPARE(serverSurface->damage(), QRegion(0, 0, 10, 10)); // and damage some part completely not bounding to the current damage region p.begin(&image); p.fillRect(QRect(50, 40, 20, 30), Qt::blue); p.end(); s->attachBuffer(m_shm->createBuffer(image)); s->damage(QRect(50, 40, 20, 30)); s->commit(Surface::CommitFlag::None); QVERIFY(damagedSpy.wait()); QCOMPARE(serverSurface->trackedDamage(), QRegion(0, 0, 10, 10).united(QRegion(50, 40, 20, 30))); QCOMPARE(serverSurface->trackedDamage().rectCount(), 2); QCOMPARE(serverSurface->damage(), QRegion(50, 40, 20, 30)); // now let's reset the tracked damage again serverSurface->resetTrackedDamage(); QVERIFY(serverSurface->trackedDamage().isEmpty()); // but not affect the actual damage QCOMPARE(serverSurface->damage(), QRegion(50, 40, 20, 30)); } void TestWaylandSurface::testSurfaceAt() { // this test verifies that surfaceAt(const QPointF&) works as expected for the case of no children using namespace KWayland::Client; using namespace KWayland::Server; // create surface QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer s(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); // a newly created surface should not be mapped and not provide a surface at a position QVERIFY(!serverSurface->isMapped()); QVERIFY(!serverSurface->surfaceAt(QPointF(0, 0))); // let's damage this surface QSignalSpy sizeChangedSpy(serverSurface, &SurfaceInterface::sizeChanged); QVERIFY(sizeChangedSpy.isValid()); QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::red); s->attachBuffer(m_shm->createBuffer(image)); s->damage(QRect(0, 0, 100, 100)); s->commit(Surface::CommitFlag::None); QVERIFY(sizeChangedSpy.wait()); // now the surface is mapped and surfaceAt should give the surface QVERIFY(serverSurface->isMapped()); QCOMPARE(serverSurface->surfaceAt(QPointF(0, 0)), serverSurface); QCOMPARE(serverSurface->surfaceAt(QPointF(100, 100)), serverSurface); // outside the geometry it should not give a surface QVERIFY(!serverSurface->surfaceAt(QPointF(101, 101))); QVERIFY(!serverSurface->surfaceAt(QPointF(-1, -1))); } void TestWaylandSurface::testDestroyAttachedBuffer() { // this test verifies that destroying of a buffer attached to a surface works using namespace KWayland::Client; using namespace KWayland::Server; // create surface QSignalSpy serverSurfaceCreated(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(serverSurfaceCreated.isValid()); QScopedPointer s(m_compositor->createSurface()); QVERIFY(serverSurfaceCreated.wait()); SurfaceInterface *serverSurface = serverSurfaceCreated.first().first().value(); // let's damage this surface QSignalSpy damagedSpy(serverSurface, &SurfaceInterface::damaged); QVERIFY(damagedSpy.isValid()); QImage image(QSize(100, 100), QImage::Format_ARGB32_Premultiplied); image.fill(Qt::red); s->attachBuffer(m_shm->createBuffer(image)); s->damage(QRect(0, 0, 100, 100)); s->commit(Surface::CommitFlag::None); QVERIFY(damagedSpy.wait()); QVERIFY(serverSurface->buffer()); // attach another buffer image.fill(Qt::blue); s->attachBuffer(m_shm->createBuffer(image)); m_connection->flush(); // Let's try to destroy it QSignalSpy destroySpy(serverSurface->buffer(), &BufferInterface::aboutToBeDestroyed); QVERIFY(destroySpy.isValid()); delete m_shm; m_shm = nullptr; QVERIFY(destroySpy.wait()); // TODO: should this emit unmapped? QVERIFY(!serverSurface->buffer()); } void TestWaylandSurface::testDestroyWithPendingCallback() { // this test tries to verify that destroying a surface with a pending callback works correctly // first create surface using namespace KWayland::Client; using namespace KWayland::Server; QScopedPointer s(m_compositor->createSurface()); QVERIFY(!s.isNull()); QVERIFY(s->isValid()); QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); // now render to it QImage img(QSize(10, 10), QImage::Format_ARGB32_Premultiplied); img.fill(Qt::black); auto b = m_shm->createBuffer(img); s->attachBuffer(b); s->damage(QRect(0, 0, 10, 10)); // add some frame callbacks for (int i = 0; i < 1000; i++) { wl_surface_frame(*s); } s->commit(KWayland::Client::Surface::CommitFlag::FrameCallback); QSignalSpy damagedSpy(serverSurface, &SurfaceInterface::damaged); QVERIFY(damagedSpy.isValid()); QVERIFY(damagedSpy.wait()); // now try to destroy the Surface again QSignalSpy destroyedSpy(serverSurface, &QObject::destroyed); QVERIFY(destroyedSpy.isValid()); s.reset(); QVERIFY(destroyedSpy.wait()); } void TestWaylandSurface::testDisconnect() { // this test verifies that the server side correctly tears down the resources when the client disconnects using namespace KWayland::Client; using namespace KWayland::Server; QScopedPointer s(m_compositor->createSurface()); QVERIFY(!s.isNull()); QVERIFY(s->isValid()); QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); // destroy client QSignalSpy clientDisconnectedSpy(serverSurface->client(), &ClientConnection::disconnected); QVERIFY(clientDisconnectedSpy.isValid()); QSignalSpy surfaceDestroyedSpy(serverSurface, &QObject::destroyed); QVERIFY(surfaceDestroyedSpy.isValid()); if (m_connection) { m_connection->deleteLater(); m_connection = nullptr; } QVERIFY(clientDisconnectedSpy.wait()); QCOMPARE(clientDisconnectedSpy.count(), 1); if (surfaceDestroyedSpy.isEmpty()) { QVERIFY(surfaceDestroyedSpy.wait()); } QTRY_COMPARE(surfaceDestroyedSpy.count(), 1); s->destroy(); m_shm->destroy(); m_compositor->destroy(); m_queue->destroy(); } void TestWaylandSurface::testOutput() { // This test verifies that the enter/leave are sent correctly to the Client using namespace KWayland::Client; using namespace KWayland::Server; qRegisterMetaType(); QScopedPointer s(m_compositor->createSurface()); QVERIFY(!s.isNull()); QVERIFY(s->isValid()); QVERIFY(s->outputs().isEmpty()); QSignalSpy enteredSpy(s.data(), &Surface::outputEntered); QVERIFY(enteredSpy.isValid()); QSignalSpy leftSpy(s.data(), &Surface::outputLeft); QVERIFY(leftSpy.isValid()); // wait for the surface on the Server side QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); QVERIFY(surfaceCreatedSpy.isValid()); QVERIFY(surfaceCreatedSpy.wait()); auto serverSurface = surfaceCreatedSpy.first().first().value(); QVERIFY(serverSurface); QCOMPARE(serverSurface->outputs(), QVector()); // create another registry to get notified about added outputs Registry registry; registry.setEventQueue(m_queue); QSignalSpy allAnnounced(®istry, &Registry::interfacesAnnounced); QVERIFY(allAnnounced.isValid()); registry.create(m_connection); QVERIFY(registry.isValid()); registry.setup(); QVERIFY(allAnnounced.wait()); QSignalSpy outputAnnouncedSpy(®istry, &Registry::outputAnnounced); QVERIFY(outputAnnouncedSpy.isValid()); auto serverOutput = m_display->createOutput(m_display); serverOutput->create(); QVERIFY(outputAnnouncedSpy.wait()); QScopedPointer clientOutput(registry.createOutput(outputAnnouncedSpy.first().first().value(), outputAnnouncedSpy.first().last().value())); QVERIFY(clientOutput->isValid()); m_connection->flush(); m_display->dispatchEvents(); // now enter it serverSurface->setOutputs(QVector{serverOutput}); QCOMPARE(serverSurface->outputs(), QVector{serverOutput}); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 1); QCOMPARE(enteredSpy.first().first().value(), clientOutput.data()); QCOMPARE(s->outputs(), QVector{clientOutput.data()}); // adding to same should not trigger serverSurface->setOutputs(QVector{serverOutput}); // leave again serverSurface->setOutputs(QVector()); QCOMPARE(serverSurface->outputs(), QVector()); QVERIFY(leftSpy.wait()); QCOMPARE(enteredSpy.count(), 1); QCOMPARE(leftSpy.count(), 1); QCOMPARE(leftSpy.first().first().value(), clientOutput.data()); QCOMPARE(s->outputs(), QVector()); // leave again should not trigger serverSurface->setOutputs(QVector()); // and enter again, just to verify serverSurface->setOutputs(QVector{serverOutput}); QCOMPARE(serverSurface->outputs(), QVector{serverOutput}); QVERIFY(enteredSpy.wait()); QCOMPARE(enteredSpy.count(), 2); QCOMPARE(leftSpy.count(), 1); //delete output client is on. //client should get an exit and be left on no outputs (which is allowed) serverOutput->deleteLater(); QVERIFY(leftSpy.wait()); QCOMPARE(serverSurface->outputs(), QVector()); } +void TestWaylandSurface::testInhibit() +{ + using namespace KWayland::Client; + using namespace KWayland::Server; + QScopedPointer s(m_compositor->createSurface()); + // wait for the surface on the Server side + QSignalSpy surfaceCreatedSpy(m_compositorInterface, &CompositorInterface::surfaceCreated); + QVERIFY(surfaceCreatedSpy.isValid()); + QVERIFY(surfaceCreatedSpy.wait()); + auto serverSurface = surfaceCreatedSpy.first().first().value(); + QVERIFY(serverSurface); + QCOMPARE(serverSurface->inhibitsIdle(), false); + + QSignalSpy inhibitsChangedSpy(serverSurface, &SurfaceInterface::inhibitsIdleChanged); + QVERIFY(inhibitsChangedSpy.isValid()); + + // now create an idle inhibition + QScopedPointer inhibitor1(m_idleInhibitManager->createInhibitor(s.data())); + QVERIFY(inhibitsChangedSpy.wait()); + QCOMPARE(serverSurface->inhibitsIdle(), true); + + // creating a second idle inhibition should not trigger the signal + QScopedPointer inhibitor2(m_idleInhibitManager->createInhibitor(s.data())); + QVERIFY(!inhibitsChangedSpy.wait()); + QCOMPARE(serverSurface->inhibitsIdle(), true); + + // and also deleting the first inhibitor should not yet change the inhibition + inhibitor1.reset(); + QVERIFY(!inhibitsChangedSpy.wait()); + QCOMPARE(serverSurface->inhibitsIdle(), true); + + // but deleting also the second inhibitor should trigger + inhibitor2.reset(); + QVERIFY(inhibitsChangedSpy.wait()); + QCOMPARE(serverSurface->inhibitsIdle(), false); + QCOMPARE(inhibitsChangedSpy.count(), 2); + + // recreate inhibitor1 should inhibit again + inhibitor1.reset(m_idleInhibitManager->createInhibitor(s.data())); + QVERIFY(inhibitsChangedSpy.wait()); + QCOMPARE(serverSurface->inhibitsIdle(), true); + // and destroying should uninhibit + inhibitor1.reset(); + QVERIFY(inhibitsChangedSpy.wait()); + QCOMPARE(serverSurface->inhibitsIdle(), false); + QCOMPARE(inhibitsChangedSpy.count(), 4); +} + QTEST_GUILESS_MAIN(TestWaylandSurface) #include "test_wayland_surface.moc" diff --git a/src/client/CMakeLists.txt b/src/client/CMakeLists.txt index ebd0926..fd80e90 100644 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -1,233 +1,239 @@ remove_definitions(-DQT_NO_CAST_FROM_BYTEARRAY) remove_definitions(-DQT_NO_CAST_FROM_ASCII) remove_definitions(-DQT_NO_CAST_TO_ASCII) # needed to access QPA include_directories(${Qt5Gui_PRIVATE_INCLUDE_DIRS}) set(CLIENT_LIB_SRCS buffer.cpp blur.cpp compositor.cpp connection_thread.cpp contrast.cpp slide.cpp event_queue.cpp datadevice.cpp datadevicemanager.cpp dataoffer.cpp datasource.cpp dpms.cpp fakeinput.cpp fullscreen_shell.cpp idle.cpp + idleinhibit.cpp keyboard.cpp outputconfiguration.cpp outputmanagement.cpp outputdevice.cpp logging.cpp output.cpp pointer.cpp pointerconstraints.cpp pointergestures.cpp plasmashell.cpp plasmawindowmanagement.cpp plasmawindowmodel.cpp region.cpp registry.cpp relativepointer.cpp seat.cpp server_decoration.cpp shadow.cpp shell.cpp shm_pool.cpp subcompositor.cpp subsurface.cpp surface.cpp touch.cpp textinput.cpp textinput_v0.cpp textinput_v2.cpp xdgshell.cpp xdgshell_v5.cpp xdgforeign_v2.cpp xdgforeign.cpp xdgshell_v6.cpp ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/fullscreen-shell.xml BASENAME fullscreen-shell ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/output-management.xml BASENAME output-management ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/outputdevice.xml BASENAME org_kde_kwin_outputdevice ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-shell.xml BASENAME plasma-shell ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-window-management.xml BASENAME plasma-window-management ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/idle.xml BASENAME idle ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/fake-input.xml BASENAME fake-input ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/shadow.xml BASENAME shadow ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/blur.xml BASENAME blur ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/contrast.xml BASENAME contrast ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/slide.xml BASENAME slide ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/dpms.xml BASENAME dpms ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/server-decoration.xml BASENAME server-decoration ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input.xml BASENAME text-input-v0 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input-unstable-v2.xml BASENAME text-input-v2 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v5.xml BASENAME xdg-shell-v5 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v6.xml BASENAME xdg-shell-v6 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/relative-pointer-unstable-v1.xml BASENAME relativepointer-unstable-v1 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-gestures-unstable-v1.xml BASENAME pointer-gestures-unstable-v1 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1 ) ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-foreign-unstable-v2.xml BASENAME xdg-foreign-unstable-v2 ) +ecm_add_wayland_client_protocol(CLIENT_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/idle-inhibit-unstable-v1.xml + BASENAME idle-inhibit-unstable-v1 +) add_library(KF5WaylandClient ${CLIENT_LIB_SRCS}) generate_export_header(KF5WaylandClient BASE_NAME KWaylandClient EXPORT_FILE_NAME KWayland/Client/kwaylandclient_export.h ) add_library(KF5::WaylandClient ALIAS KF5WaylandClient) target_include_directories(KF5WaylandClient INTERFACE "$") target_link_libraries(KF5WaylandClient PUBLIC Qt5::Gui PRIVATE Wayland::Client Qt5::Concurrent ) set_target_properties(KF5WaylandClient PROPERTIES VERSION ${KWAYLAND_VERSION_STRING} SOVERSION ${KWAYLAND_SOVERSION} EXPORT_NAME WaylandClient ) install(TARGETS KF5WaylandClient EXPORT KF5WaylandTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) set(CLIENT_LIB_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/KWayland/Client/kwaylandclient_export.h blur.h buffer.h compositor.h connection_thread.h contrast.h event_queue.h datadevice.h datadevicemanager.h dataoffer.h datasource.h dpms.h fakeinput.h fullscreen_shell.h idle.h + idleinhibit.h keyboard.h outputconfiguration.h outputmanagement.h outputdevice.h output.h pointer.h pointerconstraints.h plasmashell.h plasmawindowmanagement.h plasmawindowmodel.h pointergestures.h region.h registry.h relativepointer.h seat.h server_decoration.h shadow.h shell.h shm_pool.h slide.h subcompositor.h subsurface.h surface.h touch.h textinput.h xdgshell.h xdgforeign_v2.h ) install(FILES ${CLIENT_LIB_HEADERS} DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KWayland/Client COMPONENT Devel ) # make available to ecm_add_qch in parent folder set(KWaylandClient_APIDOX_SRCS ${CLIENT_LIB_HEADERS} PARENT_SCOPE) include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KWaylandClient LIB_NAME KF5WaylandClient DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/client/idleinhibit.cpp b/src/client/idleinhibit.cpp new file mode 100644 index 0000000..ae21320 --- /dev/null +++ b/src/client/idleinhibit.cpp @@ -0,0 +1,176 @@ +/**************************************************************************** +Copyright 2017 Martin Flöser + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#include "idleinhibit.h" +#include "event_queue.h" +#include "surface.h" +#include "wayland_pointer_p.h" + +#include + +namespace KWayland +{ +namespace Client +{ + +class Q_DECL_HIDDEN IdleInhibitManager::Private +{ +public: + Private() = default; + + void setup(zwp_idle_inhibit_manager_v1 *arg); + + WaylandPointer idleinhibitmanager; + EventQueue *queue = nullptr; +}; + +IdleInhibitManager::IdleInhibitManager(QObject *parent) + : QObject(parent) + , d(new Private) +{ +} + +void IdleInhibitManager::Private::setup(zwp_idle_inhibit_manager_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!idleinhibitmanager); + idleinhibitmanager.setup(arg); +} + +IdleInhibitManager::~IdleInhibitManager() +{ + release(); +} + +void IdleInhibitManager::setup(zwp_idle_inhibit_manager_v1 *idleinhibitmanager) +{ + d->setup(idleinhibitmanager); +} + +void IdleInhibitManager::release() +{ + d->idleinhibitmanager.release(); +} + +void IdleInhibitManager::destroy() +{ + d->idleinhibitmanager.destroy(); +} + +IdleInhibitManager::operator zwp_idle_inhibit_manager_v1*() { + return d->idleinhibitmanager; +} + +IdleInhibitManager::operator zwp_idle_inhibit_manager_v1*() const { + return d->idleinhibitmanager; +} + +bool IdleInhibitManager::isValid() const +{ + return d->idleinhibitmanager.isValid(); +} + +void IdleInhibitManager::setEventQueue(EventQueue *queue) +{ + d->queue = queue; +} + +EventQueue *IdleInhibitManager::eventQueue() +{ + return d->queue; +} + +IdleInhibitor *IdleInhibitManager::createInhibitor(Surface *surface, QObject *parent) +{ + Q_ASSERT(isValid()); + auto p = new IdleInhibitor(parent); + auto w = zwp_idle_inhibit_manager_v1_create_inhibitor(d->idleinhibitmanager, *surface); + if (d->queue) { + d->queue->addProxy(w); + } + p->setup(w); + return p; +} + +class Q_DECL_HIDDEN IdleInhibitor::Private +{ +public: + Private(IdleInhibitor *q); + + void setup(zwp_idle_inhibitor_v1 *arg); + + WaylandPointer idleinhibitor; + +private: + IdleInhibitor *q; +}; + +IdleInhibitor::Private::Private(IdleInhibitor *q) + : q(q) +{ +} + +IdleInhibitor::IdleInhibitor(QObject *parent) + : QObject(parent) + , d(new Private(this)) +{ +} + +void IdleInhibitor::Private::setup(zwp_idle_inhibitor_v1 *arg) +{ + Q_ASSERT(arg); + Q_ASSERT(!idleinhibitor); + idleinhibitor.setup(arg); +} + +IdleInhibitor::~IdleInhibitor() +{ + release(); +} + +void IdleInhibitor::setup(zwp_idle_inhibitor_v1 *idleinhibitor) +{ + d->setup(idleinhibitor); +} + +void IdleInhibitor::release() +{ + d->idleinhibitor.release(); +} + +void IdleInhibitor::destroy() +{ + d->idleinhibitor.destroy(); +} + +IdleInhibitor::operator zwp_idle_inhibitor_v1*() { + return d->idleinhibitor; +} + +IdleInhibitor::operator zwp_idle_inhibitor_v1*() const { + return d->idleinhibitor; +} + +bool IdleInhibitor::isValid() const +{ + return d->idleinhibitor.isValid(); +} + +} +} diff --git a/src/client/idleinhibit.h b/src/client/idleinhibit.h new file mode 100644 index 0000000..f538a13 --- /dev/null +++ b/src/client/idleinhibit.h @@ -0,0 +1,217 @@ +/**************************************************************************** +Copyright 2017 Martin Flöser + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_CLIENT_IDLEINHIBIT_H +#define KWAYLAND_CLIENT_IDLEINHIBIT_H + +#include + +#include + +struct zwp_idle_inhibit_manager_v1; +struct zwp_idle_inhibitor_v1; + +namespace KWayland +{ +namespace Client +{ + +class EventQueue; +class Surface; +class IdleInhibitor; + +/** + * @short Wrapper for the zwp_idle_inhibit_manager_v1 interface. + * + * This class provides a convenient wrapper for the zwp_idle_inhibit_manager_v1 interface. + * + * To use this class one needs to interact with the Registry. There are two + * possible ways to create the IdleInhibitManager interface: + * @code + * IdleInhibitManager *c = registry->createIdleInhibitManager(name, version); + * @endcode + * + * This creates the IdleInhibitManager and sets it up directly. As an alternative this + * can also be done in a more low level way: + * @code + * IdleInhibitManager *c = new IdleInhibitManager; + * c->setup(registry->bindIdleInhibitManager(name, version)); + * @endcode + * + * The IdleInhibitManager can be used as a drop-in replacement for any zwp_idle_inhibit_manager_v1 + * pointer as it provides matching cast operators. + * + * @see Registry + * @since 5.41 + **/ +class KWAYLANDCLIENT_EXPORT IdleInhibitManager : public QObject +{ + Q_OBJECT +public: + /** + * Creates a new IdleInhibitManager. + * Note: after constructing the IdleInhibitManager it is not yet valid and one needs + * to call setup. In order to get a ready to use IdleInhibitManager prefer using + * Registry::createIdleInhibitManager. + **/ + explicit IdleInhibitManager(QObject *parent = nullptr); + virtual ~IdleInhibitManager(); + + /** + * Setup this IdleInhibitManager to manage the @p idleinhibitmanager. + * When using Registry::createIdleInhibitManager there is no need to call this + * method. + **/ + void setup(zwp_idle_inhibit_manager_v1 *idleinhibitmanager); + /** + * @returns @c true if managing a zwp_idle_inhibit_manager_v1. + **/ + bool isValid() const; + /** + * Releases the zwp_idle_inhibit_manager_v1 interface. + * After the interface has been released the IdleInhibitManager instance is no + * longer valid and can be setup with another zwp_idle_inhibit_manager_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this IdleInhibitManager. + * This method is supposed to be used when the connection to the Wayland + * server goes away. If the connection is not valid anymore, it's not + * possible to call release anymore as that calls into the Wayland + * connection and the call would fail. This method cleans up the data, so + * that the instance can be deleted or set up to a new zwp_idle_inhibit_manager_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, idleinhibitmanager, &IdleInhibitManager::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + /** + * Sets the @p queue to use for creating objects with this IdleInhibitManager. + **/ + void setEventQueue(EventQueue *queue); + /** + * @returns The event queue to use for creating objects with this IdleInhibitManager. + **/ + EventQueue *eventQueue(); + + /** + * Creates an IdleInhibitor for the given @p surface. + * While the IdleInhibitor exists the @p surface is marked to inhibit idle. + * @param surface The Surface which should have idle inhibited + * @param parent The parent object for the IdleInhibitor + * @returns The created IdleInhibitor + **/ + IdleInhibitor *createInhibitor(Surface *surface, QObject *parent = nullptr); + + operator zwp_idle_inhibit_manager_v1*(); + operator zwp_idle_inhibit_manager_v1*() const; + +Q_SIGNALS: + /** + * The corresponding global for this interface on the Registry got removed. + * + * This signal gets only emitted if the IdleInhibitManager got created by + * Registry::createIdleInhibitManager + **/ + void removed(); + +private: + class Private; + QScopedPointer d; +}; + +/** + * An IdleInhibitor prevents the Output that the associated Surface is visible on from being + * set to a state where it is not visually usable due to lack of user interaction + * (e.g. blanked, dimmed, locked, set to power save, etc.) Any screensaver processes are + * also blocked from displaying. + * + * If the Surface is destroyed, unmapped, becomes occluded, loses visibility, or otherwise + * becomes not visually relevant for the user, the IdleInhibitor will not be honored by + * the compositor; if the Surface subsequently regains visibility the inhibitor takes effect + * once again. + * Likewise, the IdleInhibitor isn't honored if the system was already idled at the time the + * IdleInhibitor was established, although if the system later de-idles and re-idles the + * IdleInhibitor will take effect. + * + * @see IdleInhibitManager + * @see Surface + * @since 5.41 + **/ +class KWAYLANDCLIENT_EXPORT IdleInhibitor : public QObject +{ + Q_OBJECT +public: + virtual ~IdleInhibitor(); + + /** + * Setup this IdleInhibitor to manage the @p idleinhibitor. + * When using IdleInhibitManager::createIdleInhibitor there is no need to call this + * method. + **/ + void setup(zwp_idle_inhibitor_v1 *idleinhibitor); + /** + * @returns @c true if managing a zwp_idle_inhibitor_v1. + **/ + bool isValid() const; + /** + * Releases the zwp_idle_inhibitor_v1 interface. + * After the interface has been released the IdleInhibitor instance is no + * longer valid and can be setup with another zwp_idle_inhibitor_v1 interface. + **/ + void release(); + /** + * Destroys the data held by this IdleInhibitor. + * This method is supposed to be used when the connection to the Wayland + * server goes away. If the connection is not valid anymore, it's not + * possible to call release anymore as that calls into the Wayland + * connection and the call would fail. This method cleans up the data, so + * that the instance can be deleted or set up to a new zwp_idle_inhibitor_v1 interface + * once there is a new connection available. + * + * It is suggested to connect this method to ConnectionThread::connectionDied: + * @code + * connect(connection, &ConnectionThread::connectionDied, idleinhibitor, &IdleInhibitor::destroy); + * @endcode + * + * @see release + **/ + void destroy(); + + operator zwp_idle_inhibitor_v1*(); + operator zwp_idle_inhibitor_v1*() const; + +private: + friend class IdleInhibitManager; + explicit IdleInhibitor(QObject *parent = nullptr); + class Private; + QScopedPointer d; +}; + + +} +} + +#endif diff --git a/src/client/protocols/idle-inhibit-unstable-v1.xml b/src/client/protocols/idle-inhibit-unstable-v1.xml new file mode 100644 index 0000000..9c06cdc --- /dev/null +++ b/src/client/protocols/idle-inhibit-unstable-v1.xml @@ -0,0 +1,83 @@ + + + + + Copyright © 2015 Samsung Electronics Co., Ltd + + Permission is hereby granted, free of charge, to any person obtaining a + copy of this software and associated documentation files (the "Software"), + to deal in the Software without restriction, including without limitation + the rights to use, copy, modify, merge, publish, distribute, sublicense, + and/or sell copies of the Software, and to permit persons to whom the + Software is furnished to do so, subject to the following conditions: + + The above copyright notice and this permission notice (including the next + paragraph) shall be included in all copies or substantial portions of the + Software. + + THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + DEALINGS IN THE SOFTWARE. + + + + + This interface permits inhibiting the idle behavior such as screen + blanking, locking, and screensaving. The client binds the idle manager + globally, then creates idle-inhibitor objects for each surface. + + Warning! The protocol described in this file is experimental and + backward incompatible changes may be made. Backward compatible changes + may be added together with the corresponding interface version bump. + Backward incompatible changes are done by bumping the version number in + the protocol and interface names and resetting the interface version. + Once the protocol is to be declared stable, the 'z' prefix and the + version number in the protocol and interface names are removed and the + interface version number is reset. + + + + + Destroy the inhibit manager. + + + + + + Create a new inhibitor object associated with the given surface. + + + + + + + + + + An idle inhibitor prevents the output that the associated surface is + visible on from being set to a state where it is not visually usable due + to lack of user interaction (e.g. blanked, dimmed, locked, set to power + save, etc.) Any screensaver processes are also blocked from displaying. + + If the surface is destroyed, unmapped, becomes occluded, loses + visibility, or otherwise becomes not visually relevant for the user, the + idle inhibitor will not be honored by the compositor; if the surface + subsequently regains visibility the inhibitor takes effect once again. + Likewise, the inhibitor isn't honored if the system was already idled at + the time the inhibitor was established, although if the system later + de-idles and re-idles the inhibitor will take effect. + + + + + Remove the inhibitor effect from the associated wl_surface. + + + + + diff --git a/src/client/registry.cpp b/src/client/registry.cpp index 52d188e..fea8965 100644 --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -1,784 +1,804 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "registry.h" #include "compositor.h" #include "connection_thread.h" #include "datadevicemanager.h" #include "dpms.h" #include "event_queue.h" #include "fakeinput.h" #include "fullscreen_shell.h" #include "idle.h" +#include "idleinhibit.h" #include "logging_p.h" #include "outputconfiguration.h" #include "outputmanagement.h" #include "outputdevice.h" #include "output.h" #include "plasmashell.h" #include "plasmawindowmanagement.h" #include "pointerconstraints.h" #include "pointergestures.h" #include "seat.h" #include "shadow.h" #include "blur.h" #include "contrast.h" #include "relativepointer.h" #include "server_decoration.h" #include "slide.h" #include "shell.h" #include "shm_pool.h" #include "subcompositor.h" #include "textinput_p.h" #include "xdgshell.h" #include "xdgshell_p.h" #include "wayland_pointer_p.h" #include "xdgforeign_v2.h" // Qt #include // wayland #include #include #include #include #include +#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /***** * How to add another interface: * * define a new enum value in Registry::Interface * * define the bind method * * define the create method * * define the Announced signal * * define the Removed signal * * add a block to s_interfaces * * add the BIND macro for the new bind * * add the CREATE macro for the new create * * extend registry unit test to verify that it works ****/ namespace KWayland { namespace Client { namespace { struct SuppertedInterfaceData { quint32 maxVersion; QByteArray name; const wl_interface *interface; void (Registry::*announcedSignal)(quint32, quint32); void (Registry::*removedSignal)(quint32); }; static const QMap s_interfaces = { {Registry::Interface::Compositor, { 3, QByteArrayLiteral("wl_compositor"), &wl_compositor_interface, &Registry::compositorAnnounced, &Registry::compositorRemoved }}, {Registry::Interface::DataDeviceManager, { 2, QByteArrayLiteral("wl_data_device_manager"), &wl_data_device_manager_interface, &Registry::dataDeviceManagerAnnounced, &Registry::dataDeviceManagerRemoved }}, {Registry::Interface::Output, { 2, QByteArrayLiteral("wl_output"), &wl_output_interface, &Registry::outputAnnounced, &Registry::outputRemoved }}, {Registry::Interface::Shm, { 1, QByteArrayLiteral("wl_shm"), &wl_shm_interface, &Registry::shmAnnounced, &Registry::shmRemoved }}, {Registry::Interface::Seat, { 4, QByteArrayLiteral("wl_seat"), &wl_seat_interface, &Registry::seatAnnounced, &Registry::seatRemoved }}, {Registry::Interface::Shell, { 1, QByteArrayLiteral("wl_shell"), &wl_shell_interface, &Registry::shellAnnounced, &Registry::shellRemoved }}, {Registry::Interface::SubCompositor, { 1, QByteArrayLiteral("wl_subcompositor"), &wl_subcompositor_interface, &Registry::subCompositorAnnounced, &Registry::subCompositorRemoved }}, {Registry::Interface::PlasmaShell, { 4, QByteArrayLiteral("org_kde_plasma_shell"), &org_kde_plasma_shell_interface, &Registry::plasmaShellAnnounced, &Registry::plasmaShellRemoved }}, {Registry::Interface::PlasmaWindowManagement, { 7, QByteArrayLiteral("org_kde_plasma_window_management"), &org_kde_plasma_window_management_interface, &Registry::plasmaWindowManagementAnnounced, &Registry::plasmaWindowManagementRemoved }}, {Registry::Interface::Idle, { 1, QByteArrayLiteral("org_kde_kwin_idle"), &org_kde_kwin_idle_interface, &Registry::idleAnnounced, &Registry::idleRemoved }}, {Registry::Interface::FakeInput, { 2, QByteArrayLiteral("org_kde_kwin_fake_input"), &org_kde_kwin_fake_input_interface, &Registry::fakeInputAnnounced, &Registry::fakeInputRemoved }}, {Registry::Interface::OutputManagement, { 1, QByteArrayLiteral("org_kde_kwin_outputmanagement"), &org_kde_kwin_outputmanagement_interface, &Registry::outputManagementAnnounced, &Registry::outputManagementRemoved }}, {Registry::Interface::OutputDevice, { 1, QByteArrayLiteral("org_kde_kwin_outputdevice"), &org_kde_kwin_outputdevice_interface, &Registry::outputDeviceAnnounced, &Registry::outputDeviceRemoved }}, {Registry::Interface::Shadow, { 2, QByteArrayLiteral("org_kde_kwin_shadow_manager"), &org_kde_kwin_shadow_manager_interface, &Registry::shadowAnnounced, &Registry::shadowRemoved }}, {Registry::Interface::Blur, { 1, QByteArrayLiteral("org_kde_kwin_blur_manager"), &org_kde_kwin_blur_manager_interface, &Registry::blurAnnounced, &Registry::blurRemoved }}, {Registry::Interface::Contrast, { 1, QByteArrayLiteral("org_kde_kwin_contrast_manager"), &org_kde_kwin_contrast_manager_interface, &Registry::contrastAnnounced, &Registry::contrastRemoved }}, {Registry::Interface::Slide, { 1, QByteArrayLiteral("org_kde_kwin_slide_manager"), &org_kde_kwin_slide_manager_interface, &Registry::slideAnnounced, &Registry::slideRemoved }}, {Registry::Interface::FullscreenShell, { 1, QByteArrayLiteral("_wl_fullscreen_shell"), &_wl_fullscreen_shell_interface, &Registry::fullscreenShellAnnounced, &Registry::fullscreenShellRemoved }}, {Registry::Interface::Dpms, { 1, QByteArrayLiteral("org_kde_kwin_dpms_manager"), &org_kde_kwin_dpms_manager_interface, &Registry::dpmsAnnounced, &Registry::dpmsRemoved }}, {Registry::Interface::ServerSideDecorationManager, { 1, QByteArrayLiteral("org_kde_kwin_server_decoration_manager"), &org_kde_kwin_server_decoration_manager_interface, &Registry::serverSideDecorationManagerAnnounced, &Registry::serverSideDecorationManagerRemoved }}, {Registry::Interface::TextInputManagerUnstableV0, { 1, QByteArrayLiteral("wl_text_input_manager"), &wl_text_input_manager_interface, &Registry::textInputManagerUnstableV0Announced, &Registry::textInputManagerUnstableV0Removed }}, {Registry::Interface::TextInputManagerUnstableV2, { 1, QByteArrayLiteral("zwp_text_input_manager_v2"), &zwp_text_input_manager_v2_interface, &Registry::textInputManagerUnstableV2Announced, &Registry::textInputManagerUnstableV2Removed }}, {Registry::Interface::XdgShellUnstableV5, { 1, QByteArrayLiteral("xdg_shell"), &xdg_shell_interface, &Registry::xdgShellUnstableV5Announced, &Registry::xdgShellUnstableV5Removed }}, {Registry::Interface::RelativePointerManagerUnstableV1, { 1, QByteArrayLiteral("zwp_relative_pointer_manager_v1"), &zwp_relative_pointer_manager_v1_interface, &Registry::relativePointerManagerUnstableV1Announced, &Registry::relativePointerManagerUnstableV1Removed }}, {Registry::Interface::PointerGesturesUnstableV1, { 1, QByteArrayLiteral("zwp_pointer_gestures_v1"), &zwp_pointer_gestures_v1_interface, &Registry::pointerGesturesUnstableV1Announced, &Registry::pointerGesturesUnstableV1Removed }}, {Registry::Interface::PointerConstraintsUnstableV1, { 1, QByteArrayLiteral("zwp_pointer_constraints_v1"), &zwp_pointer_constraints_v1_interface, &Registry::pointerConstraintsUnstableV1Announced, &Registry::pointerConstraintsUnstableV1Removed }}, {Registry::Interface::XdgExporterUnstableV2, { 1, QByteArrayLiteral("zxdg_exporter_v2"), &zxdg_exporter_v2_interface, &Registry::exporterUnstableV2Announced, &Registry::exporterUnstableV2Removed }}, {Registry::Interface::XdgImporterUnstableV2, { 1, QByteArrayLiteral("zxdg_importer_v2"), &zxdg_importer_v2_interface, &Registry::importerUnstableV2Announced, &Registry::importerUnstableV2Removed }}, {Registry::Interface::XdgShellUnstableV6, { 1, QByteArrayLiteral("zxdg_shell_v6"), &zxdg_shell_v6_interface, &Registry::xdgShellUnstableV6Announced, &Registry::xdgShellUnstableV6Removed + }}, + {Registry::Interface::IdleInhibitManagerUnstableV1, { + 1, + QByteArrayLiteral("zwp_idle_inhibit_manager_v1"), + &zwp_idle_inhibit_manager_v1_interface, + &Registry::idleInhibitManagerUnstableV1Announced, + &Registry::idleInhibitManagerUnstableV1Removed }} }; static quint32 maxVersion(const Registry::Interface &interface) { auto it = s_interfaces.find(interface); if (it != s_interfaces.end()) { return it.value().maxVersion; } return 0; } } class Q_DECL_HIDDEN Registry::Private { public: Private(Registry *q); void setup(); bool hasInterface(Interface interface) const; AnnouncedInterface interface(Interface interface) const; QVector interfaces(Interface interface) const; Interface interfaceForName(quint32 name) const; template T *bind(Interface interface, uint32_t name, uint32_t version) const; template T *create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const); WaylandPointer registry; static const struct wl_callback_listener s_callbackListener; WaylandPointer callback; EventQueue *queue = nullptr; private: void handleAnnounce(uint32_t name, const char *interface, uint32_t version); void handleRemove(uint32_t name); void handleGlobalSync(); static void globalAnnounce(void *data, struct wl_registry *registry, uint32_t name, const char *interface, uint32_t version); static void globalRemove(void *data, struct wl_registry *registry, uint32_t name); static void globalSync(void *data, struct wl_callback *callback, uint32_t serial); Registry *q; struct InterfaceData { Interface interface; uint32_t name; uint32_t version; }; QList m_interfaces; static const struct wl_registry_listener s_registryListener; }; Registry::Private::Private(Registry *q) : q(q) { } void Registry::Private::setup() { wl_registry_add_listener(registry, &s_registryListener, this); wl_callback_add_listener(callback, &s_callbackListener, this); } Registry::Registry(QObject *parent) : QObject(parent) , d(new Private(this)) { } Registry::~Registry() { release(); } void Registry::release() { d->registry.release(); d->callback.release(); } void Registry::destroy() { emit registryDestroyed(); d->registry.destroy(); d->callback.destroy(); } void Registry::create(wl_display *display) { Q_ASSERT(display); Q_ASSERT(!isValid()); d->registry.setup(wl_display_get_registry(display)); d->callback.setup(wl_display_sync(display)); if (d->queue) { d->queue->addProxy(d->registry); d->queue->addProxy(d->callback); } } void Registry::create(ConnectionThread *connection) { create(connection->display()); connect(connection, &ConnectionThread::connectionDied, this, &Registry::destroy); } void Registry::setup() { Q_ASSERT(isValid()); d->setup(); } void Registry::setEventQueue(EventQueue *queue) { d->queue = queue; if (!queue) { return; } if (d->registry) { d->queue->addProxy(d->registry); } if (d->callback) { d->queue->addProxy(d->callback); } } EventQueue *Registry::eventQueue() { return d->queue; } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_registry_listener Registry::Private::s_registryListener = { globalAnnounce, globalRemove }; const struct wl_callback_listener Registry::Private::s_callbackListener = { globalSync }; #endif void Registry::Private::globalAnnounce(void *data, wl_registry *registry, uint32_t name, const char *interface, uint32_t version) { auto r = reinterpret_cast(data); Q_ASSERT(registry == r->registry); r->handleAnnounce(name, interface, version); } void Registry::Private::globalRemove(void *data, wl_registry *registry, uint32_t name) { auto r = reinterpret_cast(data); Q_ASSERT(registry == r->registry); r->handleRemove(name); } void Registry::Private::globalSync(void* data, wl_callback* callback, uint32_t serial) { Q_UNUSED(serial) auto r = reinterpret_cast(data); Q_ASSERT(r->callback == callback); r->handleGlobalSync(); r->callback.destroy(); } void Registry::Private::handleGlobalSync() { emit q->interfacesAnnounced(); } namespace { static Registry::Interface nameToInterface(const char *interface) { for (auto it = s_interfaces.begin(); it != s_interfaces.end(); ++it) { if (qstrcmp(interface, it.value().name) == 0) { return it.key(); } } return Registry::Interface::Unknown; } } void Registry::Private::handleAnnounce(uint32_t name, const char *interface, uint32_t version) { Interface i = nameToInterface(interface); emit q->interfaceAnnounced(QByteArray(interface), name, version); if (i == Interface::Unknown) { qCDebug(KWAYLAND_CLIENT) << "Unknown interface announced: " << interface << "/" << name << "/" << version; return; } qCDebug(KWAYLAND_CLIENT) << "Wayland Interface: " << interface << "/" << name << "/" << version; m_interfaces.append({i, name, version}); auto it = s_interfaces.constFind(i); if (it != s_interfaces.end()) { emit (q->*it.value().announcedSignal)(name, version); } } void Registry::Private::handleRemove(uint32_t name) { auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [name](const InterfaceData &data) { return data.name == name; } ); if (it != m_interfaces.end()) { InterfaceData data = *(it); m_interfaces.erase(it); auto sit = s_interfaces.find(data.interface); if (sit != s_interfaces.end()) { emit (q->*sit.value().removedSignal)(data.name); } } emit q->interfaceRemoved(name); } bool Registry::Private::hasInterface(Registry::Interface interface) const { auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [interface](const InterfaceData &data) { return data.interface == interface; } ); return it != m_interfaces.end(); } QVector Registry::Private::interfaces(Interface interface) const { QVector retVal; for (auto it = m_interfaces.constBegin(); it != m_interfaces.constEnd(); ++it) { const auto &data = *it; if (data.interface == interface) { retVal << AnnouncedInterface{data.name, data.version}; } } return retVal; } Registry::AnnouncedInterface Registry::Private::interface(Interface interface) const { const auto all = interfaces(interface); if (!all.isEmpty()) { return all.last(); } return AnnouncedInterface{0, 0}; } Registry::Interface Registry::Private::interfaceForName(quint32 name) const { auto it = std::find_if(m_interfaces.constBegin(), m_interfaces.constEnd(), [name] (const InterfaceData &data) { return data.name == name; }); if (it == m_interfaces.constEnd()) { return Interface::Unknown; } return (*it).interface; } bool Registry::hasInterface(Registry::Interface interface) const { return d->hasInterface(interface); } QVector Registry::interfaces(Interface interface) const { return d->interfaces(interface); } Registry::AnnouncedInterface Registry::interface(Interface interface) const { return d->interface(interface); } #define BIND2(__NAME__, __INAME__, __WL__) \ __WL__ *Registry::bind##__NAME__(uint32_t name, uint32_t version) const \ { \ return d->bind<__WL__>(Interface::__INAME__, name, qMin(maxVersion(Interface::__INAME__), version)); \ } #define BIND(__NAME__, __WL__) BIND2(__NAME__, __NAME__, __WL__) BIND(Compositor, wl_compositor) BIND(Output, wl_output) BIND(Seat, wl_seat) BIND(Shell, wl_shell) BIND(Shm, wl_shm) BIND(SubCompositor, wl_subcompositor) BIND(FullscreenShell, _wl_fullscreen_shell) BIND(DataDeviceManager, wl_data_device_manager) BIND(PlasmaShell, org_kde_plasma_shell) BIND(PlasmaWindowManagement, org_kde_plasma_window_management) BIND(Idle, org_kde_kwin_idle) BIND(FakeInput, org_kde_kwin_fake_input) BIND(OutputManagement, org_kde_kwin_outputmanagement) BIND(OutputDevice, org_kde_kwin_outputdevice) BIND(ServerSideDecorationManager, org_kde_kwin_server_decoration_manager) BIND(TextInputManagerUnstableV0, wl_text_input_manager) BIND(TextInputManagerUnstableV2, zwp_text_input_manager_v2) BIND(XdgShellUnstableV5, xdg_shell) BIND(XdgShellUnstableV6, zxdg_shell_v6) BIND(RelativePointerManagerUnstableV1, zwp_relative_pointer_manager_v1) BIND(PointerGesturesUnstableV1, zwp_pointer_gestures_v1) BIND(PointerConstraintsUnstableV1, zwp_pointer_constraints_v1) BIND(XdgExporterUnstableV2, zxdg_exporter_v2) BIND(XdgImporterUnstableV2, zxdg_importer_v2) +BIND(IdleInhibitManagerUnstableV1, zwp_idle_inhibit_manager_v1) BIND2(ShadowManager, Shadow, org_kde_kwin_shadow_manager) BIND2(BlurManager, Blur, org_kde_kwin_blur_manager) BIND2(ContrastManager, Contrast, org_kde_kwin_contrast_manager) BIND2(SlideManager, Slide, org_kde_kwin_slide_manager) BIND2(DpmsManager, Dpms, org_kde_kwin_dpms_manager) #undef BIND #undef BIND2 template T *Registry::Private::create(quint32 name, quint32 version, QObject *parent, WL *(Registry::*bindMethod)(uint32_t, uint32_t) const) { T *t = new T(parent); t->setEventQueue(queue); t->setup((q->*bindMethod)(name, version)); QObject::connect(q, &Registry::interfaceRemoved, t, [t, name] (quint32 removed) { if (name == removed) { emit t->removed(); } } ); QObject::connect(q, &Registry::registryDestroyed, t, &T::destroy); return t; } #define CREATE2(__NAME__, __BINDNAME__) \ __NAME__ *Registry::create##__NAME__(quint32 name, quint32 version, QObject *parent) \ { \ return d->create<__NAME__>(name, version, parent, &Registry::bind##__BINDNAME__); \ } #define CREATE(__NAME__) CREATE2(__NAME__, __NAME__) CREATE(Compositor) CREATE(Seat) CREATE(Shell) CREATE(SubCompositor) CREATE(FullscreenShell) CREATE(Output) CREATE(DataDeviceManager) CREATE(PlasmaShell) CREATE(PlasmaWindowManagement) CREATE(Idle) CREATE(FakeInput) CREATE(OutputManagement) CREATE(OutputDevice) CREATE(ShadowManager) CREATE(BlurManager) CREATE(ContrastManager) CREATE(SlideManager) CREATE(DpmsManager) CREATE(ServerSideDecorationManager) CREATE2(ShmPool, Shm) #undef CREATE #undef CREATE2 XdgExporter *Registry::createXdgExporter(quint32 name, quint32 version, QObject *parent) { //only V1 supported for now return d->create(name, version, parent, &Registry::bindXdgExporterUnstableV2); } XdgImporter *Registry::createXdgImporter(quint32 name, quint32 version, QObject *parent) { //only V1 supported for now return d->create(name, version, parent, &Registry::bindXdgImporterUnstableV2); } TextInputManager *Registry::createTextInputManager(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::TextInputManagerUnstableV0: return d->create(name, version, parent, &Registry::bindTextInputManagerUnstableV0); case Interface::TextInputManagerUnstableV2: return d->create(name, version, parent, &Registry::bindTextInputManagerUnstableV2); default: return nullptr; } } XdgShell *Registry::createXdgShell(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::XdgShellUnstableV5: return d->create(name, version, parent, &Registry::bindXdgShellUnstableV5); case Interface::XdgShellUnstableV6: return d->create(name, version, parent, &Registry::bindXdgShellUnstableV6); default: return nullptr; } } RelativePointerManager *Registry::createRelativePointerManager(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::RelativePointerManagerUnstableV1: return d->create(name, version, parent, &Registry::bindRelativePointerManagerUnstableV1); default: return nullptr; } } PointerGestures *Registry::createPointerGestures(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::PointerGesturesUnstableV1: return d->create(name, version, parent, &Registry::bindPointerGesturesUnstableV1); default: return nullptr; } } PointerConstraints *Registry::createPointerConstraints(quint32 name, quint32 version, QObject *parent) { switch (d->interfaceForName(name)) { case Interface::PointerConstraintsUnstableV1: return d->create(name, version, parent, &Registry::bindPointerConstraintsUnstableV1); default: return nullptr; } } +IdleInhibitManager *Registry::createIdleInhibitManager(quint32 name, quint32 version, QObject *parent) +{ + switch (d->interfaceForName(name)) { + case Interface::IdleInhibitManagerUnstableV1: + return d->create(name, version, parent, &Registry::bindIdleInhibitManagerUnstableV1); + default: + return nullptr; + } +} + namespace { static const wl_interface *wlInterface(Registry::Interface interface) { auto it = s_interfaces.find(interface); if (it != s_interfaces.end()) { return it.value().interface; } return nullptr; } } template T *Registry::Private::bind(Registry::Interface interface, uint32_t name, uint32_t version) const { auto it = std::find_if(m_interfaces.begin(), m_interfaces.end(), [=](const InterfaceData &data) { return data.interface == interface && data.name == name && data.version >= version; }); if (it == m_interfaces.end()) { qCDebug(KWAYLAND_CLIENT) << "Don't have interface " << int(interface) << "with name " << name << "and minimum version" << version; return nullptr; } auto t = reinterpret_cast(wl_registry_bind(registry, name, wlInterface(interface), version)); if (queue) { queue->addProxy(t); } return t; } bool Registry::isValid() const { return d->registry.isValid(); } wl_registry *Registry::registry() { return d->registry; } Registry::operator wl_registry*() const { return d->registry; } Registry::operator wl_registry*() { return d->registry; } } } diff --git a/src/client/registry.h b/src/client/registry.h index 8443973..82f485a 100644 --- a/src/client/registry.h +++ b/src/client/registry.h @@ -1,1433 +1,1476 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_REGISTRY_H #define WAYLAND_REGISTRY_H #include #include #include struct wl_compositor; struct wl_data_device_manager; struct wl_display; struct wl_output; struct wl_registry; struct wl_seat; struct wl_shell; struct wl_shm; struct wl_subcompositor; struct wl_text_input_manager; struct zwp_text_input_manager_v2; struct _wl_fullscreen_shell; struct org_kde_kwin_outputmanagement; struct org_kde_kwin_outputdevice; struct org_kde_kwin_fake_input; struct org_kde_kwin_idle; struct org_kde_kwin_dpms_manager; struct org_kde_kwin_shadow_manager; struct org_kde_kwin_blur_manager; struct org_kde_kwin_contrast_manager; struct org_kde_kwin_slide_manager; struct org_kde_plasma_shell; struct org_kde_plasma_window_management; struct org_kde_kwin_server_decoration_manager; struct xdg_shell; struct zxdg_shell_v6; struct zwp_relative_pointer_manager_v1; struct zwp_pointer_gestures_v1; struct zwp_pointer_constraints_v1; struct zxdg_exporter_v2; struct zxdg_importer_v2; +struct zwp_idle_inhibit_manager_v1; namespace KWayland { namespace Client { class Compositor; class ConnectionThread; class DataDeviceManager; class DpmsManager; class EventQueue; class FakeInput; class FullscreenShell; class OutputManagement; class OutputDevice; class Idle; +class IdleInhibitManager; class Output; class PlasmaShell; class PlasmaWindowManagement; class PointerConstraints; class PointerGestures; class Seat; class ShadowManager; class BlurManager; class ContrastManager; class SlideManager; class Shell; class ShmPool; class ServerSideDecorationManager; class SubCompositor; class TextInputManager; class TextInputManagerUnstableV0; class TextInputManagerUnstableV2; class XdgShell; class RelativePointerManager; class XdgExporterUnstableV2; class XdgImporterUnstableV2; class XdgExporter; class XdgImporter; /** * @short Wrapper for the wl_registry interface. * * The purpose of this class is to manage the wl_registry interface. * This class supports some well-known interfaces and can create a * wrapper class for those. * * The main purpose is to emit signals whenever a new interface is * added or an existing interface is removed. For the well known interfaces * dedicated signals are emitted allowing a user to connect directly to the * signal announcing the interface it is interested in. * * To create and setup the Registry one needs to call create with either a * wl_display from an existing Wayland connection or a ConnectionThread instance: * * @code * ConnectionThread *connection; // existing connection * Registry registry; * registry.create(connection); * registry.setup(); * @endcode * * The interfaces are announced in an asynchronous way by the Wayland server. * To initiate the announcing of the interfaces one needs to call setup. **/ class KWAYLANDCLIENT_EXPORT Registry : public QObject { Q_OBJECT public: /** * The well-known interfaces this Registry supports. * For each of the enum values the Registry is able to create a Wrapper * object. **/ enum class Interface { Unknown, ///< Refers to an Unknown interface Compositor, ///< Refers to the wl_compositor interface Shell, ///< Refers to the wl_shell interface Seat, ///< Refers to the wl_seat interface Shm, ///< Refers to the wl_shm interface Output, ///< Refers to the wl_output interface FullscreenShell, ///< Refers to the _wl_fullscreen_shell interface SubCompositor, ///< Refers to the wl_subcompositor interface; DataDeviceManager, ///< Refers to the wl_data_device_manager interface PlasmaShell, ///< Refers to org_kde_plasma_shell interface PlasmaWindowManagement, ///< Refers to org_kde_plasma_window_management interface Idle, ///< Refers to org_kde_kwin_idle_interface interface FakeInput, ///< Refers to org_kde_kwin_fake_input interface Shadow, ///< Refers to org_kde_kwin_shadow_manager interface Blur, ///< refers to org_kde_kwin_blur_manager interface Contrast, ///< refers to org_kde_kwin_contrast_manager interface Slide, ///< refers to org_kde_kwin_slide_manager Dpms, ///< Refers to org_kde_kwin_dpms_manager interface OutputManagement, ///< Refers to the wl_data_device_manager interface OutputDevice, ///< Refers to the org_kde_kwin_outputdevice interface ServerSideDecorationManager, ///< Refers to org_kde_kwin_server_decoration_manager TextInputManagerUnstableV0, ///< Refers to wl_text_input_manager, @since 5.23 TextInputManagerUnstableV2, ///< Refers to zwp_text_input_manager_v2, @since 5.23 XdgShellUnstableV5, ///< Refers to xdg_shell (unstable version 5), @since 5.25 RelativePointerManagerUnstableV1, ///< Refers to zwp_relative_pointer_manager_v1, @since 5.28 PointerGesturesUnstableV1, ///< Refers to zwp_pointer_gestures_v1, @since 5.29 PointerConstraintsUnstableV1, ///< Refers to zwp_pointer_constraints_v1, @since 5.29 XdgExporterUnstableV2, ///< refers to zxdg_exporter_v2, @since 5.40 XdgImporterUnstableV2, ///< refers to zxdg_importer_v2, @since 5.40 - XdgShellUnstableV6 ///< Refers to zxdg_shell_v6 (unstable version 6), @since 5.XX + XdgShellUnstableV6, ///< Refers to zxdg_shell_v6 (unstable version 6), @since 5.XX + IdleInhibitManagerUnstableV1 ///< Refers to zwp_idle_inhibit_manager_v1 (unstable version 1), @since 5.41 }; explicit Registry(QObject *parent = nullptr); virtual ~Registry(); /** * Releases the wl_registry interface. * After the interface has been released the Registry instance is no * longer valid and can be setup with another wl_registry interface. **/ void release(); /** * Destroys the data held by this Registry. * This method is supposed to be used when the connection to the Wayland * server goes away. If the connection is not valid anymore, it's not * possible to call release anymore as that calls into the Wayland * connection and the call would fail. This method cleans up the data, so * that the instance can be deleted or set up to a new wl_registry interface * once there is a new connection available. * * It is suggested to connect this method to ConnectionThread::connectionDied: * @code * connect(connection, &ConnectionThread::connectionDied, registry, &Registry::destroy); * @endcode * * @see release **/ void destroy(); /** * Gets the registry from the @p display. **/ void create(wl_display *display); /** * Gets the registry from the @p connection. **/ void create(ConnectionThread *connection); /** * Finalizes the setup of the Registry. * After calling this method the interfaces will be announced in an asynchronous way. * The Registry must have been created when calling this method. * @see create **/ void setup(); /** * Sets the @p queue to use for this Registry. * * The EventQueue should be set before the Registry gets setup. * The EventQueue gets automatically added to all interfaces created by * this Registry. So that all objects are in teh same EventQueue. * * @param queue The event queue to use for this Registry. **/ void setEventQueue(EventQueue *queue); /** * @returns The EventQueue used by this Registry **/ EventQueue *eventQueue(); /** * @returns @c true if managing a wl_registry. **/ bool isValid() const; /** * @returns @c true if the Registry has an @p interface. **/ bool hasInterface(Interface interface) const; /** * Representation of one announced interface. **/ struct AnnouncedInterface { /** * The name of the announced interface. **/ quint32 name; /** * The maximum supported version of the announced interface. **/ quint32 version; }; /** * Provides name and version for the @p interface. * * The first value of the returned pair is the "name", the second value is the "version". * If the @p interface has not been announced, both values are set to 0. * If there @p interface has been announced multiple times, the last announced is returned. * In case one is interested in all announced interfaces, one should prefer @link interfaces(Interface) @endlink. * * The returned information can be passed into the bind or create methods. * * @param interface The well-known interface for which the name and version should be retrieved * @returns name and version of the given interface * @since 5.5 **/ AnnouncedInterface interface(Interface interface) const; /** * Provides all pairs of name and version for the well-known @p interface. * * If the @p interface has not been announced, an empty vector is returned. * * The returned information can be passed into the bind or create methods. * * @param interface The well-known interface for which the name and version should be retrieved * @returns All pairs of name and version of the given interface * @since 5.5 **/ QVector interfaces(Interface interface) const; /** * @name Low-level bind methods for global interfaces. **/ ///@{ /** * Binds the wl_compositor with @p name and @p version. * If the @p name does not exist or is not for the compositor interface, * @c null will be returned. * * Prefer using createCompositor instead. * @see createCompositor **/ wl_compositor *bindCompositor(uint32_t name, uint32_t version) const; /** * Binds the wl_shell with @p name and @p version. * If the @p name does not exist or is not for the shell interface, * @c null will be returned. * * Prefer using createShell instead. * @see createShell **/ wl_shell *bindShell(uint32_t name, uint32_t version) const; /** * Binds the wl_seat with @p name and @p version. * If the @p name does not exist or is not for the seat interface, * @c null will be returned. * * Prefer using createSeat instead. * @see createSeat **/ wl_seat *bindSeat(uint32_t name, uint32_t version) const; /** * Binds the wl_shm with @p name and @p version. * If the @p name does not exist or is not for the shm interface, * @c null will be returned. * * Prefer using createShmPool instead. * @see createShmPool **/ wl_shm *bindShm(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_outputmanagement with @p name and @p version. * If the @p name does not exist or is not for the outputmanagement interface, * @c null will be returned. * * Prefer using createOutputManagement instead. * @see createOutputManagement **/ org_kde_kwin_outputmanagement *bindOutputManagement(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_outputdevice with @p name and @p version. * If the @p name does not exist or is not for the outputdevice interface, * @c null will be returned. * * Prefer using createOutputDevice instead. * @see createOutputDevice **/ wl_output *bindOutput(uint32_t name, uint32_t version) const; /** * Binds the wl_subcompositor with @p name and @p version. * If the @p name does not exist or is not for the subcompositor interface, * @c null will be returned. * * Prefer using createSubCompositor instead. * @see createSubCompositor **/ wl_subcompositor *bindSubCompositor(uint32_t name, uint32_t version) const; /** * Binds the wl_output with @p name and @p version. * If the @p name does not exist or is not for the output interface, * @c null will be returned. * * Prefer using createOutput instead. * @see createOutput * @since 5.5 **/ org_kde_kwin_outputdevice *bindOutputDevice(uint32_t name, uint32_t version) const; /** * Binds the _wl_fullscreen_shell with @p name and @p version. * If the @p name does not exist or is not for the fullscreen shell interface, * @c null will be returned. * * Prefer using createFullscreenShell instead. * @see createFullscreenShell **/ _wl_fullscreen_shell *bindFullscreenShell(uint32_t name, uint32_t version) const; /** * Binds the wl_data_device_manager with @p name and @p version. * If the @p name does not exist or is not for the data device manager interface, * @c null will be returned. * * Prefer using createDataDeviceManager instead. * @see createDataDeviceManager **/ wl_data_device_manager *bindDataDeviceManager(uint32_t name, uint32_t version) const; /** * Binds the org_kde_plasma_shell with @p name and @p version. * If the @p name does not exist or is not for the Plasma shell interface, * @c null will be returned. * * Prefer using createPlasmaShell instead. * @see createPlasmaShell * @since 5.4 **/ org_kde_plasma_shell *bindPlasmaShell(uint32_t name, uint32_t version) const; /** * Binds the org_kde_plasma_window_management with @p name and @p version. * If the @p name does not exist or is not for the Plasma window management interface, * @c null will be returned. * * Prefer using createPlasmaWindowManagement instead. * @see createPlasmaWindowManagement * @since 5.4 **/ org_kde_plasma_window_management *bindPlasmaWindowManagement(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_idle with @p name and @p version. * If the @p name does not exist or is not for the idle interface, * @c null will be returned. * * Prefer using createIdle instead. * @see createIdle * @since 5.4 **/ org_kde_kwin_idle *bindIdle(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_fake_input with @p name and @p version. * If the @p name does not exist or is not for the fake input interface, * @c null will be returned. * * Prefer using createFakeInput instead. * @see createFakeInput * @since 5.4 **/ org_kde_kwin_fake_input *bindFakeInput(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_shadow_manager with @p name and @p version. * If the @p name does not exist or is not for the shadow manager interface, * @c null will be returned. * * Prefer using createShadowManager instead. * @see createShadowManager * @since 5.4 **/ org_kde_kwin_shadow_manager *bindShadowManager(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_blur_manager with @p name and @p version. * If the @p name does not exist or is not for the blur manager interface, * @c null will be returned. * * Prefer using createBlurManager instead. * @see createBlurManager * @since 5.5 **/ org_kde_kwin_blur_manager *bindBlurManager(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_contrast_manager with @p name and @p version. * If the @p name does not exist or is not for the contrast manager interface, * @c null will be returned. * * Prefer using createContrastManager instead. * @see createContrastManager * @since 5.5 **/ org_kde_kwin_contrast_manager *bindContrastManager(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_slide_manager with @p name and @p version. * If the @p name does not exist or is not for the slide manager interface, * @c null will be returned. * * Prefer using createSlideManager instead. * @see createSlideManager * @since 5.5 **/ org_kde_kwin_slide_manager * bindSlideManager(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_dpms_manager with @p name and @p version. * If the @p name does not exist or is not for the dpms manager interface, * @c null will be returned. * * Prefer using createDpmsManager instead. * @see createDpmsManager * @since 5.5 **/ org_kde_kwin_dpms_manager *bindDpmsManager(uint32_t name, uint32_t version) const; /** * Binds the org_kde_kwin_server_decoration_manager with @p name and @p version. * If the @p name does not exist or is not for the server side decoration manager interface, * @c null will be returned. * * Prefer using createServerSideDecorationManager instead. * @see createServerSideDecorationManager * @since 5.6 **/ org_kde_kwin_server_decoration_manager *bindServerSideDecorationManager(uint32_t name, uint32_t version) const; /** * Binds the wl_text_input_manager with @p name and @p version. * If the @p name does not exist or is not for the text input interface in unstable version 0, * @c null will be returned. * * Prefer using createTextInputManager instead. * @see createTextInputManager * @since 5.23 **/ wl_text_input_manager *bindTextInputManagerUnstableV0(uint32_t name, uint32_t version) const; /** * Binds the zwp_text_input_manager_v2 with @p name and @p version. * If the @p name does not exist or is not for the text input interface in unstable version 2, * @c null will be returned. * * Prefer using createTextInputManager instead. * @see createTextInputManager * @since 5.23 **/ zwp_text_input_manager_v2 *bindTextInputManagerUnstableV2(uint32_t name, uint32_t version) const; /** * Binds the xdg_shell (unstable version 5) with @p name and @p version. * If the @p name does not exist or is not for the xdg shell interface in unstable version 5, * @c null will be returned. * * Prefer using createXdgShell instead. * @see createXdgShell * @since 5.25 **/ xdg_shell *bindXdgShellUnstableV5(uint32_t name, uint32_t version) const; /** * Binds the zxdg_shell_v6 (unstable version 6) with @p name and @p version. * If the @p name does not exist or is not for the xdg shell interface in unstable version 5, * @c null will be returned. * * Prefer using createXdgShell instead. * @see createXdgShell * @since 5.39 **/ zxdg_shell_v6 *bindXdgShellUnstableV6(uint32_t name, uint32_t version) const; /** * Binds the zwp_relative_pointer_manager_v1 with @p name and @p version. * If the @p name does not exist or is not for the relative pointer interface in unstable version 1, * @c null will be returned. * * Prefer using createRelativePointerManager instead. * @see createRelativePointerManager * @since 5.28 **/ zwp_relative_pointer_manager_v1 *bindRelativePointerManagerUnstableV1(uint32_t name, uint32_t version) const; /** * Binds the zwp_pointer_gestures_v1 with @p name and @p version. * If the @p name does not exist or is not for the pointer gestures interface in unstable version 1, * @c null will be returned. * * Prefer using createPointerGestures instead. * @see createPointerGestures * @since 5.29 **/ zwp_pointer_gestures_v1 *bindPointerGesturesUnstableV1(uint32_t name, uint32_t version) const; /** * Binds the zwp_pointer_constraints_v1 with @p name and @p version. * If the @p name does not exist or is not for the pointer constraints interface in unstable version 1, * @c null will be returned. * * Prefer using createPointerConstraints instead. * @see createPointerConstraints * @since 5.29 **/ zwp_pointer_constraints_v1 *bindPointerConstraintsUnstableV1(uint32_t name, uint32_t version) const; /** * Binds the zxdg_exporter_v2 with @p name and @p version. * If the @p name does not exists or isnot for the exporter * extension in unstable version 1, * @c null will be returned. * * Prefer using createXdgExporter * @since 5.40 */ zxdg_exporter_v2 *bindXdgExporterUnstableV2(uint32_t name, uint32_t version) const; /** * Binds the zxdg_importer_v2 with @p name and @p version. * If the @p name does not exists or isnot for the importer * extension in unstable version 1, * @c null will be returned. * * Prefer using createXdgImporter * @since 5.40 */ zxdg_importer_v2 *bindXdgImporterUnstableV2(uint32_t name, uint32_t version) const; + + /** + * Binds the zwp_idle_inhibit_manager_v1 with @p name and @p version. + * If the @p name does not exists or is not for the idle inhibit manager in unstable version 1, + * @c null will be returned. + * + * Prefer using createIdleInhibitManager + * @since 5.41 + */ + zwp_idle_inhibit_manager_v1 *bindIdleInhibitManagerUnstableV1(uint32_t name, uint32_t version) const; ///@} /** * @name Convenient factory methods for global objects. **/ ///@{ /** * Creates a Compositor and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_compositor interface, * the returned Compositor will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_compositor interface to bind * @param version The version or the wl_compositor interface to use * @param parent The parent for Compositor * * @returns The created Compositor. **/ Compositor *createCompositor(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a Seat and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_seat interface, * the returned Seat will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_seat interface to bind * @param version The version or the wl_seat interface to use * @param parent The parent for Seat * * @returns The created Seat. **/ Shell *createShell(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a Compositor and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_compositor interface, * the returned Compositor will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_compositor interface to bind * @param version The version or the wl_compositor interface to use * @param parent The parent for Compositor * * @returns The created Compositor. **/ Seat *createSeat(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a ShmPool and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_shm interface, * the returned ShmPool will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_shm interface to bind * @param version The version or the wl_shm interface to use * @param parent The parent for ShmPool * * @returns The created ShmPool. **/ ShmPool *createShmPool(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a SubCompositor and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_subcompositor interface, * the returned SubCompositor will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_subcompositor interface to bind * @param version The version or the wl_subcompositor interface to use * @param parent The parent for SubCompositor * * @returns The created SubCompositor. **/ SubCompositor *createSubCompositor(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an Output and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_output interface, * the returned Output will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_output interface to bind * @param version The version or the wl_output interface to use * @param parent The parent for Output * * @returns The created Output. **/ Output *createOutput(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an KWinOutputManagement and sets it up to manage the interface identified * by @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_output interface, * the returned KWinConnectors will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_outputmanagement interface to bind * @param version The version or the org_kde_kwin_outputmanagement interface to use * @param parent The parent for KWinOutputManagement * * @returns The created KWinOutputManagement. * @since 5.5 **/ OutputManagement *createOutputManagement(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an OutputDevice and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_outputdevice interface, * the returned OutputDevice will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_outputdevice interface to bind * @param version The version or the org_kde_kwin_outputdevice interface to use * @param parent The parent for OutputDevice * * @returns The created Output. * @since 5.5 **/ OutputDevice *createOutputDevice(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a FullscreenShell and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the _wl_fullscreen_shell interface, * the returned FullscreenShell will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the _wl_fullscreen_shell interface to bind * @param version The version or the _wl_fullscreen_shell interface to use * @param parent The parent for FullscreenShell * * @returns The created FullscreenShell. * @since 5.5 **/ FullscreenShell *createFullscreenShell(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a DataDeviceManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the wl_data_device_manager interface, * the returned DataDeviceManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the wl_data_device_manager interface to bind * @param version The version or the wl_data_device_manager interface to use * @param parent The parent for DataDeviceManager * * @returns The created DataDeviceManager. **/ DataDeviceManager *createDataDeviceManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a PlasmaShell and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_plasma_shell interface, * the returned PlasmaShell will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_plasma_shell interface to bind * @param version The version or the org_kde_plasma_shell interface to use * @param parent The parent for PlasmaShell * * @returns The created PlasmaShell. * @since 5.4 **/ PlasmaShell *createPlasmaShell(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a PlasmaWindowManagement and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_plasma_window_management interface, * the returned PlasmaWindowManagement will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_plasma_window_management interface to bind * @param version The version or the org_kde_plasma_window_management interface to use * @param parent The parent for PlasmaWindowManagement * * @returns The created PlasmaWindowManagement. * @since 5.4 **/ PlasmaWindowManagement *createPlasmaWindowManagement(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an Idle and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_idle interface, * the returned Idle will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_idle interface to bind * @param version The version or the org_kde_kwin_idle interface to use * @param parent The parent for Idle * * @returns The created Idle. * @since 5.4 **/ Idle *createIdle(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a FakeInput and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_fake_input interface, * the returned FakeInput will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_fake_input interface to bind * @param version The version or the org_kde_kwin_fake_input interface to use * @param parent The parent for FakeInput * * @returns The created FakeInput. * @since 5.4 **/ FakeInput *createFakeInput(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a ShadowManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_shadow_manager interface, * the returned ShadowManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_shadow_manager interface to bind * @param version The version or the org_kde_kwin_shadow_manager interface to use * @param parent The parent for ShadowManager * * @returns The created ShadowManager. * @since 5.4 **/ ShadowManager *createShadowManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a BlurManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_blur_manager interface, * the returned BlurManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_blur_manager interface to bind * @param version The version or the org_kde_kwin_blur_manager interface to use * @param parent The parent for BlurManager * * @returns The created BlurManager. * @since 5.5 **/ BlurManager *createBlurManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a ContrastManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_contrast_manager interface, * the returned ContrastManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_contrast_manager interface to bind * @param version The version or the org_kde_kwin_contrast_manager interface to use * @param parent The parent for ContrastManager * * @returns The created ContrastManager. * @since 5.5 **/ ContrastManager *createContrastManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a SlideManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_slide_manager interface, * the returned SlideManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_slide_manager interface to bind * @param version The version or the org_kde_kwin_slide_manager interface to use * @param parent The parent for SlideManager * * @returns The created SlideManager. * @since 5.5 **/ SlideManager *createSlideManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a DpmsManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_dpms_manager interface, * the returned DpmsManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_dpms_manager interface to bind * @param version The version or the org_kde_kwin_dpms_manager interface to use * @param parent The parent for DpmsManager * * @returns The created DpmsManager. * @since 5.5 **/ DpmsManager *createDpmsManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a ServerSideDecorationManager and sets it up to manage the interface identified by * @p name and @p version. * * Note: in case @p name is invalid or isn't for the org_kde_kwin_server_decoration_manager interface, * the returned ServerSideDecorationManager will not be valid. Therefore it's recommended to call * isValid on the created instance. * * @param name The name of the org_kde_kwin_server_decoration_manager interface to bind * @param version The version or the org_kde_kwin_server_decoration_manager interface to use * @param parent The parent for ServerSideDecorationManager * * @returns The created ServerSideDecorationManager. * @since 5.6 **/ ServerSideDecorationManager *createServerSideDecorationManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a TextInputManager and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li wl_text_input_manager * @li zwp_text_input_manager_v2 * * If @p name is for one of the supported interfaces the corresponding manager will be created, * otherwise @c null will be returned. * * @param name The name of the interface to bind * @param version The version of the interface to use * @param parent The parent for the TextInputManager * * @returns The created TextInputManager * @since 5.23 **/ TextInputManager *createTextInputManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an XdgShell and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li xdg_shell (Unstable version 5) * * If @p name is for one of the supported interfaces the corresponding shell will be created, * otherwise @c null will be returned. * * @param name The name of the interface to bind * @param version The version of the interface to use * @param parent The parent for the XdgShell * * @returns The created XdgShell * @since 5.25 **/ XdgShell *createXdgShell(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a RelativePointerManager and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li zwp_relative_pointer_manager_v1 * * If @p name is for one of the supported interfaces the corresponding manager will be created, * otherwise @c null will be returned. * * @param name The name of the interface to bind * @param version The version of the interface to use * @param parent The parent for the RelativePointerManager * * @returns The created RelativePointerManager * @since 5.28 **/ RelativePointerManager *createRelativePointerManager(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a PointerGestures and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li zwp_pointer_gestures_v1 * * If @p name is for one of the supported interfaces the corresponding manager will be created, * otherwise @c null will be returned. * * @param name The name of the interface to bind * @param version The version of the interface to use * @param parent The parent for the PointerGestures * * @returns The created PointerGestures * @since 5.29 **/ PointerGestures *createPointerGestures(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates a PointerConstraints and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li zwp_pointer_constraints_v1 * * If @p name is for one of the supported interfaces the corresponding manager will be created, * otherwise @c null will be returned. * * @param name The name of the interface to bind * @param version The version of the interface to use * @param parent The parent for the PointerConstraints * * @returns The created PointerConstraints * @since 5.29 **/ PointerConstraints *createPointerConstraints(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an XdgExporter and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li zxdg_exporter_v2 * * If @p name is for one of the supported interfaces the corresponding manager will be created, * otherwise @c null will be returned. * * @returns The created XdgExporter * @since 5.40 */ XdgExporter *createXdgExporter(quint32 name, quint32 version, QObject *parent = nullptr); /** * Creates an XdgImporter and sets it up to manage the interface identified by * @p name and @p version. * * This factory method supports the following interfaces: * @li zxdg_importer_v2 * * If @p name is for one of the supported interfaces the corresponding manager will be created, * otherwise @c null will be returned. * * @returns The created XdgImporter * @since 5.40 */ XdgImporter *createXdgImporter(quint32 name, quint32 version, QObject *parent = nullptr); + + /** + * Creates an IdleInhibitManager and sets it up to manage the interface identified by + * @p name and @p version. + * + * This factory method supports the following interfaces: + * @li zwp_idle_inhibit_manager_v1 + * + * If @p name is for one of the supported interfaces the corresponding manager will be created, + * otherwise @c null will be returned. + * + * @returns The created IdleInhibitManager + * @since 5.41 + */ + IdleInhibitManager *createIdleInhibitManager(quint32 name, quint32 version, QObject *parent = nullptr); ///@} /** * cast operator to the low-level Wayland @c wl_registry **/ operator wl_registry*(); /** * cast operator to the low-level Wayland @c wl_registry **/ operator wl_registry*() const; /** * @returns access to the low-level Wayland @c wl_registry **/ wl_registry *registry(); Q_SIGNALS: /** * @name Interface announced signals. **/ ///@{ /** * Emitted whenever a wl_compositor interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void compositorAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_shell interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void shellAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_seat interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void seatAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_shm interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void shmAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_subcompositor interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void subCompositorAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_output interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void outputAnnounced(quint32 name, quint32 version); /** * Emitted whenever a _wl_fullscreen_shell interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void fullscreenShellAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_data_device_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void dataDeviceManagerAnnounced(quint32 name, quint32 version); void outputManagementAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_outputdevice interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.5 **/ void outputDeviceAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_plasma_shell interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.4 **/ void plasmaShellAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_plasma_window_management interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.4 **/ void plasmaWindowManagementAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_idle interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.4 **/ void idleAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_fake_input interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.4 **/ void fakeInputAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_shadow_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.4 **/ void shadowAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_blur_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.5 **/ void blurAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_contrast_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.5 **/ void contrastAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_slide_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.5 **/ void slideAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_dpms_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.5 **/ void dpmsAnnounced(quint32 name, quint32 version); /** * Emitted whenever a org_kde_kwin_server_decoration_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.6 **/ void serverSideDecorationManagerAnnounced(quint32 name, quint32 version); /** * Emitted whenever a wl_text_input_manager interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.23 **/ void textInputManagerUnstableV0Announced(quint32 name, quint32 version); /** * Emitted whenever a zwp_text_input_manager_v2 interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.23 **/ void textInputManagerUnstableV2Announced(quint32 name, quint32 version); /** * Emitted whenever a xdg_shell (unstable version 5) interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.25 **/ void xdgShellUnstableV5Announced(quint32 name, quint32 version); /** * Emitted whenever a zxdg_shell_v6 (unstable version 6) interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.25 **/ void xdgShellUnstableV6Announced(quint32 name, quint32 version); /** * Emitted whenever a zwp_relative_pointer_manager_v1 interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.28 **/ void relativePointerManagerUnstableV1Announced(quint32 name, quint32 version); /** * Emitted whenever a zwp_pointer_gestures_v1 interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.29 **/ void pointerGesturesUnstableV1Announced(quint32 name, quint32 version); /** * Emitted whenever a zwp_pointer_constraints_v1 interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.29 **/ void pointerConstraintsUnstableV1Announced(quint32 name, quint32 version); /** * Emitted whenever a zxdg_exporter_v2 interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.40 */ void exporterUnstableV2Announced(quint32 name, quint32 version); /** * Emitted whenever a zxdg_importer_v2 interface gets announced. * @param name The name for the announced interface * @param version The maximum supported version of the announced interface * @since 5.40 */ void importerUnstableV2Announced(quint32 name, quint32 version); + + /** + * Emitted whenever a zwp_idle_inhibit_manager_v1 interface gets announced. + * @param name The name for the announced interface + * @param version The maximum supported version of the announced interface + * @since 5.41 + */ + void idleInhibitManagerUnstableV1Announced(quint32 name, quint32 version); ///@} /** * @name Interface removed signals. **/ ///@{ /** * Emitted whenever a wl_compositor interface gets removed. * @param name The name for the removed interface **/ void compositorRemoved(quint32 name); /** * Emitted whenever a wl_shell interface gets removed. * @param name The name for the removed interface **/ void shellRemoved(quint32 name); /** * Emitted whenever a wl_seat interface gets removed. * @param name The name for the removed interface **/ void seatRemoved(quint32 name); /** * Emitted whenever a wl_shm interface gets removed. * @param name The name for the removed interface **/ void shmRemoved(quint32 name); /** * Emitted whenever a wl_subcompositor interface gets removed. * @param name The name for the removed interface **/ void subCompositorRemoved(quint32 name); /** * Emitted whenever a wl_output interface gets removed. * @param name The name for the removed interface **/ void outputRemoved(quint32 name); /** * Emitted whenever a _wl_fullscreen_shell interface gets removed. * @param name The name for the removed interface **/ void fullscreenShellRemoved(quint32 name); /** * Emitted whenever a wl_data_device_manager interface gets removed. * @param name The name for the removed interface **/ void dataDeviceManagerRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_outputmanagement interface gets removed. * @param name The name for the removed interface * @since 5.5 **/ void outputManagementRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_outputdevice interface gets removed. * @param name The name for the removed interface * @since 5.5 **/ void outputDeviceRemoved(quint32 name); /** * Emitted whenever a org_kde_plasma_shell interface gets removed. * @param name The name for the removed interface * @since 5.4 **/ void plasmaShellRemoved(quint32 name); /** * Emitted whenever a org_kde_plasma_window_management interface gets removed. * @param name The name for the removed interface * @since 5.4 **/ void plasmaWindowManagementRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_idle interface gets removed. * @param name The name for the removed interface * @since 5.4 **/ void idleRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_fake_input interface gets removed. * @param name The name for the removed interface * @since 5.4 **/ void fakeInputRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_shadow_manager interface gets removed. * @param name The name for the removed interface * @since 5.4 **/ void shadowRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_blur_manager interface gets removed. * @param name The name for the removed interface * @since 5.5 **/ void blurRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_contrast_manager interface gets removed. * @param name The name for the removed interface * @since 5.5 **/ void contrastRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_slide_manager interface gets removed. * @param name The name for the removed interface * @since 5.5 **/ void slideRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_dpms_manager interface gets removed. * @param name The name for the removed interface * @since 5.5 **/ void dpmsRemoved(quint32 name); /** * Emitted whenever a org_kde_kwin_server_decoration_manager interface gets removed. * @param name The name for the removed interface * @since 5.6 **/ void serverSideDecorationManagerRemoved(quint32 name); /** * Emitted whenever a wl_text_input_manager interface gets removed. * @param name The name for the removed interface * @since 5.23 **/ void textInputManagerUnstableV0Removed(quint32 name); /** * Emitted whenever a zwp_text_input_manager_v2 interface gets removed. * @param name The name for the removed interface * @since 5.23 **/ void textInputManagerUnstableV2Removed(quint32 name); /** * Emitted whenever an xdg_shell (unstable version 5) interface gets removed. * @param name The name for the removed interface * @since 5.25 **/ void xdgShellUnstableV5Removed(quint32 name); /** * Emitted whenever an xdg_shell (unstable version 5) interface gets removed. * @param name The name for the removed interface * @since 5.25 **/ void xdgShellUnstableV6Removed(quint32 name); /** * Emitted whenever a zwp_relative_pointer_manager_v1 interface gets removed. * @param name The name for the removed interface * @since 5.28 **/ void relativePointerManagerUnstableV1Removed(quint32 name); /** * Emitted whenever a zwp_pointer_gestures_v1 interface gets removed. * @param name The name for the removed interface * @since 5.29 **/ void pointerGesturesUnstableV1Removed(quint32 name); /** * Emitted whenever a zwp_pointer_constraints_v1 interface gets removed. * @param name The name for the removed interface * @since 5.29 **/ void pointerConstraintsUnstableV1Removed(quint32 name); /** * Emitted whenever a zxdg_exporter_v2 interface gets removed. * @param name The name for the removed interface * @since 5.40 **/ void exporterUnstableV2Removed(quint32 name); /** * Emitted whenever a zxdg_importer_v2 interface gets removed. * @param name The name for the removed interface * @since 5.40 **/ void importerUnstableV2Removed(quint32 name); + + /** + * Emitted whenever a zwp_idle_inhibit_manager_v1 interface gets removed. + * @param name The name of the removed interface + * @since 5.41 + **/ + void idleInhibitManagerUnstableV1Removed(quint32 name); ///@} /** * Generic announced signal which gets emitted whenever an interface gets * announced. * * This signal is emitted before the dedicated signals are handled. If one * wants to know about one of the well-known interfaces use the dedicated * signals instead. Especially the bind methods might fail before the dedicated * signals are emitted. * * @param interface The interface (e.g. wl_compositor) which is announced * @param name The name for the announced interface * @param version The maximum supported version of the announced interface **/ void interfaceAnnounced(QByteArray interface, quint32 name, quint32 version); /** * Generic removal signal which gets emitted whenever an interface gets removed. * * This signal is emitted after the dedicated signals are handled. * * @param name The name for the removed interface **/ void interfaceRemoved(quint32 name); /** * Emitted when the Wayland display is done flushing the initial interface * callbacks, announcing wl_display properties. This can be used to compress * events. Note that this signal is emitted only after announcing interfaces, * such as outputs, but not after receiving callbacks of interface properties, * such as the output's geometry, modes, etc.. * This signal is emitted from the wl_display_sync callback. **/ void interfacesAnnounced(); Q_SIGNALS: /* * Emitted when the registry has been destroyed rather than released */ void registryDestroyed(); private: class Private; QScopedPointer d; }; } } #endif diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt index 6fd3593..0d9d248 100644 --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -1,240 +1,248 @@ set(SERVER_LIB_SRCS buffer_interface.cpp clientconnection.cpp compositor_interface.cpp datadevice_interface.cpp datadevicemanager_interface.cpp dataoffer_interface.cpp datasource_interface.cpp display.cpp dpms_interface.cpp global.cpp idle_interface.cpp + idleinhibit_interface.cpp + idleinhibit_interface_v1.cpp fakeinput_interface.cpp keyboard_interface.cpp outputconfiguration_interface.cpp outputchangeset.cpp outputmanagement_interface.cpp outputdevice_interface.cpp logging.cpp output_interface.cpp pointer_interface.cpp plasmashell_interface.cpp plasmawindowmanagement_interface.cpp pointerconstraints_interface.cpp pointerconstraints_interface_v1.cpp pointergestures_interface.cpp pointergestures_interface_v1.cpp qtsurfaceextension_interface.cpp region_interface.cpp relativepointer_interface.cpp relativepointer_interface_v1.cpp resource.cpp seat_interface.cpp slide_interface.cpp shadow_interface.cpp blur_interface.cpp contrast_interface.cpp server_decoration_interface.cpp shell_interface.cpp surface_interface.cpp subcompositor_interface.cpp touch_interface.cpp textinput_interface.cpp textinput_interface_v0.cpp textinput_interface_v2.cpp xdgshell_interface.cpp xdgshell_v5_interface.cpp xdgforeign_v2_interface.cpp xdgforeign_interface.cpp xdgshell_v6_interface.cpp ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/output-management.xml BASENAME output-management ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/outputdevice.xml BASENAME org_kde_kwin_outputdevice ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-shell.xml BASENAME plasma-shell ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/plasma-window-management.xml BASENAME plasma-window-management ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/surface-extension.xml BASENAME qt-surface-extension ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/idle.xml BASENAME idle ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/fake-input.xml BASENAME fake-input ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/shadow.xml BASENAME shadow ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/dpms.xml BASENAME dpms ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/blur.xml BASENAME blur ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/contrast.xml BASENAME contrast ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/relative-pointer-unstable-v1.xml BASENAME relativepointer-unstable-v1 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/slide.xml BASENAME slide ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/server-decoration.xml BASENAME server_decoration ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input.xml BASENAME text ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/text-input-unstable-v2.xml BASENAME text-input-unstable-v2 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v5.xml BASENAME xdg-shell-v5 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-shell-unstable-v6.xml BASENAME xdg-shell-v6 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-gestures-unstable-v1.xml BASENAME pointer-gestures-unstable-v1 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/pointer-constraints-unstable-v1.xml BASENAME pointer-constraints-unstable-v1 ) ecm_add_wayland_server_protocol(SERVER_LIB_SRCS PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/xdg-foreign-unstable-v2.xml BASENAME xdg-foreign-unstable-v2 ) +ecm_add_wayland_server_protocol(SERVER_LIB_SRCS + PROTOCOL ${KWayland_SOURCE_DIR}/src/client/protocols/idle-inhibit-unstable-v1.xml + BASENAME idle-inhibit-unstable-v1 +) + add_library(KF5WaylandServer ${SERVER_LIB_SRCS}) generate_export_header(KF5WaylandServer BASE_NAME KWaylandServer EXPORT_FILE_NAME KWayland/Server/kwaylandserver_export.h ) add_library(KF5::WaylandServer ALIAS KF5WaylandServer) target_include_directories(KF5WaylandServer INTERFACE "$") target_link_libraries(KF5WaylandServer PUBLIC Qt5::Gui PRIVATE Wayland::Server EGL::EGL Qt5::Concurrent ) set_target_properties(KF5WaylandServer PROPERTIES VERSION ${KWAYLAND_VERSION_STRING} SOVERSION ${KWAYLAND_SOVERSION} EXPORT_NAME WaylandServer ) install(TARGETS KF5WaylandServer EXPORT KF5WaylandTargets ${KF5_INSTALL_TARGETS_DEFAULT_ARGS}) set(SERVER_LIB_HEADERS ${CMAKE_CURRENT_BINARY_DIR}/KWayland/Server/kwaylandserver_export.h blur_interface.h contrast_interface.h buffer_interface.h clientconnection.h compositor_interface.h datadevice_interface.h datadevicemanager_interface.h dataoffer_interface.h datasource_interface.h display.h dpms_interface.h fakeinput_interface.h global.h idle_interface.h + idleinhibit_interface.h keyboard_interface.h outputdevice_interface.h outputchangeset.h outputconfiguration_interface.h outputmanagement_interface.h output_interface.h pointer_interface.h pointerconstraints_interface.h pointergestures_interface.h plasmashell_interface.h plasmawindowmanagement_interface.h qtsurfaceextension_interface.h region_interface.h relativepointer_interface.h resource.h seat_interface.h server_decoration_interface.h shadow_interface.h shell_interface.h slide_interface.h subcompositor_interface.h surface_interface.h textinput_interface.h touch_interface.h xdgshell_interface.h xdgforeign_interface.h ) install(FILES ${SERVER_LIB_HEADERS} DESTINATION ${KF5_INCLUDE_INSTALL_DIR}/KWayland/Server COMPONENT Devel ) # make available to ecm_add_qch in parent folder set(KWaylandServer_APIDOX_SRCS ${SERVER_LIB_HEADERS} PARENT_SCOPE) include(ECMGeneratePriFile) ecm_generate_pri_file(BASE_NAME KWaylandServer LIB_NAME KF5WaylandServer DEPS "core" FILENAME_VAR PRI_FILENAME INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF5}) install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/server/display.cpp b/src/server/display.cpp index f3c504f..f5e1664 100644 --- a/src/server/display.cpp +++ b/src/server/display.cpp @@ -1,539 +1,552 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "display.h" #include "compositor_interface.h" #include "datadevicemanager_interface.h" #include "dpms_interface.h" #include "outputconfiguration_interface.h" #include "outputmanagement_interface.h" #include "outputdevice_interface.h" #include "idle_interface.h" +#include "idleinhibit_interface_p.h" #include "fakeinput_interface.h" #include "logging_p.h" #include "output_interface.h" #include "plasmashell_interface.h" #include "plasmawindowmanagement_interface.h" #include "pointerconstraints_interface_p.h" #include "pointergestures_interface_p.h" #include "qtsurfaceextension_interface.h" #include "seat_interface.h" #include "shadow_interface.h" #include "blur_interface.h" #include "contrast_interface.h" #include "relativepointer_interface_p.h" #include "server_decoration_interface.h" #include "slide_interface.h" #include "shell_interface.h" #include "subcompositor_interface.h" #include "textinput_interface_p.h" #include "xdgshell_v5_interface_p.h" #include "xdgforeign_interface.h" #include "xdgshell_v6_interface_p.h" #include #include #include #include #include #include #include namespace KWayland { namespace Server { class Display::Private { public: Private(Display *q); void flush(); void dispatch(); void setRunning(bool running); void installSocketNotifier(); wl_display *display = nullptr; wl_event_loop *loop = nullptr; QString socketName = QStringLiteral("wayland-0"); bool running = false; QList outputs; QList outputdevices; QVector seats; QVector clients; EGLDisplay eglDisplay = EGL_NO_DISPLAY; private: Display *q; }; Display::Private::Private(Display *q) : q(q) { } void Display::Private::installSocketNotifier() { if (!QThread::currentThread()) { return; } int fd = wl_event_loop_get_fd(loop); if (fd == -1) { qCWarning(KWAYLAND_SERVER) << "Did not get the file descriptor for the event loop"; return; } QSocketNotifier *m_notifier = new QSocketNotifier(fd, QSocketNotifier::Read, q); QObject::connect(m_notifier, &QSocketNotifier::activated, q, [this] { dispatch(); } ); QObject::connect(QThread::currentThread()->eventDispatcher(), &QAbstractEventDispatcher::aboutToBlock, q, [this] { flush(); }); setRunning(true); } Display::Display(QObject *parent) : QObject(parent) , d(new Private(this)) { } Display::~Display() { terminate(); if (d->display) { wl_display_destroy(d->display); } } void Display::Private::flush() { if (!display || !loop) { return; } wl_display_flush_clients(display); } void Display::Private::dispatch() { if (!display || !loop) { return; } if (wl_event_loop_dispatch(loop, 0) != 0) { qCWarning(KWAYLAND_SERVER) << "Error on dispatching Wayland event loop"; } } void Display::setSocketName(const QString &name) { if (d->socketName == name) { return; } d->socketName = name; emit socketNameChanged(d->socketName); } QString Display::socketName() const { return d->socketName; } void Display::start(StartMode mode) { Q_ASSERT(!d->running); Q_ASSERT(!d->display); d->display = wl_display_create(); if (mode == StartMode::ConnectToSocket) { if (wl_display_add_socket(d->display, qPrintable(d->socketName)) != 0) { qCWarning(KWAYLAND_SERVER) << "Failed to create Wayland socket"; return; } } d->loop = wl_display_get_event_loop(d->display); d->installSocketNotifier(); } void Display::startLoop() { Q_ASSERT(!d->running); Q_ASSERT(d->display); d->installSocketNotifier(); } void Display::dispatchEvents(int msecTimeout) { Q_ASSERT(d->display); if (d->running) { d->dispatch(); } else if (d->loop) { wl_event_loop_dispatch(d->loop, msecTimeout); wl_display_flush_clients(d->display); } } void Display::terminate() { if (!d->running) { return; } emit aboutToTerminate(); wl_display_terminate(d->display); wl_display_destroy(d->display); d->display = nullptr; d->loop = nullptr; d->setRunning(false); } void Display::Private::setRunning(bool r) { Q_ASSERT(running != r); running = r; emit q->runningChanged(running); } OutputInterface *Display::createOutput(QObject *parent) { OutputInterface *output = new OutputInterface(this, parent); connect(output, &QObject::destroyed, this, [this,output] { d->outputs.removeAll(output); }); connect(this, &Display::aboutToTerminate, output, [this,output] { removeOutput(output); }); d->outputs << output; return output; } CompositorInterface *Display::createCompositor(QObject *parent) { CompositorInterface *compositor = new CompositorInterface(this, parent); connect(this, &Display::aboutToTerminate, compositor, [this,compositor] { delete compositor; }); return compositor; } ShellInterface *Display::createShell(QObject *parent) { ShellInterface *shell = new ShellInterface(this, parent); connect(this, &Display::aboutToTerminate, shell, [this,shell] { delete shell; }); return shell; } OutputDeviceInterface *Display::createOutputDevice(QObject *parent) { OutputDeviceInterface *output = new OutputDeviceInterface(this, parent); connect(output, &QObject::destroyed, this, [this,output] { d->outputdevices.removeAll(output); }); connect(this, &Display::aboutToTerminate, output, [this,output] { removeOutputDevice(output); }); d->outputdevices << output; return output; } OutputManagementInterface *Display::createOutputManagement(QObject *parent) { OutputManagementInterface *om = new OutputManagementInterface(this, parent); connect(this, &Display::aboutToTerminate, om, [this,om] { delete om; }); return om; } SeatInterface *Display::createSeat(QObject *parent) { SeatInterface *seat = new SeatInterface(this, parent); connect(seat, &QObject::destroyed, this, [this, seat] { d->seats.removeAll(seat); }); connect(this, &Display::aboutToTerminate, seat, [this,seat] { delete seat; }); d->seats << seat; return seat; } SubCompositorInterface *Display::createSubCompositor(QObject *parent) { auto c = new SubCompositorInterface(this, parent); connect(this, &Display::aboutToTerminate, c, [this,c] { delete c; }); return c; } DataDeviceManagerInterface *Display::createDataDeviceManager(QObject *parent) { auto m = new DataDeviceManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, m, [this,m] { delete m; }); return m; } PlasmaShellInterface *Display::createPlasmaShell(QObject* parent) { auto s = new PlasmaShellInterface(this, parent); connect(this, &Display::aboutToTerminate, s, [this, s] { delete s; }); return s; } PlasmaWindowManagementInterface *Display::createPlasmaWindowManagement(QObject *parent) { auto wm = new PlasmaWindowManagementInterface(this, parent); connect(this, &Display::aboutToTerminate, wm, [this, wm] { delete wm; }); return wm; } QtSurfaceExtensionInterface *Display::createQtSurfaceExtension(QObject *parent) { auto s = new QtSurfaceExtensionInterface(this, parent); connect(this, &Display::aboutToTerminate, s, [this, s] { delete s; }); return s; } IdleInterface *Display::createIdle(QObject *parent) { auto i = new IdleInterface(this, parent); connect(this, &Display::aboutToTerminate, i, [this, i] { delete i; }); return i; } FakeInputInterface *Display::createFakeInput(QObject *parent) { auto i = new FakeInputInterface(this, parent); connect(this, &Display::aboutToTerminate, i, [this, i] { delete i; }); return i; } ShadowManagerInterface *Display::createShadowManager(QObject *parent) { auto s = new ShadowManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, s, [this, s] { delete s; }); return s; } BlurManagerInterface *Display::createBlurManager(QObject *parent) { auto b = new BlurManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, b, [this, b] { delete b; }); return b; } ContrastManagerInterface *Display::createContrastManager(QObject *parent) { auto b = new ContrastManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, b, [this, b] { delete b; }); return b; } SlideManagerInterface *Display::createSlideManager(QObject *parent) { auto b = new SlideManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, b, [this, b] { delete b; }); return b; } DpmsManagerInterface *Display::createDpmsManager(QObject *parent) { auto d = new DpmsManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, d, [this, d] { delete d; }); return d; } ServerSideDecorationManagerInterface *Display::createServerSideDecorationManager(QObject *parent) { auto d = new ServerSideDecorationManagerInterface(this, parent); connect(this, &Display::aboutToTerminate, d, [d] { delete d; }); return d; } TextInputManagerInterface *Display::createTextInputManager(const TextInputInterfaceVersion &version, QObject *parent) { TextInputManagerInterface *t = nullptr; switch (version) { case TextInputInterfaceVersion::UnstableV0: t = new TextInputManagerUnstableV0Interface(this, parent); break; case TextInputInterfaceVersion::UnstableV1: // unsupported return nullptr; case TextInputInterfaceVersion::UnstableV2: t = new TextInputManagerUnstableV2Interface(this, parent); } connect(this, &Display::aboutToTerminate, t, [t] { delete t; }); return t; } XdgShellInterface *Display::createXdgShell(const XdgShellInterfaceVersion &version, QObject *parent) { XdgShellInterface *x = nullptr; switch (version) { case XdgShellInterfaceVersion::UnstableV5: x = new XdgShellV5Interface(this, parent); break; case XdgShellInterfaceVersion::UnstableV6: x = new XdgShellV6Interface(this, parent); break; } connect(this, &Display::aboutToTerminate, x, [x] { delete x; }); return x; } RelativePointerManagerInterface *Display::createRelativePointerManager(const RelativePointerInterfaceVersion &version, QObject *parent) { RelativePointerManagerInterface *r = nullptr; switch (version) { case RelativePointerInterfaceVersion::UnstableV1: r = new RelativePointerManagerUnstableV1Interface(this, parent); break; } connect(this, &Display::aboutToTerminate, r, [r] { delete r; }); return r; } PointerGesturesInterface *Display::createPointerGestures(const PointerGesturesInterfaceVersion &version, QObject *parent) { PointerGesturesInterface *p = nullptr; switch (version) { case PointerGesturesInterfaceVersion::UnstableV1: p = new PointerGesturesUnstableV1Interface(this, parent); break; } connect(this, &Display::aboutToTerminate, p, [p] { delete p; }); return p; } PointerConstraintsInterface *Display::createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent) { PointerConstraintsInterface *p = nullptr; switch (version) { case PointerConstraintsInterfaceVersion::UnstableV1: p = new PointerConstraintsUnstableV1Interface(this, parent); break; } connect(this, &Display::aboutToTerminate, p, [p] { delete p; }); return p; } XdgForeignInterface *Display::createXdgForeignInterface(QObject *parent) { XdgForeignInterface *foreign = new XdgForeignInterface(this, parent); connect(this, &Display::aboutToTerminate, foreign, [this,foreign] { delete foreign; }); return foreign; } +IdleInhibitManagerInterface *Display::createIdleInhibitManager(const IdleInhibitManagerInterfaceVersion &version, QObject *parent) +{ + IdleInhibitManagerInterface *i = nullptr; + switch (version) { + case IdleInhibitManagerInterfaceVersion::UnstableV1: + i = new IdleInhibitManagerUnstableV1Interface(this, parent); + break; + } + connect(this, &Display::aboutToTerminate, i, [this,i] { delete i; }); + return i; +} + void Display::createShm() { Q_ASSERT(d->display); wl_display_init_shm(d->display); } void Display::removeOutput(OutputInterface *output) { d->outputs.removeAll(output); delete output; } void Display::removeOutputDevice(OutputDeviceInterface *output) { d->outputdevices.removeAll(output); delete output; } quint32 Display::nextSerial() { return wl_display_next_serial(d->display); } quint32 Display::serial() { return wl_display_get_serial(d->display); } bool Display::isRunning() const { return d->running; } Display::operator wl_display*() { return d->display; } Display::operator wl_display*() const { return d->display; } QList< OutputInterface* > Display::outputs() const { return d->outputs; } QList< OutputDeviceInterface* > Display::outputDevices() const { return d->outputdevices; } QVector Display::seats() const { return d->seats; } ClientConnection *Display::getConnection(wl_client *client) { Q_ASSERT(client); auto it = std::find_if(d->clients.constBegin(), d->clients.constEnd(), [client](ClientConnection *c) { return c->client() == client; } ); if (it != d->clients.constEnd()) { return *it; } // no ConnectionData yet, create it auto c = new ClientConnection(client, this); d->clients << c; connect(c, &ClientConnection::disconnected, this, [this] (ClientConnection *c) { const int index = d->clients.indexOf(c); Q_ASSERT(index != -1); d->clients.remove(index); Q_ASSERT(d->clients.indexOf(c) == -1); emit clientDisconnected(c); } ); emit clientConnected(c); return c; } QVector< ClientConnection* > Display::connections() const { return d->clients; } ClientConnection *Display::createClient(int fd) { Q_ASSERT(fd != -1); Q_ASSERT(d->display); wl_client *c = wl_client_create(d->display, fd); if (!c) { return nullptr; } return getConnection(c); } void Display::setEglDisplay(void *display) { if (d->eglDisplay != EGL_NO_DISPLAY) { qCWarning(KWAYLAND_SERVER) << "EGLDisplay cannot be changed"; return; } d->eglDisplay = (EGLDisplay)display; } void *Display::eglDisplay() const { return d->eglDisplay; } } } diff --git a/src/server/display.h b/src/server/display.h index 5a9f65e..d964a0e 100644 --- a/src/server/display.h +++ b/src/server/display.h @@ -1,271 +1,282 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_DISPLAY_H #define WAYLAND_SERVER_DISPLAY_H #include #include #include #include "clientconnection.h" struct wl_client; struct wl_display; struct wl_event_loop; namespace KWayland { /** * @short KWayland Server. * * This namespace groups all classes related to the Server module. * * The main entry point into the KWayland::Server API is the Display class. * It allows to create a Wayland server and create various global objects on it. * * KWayland::Server is an API to easily create a head-less Wayland server with a * Qt style API. * * @see Display **/ namespace Server { class CompositorInterface; class DataDeviceManagerInterface; class DpmsManagerInterface; class IdleInterface; +enum class IdleInhibitManagerInterfaceVersion; +class IdleInhibitManagerInterface; class FakeInputInterface; class OutputInterface; class OutputDeviceInterface; class OutputConfigurationInterface; class OutputManagementInterface; class PlasmaShellInterface; class PlasmaWindowManagementInterface; class QtSurfaceExtensionInterface; class SeatInterface; class ShadowManagerInterface; class BlurManagerInterface; class ContrastManagerInterface; class ServerSideDecorationManagerInterface; class SlideManagerInterface; class ShellInterface; class SubCompositorInterface; enum class TextInputInterfaceVersion; class TextInputManagerInterface; class XdgShellV5Interface; enum class XdgShellInterfaceVersion; class XdgShellInterface; enum class RelativePointerInterfaceVersion; class RelativePointerManagerInterface; enum class PointerGesturesInterfaceVersion; class PointerGesturesInterface; enum class PointerConstraintsInterfaceVersion; class PointerConstraintsInterface; class XdgForeignInterface; /** * @brief Class holding the Wayland server display loop. * * @todo Improve documentation **/ class KWAYLANDSERVER_EXPORT Display : public QObject { Q_OBJECT Q_PROPERTY(QString socketName READ socketName WRITE setSocketName NOTIFY socketNameChanged) Q_PROPERTY(bool running READ isRunning NOTIFY runningChanged) public: explicit Display(QObject *parent = nullptr); virtual ~Display(); void setSocketName(const QString &name); QString socketName() const; quint32 serial(); quint32 nextSerial(); /** * How to setup the server connection. * @li ConnectToSocket: the server will open the socket identified by the socket name * @li ConnectClientsOnly: only connections through createClient are possible **/ enum class StartMode { ConnectToSocket, ConnectClientsOnly }; void start(StartMode mode = StartMode::ConnectToSocket); void terminate(); /** * Starts the event loop for the server socket. * This method should only be used if start() is used before creating the * QCoreApplication. In that case start() cannot fully setup the event processing * and the loop needs to be started after the QCoreApplication got created. * @see start * @see dispatchEvents **/ void startLoop(); /** * Dispatches pending events in a blocking way. May only be used if the Display is * created and started before the QCoreApplication is created. Once the QCoreApplication * is created and the event loop is started this method delegates to the normal dispatch * handling. * @see startLoop **/ void dispatchEvents(int msecTimeout = -1); /** * Create a client for the given file descriptor. * * The client is created as if it connected through the normal server * socket. This method can be used to create a connection bypassing the * normal socket connection. It's recommended to use together with * socketpair and pass the other side of the socket to the client. * * @param fd The file descriptor for the socket to the client * @returns The new ClientConnection or @c null on failure. **/ ClientConnection *createClient(int fd); operator wl_display*(); operator wl_display*() const; bool isRunning() const; OutputInterface *createOutput(QObject *parent = nullptr); void removeOutput(OutputInterface *output); QList outputs() const; OutputDeviceInterface *createOutputDevice(QObject *parent = nullptr); void removeOutputDevice(OutputDeviceInterface *output); QList outputDevices() const; CompositorInterface *createCompositor(QObject *parent = nullptr); void createShm(); ShellInterface *createShell(QObject *parent = nullptr); SeatInterface *createSeat(QObject *parent = nullptr); /** * @returns All SeatInterface currently managed on the Display. * @since 5.6 **/ QVector seats() const; SubCompositorInterface *createSubCompositor(QObject *parent = nullptr); DataDeviceManagerInterface *createDataDeviceManager(QObject *parent = nullptr); OutputManagementInterface *createOutputManagement(QObject *parent = nullptr); PlasmaShellInterface *createPlasmaShell(QObject *parent = nullptr); PlasmaWindowManagementInterface *createPlasmaWindowManagement(QObject *parent = nullptr); QtSurfaceExtensionInterface *createQtSurfaceExtension(QObject *parent = nullptr); IdleInterface *createIdle(QObject *parent = nullptr); FakeInputInterface *createFakeInput(QObject *parent = nullptr); ShadowManagerInterface *createShadowManager(QObject *parent = nullptr); BlurManagerInterface *createBlurManager(QObject *parent = nullptr); ContrastManagerInterface *createContrastManager(QObject *parent = nullptr); SlideManagerInterface *createSlideManager(QObject *parent = nullptr); DpmsManagerInterface *createDpmsManager(QObject *parent = nullptr); /** * @since 5.6 **/ ServerSideDecorationManagerInterface *createServerSideDecorationManager(QObject *parent = nullptr); /** * Create the text input manager in interface @p version. * @returns The created manager object * @since 5.23 **/ TextInputManagerInterface *createTextInputManager(const TextInputInterfaceVersion &version, QObject *parent = nullptr); /** * Creates the XdgShell in interface @p version. * * @since 5.25 **/ XdgShellInterface *createXdgShell(const XdgShellInterfaceVersion &version, QObject *parent = nullptr); /** * Creates the RelativePointerManagerInterface in interface @p version * * @returns The created manager object * @since 5.28 **/ RelativePointerManagerInterface *createRelativePointerManager(const RelativePointerInterfaceVersion &version, QObject *parent = nullptr); /** * Creates the PointerGesturesInterface in interface @p version * * @returns The created manager object * @since 5.29 **/ PointerGesturesInterface *createPointerGestures(const PointerGesturesInterfaceVersion &version, QObject *parent = nullptr); /** * Creates the PointerConstraintsInterface in interface @p version * * @returns The created manager object * @since 5.29 **/ PointerConstraintsInterface *createPointerConstraints(const PointerConstraintsInterfaceVersion &version, QObject *parent = nullptr); /** * Creates the XdgForeignInterface in interface @p version * * @returns The created manager object * @since 5.40 **/ XdgForeignInterface *createXdgForeignInterface(QObject *parent = nullptr); + + /** + * Creates the IdleInhibitManagerInterface in interface @p version. + * + * @returns The created manager object + * @since 5.41 + **/ + IdleInhibitManagerInterface *createIdleInhibitManager(const IdleInhibitManagerInterfaceVersion &version, QObject *parent = nullptr); + /** * Gets the ClientConnection for the given @p client. * If there is no ClientConnection yet for the given @p client, it will be created. * @param client The native client for which the ClientConnection is retrieved * @return The ClientConnection for the given native client **/ ClientConnection *getConnection(wl_client *client); QVector connections() const; /** * Set the EGL @p display for this Wayland display. * The EGLDisplay can only be set once and must be alive as long as the Wayland display * is alive. The user should have set up the binding between the EGLDisplay and the * Wayland display prior to calling this method. * * @see eglDisplay * @since 5.3 **/ void setEglDisplay(void *display); /** * @returns the EGLDisplay used for this Wayland display or EGL_NO_DISPLAY if not set. * @see setEglDisplay * @since 5.3 **/ void *eglDisplay() const; Q_SIGNALS: void socketNameChanged(const QString&); void runningChanged(bool); void aboutToTerminate(); void clientConnected(KWayland::Server::ClientConnection*); void clientDisconnected(KWayland::Server::ClientConnection*); private: class Private; QScopedPointer d; }; } } #endif diff --git a/src/server/idleinhibit_interface.cpp b/src/server/idleinhibit_interface.cpp new file mode 100644 index 0000000..97b46c2 --- /dev/null +++ b/src/server/idleinhibit_interface.cpp @@ -0,0 +1,53 @@ +/**************************************************************************** +Copyright 2017 Martin Flöser + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#include "idleinhibit_interface_p.h" + +namespace KWayland +{ +namespace Server +{ + +IdleInhibitManagerInterface::Private::Private(IdleInhibitManagerInterface *q, Display *d, const wl_interface *interface, quint32 version, IdleInhibitManagerInterfaceVersion interfaceVersion) + : Global::Private(d, interface, version) + , interfaceVersion(interfaceVersion) + , q(q) +{ +} + +IdleInhibitManagerInterface::IdleInhibitManagerInterface(Private *d, QObject *parent) + : Global(d, parent) +{ +} + +IdleInhibitManagerInterface::~IdleInhibitManagerInterface() = default; + +IdleInhibitManagerInterfaceVersion IdleInhibitManagerInterface::interfaceVersion() const +{ + Q_D(); + return d->interfaceVersion; +} + +IdleInhibitManagerInterface::Private *IdleInhibitManagerInterface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +} +} diff --git a/src/server/idleinhibit_interface.h b/src/server/idleinhibit_interface.h new file mode 100644 index 0000000..b634770 --- /dev/null +++ b/src/server/idleinhibit_interface.h @@ -0,0 +1,77 @@ +/**************************************************************************** +Copyright 2017 Martin Flöser + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_SERVER_IDLEINHIBIT_H +#define KWAYLAND_SERVER_IDLEINHIBIT_H + +#include "global.h" +#include "resource.h" + +#include + +namespace KWayland +{ +namespace Server +{ + +class Display; + +/** + * Enum describing the interface versions the IdleInhibitManagerInterface can support. + * + * @since 5.41 + **/ +enum class IdleInhibitManagerInterfaceVersion { + /** + * zwp_idle_inhibit_manager_v1 + **/ + UnstableV1 +}; + +/** + * The IdleInhibitorManagerInterface is used by clients to inhibit idle on a + * SurfaceInterface. Whether a SurfaceInterface inhibits idle is exposes through + * @link{SurfaceInterface::inhibitsIdle}. + * + * @since 5.41 + **/ +class KWAYLANDSERVER_EXPORT IdleInhibitManagerInterface : public Global +{ + Q_OBJECT +public: + virtual ~IdleInhibitManagerInterface(); + + /** + * @returns The interface version used by this IdleInhibitManagerInterface + **/ + IdleInhibitManagerInterfaceVersion interfaceVersion() const; + +protected: + class Private; + explicit IdleInhibitManagerInterface(Private *d, QObject *parent = nullptr); + +private: + Private *d_func() const; +}; + + +} +} + +#endif diff --git a/src/server/idleinhibit_interface_p.h b/src/server/idleinhibit_interface_p.h new file mode 100644 index 0000000..8ba5766 --- /dev/null +++ b/src/server/idleinhibit_interface_p.h @@ -0,0 +1,96 @@ +/**************************************************************************** +Copyright 2017 Martin Flöser + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#ifndef KWAYLAND_SERVER_IDLEINHIBIT_P_H +#define KWAYLAND_SERVER_IDLEINHIBIT_P_H + +#include "idleinhibit_interface.h" +#include "global_p.h" +#include "resource_p.h" + +#include + +namespace KWayland +{ +namespace Server +{ + +class Q_DECL_HIDDEN IdleInhibitManagerUnstableV1Interface : public IdleInhibitManagerInterface +{ + Q_OBJECT +public: + explicit IdleInhibitManagerUnstableV1Interface(Display *display, QObject *parent = nullptr); + ~IdleInhibitManagerUnstableV1Interface() override; + +private: + class Private; +}; + +class Q_DECL_HIDDEN IdleInhibitManagerInterface::Private : public Global::Private +{ +public: + IdleInhibitManagerInterfaceVersion interfaceVersion; + +protected: + Private(IdleInhibitManagerInterface *q, Display *d, const wl_interface *interface, quint32 version, IdleInhibitManagerInterfaceVersion interfaceVersion); + IdleInhibitManagerInterface *q; +}; + +class Q_DECL_HIDDEN IdleInhibitorInterface : public Resource +{ + Q_OBJECT +public: + explicit IdleInhibitorInterface(IdleInhibitManagerInterface *c, wl_resource *parentResource); + + virtual ~IdleInhibitorInterface(); + + /** + * @returns The interface version used by this IdleInhibitorInterface + **/ + IdleInhibitManagerInterfaceVersion interfaceVersion() const; + +protected: + class Private; + +private: + Private *d_func() const; + friend class IdleInhibitManagerUnstableV1Interface; +}; + +class Q_DECL_HIDDEN IdleInhibitorInterface::Private : public Resource::Private +{ +public: + Private(IdleInhibitorInterface *q, IdleInhibitManagerInterface *m, wl_resource *parentResource); + ~Private(); + +private: + + IdleInhibitorInterface *q_func() { + return reinterpret_cast(q); + } + + static const struct zwp_idle_inhibitor_v1_interface s_interface; +}; + + +} +} + +#endif + diff --git a/src/server/idleinhibit_interface_v1.cpp b/src/server/idleinhibit_interface_v1.cpp new file mode 100644 index 0000000..2920293 --- /dev/null +++ b/src/server/idleinhibit_interface_v1.cpp @@ -0,0 +1,139 @@ +/**************************************************************************** +Copyright 2017 Martin Flöser + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) version 3, or any +later version accepted by the membership of KDE e.V. (or its +successor approved by the membership of KDE e.V.), which shall +act as a proxy defined in Section 6 of version 3 of the license. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library. If not, see . +****************************************************************************/ +#include "idleinhibit_interface_p.h" +#include "display.h" +#include "surface_interface_p.h" + +namespace KWayland +{ +namespace Server +{ + +class Q_DECL_HIDDEN IdleInhibitManagerUnstableV1Interface::Private : public IdleInhibitManagerInterface::Private +{ +public: + Private(IdleInhibitManagerUnstableV1Interface *q, Display *d); + +private: + void bind(wl_client *client, uint32_t version, uint32_t id) override; + + static void unbind(wl_resource *resource); + static Private *cast(wl_resource *r) { + return reinterpret_cast(wl_resource_get_user_data(r)); + } + + static void destroyCallback(wl_client *client, wl_resource *resource); + static void createInhibitorCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource * surface); + + static const struct zwp_idle_inhibit_manager_v1_interface s_interface; + static const quint32 s_version; +}; + +const quint32 IdleInhibitManagerUnstableV1Interface::Private::s_version = 1; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zwp_idle_inhibit_manager_v1_interface IdleInhibitManagerUnstableV1Interface::Private::s_interface = { + destroyCallback, + createInhibitorCallback +}; +#endif + +IdleInhibitManagerUnstableV1Interface::Private::Private(IdleInhibitManagerUnstableV1Interface *q, Display *d) + : IdleInhibitManagerInterface::Private(q, d, &zwp_idle_inhibit_manager_v1_interface, s_version, IdleInhibitManagerInterfaceVersion::UnstableV1) +{ +} + +void IdleInhibitManagerUnstableV1Interface::Private::destroyCallback(wl_client *client, wl_resource *resource) +{ + Q_UNUSED(client) + wl_resource_destroy(resource); +} + +void IdleInhibitManagerUnstableV1Interface::Private::createInhibitorCallback(wl_client *client, wl_resource *resource, uint32_t id, wl_resource *surface) +{ + auto s = SurfaceInterface::get(surface); + if (!s) { + // send error? + return; + } + auto q = cast(resource); + auto inhibitor = new IdleInhibitorInterface(q->q, resource); + inhibitor->d_func()->create(q->display->getConnection(client), version, id); + s->d_func()->installIdleInhibitor(inhibitor); +} + +void IdleInhibitManagerUnstableV1Interface::Private::bind(wl_client *client, uint32_t version, uint32_t id) +{ + auto c = display->getConnection(client); + wl_resource *resource = c->createResource(&zwp_idle_inhibit_manager_v1_interface, qMin(version, s_version), id); + if (!resource) { + wl_client_post_no_memory(client); + return; + } + wl_resource_set_implementation(resource, &s_interface, this, unbind); + // TODO: should we track? +} + +void IdleInhibitManagerUnstableV1Interface::Private::unbind(wl_resource *resource) +{ + Q_UNUSED(resource) + // TODO: implement? +} + +IdleInhibitManagerUnstableV1Interface::IdleInhibitManagerUnstableV1Interface(Display *display, QObject *parent) + : IdleInhibitManagerInterface(new Private(this, display), parent) +{ +} + +IdleInhibitManagerUnstableV1Interface::~IdleInhibitManagerUnstableV1Interface() = default; + +#ifndef DOXYGEN_SHOULD_SKIP_THIS +const struct zwp_idle_inhibitor_v1_interface IdleInhibitorInterface::Private::s_interface = { + resourceDestroyedCallback +}; +#endif + +IdleInhibitorInterface::Private::Private(IdleInhibitorInterface *q, IdleInhibitManagerInterface *c, wl_resource *parentResource) + : Resource::Private(q, c, parentResource, &zwp_idle_inhibitor_v1_interface, &s_interface) +{ +} + +IdleInhibitorInterface::Private::~Private() +{ + if (resource) { + wl_resource_destroy(resource); + resource = nullptr; + } +} + +IdleInhibitorInterface::IdleInhibitorInterface(IdleInhibitManagerInterface *m, wl_resource *parentResource) + : Resource(new Private(this, m, parentResource)) +{ +} + +IdleInhibitorInterface::~IdleInhibitorInterface() = default; + +IdleInhibitorInterface::Private *IdleInhibitorInterface::d_func() const +{ + return reinterpret_cast(d.data()); +} + +} +} diff --git a/src/server/surface_interface.cpp b/src/server/surface_interface.cpp index 37179a6..0e8936c 100644 --- a/src/server/surface_interface.cpp +++ b/src/server/surface_interface.cpp @@ -1,865 +1,888 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #include "surface_interface.h" #include "surface_interface_p.h" #include "buffer_interface.h" #include "clientconnection.h" #include "compositor_interface.h" +#include "idleinhibit_interface_p.h" #include "pointerconstraints_interface_p.h" #include "region_interface.h" #include "subcompositor_interface.h" #include "subsurface_interface_p.h" // Qt #include // Wayland #include // std #include namespace KWayland { namespace Server { SurfaceInterface::Private::Private(SurfaceInterface *q, CompositorInterface *c, wl_resource *parentResource) : Resource::Private(q, c, parentResource, &wl_surface_interface, &s_interface) { } SurfaceInterface::Private::~Private() { destroy(); } void SurfaceInterface::Private::addChild(QPointer< SubSurfaceInterface > child) { // protocol is not precise on how to handle the addition of new sub surfaces pending.children.append(child); subSurfacePending.children.append(child); current.children.append(child); Q_Q(SurfaceInterface); emit q->subSurfaceTreeChanged(); QObject::connect(child.data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged); QObject::connect(child->surface().data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged); QObject::connect(child->surface().data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged); QObject::connect(child->surface().data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged); } void SurfaceInterface::Private::removeChild(QPointer< SubSurfaceInterface > child) { // protocol is not precise on how to handle the addition of new sub surfaces pending.children.removeAll(child); subSurfacePending.children.removeAll(child); current.children.removeAll(child); Q_Q(SurfaceInterface); emit q->subSurfaceTreeChanged(); QObject::disconnect(child.data(), &SubSurfaceInterface::positionChanged, q, &SurfaceInterface::subSurfaceTreeChanged); if (!child->surface().isNull()) { QObject::disconnect(child->surface().data(), &SurfaceInterface::damaged, q, &SurfaceInterface::subSurfaceTreeChanged); QObject::disconnect(child->surface().data(), &SurfaceInterface::unmapped, q, &SurfaceInterface::subSurfaceTreeChanged); QObject::disconnect(child->surface().data(), &SurfaceInterface::subSurfaceTreeChanged, q, &SurfaceInterface::subSurfaceTreeChanged); } } bool SurfaceInterface::Private::raiseChild(QPointer subsurface, SurfaceInterface *sibling) { Q_Q(SurfaceInterface); auto it = std::find(pending.children.begin(), pending.children.end(), subsurface); if (it == pending.children.end()) { return false; } if (pending.children.count() == 1) { // nothing to do return true; } if (sibling == q) { // it's to the parent, so needs to become last item pending.children.append(*it); pending.children.erase(it); pending.childrenChanged = true; return true; } if (!sibling->subSurface()) { // not a sub surface return false; } auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface()); if (siblingIt == pending.children.end() || siblingIt == it) { // not a sibling return false; } auto value = (*it); pending.children.erase(it); // find the iterator again siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface()); pending.children.insert(++siblingIt, value); pending.childrenChanged = true; return true; } bool SurfaceInterface::Private::lowerChild(QPointer subsurface, SurfaceInterface *sibling) { Q_Q(SurfaceInterface); auto it = std::find(pending.children.begin(), pending.children.end(), subsurface); if (it == pending.children.end()) { return false; } if (pending.children.count() == 1) { // nothing to do return true; } if (sibling == q) { // it's to the parent, so needs to become first item auto value = *it; pending.children.erase(it); pending.children.prepend(value); pending.childrenChanged = true; return true; } if (!sibling->subSurface()) { // not a sub surface return false; } auto siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface()); if (siblingIt == pending.children.end() || siblingIt == it) { // not a sibling return false; } auto value = (*it); pending.children.erase(it); // find the iterator again siblingIt = std::find(pending.children.begin(), pending.children.end(), sibling->subSurface()); pending.children.insert(siblingIt, value); pending.childrenChanged = true; return true; } void SurfaceInterface::Private::setShadow(const QPointer &shadow) { pending.shadow = shadow; pending.shadowIsSet = true; } void SurfaceInterface::Private::setBlur(const QPointer &blur) { pending.blur = blur; pending.blurIsSet = true; } void SurfaceInterface::Private::setSlide(const QPointer &slide) { pending.slide = slide; pending.slideIsSet = true; } void SurfaceInterface::Private::setContrast(const QPointer &contrast) { pending.contrast = contrast; pending.contrastIsSet = true; } void SurfaceInterface::Private::installPointerConstraint(LockedPointerInterface *lock) { Q_ASSERT(lockedPointer.isNull()); Q_ASSERT(confinedPointer.isNull()); lockedPointer = QPointer(lock); if (lock->lifeTime() == LockedPointerInterface::LifeTime::OneShot) { constrainsOneShotConnection = QObject::connect(lock, &LockedPointerInterface::lockedChanged, q_func(), [this] { if (lockedPointer.isNull()) { return; } if (!lockedPointer->isLocked()) { lockedPointer.clear(); disconnect(constrainsOneShotConnection); constrainsOneShotConnection = QMetaObject::Connection(); disconnect(constrainsUnboundConnection); constrainsUnboundConnection = QMetaObject::Connection(); emit q_func()->pointerConstraintsChanged(); } } ); } constrainsUnboundConnection = QObject::connect(lock, &LockedPointerInterface::unbound, q_func(), [this] { if (lockedPointer.isNull()) { return; } lockedPointer.clear(); disconnect(constrainsOneShotConnection); constrainsOneShotConnection = QMetaObject::Connection(); disconnect(constrainsUnboundConnection); constrainsUnboundConnection = QMetaObject::Connection(); emit q_func()->pointerConstraintsChanged(); } ); emit q_func()->pointerConstraintsChanged(); } +void SurfaceInterface::Private::installIdleInhibitor(IdleInhibitorInterface *inhibitor) +{ + idleInhibitors << inhibitor; + QObject::connect(inhibitor, &IdleInhibitorInterface::aboutToBeUnbound, q, + [this, inhibitor] { + idleInhibitors.removeOne(inhibitor); + if (idleInhibitors.isEmpty()) { + emit q_func()->inhibitsIdleChanged(); + } + } + ); + if (idleInhibitors.count() == 1) { + emit q_func()->inhibitsIdleChanged(); + } +} + void SurfaceInterface::Private::installPointerConstraint(ConfinedPointerInterface *confinement) { Q_ASSERT(lockedPointer.isNull()); Q_ASSERT(confinedPointer.isNull()); confinedPointer = QPointer(confinement); if (confinement->lifeTime() == ConfinedPointerInterface::LifeTime::OneShot) { constrainsOneShotConnection = QObject::connect(confinement, &ConfinedPointerInterface::confinedChanged, q_func(), [this] { if (confinedPointer.isNull()) { return; } if (!confinedPointer->isConfined()) { confinedPointer.clear(); disconnect(constrainsOneShotConnection); constrainsOneShotConnection = QMetaObject::Connection(); disconnect(constrainsUnboundConnection); constrainsUnboundConnection = QMetaObject::Connection(); emit q_func()->pointerConstraintsChanged(); } } ); } constrainsUnboundConnection = QObject::connect(confinement, &ConfinedPointerInterface::unbound, q_func(), [this] { if (confinedPointer.isNull()) { return; } confinedPointer.clear(); disconnect(constrainsOneShotConnection); constrainsOneShotConnection = QMetaObject::Connection(); disconnect(constrainsUnboundConnection); constrainsUnboundConnection = QMetaObject::Connection(); emit q_func()->pointerConstraintsChanged(); } ); emit q_func()->pointerConstraintsChanged(); } #ifndef DOXYGEN_SHOULD_SKIP_THIS const struct wl_surface_interface SurfaceInterface::Private::s_interface = { resourceDestroyedCallback, attachCallback, damageCallback, frameCallaback, opaqueRegionCallback, inputRegionCallback, commitCallback, bufferTransformCallback, bufferScaleCallback }; #endif SurfaceInterface::SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource) : Resource(new Private(this, parent, parentResource)) { } SurfaceInterface::~SurfaceInterface() = default; void SurfaceInterface::frameRendered(quint32 msec) { Q_D(); // notify all callbacks const bool needsFlush = !d->current.callbacks.isEmpty(); while (!d->current.callbacks.isEmpty()) { wl_resource *r = d->current.callbacks.takeFirst(); wl_callback_send_done(r, msec); wl_resource_destroy(r); } for (auto it = d->current.children.constBegin(); it != d->current.children.constEnd(); ++it) { const auto &subSurface = *it; if (subSurface.isNull() || subSurface->d_func()->surface.isNull()) { continue; } subSurface->d_func()->surface->frameRendered(msec); } if (needsFlush) { client()->flush(); } } void SurfaceInterface::Private::destroy() { // copy all existing callbacks to new list and clear existing lists // the wl_resource_destroy on the callback resource goes into destroyFrameCallback // which would modify the list we are iterating on QList callbacksToDestroy; callbacksToDestroy << current.callbacks; current.callbacks.clear(); callbacksToDestroy << pending.callbacks; pending.callbacks.clear(); callbacksToDestroy << subSurfacePending.callbacks; subSurfacePending.callbacks.clear(); for (auto it = callbacksToDestroy.constBegin(), end = callbacksToDestroy.constEnd(); it != end; it++) { wl_resource_destroy(*it); } if (current.buffer) { current.buffer->unref(); } } void SurfaceInterface::Private::swapStates(State *source, State *target, bool emitChanged) { Q_Q(SurfaceInterface); bool bufferChanged = source->bufferIsSet; const bool opaqueRegionChanged = source->opaqueIsSet; const bool inputRegionChanged = source->inputIsSet; const bool scaleFactorChanged = source->scaleIsSet && (target->scale != source->scale); const bool transformChanged = source->transformIsSet && (target->transform != source->transform); const bool shadowChanged = source->shadowIsSet; const bool blurChanged = source->blurIsSet; const bool contrastChanged = source->contrastIsSet; const bool slideChanged = source->slideIsSet; const bool childrenChanged = source->childrenChanged; bool sizeChanged = false; auto buffer = target->buffer; if (bufferChanged) { // TODO: is the reffing correct for subsurfaces? QSize oldSize; if (target->buffer) { oldSize = target->buffer->size(); if (emitChanged) { target->buffer->unref(); QObject::disconnect(target->buffer, &BufferInterface::sizeChanged, q, &SurfaceInterface::sizeChanged); } else { delete target->buffer; target->buffer = nullptr; } } if (source->buffer) { if (emitChanged) { source->buffer->ref(); QObject::connect(source->buffer, &BufferInterface::sizeChanged, q, &SurfaceInterface::sizeChanged); } const QSize newSize = source->buffer->size(); sizeChanged = newSize.isValid() && newSize != oldSize; } if (!target->buffer && !source->buffer && emitChanged) { // null buffer set on a not mapped surface, don't emit unmapped bufferChanged = false; } buffer = source->buffer; } // copy values if (bufferChanged) { target->buffer = buffer; target->damage = source->damage; target->bufferIsSet = source->bufferIsSet; } if (childrenChanged) { target->childrenChanged = source->childrenChanged; target->children = source->children; } target->callbacks.append(source->callbacks); if (shadowChanged) { target->shadow = source->shadow; target->shadowIsSet = true; } if (blurChanged) { target->blur = source->blur; target->blurIsSet = true; } if (contrastChanged) { target->contrast = source->contrast; target->contrastIsSet = true; } if (slideChanged) { target->slide = source->slide; target->slideIsSet = true; } if (inputRegionChanged) { target->input = source->input; target->inputIsInfinite = source->inputIsInfinite; target->inputIsSet = true; } if (opaqueRegionChanged) { target->opaque = source->opaque; target->opaqueIsSet = true; } if (scaleFactorChanged) { target->scale = source->scale; target->scaleIsSet = true; } if (transformChanged) { target->transform = source->transform; target->transformIsSet = true; } if (!lockedPointer.isNull()) { lockedPointer->d_func()->commit(); } if (!confinedPointer.isNull()) { confinedPointer->d_func()->commit(); } *source = State{}; source->children = target->children; if (opaqueRegionChanged) { emit q->opaqueChanged(target->opaque); } if (inputRegionChanged) { emit q->inputChanged(target->input); } if (scaleFactorChanged) { emit q->scaleChanged(target->scale); if (buffer && !sizeChanged) { emit q->sizeChanged(); } } if (transformChanged) { emit q->transformChanged(target->transform); } if (bufferChanged && emitChanged) { if (!target->damage.isEmpty()) { const QRegion windowRegion = QRegion(0, 0, q->size().width(), q->size().height()); if (!windowRegion.isEmpty()) { target->damage = windowRegion.intersected(target->damage); if (emitChanged) { subSurfaceIsMapped = true; trackedDamage = trackedDamage.united(target->damage); emit q->damaged(target->damage); // workaround for https://bugreports.qt.io/browse/QTBUG-52092 // if the surface is a sub-surface, but the main surface is not yet mapped, fake frame rendered if (subSurface && !subSurface->mainSurface()->buffer()) { q->frameRendered(0); } } } } else if (!target->buffer && emitChanged) { subSurfaceIsMapped = false; emit q->unmapped(); } } if (!emitChanged) { return; } if (sizeChanged) { emit q->sizeChanged(); } if (shadowChanged) { emit q->shadowChanged(); } if (blurChanged) { emit q->blurChanged(); } if (contrastChanged) { emit q->contrastChanged(); } if (slideChanged) { emit q->slideOnShowHideChanged(); } if (childrenChanged) { emit q->subSurfaceTreeChanged(); } } void SurfaceInterface::Private::commit() { if (!subSurface.isNull() && subSurface->isSynchronized()) { swapStates(&pending, &subSurfacePending, false); } else { swapStates(&pending, ¤t, true); if (!subSurface.isNull()) { subSurface->d_func()->commit(); } // commit all subSurfaces to apply position changes // "The cached state is applied to the sub-surface immediately after the parent surface's state is applied" for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) { const auto &subSurface = *it; if (subSurface.isNull()) { continue; } subSurface->d_func()->commit(); } } } void SurfaceInterface::Private::commitSubSurface() { if (subSurface.isNull() || !subSurface->isSynchronized()) { return; } swapStates(&subSurfacePending, ¤t, true); // "The cached state is applied to the sub-surface immediately after the parent surface's state is applied" for (auto it = current.children.constBegin(); it != current.children.constEnd(); ++it) { const auto &subSurface = *it; if (subSurface.isNull() || !subSurface->isSynchronized()) { continue; } subSurface->d_func()->commit(); } } void SurfaceInterface::Private::damage(const QRect &rect) { if (!pending.bufferIsSet || (pending.bufferIsSet && !pending.buffer)) { // TODO: should we send an error? return; } pending.damage = pending.damage.united(rect); } void SurfaceInterface::Private::setScale(qint32 scale) { pending.scale = scale; pending.scaleIsSet = true; } void SurfaceInterface::Private::setTransform(OutputInterface::Transform transform) { pending.transform = transform; } void SurfaceInterface::Private::addFrameCallback(uint32_t callback) { wl_resource *r = client->createResource(&wl_callback_interface, 1, callback); if (!r) { wl_resource_post_no_memory(resource); return; } wl_resource_set_implementation(r, nullptr, this, destroyFrameCallback); pending.callbacks << r; } void SurfaceInterface::Private::attachBuffer(wl_resource *buffer, const QPoint &offset) { pending.bufferIsSet = true; pending.offset = offset; if (pending.buffer) { delete pending.buffer; } if (!buffer) { // got a null buffer, deletes content in next frame pending.buffer = nullptr; pending.damage = QRegion(); return; } Q_Q(SurfaceInterface); pending.buffer = new BufferInterface(buffer, q); QObject::connect(pending.buffer, &BufferInterface::aboutToBeDestroyed, q, [this](BufferInterface *buffer) { if (pending.buffer == buffer) { pending.buffer = nullptr; } if (subSurfacePending.buffer == buffer) { subSurfacePending.buffer = nullptr; } if (current.buffer == buffer) { current.buffer->unref(); current.buffer = nullptr; } } ); } void SurfaceInterface::Private::destroyFrameCallback(wl_resource *r) { auto s = cast(r); s->current.callbacks.removeAll(r); s->pending.callbacks.removeAll(r); s->subSurfacePending.callbacks.removeAll(r); } void SurfaceInterface::Private::attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy) { Q_UNUSED(client) cast(resource)->attachBuffer(buffer, QPoint(sx, sy)); } void SurfaceInterface::Private::damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height) { Q_UNUSED(client) cast(resource)->damage(QRect(x, y, width, height)); } void SurfaceInterface::Private::frameCallaback(wl_client *client, wl_resource *resource, uint32_t callback) { auto s = cast(resource); Q_ASSERT(client == *s->client); s->addFrameCallback(callback); } void SurfaceInterface::Private::opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region) { auto s = cast(resource); Q_ASSERT(client == *s->client); auto r = RegionInterface::get(region); s->setOpaque(r ? r->region() : QRegion()); } void SurfaceInterface::Private::setOpaque(const QRegion ®ion) { pending.opaqueIsSet = true; pending.opaque = region; } void SurfaceInterface::Private::inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region) { auto s = cast(resource); Q_ASSERT(client == *s->client); auto r = RegionInterface::get(region); s->setInput(r ? r->region() : QRegion(), !r); } void SurfaceInterface::Private::setInput(const QRegion ®ion, bool isInfinite) { pending.inputIsSet = true; pending.inputIsInfinite = isInfinite; pending.input = region; } void SurfaceInterface::Private::commitCallback(wl_client *client, wl_resource *resource) { Q_UNUSED(client) cast(resource)->commit(); } void SurfaceInterface::Private::bufferTransformCallback(wl_client *client, wl_resource *resource, int32_t transform) { Q_UNUSED(client) cast(resource)->setTransform(OutputInterface::Transform(transform)); } void SurfaceInterface::Private::bufferScaleCallback(wl_client *client, wl_resource *resource, int32_t scale) { Q_UNUSED(client) cast(resource)->setScale(scale); } QRegion SurfaceInterface::damage() const { Q_D(); return d->current.damage; } QRegion SurfaceInterface::opaque() const { Q_D(); return d->current.opaque; } QRegion SurfaceInterface::input() const { Q_D(); return d->current.input; } bool SurfaceInterface::inputIsInfitine() const { return inputIsInfinite(); } bool SurfaceInterface::inputIsInfinite() const { Q_D(); return d->current.inputIsInfinite; } qint32 SurfaceInterface::scale() const { Q_D(); return d->current.scale; } OutputInterface::Transform SurfaceInterface::transform() const { Q_D(); return d->current.transform; } BufferInterface *SurfaceInterface::buffer() { Q_D(); return d->current.buffer; } QPoint SurfaceInterface::offset() const { Q_D(); return d->current.offset; } SurfaceInterface *SurfaceInterface::get(wl_resource *native) { return Private::get(native); } SurfaceInterface *SurfaceInterface::get(quint32 id, const ClientConnection *client) { return Private::get(id, client); } QList< QPointer< SubSurfaceInterface > > SurfaceInterface::childSubSurfaces() const { Q_D(); return d->current.children; } QPointer< SubSurfaceInterface > SurfaceInterface::subSurface() const { Q_D(); return d->subSurface; } QSize SurfaceInterface::size() const { Q_D(); // TODO: apply transform to the buffer size if (d->current.buffer) { return d->current.buffer->size() / scale(); } return QSize(); } QPointer< ShadowInterface > SurfaceInterface::shadow() const { Q_D(); return d->current.shadow; } QPointer< BlurInterface > SurfaceInterface::blur() const { Q_D(); return d->current.blur; } QPointer< ContrastInterface > SurfaceInterface::contrast() const { Q_D(); return d->current.contrast; } QPointer< SlideInterface > SurfaceInterface::slideOnShowHide() const { Q_D(); return d->current.slide; } bool SurfaceInterface::isMapped() const { Q_D(); if (d->subSurface) { // from spec: // "A sub-surface becomes mapped, when a non-NULL wl_buffer is applied and the parent surface is mapped." return d->subSurfaceIsMapped && !d->subSurface->parentSurface().isNull() && d->subSurface->parentSurface()->isMapped(); } return d->current.buffer != nullptr; } QRegion SurfaceInterface::trackedDamage() const { Q_D(); return d->trackedDamage; } void SurfaceInterface::resetTrackedDamage() { Q_D(); d->trackedDamage = QRegion(); } QVector SurfaceInterface::outputs() const { Q_D(); return d->outputs; } void SurfaceInterface::setOutputs(const QVector &outputs) { Q_D(); QVector removedOutputs = d->outputs; for (auto it = outputs.constBegin(), end = outputs.constEnd(); it != end; ++it) { const auto o = *it; removedOutputs.removeOne(o); } for (auto it = removedOutputs.constBegin(), end = removedOutputs.constEnd(); it != end; ++it) { const auto resources = (*it)->clientResources(client()); for (wl_resource *r : resources) { wl_surface_send_leave(d->resource, r); } disconnect(d->outputDestroyedConnections.take(*it)); } QVector addedOutputsOutputs = outputs; for (auto it = d->outputs.constBegin(), end = d->outputs.constEnd(); it != end; ++it) { const auto o = *it; addedOutputsOutputs.removeOne(o); } for (auto it = addedOutputsOutputs.constBegin(), end = addedOutputsOutputs.constEnd(); it != end; ++it) { const auto o = *it; const auto resources = o->clientResources(client()); for (wl_resource *r : resources) { wl_surface_send_enter(d->resource, r); } d->outputDestroyedConnections[o] = connect(o, &Global::aboutToDestroyGlobal, this, [this, o] { Q_D(); auto outputs = d->outputs; if (outputs.removeOne(o)) { setOutputs(outputs); }}); } // TODO: send enter when the client binds the OutputInterface another time d->outputs = outputs; } SurfaceInterface *SurfaceInterface::surfaceAt(const QPointF &position) { if (!isMapped()) { return nullptr; } Q_D(); // go from top to bottom. Top most child is last in list QListIterator> it(d->current.children); it.toBack(); while (it.hasPrevious()) { const auto ¤t = it.previous(); auto surface = current->surface(); if (surface.isNull()) { continue; } if (auto s = surface->surfaceAt(position - current->position())) { return s; } } // check whether the geometry contains the pos if (!size().isEmpty() && QRectF(QPoint(0, 0), size()).contains(position)) { return this; } return nullptr; } QPointer SurfaceInterface::lockedPointer() const { Q_D(); return d->lockedPointer; } QPointer SurfaceInterface::confinedPointer() const { Q_D(); return d->confinedPointer; } +bool SurfaceInterface::inhibitsIdle() const +{ + Q_D(); + return !d->idleInhibitors.isEmpty(); +} + SurfaceInterface::Private *SurfaceInterface::d_func() const { return reinterpret_cast(d.data()); } } } diff --git a/src/server/surface_interface.h b/src/server/surface_interface.h index c7f2fc6..232c38c 100644 --- a/src/server/surface_interface.h +++ b/src/server/surface_interface.h @@ -1,330 +1,346 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_SURFACE_INTERFACE_H #define WAYLAND_SERVER_SURFACE_INTERFACE_H #include "resource.h" #include "output_interface.h" #include #include #include #include namespace KWayland { namespace Server { class BlurManagerInterface; class BlurInterface; class BufferInterface; class ConfinedPointerInterface; class ContrastInterface; class ContrastManagerInterface; class CompositorInterface; +class IdleInhibitManagerUnstableV1Interface; class LockedPointerInterface; class PointerConstraintsUnstableV1Interface; class ShadowManagerInterface; class ShadowInterface; class SlideInterface; class SubSurfaceInterface; /** * @brief Resource representing a wl_surface. * * The SurfaceInterface gets created by the CompositorInterface. A SurfaceInterface normally * takes up a role by being "attached" to either a ShellSurfaceInterface, a SubSurfaceInterface * or a Cursor. * * The implementation of the SurfaceInterface does not only wrap the features exposed by wl_surface, * but goes further by integrating the information added to a SurfaceInterface by other interfaces. * This should make interacting from the server easier, it only needs to monitor the SurfaceInterface * and does not need to track each specific interface. * * The SurfaceInterface takes care of reference/unreferencing the BufferInterface attached to it. * As long as a BufferInterface is attached, the released signal won't be sent. If the BufferInterface * is no longer needed by the SurfaceInterface, it will get unreferenced and might be automatically * deleted (if it's no longer referenced). * * @see CompositorInterface * @see BufferInterface * @see SubSurfaceInterface * @see BlurInterface * @see ContrastInterface * @see ShadowInterface * @see SlideInterface **/ class KWAYLANDSERVER_EXPORT SurfaceInterface : public Resource { Q_OBJECT /** * The current damage region. **/ Q_PROPERTY(QRegion damage READ damage NOTIFY damaged) /** * The opaque region for a translucent buffer. **/ Q_PROPERTY(QRegion opaque READ opaque NOTIFY opaqueChanged) /** * The current input region. **/ Q_PROPERTY(QRegion input READ input NOTIFY inputChanged) Q_PROPERTY(qint32 scale READ scale NOTIFY scaleChanged) Q_PROPERTY(KWayland::Server::OutputInterface::Transform transform READ transform NOTIFY transformChanged) Q_PROPERTY(QSize size READ size NOTIFY sizeChanged) public: virtual ~SurfaceInterface(); void frameRendered(quint32 msec); QRegion damage() const; QRegion opaque() const; QRegion input() const; /** * Use Surface::inputIsInfinite instead. * @deprecated * @see inputIsInfinite */ bool inputIsInfitine() const; /** * Replaces Surface::inputIsInfitine instead. * @since 5.5 */ bool inputIsInfinite() const; qint32 scale() const; OutputInterface::Transform transform() const; /** * @returns the current BufferInterface, might be @c nullptr. **/ BufferInterface *buffer(); QPoint offset() const; /** * The size of the Surface in global compositor space. * @see For buffer size use BufferInterface::size * from SurfaceInterface::buffer * @since 5.3 **/ QSize size() const; /** * @returns The SubSurface for this Surface in case there is one. **/ QPointer subSurface() const; /** * @returns Children in stacking order from bottom (first) to top (last). **/ QList> childSubSurfaces() const; /** * @returns The Shadow for this Surface. * @since 5.4 **/ QPointer shadow() const; /** * @returns The Blur for this Surface. * @since 5.5 **/ QPointer blur() const; /** * @returns The Slide for this Surface. * @since 5.5 **/ QPointer slideOnShowHide() const; /** * @returns The Contrast for this Surface. * @since 5.5 **/ QPointer contrast() const; /** * Whether the SurfaceInterface is currently considered to be mapped. * A SurfaceInterface is mapped if it has a non-null BufferInterface attached. * If the SurfaceInterface references a SubSurfaceInterface it is only considered * mapped if it has a BufferInterface attached and the parent SurfaceInterface is mapped. * * @returns Whether the SurfaceInterface is currently mapped * @since 5.22 **/ bool isMapped() const; /** * Returns the tracked damage since the last call to {@link resetTrackedDamage}. * In contrast to {@link damage} this method does not reset the damage when * a new BufferInterface gets committed. This allows a compositor to properly * track the damage over multiple commits even if it didn't render each new * BufferInterface. * * The damage gets reset whenever {@link resetTrackedDamage} is called. * This allows a compositor to properly track the change in its rendering scene * for this SurfaceInterface. After it updates its internal state (e.g. by creating * an OpenGL texture from the BufferInterface) it can invoke {@link resetTrackedDamage} * and the damage tracker will start to track further damage changes. * * @returns Combined damage since last call to resetTrackedDamage * @see damage * @see resetTrackedDamage * @since 5.22 **/ QRegion trackedDamage() const; /** * Reset the damage tracking. The compositor should invoke this method once it updated * it's internal state and processed the current damage. * @see trackedDamage * @since 5.22 **/ void resetTrackedDamage(); /** * Finds the SurfaceInterface at the given @p position in surface-local coordinates. * This can be either a descendant SurfaceInterface honoring the stacking order or * the SurfaceInterface itself if its geometry contains the given @p position. * * If no such SurfaceInterface is found, e.g. because the SurfaceInterface is unmapped, * @c nullptr is returned. * * @param position The position in surface-local coordinates * @returns Child surface at the given @p position or surface itself at the position, might be @c nullptr * @since 5.22 **/ SurfaceInterface *surfaceAt(const QPointF &position); /** * Sets the @p outputs this SurfaceInterface overlaps with, may be empty. * * The compositor should update whenever the SurfaceInterface becomes visible on * an OutputInterface by e.g. getting (un)mapped, resized, moved, etc. * * @see outputs * @since 5.27 **/ void setOutputs(const QVector &outputs); /** * @returns All OutputInterfaces the SurfaceInterface is on. * @see setOutputs * @since 5.27 **/ QVector outputs() const; /** * Pointer confinement installed on this SurfaceInterface. * @see pointerConstraintsChanged * @since 5.29 **/ QPointer confinedPointer() const; /** * Pointer lock installed on this SurfaceInterface. * @see pointerConstraintsChanged * @since 5.29 **/ QPointer lockedPointer() const; + /** + * @returns Whether this SurfaceInterface wants idle to be inhibited on the Output it is shown + * @see inhibitsIdleChanged + * @since 5.41 + **/ + bool inhibitsIdle() const; + /** * @returns The SurfaceInterface for the @p native resource. **/ static SurfaceInterface *get(wl_resource *native); /** * @returns The SurfaceInterface with given @p id for @p client, if it exists, otherwise @c nullptr. * @since 5.3 **/ static SurfaceInterface *get(quint32 id, const ClientConnection *client); Q_SIGNALS: /** * Emitted whenever the SurfaceInterface got damaged. * The signal is only emitted during the commit of state. * A damage means that a new BufferInterface got attached. * * @see buffer * @see damage **/ void damaged(const QRegion&); void opaqueChanged(const QRegion&); void inputChanged(const QRegion&); void scaleChanged(qint32); void transformChanged(KWayland::Server::OutputInterface::Transform); /** * Emitted when the Surface removes its content **/ void unmapped(); /** * @since 5.3 **/ void sizeChanged(); /** * @since 5.4 **/ void shadowChanged(); /** * @since 5.5 **/ void blurChanged(); /** * @since 5.5 **/ void slideOnShowHideChanged(); /** * @since 5.5 **/ void contrastChanged(); /** * Emitted whenever the tree of sub-surfaces changes in a way which requires a repaint. * @since 5.22 **/ void subSurfaceTreeChanged(); /** * Emitted whenever a pointer constraint get (un)installed on this SurfaceInterface. * * The pointer constraint does not get activated, the compositor needs to activate * the lock/confinement. * * @see confinedPointer * @see lockedPointer * @since 5.29 **/ void pointerConstraintsChanged(); + /** + * Emitted whenever the SurfaceInterface starts/ends to inhibit idle. + * @see inhibitsIdle + * @since 5.41 + **/ + void inhibitsIdleChanged(); + private: friend class CompositorInterface; friend class SubSurfaceInterface; friend class ShadowManagerInterface; friend class BlurManagerInterface; friend class SlideManagerInterface; friend class ContrastManagerInterface; + friend class IdleInhibitManagerUnstableV1Interface; friend class PointerConstraintsUnstableV1Interface; explicit SurfaceInterface(CompositorInterface *parent, wl_resource *parentResource); class Private; Private *d_func() const; }; } } Q_DECLARE_METATYPE(KWayland::Server::SurfaceInterface*) #endif diff --git a/src/server/surface_interface_p.h b/src/server/surface_interface_p.h index 30c39db..974fe3b 100644 --- a/src/server/surface_interface_p.h +++ b/src/server/surface_interface_p.h @@ -1,137 +1,141 @@ /******************************************************************** Copyright 2014 Martin Gräßlin This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) version 3, or any later version accepted by the membership of KDE e.V. (or its successor approved by the membership of KDE e.V.), which shall act as a proxy defined in Section 6 of version 3 of the license. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this library. If not, see . *********************************************************************/ #ifndef WAYLAND_SERVER_SURFACE_INTERFACE_P_H #define WAYLAND_SERVER_SURFACE_INTERFACE_P_H #include "surface_interface.h" #include "resource_p.h" // Qt #include // Wayland #include namespace KWayland { namespace Server { +class IdleInhibitorInterface; + class SurfaceInterface::Private : public Resource::Private { public: struct State { QRegion damage = QRegion(); QRegion opaque = QRegion(); QRegion input = QRegion(); bool inputIsSet = false; bool opaqueIsSet = false; bool bufferIsSet = false; bool shadowIsSet = false; bool blurIsSet = false; bool contrastIsSet = false; bool slideIsSet = false; bool inputIsInfinite = true; bool childrenChanged = false; bool scaleIsSet = false; bool transformIsSet = false; qint32 scale = 1; OutputInterface::Transform transform = OutputInterface::Transform::Normal; QList callbacks = QList(); QPoint offset = QPoint(); BufferInterface *buffer = nullptr; // stacking order: bottom (first) -> top (last) QList> children; QPointer shadow; QPointer blur; QPointer contrast; QPointer slide; }; Private(SurfaceInterface *q, CompositorInterface *c, wl_resource *parentResource); ~Private(); void destroy(); void addChild(QPointer subsurface); void removeChild(QPointer subsurface); bool raiseChild(QPointer subsurface, SurfaceInterface *sibling); bool lowerChild(QPointer subsurface, SurfaceInterface *sibling); void setShadow(const QPointer &shadow); void setBlur(const QPointer &blur); void setContrast(const QPointer &contrast); void setSlide(const QPointer &slide); void installPointerConstraint(LockedPointerInterface *lock); void installPointerConstraint(ConfinedPointerInterface *confinement); + void installIdleInhibitor(IdleInhibitorInterface *inhibitor); void commitSubSurface(); void commit(); State current; State pending; State subSurfacePending; QPointer subSurface; QRegion trackedDamage; // workaround for https://bugreports.qt.io/browse/QTBUG-52192 // A subsurface needs to be considered mapped even if it doesn't have a buffer attached // Otherwise Qt's sub-surfaces will never be visible and the client will freeze due to // waiting on the frame callback of the never visible surface bool subSurfaceIsMapped = true; QVector outputs; QPointer lockedPointer; QPointer confinedPointer; QHash outputDestroyedConnections; + QVector idleInhibitors; private: QMetaObject::Connection constrainsOneShotConnection; QMetaObject::Connection constrainsUnboundConnection; SurfaceInterface *q_func() { return reinterpret_cast(q); } void swapStates(State *source, State *target, bool emitChanged); void damage(const QRect &rect); void setScale(qint32 scale); void setTransform(OutputInterface::Transform transform); void addFrameCallback(uint32_t callback); void attachBuffer(wl_resource *buffer, const QPoint &offset); void setOpaque(const QRegion ®ion); void setInput(const QRegion ®ion, bool isInfinite); static void destroyFrameCallback(wl_resource *r); static void attachCallback(wl_client *client, wl_resource *resource, wl_resource *buffer, int32_t sx, int32_t sy); static void damageCallback(wl_client *client, wl_resource *resource, int32_t x, int32_t y, int32_t width, int32_t height); static void frameCallaback(wl_client *client, wl_resource *resource, uint32_t callback); static void opaqueRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region); static void inputRegionCallback(wl_client *client, wl_resource *resource, wl_resource *region); static void commitCallback(wl_client *client, wl_resource *resource); // since version 2 static void bufferTransformCallback(wl_client *client, wl_resource *resource, int32_t transform); // since version 3 static void bufferScaleCallback(wl_client *client, wl_resource *resource, int32_t scale); static const struct wl_surface_interface s_interface; }; } } #endif diff --git a/src/tools/mapping.txt b/src/tools/mapping.txt index 871599f..77f51ab 100644 --- a/src/tools/mapping.txt +++ b/src/tools/mapping.txt @@ -1,60 +1,62 @@ #wl_name;KWayland::ClientName wl_buffer;Buffer wl_compositor;Compositor wl_data_device;DataDevice wl_data_device_manager;DataDeviceManager wl_data_offer;DataOffer wl_data_source;DataSource wl_event_queue;EventQueue wl_keyboard;Keyboard wl_output;Output wl_pointer;Pointer wl_region;Region wl_registry;Registry wl_seat;Seat wl_shell;Shell wl_shell_surface;ShellSurface wl_shm;ShmPool wl_subcompositor;SubCompositor wl_subsurface;SubSurface wl_surface;Surface wl_touch;Touch _wl_fullscreen_shell;FullscreenShell org_kde_kwin_blur;Blur org_kde_kwin_blur_manager;BlurManager org_kde_kwin_contrast;Contrast org_kde_kwin_contrast_manager;ContrastManager org_kde_kwin_slide;Slide org_kde_kwin_slide_manager;SlideManager org_kde_kwin_fake_input;FakeInput org_kde_kwin_idle;Idle org_kde_kwin_idle_timeout;IdleTimeout org_kde_kwin_outputmanagement;OutputManagement org_kde_kwin_outputconfiguration;OutputConfiguration org_kde_kwin_outputdevice;OutputDevice org_kde_kwin_shadow;Shadow org_kde_kwin_shadow_manager;ShadowManager org_kde_plasma_shell;PlasmaShell org_kde_plasma_surface;PlasmaShellSurface org_kde_plasma_window_management;PlasmaWindowManagement org_kde_plasma_window;PlasmaWindow org_kde_kwin_server_decoration_manager;ServerSideDecorationManager org_kde_kwin_server_decoration;ServerSideDecoration wl_text_input;TextInputUnstableV0 wl_text_input_manager;TextInputManagerUnstableV0 zwp_text_input_v2;TextInputUnstableV2 zwp_text_input_manager_v2;TextInputManagerUnstableV2 xdg_shell;XdgShellV5 xdg_surface;XdgSurfaceV5 xdg_popup;XdgPopupV5 zxdg_shell_v6;XdgShellV6 zxdg_surface_v6;XdgSurfaceV6 zxdg_popup_v6;XdgPopupV6 zwp_relative_pointer_manager_v1;RelativePointerManagerUnstableV1 zwp_relative_pointer_v1;RelativePointerUnstableV1 zwp_pointer_gestures_v1;PointerGesturesUnstableV1 zwp_pointer_gesture_swipe_v1;PointerSwipeGestureUnstableV1 zwp_pointer_gesture_pinch_v1;PointerPinchGestureUnstableV1 zwp_pointer_constraints_v1;PointerConstraints zwp_locked_pointer_v1;LockedPointer zwp_confined_pointer_v1;ConfinedPointer +zwp_idle_inhibit_manager_v1;IdleInhibitManager +zwp_idle_inhibitor_v1;IdleInhibitor