summaryrefslogtreecommitdiff
path: root/src/managers/screenshare/ScreenshareManager.cpp
diff options
context:
space:
mode:
authorIkalco <73481042+ikalco@users.noreply.github.com>2026-02-22 06:30:11 -0600
committerGitHub <noreply@github.com>2026-02-22 12:30:11 +0000
commitb4ee4674f9a74e3d602c7fb17bc09f79d221583c (patch)
tree294bbb207c44e778dd78afda65cbd79181f04124 /src/managers/screenshare/ScreenshareManager.cpp
parent93dbf884261efcb387e920b1cd0e4ed5b288bc3a (diff)
protocols: implement image-capture-source-v1 and image-copy-capture-v1 (#11709)
Implements the new screencopy protocols
Diffstat (limited to 'src/managers/screenshare/ScreenshareManager.cpp')
-rw-r--r--src/managers/screenshare/ScreenshareManager.cpp161
1 files changed, 161 insertions, 0 deletions
diff --git a/src/managers/screenshare/ScreenshareManager.cpp b/src/managers/screenshare/ScreenshareManager.cpp
new file mode 100644
index 00000000..823e99b3
--- /dev/null
+++ b/src/managers/screenshare/ScreenshareManager.cpp
@@ -0,0 +1,161 @@
+#include "ScreenshareManager.hpp"
+#include "../../render/Renderer.hpp"
+#include "../../Compositor.hpp"
+#include "../../desktop/view/Window.hpp"
+#include "../../protocols/core/Seat.hpp"
+
+using namespace Screenshare;
+
+CScreenshareManager::CScreenshareManager() {
+ ;
+}
+
+void CScreenshareManager::onOutputCommit(PHLMONITOR monitor) {
+ std::erase_if(m_sessions, [&](const WP<CScreenshareSession>& session) { return session.expired(); });
+
+ // if no pending frames, and no sessions are sharing, then unblock ds
+ if (m_pendingFrames.empty()) {
+ for (const auto& session : m_sessions) {
+ if (!session->m_stopped && session->m_sharing)
+ return;
+ }
+
+ g_pHyprRenderer->m_directScanoutBlocked = false;
+ return; // nothing to share
+ }
+
+ std::ranges::for_each(m_pendingFrames, [&](WP<CScreenshareFrame>& frame) {
+ if (frame.expired() || !frame->m_shared || frame->done())
+ return;
+
+ if (frame->m_session->monitor() != monitor)
+ return;
+
+ if (frame->m_session->m_type == SHARE_WINDOW) {
+ CBox geometry = {frame->m_session->m_window->m_realPosition->value(), frame->m_session->m_window->m_realSize->value()};
+ if (geometry.intersection({monitor->m_position, monitor->m_size}).empty())
+ return;
+ }
+
+ frame->copy();
+ });
+
+ std::erase_if(m_pendingFrames, [&](const WP<CScreenshareFrame>& frame) { return frame.expired(); });
+}
+
+UP<CScreenshareSession> CScreenshareManager::newSession(wl_client* client, PHLMONITOR monitor) {
+ if UNLIKELY (!monitor || !g_pCompositor->monitorExists(monitor)) {
+ LOGM(Log::ERR, "Client requested sharing of a monitor that is gone");
+ return nullptr;
+ }
+
+ UP<CScreenshareSession> session = UP<CScreenshareSession>(new CScreenshareSession(monitor, client));
+
+ session->m_self = session;
+ m_sessions.emplace_back(session);
+
+ return session;
+}
+
+UP<CScreenshareSession> CScreenshareManager::newSession(wl_client* client, PHLMONITOR monitor, CBox captureRegion) {
+ if UNLIKELY (!monitor || !g_pCompositor->monitorExists(monitor)) {
+ LOGM(Log::ERR, "Client requested sharing of a monitor that is gone");
+ return nullptr;
+ }
+
+ UP<CScreenshareSession> session = UP<CScreenshareSession>(new CScreenshareSession(monitor, captureRegion, client));
+
+ session->m_self = session;
+ m_sessions.emplace_back(session);
+
+ return session;
+}
+
+UP<CScreenshareSession> CScreenshareManager::newSession(wl_client* client, PHLWINDOW window) {
+ if UNLIKELY (!window || !window->m_isMapped) {
+ LOGM(Log::ERR, "Client requested sharing of window that is gone or not shareable!");
+ return nullptr;
+ }
+
+ UP<CScreenshareSession> session = UP<CScreenshareSession>(new CScreenshareSession(window, client));
+
+ session->m_self = session;
+ m_sessions.emplace_back(session);
+
+ return session;
+}
+
+UP<CCursorshareSession> CScreenshareManager::newCursorSession(wl_client* client, WP<CWLPointerResource> pointer) {
+ UP<CCursorshareSession> session = UP<CCursorshareSession>(new CCursorshareSession(client, pointer));
+
+ session->m_self = session;
+ m_cursorSessions.emplace_back(session);
+
+ return session;
+}
+
+WP<CScreenshareSession> CScreenshareManager::getManagedSession(wl_client* client, PHLMONITOR monitor) {
+ return getManagedSession(SHARE_MONITOR, client, monitor, nullptr, {});
+}
+
+WP<CScreenshareSession> CScreenshareManager::getManagedSession(wl_client* client, PHLMONITOR monitor, CBox captureBox) {
+
+ return getManagedSession(SHARE_REGION, client, monitor, nullptr, captureBox);
+}
+
+WP<CScreenshareSession> CScreenshareManager::getManagedSession(wl_client* client, PHLWINDOW window) {
+ return getManagedSession(SHARE_WINDOW, client, nullptr, window, {});
+}
+
+WP<CScreenshareSession> CScreenshareManager::getManagedSession(eScreenshareType type, wl_client* client, PHLMONITOR monitor, PHLWINDOW window, CBox captureBox) {
+ if (type == SHARE_NONE)
+ return {};
+
+ auto it = std::ranges::find_if(m_managedSessions, [&](const auto& session) {
+ if (session->m_session->m_client != client || session->m_session->m_type != type)
+ return false;
+
+ switch (type) {
+ case SHARE_MONITOR: return session->m_session->m_monitor == monitor;
+ case SHARE_WINDOW: return session->m_session->m_window == window;
+ case SHARE_REGION: return session->m_session->m_monitor == monitor && session->m_session->m_captureBox == captureBox;
+ case SHARE_NONE:
+ default: return false;
+ }
+
+ return false;
+ });
+
+ if (it == m_managedSessions.end()) {
+ UP<CScreenshareSession> session;
+ switch (type) {
+ case SHARE_MONITOR: session = UP<CScreenshareSession>(new CScreenshareSession(monitor, client)); break;
+ case SHARE_WINDOW: session = UP<CScreenshareSession>(new CScreenshareSession(window, client)); break;
+ case SHARE_REGION: session = UP<CScreenshareSession>(new CScreenshareSession(monitor, captureBox, client)); break;
+ case SHARE_NONE:
+ default: return {};
+ }
+
+ session->m_self = session;
+ m_sessions.emplace_back(session);
+
+ it = m_managedSessions.emplace(m_managedSessions.end(), makeUnique<SManagedSession>(std::move(session)));
+ }
+
+ auto& session = *it;
+
+ session->stoppedListener = session->m_session->m_events.stopped.listen([session = WP<SManagedSession>(session)]() {
+ std::erase_if(Screenshare::mgr()->m_managedSessions, [&](const auto& s) { return !s || session.expired() || s->m_session == session->m_session; });
+ });
+
+ return session->m_session;
+}
+
+void CScreenshareManager::destroyClientSessions(wl_client* client) {
+ LOGM(Log::TRACE, "Destroy client sessions for {:x}", (uintptr_t)client);
+ std::erase_if(m_managedSessions, [&](const auto& session) { return !session || session->m_session->m_client == client; });
+}
+
+CScreenshareManager::SManagedSession::SManagedSession(UP<CScreenshareSession>&& session) : m_session(std::move(session)) {
+ ;
+}