{"id":2498,"date":"2021-01-26T11:29:40","date_gmt":"2021-01-26T03:29:40","guid":{"rendered":"https:\/\/www.csslayer.info\/wordpress\/?p=2498"},"modified":"2021-01-27T09:57:07","modified_gmt":"2021-01-27T01:57:07","slug":"client-side-input-panel-for-fcitx-5","status":"publish","type":"post","link":"https:\/\/www.csslayer.info\/wordpress\/fcitx-dev\/client-side-input-panel-for-fcitx-5\/","title":{"rendered":"Client Side Input panel for Fcitx 5"},"content":{"rendered":"\n<p>\uff08English version is at the end of this post.)<\/p>\n\n\n\n<p>\u8f93\u5165\u6846\u7684\u5b9a\u4f4d\u76f8\u5173\u7684\u95ee\u9898\u5176\u5b9e\u5f88\u590d\u6742\uff0c\u8fc7\u53bb Fcitx \u603b\u662f\u81ea\u5df1\u7ed8\u5236\u76f8\u5173\u7684\u7a97\u53e3\u3002X11 \u8fd9\u4e2a\u529e\u6cd5\u8fd8\u597d\u4f7f\uff0c\u4f46\u662f\u5176\u4ed6\u60c5\u51b5\u53ef\u80fd\u5c31\u6ca1\u8fd9\u4e48\u597d\u4f7f\u4e86\u3002\u8ba9\u5ba2\u6237\u7aef\u7ed8\u5236\u7a97\u53e3\u7684\u60f3\u6cd5\u5176\u5b9e\u6bd4 Fcitx 5 \u8981\u65e9\u5f97\u591a\uff0c\u6700\u65e9\u662f\u4e3a\u4e86 fbterm \u800c\u589e\u52a0\u7684\u652f\u6301\u3002<\/p>\n\n\n\n<p>\u663e\u7136 fbterm \u6ca1\u6cd5\u5229\u7528\u4efb\u4f55\u6765\u81ea\u663e\u793a\u7ba1\u7406\u5668\u7684\u754c\u9762\uff0c\u6240\u4ee5\u5b83\u9700\u8981\u81ea\u5df1\u7ed8\u5236\u5b83\u81ea\u5df1\u7684\u754c\u9762\u3002\u90a3\u4f1a\u513f\u6211\u6dfb\u52a0\u4e86\u4e00\u4e2a\u5f88\u7b80\u5355\u7684\u5b9e\u73b0\u6765\u652f\u6301\u8fd9\u4e2a\u529f\u80fd\u3002<\/p>\n\n\n\n<p>\u4e3a\u4e86\u6b63\u786e\u663e\u793a\u754c\u9762\u9700\u8981\u652f\u6301\u4ee5\u4e0b\u529f\u80fd\uff1a<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>\u7a97\u53e3\u663e\u793a\u5728\u5149\u6807\u7684\u4f4d\u7f6e<\/li><li>\u7a97\u53e3\u4e0d\u80fd\u79fb\u51fa\u5c4f\u5e55<\/li><\/ul>\n\n\n\n<p>\u5728 wayland \u91cc\uff0c\u548c X \u6700\u5927\u7684\u533a\u522b\u5c31\u662f\u4e0d\u77e5\u9053\u7a97\u53e3\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u4e0d\u5f97\u4e0d\u4f7f\u7528\u7279\u522b\u7684\u65b9\u6cd5\u6765\u652f\u6301\u3002<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>\u7528 wayland \u7684\u8f93\u5165\u6cd5\u534f\u8bae\u7684\u8bdd\uff0c\u5b83\u786e\u5b9e\u662f\u652f\u6301\u5c06\u67d0\u4e2a\u7a97\u53e3\u6807\u8bb0\u4e3a\u8f93\u5165\u6cd5\u7a97\u53e3\u5e76\u8ba9\u6df7\u6210\u5668\u5e2e\u4f60\u8fdb\u884c\u5b9a\u4f4d\uff0c\u4f46\u662f\u9700\u8981\u7a0b\u5e8f\u81ea\u5df1\u5148\u4f7f\u7528 wayland \u7684\u8f93\u5165\u6cd5\u534f\u8bae\uff0c\u6df7\u6210\u5668\u4e5f\u8981\u652f\u6301\u8fd9\u4e2a\u534f\u8bae\u3002\u76ee\u524d\u8fd9\u4e24\u90e8\u5206\u7684\u652f\u6301\u5e76\u4e0d\u597d\u3002<\/li><li>\u6216\u8005\u8ba9\u7a97\u53e3\u4f20\u9001\u4e00\u4e2a\u76f8\u5bf9\u5750\u6807\uff0c\u7136\u540e\u8ba9\u6df7\u6210\u5668\u5e2e\u5fd9\u79fb\u52a8\u7a97\u53e3\u3002gnome wayland + kimpanel \u7684\u6269\u5c55\u5c31\u662f\u8fd9\u6837\u8fdb\u884c\u5b9a\u4f4d\u7684\uff0c\u56e0\u4e3a kimpanel \u6269\u5c55\u6b63\u597d\u662f\u8fd0\u884c\u5728\u6df7\u6210\u5668\u91cc\u9762\u6240\u4ee5\u77e5\u9053\u6240\u6709\u7684\u7a97\u53e3\u4fe1\u606f\u3002\u4f46\u662f\u8ba9\u5404\u79cd\u6df7\u6210\u5668\u90fd\u652f\u6301\u8fd9\u4e2a\u4e5f\u4e0d\u592a\u73b0\u5b9e\u3002<\/li><li>\u7136\u540e\u5c31\u662f\u672c\u6b21\u8bf4\u5230\u7684\u65b9\u5f0f\uff0c\u8ba9\u7a0b\u5e8f\u81ea\u5df1\u7ed8\u5236\u754c\u9762\u3002\u5f53\u7136\uff0c\u7f3a\u70b9\u5c31\u662f\u5b9e\u73b0\u901a\u8fc7 im module \u7684\u8bdd\uff0c\u5c31\u53ea\u80fd\u652f\u6301 Gtk \/ Qt \u7684\u7a0b\u5e8f\uff0c\u4f46\u76f8\u5bf9\u6765\u8bf4\u53ef\u4ee5\u8986\u76d6\u5927\u90e8\u5206\u7684\u7a0b\u5e8f\u4e86\u3002\u6211\u4e2a\u4eba\u5bf9\u4e8e\u8fd9\u4e2a\u65b9\u6cd5\u6bd4\u8f83\u53cd\u611f\uff0c\u56e0\u4e3a\u611f\u89c9\u53ef\u80fd\u51fa\u95ee\u9898\u7684\u5730\u65b9\u5f88\u591a\uff0c\u5bf9\u4e8e\u7a0b\u5e8f\u6765\u8bf4\u6dfb\u52a0\u4e00\u4e2a\u989d\u5916\u7a97\u53e3\u548c\u8fc7\u53bb\u7684 im module \u76f8\u6bd4\u6709\u4e86\u66f4\u5f3a\u7684\u4fb5\u5165\u6027\u3002\u4e0d\u8fc7\u5728\u5176\u4ed6\u5f88\u591a\u7cfb\u7edf\u4e0a\uff0c\u4f8b\u5982 windows \u548c uim \u53ef\u80fd\u90fd\u4f7f\u7528\u4e86\u8fd9\u4e2a\u65b9\u5f0f\u3002<\/li><\/ul>\n\n\n\n<p>\u4e0d\u8fc7\u76f8\u6bd4\u53ea\u662f\u56e0\u4e3a\u62c5\u5fc3\u5c31\u4e0d\u91c7\u53d6\u884c\u52a8\u7684\u8bdd\uff0c\u8fd8\u4e0d\u5982\u5148\u8bd5\u4e00\u8bd5\uff0c\u6bd5\u7adf\u89e3\u51b3\u5b9e\u9645\u5b58\u5728\u7684\u95ee\u9898\u7684\u610f\u4e49\u66f4\u52a0\u91cd\u5927\u3002\u60f3\u8981\u6d4b\u8bd5\u7684\u8bdd\u9700\u8981\u4f7f\u7528 fcitx5 \/ fcitx5-qt \/ fcitx5-gtk \u7684 git\u4ee3\u7801\u3002<\/p>\n\n\n\n<p>\u76ee\u524d\u8fd8\u6709\u4e00\u4e9b\u5b9e\u73b0\u7684\u9650\u5236\uff1a<\/p>\n\n\n\n<p>Gtk 3 \u4e0d\u652f\u6301\u5df2\u7ecf\u5b9e\u73b0\u7684\u7a97\u53e3\u91cd\u65b0\u79fb\u52a8\u4f4d\u7f6e\uff0cGtk 4 \u5bf9\u4e8e\u4e0d\u652f\u6301\u8f83\u65b0\u7684 xdg popup positioner \u7684\u6df7\u6210\u5668\u7684\u662f\u91c7\u7528\u9690\u85cf\u518d\u663e\u793a\u7a97\u53e3\u7684\u65b9\u5f0f\uff0c\u800c\u8fd9\u4e2a\u65b9\u5f0f\u4f1a\u5bfc\u81f4\u7a97\u53e3\u95ea\u70c1\uff08Qt \u7528\u540c\u6837\u7684 hack \u5c31\u4e0d\u4f1a\uff0c\u6211\u731c\u6d4b\u662f Gtk \u6709\u548c\u5237\u65b0\u7387\u5bf9\u9f50\u4e4b\u7c7b\u7684\u64cd\u4f5c\uff1f\uff09\u3002\u6240\u4ee5\u6211\u5e72\u8106\u5c31\u6ca1\u5728 Gtk 3 \u7528\u8fd9\u4e2a hack\uff0c\u6bd5\u7adf\u95ea\u70c1\u8d77\u6765\u770b\u7740\u66f4\u7cdf\u4e00\u70b9\u2026<\/p>\n\n\n\n<p>Qt \u7684\u8bdd\u51fa\u4e8e\u6ca1\u6709\u66b4\u9732 xdg positioner api \u7684\u9650\u5236\uff0c\u5728\u7a97\u53e3\u5b9a\u4f4d\u65b9\u9762\u5e76\u4e0d\u80fd\u4fdd\u8bc1\u4e0d\u79fb\u51fa\u5c4f\u5e55\uff0c\u56e0\u6b64\u6211\u91c7\u53d6\u4e86\u53e6\u4e00\u4e2a\u65b9\u5f0f\uff1a\u4fdd\u8bc1\u8f93\u5165\u6846\u603b\u662f\u5728\u7a97\u53e3\u8303\u56f4\u5185\u3002\u8fd9\u4e2a\u5bf9\u4e8e\u5c0f\u7a97\u53e3\u5e76\u4e0d\u662f\u7279\u522b\u53cb\u597d\uff0c\u4f8b\u5982 krunner\uff0c\u4e0d\u8fc7\u6211\u4e5f\u6ca1\u6709\u66f4\u597d\u7684\u529e\u6cd5\u4e86\u3002<\/p>\n\n\n\n<p>\u672c\u6587\u5c31\u662f\u7528 firefox + wayland \u8f93\u5165\u7684\uff0c\u6574\u4f53\u6765\u8bf4\u8fd8\u884c\u2026\u2026Gtk 3 \u5b9a\u4f4d\u5ef6\u8fdf\u867d\u7136\u6709\u70b9\u96be\u53d7\u4e0d\u8fc7\u53cd\u6b63\u6211\u4e5f\u6ca1\u66f4\u597d\u529e\u6cd5\u5566\u3002<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>In order to properly display an input window, there are certain features need to be supported:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>Input window should be positioned right beside the cursor poistion.<\/li><li>Input window should not be placed out of screen.<\/li><\/ul>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>There are current multiple approaches being used with in Fcitx:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>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.<\/li><li>Or, with im module, send over a relative coordinates and ask composition to position the window with this &#8220;relative&#8221; 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&#8217;t scale anyway, because it&#8217;s unlikely to make all the compositors to support the same thing.<\/li><li>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 <a href=\"https:\/\/github.com\/uim\/uim\/\" data-type=\"URL\" data-id=\"https:\/\/github.com\/uim\/uim\/\">uim<\/a> 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.<\/li><\/ul>\n\n\n\n<p>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.<\/p>\n\n\n\n<p>So free free to give it a try, you&#8217;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.<\/p>\n\n\n\n<p>There still some limitation in this implementation:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li>Gtk 3 doesn&#8217;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&#8217;t, which is really weird. My guess is this is related to frame alignment or sth.).<\/li><li>Qt doesn&#8217;t expose all the possible interface for xdg popup, which means the position can&#8217;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&#8217;t work well for tiny window like krunner, but I have no other good solution for it. Qt 6&#8217;s wayland is able to get the native interface for xdg popup, so it might be possible to do some manual coding there.<\/li><\/ol>\n","protected":false},"excerpt":{"rendered":"<p>\uff08English version is at the end of this post.) \u8f93\u5165\u6846\u7684\u5b9a\u4f4d\u76f8\u5173\u7684\u95ee\u9898\u5176\u5b9e\u5f88\u590d\u6742\uff0c\u8fc7\u53bb Fcitx \u603b\u662f\u81ea\u5df1\u7ed8\u5236\u76f8\u5173\u7684\u7a97\u53e3\u3002X11 \u8fd9\u4e2a\u529e\u6cd5\u8fd8\u597d\u4f7f\uff0c\u4f46\u662f\u5176\u4ed6\u60c5\u51b5\u53ef\u80fd\u5c31\u6ca1\u8fd9\u4e48\u597d\u4f7f\u4e86\u3002\u8ba9\u5ba2\u6237\u7aef\u7ed8\u5236\u7a97\u53e3\u7684\u60f3\u6cd5\u5176\u5b9e\u6bd4 Fcitx 5 \u8981\u65e9\u5f97\u591a\uff0c\u6700\u65e9\u662f\u4e3a\u4e86 fbterm \u800c\u589e\u52a0\u7684\u652f\u6301\u3002 \u663e\u7136 fbterm \u6ca1\u6cd5\u5229\u7528\u4efb\u4f55\u6765\u81ea\u663e\u793a\u7ba1\u7406\u5668\u7684\u754c\u9762\uff0c\u6240\u4ee5\u5b83\u9700\u8981\u81ea\u5df1\u7ed8\u5236\u5b83\u81ea\u5df1\u7684\u754c\u9762\u3002\u90a3\u4f1a\u513f\u6211\u6dfb\u52a0\u4e86\u4e00\u4e2a\u5f88\u7b80\u5355\u7684\u5b9e\u73b0\u6765\u652f\u6301\u8fd9\u4e2a\u529f\u80fd\u3002 \u4e3a\u4e86\u6b63\u786e\u663e\u793a\u754c\u9762\u9700\u8981\u652f\u6301\u4ee5\u4e0b\u529f\u80fd\uff1a \u7a97\u53e3\u663e\u793a\u5728\u5149\u6807\u7684\u4f4d\u7f6e \u7a97\u53e3\u4e0d\u80fd\u79fb\u51fa\u5c4f\u5e55 \u5728 wayland \u91cc\uff0c\u548c X \u6700\u5927\u7684\u533a\u522b\u5c31\u662f\u4e0d\u77e5\u9053\u7a97\u53e3\u7684\u4f4d\u7f6e\uff0c\u6240\u4ee5\u4e0d\u5f97\u4e0d\u4f7f\u7528\u7279\u522b\u7684\u65b9\u6cd5\u6765\u652f\u6301\u3002 \u7528 wayland \u7684\u8f93\u5165\u6cd5\u534f\u8bae\u7684\u8bdd\uff0c\u5b83\u786e\u5b9e\u662f\u652f\u6301\u5c06\u67d0\u4e2a\u7a97\u53e3\u6807\u8bb0\u4e3a\u8f93\u5165\u6cd5\u7a97\u53e3\u5e76\u8ba9\u6df7\u6210\u5668\u5e2e\u4f60\u8fdb\u884c\u5b9a\u4f4d\uff0c\u4f46\u662f\u9700\u8981\u7a0b\u5e8f\u81ea\u5df1\u5148\u4f7f\u7528 wayland \u7684\u8f93\u5165\u6cd5\u534f\u8bae\uff0c\u6df7\u6210\u5668\u4e5f\u8981\u652f\u6301\u8fd9\u4e2a\u534f\u8bae\u3002\u76ee\u524d\u8fd9\u4e24\u90e8\u5206\u7684\u652f\u6301\u5e76\u4e0d\u597d\u3002 \u6216\u8005\u8ba9\u7a97\u53e3\u4f20\u9001\u4e00\u4e2a\u76f8\u5bf9\u5750\u6807\uff0c\u7136\u540e\u8ba9\u6df7\u6210\u5668\u5e2e\u5fd9\u79fb\u52a8\u7a97\u53e3\u3002gnome wayland + kimpanel \u7684\u6269\u5c55\u5c31\u662f\u8fd9\u6837\u8fdb\u884c\u5b9a\u4f4d\u7684\uff0c\u56e0\u4e3a kimpanel &hellip; <a href=\"https:\/\/www.csslayer.info\/wordpress\/fcitx-dev\/client-side-input-panel-for-fcitx-5\/\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[44],"tags":[12,248,80,43],"class_list":["post-2498","post","type-post","status-publish","format-standard","hentry","category-fcitx-dev","tag-fcitx","tag-fcitx5","tag-gtk","tag-qt"],"_links":{"self":[{"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/posts\/2498","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/comments?post=2498"}],"version-history":[{"count":3,"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/posts\/2498\/revisions"}],"predecessor-version":[{"id":2502,"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/posts\/2498\/revisions\/2502"}],"wp:attachment":[{"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/media?parent=2498"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/categories?post=2498"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.csslayer.info\/wordpress\/wp-json\/wp\/v2\/tags?post=2498"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}