Wayland 下 Emacs(PGTK)输入法候选框定位 Bug:输入瞬间候选框先出现在上一次光标位置,再跳回正确位置

环境

  • 操作系统:Arch Linux
  • 显示协议:Wayland
  • 合成器(compositor):niri 26.04 (8ed0da4);已验证在 GNOME(Mutter)下现象完全相同,不限于 niri
  • Emacs:PGTK 构建,GNU Emacs 32.0.50(源码自编译,/usr/local/bin/emacsemacs-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.sozwp_input_method_v2 前端)+ libwayland.so
  • 复现率:100%(稳定复现)

复现步骤

  1. 在缓冲区位置 A 处正常输入一段中文。
  2. 按多次回车把光标移动到另一个位置 B。
  3. 再次开始拼音输入。

现象

  • 按下第一键、候选框出现的瞬间,候选框位于上一次输入的位置 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_cursorsrc/pgtkterm.c:3024)→ pgtk_im_set_cursor_locationsrc/pgtkterm.c:3072)→ gtk_im_context_set_cursor_locationsrc/pgtkim.c:214)。
  • 移动光标后该调用确实执行、坐标正确(最终候选框跳到正确位置可证)。

2. 尝试过的补丁:按键进 IM 前主动推送,无效

最初假设是"GTK 的 ibus/fcitx5 IM 模块空闲时忽略 rect 更新",故在 pgtk_im_filter_keypresssrc/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 不更新)。

问题

这个问题能解决吗?

1 个赞

我也是 arch wayland pgtk,GNU Emacs 32.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.52, cairo version 1.18.4) of 2026-08-03,没有这种情况。

你用的是什么窗口管理器/桌面环境?

noctalia + labwc,然后用 wlrctl 控制窗口的聚焦隐藏,以及聚焦时的鼠标移动。

我用的ubuntu 2604自带的emacs 30.2 pgtk版, 仔细看了也会出现, 只是太快了, 不仔细看感觉不到.