#pragma once #include #include #include #include #include #include #include "alvin/error.hpp" #include "alvin/frame.hpp" #include "alvin/window.hpp" namespace alvin { enum class CaptureBackend { Auto, Portal, // xdg-desktop-portal ScreenCast + PipeWire (any modern Wayland desktop) Gdi, // Win32 BitBlt / PrintWindow }; std::string_view toString(CaptureBackend backend) noexcept; enum class CaptureSource : std::uint8_t { Monitor = 1, Window = 2, Any = Monitor | Window, }; struct CaptureOptions { CaptureBackend backend = CaptureBackend::Auto; // What the portal picker offers. On Windows, Monitor + monitorIndex or // Window + window select the target directly with no dialog. CaptureSource source = CaptureSource::Monitor; int monitorIndex = 0; std::optional window; bool showCursor = false; // Portal only: token from Capture::restoreToken() of an earlier session. // Lets the compositor skip the picker and reuse the previous selection. std::string restoreToken; std::chrono::milliseconds permissionTimeout = std::chrono::minutes(2); }; // A live capture of one monitor or window. class Capture { public: static Result> create(const CaptureOptions& options = {}); virtual ~Capture() = default; Capture(const Capture&) = delete; Capture& operator=(const Capture&) = delete; virtual CaptureBackend backend() const = 0; // Most recent frame. Blocks until the first frame arrives (up to timeout). // Streaming backends only deliver frames when the screen changes, so this // does not wait for a *new* frame; use nextFrame() for that. virtual Result grab(std::chrono::milliseconds timeout = std::chrono::seconds(5)) = 0; // Waits for a frame newer than any previously returned one. virtual Result nextFrame(std::chrono::milliseconds timeout = std::chrono::seconds(5)) = 0; virtual std::string restoreToken() const { return {}; } protected: Capture() = default; }; } // namespace alvin