docs(cap_wlr): 中文注释 wlr-screencopy 协议绑定

This commit is contained in:
dailz
2026-06-22 16:52:48 +08:00
parent 3d314a35aa
commit d3016161d1
+43
View File
@@ -1,3 +1,20 @@
//! 文件: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;
@@ -7,6 +24,9 @@ use wayland_protocols_wlr::screencopy::v1::client::zwlr_screencopy_frame_v1::Zwl
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
@@ -17,15 +37,27 @@ 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,
@@ -35,11 +67,15 @@ impl CaptureSource for CapWlrScreencopy {
// 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
@@ -48,16 +84,23 @@ impl CaptureSource for CapWlrScreencopy {
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();
}
}