Skip to content

Experimental IBus support for X11 backend built on top of the IME API#10

Draft
ashie wants to merge 12 commits into
im-supportfrom
im-support-ibus
Draft

Experimental IBus support for X11 backend built on top of the IME API#10
ashie wants to merge 12 commits into
im-supportfrom
im-support-ibus

Conversation

@ashie

@ashie ashie commented Jun 20, 2026

Copy link
Copy Markdown
Member

This PR is an experiment built on top of the IME API introduced by PR #2130: Add IME support for each platform.

One motivation for this work is that the traditional X11 XIM protocol is relatively limited compared to modern IME frameworks and can make it difficult to provide functionality comparable to IME implementations available on other platforms.

While XIM remains useful as a baseline solution, as GLFW's IME support evolves, it may be desirable to investigate alternatives that can expose richer IME functionality on X11.

The goal of this experiment is therefore not to propose IBus support for GLFW itself, but to evaluate whether the abstractions introduced by PR glfw#2130 are flexible enough to support an alternative X11 IME backend without modifying the GLFW event loop.

The prototype uses:

  • a dynamically loaded IME module
  • a dedicated D-Bus worker thread
  • IBus input contexts

and currently supports:

  • preedit
  • commit
  • candidate window positioning

on X11.

This implementation should be viewed as a research prototype rather than an upstream proposal.

See docs/ime-ibus-prototype.md for architecture details, design rationale, limitations and future work.

Additional prerequisites

  • Dev package of DBus
  • IBus or Fcitx5 via its IBus compatibility frontend (untested)

Build:

$ cmake -B build
$ cmake --build build --target glfw glfw-ibus

Run demo:

$ GLFW_IM_MODULE=$PWD/build/src/glfw-ibus.so ./build/tests/input_text

@ashie ashie changed the title Im support ibus Experimental IBus support for X11 backend built on top of the IME API Jun 20, 2026
@ashie ashie force-pushed the im-support-ibus branch from c1d8b43 to fcb9c12 Compare June 20, 2026 08:00
ashie added 12 commits June 21, 2026 17:02
Introduce glfwSetTextInputFocus(window, focused), internal state and a
platform hook for explicit application text input focus.

Track whether the application has explicitly called the API with
textInputFocusExplicit, so existing applications keep legacy platform
behavior until they opt into explicit text input focus.

This follows the text input focus direction from the IME support
discussions in #5 and #7, without changing
platform behavior yet.
Map explicit text input focus to XIM input context focus with XSetICFocus
and XUnsetICFocus.

On focus out, reset preedit through the existing X11 helper before
unsetting IC focus, preserving its conservative behavior.  Native FocusIn
only restores XIC focus when text input focus has not been explicitly
disabled.
When explicit text input focus is inactive, keep GLFW from processing its
own WM_IME_* composition, preedit, candidate and IME status paths while
preserving normal key input.

On Win32, gating GLFW message handling is not enough to prevent native IMM
candidate UI from appearing. Temporarily associate a NULL HIMC with the
window while explicit text input focus is out, then restore the saved HIMC
when focus returns.

Cancel and clear active preedit/candidate state as focus-out cleanup. After
restoring the HIMC, reapply the preedit cursor rectangle so candidate UI
uses the latest location.
When explicit text input focus is inactive, skip interpretKeyEvents and
send plain event characters through GLFW text input instead. This
prevents routing key events through NSTextInput composition while
preserving normal key input.

Applications that never call glfwSetTextInputFocus keep the previous
interpretKeyEvents behavior.

On focus out, discard marked text through the existing NSTextInputContext
reset path. Do not use TIS input source switching for this API.
Map explicit text input focus to text-input-v3 enable/disable and
text-input-v1 activate/deactivate.

When text input focus is inactive, avoid auto-enabling text input on
protocol enter and ignore stale text-input callbacks.  Applications
that never call glfwSetTextInputFocus keep the previous enter-time
activation behavior.

On focus out, reset local preedit state and send the available protocol
reset/disable requests.
Expose glfwSetTextInputFocus in the input_text test so IME and text input
focus behavior can be exercised independently.

The UI starts in compatibility mode, then shows explicit Focus In or
Focus Out after the toggle is used.
This adds a dynamically loaded X11 IME module ABI and an experimental
glfw-ibus.so backend for feasibility testing only. The module owns
D-Bus and worker-thread communication, while GLFW drains queued IME
events on the main thread without modifying the event loop architecture.

