compose: one Compose table for the XIM and IBus frontends

An IBus client throws away a dead key its engine did not take — the GTK
module's own comment says so, and Qt does the same — so é and ü were
lost in every IBus application, while XIM composed them with a table of
its own.  That table moves to compose.c, which both frontends now use;
xim.c is the shorter for it.

A finished sequence is text, not a key: the engine is asked to hand back
what it had pending, and the composed text follows it, so the composed
character can no longer land before the syllable typed before it.
This commit is contained in:
2026-08-17 12:16:07 +09:00
parent a0e83f98c6
commit ef7fb627c6
13 changed files with 149 additions and 64 deletions

27
ibus.c
View File

@@ -531,13 +531,21 @@ dropconncontexts(DBusConnection *conn)
* focus events of two applications can cross.
*/
static int
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
processkey(Ictx *ctx, u32int sym, u32int state, char *text, int n, Keyres *res)
{
text[0] = '\0';
if(state & Relmask || hidden(ctx))
return 0;
ctx->focused = 1;
sendrequest(ctx, Keypress, ipckeysym(sym, xkb_keysym_to_utf32(sym)),
ipcmod(state), res);
/* An IBus client drops a dead key we do not take: compose it here. */
if(composekey(sym, text, n))
return -1;
if(text[0] != '\0')
/* Composed text follows whatever was pending. */
sendrequest(ctx, Keyreset, 0, 0, res);
else
sendrequest(ctx, Keypress, ipckeysym(sym, xkb_keysym_to_utf32(sym)),
ipcmod(state), res);
if(preowner != nil && preowner != ctx)
checkpreowner();
return 1;
@@ -641,14 +649,15 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{
dbus_uint32_t sym, code, state;
Keyres res;
char commit[Maxutf], preedit[Maxutf];
int restart;
char commit[Maxutf], preedit[Maxutf], text[Maxutf];
int restart, rv;
dbus_message_get_args(m, nil, DBUS_TYPE_UINT32, &sym,
DBUS_TYPE_UINT32, &code, DBUS_TYPE_UINT32, &state,
DBUS_TYPE_INVALID);
if(!processkey(ctx, sym, state, &res))
return replybool(c, m, 0);
rv = processkey(ctx, sym, state, text, sizeof text, &res);
if(rv <= 0) /* below zero: a sequence in the making */
return replybool(c, m, rv < 0);
stoutf(&res.commit, commit, sizeof commit);
stoutf(&res.preedit, preedit, sizeof preedit);
/* A commit ends the preedit around it, so clients place it right. */
@@ -658,10 +667,12 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
emitpreedit(ctx, "");
if(commit[0] != '\0')
emitcommit(ctx, commit);
if(text[0] != '\0')
emitcommit(ctx, text);
if(clientpreedit(ctx) && (!restart || preedit[0] != '\0'))
emitpreedit(ctx, preedit);
ctx->keying = 0;
return replybool(c, m, res.eaten);
return replybool(c, m, res.eaten || text[0] != '\0');
}
/* Properties.Get PostProcessKeyEvent: what the last key produced. */