wl: the text before the cursor, and the runes to take back

The surrounding_text event was taken and thrown away.  It carries the
text around the cursor with a byte offset into it, and belongs to the
activation like the content type, so it is pending until done and
starts empty at every activate.  delete_surrounding_text counts bytes
where the engine counts runes, and the frontend holds the text those
runes are in, so it measures them itself.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-08-18 14:31:44 +09:00
parent 921e632eae
commit 5d9a2a614e
4 changed files with 59 additions and 1 deletions

34
wl.c
View File

@@ -65,6 +65,7 @@ static int active; /* a text input is being served */
static int pendingactive;
static int activated; /* an activate arrived since the last done */
static u32int purpose, pendingpurpose;
static Str surround, pendingsurround; /* the client's text before the cursor */
static u32int sent[Maxcode/32]; /* keycodes passed on and still down */
static u32int lasttime; /* the compositor's clock, for a release of our own */
static int reprate; /* repeats a second the seat asks for; 0 is none */
@@ -116,11 +117,26 @@ sendrequest(int op, u32int ks, u32int mod, Keyres *res)
kr.op = op;
kr.ks = ks;
kr.mod = mod;
kr.surround = surround;
kr.reply = replyc;
chansend(keyc, &kr);
chanrecv(replyc, res);
}
/* The bytes the last n runes of the client's text take. */
static int
backbytes(int n)
{
char utf[Maxutf];
Str s;
int i;
sclear(&s);
for(i = max(surround.n - n, 0); i < surround.n; i++)
sputr(&s, surround.r[i]);
return stoutf(&s, utf, sizeof utf);
}
/* The engine's modifier bits, read from the grab's own keyboard state. */
static u32int
modmask(void)
@@ -187,6 +203,10 @@ answer(Keyres *res, char *tail)
char utf[2*Maxutf];
int n;
/* The compositor takes the text back before it inserts ours. */
if(res->del > 0)
zwp_input_method_v2_delete_surrounding_text(im,
backbytes(res->del), 0);
n = stoutf(&res->commit, utf, sizeof utf);
if(tail[0] != '\0')
n += snprint(utf+n, sizeof utf - n, "%s", tail);
@@ -407,6 +427,7 @@ imactivate(void*, struct zwp_input_method_v2*)
pendingactive = 1;
activated = 1;
pendingpurpose = 0;
sclear(&pendingsurround);
}
static void
@@ -415,9 +436,19 @@ imdeactivate(void*, struct zwp_input_method_v2*)
pendingactive = 0;
}
/*
* The text around the cursor, of which a reading can use what comes
* before it. A text input that sends none leaves this empty, and then
* nothing is ever reached back into or taken away.
*/
static void
imsurrounding(void*, struct zwp_input_method_v2*, const char*, u32int, u32int)
imsurrounding(void*, struct zwp_input_method_v2*, const char *text,
u32int cursor, u32int)
{
u32int n;
n = strlen(text);
stail(&pendingsurround, (char*)text, cursor < n ? cursor : n);
}
static void
@@ -444,6 +475,7 @@ imdone(void*, struct zwp_input_method_v2*)
serial++;
washidden = hidden();
purpose = pendingpurpose;
surround = pendingsurround;
if(activated || (active && !pendingactive))
leave();
else if(active && !washidden && hidden())