chansrv: Fix regression from the previous commit breaking Model A entirely

The "don't reclaim a deliberately-chosen engine" guard from the last
commit had a logic bug that broke ordinary Model A composition
completely, not just the edge case it was meant to fix.

ibus_bus_set_global_engine() sets the global engine *name*
synchronously, but the actual engine instance (g_engine) is created
asynchronously afterward. During that brief window, the global engine
name is already "XrdpIme" but g_engine is still NULL - the existing
fast path (name == "XrdpIme" && g_engine != NULL) correctly falls
through in that case, same as always. But the new guard only checked
whether the current name differed from last_input_name, and "XrdpIme"
is *always* different from last_input_name by construction (that's
the name of whatever we switched away from). So every commit that
landed in that async window got misclassified as "a different engine
took over" and silently dropped. Composing even one phrase sends
several characters in quick succession, so this was most of them -
not just the intended edge case.

Fixed by checking name == "XrdpIme" first, independent of g_engine's
readiness, before ever reaching the "is this some other engine"
guard - that window means "still connecting", not "something else
took over".

Verified against the exact failure condition: sent a 9-character
phrase rapid-fire immediately after xrdp_input_unicode_init() (no
settle time), landing correctly as a single unbroken phrase with zero
drops. Also re-ran all four trigger-happy scenarios from the previous
commit, plus a new check sending 5 characters rapid-fire immediately
after a from-original reassertion - all pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Liyi Meng
2026-08-18 08:22:45 +00:00
parent 82b4eb6556
commit 55a4f81083
+30 -16
View File
@@ -196,29 +196,43 @@ xrdp_input_enable(void)
desc = ibus_bus_get_global_engine(local_bus); desc = ibus_bus_get_global_engine(local_bus);
name = desc != NULL ? ibus_engine_desc_get_name(desc) : NULL; name = desc != NULL ? ibus_engine_desc_get_name(desc) : NULL;
if (name != NULL && g_ascii_strcasecmp(name, "XrdpIme") == 0 && if (name != NULL && g_ascii_strcasecmp(name, "XrdpIme") == 0)
g_engine != NULL) {
if (g_engine != NULL)
{ {
g_object_unref(desc); g_object_unref(desc);
g_object_unref(local_bus); g_object_unref(local_bus);
return TRUE; return TRUE;
} }
/* XrdpIme is already the global engine, but ibus_bus_set_global_
/* Only reclaim XrdpIme if the current engine is either unset, or is * engine() only sets the *name* synchronously - the actual
* the original one we remembered before ever switching away from * engine instance (g_engine) is created asynchronously after.
* it (last_input_name) - that's ibus silently reverting on its * This is that brief in-flight window, NOT a case of some
* own, which is exactly the scenario this reassertion exists to * other engine having taken over, so it must not hit the
* fix. If it's some OTHER named engine, that's a deliberate user * "leave a deliberately different engine alone" guard below
* action (e.g. manually switching to a native engine like * (name == "XrdpIme" is *always* != last_input_name by
* libpinyin to compose directly in the remote session), possibly * construction, so that guard would otherwise reject every
* well before this call - forcibly reclaiming XrdpIme would yank * commit that lands in this window - which, since composing
* that away mid-use for the sake of a single, possibly stale or * even one phrase sends several characters in quick
* deferred commit (e.g. macOS auto-flushing a composition that was * succession, was most of them). Fall through and let the
* left pending after the user moved on to something else). Drop * queue/prepare-check mechanism wait for g_engine as usual. */
* this commit instead and leave the user's active choice alone. */ }
if (last_input_name != NULL && name != NULL && else if (last_input_name != NULL && name != NULL &&
g_ascii_strcasecmp(name, last_input_name) != 0) g_ascii_strcasecmp(name, last_input_name) != 0)
{ {
/* Only reclaim XrdpIme if the current engine is either unset,
* or is the original one we remembered before ever switching
* away from it (last_input_name) - that's ibus silently
* reverting on its own, which is exactly the scenario this
* reassertion exists to fix. Anything else named is a
* deliberate user action (e.g. manually switching to a native
* engine like libpinyin to compose directly in the remote
* session), possibly well before this call - forcibly
* reclaiming XrdpIme would yank that away mid-use for the sake
* of a single, possibly stale or deferred commit (e.g. macOS
* auto-flushing a composition left pending after the user
* moved on to something else). Drop this commit instead and
* leave the user's active choice alone. */
LOG(LOG_LEVEL_WARNING, LOG(LOG_LEVEL_WARNING,
"xrdp_input_enable: global engine is \"%s\", not XrdpIme or " "xrdp_input_enable: global engine is \"%s\", not XrdpIme or "
"the original \"%s\" - leaving it alone rather than " "the original \"%s\" - leaving it alone rather than "