GTK’s support for loadable modules dates back to the beginning of time, which is why GTK has a lot of code to deal with GTypeModules and with search paths, etc. Much later on, Alex revisited this topic for GVfs, and came up with the concept of extension points and GIO modules, which implement them. This is a much nicer framework, and GTK 4 is the perfect opportunity for us to switch to using it.
Changes in GTK+ 4
Therefore, I’ve recently spent some time on the module support in GTK. The major changes here are the following:
- We no longer support general-purpose loadable modules. One of the few remaining users of this facility is libcanberra, and we will look at implementing ‘event sound’ functionality directly in GTK+ instead of relying on a module for it. If you rely on loading GTK+ modules, please come and talk to us about other ways to achieve what you are doing.
- Print backends are now defined using an extension point named “gtk-print-backend”, which requires the type GtkPrintBackend. The existing print backends have been converted to GIO modules implementing this extension point. Since we have never supported out-of-tree print backends, this should not affect anybody else.
- Input methods are also defined using an extension point, named “gtk-im-module”, which requires the GtkIMContext type. We have dropped all the non-platform IM modules, and moved the platform IM modules into GTK+ proper, while also implementing the extension point.
Adapting existing input methods
Since we still support out-of-tree IM modules, I want to use the rest of this post to give a quick sketch of how an out-of-tree IM module for GTK+ 4 has to look.
There are a few steps to convert a traditional GTypeModule-based IM module to the new extension point. The example code below is taken from the Broadway input method.
Use G_DEFINE_DYNAMIC_TYPE
We are going to load a type from a module, and G_DEFINE_DYNAMIC_TYPE is the proper way to define such types:
G_DEFINE_DYNAMIC_TYPE (GtkIMContextBroadway, gtk_im_context_broadway, GTK_TYPE_IM_CONTEXT)
Note that this macro defines a gtk_im_context_broadway_register_type() function, which we will use in the next step.
Note that dynamic types are expected to have a class_finalize function in addition to the more common class_init, which can be trivial:
static void gtk_im_context_broadway_class_finalize (GtkIMContextBroadwayClass *class) { }
Implement the GIO module API
In order to be usable as a GIOModule, a module must implement three functions: g_io_module_load(), g_io_module_unload() and g_io_module_query() (strictly speaking, the last one is optional, but we’ll implement it here anyway).
void g_io_module_load (GIOModule *module) { g_type_module_use (G_TYPE_MODULE (module)); gtk_im_context_broadway_register_type (G_TYPE_MODULE (module)); g_io_extension_point_implement (GTK_IM_MODULE_EXTENSION_POINT_NAME, GTK_TYPE_IM_CONTEXT_BROADWAY, "broadway", 10); }
void g_io_module_unload (GIOModule *module) { }
char ** g_io_module_query (void) { char *eps[] = { GTK_IM_MODULE_EXTENSION_POINT_NAME, NULL }; return g_strdupv (eps); }
Install your module properly
GTK+ will still look in $LIBDIR/gtk-4.0/immodules/ for input methods to load, but GIO only looks at shared objects whose name starts with “lib”, so make sure you follow that convention.
Debugging
And thats it!
Now GTK+ 4 should load your input method, and if you run a GTK+ 4 application with GTK_DEBUG=modules, you should see your module show up in the debug output.
Just to be sure, am I correct in understanding that this change impacts the input method frameworks (i.e things like ibus or fcitx), not the input method engines? (e.g things like ibus-cangjie or fcitx-libpinyin)
It affects how GTK+ loads input method modules. If you install something into /usr/lib/gtk-3.0/immodules/, then you need to make changes when it comes to /usr/lib/gtk-4.0/immodules/