video/out/x11_common: make IME work (for libmpv usage)

The implementation is minimal since it already uses XIM for UTF-8 text
input. The only changes needed are small fixes: setting the IC focus and
correct the usage of window param for XFilterEvent, and IME will
"just work"...

...after setting 2 process-wide global values before VO creation:
LC_CTYPE and X locale modifiers. So this usage is currently limited to
libmpv clients which don't want to do their own IME processing.

locale strikes once again:
XIM input methods require them to be set before creating the XIM context to
work, even though they don't matter after the context is created. Both of
these values being process-wide global means that the only time to safely
set these values is before the process creates any thread.

In theory, mpv could set LC_CTYPE in the main when running standalone,
but locale being locale means something is always messed up. In this case,
setting LC_CTYPE changes "Character classification and case conversion"
behavior. While mpv uses its own ASCII-only is*() and to*() functions to
avoid some of the issues, it also uses strcasecmp() and POSIX regex which
behaviors are affected by LC_CTYPE.

In summary, to avoid unavoidable race conditions mpv won't do this in
standalone mode right now.
It's now libmpv users' responsibility to:

- set LC_CTYPE to a locale usable for XIM, such as a UTF-8 locale
- set X locale modifiers with XSetLocaleModifiers
- hope that all stars align if trying to switch locale back afterwards

On most setups, both of these can be empty strings, In this case, the usual
XMODIFIERS environment variable must be set to enable IME support.
(e.g. XMODIFIERS=@im=fcitx)
This commit is contained in:
nanahi 2024-09-02 15:57:50 -04:00 committed by Kacper Michajłow
parent baabc291f1
commit 4ab1ab8284
1 changed files with 3 additions and 1 deletions

View File

@ -1256,7 +1256,7 @@ void vo_x11_check_events(struct vo *vo)
while (XPending(display)) { while (XPending(display)) {
XNextEvent(display, &Event); XNextEvent(display, &Event);
if (XFilterEvent(&Event, x11->window)) if (XFilterEvent(&Event, None))
continue; continue;
MP_TRACE(x11, "XEvent: %d\n", Event.type); MP_TRACE(x11, "XEvent: %d\n", Event.type);
switch (Event.type) { switch (Event.type) {
@ -1646,6 +1646,8 @@ static void vo_x11_create_window(struct vo *vo, XVisualInfo *vis,
XNClientWindow, x11->window, XNClientWindow, x11->window,
XNFocusWindow, x11->window, XNFocusWindow, x11->window,
NULL); NULL);
if (x11->xic)
XSetICFocus(x11->xic);
} }
if (!x11->parent) { if (!x11->parent) {