ipc, srv, gtk: the client's text goes over and a take-back comes back
The engine can reach a Hanja reading back into the text the client already holds, but only if the frontend hands that text over and can take some of it away again. GTK 3 has both: retrieve-surrounding brings the text around the cursor and delete-surrounding removes runes before it, and a widget that answers neither leaves the text empty, so nothing is ever reached into or taken from it. The wire grows a control frame for the text, sent like the caret only when it changes, and one byte in every response for the runes to take back. That byte moves the length fields along, so the version goes to 2: an old daemon and a new module, either way round, fail the handshake and the module falls through to GtkIMContextSimple rather than misread a frame. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
63
gtk/main.c
63
gtk/main.c
@@ -24,6 +24,9 @@ struct Im
|
||||
int cursorvalid;
|
||||
int caretsent;
|
||||
unsigned char sent[Ipccaretsz];
|
||||
char surround[Ipcfieldmax];
|
||||
int nsurround;
|
||||
int surroundsent;
|
||||
};
|
||||
|
||||
typedef struct ImClass ImClass;
|
||||
@@ -65,6 +68,7 @@ srvdrop(Im *im, int notify)
|
||||
im->fd = -1;
|
||||
im->ext = 0;
|
||||
im->caretsent = 0;
|
||||
im->surroundsent = 0;
|
||||
if(notify)
|
||||
setpreedit(im, "", 0);
|
||||
else{
|
||||
@@ -157,6 +161,58 @@ sendcaret(Im *im)
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* The text just before the cursor, as much of it as a reading can use,
|
||||
* cut on a rune boundary. A widget that keeps none leaves it empty, and
|
||||
* then the daemon never asks for any of it back.
|
||||
*/
|
||||
static void
|
||||
readsurround(Im *im, GtkIMContext *ctx)
|
||||
{
|
||||
char *text, *p;
|
||||
gint cursor;
|
||||
int start;
|
||||
|
||||
im->nsurround = 0;
|
||||
if(!gtk_im_context_get_surrounding(ctx, &text, &cursor))
|
||||
return;
|
||||
if(cursor < 0 || cursor > (gint)strlen(text)){
|
||||
g_free(text);
|
||||
return;
|
||||
}
|
||||
start = cursor > Ipcfieldmax ? cursor - Ipcfieldmax : 0;
|
||||
for(p = text + start; p < text + cursor && (*p & 0xc0) == 0x80; p++)
|
||||
;
|
||||
im->nsurround = text + cursor - p;
|
||||
memcpy(im->surround, p, im->nsurround);
|
||||
g_free(text);
|
||||
}
|
||||
|
||||
/* Sent only when it changes, as the caret is. */
|
||||
static int
|
||||
sendsurround(Im *im, GtkIMContext *ctx)
|
||||
{
|
||||
unsigned char hdr[Ipcreqsz];
|
||||
char was[Ipcfieldmax];
|
||||
int nwas;
|
||||
|
||||
if(im->fd < 0 || !im->ext)
|
||||
return 0;
|
||||
nwas = im->nsurround;
|
||||
memcpy(was, im->surround, nwas);
|
||||
readsurround(im, ctx);
|
||||
if(im->surroundsent && nwas == im->nsurround &&
|
||||
memcmp(was, im->surround, nwas) == 0)
|
||||
return 0;
|
||||
ipcpacksurround(hdr, im->nsurround);
|
||||
if(ipcsend(im->fd, hdr, sizeof hdr) < 0 ||
|
||||
(im->nsurround > 0 &&
|
||||
ipcsend(im->fd, im->surround, im->nsurround) < 0))
|
||||
return -1;
|
||||
im->surroundsent = 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
srvconnect(Im *im)
|
||||
{
|
||||
@@ -286,7 +342,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
||||
if(srvconnect(im) < 0)
|
||||
return simplefilter(ctx, ev, 0);
|
||||
/* A retained GDK window may have moved since the last cursor report. */
|
||||
if(sendcaret(im) < 0){
|
||||
if(sendcaret(im) < 0 || sendsurround(im, ctx) < 0){
|
||||
srvclose(im);
|
||||
return simplefilter(ctx, ev, 0);
|
||||
}
|
||||
@@ -298,6 +354,11 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
||||
}
|
||||
if(im->usepreedit && commit[0] != '\0' && im->prelen > 0)
|
||||
setpreedit(im, "", 0);
|
||||
/* The reading reached into the widget's own text: give it back. */
|
||||
if(resp.del > 0){
|
||||
gtk_im_context_delete_surrounding(ctx, -resp.del, resp.del);
|
||||
im->surroundsent = 0;
|
||||
}
|
||||
if(commit[0] != '\0')
|
||||
g_signal_emit_by_name(ctx, "commit", commit);
|
||||
if(im->usepreedit)
|
||||
|
||||
Reference in New Issue
Block a user