diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6d0d14379..8fbb517e6 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 3b4c4dd18..a0728e390 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 e31fb9db7..6000a67cb 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 5e9d0e9f5..3201b28fc 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 c6e42881d..e5ead5ff8 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 d6f98a887..ed40331f9 100644
--- a/src/includes.hpp
+++ b/src/includes.hpp
@@ -90,7 +90,6 @@ extern "C" {
 #include <wlr/backend/headless.h>
 #include <wlr/backend/multi.h>
 #include <wlr/backend/wayland.h>
-#include <wlr/types/wlr_session_lock_v1.h>
 #include <wlr/types/wlr_single_pixel_buffer_v1.h>
 #include <wlr/util/box.h>
 #include <wlr/util/transform.h>
diff --git a/src/managers/ProtocolManager.cpp b/src/managers/ProtocolManager.cpp
index b721f17a3..580622b07 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<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");
+    PROTO::sessionLock        = std::make_unique<CSessionLockProtocol>(&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 d6fc912cd..d1c609d38 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<CSessionLockSurface> 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<SP<CSessionLock>>(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<CSessionLock> pLock) {
 
     static auto PALLOWRELOCK = CConfigValue<Hyprlang::INT>("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<SSessionLock>();
+    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<SP<CSessionLockSurface>>(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<SSessionLockSurface>());
+        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<SSessionLockSurface>(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 c2c539dbc..d655a2bcc 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 <cstdint>
 #include <unordered_map>
 
+class CSessionLockSurface;
+class CSessionLock;
+
 struct SSessionLockSurface {
-    wlr_session_lock_surface_v1* pWlrLockSurface = nullptr;
-    uint64_t                     iMonitorID      = -1;
+    SSessionLockSurface(SP<CSessionLockSurface> surface_);
 
-    bool                         mapped = false;
+    WP<CSessionLockSurface> 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<CSessionLock>                                  lock;
 
     std::vector<std::unique_ptr<SSessionLockSurface>> vSessionLockSurfaces;
     std::unordered_map<uint64_t, CTimer>              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<SSessionLock> m_pSessionLock;
+
+    struct {
+        CHyprSignalListener newLock;
+    } listeners;
+
+    void onNewSessionLock(SP<CSessionLock> pWlrLock);
 };
 
 inline std::unique_ptr<CSessionLockManager> g_pSessionLockManager;
\ No newline at end of file
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 72c1772c8..ca1597b19 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 000000000..4c4b18469
--- /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<CExtSessionLockSurfaceV1> resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP<CSessionLock> 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<CExtSessionLockV1> 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<CExtSessionLockManagerV1>(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<CSessionLock>(std::make_shared<CExtSessionLockV1>(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<CSessionLock> 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<CSessionLockSurface>(std::make_shared<CExtSessionLockSurfaceV1>(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 000000000..b5d7aed5c
--- /dev/null
+++ b/src/protocols/SessionLock.hpp
@@ -0,0 +1,102 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+#include <cstdint>
+#include "WaylandProtocol.hpp"
+#include "ext-session-lock-v1.hpp"
+#include "../helpers/signal/Signal.hpp"
+
+class CMonitor;
+class CSessionLock;
+
+class CSessionLockSurface {
+  public:
+    CSessionLockSurface(SP<CExtSessionLockSurfaceV1> resource_, wlr_surface* surface_, CMonitor* pMonitor_, WP<CSessionLock> owner_);
+    ~CSessionLockSurface();
+
+    bool         good();
+    bool         inert();
+    CMonitor*    monitor();
+    wlr_surface* surface();
+
+    struct {
+        CSignal map;
+        CSignal destroy;
+        CSignal commit;
+    } events;
+
+  private:
+    SP<CExtSessionLockSurfaceV1> resource;
+    WP<CSessionLock>             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<CExtSessionLockV1> resource_);
+    ~CSessionLock();
+
+    bool good();
+    void sendLocked();
+
+    struct {
+        CSignal newLockSurface; // SP<CSessionLockSurface>
+        CSignal unlockAndDestroy;
+        CSignal destroyed; // fires regardless of whether there was a unlockAndDestroy or not.
+    } events;
+
+  private:
+    SP<CExtSessionLockV1> 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<CSessionLock>
+    } 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<UP<CExtSessionLockManagerV1>> m_vManagers;
+    std::vector<SP<CSessionLock>>             m_vLocks;
+    std::vector<SP<CSessionLockSurface>>      m_vLockSurfaces;
+
+    friend class CSessionLock;
+    friend class CSessionLockSurface;
+};
+
+namespace PROTO {
+    inline UP<CSessionLockProtocol> sessionLock;
+};
diff --git a/src/render/Renderer.cpp b/src/render/Renderer.cpp
index 6b1545b19..d22edf5ce 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 <xf86drm.h>
@@ -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));