X11复制仅返回GDK_SELECTION 无法获取CLIPBOARD文本类型问题咨询
问题原因
- 你混淆了X11剪贴板事件的触发逻辑:
SelectionRequest事件只会发送给当前剪贴板的所有者,只有当你的窗口被X Server认定为CLIPBOARD选择的所有者时,才会收到其他程序发来的内容查询请求,这个事件本身不是用来监听剪贴板变更的。 - 你当前收到的
target=TARGETS请求,是其他程序在查询你的窗口作为剪贴板所有者支持的所有数据格式,并不是请求文本内容。你没有正确响应这个TARGETS请求,告知请求方你支持文本格式,自然不会收到后续的text/unicode/string类的格式请求。 - 你的代码存在明显变量错误:
DefaultScreen(mdisplay)里的mdisplay未定义(你前面打开的Display变量名是display)、判断条件里的x_event未定义(你前面声明的事件变量名是event),这些问题也会导致逻辑执行异常。 - X11原生没有提供剪贴板变更的被动监听接口,你当前的实现逻辑本身不符合X11剪贴板的工作规范,偶现的成功属于异常场景的巧合——那次请求方没有先查询支持的格式,直接发送了文本类型的内容请求,所以你能拿到对应日志,正常流程下请求方都会先查TARGETS,你没有响应自然不会有后续请求,无法稳定复现。
正确实现方案
- 优先使用XFixes扩展实现剪贴板变更监听:XFixes提供了
XFixesSelectSelectionInput接口,可以直接注册监听CLIPBOARD选择的变更事件,不需要你主动抢占剪贴板所有者身份,也不需要轮询。示例代码片段:
// 初始化XFixes扩展 int fixes_opcode, fixes_event_base, fixes_error_base; if (!XQueryExtension(display, "XFIXES", &fixes_opcode, &fixes_event_base, &fixes_error_base)) { // 不支持XFixes的环境可降级到定时轮询剪贴板所有者ID的方案 } // 监听CLIPBOARD的所有者变更事件 XFixesSelectSelectionInput(display, root_window, clipboard, XFixesSetSelectionOwnerNotifyMask);
之后你就可以在事件循环里监听XFixes的变更事件,判断剪贴板所有者发生变化后,再主动请求内容。
- 请求剪贴板文本的标准流程:
- 检测到剪贴板变更后,调用
XConvertSelection(display, clipboard, XInternAtom(display, "UTF8_STRING", False), None, your_window, CurrentTime),主动请求UTF8格式的剪贴板内容 - 等待接收
SelectionNotify事件 - 收到事件后,调用
XGetWindowProperty读取你窗口对应的属性,就能拿到实际的文本内容
- 检测到剪贴板变更后,调用
内容的提问来源于stack exchange,提问作者kishoredbn
相关产品推荐
相关产品推荐

