mirror of
https://git.outfoxxed.me/quickshell/quickshell.git
synced 2025-11-06 19:14:57 +11:00
wayland/idle-inhibit: add idle inhibitor
This commit is contained in:
parent
a5431dd02d
commit
b8625aa098
8 changed files with 377 additions and 0 deletions
|
|
@ -114,6 +114,9 @@ if (HYPRLAND)
|
||||||
add_subdirectory(hyprland)
|
add_subdirectory(hyprland)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(idle_inhibit)
|
||||||
|
list(APPEND WAYLAND_MODULES Quickshell.Wayland._IdleInhibitor)
|
||||||
|
|
||||||
# widgets for qmenu
|
# widgets for qmenu
|
||||||
target_link_libraries(quickshell-wayland PRIVATE
|
target_link_libraries(quickshell-wayland PRIVATE
|
||||||
Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate
|
Qt::Quick Qt::Widgets Qt::WaylandClient Qt::WaylandClientPrivate
|
||||||
|
|
|
||||||
25
src/wayland/idle_inhibit/CMakeLists.txt
Normal file
25
src/wayland/idle_inhibit/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
qt_add_library(quickshell-wayland-idle-inhibit STATIC
|
||||||
|
proto.cpp
|
||||||
|
inhibitor.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
qt_add_qml_module(quickshell-wayland-idle-inhibit
|
||||||
|
URI Quickshell.Wayland._IdleInhibitor
|
||||||
|
VERSION 0.1
|
||||||
|
DEPENDENCIES QtQuick
|
||||||
|
)
|
||||||
|
|
||||||
|
install_qml_module(quickshell-wayland-idle-inhibit)
|
||||||
|
|
||||||
|
qs_add_module_deps_light(quickshell-wayland-idle-inhibit Quickshell)
|
||||||
|
|
||||||
|
wl_proto(wlp-idle-inhibit idle-inhibit-unstable-v1 "${CMAKE_CURRENT_SOURCE_DIR}")
|
||||||
|
|
||||||
|
target_link_libraries(quickshell-wayland-idle-inhibit PRIVATE
|
||||||
|
Qt::Quick Qt::WaylandClient Qt::WaylandClientPrivate wayland-client
|
||||||
|
wlp-idle-inhibit
|
||||||
|
)
|
||||||
|
|
||||||
|
qs_module_pch(quickshell-wayland-idle-inhibit SET large)
|
||||||
|
|
||||||
|
target_link_libraries(quickshell PRIVATE quickshell-wayland-idle-inhibitplugin)
|
||||||
83
src/wayland/idle_inhibit/idle-inhibit-unstable-v1.xml
Normal file
83
src/wayland/idle_inhibit/idle-inhibit-unstable-v1.xml
Normal file
|
|
@ -0,0 +1,83 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="idle_inhibit_unstable_v1">
|
||||||
|
|
||||||
|
<copyright>
|
||||||
|
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.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="zwp_idle_inhibit_manager_v1" version="1">
|
||||||
|
<description summary="control behavior when display idles">
|
||||||
|
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.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the idle inhibitor object">
|
||||||
|
Destroy the inhibit manager.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="create_inhibitor">
|
||||||
|
<description summary="create a new inhibitor object">
|
||||||
|
Create a new inhibitor object associated with the given surface.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_idle_inhibitor_v1"/>
|
||||||
|
<arg name="surface" type="object" interface="wl_surface"
|
||||||
|
summary="the surface that inhibits the idle behavior"/>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_idle_inhibitor_v1" version="1">
|
||||||
|
<description summary="context object for inhibiting idle behavior">
|
||||||
|
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.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy the idle inhibitor object">
|
||||||
|
Remove the inhibitor effect from the associated wl_surface.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
136
src/wayland/idle_inhibit/inhibitor.cpp
Normal file
136
src/wayland/idle_inhibit/inhibitor.cpp
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include "inhibitor.hpp"
|
||||||
|
|
||||||
|
#include <private/qwaylandwindow_p.h>
|
||||||
|
#include <qlogging.h>
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
#include "../../window/proxywindow.hpp"
|
||||||
|
#include "../../window/windowinterface.hpp"
|
||||||
|
#include "proto.hpp"
|
||||||
|
|
||||||
|
namespace qs::wayland::idle_inhibit {
|
||||||
|
using QtWaylandClient::QWaylandWindow;
|
||||||
|
|
||||||
|
IdleInhibitor::IdleInhibitor() {
|
||||||
|
this->bBoundWindow.setBinding([this] { return this->bEnabled ? this->bWindowObject : nullptr; });
|
||||||
|
}
|
||||||
|
|
||||||
|
QObject* IdleInhibitor::window() const { return this->bWindowObject; }
|
||||||
|
|
||||||
|
void IdleInhibitor::setWindow(QObject* window) {
|
||||||
|
if (window == this->bWindowObject) return;
|
||||||
|
|
||||||
|
auto* proxyWindow = qobject_cast<ProxyWindowBase*>(window);
|
||||||
|
|
||||||
|
if (proxyWindow == nullptr) {
|
||||||
|
if (auto* iface = qobject_cast<WindowInterface*>(window)) {
|
||||||
|
proxyWindow = iface->proxyWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->bWindowObject = proxyWindow ? window : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleInhibitor::boundWindowChanged() {
|
||||||
|
auto* window = this->bBoundWindow.value();
|
||||||
|
auto* proxyWindow = qobject_cast<ProxyWindowBase*>(window);
|
||||||
|
|
||||||
|
if (proxyWindow == nullptr) {
|
||||||
|
if (auto* iface = qobject_cast<WindowInterface*>(window)) {
|
||||||
|
proxyWindow = iface->proxyWindow();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxyWindow == this->proxyWindow) return;
|
||||||
|
|
||||||
|
if (this->mWaylandWindow) {
|
||||||
|
QObject::disconnect(this->mWaylandWindow, nullptr, this, nullptr);
|
||||||
|
this->mWaylandWindow = nullptr;
|
||||||
|
this->onWaylandSurfaceDestroyed();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->proxyWindow) {
|
||||||
|
QObject::disconnect(this->proxyWindow, nullptr, this, nullptr);
|
||||||
|
this->proxyWindow = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (proxyWindow) {
|
||||||
|
this->proxyWindow = proxyWindow;
|
||||||
|
|
||||||
|
QObject::connect(proxyWindow, &QObject::destroyed, this, &IdleInhibitor::onWindowDestroyed);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
proxyWindow,
|
||||||
|
&ProxyWindowBase::backerVisibilityChanged,
|
||||||
|
this,
|
||||||
|
&IdleInhibitor::onWindowVisibilityChanged
|
||||||
|
);
|
||||||
|
|
||||||
|
this->onWindowVisibilityChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
emit this->windowChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleInhibitor::onWindowDestroyed() {
|
||||||
|
this->proxyWindow = nullptr;
|
||||||
|
this->onWaylandSurfaceDestroyed();
|
||||||
|
this->bWindowObject = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleInhibitor::onWindowVisibilityChanged() {
|
||||||
|
if (!this->proxyWindow->isVisibleDirect()) return;
|
||||||
|
|
||||||
|
auto* window = this->proxyWindow->backingWindow();
|
||||||
|
if (!window->handle()) window->create();
|
||||||
|
|
||||||
|
auto* waylandWindow = dynamic_cast<QWaylandWindow*>(window->handle());
|
||||||
|
if (waylandWindow == this->mWaylandWindow) return;
|
||||||
|
this->mWaylandWindow = waylandWindow;
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
waylandWindow,
|
||||||
|
&QObject::destroyed,
|
||||||
|
this,
|
||||||
|
&IdleInhibitor::onWaylandWindowDestroyed
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
waylandWindow,
|
||||||
|
&QWaylandWindow::surfaceCreated,
|
||||||
|
this,
|
||||||
|
&IdleInhibitor::onWaylandSurfaceCreated
|
||||||
|
);
|
||||||
|
|
||||||
|
QObject::connect(
|
||||||
|
waylandWindow,
|
||||||
|
&QWaylandWindow::surfaceDestroyed,
|
||||||
|
this,
|
||||||
|
&IdleInhibitor::onWaylandSurfaceDestroyed
|
||||||
|
);
|
||||||
|
|
||||||
|
if (waylandWindow->surface()) this->onWaylandSurfaceCreated();
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleInhibitor::onWaylandWindowDestroyed() { this->mWaylandWindow = nullptr; }
|
||||||
|
|
||||||
|
void IdleInhibitor::onWaylandSurfaceCreated() {
|
||||||
|
auto* manager = impl::IdleInhibitManager::instance();
|
||||||
|
|
||||||
|
if (!manager) {
|
||||||
|
qWarning() << "Cannot enable idle inhibitor as idle-inhibit-unstable-v1 is not supported by "
|
||||||
|
"the current compositor.";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
delete this->inhibitor;
|
||||||
|
this->inhibitor = manager->createIdleInhibitor(this->mWaylandWindow);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IdleInhibitor::onWaylandSurfaceDestroyed() {
|
||||||
|
delete this->inhibitor;
|
||||||
|
this->inhibitor = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::wayland::idle_inhibit
|
||||||
72
src/wayland/idle_inhibit/inhibitor.hpp
Normal file
72
src/wayland/idle_inhibit/inhibitor.hpp
Normal file
|
|
@ -0,0 +1,72 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <qobject.h>
|
||||||
|
#include <qproperty.h>
|
||||||
|
#include <qqmlintegration.h>
|
||||||
|
#include <qtmetamacros.h>
|
||||||
|
|
||||||
|
#include "../../window/proxywindow.hpp"
|
||||||
|
#include "proto.hpp"
|
||||||
|
|
||||||
|
namespace qs::wayland::idle_inhibit {
|
||||||
|
|
||||||
|
///! Prevents a wayland session from idling
|
||||||
|
/// If an idle daemon is running, it may perform actions such as locking the screen
|
||||||
|
/// or putting the computer to sleep.
|
||||||
|
///
|
||||||
|
/// An idle inhibitor prevents a wayland session from being marked as idle, if compositor
|
||||||
|
/// defined heuristics determine the window the inhibitor is attached to is important.
|
||||||
|
///
|
||||||
|
/// A compositor will usually consider a @@Quickshell.PanelWindow or
|
||||||
|
/// a focused @@Quickshell.FloatingWindow to be important.
|
||||||
|
///
|
||||||
|
/// > [!NOTE] Using an idle inhibitor requires the compositor support the [idle-inhibit-unstable-v1] protocol.
|
||||||
|
///
|
||||||
|
/// [idle-inhibit-unstable-v1]: https://wayland.app/protocols/idle-inhibit-unstable-v1
|
||||||
|
class IdleInhibitor: public QObject {
|
||||||
|
Q_OBJECT;
|
||||||
|
QML_ELEMENT;
|
||||||
|
// clang-format off
|
||||||
|
/// If the idle inhibitor should be enabled. Defaults to false.
|
||||||
|
Q_PROPERTY(bool enabled READ default WRITE default NOTIFY enabledChanged BINDABLE bindableEnabled);
|
||||||
|
/// The window to associate the idle inhibitor with. This may be used by the compositor
|
||||||
|
/// to determine if the inhibitor should be respected.
|
||||||
|
///
|
||||||
|
/// Must be set to a non null value to enable the inhibitor.
|
||||||
|
Q_PROPERTY(QObject* window READ window WRITE setWindow NOTIFY windowChanged);
|
||||||
|
// clang-format on
|
||||||
|
|
||||||
|
public:
|
||||||
|
IdleInhibitor();
|
||||||
|
|
||||||
|
[[nodiscard]] QObject* window() const;
|
||||||
|
void setWindow(QObject* window);
|
||||||
|
|
||||||
|
[[nodiscard]] QBindable<bool> bindableEnabled() { return &this->bEnabled; }
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void enabledChanged();
|
||||||
|
void windowChanged();
|
||||||
|
|
||||||
|
private slots:
|
||||||
|
void onWindowDestroyed();
|
||||||
|
void onWindowVisibilityChanged();
|
||||||
|
void onWaylandWindowDestroyed();
|
||||||
|
void onWaylandSurfaceCreated();
|
||||||
|
void onWaylandSurfaceDestroyed();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void boundWindowChanged();
|
||||||
|
ProxyWindowBase* proxyWindow = nullptr;
|
||||||
|
QtWaylandClient::QWaylandWindow* mWaylandWindow = nullptr;
|
||||||
|
|
||||||
|
impl::IdleInhibitor* inhibitor = nullptr;
|
||||||
|
|
||||||
|
// clang-format off
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(IdleInhibitor, bool, bEnabled, &IdleInhibitor::enabledChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(IdleInhibitor, QObject*, bWindowObject, &IdleInhibitor::windowChanged);
|
||||||
|
Q_OBJECT_BINDABLE_PROPERTY(IdleInhibitor, QObject*, bBoundWindow, &IdleInhibitor::boundWindowChanged);
|
||||||
|
// clang-format on
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::wayland::idle_inhibit
|
||||||
23
src/wayland/idle_inhibit/proto.cpp
Normal file
23
src/wayland/idle_inhibit/proto.cpp
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include "proto.hpp"
|
||||||
|
|
||||||
|
#include <private/qwaylandwindow_p.h>
|
||||||
|
#include <qwaylandclientextension.h>
|
||||||
|
|
||||||
|
namespace qs::wayland::idle_inhibit::impl {
|
||||||
|
|
||||||
|
IdleInhibitManager::IdleInhibitManager(): QWaylandClientExtensionTemplate(1) { this->initialize(); }
|
||||||
|
|
||||||
|
IdleInhibitManager* IdleInhibitManager::instance() {
|
||||||
|
static auto* instance = new IdleInhibitManager(); // NOLINT
|
||||||
|
return instance->isInitialized() ? instance : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleInhibitor* IdleInhibitManager::createIdleInhibitor(QtWaylandClient::QWaylandWindow* surface) {
|
||||||
|
return new IdleInhibitor(this->create_inhibitor(surface->surface()));
|
||||||
|
}
|
||||||
|
|
||||||
|
IdleInhibitor::~IdleInhibitor() {
|
||||||
|
if (this->isInitialized()) this->destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace qs::wayland::idle_inhibit::impl
|
||||||
34
src/wayland/idle_inhibit/proto.hpp
Normal file
34
src/wayland/idle_inhibit/proto.hpp
Normal file
|
|
@ -0,0 +1,34 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <private/qwaylandwindow_p.h>
|
||||||
|
#include <qtclasshelpermacros.h>
|
||||||
|
#include <qwayland-idle-inhibit-unstable-v1.h>
|
||||||
|
#include <qwaylandclientextension.h>
|
||||||
|
|
||||||
|
#include "wayland-idle-inhibit-unstable-v1-client-protocol.h"
|
||||||
|
|
||||||
|
namespace qs::wayland::idle_inhibit::impl {
|
||||||
|
|
||||||
|
class IdleInhibitor;
|
||||||
|
|
||||||
|
class IdleInhibitManager
|
||||||
|
: public QWaylandClientExtensionTemplate<IdleInhibitManager>
|
||||||
|
, public QtWayland::zwp_idle_inhibit_manager_v1 {
|
||||||
|
public:
|
||||||
|
explicit IdleInhibitManager();
|
||||||
|
|
||||||
|
IdleInhibitor* createIdleInhibitor(QtWaylandClient::QWaylandWindow* surface);
|
||||||
|
|
||||||
|
static IdleInhibitManager* instance();
|
||||||
|
};
|
||||||
|
|
||||||
|
class IdleInhibitor: public QtWayland::zwp_idle_inhibitor_v1 {
|
||||||
|
public:
|
||||||
|
explicit IdleInhibitor(::zwp_idle_inhibitor_v1* inhibitor)
|
||||||
|
: QtWayland::zwp_idle_inhibitor_v1(inhibitor) {}
|
||||||
|
|
||||||
|
~IdleInhibitor() override;
|
||||||
|
Q_DISABLE_COPY_MOVE(IdleInhibitor);
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace qs::wayland::idle_inhibit::impl
|
||||||
|
|
@ -5,5 +5,6 @@ headers = [
|
||||||
"session_lock.hpp",
|
"session_lock.hpp",
|
||||||
"toplevel_management/qml.hpp",
|
"toplevel_management/qml.hpp",
|
||||||
"screencopy/view.hpp",
|
"screencopy/view.hpp",
|
||||||
|
"idle_inhibit/inhibitor.hpp",
|
||||||
]
|
]
|
||||||
-----
|
-----
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue