#pragma once #include #include "../../helpers/memory/Memory.hpp" #include "../../protocols/types/Buffer.hpp" #include "../../render/Framebuffer.hpp" #include "../eventLoop/EventLoopTimer.hpp" #include "../../render/Renderer.hpp" // TODO: do screenshare damage class CWLPointerResource; namespace Screenshare { enum eScreenshareType : uint8_t { SHARE_MONITOR, SHARE_WINDOW, SHARE_REGION, SHARE_NONE }; enum eScreenshareError : uint8_t { ERROR_NONE, ERROR_UNKNOWN, ERROR_STOPPED, ERROR_NO_BUFFER, ERROR_BUFFER_SIZE, ERROR_BUFFER_FORMAT }; enum eScreenshareResult : uint8_t { RESULT_COPIED, RESULT_NOT_COPIED, RESULT_TIMESTAMP, }; using FScreenshareCallback = std::function; using FSourceBoxCallback = std::function; class CScreenshareSession { public: CScreenshareSession(const CScreenshareSession&) = delete; CScreenshareSession(CScreenshareSession&&) = delete; ~CScreenshareSession(); UP nextFrame(bool overlayCursor); void stop(); bool isActive(); // constraints const std::vector& allowedFormats() const; Vector2D bufferSize() const; PHLMONITOR monitor() const; // this will return the correct monitor based on type struct { CSignalT<> stopped; CSignalT<> constraintsChanged; } m_events; private: CScreenshareSession(PHLMONITOR monitor, wl_client* client); CScreenshareSession(PHLMONITOR monitor, CBox captureRegion, wl_client* client); CScreenshareSession(PHLWINDOW window, wl_client* client); WP m_self; bool m_stopped = false; eScreenshareType m_type = SHARE_NONE; PHLMONITORREF m_monitor; PHLWINDOWREF m_window; CBox m_captureBox = {}; // given capture area in logical coordinates (see xdg_output) wl_client* m_client = nullptr; std::string m_name = ""; std::vector m_formats; Vector2D m_bufferSize = Vector2D(0, 0); SP m_tempFB; SP m_shareStopTimer; bool m_sharing = false; struct { CHyprSignalListener monitorDestroyed; CHyprSignalListener monitorModeChanged; CHyprSignalListener windowDestroyed; CHyprSignalListener windowSizeChanged; CHyprSignalListener windowMonitorChanged; } m_listeners; void screenshareEvents(bool started); void calculateConstraints(); void init(); friend class CScreenshareFrame; friend class CScreenshareManager; }; class CCursorshareSession { public: CCursorshareSession(const CCursorshareSession&) = delete; CCursorshareSession(CCursorshareSession&&) = delete; ~CCursorshareSession(); eScreenshareError share(PHLMONITOR monitor, SP buffer, FSourceBoxCallback sourceBoxCallback, FScreenshareCallback callback); void stop(); // constraints DRMFormat format() const; Vector2D bufferSize() const; Vector2D hotspot() const; struct { CSignalT<> stopped; CSignalT<> constraintsChanged; } m_events; private: CCursorshareSession(wl_client* client, WP pointer); WP m_self; bool m_stopped = false; bool m_constraintsChanged = true; wl_client* m_client = nullptr; WP m_pointer; // constraints DRMFormat m_format = 0 /* DRM_FORMAT_INVALID */; Vector2D m_hotspot = Vector2D(0, 0); Vector2D m_bufferSize = Vector2D(0, 0); struct { bool pending = false; PHLMONITOR monitor; SP buffer; FSourceBoxCallback sourceBoxCallback; FScreenshareCallback callback; } m_pendingFrame; struct { CHyprSignalListener pointerDestroyed; CHyprSignalListener cursorChanged; } m_listeners; bool copy(); void render(); void calculateConstraints(); friend class CScreenshareFrame; friend class CScreenshareManager; }; class CScreenshareFrame { public: CScreenshareFrame(const CScreenshareFrame&) = delete; CScreenshareFrame(CScreenshareFrame&&) = delete; CScreenshareFrame(WP session, bool overlayCursor, bool isFirst); ~CScreenshareFrame(); bool done() const; eScreenshareError share(SP buffer, const CRegion& damage, FScreenshareCallback callback); Vector2D bufferSize() const; wl_output_transform transform() const; // returns the transform applied by compositor on the buffer const CRegion& damage() const; private: WP m_self; WP m_session; FScreenshareCallback m_callback; SP m_buffer; Vector2D m_bufferSize = Vector2D(0, 0); CRegion m_damage; // damage in buffer coords bool m_shared = false, m_copied = false, m_failed = false; bool m_overlayCursor = true; bool m_isFirst = false; // void copy(); bool copyDmabuf(); bool copyShm(); void render(); void renderMonitor(); void renderMonitorRegion(); void renderWindow(); void storeTempFB(); friend class CScreenshareManager; friend class CScreenshareSession; }; class CScreenshareManager { public: CScreenshareManager(); UP newSession(wl_client* client, PHLMONITOR monitor); UP newSession(wl_client* client, PHLMONITOR monitor, CBox captureRegion); UP newSession(wl_client* client, PHLWINDOW window); WP getManagedSession(wl_client* client, PHLMONITOR monitor); WP getManagedSession(wl_client* client, PHLMONITOR monitor, CBox captureBox); WP getManagedSession(wl_client* client, PHLWINDOW window); UP newCursorSession(wl_client* client, WP pointer); void onOutputCommit(PHLMONITOR monitor); bool isOutputBeingSSd(PHLMONITOR monitor); private: std::vector> m_sessions; std::vector> m_cursorSessions; std::vector> m_pendingFrames; struct SManagedSession { SManagedSession(UP&& session); UP m_session; CHyprSignalListener stoppedListener; }; std::vector> m_managedSessions; WP getManagedSession(eScreenshareType type, wl_client* client, PHLMONITOR monitor, PHLWINDOW window, CBox captureBox); friend class CScreenshareSession; }; inline UP& mgr() { static UP manager = nullptr; if (!manager && g_pHyprRenderer) { Log::logger->log(Log::DEBUG, "Starting ScreenshareManager"); manager = makeUnique(); } return manager; } } template <> struct std::formatter : std::formatter { auto format(const Screenshare::eScreenshareType& res, std::format_context& ctx) const { switch (res) { case Screenshare::SHARE_MONITOR: return formatter::format("monitor", ctx); case Screenshare::SHARE_WINDOW: return formatter::format("window", ctx); case Screenshare::SHARE_REGION: return formatter::format("region", ctx); case Screenshare::SHARE_NONE: return formatter::format("ERR NONE", ctx); } return formatter::format("error", ctx); } };