diff options
-rwxr-xr-x | CMakeLists.txt | 2 | ||||
-rw-r--r-- | protocols/idle.xml | 49 | ||||
-rw-r--r-- | protocols/meson.build | 2 | ||||
-rw-r--r-- | src/Compositor.cpp | 9 | ||||
-rw-r--r-- | src/Compositor.hpp | 3 | ||||
-rw-r--r-- | src/includes.hpp | 1 | ||||
-rw-r--r-- | src/managers/ProtocolManager.cpp | 3 | ||||
-rw-r--r-- | src/managers/input/IdleInhibitor.cpp | 19 | ||||
-rw-r--r-- | src/managers/input/InputManager.cpp | 9 | ||||
-rw-r--r-- | src/managers/input/Tablets.cpp | 9 | ||||
-rw-r--r-- | src/managers/input/Touch.cpp | 3 | ||||
-rw-r--r-- | src/protocols/IdleNotify.cpp | 104 | ||||
-rw-r--r-- | src/protocols/IdleNotify.hpp | 55 |
13 files changed, 186 insertions, 82 deletions
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 @@ -<?xml version="1.0" encoding="UTF-8"?> -<protocol name="idle"> - <copyright><![CDATA[ - Copyright (C) 2015 Martin Gräßlin - - This program 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) any later version. - - This program 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 program. If not, see <http://www.gnu.org/licenses/>. - ]]></copyright> - <interface name="org_kde_kwin_idle" version="1"> - <description summary="User idle time manager"> - 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.. - </description> - <request name="get_idle_timeout"> - <arg name="id" type="new_id" interface="org_kde_kwin_idle_timeout"/> - <arg name="seat" type="object" interface="wl_seat"/> - <arg name="timeout" type="uint" summary="The idle timeout in msec"/> - </request> - </interface> - <interface name="org_kde_kwin_idle_timeout" version="1"> - <request name="release" type="destructor"> - <description summary="release the timeout object"/> - </request> - <request name="simulate_user_activity"> - <description summary="Simulates user activity for this timeout, behaves just like real user activity on the seat"/> - </request> - <event name="idle"> - <description summary="Triggered when there has not been any user activity in the requested idle time interval"/> - </event> - <event name="resumed"> - <description summary="Triggered on the first user activity after an idle event"/> - </event> - </interface> -</protocol> 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 <wlr/backend/wayland.h> #include <wlr/types/wlr_session_lock_v1.h> #include <wlr/types/wlr_single_pixel_buffer_v1.h> -#include <wlr/types/wlr_idle_notify_v1.h> #include <wlr/util/box.h> #include <wlr/util/transform.h> #include <wlr/render/swapchain.h> 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<CPointerConstraintsProtocol>(&zwp_pointer_constraints_v1_interface, 1, "PointerConstraints"); PROTO::outputPower = std::make_unique<COutputPowerProtocol>(&zwlr_output_power_manager_v1_interface, 1, "OutputPower"); PROTO::activation = std::make_unique<CXDGActivationProtocol>(&xdg_activation_v1_interface, 1, "XDGActivation"); + PROTO::idle = std::make_unique<CIdleNotifyProtocol>(&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<SIdleInhibitor>()).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<Hyprlang::INT>("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<CEventLoopTimer> self, void* data) { + + const auto NOTIF = (CExtIdleNotification*)data; + + NOTIF->onTimerFired(); + + return 0; +} + +CExtIdleNotification::CExtIdleNotification(SP<CExtIdleNotificationV1> 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<CEventLoopTimer>(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<CExtIdleNotifierV1>(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<CExtIdleNotification>(std::make_shared<CExtIdleNotificationV1>(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 <memory> +#include <vector> +#include <unordered_map> +#include "WaylandProtocol.hpp" +#include "ext-idle-notify-v1.hpp" + +class CEventLoopTimer; + +class CExtIdleNotification { + public: + CExtIdleNotification(SP<CExtIdleNotificationV1> resource_, uint32_t timeoutMs); + ~CExtIdleNotification(); + + bool good(); + void onTimerFired(); + void onActivity(); + + private: + SP<CExtIdleNotificationV1> resource; + uint32_t timeoutMs = 0; + std::shared_ptr<CEventLoopTimer> 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<UP<CExtIdleNotifierV1>> m_vManagers; + std::vector<SP<CExtIdleNotification>> m_vNotifications; + + friend class CExtIdleNotification; +}; + +namespace PROTO { + inline UP<CIdleNotifyProtocol> idle; +}; |