Repository navigation
X11 Large Transfer
本页记录 src-tauri/vendor/arboard/ 里的本地补丁。基线是 crates.io arboard 3.6.1,保留原 MIT / Apache-2.0 许可证与全部平台源码,生产补丁只涉及 X11。补丁清单在 vendor/arboard/PATCHES.md。
内部复制的 OCR 文本或译文会在后续轮询中被重新录入历史,产生重复条目。
原实现在设置 selection owner 后只做 flush()。另一个连接的 roundtrip 不能证明写连接已经完成。 watcher 可能先读到内部文本并消费掉写入抑制标记,下一轮才收到 SelectionNotify,于是同一份内容被当作外部新内容再次入库。
对 set_selection_owner 返回的实际 VoidCookie 调用 check(),等待服务器完成写连接请求并传播错误,保留原有的 flush()。
这是一个通用教训:跨连接的往返不构成对另一条连接完成状态的证明。
高熵 4K / 8K 截图复制后,独立的 arboard 与 xclip 读取均失败。
原提供端把整张 PNG 一次写入 X property。X server 有单次请求字节上限,高熵图压缩率低,超限后请求直接被拒。
新增 src/platform/linux/x11/incr.rs,所有状态由剪贴板服务线程持有,系统写入不等待接收者。
根据实际 maximum_request_bytes 扣除协议头和 padding
↓
决定 direct 还是 INCR,每块最多 1 MiB
↓
等待 requestor 删除属性后再推进
↓
最终零长度块也必须确认
| 约束 | 值 |
|---|---|
| 最多活动传输 | 4 个 |
| 独立不可变 payload 快照合计 | 256 MiB |
| 单块上限 | 1 MiB |
| handover 初始握手 | 最多 4 s |
| 空闲超时 | 4 s |
| 总截止 | 30 s |
同一张图的多个 reader 共享 Arc,不复制 payload。
256 MiB 是压缩传输及保留快照的预算,不是 PNG 解码像素的预算——两者不能混算。
这些是实现里最容易出错的地方:
-
selection 替换和
SelectionClear保留已接受请求的旧快照。 换了剪贴板内容不能让正在传输的旧请求半途失败。 -
所有目标在分派前统一拒绝活动
(requestor, property)冲突。 同一个键上不能有两个传输。 - requestor 销毁只回收它自己的传输。 同一窗口有多个 property 时,最后一个结束才恢复旧事件 mask。
- 只有自有窗口销毁才终止服务。
- manager 通知到达后仍须等待实际数据及最终零块确认。 半张图不能算成功结果,失败要清理残留属性。
先读取零长度属性的 metadata,在分配 body 之前检查预算。INCR header 只允许一个 u32,数据按剩余预算读取并拒绝 bytes_after。
原实现的 10 ms 分块截止改为 4 s 空闲 / 30 s 总截止,以兼容合法的慢接收链路。
这些超时约束的是「正常运行的 X server 上停滞的 requestor」。它们不提供对挂死 X server 的系统 I/O 超时保证——那是不同层面的问题。
补丁的测试分两层,因为协议测试必须隔离:
# 纯状态测试,不连接桌面
cargo test --locked --manifest-path src-tauri/Cargo.toml \
-p arboard --lib platform::linux::x11::incr::tests::
# 新建私有 Xvfb,运行协议、接收预算及 watcher 抑制回归
# 需要 xvfb / xauth / xclip
./scripts/test-x11-clipboard.sh脚本已接入 ci-local.sh 和 Linux CI,Windows / macOS 不执行。
覆盖范围:高熵 4K/8K 的独立进程与 xclip 逐像素互操作、慢 chunk、多 reader、selection 更换、同 key 冲突、销毁与不消费的回收、完整 handover 及后续小文本。预算/快照/总截止为纯单元测试;写屏障回归覆盖受控写序、内部抑制和外部同内容再次置顶。
正式协议测试文件默认 ignored,要求显式隔离环境,并且只在 Linux 编译。测试 fixture 会保持客户端连接以防 Xvfb 自动 reset——这一点在三个独立新建的 X server 上都验证过。
工作区显式包含此 vendored 库,但默认成员只有主程序,普通 cargo test 不运行依赖自己的测试。上游默认单元测试被标记 ignored,避免显式运行时意外访问真实桌面;Linux 剪贴板写入的 doctest 改为 no_run(仍编译),防止 cargo test --workspace 执行示例写入。
升级 arboard 时必须逐项核对写完成屏障、INCR 生命周期与预算边界,复跑上述门禁,再决定移除补丁还是重放补丁。