Hyprland/src/managers/SessionLockManager.cpp

219 lines
7.8 KiB
C++
Raw Normal View History

2023-02-03 11:58:55 +00:00
#include "SessionLockManager.hpp"
#include "../Compositor.hpp"
#include "../config/ConfigValue.hpp"
2024-04-20 14:14:54 +01:00
#include "../protocols/FractionalScale.hpp"
2024-04-30 16:32:05 +01:00
#include "../protocols/SessionLock.hpp"
#include "../render/Renderer.hpp"
#include "./managers/SeatManager.hpp"
#include "./managers/input/InputManager.hpp"
#include "./managers/eventLoop/EventLoopManager.hpp"
#include <algorithm>
#include <ranges>
2023-02-03 11:58:55 +00:00
2024-04-30 16:32:05 +01:00
SSessionLockSurface::SSessionLockSurface(SP<CSessionLockSurface> surface_) : surface(surface_) {
pWlrSurface = surface->surface();
2023-02-03 11:58:55 +00:00
listeners.map = surface_->m_events.map.listen([this] {
2024-04-30 16:32:05 +01:00
mapped = true;
2023-02-03 11:58:55 +00:00
g_pInputManager->simulateMouseMovement();
2023-02-03 11:58:55 +00:00
2024-04-30 16:32:05 +01:00
const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID);
2023-02-03 11:58:55 +00:00
2024-04-30 16:32:05 +01:00
if (PMONITOR)
g_pHyprRenderer->damageMonitor(PMONITOR);
});
2023-02-03 11:58:55 +00:00
listeners.destroy = surface_->m_events.destroy.listen([this] {
if (pWlrSurface == g_pCompositor->m_lastFocus)
g_pCompositor->m_lastFocus.reset();
2023-02-03 11:58:55 +00:00
2024-04-30 16:32:05 +01:00
g_pSessionLockManager->removeSessionLockSurface(this);
});
2023-02-03 11:58:55 +00:00
listeners.commit = surface_->m_events.commit.listen([this] {
2024-04-30 16:32:05 +01:00
const auto PMONITOR = g_pCompositor->getMonitorFromID(iMonitorID);
2023-02-03 11:58:55 +00:00
if (mapped && !g_pCompositor->m_lastFocus)
g_pInputManager->simulateMouseMovement();
2024-04-30 16:32:05 +01:00
if (PMONITOR)
g_pHyprRenderer->damageMonitor(PMONITOR);
});
2023-02-03 11:58:55 +00:00
}
2024-04-30 16:32:05 +01:00
CSessionLockManager::CSessionLockManager() {
m_listeners.newLock = PROTO::sessionLock->m_events.newLock.listen([this](const auto& lock) { this->onNewSessionLock(lock); });
2023-02-03 11:58:55 +00:00
}
2024-04-30 16:32:05 +01:00
void CSessionLockManager::onNewSessionLock(SP<CSessionLock> pLock) {
static auto PALLOWRELOCK = CConfigValue<Hyprlang::INT>("misc:allow_session_lock_restore");
2023-05-13 12:36:36 +01:00
2024-04-30 16:32:05 +01:00
if (PROTO::sessionLock->isLocked() && !*PALLOWRELOCK) {
LOGM(LOG, "Cannot re-lock, misc:allow_session_lock_restore is disabled");
pLock->sendDenied();
2023-02-03 11:58:55 +00:00
return;
}
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());
2023-02-03 11:58:55 +00:00
m_sessionLock = makeUnique<SSessionLock>();
m_sessionLock->lock = pLock;
m_sessionLock->lockTimer.reset();
2023-02-03 11:58:55 +00:00
m_sessionLock->listeners.newSurface = pLock->m_events.newLockSurface.listen([this](const SP<CSessionLockSurface>& surface) {
const auto PMONITOR = surface->monitor();
2023-02-03 11:58:55 +00:00
const auto NEWSURFACE = m_sessionLock->vSessionLockSurfaces.emplace_back(makeUnique<SSessionLockSurface>(surface)).get();
NEWSURFACE->iMonitorID = PMONITOR->m_id;
PROTO::fractional->sendScale(surface->surface(), PMONITOR->m_scale);
2024-04-30 16:32:05 +01:00
});
2023-02-03 11:58:55 +00:00
m_sessionLock->listeners.unlock = pLock->m_events.unlockAndDestroy.listen([this] {
m_sessionLock.reset();
2024-04-30 16:32:05 +01:00
g_pInputManager->refocus();
for (auto const& m : g_pCompositor->m_monitors)
g_pHyprRenderer->damageMonitor(m);
2024-04-30 16:32:05 +01:00
});
2023-02-03 11:58:55 +00:00
m_sessionLock->listeners.destroy = pLock->m_events.destroyed.listen([this] {
m_sessionLock.reset();
2024-04-30 16:32:05 +01:00
g_pCompositor->focusSurface(nullptr);
2023-02-03 11:58:55 +00:00
for (auto const& m : g_pCompositor->m_monitors)
g_pHyprRenderer->damageMonitor(m);
2024-04-30 16:32:05 +01:00
});
2023-02-03 11:58:55 +00:00
g_pCompositor->focusSurface(nullptr);
g_pSeatManager->setGrab(nullptr);
2025-07-20 12:33:22 +02:00
if (!g_pCompositor->m_unsafeState) {
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);
g_pEventLoopManager->addTimer(m_sessionLock->sendDeniedTimer);
} else {
// Normally the locked event is sent after each output rendered a lock screen frame.
// When there are no outputs, send it right away.
m_sessionLock->lock->sendLocked();
m_sessionLock->hasSentLocked = true;
}
2023-02-03 11:58:55 +00:00
}
void CSessionLockManager::removeSendDeniedTimer() {
if (!m_sessionLock || !m_sessionLock->sendDeniedTimer)
return;
g_pEventLoopManager->removeTimer(m_sessionLock->sendDeniedTimer);
m_sessionLock->sendDeniedTimer.reset();
}
2023-02-03 11:58:55 +00:00
bool CSessionLockManager::isSessionLocked() {
2024-04-30 16:32:05 +01:00
return PROTO::sessionLock->isLocked();
2023-02-03 11:58:55 +00:00
}
WP<SSessionLockSurface> CSessionLockManager::getSessionLockSurfaceForMonitor(uint64_t id) {
if (!m_sessionLock)
return {};
2024-04-30 16:32:05 +01:00
for (auto const& sls : m_sessionLock->vSessionLockSurfaces) {
2023-02-03 11:58:55 +00:00
if (sls->iMonitorID == id) {
if (sls->mapped)
return sls;
2023-02-03 11:58:55 +00:00
else
return {};
2023-02-03 11:58:55 +00:00
}
}
return {};
2023-02-03 11:58:55 +00:00
}
void CSessionLockManager::onLockscreenRenderedOnMonitor(uint64_t id) {
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;
}
}
bool CSessionLockManager::isSurfaceSessionLock(SP<CWLSurfaceResource> pSurface) {
2024-04-30 16:32:05 +01:00
// 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_sessionLock)
2024-04-30 16:32:05 +01:00
return false;
for (auto const& sls : m_sessionLock->vSessionLockSurfaces) {
if (sls->surface->surface() == pSurface)
2023-02-03 11:58:55 +00:00
return true;
}
return false;
}
bool CSessionLockManager::anySessionLockSurfacesPresent() {
return m_sessionLock && std::ranges::any_of(m_sessionLock->vSessionLockSurfaces, [](const auto& surf) { return surf->mapped; });
}
2023-02-03 11:58:55 +00:00
void CSessionLockManager::removeSessionLockSurface(SSessionLockSurface* pSLS) {
if (!m_sessionLock)
2024-04-30 16:32:05 +01:00
return;
std::erase_if(m_sessionLock->vSessionLockSurfaces, [&](const auto& other) { return pSLS == other.get(); });
if (g_pCompositor->m_lastFocus)
return;
for (auto const& sls : m_sessionLock->vSessionLockSurfaces) {
if (!sls->mapped)
continue;
g_pCompositor->focusSurface(sls->surface->surface());
break;
}
2023-02-03 11:58:55 +00:00
}
bool CSessionLockManager::clientLocked() {
return m_sessionLock && m_sessionLock->hasSentLocked;
2024-04-30 16:32:05 +01:00
}
bool CSessionLockManager::clientDenied() {
return m_sessionLock && m_sessionLock->hasSentDenied;
}
bool CSessionLockManager::shallConsiderLockMissing() {
if (!m_sessionLock)
return true;
static auto LOCKDEAD_SCREEN_DELAY = CConfigValue<Hyprlang::INT>("misc:lockdead_screen_delay");
return m_sessionLock->lockTimer.getMillis() > *LOCKDEAD_SCREEN_DELAY;
}