diff --git a/examples/list_globals.rs b/examples/list_globals.rs index 518e721..100dd7a 100644 --- a/examples/list_globals.rs +++ b/examples/list_globals.rs @@ -1,11 +1,43 @@ +//! 列出当前 Wayland 桌面广播的全部全局对象(registry globals)。 +//! +//! Wayland 协议采用"客户端发现"模型:客户端连接到 compositor 后,第一件事是从 +//! registry 中枚举所有被广播的 interface(如 `wl_compositor`、`wl_shm`、 +//! `zwlr_screencopy_manager_v1`、`zxdg_portal_screencast` 等),每个 global 带有 +//! 唯一数字 name、interface 名字符串、最高支持版本号。本示例即打印这三元组。 +//! +//! 类比 Go 的 `xcursor` / wayland-client 示例:用最小可运行代码确认运行环境。 +//! +//! 运行(参见 AGENTS.md "Useful manual commands"): +//! ```sh +//! cargo run --example list_globals +//! ``` +//! +//! 该示例也是 `src/backend_detect.rs` 中检测 `zwlr_screencopy_manager_v1` 是否存在的 +//! 同款机制(参见 `check_screencopy_available`),用于决定走 wlr-screencopy 还是 Portal。 + +// 引入 wayland-client 的快捷初始化辅助函数:内部完成 connect + registry bind + 同步枚举。 use wayland_client::globals::registry_queue_init; +// GlobalListContents 是 registry_queue_init 返回的"已收集好的 global 列表"句柄类型。 use wayland_client::globals::GlobalListContents; +// WlRegistry 是 Wayland 协议对象;Event 是其产生的枚举事件(global/global_remove)。 use wayland_client::protocol::wl_registry::{Event, WlRegistry}; +// Connection 表示与 compositor 的 socket 连接;QueueHandle 是事件队列句柄; +// Dispatch 是 trait,用户必须为关心的协议对象实现它以接收事件回调。 use wayland_client::{Connection, Dispatch, QueueHandle}; +// 示例用的极简 state:无字段。Wayland 客户端需要至少一个 state 类型作为 +// Dispatch trait 的 `Self`,这里就用零大小类型 `Ls`(list globals 的缩写)。 struct Ls; +// 为 Ls 实现 WlRegistry 的 Dispatch:本示例只需枚举 globals,不需要响应任何 +// registry 事件,因此 event 函数留空。wayland-client 要求即便不处理事件也必须 +// 实现 Dispatch(trait contract 强制),否则 `registry_queue_init::` 无法编译。 +// +// Go 类比:类似 `type Ls struct{}` + `func (Ls) HandleEvent(...) {}`—— +// 显式声明"我接收事件但不响应"。 impl Dispatch for Ls { + // 所有参数加 `_` 前缀表示本实现不读取任何参数(Rust 中 `_x` 与 `x` 区分: + // 前者显式标记未使用,避免 dead_code 警告)。 fn event( _state: &mut Self, _registry: &WlRegistry, @@ -17,10 +49,25 @@ impl Dispatch for Ls { } } +// 程序入口。Rust 的 `fn main()` 不能返回 `Result`(标准约定),故用 `.unwrap()` +// 简单 panic;示例程序通常省略错误处理以突出主线逻辑。 fn main() { + // 从 `WAYLAND_DISPLAY` / `XDG_RUNTIME_DIR` 环境变量建立与 compositor 的 socket 连接。 + // 类比 Go 的 `net.Dial("unix", path)`。`.unwrap()` 在连接失败时 panic(示例代码约定)。 let conn = Connection::connect_to_env().unwrap(); + + // registry_queue_init 是 wayland-client 的高层辅助:内部发送 sync request 并阻塞 + // 直到 registry 全部 global 事件到达。返回 (GlobalList, EventQueue)。 + // `::` 是 turbofish 显式指定 state 类型,对应上面 `impl Dispatch for Ls`。 + // 类比 Go 的 `globals, queue := wayland.RegistryQueueInit[Ls](conn)`(泛型实例化)。 let (globals, _queue) = registry_queue_init::(&conn).unwrap(); + + // 遍历所有已收集的 globals。`globals.contents()` 返回内部快照引用, + // `.clone_list()` 复制成 `Vec`(每个 entry 含 name/interface/version)。 + // 类比 Go `for _, g := range globals { ... }`——Rust 的 `for ... in` 直接消费迭代器。 for g in globals.contents().clone_list() { + // `println!` 是 Rust 标准宏(不是函数),类比 Go `fmt.Printf("%d: %s v%d\n", ...)`。 + // `{}` 自动调用参数的 `Display` trait;name 是 u32、interface 是 String、version 是 u32。 println!("{}: {} v{}", g.name, g.interface, g.version); } }