The prototype includes preedit and commit handling, cursor location
updates for IBus SetCursorLocation, the first-candidate-window positioning
workaround, GLFW_IME_DEBUG instrumentation, and documentation of the
architecture and known timeout risks.
Keep XFilterEvent as the suppressor for the XIM path, but do not
call it before the experimental IME module sees KeyPress events.

When the module reports a key as handled, return before normal GLFW
key and character processing. This gives the IME module path the same
kind of duplicate-input suppression that XFilterEvent provides for the
XIM path, while keeping the XIM behavior unchanged.

This effectively extends the duplicate-input suppression addressed by
PR glfw#1972 to the experimental IME module path.
Map glfwSetTextInputFocus to the experimental X11 IME module path.

When text input focus is enabled for a focused X11 window, send FocusIn to
the module so IBus resumes routing text input. When it is disabled, reset
composition and send FocusOut, keeping GLFW window focus separate from the
text input focus abstraction.

Also gate the module KeyPress path on GLFW's text input focus state so
FocusOut actually stops routing input through IBus. Applications that never
opt into explicit text input focus keep the legacy behavior.

Document the prototype mapping without adding a new module ABI entry.
Parse IBus UpdatePreeditText cursor position, visibility and text
attributes in the experimental X11 IME module.

The module now converts IBus attribute ranges into GLFW preedit block
sizes, picks a focused block from highlighted attributes or the caret, and
passes the caret index through to the GLFW main-thread preedit update.
This keeps D-Bus and IBus details inside the module while allowing
applications to draw richer preedit state.

Bump the experimental module ABI because the host preedit callback now
carries block metadata.
Document the current state of the experimental X11 IBus module after
adding text input focus gating and richer preedit handling.

The prototype now maps IBus caret and attribute ranges to GLFW preedit
state, gates ProcessKeyEvent on explicit text input focus, and is close to
usable for application testing while still remaining experimental.
Add two switches for game/application compatibility testing.

GLFW_IME_MODE_AS_TEXT_INPUT_FOCUS makes GLFW_IME control GLFW's text input
focus path by default, and also acts as the runtime override environment
variable. This lets applications that already toggle GLFW_IME use the more
portable text-input-focus semantics without code changes.

glfwGetInputMode(GLFW_IME) keeps reporting the native IME status until
text input focus has been explicitly set for the window, preserving the
old query behavior for applications that never use the compatibility mode.

GLFW_EMBED_IBUS_MODULE builds the IBus backend into the X11 GLFW library.
The embedded backend is used when GLFW_IM_MODULE is not set, while
GLFW_IM_MODULE can still override it with an external module.
@ashie ashie force-pushed the im-support-ibus branch from fcb9c12 to 536fbb4 Compare June 24, 2026 08:11
@ashie

ashie commented Jun 24, 2026

Copy link
Copy Markdown
Member Author

New experimental build switches

I've added two more optional build switches for experiments with applications that already use GLFW with glfw#2130.

These options are not intended as an upstream API proposal. They are provided to make it easier to evaluate the IBus backend with existing applications and prebuilt GLFW binaries.

GLFW_IME_MODE_AS_TEXT_INPUT_FOCUS

When this CMake option is enabled, glfwSetInputMode(window, GLFW_IME, value) is routed through GLFW's text input focus path (glfwSetTextInputFocus() API propsed at glfw#2130 (comment)) instead of the native platform IME open/close state.

This is useful for applications that already toggle GLFW_IME, but really want to express whether text input should currently be focused. The runtime environment variable GLFW_IME_MODE_AS_TEXT_INPUT_FOCUS can also be used to enable or disable this behavior without rebuilding GLFW.

$ GLFW_IME_MODE_AS_TEXT_INPUT_FOCUS=1 ./application

GLFW_EMBED_IBUS_MODULE

When this CMake option is enabled, the IBus backend is built into the X11 GLFW library instead of requiring glfw-ibus.so to be loaded with GLFW_IM_MODULE.
This removes the need to ask end users to set GLFW_IM_MODULE when testing a prebuilt GLFW build with IBus support. If GLFW_IM_MODULE is still set, the external module takes precedence over the embedded backend.


Example build:

$ cmake -B build \
    -D GLFW_EMBED_IBUS_MODULE=ON \
    -D GLFW_IME_MODE_AS_TEXT_INPUT_FOCUS=ON
$ cmake --build build --target glfw

With these options enabled, applications can test the IBus path without setting GLFW_IM_MODULE:

$ ./build/tests/input_text

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant