- JavaScript 89.6%
- CMake 5.9%
- Shell 2.6%
- CSS 1.9%
| po | ||
| schemas | ||
| .clang-format | ||
| .gitignore | ||
| CMakeLists.txt | ||
| COPYING | ||
| extension.js | ||
| indicator.js | ||
| install.sh | ||
| lib.js | ||
| menu.js | ||
| Messages.sh | ||
| metadata.json.in | ||
| panel.js | ||
| prefs.js | ||
| README.md | ||
| README_original | ||
| stylesheet.css | ||
| 修复inputmethodpanel候选框位置问题.md | ||
Input Method Panel (kimpanel) 修复版
基于 wengxt/gnome-shell-extension-kimpanel v91 (GNOME Shell 48-50)
问题描述
在部分应用(Electron 应用如 OpenCode、Chrome 中靠近屏幕底部的输入框)中使用 fcitx5 输入中文时,候选框出现以下问题:
| 应用 | 类型 | 现象 |
|---|---|---|
| gedit / notepadqq | Wayland 原生 (GTK) | 候选框正常,靠近底部时自动翻转到光标上方 |
| OpenCode / Chrome | XWayland (Electron/Chromium) | 候选框溢出屏幕下方,完全看不到;或候选框与输入文字重叠 |
环境:Debian 13 + GNOME Shell 48 + fcitx5-rime + Wayland,200% 缩放
根因分析
kimpanel 扩展通过 D-Bus 接收 fcitx5 的光标坐标,在 GNOME Shell 上渲染候选框。坐标传入有两种路径:
| 路径 | relative | 使用场景 | 坐标含义 |
|---|---|---|---|
SetRelativeSpotRectV2 |
true |
Wayland 原生应用 | 窗口相对坐标,带 scale |
SetSpotRect / UpdateSpotLocation |
false |
XWayland 应用 | 绝对屏幕坐标 |
Bug 1(核心):Mtk.Rectangle 属性名错误
panel.js 第 230-231 行,构造 MtkRectangle 时使用 width/height,但读取时用了 w/h:
// 构造:正确
rect = new Mtk.Rectangle({x: x, y: y, width: w, height: h});
// 读取:BUG — MtkRectangle 没有 .w / .h 属性
w = rect.w; // → undefined
h = rect.h; // → undefined
Mtk.Rectangle 的 C 结构体字段是 width/height,GJS 绑定严格映射为 rect.width/rect.height。rect.w/rect.h 永远是 undefined。
这导致:
h == 0检查永远为false(undefined == 0 → false)- 边界检测表达式
y + panel_height + h >= monitor.height变成NaN >= 1440 → false - 箭头翻转逻辑完全失效,候选框永远出现在光标下方
_cursor.set_size(undefined, undefined)使 BoxPointer 定位混乱
Bug 2:绝对坐标被 protocol_to_stage_rect 误处理
SetSpotRect 传入的已经是全屏绝对坐标(X root 坐标 → stage 坐标),但代码对其调用了 protocol_to_stage_rect()。该函数期望输入为窗口相对坐标,对 XWayland 窗口会叠加窗口偏移量,使坐标进一步偏离。
Bug 3:panel_height 为 0 或 stale 值
this.panel.get_height() 在面板首次显示或内容变化后可能返回 0(尚未测量),边界检测的 y + 0 + h >= monitor.height 使用 0 导致翻转阈值不准确。
修复内容
所有修改仅涉及 panel.js:
修复 1:rect.w → rect.width,rect.h → rect.height(核心)
- w = rect.w;
- h = rect.h;
+ w = rect.width;
+ h = rect.height;
使用正确的 GJS 属性名,使 w/h 获得真实的像素值。边界检测、光源尺寸、BoxPointer 定位全部恢复正确行为。
修复 2:移除 protocol_to_stage_rect 的误调用
} else {
rect = new Mtk.Rectangle({x : x, y : y, width : w, height : h});
- if (focusWindow) {
- rect = focusWindow.protocol_to_stage_rect(rect);
- }
}
SetSpotRect 传入的是屏幕绝对坐标,不应再叠加窗口偏移。Wayland 原生应用的 SetRelativeSpotRectV2 路径(relative=true)保持不变。
修复 3:panel_height 最小值保障
let panel_height = this.panel.get_height();
+ if (panel_height < 1) {
+ panel_height = 80;
+ }
当面板尚未测量高度时,使用 80px 作为合理估算值,确保边界检测在首次调用时就能正确工作。
修复 4:屏幕底部 clamp 优化
- y = monitor.y + monitor.height - 1;
- h = 1;
+ y = monitor.y + monitor.height - 50;
+ h = 20;
光标溢出屏幕底部时,将光源(_cursor actor)放置在距屏幕底边 50px 处,高度 20px,配合 St.Side.BOTTOM 箭头(候选框出现在光标上方),避免候选框与输入文字重叠。
备份与恢复
# 文件列表
panel.js ← 修复后的版本
panel.js.bak ← 原始版本备份
extension.js ← 原始版本(未修改)
extension.js.bak ← 原始版本备份
# 恢复原始版本
cp panel.js.bak panel.js
# 然后注销重新登录
已知限制
XWayland 应用(Electron/OpenCode/Chrome on X11 backend)的光标坐标来自 fcitx5 的 XIM 前端,坐标值与 Wayland 原生应用相比存在偏移。这导致候选框与光标的距离略大于 gedit 等 Wayland 原生应用。该偏移源自 fcitx5 或 XIM 协议层面,无法在 GNOME Shell 扩展中根除,但候选框现在已可见且不会溢出屏幕。
兼容性
- GNOME Shell 48-50
- 任意分辨率和缩放比(1x/2x/...,包括 200% HiDPI)
- Wayland 会话
- fcitx5 5.x + kimpanel protocol
- 不影响 Wayland 原生应用(gedit 等)的原有行为