ipc: strip machinery no peer uses; keep client state in one Keyreq

ipc.c: an AF_UNIX nonblocking connect completes at once or fails with
EAGAIN, so the EINPROGRESS/poll/SO_ERROR path and the fcntl juggling
were dead; the deadline plumbing checked a clock that cannot fail and
re-tested the deadline before every transfer although only waitfd
blocks; readfield's truncation and discard loop served the unit test,
since every caller owns char[Ipcfieldmax+1]; NULL-argument checks on
in-tree encoders are gone (peer validation stays). The primary key frame
is Ipckey, not 'legacy'; ipckeysym names the keysym mapping.

srv.c: the per-connection capability and caret already lived in the
persistent Keyreq; the mirror locals and 'negotiated' flag guarded a
protocol rule no client relied on. proccreate never fails in libthread.

gtk: focus-out no longer round-trips a reset before closing the socket
that releases the engine; the caret dedup compares the packed frame;
srvconnect's preedit no-ops and the insimple flag are gone.
This commit is contained in:
2026-08-16 15:53:08 +09:00
parent 43b469f70b
commit eb0f88f764
11 changed files with 205 additions and 394 deletions

View File

@@ -1,5 +1,4 @@
#include <errno.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -19,7 +18,6 @@ struct Im
int ext;
int private;
int simpleactive;
int insimple;
int simpledone;
char pre[Ipcfieldmax+1];
int prelen;
@@ -27,10 +25,7 @@ struct Im
GdkRectangle cursor;
int cursorvalid;
int caretsent;
int sentvalid;
int32_t sentx;
int32_t senty;
int32_t senth;
unsigned char sent[Ipccaretsz];
};
typedef struct ImClass ImClass;
@@ -86,22 +81,14 @@ srvclose(Im *im)
srvdrop(im, 1);
}
/* Both buffers are char[Ipcfieldmax+1]. */
static int
validtext(const char *s, size_t n)
readresp(Im *im, int want, char *commit, char *pre, Ipcresp *resp)
{
return s[n] == '\0' && memchr(s, '\0', n) == NULL &&
g_utf8_validate(s, n, NULL);
}
static int
readresp(Im *im, int want, char *commit, int ncommit, char *pre, int npre,
Ipcresp *resp)
{
if(ipcreadresp(im->fd, want, commit, ncommit, pre, npre,
resp) < 0)
if(ipcreadresp(im->fd, want, commit, pre, resp) < 0)
return -1;
if(!validtext(commit, resp->commitlen) ||
(want && !validtext(pre, resp->preeditlen))){
if(!g_utf8_validate(commit, resp->commitlen, NULL) ||
(want && !g_utf8_validate(pre, resp->preeditlen, NULL))){
errno = EPROTO;
return -1;
}
@@ -117,76 +104,58 @@ dropwindow(Im *im)
im->cursorvalid = 0;
}
/* Root-relative caret in device pixels; returns whether it is known. */
static int
caretget(Im *im, int *valid, int32_t *x, int32_t *y, int32_t *h)
caretget(Im *im, int32_t *x, int32_t *y, int32_t *h)
{
gint rx, ry, scale;
int64_t sx, sy, sh;
*valid = 0;
*x = *y = *h = 0;
if(im->win != NULL && gdk_window_is_destroyed(im->win))
dropwindow(im);
if(!im->cursorvalid || im->win == NULL){
im->cursorvalid = 0;
if(!im->cursorvalid || im->win == NULL || im->cursor.height < 0)
return 0;
}
#ifdef GDK_WINDOWING_X11
if(!GDK_IS_X11_WINDOW(im->win)){
im->cursorvalid = 0;
if(!GDK_IS_X11_WINDOW(im->win))
return 0;
}
#else
im->cursorvalid = 0;
return 0;
#endif
if(im->cursor.height < 0){
im->cursorvalid = 0;
return 0;
}
scale = gdk_window_get_scale_factor(im->win);
if(scale <= 0){
im->cursorvalid = 0;
if(scale <= 0)
return 0;
}
/* GDK translates the client-relative point before device scaling. */
gdk_window_get_root_coords(im->win, 0, 0, &rx, &ry);
sx = ((int64_t)rx + im->cursor.x) * scale;
sy = ((int64_t)ry + im->cursor.y) * scale;
sh = (int64_t)im->cursor.height * scale;
if(sx < INT32_MIN || sx > INT32_MAX ||
sy < INT32_MIN || sy > INT32_MAX || sh > INT32_MAX){
im->cursorvalid = 0;
sy < INT32_MIN || sy > INT32_MAX || sh > INT32_MAX)
return 0;
}
*valid = 1;
*x = sx;
*y = sy;
*h = sh;
return 0;
return 1;
}
static int
sendcaret(Im *im)
{
unsigned char buf[Ipccaretsz];
int valid;
int32_t x, y, h;
int valid;
if(im->fd < 0 || !im->ext)
return 0;
caretget(im, &valid, &x, &y, &h);
if(im->caretsent && valid == im->sentvalid &&
(!valid || (x == im->sentx && y == im->senty && h == im->senth)))
valid = caretget(im, &x, &y, &h);
ipcpackcaret(buf, valid, x, y, h);
if(im->caretsent && memcmp(buf, im->sent, sizeof buf) == 0)
return 0;
if(ipcpackcaret(buf, valid, x, y, h) < 0 ||
ipcsend(im->fd, buf, sizeof buf) < 0)
if(ipcsend(im->fd, buf, sizeof buf) < 0)
return -1;
memcpy(im->sent, buf, sizeof buf);
im->caretsent = 1;
im->sentvalid = valid;
im->sentx = x;
im->senty = y;
im->senth = h;
return 0;
}
@@ -206,17 +175,12 @@ srvconnect(Im *im)
/* Marker zero is an old daemon's harmless key-zero response. */
ipcpackcap(buf, im->usepreedit);
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
readresp(im, im->usepreedit, commit, sizeof commit,
pre, sizeof pre, &resp) < 0){
readresp(im, im->usepreedit, commit, pre, &resp) < 0){
srvclose(im);
return -1;
}
if(im->usepreedit)
setpreedit(im, pre, resp.preeditlen);
im->ext = resp.eaten != 0;
if(!im->usepreedit)
setpreedit(im, "", 0);
if(im->ext && sendcaret(im) < 0){
if(sendcaret(im) < 0){
srvclose(im);
return -1;
}
@@ -228,18 +192,20 @@ simplecommit(GtkIMContext *ctx, const char *s, Im *im)
{
(void)ctx;
(void)s;
if(im->insimple)
im->simpledone = 1;
im->simpledone = 1;
}
static void
simpleend(GtkIMContext *ctx, Im *im)
{
(void)ctx;
if(im->insimple)
im->simpledone = 1;
im->simpledone = 1;
}
/*
* GtkIMContextSimple composes dead keys and Compose sequences; it keeps
* the key stream until it commits, ends its preedit, or rejects a press.
*/
static gboolean
simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
{
@@ -249,9 +215,7 @@ simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
im = (Im*)ctx;
im->simpleactive = 1;
im->simpledone = 0;
im->insimple = 1;
r = parentim->filter_keypress(ctx, ev);
im->insimple = 0;
if((!r && !release) || im->simpledone)
im->simpleactive = 0;
return r;
@@ -271,8 +235,7 @@ sendreset(Im *im)
}
ipcpackreset(buf, im->usepreedit);
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
readresp(im, im->usepreedit, commit, sizeof commit,
pre, sizeof pre, &resp) < 0){
readresp(im, im->usepreedit, commit, pre, &resp) < 0){
srvclose(im);
return;
}
@@ -297,7 +260,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
}
if(im->simpleactive)
return simplefilter(ctx, ev, 0);
key = ipckey(ev->keyval, gdk_keyval_to_unicode(ev->keyval));
key = ipckeysym(ev->keyval, gdk_keyval_to_unicode(ev->keyval));
mod = ipcmod(ev->state);
if(im->private || key == 0)
return simplefilter(ctx, ev, 0);
@@ -310,8 +273,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
}
ipcpackreq(buf, im->usepreedit, mod, key);
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
readresp(im, im->usepreedit, commit, sizeof commit,
pre, sizeof pre, &resp) < 0){
readresp(im, im->usepreedit, commit, pre, &resp) < 0){
srvclose(im);
return simplefilter(ctx, ev, 0);
}
@@ -371,8 +333,7 @@ focusout(GtkIMContext *ctx)
if(parentim->focus_out != NULL)
parentim->focus_out(ctx);
im->simpleactive = 0;
sendreset(im);
/* Closing the context connection releases engine ownership. */
/* Closing the connection releases the engine, which resets it. */
srvclose(im);
}
@@ -398,8 +359,7 @@ setusepreedit(GtkIMContext *ctx, gboolean use)
return;
ipcpackcap(buf, use);
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
readresp(im, use, commit, sizeof commit,
pre, sizeof pre, &resp) < 0 ||
readresp(im, use, commit, pre, &resp) < 0 ||
!resp.eaten){
srvclose(im);
return;