108 lines
5.8 KiB
Rust
108 lines
5.8 KiB
Rust
//! 文件: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();
|
||
}
|
||
}
|
||
}
|