diff --git a/CMakeLists.txt b/CMakeLists.txt
index 23d2b085..6d0d1437 100755
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -249,7 +249,6 @@ target_link_libraries(Hyprland
uuid
)
-protocol("protocols/idle.xml" "idle" true)
protocol("protocols/tablet-unstable-v2.xml" "tablet-unstable-v2" true)
protocol("protocols/wlr-layer-shell-unstable-v1.xml" "wlr-layer-shell-unstable-v1" true)
protocol("protocols/wlr-screencopy-unstable-v1.xml" "wlr-screencopy-unstable-v1" true)
@@ -276,6 +275,7 @@ protocolNew("unstable/keyboard-shortcuts-inhibit/keyboard-shortcuts-inhibit-unst
protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstable-v3" false)
protocolNew("unstable/pointer-constraints/pointer-constraints-unstable-v1.xml" "pointer-constraints-unstable-v1" false)
protocolNew("staging/xdg-activation/xdg-activation-v1.xml" "xdg-activation-v1" false)
+protocolNew("staging/ext-idle-notify/ext-idle-notify-v1.xml" "ext-idle-notify-v1" false)
# tools
add_subdirectory(hyprctl)
diff --git a/protocols/idle.xml b/protocols/idle.xml
deleted file mode 100644
index 92d9989c..00000000
--- a/protocols/idle.xml
+++ /dev/null
@@ -1,49 +0,0 @@
-
-
- .
- ]]>
-
-
- This interface allows to monitor user idle time on a given seat. The interface
- allows to register timers which trigger after no user activity was registered
- on the seat for a given interval. It notifies when user activity resumes.
-
- This is useful for applications wanting to perform actions when the user is not
- interacting with the system, e.g. chat applications setting the user as away, power
- management features to dim screen, etc..
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/protocols/meson.build b/protocols/meson.build
index 6e7ae666..3b4c4dd1 100644
--- a/protocols/meson.build
+++ b/protocols/meson.build
@@ -30,7 +30,6 @@ protocols = [
['wlr-layer-shell-unstable-v1.xml'],
['wlr-screencopy-unstable-v1.xml'],
['tablet-unstable-v2.xml'],
- ['idle.xml'],
[hl_protocol_dir, 'protocols/hyprland-toplevel-export-v1.xml'],
[hl_protocol_dir, 'protocols/hyprland-global-shortcuts-v1.xml']
]
@@ -53,6 +52,7 @@ new_protocols = [
[wl_protocol_dir, 'unstable/text-input/text-input-unstable-v3.xml'],
[wl_protocol_dir, 'unstable/pointer-constraints/pointer-constraints-unstable-v1.xml'],
[wl_protocol_dir, 'staging/xdg-activation/xdg-activation-v1.xml'],
+ [wl_protocol_dir, 'staging/ext-idle-notify/ext-idle-notify-v1.xml'],
]
wl_protos_src = []
diff --git a/src/Compositor.cpp b/src/Compositor.cpp
index d1b41e1d..b8358cbe 100644
--- a/src/Compositor.cpp
+++ b/src/Compositor.cpp
@@ -237,8 +237,6 @@ void CCompositor::initServer() {
m_sWLRPresentation = wlr_presentation_create(m_sWLDisplay, m_sWLRBackend);
- m_sWLRIdleNotifier = wlr_idle_notifier_v1_create(m_sWLDisplay);
-
m_sWLRLayerShell = wlr_layer_shell_v1_create(m_sWLDisplay, 4);
m_sWLRServerDecoMgr = wlr_server_decoration_manager_create(m_sWLDisplay);
@@ -2701,13 +2699,6 @@ PHLWINDOW CCompositor::getForceFocus() {
return nullptr;
}
-void CCompositor::notifyIdleActivity() {
- wlr_idle_notifier_v1_notify_activity(g_pCompositor->m_sWLRIdleNotifier, g_pCompositor->m_sSeat.seat);
-}
-
-void CCompositor::setIdleActivityInhibit(bool enabled) {
- wlr_idle_notifier_v1_set_inhibited(g_pCompositor->m_sWLRIdleNotifier, !enabled);
-}
void CCompositor::arrangeMonitors() {
static auto* const PXWLFORCESCALEZERO = (Hyprlang::INT* const*)g_pConfigManager->getConfigValuePtr("xwayland:force_zero_scaling");
diff --git a/src/Compositor.hpp b/src/Compositor.hpp
index bfb347af..d0acad4d 100644
--- a/src/Compositor.hpp
+++ b/src/Compositor.hpp
@@ -52,7 +52,6 @@ class CCompositor {
wlr_drm* m_sWRLDRM;
wlr_drm_lease_v1_manager* m_sWRLDRMLeaseMgr;
wlr_output_layout* m_sWLROutputLayout;
- wlr_idle_notifier_v1* m_sWLRIdleNotifier;
wlr_layer_shell_v1* m_sWLRLayerShell;
wlr_xdg_shell* m_sWLRXDGShell;
wlr_cursor* m_sWLRCursor;
@@ -185,8 +184,6 @@ class CCompositor {
void performUserChecks();
void moveWindowToWorkspaceSafe(PHLWINDOW pWindow, PHLWORKSPACE pWorkspace);
PHLWINDOW getForceFocus();
- void notifyIdleActivity();
- void setIdleActivityInhibit(bool inhibit);
void arrangeMonitors();
void enterUnsafeState();
void leaveUnsafeState();
diff --git a/src/includes.hpp b/src/includes.hpp
index cdb38bd7..d6f98a88 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -92,7 +92,6 @@ extern "C" {
#include
#include
#include
-#include
#include
#include
#include
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index b00e111e..b721f17a 100644
--- a/src/managers/ProtocolManager.cpp
+++ b/src/managers/ProtocolManager.cpp
@@ -17,6 +17,7 @@
#include "../protocols/PointerConstraints.hpp"
#include "../protocols/OutputPower.hpp"
#include "../protocols/XDGActivation.hpp"
+#include "../protocols/IdleNotify.hpp"
#include "tearing-control-v1.hpp"
#include "fractional-scale-v1.hpp"
@@ -35,6 +36,7 @@
#include "pointer-constraints-unstable-v1.hpp"
#include "wlr-output-power-management-unstable-v1.hpp"
#include "xdg-activation-v1.hpp"
+#include "ext-idle-notify-v1.hpp"
CProtocolManager::CProtocolManager() {
@@ -55,6 +57,7 @@ CProtocolManager::CProtocolManager() {
PROTO::constraints = std::make_unique(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints");
PROTO::outputPower = std::make_unique(&zwlr_output_power_manager_v1_interface, 1, "OutputPower");
PROTO::activation = std::make_unique(&xdg_activation_v1_interface, 1, "XDGActivation");
+ PROTO::idle = std::make_unique(&ext_idle_notifier_v1_interface, 1, "IdleNotify");
// Old protocol implementations.
// TODO: rewrite them to use hyprwayland-scanner.
diff --git a/src/managers/input/IdleInhibitor.cpp b/src/managers/input/IdleInhibitor.cpp
index 6ec5fc81..40c8c637 100644
--- a/src/managers/input/IdleInhibitor.cpp
+++ b/src/managers/input/IdleInhibitor.cpp
@@ -1,6 +1,7 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
#include "../../protocols/IdleInhibit.hpp"
+#include "../../protocols/IdleNotify.hpp"
void CInputManager::newIdleInhibitor(std::any inhibitor) {
const auto PINHIBIT = m_vIdleInhibitors.emplace_back(std::make_unique()).get();
@@ -29,11 +30,11 @@ void CInputManager::newIdleInhibitor(std::any inhibitor) {
void CInputManager::recheckIdleInhibitorStatus() {
for (auto& ii : m_vIdleInhibitors) {
- if (ii->pWindow.expired()) {
- g_pCompositor->setIdleActivityInhibit(false);
- return;
- } else if (g_pHyprRenderer->shouldRenderWindow(ii->pWindow.lock())) {
- g_pCompositor->setIdleActivityInhibit(false);
+ if (ii->pWindow.expired())
+ continue;
+
+ if (g_pHyprRenderer->shouldRenderWindow(ii->pWindow.lock())) {
+ PROTO::idle->setInhibit(true);
return;
}
}
@@ -44,21 +45,21 @@ void CInputManager::recheckIdleInhibitorStatus() {
continue;
if (w->m_eIdleInhibitMode == IDLEINHIBIT_ALWAYS) {
- g_pCompositor->setIdleActivityInhibit(false);
+ PROTO::idle->setInhibit(true);
return;
}
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FOCUS && g_pCompositor->isWindowActive(w)) {
- g_pCompositor->setIdleActivityInhibit(false);
+ PROTO::idle->setInhibit(true);
return;
}
if (w->m_eIdleInhibitMode == IDLEINHIBIT_FULLSCREEN && w->m_bIsFullscreen && g_pCompositor->isWorkspaceVisible(w->m_pWorkspace)) {
- g_pCompositor->setIdleActivityInhibit(false);
+ PROTO::idle->setInhibit(true);
return;
}
}
- g_pCompositor->setIdleActivityInhibit(true);
+ PROTO::idle->setInhibit(false);
return;
}
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index adfa5029..47dc2bf6 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -8,6 +8,7 @@
#include "../../protocols/IdleInhibit.hpp"
#include "../../protocols/RelativePointer.hpp"
#include "../../protocols/PointerConstraints.hpp"
+#include "../../protocols/IdleNotify.hpp"
CInputManager::CInputManager() {
m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) {
@@ -144,7 +145,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
EMIT_HOOK_EVENT_CANCELLABLE("mouseMove", MOUSECOORDSFLOORED);
if (time)
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
m_vLastCursorPosFloored = MOUSECOORDSFLOORED;
@@ -480,7 +481,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) {
void CInputManager::onMouseButton(wlr_pointer_button_event* e) {
EMIT_HOOK_EVENT_CANCELLABLE("mouseButton", e);
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
m_tmrLastCursorMovement.reset();
@@ -705,7 +706,7 @@ void CInputManager::onMouseWheel(wlr_pointer_axis_event* e) {
bool passEvent = g_pKeybindManager->onAxisEvent(e);
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
if (!passEvent)
return;
@@ -1216,7 +1217,7 @@ void CInputManager::onKeyboardKey(wlr_keyboard_key_event* e, SKeyboard* pKeyboar
bool passEvent = g_pKeybindManager->onKeyEvent(e, pKeyboard);
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
if (passEvent) {
diff --git a/src/managers/input/Tablets.cpp b/src/managers/input/Tablets.cpp
index d60a6a6f..979eb1a7 100644
--- a/src/managers/input/Tablets.cpp
+++ b/src/managers/input/Tablets.cpp
@@ -1,5 +1,6 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
+#include "../../protocols/IdleNotify.hpp"
void CInputManager::newTabletTool(wlr_input_device* pDevice) {
const auto PNEWTABLET = &m_lTablets.emplace_back();
@@ -99,7 +100,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
if (EVENT->updated_axes & (WLR_TABLET_TOOL_AXIS_TILT_X | WLR_TABLET_TOOL_AXIS_TILT_Y))
wlr_tablet_v2_tablet_tool_notify_tilt(PTOOL->wlrTabletToolV2, PTOOL->tiltX, PTOOL->tiltY);
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
},
PNEWTABLET, "Tablet");
@@ -120,7 +121,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
wlr_send_tablet_v2_tablet_tool_up(PTOOL->wlrTabletToolV2);
}
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
},
PNEWTABLET, "Tablet");
@@ -132,7 +133,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
const auto PTOOL = g_pInputManager->ensureTabletToolPresent(EVENT->tool);
wlr_tablet_v2_tablet_tool_notify_button(PTOOL->wlrTabletToolV2, (zwp_tablet_pad_v2_button_state)EVENT->button, (zwp_tablet_pad_v2_button_state)EVENT->state);
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
},
PNEWTABLET, "Tablet");
@@ -158,7 +159,7 @@ void CInputManager::newTabletTool(wlr_input_device* pDevice) {
g_pInputManager->focusTablet(PTAB, EVENT->tool);
}
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
},
PNEWTABLET, "Tablet");
diff --git a/src/managers/input/Touch.cpp b/src/managers/input/Touch.cpp
index 302d9e1d..a3f28ac0 100644
--- a/src/managers/input/Touch.cpp
+++ b/src/managers/input/Touch.cpp
@@ -1,6 +1,7 @@
#include "InputManager.hpp"
#include "../../Compositor.hpp"
#include "../../config/ConfigValue.hpp"
+#include "../../protocols/IdleNotify.hpp"
void CInputManager::onTouchDown(wlr_touch_down_event* e) {
static auto PSWIPETOUCH = CConfigValue("gestures:workspace_swipe_touch");
@@ -83,7 +84,7 @@ void CInputManager::onTouchDown(wlr_touch_down_event* e) {
wlr_seat_touch_notify_down(g_pCompositor->m_sSeat.seat, m_sTouchData.touchFocusSurface, e->time_msec, e->touch_id, local.x, local.y);
- g_pCompositor->notifyIdleActivity();
+ PROTO::idle->onActivity();
}
void CInputManager::onTouchUp(wlr_touch_up_event* e) {
diff --git a/src/protocols/IdleNotify.cpp b/src/protocols/IdleNotify.cpp
new file mode 100644
index 00000000..950fbf06
--- /dev/null
+++ b/src/protocols/IdleNotify.cpp
@@ -0,0 +1,104 @@
+#include "IdleNotify.hpp"
+#include "../managers/eventLoop/EventLoopManager.hpp"
+
+#define LOGM PROTO::idle->protoLog
+
+static int onTimer(std::shared_ptr self, void* data) {
+
+ const auto NOTIF = (CExtIdleNotification*)data;
+
+ NOTIF->onTimerFired();
+
+ return 0;
+}
+
+CExtIdleNotification::CExtIdleNotification(SP resource_, uint32_t timeoutMs_) : resource(resource_), timeoutMs(timeoutMs_) {
+ if (!resource_->resource())
+ return;
+
+ resource->setDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); });
+ resource->setOnDestroy([this](CExtIdleNotificationV1* r) { PROTO::idle->destroyNotification(this); });
+
+ timer = std::make_shared(std::nullopt, onTimer, this);
+ g_pEventLoopManager->addTimer(timer);
+
+ updateTimer();
+
+ LOGM(LOG, "Registered idle-notification for {}ms", timeoutMs_);
+}
+
+CExtIdleNotification::~CExtIdleNotification() {
+ g_pEventLoopManager->removeTimer(timer);
+ timer.reset();
+}
+
+bool CExtIdleNotification::good() {
+ return resource->resource();
+}
+
+void CExtIdleNotification::updateTimer() {
+ if (PROTO::idle->isInhibited)
+ timer->updateTimeout(std::nullopt);
+ else
+ timer->updateTimeout(std::chrono::milliseconds(timeoutMs));
+}
+
+void CExtIdleNotification::onTimerFired() {
+ resource->sendIdled();
+ idled = true;
+}
+
+void CExtIdleNotification::onActivity() {
+ if (idled)
+ resource->sendResumed();
+
+ idled = false;
+ updateTimer();
+}
+
+CIdleNotifyProtocol::CIdleNotifyProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) {
+ ;
+}
+
+void CIdleNotifyProtocol::bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id) {
+ const auto RESOURCE = m_vManagers.emplace_back(std::make_unique(client, ver, id)).get();
+ RESOURCE->setOnDestroy([this](CExtIdleNotifierV1* p) { this->onManagerResourceDestroy(p->resource()); });
+
+ RESOURCE->setDestroy([this](CExtIdleNotifierV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); });
+ RESOURCE->setGetIdleNotification([this](CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) { this->onGetNotification(pMgr, id, timeout, seat); });
+}
+
+void CIdleNotifyProtocol::onManagerResourceDestroy(wl_resource* res) {
+ std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; });
+}
+
+void CIdleNotifyProtocol::destroyNotification(CExtIdleNotification* notif) {
+ std::erase_if(m_vNotifications, [&](const auto& other) { return other.get() == notif; });
+}
+
+void CIdleNotifyProtocol::onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat) {
+ const auto CLIENT = wl_resource_get_client(pMgr->resource());
+ const auto RESOURCE =
+ m_vNotifications
+ .emplace_back(std::make_unique(std::make_shared(CLIENT, wl_resource_get_version(pMgr->resource()), id), timeout))
+ .get();
+
+ if (!RESOURCE->good()) {
+ wl_resource_post_no_memory(pMgr->resource());
+ m_vNotifications.pop_back();
+ return;
+ }
+}
+
+void CIdleNotifyProtocol::onActivity() {
+ for (auto& n : m_vNotifications) {
+ n->onActivity();
+ }
+}
+
+void CIdleNotifyProtocol::setInhibit(bool inhibited) {
+ isInhibited = inhibited;
+ for (auto& n : m_vNotifications) {
+ n->onActivity();
+ }
+}
\ No newline at end of file
diff --git a/src/protocols/IdleNotify.hpp b/src/protocols/IdleNotify.hpp
new file mode 100644
index 00000000..c1c7b62d
--- /dev/null
+++ b/src/protocols/IdleNotify.hpp
@@ -0,0 +1,55 @@
+#pragma once
+
+#include
+#include
+#include
+#include "WaylandProtocol.hpp"
+#include "ext-idle-notify-v1.hpp"
+
+class CEventLoopTimer;
+
+class CExtIdleNotification {
+ public:
+ CExtIdleNotification(SP resource_, uint32_t timeoutMs);
+ ~CExtIdleNotification();
+
+ bool good();
+ void onTimerFired();
+ void onActivity();
+
+ private:
+ SP resource;
+ uint32_t timeoutMs = 0;
+ std::shared_ptr timer;
+
+ bool idled = false;
+
+ void updateTimer();
+};
+
+class CIdleNotifyProtocol : public IWaylandProtocol {
+ public:
+ CIdleNotifyProtocol(const wl_interface* iface, const int& ver, const std::string& name);
+
+ virtual void bindManager(wl_client* client, void* data, uint32_t ver, uint32_t id);
+
+ void onActivity();
+ void setInhibit(bool inhibited);
+
+ private:
+ void onManagerResourceDestroy(wl_resource* res);
+ void destroyNotification(CExtIdleNotification* notif);
+ void onGetNotification(CExtIdleNotifierV1* pMgr, uint32_t id, uint32_t timeout, wl_resource* seat);
+
+ bool isInhibited = false;
+
+ //
+ std::vector> m_vManagers;
+ std::vector> m_vNotifications;
+
+ friend class CExtIdleNotification;
+};
+
+namespace PROTO {
+ inline UP idle;
+};