环境
- 操作系统:Arch Linux
- 显示协议:Wayland
- 合成器(compositor):niri 26.04 (8ed0da4);已验证在 GNOME(Mutter)下现象完全相同,不限于 niri
- Emacs:PGTK 构建,GNU Emacs 32.0.50(源码自编译,
/usr/local/bin/emacs→emacs-32.0.50) - 输入法:fcitx5 5.1.21(仅 fcitx5 daemon 在运行;无 ibus-daemon)
- Emacs 实际加载的 GTK IM 模块:
im-wayland.so(GTK3 的 Wayland 模块,走zwp_text_input_v3协议;经/proc/<pid>/maps验证) - fcitx5 侧对 Wayland 的对接:
libwaylandim.so(zwp_input_method_v2前端)+libwayland.so - 复现率:100%(稳定复现)
复现步骤
- 在缓冲区位置 A 处正常输入一段中文。
- 按多次回车把光标移动到另一个位置 B。
- 再次开始拼音输入。
现象
- 按下第一键、候选框出现的瞬间,候选框位于上一次输入的位置 A;
- 约 0.01~0.0x 秒后,候选框"闪烁"跳到当前光标所在的正确位置 B;
- 之后输入过程位置一直正确,直到下一次移动光标重新触发。
关键观察:无论移动光标后等待多久再输入,第一下候选框永远是旧位置。说明不是消息延迟——若是延迟,等待后再输入就应是正确位置。
视频演示
数据链路(已核实)
Emacs (PGTK, gtk_im_context_set_cursor_location)
└→ GTK3 im-wayland 模块 → zwp_text_input_v3::set_cursor_rectangle
└→ niri 合成器
└→ fcitx5 (libwaylandim.so, zwp_input_method_v2)
└→ 引擎 → 候选框
对照:Zed(GPUI)直接实现 zwp_text_input_v3,同样走 niri → fcitx5,无此问题。
排查过程
1. Emacs 端确认在重绘时上报光标位置
pgtk_draw_window_cursor(src/pgtkterm.c:3024)→pgtk_im_set_cursor_location(src/pgtkterm.c:3072)→gtk_im_context_set_cursor_location(src/pgtkim.c:214)。- 移动光标后该调用确实执行、坐标正确(最终候选框跳到正确位置可证)。
2. 尝试过的补丁:按键进 IM 前主动推送,无效
最初假设是"GTK 的 ibus/fcitx5 IM 模块空闲时忽略 rect 更新",故在 pgtk_im_filter_keypress(src/pgtkim.c:202)把按键交给 gtk_im_context_filter_keypress 之前,主动推送一次当前光标位置(带去重缓存,仅位置变化时调用)。重新编译后测试:完全无改善。
3. 与 Zed 的对比
Zed 直接实现 zwp_text_input_v3:光标矩形通过 set_cursor_rectangle + commit 随帧提交,是合成器常驻状态。移动光标后立即输入,候选框第一下就在正确位置。
两边最终都走 zwp_text_input_v3 → niri → fcitx5,但:
- Zed:rect 是应用主动、显式地随每帧/选择变化 commit;
- Emacs/GTK:rect 由 GTK
im-wayland内部管理,行为不可控(可能只在合成激活期间才真正提交/转发,空闲时 rect 不更新)。
问题
这个问题能解决吗?