fix(engine): a reset or a lost focus commits the pending text
Clicking elsewhere, changing focus, or any client reset dropped the composition in the GTK module and IBus (only XIM ResetIC handed it back), so typing 안녕 and clicking Send lost 녕. The engine now returns the pending text — a moved-to candidate first, as Enter would — on Keyreset and Keyrelease; the GTK module asks for it before closing on focus-out and commits it, IBus commits it on FocusOut, Reset and a switch to a password field, and XIM commits it on focus loss and hands it back on ResetIC without a separate capability probe.
This commit is contained in:
97
ibus.c
97
ibus.c
@@ -288,36 +288,6 @@ sendrequest(Ictx *ctx, int op, u32int ks, u32int mod, Keyres *res)
|
||||
chanrecv(replyc, res);
|
||||
}
|
||||
|
||||
static void
|
||||
releasecontext(Ictx *ctx)
|
||||
{
|
||||
Keyres res;
|
||||
|
||||
if(ctx->focused)
|
||||
sendrequest(ctx, Keyrelease, 0, 0, &res);
|
||||
ctx->focused = 0;
|
||||
memset(&ctx->caret, 0, sizeof ctx->caret);
|
||||
}
|
||||
|
||||
static void
|
||||
dropcontext(Ictx *ctx)
|
||||
{
|
||||
releasecontext(ctx);
|
||||
if(preowner == ctx)
|
||||
preowner = nil;
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
dropconncontexts(DBusConnection *conn)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < nelem(contexts); i++)
|
||||
if(contexts[i].conn == conn)
|
||||
dropcontext(&contexts[i]);
|
||||
}
|
||||
|
||||
static int
|
||||
hidden(Ictx *ctx)
|
||||
{
|
||||
@@ -465,6 +435,52 @@ checkpreowner(void)
|
||||
emitpreedit(ctx, "");
|
||||
}
|
||||
|
||||
/* A reset or a lost focus hands the pending text back as committed text. */
|
||||
static void
|
||||
flushcontext(Ictx *ctx, int op)
|
||||
{
|
||||
Keyres res;
|
||||
char commit[Maxutf];
|
||||
|
||||
sendrequest(ctx, op, 0, 0, &res);
|
||||
if(clientpreedit(ctx))
|
||||
emitpreedit(ctx, "");
|
||||
stoutf(&res.commit, commit, sizeof commit);
|
||||
if(commit[0] != '\0')
|
||||
emitcommit(ctx->conn, ctx->path, commit);
|
||||
}
|
||||
|
||||
/* Nobody is left to hand text to: the context or its connection is gone. */
|
||||
static void
|
||||
releasecontext(Ictx *ctx)
|
||||
{
|
||||
Keyres res;
|
||||
|
||||
if(ctx->focused)
|
||||
sendrequest(ctx, Keyrelease, 0, 0, &res);
|
||||
ctx->focused = 0;
|
||||
memset(&ctx->caret, 0, sizeof ctx->caret);
|
||||
}
|
||||
|
||||
static void
|
||||
dropcontext(Ictx *ctx)
|
||||
{
|
||||
releasecontext(ctx);
|
||||
if(preowner == ctx)
|
||||
preowner = nil;
|
||||
memset(ctx, 0, sizeof *ctx);
|
||||
}
|
||||
|
||||
static void
|
||||
dropconncontexts(DBusConnection *conn)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < nelem(contexts); i++)
|
||||
if(contexts[i].conn == conn)
|
||||
dropcontext(&contexts[i]);
|
||||
}
|
||||
|
||||
static int
|
||||
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
|
||||
{
|
||||
@@ -603,11 +619,7 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||
static DBusHandlerResult
|
||||
handlereset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||
{
|
||||
Keyres res;
|
||||
|
||||
sendrequest(ctx, Keyreset, 0, 0, &res);
|
||||
if(clientpreedit(ctx))
|
||||
emitpreedit(ctx, "");
|
||||
flushcontext(ctx, Keyreset);
|
||||
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
||||
}
|
||||
|
||||
@@ -621,9 +633,10 @@ handlefocusin(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||
static DBusHandlerResult
|
||||
handlefocusout(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||
{
|
||||
releasecontext(ctx);
|
||||
if(clientpreedit(ctx))
|
||||
emitpreedit(ctx, "");
|
||||
if(ctx->focused)
|
||||
flushcontext(ctx, Keyrelease);
|
||||
ctx->focused = 0;
|
||||
memset(&ctx->caret, 0, sizeof ctx->caret);
|
||||
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
||||
}
|
||||
|
||||
@@ -701,7 +714,6 @@ handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||
DBusMessageIter value, st;
|
||||
dbus_bool_t b;
|
||||
u32int purpose;
|
||||
Keyres res;
|
||||
int washidden;
|
||||
|
||||
if(!getproperty(m, &iface, &name, &value))
|
||||
@@ -716,11 +728,8 @@ handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
|
||||
"ContentType expects (uu)");
|
||||
washidden = hidden(ctx);
|
||||
ctx->purpose = purpose;
|
||||
if(ctx->focused && !washidden && hidden(ctx)){
|
||||
sendrequest(ctx, Keyreset, 0, 0, &res);
|
||||
if(clientpreedit(ctx))
|
||||
emitpreedit(ctx, "");
|
||||
}
|
||||
if(ctx->focused && !washidden && hidden(ctx))
|
||||
flushcontext(ctx, Keyreset);
|
||||
return reply(c, m, DBUS_TYPE_INVALID, nil);
|
||||
}
|
||||
if(strcmp(name, "ClientCommitPreedit") == 0){
|
||||
|
||||
Reference in New Issue
Block a user