diff --git a/autotests/client/test_wayland_registry.cpp b/autotests/client/test_wayland_registry.cpp --- a/autotests/client/test_wayland_registry.cpp +++ b/autotests/client/test_wayland_registry.cpp @@ -30,6 +30,7 @@ #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" @@ -41,6 +42,7 @@ #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" @@ -59,6 +61,7 @@ // Wayland #include #include +#include #include #include #include @@ -95,6 +98,7 @@ void testBindRelativePointerManagerUnstableV1(); void testBindPointerGesturesUnstableV1(); void testBindPointerConstraintsUnstableV1(); + void testBindIdleIhibitManagerUnstableV1(); void testGlobalSync(); void testGlobalSyncThreaded(); void testRemoval(); @@ -122,6 +126,7 @@ KWayland::Server::PointerConstraintsInterface *m_pointerConstraintsV1; KWayland::Server::BlurManagerInterface *m_blur; KWayland::Server::ContrastManagerInterface *m_contrast; + KWayland::Server::IdleInhibitManagerInterface *m_idleInhibit; }; @@ -147,6 +152,7 @@ , m_pointerConstraintsV1(nullptr) , m_blur(nullptr) , m_contrast(nullptr) + , m_idleInhibit(nullptr) { } @@ -199,6 +205,9 @@ 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() @@ -356,6 +365,11 @@ 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() @@ -393,6 +407,8 @@ 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()); @@ -408,6 +424,7 @@ QVERIFY(!outputManagementAnnouncedSpy.isEmpty()); QVERIFY(!serverSideDecorationManagerAnnouncedSpy.isEmpty()); QVERIFY(!blurAnnouncedSpy.isEmpty()); + QVERIFY(!idleInhibitManagerUnstableV1AnnouncedSpy.isEmpty()); QVERIFY(registry.hasInterface(KWayland::Client::Registry::Interface::Compositor)); @@ -421,6 +438,7 @@ 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()); @@ -433,6 +451,7 @@ 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()); @@ -444,6 +463,7 @@ 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(); @@ -457,6 +477,8 @@ 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()); @@ -547,6 +569,14 @@ 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 @@ -557,6 +587,7 @@ QCOMPARE(subcompositorObjectRemovedSpy.count(), 1); QCOMPARE(serverSideDecoManagerObjectRemovedSpy.count(), 1); QCOMPARE(blurObjectRemovedSpy.count(), 1); + QCOMPARE(idleInhibitManagerObjectRemovedSpy.count(), 1); } void TestWaylandRegistry::testOutOfSyncRemoval() diff --git a/autotests/client/test_wayland_surface.cpp b/autotests/client/test_wayland_surface.cpp --- a/autotests/client/test_wayland_surface.cpp +++ b/autotests/client/test_wayland_surface.cpp @@ -25,18 +25,22 @@ #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 @@ -62,14 +66,17 @@ 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; }; @@ -100,6 +107,11 @@ 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())); @@ -143,6 +155,9 @@ 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() @@ -1091,5 +1106,53 @@ 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 --- a/src/client/CMakeLists.txt +++ b/src/client/CMakeLists.txt @@ -21,6 +21,7 @@ fakeinput.cpp fullscreen_shell.cpp idle.cpp + idleinhibit.cpp keyboard.cpp outputconfiguration.cpp outputmanagement.cpp @@ -149,6 +150,10 @@ 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 @@ -190,6 +195,7 @@ fakeinput.h fullscreen_shell.h idle.h + idleinhibit.h keyboard.h outputconfiguration.h outputmanagement.h diff --git a/src/client/idleinhibit.h b/src/client/idleinhibit.h new file mode 100644 --- /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/idleinhibit.cpp b/src/client/idleinhibit.cpp new file mode 100644 --- /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/protocols/idle-inhibit-unstable-v1.xml b/src/client/protocols/idle-inhibit-unstable-v1.xml new file mode 100644 --- /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.h b/src/client/registry.h --- a/src/client/registry.h +++ b/src/client/registry.h @@ -56,6 +56,7 @@ struct zwp_pointer_constraints_v1; struct zxdg_exporter_v2; struct zxdg_importer_v2; +struct zwp_idle_inhibit_manager_v1; namespace KWayland { @@ -72,6 +73,7 @@ class OutputManagement; class OutputDevice; class Idle; +class IdleInhibitManager; class Output; class PlasmaShell; class PlasmaWindowManagement; @@ -160,7 +162,8 @@ 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(); @@ -557,6 +560,16 @@ * @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; ///@} /** @@ -997,6 +1010,21 @@ * @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); ///@} /** @@ -1210,6 +1238,14 @@ * @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. @@ -1383,6 +1419,13 @@ * @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 diff --git a/src/client/registry.cpp b/src/client/registry.cpp --- a/src/client/registry.cpp +++ b/src/client/registry.cpp @@ -26,6 +26,7 @@ #include "fakeinput.h" #include "fullscreen_shell.h" #include "idle.h" +#include "idleinhibit.h" #include "logging_p.h" #include "outputconfiguration.h" #include "outputmanagement.h" @@ -58,6 +59,7 @@ #include #include #include +#include #include #include #include @@ -305,6 +307,13 @@ &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 }} }; @@ -608,6 +617,7 @@ 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) @@ -732,6 +742,16 @@ } } +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) { diff --git a/src/server/CMakeLists.txt b/src/server/CMakeLists.txt --- a/src/server/CMakeLists.txt +++ b/src/server/CMakeLists.txt @@ -10,6 +10,8 @@ dpms_interface.cpp global.cpp idle_interface.cpp + idleinhibit_interface.cpp + idleinhibit_interface_v1.cpp fakeinput_interface.cpp keyboard_interface.cpp outputconfiguration_interface.cpp @@ -154,6 +156,11 @@ 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 @@ -198,6 +205,7 @@ fakeinput_interface.h global.h idle_interface.h + idleinhibit_interface.h keyboard_interface.h outputdevice_interface.h outputchangeset.h diff --git a/src/server/display.h b/src/server/display.h --- a/src/server/display.h +++ b/src/server/display.h @@ -53,6 +53,8 @@ class DataDeviceManagerInterface; class DpmsManagerInterface; class IdleInterface; +enum class IdleInhibitManagerInterfaceVersion; +class IdleInhibitManagerInterface; class FakeInputInterface; class OutputInterface; class OutputDeviceInterface; @@ -227,6 +229,15 @@ * @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. diff --git a/src/server/display.cpp b/src/server/display.cpp --- a/src/server/display.cpp +++ b/src/server/display.cpp @@ -25,6 +25,7 @@ #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" @@ -420,6 +421,18 @@ 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); diff --git a/src/server/idleinhibit_interface.h b/src/server/idleinhibit_interface.h new file mode 100644 --- /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.cpp b/src/server/idleinhibit_interface.cpp new file mode 100644 --- /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_p.h b/src/server/idleinhibit_interface_p.h new file mode 100644 --- /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 --- /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.h b/src/server/surface_interface.h --- a/src/server/surface_interface.h +++ b/src/server/surface_interface.h @@ -40,6 +40,7 @@ class ContrastInterface; class ContrastManagerInterface; class CompositorInterface; +class IdleInhibitManagerUnstableV1Interface; class LockedPointerInterface; class PointerConstraintsUnstableV1Interface; class ShadowManagerInterface; @@ -242,6 +243,13 @@ **/ 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. **/ @@ -308,13 +316,21 @@ **/ 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); diff --git a/src/server/surface_interface.cpp b/src/server/surface_interface.cpp --- a/src/server/surface_interface.cpp +++ b/src/server/surface_interface.cpp @@ -22,6 +22,7 @@ #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" @@ -213,6 +214,22 @@ 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()); @@ -856,6 +873,12 @@ 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_p.h b/src/server/surface_interface_p.h --- a/src/server/surface_interface_p.h +++ b/src/server/surface_interface_p.h @@ -32,6 +32,8 @@ namespace Server { +class IdleInhibitorInterface; + class SurfaceInterface::Private : public Resource::Private { public: @@ -77,6 +79,7 @@ void setSlide(const QPointer &slide); void installPointerConstraint(LockedPointerInterface *lock); void installPointerConstraint(ConfinedPointerInterface *confinement); + void installIdleInhibitor(IdleInhibitorInterface *inhibitor); void commitSubSurface(); void commit(); @@ -98,6 +101,7 @@ QPointer lockedPointer; QPointer confinedPointer; QHash outputDestroyedConnections; + QVector idleInhibitors; private: QMetaObject::Connection constrainsOneShotConnection; diff --git a/src/tools/mapping.txt b/src/tools/mapping.txt --- a/src/tools/mapping.txt +++ b/src/tools/mapping.txt @@ -58,3 +58,5 @@ 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