|
| 1 | +# Input Methods in GTK |
| 2 | + |
| 3 | +This document describes how Keyman is connected to a client app, in other words |
| 4 | +how a keypress in the app ends up being processed by the Keyman engine. |
| 5 | + |
| 6 | +For text input, GTK (or rather the app) will add input method support to a widget. |
| 7 | +How the input method gets loaded depends on the GTK version. |
| 8 | + |
| 9 | +IBus provides input modules for GTK 2, GTK 3, GTK 4, X11, and Wayland. |
| 10 | +However, the Wayland one is not used with Gnome because GTK provides |
| 11 | +its own implementation. |
| 12 | + |
| 13 | +Which input modules are available depends on the GTK version. Apps that |
| 14 | +don't use the Gnome/GTK framework use different ways for input method |
| 15 | +support. |
| 16 | + |
| 17 | +## GTK 4 |
| 18 | + |
| 19 | +```mermaid |
| 20 | +flowchart LR |
| 21 | + subgraph GTK |
| 22 | + app(application) |
| 23 | + im-module["im-module |
| 24 | + (IBusIMContext)"] |
| 25 | + app --- im-module |
| 26 | + end |
| 27 | +
|
| 28 | + subgraph ibus[ibus-daemon] |
| 29 | + direction LR |
| 30 | + IBusInputContext <--> IBusEngine |
| 31 | + end |
| 32 | +
|
| 33 | + subgraph keyman |
| 34 | + ibus-engine-keyman |
| 35 | + end |
| 36 | +
|
| 37 | + GTK <--> ibus <--> keyman |
| 38 | +
|
| 39 | + style app color:#FFFFFF, stroke:#00C853, fill:#00C853 |
| 40 | +``` |
| 41 | + |
| 42 | +The im-module implements a [GIOExtensionPoint](https://docs.gtk.org/gio/struct.IOExtensionPoint.html) |
| 43 | +"gtk-im-module". The type extends `GtkIMContext`. |
| 44 | +When loading the app, GTK dynamically loads and starts the extension |
| 45 | +specified by the environment variable `GTK_IM_MODULE` (or the default which is |
| 46 | +probably the one with the highest priority). |
| 47 | + |
| 48 | +External modules are located in `/usr/lib/x86_64-linux-gnu/gtk-4.0/4.0.0/immodules` |
| 49 | +and named `lib*.so`. |
| 50 | + |
| 51 | +Each module has a priority, a name and the type that implements it. |
| 52 | + |
| 53 | +GTK4 has built-in support for Wayland (`GtkIMContextWayland`), Broadway |
| 54 | +(`GtkIMContextBroadway`, irrelevant for Keyman) and gtk-im-context-simple |
| 55 | +(`GtkIMContextSimple`, irrelevant for Keyman). `GtkIMContextWayland` is |
| 56 | +implemented as part of GTK 4, the source code can be found in |
| 57 | +<https://github.com/GNOME/gtk/blob/main/gtk/gtkimcontextwayland.c>. |
| 58 | + |
| 59 | +The input method for ibus is implemented as an external module |
| 60 | +(type `IBusIMContext`). Source code is in |
| 61 | +<https://github.com/ibus/ibus/tree/main/client/gtk4>. |
| 62 | + |
| 63 | +The IBus communication between `IBusIMContext`, ibus-daemon and the ibus |
| 64 | +engine (aka Keyman) happens with DBus messages on a separate IBus DBus |
| 65 | +instance. |
| 66 | + |
| 67 | +## GTK 2/GTK 3 |
| 68 | + |
| 69 | +With older GTK versions basically the same components are involved, |
| 70 | +although a different mechanism to discover and load the |
| 71 | +im-modules is used. |
| 72 | + |
| 73 | +GTK caches the available modules in a module database located in |
| 74 | +`/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules.cache` or whereever |
| 75 | +the `GTK_IM_MODULE_FILE` environment variable points. This database is |
| 76 | +read, or if necessary initialized, on application startup. |
| 77 | + |
| 78 | +For each module the database contains an id, the name, the path, i18n domain(?) |
| 79 | +and default locales. |
| 80 | + |
| 81 | +GTK then determines what input module to load based on the `GTK_IM_MODULE` |
| 82 | +environment variable (which can contain more than one module separated by |
| 83 | +colons) or the `XSETTINGS` `gtk-im-module` property. It then checks that |
| 84 | +the currently running display type is compatible with the module, and that |
| 85 | +the current locale matches the locales supported by the module. An exact match |
| 86 | +(`en_US` vs `en_US`) gets 4 points, a match of the language (`en_US` vs `en`) |
| 87 | +gets 3 points, a match with a different region (`en_US` vs `en_UK`) 2 points, |
| 88 | +and a wildcard (`en_US` vs `*`) 1 point. |
| 89 | + |
| 90 | +Each input module implements a subclass of `GTKIMContext` plus the 4 required |
| 91 | +entry points: |
| 92 | + |
| 93 | +- `im_module_init()` - Initialize module |
| 94 | +- `im_module_list()` - Describe available contexts |
| 95 | +- `im_module_create()` - Create context instance |
| 96 | +- `im_module_exit()` - Cleanup on unload |
| 97 | + |
| 98 | +GTK uses `GModule` to dynamically load the module's `.so` file and then calls |
| 99 | +`im_module_init()` on the module, followed by `im_module_create()` to instantiate |
| 100 | +the actual `GtkIMContext` subclass. |
| 101 | + |
| 102 | +If no module matches or loading fails, GTK falls back to `GtkIMContextSimple`. |
| 103 | + |
| 104 | +GTK3 provides support for several input methods, more than with GTK4. Those |
| 105 | +can be found in <https://github.com/GNOME/gtk/tree/gtk-3-24/modules/input>. |
| 106 | +Among the built-in modules are `im-wayland` (for Wayland), `im-xim` (for X11), |
| 107 | +`im-thai` (for Thai), and `im-ime` (for Windows). |
| 108 | + |
| 109 | +The input method for ibus is implemented as an external module |
| 110 | +(type `IBusIMContext`). Source code is in |
| 111 | +<https://github.com/ibus/ibus/tree/main/client/gtk3>. |
| 112 | + |
| 113 | +All modules are located in `/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules` |
| 114 | +and named `*.so`, e.g. `im-ibus.so`. |
| 115 | + |
| 116 | +## Tips |
| 117 | + |
| 118 | +- GTK has a built-in |
| 119 | + [inspection/debugging tool](https://developer.gnome.org/documentation/tools/inspector.html) |
| 120 | + which can be opened with <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>I</kbd>, or |
| 121 | + <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>D</kbd>, or by setting the |
| 122 | + environment variable `GTK_DEBUG=interactive`. |
| 123 | +- Available GTK3 IM modules can be listed with |
| 124 | + `/usr/lib/x86_64-linux-gnu/libgtk-3-0t64/gtk-query-immodules-3.0` or by |
| 125 | + looking at `/usr/lib/x86_64-linux-gnu/gtk-3.0/3.0.0/immodules.cache`. |
| 126 | + |
| 127 | +## Links |
| 128 | + |
| 129 | +- [GTK4 Input Handling](https://docs.gtk.org/gtk4/input-handling.html) |
0 commit comments