Client Side Input panel for Fcitx 5

(English version is at the end of this post.)

输入框的定位相关的问题其实很复杂,过去 Fcitx 总是自己绘制相关的窗口。X11 这个办法还好使,但是其他情况可能就没这么好使了。让客户端绘制窗口的想法其实比 Fcitx 5 要早得多,最早是为了 fbterm 而增加的支持。

显然 fbterm 没法利用任何来自显示管理器的界面,所以它需要自己绘制它自己的界面。那会儿我添加了一个很简单的实现来支持这个功能。

为了正确显示界面需要支持以下功能:

  • 窗口显示在光标的位置
  • 窗口不能移出屏幕

在 wayland 里,和 X 最大的区别就是不知道窗口的位置,所以不得不使用特别的方法来支持。

  • 用 wayland 的输入法协议的话,它确实是支持将某个窗口标记为输入法窗口并让混成器帮你进行定位,但是需要程序自己先使用 wayland 的输入法协议,混成器也要支持这个协议。目前这两部分的支持并不好。
  • 或者让窗口传送一个相对坐标,然后让混成器帮忙移动窗口。gnome wayland + kimpanel 的扩展就是这样进行定位的,因为 kimpanel 扩展正好是运行在混成器里面所以知道所有的窗口信息。但是让各种混成器都支持这个也不太现实。
  • 然后就是本次说到的方式,让程序自己绘制界面。当然,缺点就是实现通过 im module 的话,就只能支持 Gtk / Qt 的程序,但相对来说可以覆盖大部分的程序了。我个人对于这个方法比较反感,因为感觉可能出问题的地方很多,对于程序来说添加一个额外窗口和过去的 im module 相比有了更强的侵入性。不过在其他很多系统上,例如 windows 和 uim 可能都使用了这个方式。

不过相比只是因为担心就不采取行动的话,还不如先试一试,毕竟解决实际存在的问题的意义更加重大。想要测试的话需要使用 fcitx5 / fcitx5-qt / fcitx5-gtk 的 git代码。

目前还有一些实现的限制:

Gtk 3 不支持已经实现的窗口重新移动位置,Gtk 4 对于不支持较新的 xdg popup positioner 的混成器的是采用隐藏再显示窗口的方式,而这个方式会导致窗口闪烁(Qt 用同样的 hack 就不会,我猜测是 Gtk 有和刷新率对齐之类的操作?)。所以我干脆就没在 Gtk 3 用这个 hack,毕竟闪烁起来看着更糟一点…

Qt 的话出于没有暴露 xdg positioner api 的限制,在窗口定位方面并不能保证不移出屏幕,因此我采取了另一个方式:保证输入框总是在窗口范围内。这个对于小窗口并不是特别友好,例如 krunner,不过我也没有更好的办法了。

本文就是用 firefox + wayland 输入的,整体来说还行……Gtk 3 定位延迟虽然有点难受不过反正我也没更好办法啦。

In the past years, fcitx always renders its pop up on by itself. This is Ok for X11, but not so good for other cases. The idea of letting client to render its UI actually existed long before fcitx 5 comes out. It was first introduced in fcitx 4 for fbterm.

Obviously, fbterm can not render UI using any display server, so it need to render the UI by itself. At that time I added an adhoc implementation for it to display a UI with a minimum implmentation.

In order to properly display an input window, there are certain features need to be supported:

  • Input window should be positioned right beside the cursor poistion.
  • Input window should not be placed out of screen.

In the wayland world, things is also very different from X. Without the knowledge of window positioning, we need to have some different way to support this.

There are current multiple approaches being used with in Fcitx:

  • With zwp_input_method, the wayland protocol, it has support to declare a surface to be input panel window, and compositor will position it properly. Unfortunately, this requires client to use wayland and text-input protocol, which is not yet well supported by the clients.
  • Or, with im module, send over a relative coordinates and ask composition to position the window with this “relative” coordinates instead of traditional absolute ones. This is used by gnome wayland + kimpanel extension. Luckily, gnome-shell extension runs within compositor, which means it has all information about the windows, e.g. which window currently has focus, window position. It can also to freely move the window created by extension. But this won’t scale anyway, because it’s unlikely to make all the compositors to support the same thing.
  • Then we can still ask client to render the window, just like fcitx-fbterm. This is an intrusive way for the application, so I never tried this approach before. Just FYI, this approach is being used by many other systems, for example, Windows, So it is not an rare solution. I also heard that uim is using such approach. But it also has its downside: duplication of code for rendering, inconsistency between toolkits, only support Gtk/Qt, more likely to have problem for certain weird application.

There is no silver bullet to this problem, but I always want to help our users to type text more freely, regardless of which desktop they want to use.

So free free to give it a try, you’ll need git from fcitx5 / fcitx5-gtk / fcitx5-qt. So far I tested many applications, including libreoffce, firefox that I suspect may have problem, but so far it looks good.

There still some limitation in this implementation:

  1. Gtk 3 doesn’t support xdg popup reposition, while this is not yet supported by a lot of compositor, Gtk 4 workaround this automatically by show and hide the window. But if I use such workaround manually in Gtk 3, it will cause the window flicker (Similar code in Qt won’t, which is really weird. My guess is this is related to frame alignment or sth.).
  2. Qt doesn’t expose all the possible interface for xdg popup, which means the position can’t use the slide / flip parameter like Gtk to ensure it is within the screen. So I took another approach here: ensure the popup window always within the range of original window. This doesn’t work well for tiny window like krunner, but I have no other good solution for it. Qt 6’s wayland is able to get the native interface for xdg popup, so it might be possible to do some manual coding there.
This entry was posted in fcitx development and tagged , , , . Bookmark the permalink.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.