22
33#include < algorithm>
44#include < hyprutils/memory/Casts.hpp>
5+ #include < optional>
56#include < xkbcommon/xkbcommon-keysyms.h>
67
78#include " ../InternalBackend.hpp"
89#include " ../Input.hpp"
910#include " ../../element/Element.hpp"
1011#include " ../../window/WaylandWindow.hpp"
1112#include " ../../window/WaylandLayer.hpp"
13+ #include " ../../window/WaylandLockSurface.hpp"
1214#include " ../../output/WaylandOutput.hpp"
1315#include " ../../Macros.hpp"
1416
@@ -100,15 +102,23 @@ bool CWaylandPlatform::attempt() {
100102 // We just need to deferre it a bit so that the globals are defined before we emit the event.
101103 // But once they are defined, we probably don't want it to be a idle function.
102104 m_idleCallbacks.emplace_back ([id]() { g_backend->m_events .outputAdded .emit (id); });
105+ } else if (NAME == ext_session_lock_manager_v1_interface.name ) {
106+ TRACE (g_logger->log (HT_LOG_TRACE, " > binding to global: {} (version {}) with id {}" , name, 1 , id));
107+ m_waylandState.sessionLock = makeShared<CCExtSessionLockManagerV1>(
108+ (wl_proxy*)wl_registry_bind ((wl_registry*)m_waylandState.registry ->resource (), id, &ext_session_lock_manager_v1_interface, 1 ));
103109 }
104110 });
105111 m_waylandState.registry ->setGlobalRemove ([this ](CCWlRegistry* r, uint32_t id) {
112+ TRACE (g_logger->log (HT_LOG_TRACE, " Global {} removed" , id));
113+
114+ auto lockSurfaceIt = std::ranges::find_if (m_lockSurfaces, [id](const auto & other) { return other->m_outputId == id; });
115+ if (lockSurfaceIt != m_lockSurfaces.end ()) {
116+ (*lockSurfaceIt)->m_events .closeRequest .emit ();
117+ m_lockSurfaces.erase (lockSurfaceIt);
118+ }
106119 auto outputIt = std::ranges::find_if (m_outputs, [id](const auto & other) { return other->m_id == id; });
107120 if (outputIt != m_outputs.end ())
108121 m_outputs.erase (outputIt);
109-
110- g_logger->log (HT_LOG_DEBUG, " Global {} removed" , id);
111- g_backend->m_events .outputRemoved .emit (id);
112122 });
113123
114124 wl_display_roundtrip (m_waylandState.display );
@@ -127,9 +137,7 @@ bool CWaylandPlatform::attempt() {
127137}
128138
129139CWaylandPlatform::~CWaylandPlatform () {
130- const auto DPY = m_waylandState.display ;
131- m_waylandState = {};
132- wl_display_disconnect (DPY);
140+ m_outputs.clear ();
133141
134142 if (m_drmState.fd >= 0 )
135143 close (m_drmState.fd );
@@ -140,6 +148,10 @@ CWaylandPlatform::~CWaylandPlatform() {
140148 xkb_keymap_unref (m_waylandState.seatState .xkbKeymap );
141149 if (m_waylandState.seatState .xkbContext )
142150 xkb_context_unref (m_waylandState.seatState .xkbContext );
151+
152+ const auto DPY = m_waylandState.display ;
153+ m_waylandState = {};
154+ wl_display_disconnect (DPY);
143155}
144156
145157bool CWaylandPlatform::dispatchEvents () {
@@ -618,3 +630,50 @@ void CWaylandPlatform::stopRepeatTimer() {
618630 m_waylandState.seatState .repeatTimer ->cancel ();
619631 m_waylandState.seatState .repeatTimer .reset ();
620632}
633+
634+ SP<CCExtSessionLockV1> CWaylandPlatform::aquireSessionLock () {
635+ if (m_waylandState.sessionLockState .sessionLocked && m_waylandState.sessionLockState .sessionUnlocked ) {
636+ g_logger->log (HT_LOG_ERROR, " We already unlocked. We shouldn't be calling aquireSessionLock?" );
637+ return nullptr ;
638+ }
639+
640+ if (!m_waylandState.sessionLockState .lock ) {
641+ m_waylandState.sessionLockState .lock = makeShared<CCExtSessionLockV1>(m_waylandState.sessionLock ->sendLock ());
642+ if (!m_waylandState.sessionLockState .lock ) {
643+ g_logger->log (HT_LOG_ERROR, " Failed to create a session lock object!" );
644+ return nullptr ;
645+ }
646+
647+ m_waylandState.sessionLockState .lock ->setLocked ([this ](CCExtSessionLockV1* r) { m_waylandState.sessionLockState .sessionLocked = true ; });
648+
649+ m_waylandState.sessionLockState .lock ->setFinished ([](CCExtSessionLockV1* r) { // FIXME: we need to make sure the client can exit after this event
650+ });
651+
652+ // roundtrip in case the compositor sends `finished` right away
653+ wl_display_roundtrip (m_waylandState.display );
654+
655+ // FIXME: we need to test if finished was sent right here too!
656+ }
657+
658+ return m_waylandState.sessionLockState .lock ;
659+ }
660+
661+ void CWaylandPlatform::unlockSessionLock () {
662+ if (!m_waylandState.sessionLockState .lock )
663+ return ;
664+
665+ m_waylandState.sessionLockState .lock ->sendUnlockAndDestroy ();
666+ m_waylandState.sessionLockState .lock = nullptr ;
667+ m_waylandState.sessionLockState .sessionUnlocked = true ;
668+
669+ // roundtrip in order to make sure we have unlocked before sending closeRequest
670+ wl_display_roundtrip (m_waylandState.display );
671+
672+ for (const auto & sls : m_lockSurfaces) {
673+ if (sls.expired ())
674+ continue ;
675+ sls->m_events .closeRequest .emit ();
676+ }
677+
678+ m_lockSurfaces.clear ();
679+ }
0 commit comments