diff --git a/CMakeLists.txt b/CMakeLists.txt index 6d0d1437..8fbb517e 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -276,6 +276,7 @@ protocolNew("unstable/text-input/text-input-unstable-v3.xml" "text-input-unstabl 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) +protocolNew("staging/ext-session-lock/ext-session-lock-v1.xml" "ext-session-lock-v1" false) # tools add_subdirectory(hyprctl) diff --git a/protocols/meson.build b/protocols/meson.build index 3b4c4dd1..a0728e39 100644 --- a/protocols/meson.build +++ b/protocols/meson.build @@ -53,6 +53,7 @@ new_protocols = [ [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_protocol_dir, 'staging/ext-session-lock/ext-session-lock-v1.xml'], ] wl_protos_src = [] diff --git a/src/Compositor.cpp b/src/Compositor.cpp index e31fb9db..6000a67c 100644 --- a/src/Compositor.cpp +++ b/src/Compositor.cpp @@ -266,8 +266,6 @@ void CCompositor::initServer() { m_sWLRHeadlessBackend = wlr_headless_backend_create(m_sWLEventLoop); - m_sWLRSessionLockMgr = wlr_session_lock_manager_v1_create(m_sWLDisplay); - if (!m_sWLRHeadlessBackend) { Debug::log(CRIT, "Couldn't create the headless backend"); throwError("wlr_headless_backend_create() failed!"); @@ -315,7 +313,6 @@ void CCompositor::initAllSignals() { addWLSignal(&m_sWLRVKeyboardMgr->events.new_virtual_keyboard, &Events::listen_newVirtualKeyboard, m_sWLRVKeyboardMgr, "VKeyboardMgr"); addWLSignal(&m_sWLRRenderer->events.destroy, &Events::listen_RendererDestroy, m_sWLRRenderer, "WLRRenderer"); addWLSignal(&m_sWLRIMEMgr->events.input_method, &Events::listen_newIME, m_sWLRIMEMgr, "IMEMgr"); - addWLSignal(&m_sWLRSessionLockMgr->events.new_lock, &Events::listen_newSessionLock, m_sWLRSessionLockMgr, "SessionLockMgr"); if (m_sWRLDRMLeaseMgr) addWLSignal(&m_sWRLDRMLeaseMgr->events.request, &Events::listen_leaseRequest, &m_sWRLDRMLeaseMgr, "DRM"); @@ -359,7 +356,6 @@ void CCompositor::removeAllSignals() { removeWLSignal(&Events::listen_newVirtualKeyboard); removeWLSignal(&Events::listen_RendererDestroy); removeWLSignal(&Events::listen_newIME); - removeWLSignal(&Events::listen_newSessionLock); if (m_sWRLDRMLeaseMgr) removeWLSignal(&Events::listen_leaseRequest); diff --git a/src/Compositor.hpp b/src/Compositor.hpp index 5e9d0e9f..3201b28f 100644 --- a/src/Compositor.hpp +++ b/src/Compositor.hpp @@ -67,7 +67,6 @@ class CCompositor { wlr_input_method_manager_v2* m_sWLRIMEMgr; wlr_linux_dmabuf_v1* m_sWLRLinuxDMABuf; wlr_backend* m_sWLRHeadlessBackend; - wlr_session_lock_manager_v1* m_sWLRSessionLockMgr; // ------------------------------------------------- // std::string m_szHyprTempDataRoot = ""; diff --git a/src/events/Misc.cpp b/src/events/Misc.cpp index c6e42881..e5ead5ff 100644 --- a/src/events/Misc.cpp +++ b/src/events/Misc.cpp @@ -193,9 +193,3 @@ void Events::listener_newIME(wl_listener* listener, void* data) { g_pInputManager->m_sIMERelay.onNewIME((wlr_input_method_v2*)data); } - -void Events::listener_newSessionLock(wl_listener* listener, void* data) { - Debug::log(LOG, "New session lock!"); - - g_pSessionLockManager->onNewSessionLock((wlr_session_lock_v1*)data); -} diff --git a/src/includes.hpp b/src/includes.hpp index d6f98a88..ed40331f 100644 --- a/src/includes.hpp +++ b/src/includes.hpp @@ -90,7 +90,6 @@ extern "C" { #include #include #include -#include #include #include #include diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp index b721f17a..580622b0 100644 --- a/src/managers/ProtocolManager.cpp +++ b/src/managers/ProtocolManager.cpp @@ -18,6 +18,7 @@ #include "../protocols/OutputPower.hpp" #include "../protocols/XDGActivation.hpp" #include "../protocols/IdleNotify.hpp" +#include "../protocols/SessionLock.hpp" #include "tearing-control-v1.hpp" #include "fractional-scale-v1.hpp" @@ -37,6 +38,7 @@ #include "wlr-output-power-management-unstable-v1.hpp" #include "xdg-activation-v1.hpp" #include "ext-idle-notify-v1.hpp" +#include "ext-session-lock-v1.hpp" CProtocolManager::CProtocolManager() { @@ -58,6 +60,7 @@ CProtocolManager::CProtocolManager() { 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"); + PROTO::sessionLock = std::make_unique(&ext_session_lock_manager_v1_interface, 1, "SessionLock"); // Old protocol implementations. // TODO: rewrite them to use hyprwayland-scanner. diff --git a/src/managers/SessionLockManager.cpp b/src/managers/SessionLockManager.cpp index d6fc912c..d1c609d3 100644 --- a/src/managers/SessionLockManager.cpp +++ b/src/managers/SessionLockManager.cpp @@ -2,141 +2,92 @@ #include "../Compositor.hpp" #include "../config/ConfigValue.hpp" #include "../protocols/FractionalScale.hpp" +#include "../protocols/SessionLock.hpp" -static void handleSurfaceMap(void* owner, void* data) { - const auto PSURFACE = (SSessionLockSurface*)owner; +SSessionLockSurface::SSessionLockSurface(SP surface_) : surface(surface_) { + pWlrSurface = surface.lock()->surface(); - Debug::log(LOG, "SessionLockSurface {:x} mapped", (uintptr_t)PSURFACE); + listeners.map = surface_->events.map.registerListener([this](std::any data) { + mapped = true; - PSURFACE->mapped = true; + g_pCompositor->focusSurface(surface.lock()->surface()); - g_pCompositor->focusSurface(PSURFACE->pWlrLockSurface->surface); + const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); - const auto PMONITOR = g_pCompositor->getMonitorFromID(PSURFACE->iMonitorID); + if (PMONITOR) + g_pHyprRenderer->damageMonitor(PMONITOR); + }); - if (PMONITOR) - g_pHyprRenderer->damageMonitor(PMONITOR); + listeners.destroy = surface_->events.destroy.registerListener([this](std::any data) { + if (pWlrSurface == g_pCompositor->m_pLastFocus) + g_pCompositor->m_pLastFocus = nullptr; + + g_pSessionLockManager->removeSessionLockSurface(this); + }); + + listeners.commit = surface_->events.commit.registerListener([this](std::any data) { + const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID); + + if (PMONITOR) + g_pHyprRenderer->damageMonitor(PMONITOR); + }); } -static void handleSurfaceCommit(void* owner, void* data) { - const auto PSURFACE = (SSessionLockSurface*)owner; - - const auto PMONITOR = g_pCompositor->getMonitorFromID(PSURFACE->iMonitorID); - - if (PMONITOR) - g_pHyprRenderer->damageMonitor(PMONITOR); +CSessionLockManager::CSessionLockManager() { + listeners.newLock = PROTO::sessionLock->events.newLock.registerListener([this](std::any data) { this->onNewSessionLock(std::any_cast>(data)); }); } -static void handleSurfaceDestroy(void* owner, void* data) { - const auto PSURFACE = (SSessionLockSurface*)owner; - - Debug::log(LOG, "SessionLockSurface {:x} destroyed", (uintptr_t)PSURFACE); - - PSURFACE->hyprListener_commit.removeCallback(); - PSURFACE->hyprListener_destroy.removeCallback(); - PSURFACE->hyprListener_map.removeCallback(); - - if (PSURFACE->pWlrLockSurface->surface == g_pCompositor->m_pLastFocus) - g_pCompositor->m_pLastFocus = nullptr; - - g_pSessionLockManager->removeSessionLockSurface(PSURFACE); -} - -void CSessionLockManager::onNewSessionLock(wlr_session_lock_v1* pWlrLock) { +void CSessionLockManager::onNewSessionLock(SP pLock) { static auto PALLOWRELOCK = CConfigValue("misc:allow_session_lock_restore"); - if (m_sSessionLock.active && (!*PALLOWRELOCK || m_sSessionLock.pWlrLock)) { - Debug::log(LOG, "Attempted to lock a locked session!"); - wlr_session_lock_v1_destroy(pWlrLock); + if (PROTO::sessionLock->isLocked() && !*PALLOWRELOCK) { + Debug::log(LOG, "Cannot re-lock, misc:allow_session_lock_restore is disabled"); return; } - Debug::log(LOG, "Session got locked by {:x}", (uintptr_t)pWlrLock); + Debug::log(LOG, "Session got locked by {:x}", (uintptr_t)pLock.get()); - m_sSessionLock.pWlrLock = pWlrLock; + m_pSessionLock = std::make_unique(); + m_pSessionLock->lock = pLock; - g_pCompositor->m_sSeat.exclusiveClient = wl_resource_get_client(pWlrLock->resource); + m_pSessionLock->listeners.newSurface = pLock->events.newLockSurface.registerListener([this](std::any data) { + auto SURFACE = std::any_cast>(data); - m_sSessionLock.hyprListener_newSurface.initCallback( - &pWlrLock->events.new_surface, - [&](void* owner, void* data) { - const auto PSURFACE = &*m_sSessionLock.vSessionLockSurfaces.emplace_back(std::make_unique()); + const auto PMONITOR = SURFACE->monitor(); - const auto PWLRSURFACE = (wlr_session_lock_surface_v1*)data; + const auto NEWSURFACE = m_pSessionLock->vSessionLockSurfaces.emplace_back(std::make_unique(SURFACE)).get(); + NEWSURFACE->iMonitorID = PMONITOR->ID; + PROTO::fractional->sendScale(SURFACE->surface(), PMONITOR->scale); + }); - const auto PMONITOR = g_pCompositor->getMonitorFromOutput(PWLRSURFACE->output); + m_pSessionLock->listeners.unlock = pLock->events.unlockAndDestroy.registerListener([this](std::any data) { + m_pSessionLock.reset(); + g_pInputManager->refocus(); - if (!PMONITOR) { - m_sSessionLock.vSessionLockSurfaces.pop_back(); - return; - } + for (auto& m : g_pCompositor->m_vMonitors) + g_pHyprRenderer->damageMonitor(m.get()); + }); - PSURFACE->pWlrLockSurface = PWLRSURFACE; - PSURFACE->iMonitorID = PMONITOR->ID; + m_pSessionLock->listeners.destroy = pLock->events.destroyed.registerListener([this](std::any data) { + g_pCompositor->focusSurface(nullptr); - PROTO::fractional->sendScale(PSURFACE->pWlrLockSurface->surface, PMONITOR->scale); + for (auto& m : g_pCompositor->m_vMonitors) + g_pHyprRenderer->damageMonitor(m.get()); + }); - wlr_session_lock_surface_v1_configure(PWLRSURFACE, PMONITOR->vecSize.x, PMONITOR->vecSize.y); - - PSURFACE->hyprListener_map.initCallback(&PWLRSURFACE->surface->events.map, &handleSurfaceMap, PSURFACE, "SSessionLockSurface"); - PSURFACE->hyprListener_destroy.initCallback(&PWLRSURFACE->events.destroy, &handleSurfaceDestroy, PSURFACE, "SSessionLockSurface"); - PSURFACE->hyprListener_commit.initCallback(&PWLRSURFACE->surface->events.commit, &handleSurfaceCommit, PSURFACE, "SSessionLockSurface"); - }, - pWlrLock, "wlr_session_lock_v1"); - - m_sSessionLock.hyprListener_unlock.initCallback( - &pWlrLock->events.unlock, - [&](void* owner, void* data) { - Debug::log(LOG, "Session Unlocked"); - - m_sSessionLock.hyprListener_destroy.removeCallback(); - m_sSessionLock.hyprListener_newSurface.removeCallback(); - m_sSessionLock.hyprListener_unlock.removeCallback(); - - m_sSessionLock.active = false; - - m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.clear(); - - g_pCompositor->m_sSeat.exclusiveClient = nullptr; - g_pInputManager->refocus(); - - for (auto& m : g_pCompositor->m_vMonitors) - g_pHyprRenderer->damageMonitor(m.get()); - }, - pWlrLock, "wlr_session_lock_v1"); - - m_sSessionLock.hyprListener_destroy.initCallback( - &pWlrLock->events.destroy, - [&](void* owner, void* data) { - Debug::log(LOG, "Session Lock Abandoned"); - - m_sSessionLock.hyprListener_destroy.removeCallback(); - m_sSessionLock.hyprListener_newSurface.removeCallback(); - m_sSessionLock.hyprListener_unlock.removeCallback(); - - g_pCompositor->m_sSeat.exclusiveClient = nullptr; - - g_pCompositor->focusSurface(nullptr); - - m_sSessionLock.pWlrLock = nullptr; - - for (auto& m : g_pCompositor->m_vMonitors) - g_pHyprRenderer->damageMonitor(m.get()); - }, - pWlrLock, "wlr_session_lock_v1"); - - wlr_session_lock_v1_send_locked(pWlrLock); - - g_pSessionLockManager->activateLock(); + pLock->sendLocked(); } bool CSessionLockManager::isSessionLocked() { - return m_sSessionLock.active; + return PROTO::sessionLock->isLocked(); } SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64_t id) { - for (auto& sls : m_sSessionLock.vSessionLockSurfaces) { + if (!m_pSessionLock) + return nullptr; + + for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { if (sls->iMonitorID == id) { if (sls->mapped) return sls.get(); @@ -151,11 +102,14 @@ SSessionLockSurface* CSessionLockManager::getSessionLockSurfaceForMonitor(uint64 // We don't want the red screen to flash. // This violates the protocol a bit, but tries to handle the missing sync between a lock surface beeing created and the red screen beeing drawn. float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { - const auto& NOMAPPEDSURFACETIMER = m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.find(id); + if (!m_pSessionLock) + return 0.F; - if (NOMAPPEDSURFACETIMER == m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.end()) { - m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers.emplace(id, CTimer()); - m_sSessionLock.mMonitorsWithoutMappedSurfaceTimers[id].reset(); + const auto& NOMAPPEDSURFACETIMER = m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers.find(id); + + if (NOMAPPEDSURFACETIMER == m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers.end()) { + m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers.emplace(id, CTimer()); + m_pSessionLock->mMonitorsWithoutMappedSurfaceTimers[id].reset(); return 0.f; } @@ -163,8 +117,14 @@ float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) { } bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) { - for (auto& sls : m_sSessionLock.vSessionLockSurfaces) { - if (sls->pWlrLockSurface->surface == pSurface) + // TODO: this has some edge cases when it's wrong (e.g. destroyed lock but not yet surfaces) + // but can be easily fixed when I rewrite wlr_surface + + if (!m_pSessionLock) + return false; + + for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { + if (sls->surface.lock()->surface() == pSurface) return true; } @@ -172,20 +132,23 @@ bool CSessionLockManager::isSurfaceSessionLock(wlr_surface* pSurface) { } void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) { - std::erase_if(m_sSessionLock.vSessionLockSurfaces, [&](const auto& other) { return pSLS == other.get(); }); + if (!m_pSessionLock) + return; + + std::erase_if(m_pSessionLock->vSessionLockSurfaces, [&](const auto& other) { return pSLS == other.get(); }); if (g_pCompositor->m_pLastFocus) return; - for (auto& sls : m_sSessionLock.vSessionLockSurfaces) { + for (auto& sls : m_pSessionLock->vSessionLockSurfaces) { if (!sls->mapped) continue; - g_pCompositor->focusSurface(sls->pWlrLockSurface->surface); + g_pCompositor->focusSurface(sls->surface.lock()->surface()); break; } } -void CSessionLockManager::activateLock() { - m_sSessionLock.active = true; -} \ No newline at end of file +bool CSessionLockManager::isSessionLockPresent() { + return m_pSessionLock && !m_pSessionLock->vSessionLockSurfaces.empty(); +} diff --git a/src/managers/SessionLockManager.hpp b/src/managers/SessionLockManager.hpp index c2c539db..d655a2bc 100644 --- a/src/managers/SessionLockManager.hpp +++ b/src/managers/SessionLockManager.hpp @@ -2,51 +2,65 @@ #include "../defines.hpp" #include "../helpers/Timer.hpp" +#include "../helpers/signal/Listener.hpp" #include #include +class CSessionLockSurface; +class CSessionLock; + struct SSessionLockSurface { - wlr_session_lock_surface_v1* pWlrLockSurface = nullptr; - uint64_t iMonitorID = -1; + SSessionLockSurface(SP surface_); - bool mapped = false; + WP surface; + wlr_surface* pWlrSurface = nullptr; + uint64_t iMonitorID = -1; - DYNLISTENER(map); - DYNLISTENER(destroy); - DYNLISTENER(commit); + bool mapped = false; + + struct { + CHyprSignalListener map; + CHyprSignalListener destroy; + CHyprSignalListener commit; + } listeners; }; struct SSessionLock { - bool active = false; - wlr_session_lock_v1* pWlrLock = nullptr; + WP lock; std::vector> vSessionLockSurfaces; std::unordered_map mMonitorsWithoutMappedSurfaceTimers; - DYNLISTENER(newSurface); - DYNLISTENER(unlock); - DYNLISTENER(destroy); + struct { + CHyprSignalListener newSurface; + CHyprSignalListener unlock; + CHyprSignalListener destroy; + } listeners; }; class CSessionLockManager { public: - CSessionLockManager() = default; + CSessionLockManager(); ~CSessionLockManager() = default; - void onNewSessionLock(wlr_session_lock_v1*); SSessionLockSurface* getSessionLockSurfaceForMonitor(uint64_t); float getRedScreenAlphaForMonitor(uint64_t); bool isSessionLocked(); + bool isSessionLockPresent(); bool isSurfaceSessionLock(wlr_surface*); void removeSessionLockSurface(SSessionLockSurface*); - void activateLock(); - private: - SSessionLock m_sSessionLock; + UP m_pSessionLock; + + struct { + CHyprSignalListener newLock; + } listeners; + + void onNewSessionLock(SP pWlrLock); }; inline std::unique_ptr g_pSessionLockManager; \ No newline at end of file diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp index 72c1772c..ca1597b1 100644 --- a/src/managers/input/InputManager.cpp +++ b/src/managers/input/InputManager.cpp @@ -9,6 +9,7 @@ #include "../../protocols/RelativePointer.hpp" #include "../../protocols/PointerConstraints.hpp" #include "../../protocols/IdleNotify.hpp" +#include "../../protocols/SessionLock.hpp" CInputManager::CInputManager() { m_sListeners.setCursorShape = PROTO::cursorShape->events.setShape.registerListener([this](std::any data) { @@ -236,7 +237,7 @@ void CInputManager::mouseMoveUnified(uint32_t time, bool refocus) { if (!PSLS) return; - foundSurface = PSLS->pWlrLockSurface->surface; + foundSurface = PSLS->surface.lock()->surface(); surfacePos = PMONITOR->vecPosition; } diff --git a/src/protocols/SessionLock.cpp b/src/protocols/SessionLock.cpp new file mode 100644 index 00000000..4c4b1846 --- /dev/null +++ b/src/protocols/SessionLock.cpp @@ -0,0 +1,202 @@ +#include "SessionLock.hpp" +#include "../Compositor.hpp" + +#define LOGM PROTO::sessionLock->protoLog + +CSessionLockSurface::CSessionLockSurface(SP resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP owner_) : + resource(resource_), sessionLock(owner_), pSurface(surface_), pMonitor(pMonitor_) { + if (!resource->resource()) + return; + + resource->setDestroy([this](CExtSessionLockSurfaceV1* r) { + events.destroy.emit(); + PROTO::sessionLock->destroyResource(this); + }); + resource->setOnDestroy([this](CExtSessionLockSurfaceV1* r) { + events.destroy.emit(); + PROTO::sessionLock->destroyResource(this); + }); + + resource->setAckConfigure([this](CExtSessionLockSurfaceV1* r, uint32_t serial) { ackdConfigure = true; }); + + hyprListener_surfaceCommit.initCallback( + &pSurface->events.commit, + [this](void* owner, void* data) { + if (!pSurface->current.buffer) { + LOGM(ERR, "SessionLock attached a null buffer"); + wl_resource_post_error(resource->resource(), EXT_SESSION_LOCK_SURFACE_V1_ERROR_NULL_BUFFER, "Null buffer attached"); + return; + } + + if (!ackdConfigure) { + LOGM(ERR, "SessionLock committed without an ack"); + wl_resource_post_error(resource->resource(), EXT_SESSION_LOCK_SURFACE_V1_ERROR_COMMIT_BEFORE_FIRST_ACK, "Committed surface before first ack"); + return; + } + + if (committed) + events.commit.emit(); + else + events.map.emit(); + committed = true; + }, + this, "SessionLockSurface"); + + hyprListener_surfaceDestroy.initCallback( + &pSurface->events.destroy, + [this](void* owner, void* data) { + LOGM(WARN, "SessionLockSurface object remains but surface is being destroyed???"); + hyprListener_surfaceCommit.removeCallback(); + hyprListener_surfaceDestroy.removeCallback(); + pSurface = nullptr; + }, + this, "SessionLockSurface"); + + sendConfigure(); + + listeners.monitorMode = pMonitor->events.modeChanged.registerListener([this](std::any data) { sendConfigure(); }); +} + +CSessionLockSurface::~CSessionLockSurface() { + hyprListener_surfaceCommit.removeCallback(); + hyprListener_surfaceDestroy.removeCallback(); + events.destroy.emit(); // just in case. +} + +void CSessionLockSurface::sendConfigure() { + const auto CLIENT = wl_resource_get_client(resource->resource()); + const auto SERIAL = wlr_seat_client_next_serial(wlr_seat_client_for_wl_client(g_pCompositor->m_sSeat.seat, CLIENT)); + resource->sendConfigure(SERIAL, pMonitor->vecSize.x, pMonitor->vecSize.y); +} + +bool CSessionLockSurface::good() { + return resource->resource(); +} + +bool CSessionLockSurface::inert() { + return sessionLock.expired(); +} + +CMonitor* CSessionLockSurface::monitor() { + return pMonitor; +} + +wlr_surface* CSessionLockSurface::surface() { + return pSurface; +} + +CSessionLock::CSessionLock(SP resource_) : resource(resource_) { + if (!resource->resource()) + return; + + resource->setDestroy([this](CExtSessionLockV1* r) { PROTO::sessionLock->destroyResource(this); }); + resource->setOnDestroy([this](CExtSessionLockV1* r) { PROTO::sessionLock->destroyResource(this); }); + + resource->setGetLockSurface([this](CExtSessionLockV1* r, uint32_t id, wl_resource* surf, wl_resource* output) { + if (inert) { + LOGM(ERR, "Lock is trying to send getLockSurface after it's inert"); + return; + } + + PROTO::sessionLock->onGetLockSurface(r, id, surf, output); + }); + + resource->setUnlockAndDestroy([this](CExtSessionLockV1* r) { + events.unlockAndDestroy.emit(); + inert = true; + PROTO::sessionLock->locked = false; + PROTO::sessionLock->destroyResource(this); + }); +} + +CSessionLock::~CSessionLock() { + events.destroyed.emit(); +} + +void CSessionLock::sendLocked() { + resource->sendLocked(); +} + +bool CSessionLock::good() { + return resource->resource(); +} + +CSessionLockProtocol::CSessionLockProtocol(const wl_interface* iface, const int& ver, const std::string& name) : IWaylandProtocol(iface, ver, name) { + ; +} + +void CSessionLockProtocol::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](CExtSessionLockManagerV1* p) { this->onManagerResourceDestroy(p->resource()); }); + + RESOURCE->setDestroy([this](CExtSessionLockManagerV1* pMgr) { this->onManagerResourceDestroy(pMgr->resource()); }); + RESOURCE->setLock([this](CExtSessionLockManagerV1* pMgr, uint32_t id) { this->onLock(pMgr, id); }); +} + +void CSessionLockProtocol::onManagerResourceDestroy(wl_resource* res) { + std::erase_if(m_vManagers, [&](const auto& other) { return other->resource() == res; }); +} + +void CSessionLockProtocol::destroyResource(CSessionLock* lock) { + std::erase_if(m_vLocks, [&](const auto& other) { return other.get() == lock; }); +} + +void CSessionLockProtocol::destroyResource(CSessionLockSurface* surf) { + std::erase_if(m_vLockSurfaces, [&](const auto& other) { return other.get() == surf; }); +} + +void CSessionLockProtocol::onLock(CExtSessionLockManagerV1* pMgr, uint32_t id) { + + LOGM(LOG, "New sessionLock with id {}", id); + + const auto CLIENT = wl_resource_get_client(pMgr->resource()); + const auto RESOURCE = m_vLocks.emplace_back(std::make_unique(std::make_shared(CLIENT, wl_resource_get_version(pMgr->resource()), id))); + + if (!RESOURCE->good()) { + wl_resource_post_no_memory(pMgr->resource()); + m_vLocks.pop_back(); + return; + } + + if (m_vLocks.size() > 1) { + LOGM(ERR, "Tried to lock a locked session"); + RESOURCE->resource->sendFinished(); + RESOURCE->inert = true; + return; + } + + locked = true; + + events.newLock.emit(RESOURCE); +} + +void CSessionLockProtocol::onGetLockSurface(CExtSessionLockV1* lock, uint32_t id, wl_resource* surface, wl_resource* output) { + LOGM(LOG, "New sessionLockSurface with id {}", id); + + auto PSURFACE = wlr_surface_from_resource(surface); + auto PMONITOR = g_pCompositor->getMonitorFromOutput(wlr_output_from_resource(output)); + + SP sessionLock; + for (auto& l : m_vLocks) { + if (l->resource.get() == lock) { + sessionLock = l; + break; + } + } + + const auto CLIENT = wl_resource_get_client(lock->resource()); + const auto RESOURCE = m_vLockSurfaces.emplace_back( + std::make_unique(std::make_shared(CLIENT, wl_resource_get_version(lock->resource()), id), PSURFACE, PMONITOR, sessionLock)); + + if (!RESOURCE->good()) { + wl_resource_post_no_memory(lock->resource()); + m_vLockSurfaces.pop_back(); + return; + } + + sessionLock->events.newLockSurface.emit(RESOURCE); +} + +bool CSessionLockProtocol::isLocked() { + return locked; +} \ No newline at end of file diff --git a/src/protocols/SessionLock.hpp b/src/protocols/SessionLock.hpp new file mode 100644 index 00000000..b5d7aed5 --- /dev/null +++ b/src/protocols/SessionLock.hpp @@ -0,0 +1,102 @@ +#pragma once + +#include +#include +#include +#include "WaylandProtocol.hpp" +#include "ext-session-lock-v1.hpp" +#include "../helpers/signal/Signal.hpp" + +class CMonitor; +class CSessionLock; + +class CSessionLockSurface { + public: + CSessionLockSurface(SP resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP owner_); + ~CSessionLockSurface(); + + bool good(); + bool inert(); + CMonitor* monitor(); + wlr_surface* surface(); + + struct { + CSignal map; + CSignal destroy; + CSignal commit; + } events; + + private: + SP resource; + WP sessionLock; + wlr_surface* pSurface = nullptr; + CMonitor* pMonitor = nullptr; + + bool ackdConfigure = false; + bool committed = false; + + void sendConfigure(); + + DYNLISTENER(surfaceCommit); + DYNLISTENER(surfaceDestroy); + + struct { + CHyprSignalListener monitorMode; + } listeners; +}; + +class CSessionLock { + public: + CSessionLock(SP resource_); + ~CSessionLock(); + + bool good(); + void sendLocked(); + + struct { + CSignal newLockSurface; // SP + CSignal unlockAndDestroy; + CSignal destroyed; // fires regardless of whether there was a unlockAndDestroy or not. + } events; + + private: + SP resource; + + bool inert = false; + + friend class CSessionLockProtocol; +}; + +class CSessionLockProtocol : public IWaylandProtocol { + public: + CSessionLockProtocol(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); + + bool isLocked(); + + struct { + CSignal newLock; // SP + } events; + + private: + void onManagerResourceDestroy(wl_resource* res); + void destroyResource(CSessionLock* lock); + void destroyResource(CSessionLockSurface* surf); + void onLock(CExtSessionLockManagerV1* pMgr, uint32_t id); + void onGetLockSurface(CExtSessionLockV1* lock, uint32_t id, wl_resource* surface, wl_resource* output); + + bool locked = false; + + // + std::vector> m_vManagers; + std::vector> m_vLocks; + std::vector> m_vLockSurfaces; + + friend class CSessionLock; + friend class CSessionLockSurface; +}; + +namespace PROTO { + inline UP sessionLock; +}; diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp index 6b1545b1..d22edf5c 100644 --- a/src/render/Renderer.cpp +++ b/src/render/Renderer.cpp @@ -7,6 +7,7 @@ #include "../managers/CursorManager.hpp" #include "../desktop/Window.hpp" #include "../desktop/LayerSurface.hpp" +#include "../protocols/SessionLock.hpp" extern "C" { #include @@ -739,12 +740,12 @@ void CHyprRenderer::renderSessionLockSurface(SSessionLockSurface* pSurface, CMon SRenderData renderdata = {pMonitor, time, pMonitor->vecPosition.x, pMonitor->vecPosition.y}; renderdata.blur = false; - renderdata.surface = pSurface->pWlrLockSurface->surface; + renderdata.surface = pSurface->surface.lock()->surface(); renderdata.decorate = false; renderdata.w = pMonitor->vecSize.x; renderdata.h = pMonitor->vecSize.y; - wlr_surface_for_each_surface(pSurface->pWlrLockSurface->surface, renderSurface, &renderdata); + renderSurface(renderdata.surface, 0, 0, &renderdata); } void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPACE pWorkspace, timespec* time, const Vector2D& translate, const float& scale) { @@ -763,7 +764,7 @@ void CHyprRenderer::renderAllClientsForWorkspace(CMonitor* pMonitor, PHLWORKSPAC if (!pMonitor) return; - if (!g_pCompositor->m_sSeat.exclusiveClient && g_pSessionLockManager->isSessionLocked()) { + if (g_pSessionLockManager->isSessionLocked() && !g_pSessionLockManager->isSessionLockPresent()) { // locked with no exclusive, draw only red CBox boxe = {0, 0, INT16_MAX, INT16_MAX}; g_pHyprOpenGL->renderRect(&boxe, CColor(1.0, 0.2, 0.2, 1.0));