ipc: negotiate preedit capability and caret messages

This commit is contained in:
2026-08-14 18:53:14 +09:00
parent b536573622
commit 6a58b63223
7 changed files with 538 additions and 17 deletions

103
ipc.c
View File

@@ -20,6 +20,32 @@ getlen(const unsigned char p[Ipclensz])
return p[0] | (p[1] << 8);
}
static void
put32(unsigned char *p, int32_t v)
{
uint32_t u;
u = v;
p[0] = u;
p[1] = u >> 8;
p[2] = u >> 16;
p[3] = u >> 24;
}
static int32_t
get32(const unsigned char *p)
{
uint32_t u;
u = (uint32_t)p[0] |
((uint32_t)p[1] << 8) |
((uint32_t)p[2] << 16) |
((uint32_t)p[3] << 24);
if(u <= INT32_MAX)
return u;
return -(int32_t)(~u) - 1;
}
int
ipcpath(char *dst, size_t cap)
{
@@ -82,6 +108,37 @@ ipcpackreset(unsigned char req[Ipcreqsz], int want)
req[0] = Ipcreqreset | (want ? Ipcreqwant : 0);
}
/* An old server sees this reserved frame as a key-zero request. */
void
ipcpackcap(unsigned char req[Ipcreqsz], int want)
{
memset(req, 0, Ipcreqsz);
req[0] = Ipcext | (want ? Ipcreqwant : 0);
req[1] = Ipcversion;
req[2] = Ipcopcap;
}
int
ipcpackcaret(unsigned char req[Ipccaretsz], int valid, int32_t x,
int32_t y, int32_t h)
{
if(valid != 0 && valid != 1)
return -1;
if(valid && h < 0)
return -1;
memset(req, 0, Ipccaretsz);
req[0] = Ipcext;
req[1] = Ipcversion;
req[2] = Ipcopcaret;
req[3] = valid;
if(!valid)
return 0;
put32(req + 4, x);
put32(req + 8, y);
put32(req + 12, h);
return 0;
}
void
ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, uint32_t *mod,
uint32_t *key)
@@ -94,6 +151,52 @@ ipcunpackreq(const unsigned char req[Ipcreqsz], int *want, uint32_t *mod,
((uint32_t)req[5] << 24);
}
int
ipcreqtype(const unsigned char req[Ipcreqsz])
{
if((req[0] & Ipcext) == 0)
return Ipclegacy;
if(req[1] != Ipcversion)
return Ipcunknown;
switch(req[2]){
case Ipcopcap:
if((req[0] & ~(Ipcext|Ipcreqwant)) != 0 ||
req[3] != 0 || req[4] != 0 || req[5] != 0)
return Ipcunknown;
return Ipccap;
case Ipcopcaret:
if(req[0] != Ipcext || req[3] > 1)
return Ipcunknown;
return Ipccaret;
}
return Ipcunknown;
}
int
ipcunpackcaret(const unsigned char req[Ipccaretsz], int *valid,
int32_t *x, int32_t *y, int32_t *h)
{
int32_t wireh;
if(valid == NULL || x == NULL || y == NULL || h == NULL ||
ipcreqtype(req) != Ipccaret)
return -1;
wireh = get32(req + 12);
if(wireh < 0)
return -1;
*valid = req[3];
if(!*valid){
*x = 0;
*y = 0;
*h = 0;
return 0;
}
*x = get32(req + 4);
*y = get32(req + 8);
*h = wireh;
return 0;
}
int
ipcreqreset(const unsigned char req[Ipcreqsz])
{