session-lock: don't render workspaces when locked (#10865)

Avoid rendering the workspace behind if we are locked
This commit is contained in:
Maximilian Seidler 2025-07-14 13:13:54 +02:00 committed by GitHub
parent d0f58baf29
commit 01971cb6c7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
7 changed files with 129 additions and 81 deletions

View file

@ -3,9 +3,10 @@
#include "../config/ConfigValue.hpp"
#include "../protocols/FractionalScale.hpp"
#include "../protocols/SessionLock.hpp"
#include "../managers/SeatManager.hpp"
#include "../render/Renderer.hpp"
#include "../managers/input/InputManager.hpp"
#include "./managers/SeatManager.hpp"
#include "./managers/input/InputManager.hpp"
#include "./managers/eventLoop/EventLoopManager.hpp"
#include <algorithm>
#include <ranges>
@ -49,16 +50,19 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
static auto PALLOWRELOCK = CConfigValue<Hyprlang::INT>("misc:allow_session_lock_restore");
if (PROTO::sessionLock->isLocked() && !*PALLOWRELOCK) {
Debug::log(LOG, "Cannot re-lock, misc:allow_session_lock_restore is disabled");
LOGM(LOG, "Cannot re-lock, misc:allow_session_lock_restore is disabled");
pLock->sendDenied();
return;
}
Debug::log(LOG, "Session got locked by {:x}", (uintptr_t)pLock.get());
if (m_sessionLock && !clientDenied() && !clientLocked())
return; // Not allowing to relock in case the old lock is still in a limbo
LOGM(LOG, "Session got locked by {:x}", (uintptr_t)pLock.get());
m_sessionLock = makeUnique<SSessionLock>();
m_sessionLock->lock = pLock;
m_sessionLock->mLockTimer.reset();
m_sessionLock->lockTimer.reset();
m_sessionLock->listeners.newSurface = pLock->m_events.newLockSurface.listen([this](const SP<CSessionLockSurface>& surface) {
const auto PMONITOR = surface->monitor();
@ -87,14 +91,48 @@ void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
g_pCompositor->focusSurface(nullptr);
g_pSeatManager->setGrab(nullptr);
m_sessionLock->sendDeniedTimer = makeShared<CEventLoopTimer>(
// Within this arbitrary amount of time, a session-lock client is expected to create and commit a lock surface for each output. If the client fails to do that, it will be denied.
std::chrono::seconds(5),
[](auto, auto) {
if (!g_pSessionLockManager || g_pSessionLockManager->clientLocked() || g_pSessionLockManager->clientDenied())
return;
if (g_pCompositor->m_unsafeState || !g_pCompositor->m_aqBackend->hasSession() || !g_pCompositor->m_aqBackend->session->active) {
// Because the session is inactive, there is a good reason for why the client did't recieve locked or denied.
// We send locked, although this could lead to imperfect frames when we start to render again.
g_pSessionLockManager->m_sessionLock->lock->sendLocked();
g_pSessionLockManager->m_sessionLock->hasSentLocked = true;
return;
}
if (g_pSessionLockManager->m_sessionLock && g_pSessionLockManager->m_sessionLock->lock) {
g_pSessionLockManager->m_sessionLock->lock->sendDenied();
g_pSessionLockManager->m_sessionLock->hasSentDenied = true;
}
},
nullptr);
if (m_sessionLock->sendDeniedTimer)
g_pEventLoopManager->addTimer(m_sessionLock->sendDeniedTimer);
// Normally the locked event is sent after each output rendered a lock screen frame.
// When there are no outputs, send it right away.
if (g_pCompositor->m_unsafeState) {
removeSendDeniedTimer();
m_sessionLock->lock->sendLocked();
m_sessionLock->hasSentLocked = true;
}
}
void CSessionLockManager::removeSendDeniedTimer() {
if (!m_sessionLock || !m_sessionLock->sendDeniedTimer)
return;
g_pEventLoopManager->removeTimer(m_sessionLock->sendDeniedTimer);
m_sessionLock->sendDeniedTimer.reset();
}
bool CSessionLockManager::isSessionLocked() {
return PROTO::sessionLock->isLocked();
}
@ -115,28 +153,13 @@ WP<SSessionLockSurface> CSessionLockManager::getSessionLockSurfaceForMonitor(uin
return {};
}
// We don't want the red screen to flash.
float CSessionLockManager::getRedScreenAlphaForMonitor(uint64_t id) {
if (!m_sessionLock)
return 1.F;
const auto& NOMAPPEDSURFACETIMER = m_sessionLock->mMonitorsWithoutMappedSurfaceTimers.find(id);
if (NOMAPPEDSURFACETIMER == m_sessionLock->mMonitorsWithoutMappedSurfaceTimers.end()) {
m_sessionLock->mMonitorsWithoutMappedSurfaceTimers.emplace(id, CTimer());
m_sessionLock->mMonitorsWithoutMappedSurfaceTimers[id].reset();
return 0.f;
}
return std::clamp(NOMAPPEDSURFACETIMER->second.getSeconds() - /* delay for screencopy */ 0.5f, 0.f, 1.f);
}
void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) {
if (!m_sessionLock || m_sessionLock->hasSentLocked)
if (!m_sessionLock || m_sessionLock->hasSentLocked || m_sessionLock->hasSentDenied)
return;
m_sessionLock->lockedMonitors.emplace(id);
const bool LOCKED = std::ranges::all_of(g_pCompositor->m_monitors, [this](auto m) { return m_sessionLock->lockedMonitors.contains(m->m_id); });
if (LOCKED && m_sessionLock->lock->good()) {
removeSendDeniedTimer();
m_sessionLock->lock->sendLocked();
m_sessionLock->hasSentLocked = true;
}
@ -157,6 +180,10 @@ bool CSessionLockManager::isSurfaceSessionLock(SP<CWLSurfaceResource> pSurface)
return false;
}
bool CSessionLockManager::anySessionLockSurfacesPresent() {
return m_sessionLock && std::ranges::any_of(m_sessionLock->vSessionLockSurfaces, [](const auto& surf) { return surf->mapped; });
}
void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) {
if (!m_sessionLock)
return;
@ -175,19 +202,19 @@ void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) {
}
}
bool CSessionLockManager::isSessionLockPresent() {
return m_sessionLock && !m_sessionLock->vSessionLockSurfaces.empty();
bool CSessionLockManager::clientLocked() {
return m_sessionLock && m_sessionLock->hasSentLocked;
}
bool CSessionLockManager::anySessionLockSurfacesPresent() {
return m_sessionLock && std::ranges::any_of(m_sessionLock->vSessionLockSurfaces, [](const auto& surf) { return surf->mapped; });
bool CSessionLockManager::clientDenied() {
return m_sessionLock && m_sessionLock->hasSentDenied;
}
bool CSessionLockManager::shallConsiderLockMissing() {
if (!m_sessionLock)
return false;
return true;
static auto LOCKDEAD_SCREEN_DELAY = CConfigValue<Hyprlang::INT>("misc:lockdead_screen_delay");
return m_sessionLock->mLockTimer.getMillis() > *LOCKDEAD_SCREEN_DELAY;
return m_sessionLock->lockTimer.getMillis() > *LOCKDEAD_SCREEN_DELAY;
}