PAYATHON 2026

Wayland 中为何收不到 wl_data_device 的 data_offer 事件?

数据小陈

结论

日志显示,wl_data_device_manager 和 wl_seat 已绑定,客户端也已发送 get_data_device 请求。问题更可能出在客户端没有创建获得键盘焦点的 wl_surface。Wayland 核心剪贴板选择通常与键盘焦点关联,因此仅创建数据设备并注册 listener,不能保证后台客户端收到剪贴板通知。具体行为还取决于合成器及其策略。

日志说明了什么

服务端发送了 wl_seat.name("Hyprland") 和 wl_seat.capabilities(3),但客户端没有为 wl_seat 注册 listener,因此这两项事件被丢弃。它们不同于 data_offer,也不能证明剪贴板选择已传递给客户端。

日志中也没有服务端发送的 wl_data_device.data_offer 或 wl_data_device.selection 事件。data_offer 用于通知客户端有剪贴板或拖放数据提供对象;注册回调本身不会触发该事件。处理剪贴板时还应关注 selection 回调,并在收到新 offer 时处理其 MIME 类型。

建议的排查步骤

  1. 创建并映射一个 wl_surface,使其获得键盘焦点。当前程序没有创建 surface,因此无法依靠核心 wl_data_device 接口在后台读取剪贴板。
  2. 等该 surface 获得焦点后,从另一个客户端设置或更新剪贴板内容,再观察 data_offer 和 selection 回调。回调是否触发取决于当前选择状态和合成器行为。注册 listener 成功并不保证能收到初始剪贴板内容。
  3. 如果需要在没有焦点时监听剪贴板,检查合成器是否支持相应的数据控制协议。日志列出了 zwlr_data_control_manager_v1 和 ext_data_control_manager_v1,但这不表示核心 wl_data_device 支持后台访问。客户端需要实现所选扩展协议,并遵循合成器的访问策略。
  4. 为区分“没有事件”和“输出没有刷新”,让 fprintf(stderr, ...) 与 fflush(stdout) 使用同一个输出流:
fprintf(stderr, "data_offer received\n");
fflush(stderr);

确认收到 data_offer 后,再通过 offer 查询 MIME 类型,并使用对应的 Wayland 数据传输流程读取内容。

注意事项

这段日志不足以断定 Hyprland 出现故障。它能确认请求已发出,但无法说明服务端发送剪贴板 offer 的条件是否满足。先让客户端获得键盘焦点,并触发一次新的剪贴板选择,再检查核心协议路径;如果要在后台读取,则需单独核对数据控制扩展和合成器策略。

备注:内容仅供参考。