Files
wl-webrtc/src/cap_wlr_screencopy.rs

108 lines
5.8 KiB
Rust
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
//! 文件:wlr-screencopy-unstable-v1 协议客户端绑定(`CaptureSource` 实现)
//!
//! 本文件实现 `CapWlrScreencopy`,作为 `state.rs` 中 `State<S>` 的泛型参数 `S`
//! 的两个具体实现之一(另一个是 `CapPortal`)。wlr-screencopy 是 wlroots 原生
//! 协议,优先于 XDG Portal/PipeWire:无需 D-Bus、无需用户授权对话框。
//!
//! 协议绑定来源:`wayland_protocols_wlr::screencopy::v1::client::*` 由
//! wayland-scanner 工具根据 `wlr-screencopy-unstable-v1.xml` 自动生成(类似 Go
//! 用 cgo 绑定 C 库,但 Rust 通过 wayland-client crate 暴露 type-safe wrapper
//! 无需手写 C FFI)。
//!
//! 异步模型:客户端无法主动"截屏",只能:(1) 绑定全局 manager、(2) 调用
//! `manager.capture_output()` 创建帧对象、(3) 等待内核推送 buffer/format 事件、
//! (4) 调用 `frame.copy(buffer)` 请求拷贝。因此本文件的 `alloc_frame()` 永远
//! 返回 `None`,真正的帧创建逻辑在 `state.rs` 的 Dispatch impl 中(英文注释
//! 标记为 T6b)。
use anyhow::Result;
use wayland_client::globals::GlobalList;
use wayland_client::protocol::wl_buffer::WlBuffer;
use wayland_client::protocol::wl_output::WlOutput;
use wayland_client::QueueHandle;
use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::ZwlrScreencopyFrameV1;
use crate::state::{CaptureSource, OutputInfo, State};
// L2: `CaptureSource` trait 的具体实现——wlroots 原生 wlr-screencopy 协议后端。
// 仅持有"当前在飞"的帧对象;协议管理器 `ZwlrScreencopyManagerV1` 的绑定存放
// 在 `State` 的状态机字段中(需要 Dispatch impl,见下方英文注释)。
/// wlr-screencopy capture backend.
///
/// Holds the current in-flight frame protocol object. The
/// `ZwlrScreencopyManagerV1` is stored separately in
/// `State::EverythingButFmt` because binding it requires a `Dispatch`
/// impl that lives in state.rs (T6b).
pub struct CapWlrScreencopy {
/// The active frame object for the current capture cycle.
/// Set by Dispatch impls after `manager.capture_output()`, cleared
/// by `on_done_with_frame()`.
// L3: `Option<T>` 类似 Go 的 `*T`(指针)——要么持有 T 的值,要么是 None(空)。
pub current_frame: Option<ZwlrScreencopyFrameV1>,
}
// L2: 为 `CapWlrScreencopy` 实现 `CaptureSource` trait。
// Rust 的 `impl Trait for Type` 块类比 Go 的 method receiver——
// Go: `func (r *Type) Method(args)`receiver 作为第一个参数显式声明)
// Rust: `fn method(&self, args)``&self` 是 `self: &Self` 的语法糖,等价 Go receiver
// trait impl 要求方法签名与 trait 定义严格一致,编译器会校验。
impl CaptureSource for CapWlrScreencopy {
/// Unit type: wlr-screencopy is fully asynchronous — `alloc_frame()`
/// always returns `None`. The frame object is created by Dispatch
/// impls calling `manager.capture_output()`, not by this method.
// L3: `type Frame = ();` 关联类型(associated type):将"帧"的具体类型延迟到
// impl 处决定。wlr-screencopy 用 unit `()` 因为帧对象生命周期由 Dispatch 控制。
type Frame = ();
// L3: 构造函数。`Self` 在 impl 块内是 `CapWlrScreencopy` 的类型别名。
// 参数名以 `_` 前缀表示"有意未使用"——manager 绑定不在此处发生,故这些
// 参数(GlobalList/WlOutput/OutputInfo/QueueHandle)暂未消费。返回
// `Result<Self>`,失败由调用方用 `?` 操作符传播(类比 Go 的 `if err != nil`)。
fn new(
_gm: &GlobalList,
_output: &WlOutput,
_output_info: &OutputInfo,
_qh: &QueueHandle<State<Self>>,
) -> Result<Self> {
// Manager binding happens in state.rs during the ProbingOutputs →
// EverythingButFmt stage transition (T6b). It requires a Dispatch
// impl that doesn't exist yet, so we cannot call gm.bind() here.
// `Ok(...)` 是 `Result::Ok(...)` 的简写,将成功值包装为 Result 返回;
// `Self { ... }` 等价于 `CapWlrScreencopy { ... }`impl 块内可用。
Ok(Self {
current_frame: None,
})
}
// L3: 分配帧对象。返回 `Option<Self::Frame>`(此处 Frame = (),故永远返回 None)。
// `&mut self` 是 `self: &mut Self` 的简写(类比 Go 指针 receiver `*Type`)。
fn alloc_frame(&mut self) -> Option<Self::Frame> {
// wlr-screencopy is asynchronous: the Dispatch impl creates a new
// ZwlrScreencopyFrameV1 which triggers the buffer allocation flow
// (buffer event → negotiate format → create DMA-BUF). This method
// always returns None.
None
}
// L3: 提交拷贝请求:将已分配的 DMA-BUF(WlBuffer)关联到当前帧对象。
fn queue_copy(&mut self, buffer: &WlBuffer, _qh: &QueueHandle<State<Self>>) {
// `if let Some(x) = &expr`pattern matching,当 expr 是 Some 时绑定内部值。
// 此处 `&self.current_frame` 不可变借用,调用 `frame.copy(buffer)` 提交拷贝。
if let Some(frame) = &self.current_frame {
frame.copy(buffer);
} else {
// `tracing::warn!` 是结构化日志宏(类比 Go log.Printf,但支持字段)。
tracing::warn!("queue_copy: no current wlr-screencopy frame");
}
}
// L3: 帧处理完成后的清理。`_frame: Self::Frame` 前缀 `_` 表示参数未使用(Frame 是 unit)。
fn on_done_with_frame(&mut self, _frame: Self::Frame) {
// `Option::take()`:取出 Some 并将原位置替换为 None,原值所有权转移给返回值。
if let Some(frame) = self.current_frame.take() {
// `frame.destroy()` 发送 wayland 析构请求,释放服务端协议对象资源。
frame.destroy();
}
}
}