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:
@@ -128,10 +128,10 @@ sendkey(int key, int mod)
|
|||||||
static int
|
static int
|
||||||
readresp(void)
|
readresp(void)
|
||||||
{
|
{
|
||||||
char buf[Ipcfieldmax+1];
|
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
|
|
||||||
return ipcreadresp(fd, 0, buf, sizeof buf, NULL, 0, &resp);
|
return ipcreadresp(fd, 0, commit, preedit, &resp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static double
|
static double
|
||||||
|
|||||||
100
gtk/main.c
100
gtk/main.c
@@ -1,5 +1,4 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <limits.h>
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@@ -19,7 +18,6 @@ struct Im
|
|||||||
int ext;
|
int ext;
|
||||||
int private;
|
int private;
|
||||||
int simpleactive;
|
int simpleactive;
|
||||||
int insimple;
|
|
||||||
int simpledone;
|
int simpledone;
|
||||||
char pre[Ipcfieldmax+1];
|
char pre[Ipcfieldmax+1];
|
||||||
int prelen;
|
int prelen;
|
||||||
@@ -27,10 +25,7 @@ struct Im
|
|||||||
GdkRectangle cursor;
|
GdkRectangle cursor;
|
||||||
int cursorvalid;
|
int cursorvalid;
|
||||||
int caretsent;
|
int caretsent;
|
||||||
int sentvalid;
|
unsigned char sent[Ipccaretsz];
|
||||||
int32_t sentx;
|
|
||||||
int32_t senty;
|
|
||||||
int32_t senth;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct ImClass ImClass;
|
typedef struct ImClass ImClass;
|
||||||
@@ -86,22 +81,14 @@ srvclose(Im *im)
|
|||||||
srvdrop(im, 1);
|
srvdrop(im, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Both buffers are char[Ipcfieldmax+1]. */
|
||||||
static int
|
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 &&
|
if(ipcreadresp(im->fd, want, commit, pre, resp) < 0)
|
||||||
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)
|
|
||||||
return -1;
|
return -1;
|
||||||
if(!validtext(commit, resp->commitlen) ||
|
if(!g_utf8_validate(commit, resp->commitlen, NULL) ||
|
||||||
(want && !validtext(pre, resp->preeditlen))){
|
(want && !g_utf8_validate(pre, resp->preeditlen, NULL))){
|
||||||
errno = EPROTO;
|
errno = EPROTO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -117,76 +104,58 @@ dropwindow(Im *im)
|
|||||||
im->cursorvalid = 0;
|
im->cursorvalid = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Root-relative caret in device pixels; returns whether it is known. */
|
||||||
static int
|
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;
|
gint rx, ry, scale;
|
||||||
int64_t sx, sy, sh;
|
int64_t sx, sy, sh;
|
||||||
|
|
||||||
*valid = 0;
|
|
||||||
*x = *y = *h = 0;
|
*x = *y = *h = 0;
|
||||||
if(im->win != NULL && gdk_window_is_destroyed(im->win))
|
if(im->win != NULL && gdk_window_is_destroyed(im->win))
|
||||||
dropwindow(im);
|
dropwindow(im);
|
||||||
if(!im->cursorvalid || im->win == NULL){
|
if(!im->cursorvalid || im->win == NULL || im->cursor.height < 0)
|
||||||
im->cursorvalid = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#ifdef GDK_WINDOWING_X11
|
#ifdef GDK_WINDOWING_X11
|
||||||
if(!GDK_IS_X11_WINDOW(im->win)){
|
if(!GDK_IS_X11_WINDOW(im->win))
|
||||||
im->cursorvalid = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
#else
|
#else
|
||||||
im->cursorvalid = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
if(im->cursor.height < 0){
|
|
||||||
im->cursorvalid = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
scale = gdk_window_get_scale_factor(im->win);
|
scale = gdk_window_get_scale_factor(im->win);
|
||||||
if(scale <= 0){
|
if(scale <= 0)
|
||||||
im->cursorvalid = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
/* GDK translates the client-relative point before device scaling. */
|
/* GDK translates the client-relative point before device scaling. */
|
||||||
gdk_window_get_root_coords(im->win, 0, 0, &rx, &ry);
|
gdk_window_get_root_coords(im->win, 0, 0, &rx, &ry);
|
||||||
sx = ((int64_t)rx + im->cursor.x) * scale;
|
sx = ((int64_t)rx + im->cursor.x) * scale;
|
||||||
sy = ((int64_t)ry + im->cursor.y) * scale;
|
sy = ((int64_t)ry + im->cursor.y) * scale;
|
||||||
sh = (int64_t)im->cursor.height * scale;
|
sh = (int64_t)im->cursor.height * scale;
|
||||||
if(sx < INT32_MIN || sx > INT32_MAX ||
|
if(sx < INT32_MIN || sx > INT32_MAX ||
|
||||||
sy < INT32_MIN || sy > INT32_MAX || sh > INT32_MAX){
|
sy < INT32_MIN || sy > INT32_MAX || sh > INT32_MAX)
|
||||||
im->cursorvalid = 0;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
|
||||||
*valid = 1;
|
|
||||||
*x = sx;
|
*x = sx;
|
||||||
*y = sy;
|
*y = sy;
|
||||||
*h = sh;
|
*h = sh;
|
||||||
return 0;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
sendcaret(Im *im)
|
sendcaret(Im *im)
|
||||||
{
|
{
|
||||||
unsigned char buf[Ipccaretsz];
|
unsigned char buf[Ipccaretsz];
|
||||||
int valid;
|
|
||||||
int32_t x, y, h;
|
int32_t x, y, h;
|
||||||
|
int valid;
|
||||||
|
|
||||||
if(im->fd < 0 || !im->ext)
|
if(im->fd < 0 || !im->ext)
|
||||||
return 0;
|
return 0;
|
||||||
caretget(im, &valid, &x, &y, &h);
|
valid = caretget(im, &x, &y, &h);
|
||||||
if(im->caretsent && valid == im->sentvalid &&
|
ipcpackcaret(buf, valid, x, y, h);
|
||||||
(!valid || (x == im->sentx && y == im->senty && h == im->senth)))
|
if(im->caretsent && memcmp(buf, im->sent, sizeof buf) == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if(ipcpackcaret(buf, valid, x, y, h) < 0 ||
|
if(ipcsend(im->fd, buf, sizeof buf) < 0)
|
||||||
ipcsend(im->fd, buf, sizeof buf) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
memcpy(im->sent, buf, sizeof buf);
|
||||||
im->caretsent = 1;
|
im->caretsent = 1;
|
||||||
im->sentvalid = valid;
|
|
||||||
im->sentx = x;
|
|
||||||
im->senty = y;
|
|
||||||
im->senth = h;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -206,17 +175,12 @@ srvconnect(Im *im)
|
|||||||
/* Marker zero is an old daemon's harmless key-zero response. */
|
/* Marker zero is an old daemon's harmless key-zero response. */
|
||||||
ipcpackcap(buf, im->usepreedit);
|
ipcpackcap(buf, im->usepreedit);
|
||||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||||
readresp(im, im->usepreedit, commit, sizeof commit,
|
readresp(im, im->usepreedit, commit, pre, &resp) < 0){
|
||||||
pre, sizeof pre, &resp) < 0){
|
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(im->usepreedit)
|
|
||||||
setpreedit(im, pre, resp.preeditlen);
|
|
||||||
im->ext = resp.eaten != 0;
|
im->ext = resp.eaten != 0;
|
||||||
if(!im->usepreedit)
|
if(sendcaret(im) < 0){
|
||||||
setpreedit(im, "", 0);
|
|
||||||
if(im->ext && sendcaret(im) < 0){
|
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -228,7 +192,6 @@ simplecommit(GtkIMContext *ctx, const char *s, Im *im)
|
|||||||
{
|
{
|
||||||
(void)ctx;
|
(void)ctx;
|
||||||
(void)s;
|
(void)s;
|
||||||
if(im->insimple)
|
|
||||||
im->simpledone = 1;
|
im->simpledone = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -236,10 +199,13 @@ static void
|
|||||||
simpleend(GtkIMContext *ctx, Im *im)
|
simpleend(GtkIMContext *ctx, Im *im)
|
||||||
{
|
{
|
||||||
(void)ctx;
|
(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
|
static gboolean
|
||||||
simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
|
simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
|
||||||
{
|
{
|
||||||
@@ -249,9 +215,7 @@ simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
|
|||||||
im = (Im*)ctx;
|
im = (Im*)ctx;
|
||||||
im->simpleactive = 1;
|
im->simpleactive = 1;
|
||||||
im->simpledone = 0;
|
im->simpledone = 0;
|
||||||
im->insimple = 1;
|
|
||||||
r = parentim->filter_keypress(ctx, ev);
|
r = parentim->filter_keypress(ctx, ev);
|
||||||
im->insimple = 0;
|
|
||||||
if((!r && !release) || im->simpledone)
|
if((!r && !release) || im->simpledone)
|
||||||
im->simpleactive = 0;
|
im->simpleactive = 0;
|
||||||
return r;
|
return r;
|
||||||
@@ -271,8 +235,7 @@ sendreset(Im *im)
|
|||||||
}
|
}
|
||||||
ipcpackreset(buf, im->usepreedit);
|
ipcpackreset(buf, im->usepreedit);
|
||||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||||
readresp(im, im->usepreedit, commit, sizeof commit,
|
readresp(im, im->usepreedit, commit, pre, &resp) < 0){
|
||||||
pre, sizeof pre, &resp) < 0){
|
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -297,7 +260,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
|||||||
}
|
}
|
||||||
if(im->simpleactive)
|
if(im->simpleactive)
|
||||||
return simplefilter(ctx, ev, 0);
|
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);
|
mod = ipcmod(ev->state);
|
||||||
if(im->private || key == 0)
|
if(im->private || key == 0)
|
||||||
return simplefilter(ctx, ev, 0);
|
return simplefilter(ctx, ev, 0);
|
||||||
@@ -310,8 +273,7 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
|||||||
}
|
}
|
||||||
ipcpackreq(buf, im->usepreedit, mod, key);
|
ipcpackreq(buf, im->usepreedit, mod, key);
|
||||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||||
readresp(im, im->usepreedit, commit, sizeof commit,
|
readresp(im, im->usepreedit, commit, pre, &resp) < 0){
|
||||||
pre, sizeof pre, &resp) < 0){
|
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
return simplefilter(ctx, ev, 0);
|
return simplefilter(ctx, ev, 0);
|
||||||
}
|
}
|
||||||
@@ -371,8 +333,7 @@ focusout(GtkIMContext *ctx)
|
|||||||
if(parentim->focus_out != NULL)
|
if(parentim->focus_out != NULL)
|
||||||
parentim->focus_out(ctx);
|
parentim->focus_out(ctx);
|
||||||
im->simpleactive = 0;
|
im->simpleactive = 0;
|
||||||
sendreset(im);
|
/* Closing the connection releases the engine, which resets it. */
|
||||||
/* Closing the context connection releases engine ownership. */
|
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,8 +359,7 @@ setusepreedit(GtkIMContext *ctx, gboolean use)
|
|||||||
return;
|
return;
|
||||||
ipcpackcap(buf, use);
|
ipcpackcap(buf, use);
|
||||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||||
readresp(im, use, commit, sizeof commit,
|
readresp(im, use, commit, pre, &resp) < 0 ||
|
||||||
pre, sizeof pre, &resp) < 0 ||
|
|
||||||
!resp.eaten){
|
!resp.eaten){
|
||||||
srvclose(im);
|
srvclose(im);
|
||||||
return;
|
return;
|
||||||
|
|||||||
2
ibus.c
2
ibus.c
@@ -358,7 +358,7 @@ processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
|
|||||||
{
|
{
|
||||||
if(state & Relmask || !ctx->focused || hidden(ctx))
|
if(state & Relmask || !ctx->focused || hidden(ctx))
|
||||||
return 0;
|
return 0;
|
||||||
sendrequest(ctx, Keypress, ipckey(sym, xkb_keysym_to_utf32(sym)),
|
sendrequest(ctx, Keypress, ipckeysym(sym, xkb_keysym_to_utf32(sym)),
|
||||||
ipcmod(state), res);
|
ipcmod(state), res);
|
||||||
if(preowner != nil && preowner != ctx)
|
if(preowner != nil && preowner != ctx)
|
||||||
checkpreowner();
|
checkpreowner();
|
||||||
|
|||||||
215
ipc.c
215
ipc.c
@@ -1,7 +1,6 @@
|
|||||||
#define _POSIX_C_SOURCE 200809L
|
#define _POSIX_C_SOURCE 200809L
|
||||||
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <fcntl.h>
|
|
||||||
#include <poll.h>
|
#include <poll.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
@@ -17,57 +16,32 @@ nowms(void)
|
|||||||
{
|
{
|
||||||
struct timespec ts;
|
struct timespec ts;
|
||||||
|
|
||||||
if(clock_gettime(CLOCK_MONOTONIC, &ts) < 0)
|
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||||
return -1;
|
|
||||||
return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
return (int64_t)ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int64_t
|
static int64_t
|
||||||
deadline(void)
|
deadline(void)
|
||||||
{
|
{
|
||||||
int64_t now;
|
return nowms() + Ipcwaitms;
|
||||||
|
|
||||||
now = nowms();
|
|
||||||
if(now < 0)
|
|
||||||
return -1;
|
|
||||||
return now + Ipcwaitms;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
checkdeadline(int64_t until)
|
|
||||||
{
|
|
||||||
int64_t now;
|
|
||||||
|
|
||||||
now = nowms();
|
|
||||||
if(now < 0)
|
|
||||||
return -1;
|
|
||||||
if(now >= until){
|
|
||||||
errno = ETIMEDOUT;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
waitfd(int fd, short events, int64_t until)
|
waitfd(int fd, short events, int64_t until)
|
||||||
{
|
{
|
||||||
struct pollfd pfd;
|
struct pollfd pfd;
|
||||||
int64_t now, left;
|
int64_t left;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
pfd.fd = fd;
|
pfd.fd = fd;
|
||||||
pfd.events = events;
|
pfd.events = events;
|
||||||
for(;;){
|
for(;;){
|
||||||
now = nowms();
|
left = until - nowms();
|
||||||
if(now < 0)
|
|
||||||
return -1;
|
|
||||||
left = until - now;
|
|
||||||
if(left <= 0){
|
if(left <= 0){
|
||||||
errno = ETIMEDOUT;
|
errno = ETIMEDOUT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
pfd.revents = 0;
|
n = poll(&pfd, 1, left);
|
||||||
n = poll(&pfd, 1, left > INT32_MAX ? INT32_MAX : (int)left);
|
|
||||||
if(n < 0 && errno == EINTR)
|
if(n < 0 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
if(n < 0)
|
if(n < 0)
|
||||||
@@ -76,11 +50,6 @@ waitfd(int fd, short events, int64_t until)
|
|||||||
errno = ETIMEDOUT;
|
errno = ETIMEDOUT;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(pfd.revents & POLLNVAL){
|
|
||||||
errno = EBADF;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(pfd.revents & (events|POLLERR|POLLHUP))
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -93,8 +62,6 @@ readwait(int fd, void *buf, size_t n, int64_t until)
|
|||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
while(n > 0){
|
while(n > 0){
|
||||||
if(checkdeadline(until) < 0)
|
|
||||||
return -1;
|
|
||||||
r = recv(fd, p, n, MSG_DONTWAIT);
|
r = recv(fd, p, n, MSG_DONTWAIT);
|
||||||
if(r < 0 && errno == EINTR)
|
if(r < 0 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
@@ -143,15 +110,10 @@ put32(unsigned char *p, int32_t v)
|
|||||||
static int32_t
|
static int32_t
|
||||||
get32(const unsigned char *p)
|
get32(const unsigned char *p)
|
||||||
{
|
{
|
||||||
uint32_t u;
|
return (int32_t)((uint32_t)p[0] |
|
||||||
|
|
||||||
u = (uint32_t)p[0] |
|
|
||||||
((uint32_t)p[1] << 8) |
|
((uint32_t)p[1] << 8) |
|
||||||
((uint32_t)p[2] << 16) |
|
((uint32_t)p[2] << 16) |
|
||||||
((uint32_t)p[3] << 24);
|
((uint32_t)p[3] << 24));
|
||||||
if(u <= INT32_MAX)
|
|
||||||
return u;
|
|
||||||
return -(int32_t)(~u) - 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
@@ -160,8 +122,6 @@ ipcpath(char *dst, size_t cap)
|
|||||||
const char *dir, *sep;
|
const char *dir, *sep;
|
||||||
int n;
|
int n;
|
||||||
|
|
||||||
if(dst == NULL || cap == 0)
|
|
||||||
return -1;
|
|
||||||
dir = getenv("XDG_RUNTIME_DIR");
|
dir = getenv("XDG_RUNTIME_DIR");
|
||||||
if(dir != NULL && dir[0] == '/'){
|
if(dir != NULL && dir[0] == '/'){
|
||||||
sep = dir[strlen(dir)-1] == '/' ? "" : "/";
|
sep = dir[strlen(dir)-1] == '/' ? "" : "/";
|
||||||
@@ -174,13 +134,16 @@ ipcpath(char *dst, size_t cap)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* A nonblocking AF_UNIX connect completes at once or fails with EAGAIN
|
||||||
|
* when the daemon's backlog is full; the socket stays nonblocking because
|
||||||
|
* every transfer below polls with a deadline.
|
||||||
|
*/
|
||||||
int
|
int
|
||||||
ipcconnect(void)
|
ipcconnect(void)
|
||||||
{
|
{
|
||||||
struct sockaddr_un addr;
|
struct sockaddr_un addr;
|
||||||
socklen_t nerr;
|
int e, fd;
|
||||||
int e, err, fd, fdflags, flags;
|
|
||||||
int64_t until;
|
|
||||||
|
|
||||||
memset(&addr, 0, sizeof addr);
|
memset(&addr, 0, sizeof addr);
|
||||||
addr.sun_family = AF_UNIX;
|
addr.sun_family = AF_UNIX;
|
||||||
@@ -188,39 +151,16 @@ ipcconnect(void)
|
|||||||
errno = ENAMETOOLONG;
|
errno = ENAMETOOLONG;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
fd = socket(AF_UNIX, SOCK_STREAM, 0);
|
fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
|
||||||
if(fd < 0)
|
if(fd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
fdflags = fcntl(fd, F_GETFD);
|
|
||||||
if(fdflags < 0 || fcntl(fd, F_SETFD, fdflags|FD_CLOEXEC) < 0)
|
|
||||||
goto Bad;
|
|
||||||
flags = fcntl(fd, F_GETFL);
|
|
||||||
if(flags < 0 || fcntl(fd, F_SETFL, flags|O_NONBLOCK) < 0)
|
|
||||||
goto Bad;
|
|
||||||
until = deadline();
|
|
||||||
if(until < 0)
|
|
||||||
goto Bad;
|
|
||||||
if(connect(fd, (struct sockaddr*)&addr, sizeof addr) < 0){
|
if(connect(fd, (struct sockaddr*)&addr, sizeof addr) < 0){
|
||||||
if(errno != EINPROGRESS && errno != EALREADY && errno != EINTR)
|
|
||||||
goto Bad;
|
|
||||||
if(waitfd(fd, POLLOUT, until) < 0)
|
|
||||||
goto Bad;
|
|
||||||
nerr = sizeof err;
|
|
||||||
if(getsockopt(fd, SOL_SOCKET, SO_ERROR, &err, &nerr) < 0)
|
|
||||||
goto Bad;
|
|
||||||
if(err != 0){
|
|
||||||
errno = err;
|
|
||||||
goto Bad;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if(fcntl(fd, F_SETFL, flags) < 0)
|
|
||||||
goto Bad;
|
|
||||||
return fd;
|
|
||||||
Bad:
|
|
||||||
e = errno;
|
e = errno;
|
||||||
close(fd);
|
close(fd);
|
||||||
errno = e;
|
errno = e;
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -228,7 +168,7 @@ Bad:
|
|||||||
* as themselves, the function keysyms 0xff00-0xffff as Kspec+offset.
|
* as themselves, the function keysyms 0xff00-0xffff as Kspec+offset.
|
||||||
*/
|
*/
|
||||||
uint32_t
|
uint32_t
|
||||||
ipckey(uint32_t sym, uint32_t unicode)
|
ipckeysym(uint32_t sym, uint32_t unicode)
|
||||||
{
|
{
|
||||||
if(unicode >= ' ' && unicode != 0x7f)
|
if(unicode >= ' ' && unicode != 0x7f)
|
||||||
return unicode;
|
return unicode;
|
||||||
@@ -277,25 +217,20 @@ ipcpackcap(unsigned char req[Ipcreqsz], int want)
|
|||||||
req[2] = Ipcopcap;
|
req[2] = Ipcopcap;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
void
|
||||||
ipcpackcaret(unsigned char req[Ipccaretsz], int valid, int32_t x,
|
ipcpackcaret(unsigned char req[Ipccaretsz], int valid, int32_t x,
|
||||||
int32_t y, int32_t h)
|
int32_t y, int32_t h)
|
||||||
{
|
{
|
||||||
if(valid != 0 && valid != 1)
|
|
||||||
return -1;
|
|
||||||
if(valid && h < 0)
|
|
||||||
return -1;
|
|
||||||
memset(req, 0, Ipccaretsz);
|
memset(req, 0, Ipccaretsz);
|
||||||
req[0] = Ipcext;
|
req[0] = Ipcext;
|
||||||
req[1] = Ipcversion;
|
req[1] = Ipcversion;
|
||||||
req[2] = Ipcopcaret;
|
req[2] = Ipcopcaret;
|
||||||
req[3] = valid;
|
req[3] = valid != 0;
|
||||||
if(!valid)
|
if(valid){
|
||||||
return 0;
|
|
||||||
put32(req + 4, x);
|
put32(req + 4, x);
|
||||||
put32(req + 8, y);
|
put32(req + 8, y);
|
||||||
put32(req + 12, h);
|
put32(req + 12, h);
|
||||||
return 0;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -314,7 +249,7 @@ int
|
|||||||
ipcreqtype(const unsigned char req[Ipcreqsz])
|
ipcreqtype(const unsigned char req[Ipcreqsz])
|
||||||
{
|
{
|
||||||
if((req[0] & Ipcext) == 0)
|
if((req[0] & Ipcext) == 0)
|
||||||
return Ipclegacy;
|
return Ipckey;
|
||||||
if(req[1] != Ipcversion)
|
if(req[1] != Ipcversion)
|
||||||
return Ipcunknown;
|
return Ipcunknown;
|
||||||
switch(req[2]){
|
switch(req[2]){
|
||||||
@@ -335,24 +270,12 @@ int
|
|||||||
ipcunpackcaret(const unsigned char req[Ipccaretsz], int *valid,
|
ipcunpackcaret(const unsigned char req[Ipccaretsz], int *valid,
|
||||||
int32_t *x, int32_t *y, int32_t *h)
|
int32_t *x, int32_t *y, int32_t *h)
|
||||||
{
|
{
|
||||||
int32_t wireh;
|
if(ipcreqtype(req) != Ipccaret || get32(req + 12) < 0)
|
||||||
|
|
||||||
if(valid == NULL || x == NULL || y == NULL || h == NULL ||
|
|
||||||
ipcreqtype(req) != Ipccaret)
|
|
||||||
return -1;
|
|
||||||
wireh = get32(req + 12);
|
|
||||||
if(wireh < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
*valid = req[3];
|
*valid = req[3];
|
||||||
if(!*valid){
|
*x = *valid ? get32(req + 4) : 0;
|
||||||
*x = 0;
|
*y = *valid ? get32(req + 8) : 0;
|
||||||
*y = 0;
|
*h = *valid ? get32(req + 12) : 0;
|
||||||
*h = 0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
*x = get32(req + 4);
|
|
||||||
*y = get32(req + 8);
|
|
||||||
*h = wireh;
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -371,21 +294,15 @@ ipcpackresp(unsigned char *dst, size_t cap, int eaten,
|
|||||||
|
|
||||||
if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax)
|
if(ncommit > Ipcfieldmax || npreedit > Ipcfieldmax)
|
||||||
return -1;
|
return -1;
|
||||||
if((ncommit > 0 && commit == NULL) ||
|
|
||||||
(want && npreedit > 0 && preedit == NULL))
|
|
||||||
return -1;
|
|
||||||
n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0);
|
n = Ipcresphdrsz + ncommit + (want ? Ipclensz + npreedit : 0);
|
||||||
if(dst == NULL || cap < n)
|
if(cap < n)
|
||||||
return -1;
|
return -1;
|
||||||
dst[0] = eaten != 0;
|
dst[0] = eaten != 0;
|
||||||
putlen(dst + 1, ncommit);
|
putlen(dst + 1, ncommit);
|
||||||
if(ncommit > 0)
|
|
||||||
memcpy(dst + Ipcresphdrsz, commit, ncommit);
|
memcpy(dst + Ipcresphdrsz, commit, ncommit);
|
||||||
if(want){
|
if(want){
|
||||||
putlen(dst + Ipcresphdrsz + ncommit, npreedit);
|
putlen(dst + Ipcresphdrsz + ncommit, npreedit);
|
||||||
if(npreedit > 0)
|
memcpy(dst + Ipcresphdrsz + ncommit + Ipclensz, preedit, npreedit);
|
||||||
memcpy(dst + Ipcresphdrsz + ncommit + Ipclensz,
|
|
||||||
preedit, npreedit);
|
|
||||||
}
|
}
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
@@ -417,14 +334,8 @@ ipcsend(int fd, const void *buf, size_t n)
|
|||||||
int64_t until;
|
int64_t until;
|
||||||
|
|
||||||
p = buf;
|
p = buf;
|
||||||
if(n == 0)
|
|
||||||
return 0;
|
|
||||||
until = deadline();
|
until = deadline();
|
||||||
if(until < 0)
|
|
||||||
return -1;
|
|
||||||
while(n > 0){
|
while(n > 0){
|
||||||
if(checkdeadline(until) < 0)
|
|
||||||
return -1;
|
|
||||||
r = send(fd, p, n, MSG_NOSIGNAL|MSG_DONTWAIT);
|
r = send(fd, p, n, MSG_NOSIGNAL|MSG_DONTWAIT);
|
||||||
if(r < 0 && errno == EINTR)
|
if(r < 0 && errno == EINTR)
|
||||||
continue;
|
continue;
|
||||||
@@ -445,73 +356,53 @@ ipcsend(int fd, const void *buf, size_t n)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Reads a length-prefixed field into dst[Ipcfieldmax+1]. */
|
||||||
static int
|
static int
|
||||||
readfield(int fd, size_t n, char *dst, size_t cap, size_t *copied,
|
readfield(int fd, char *dst, int64_t until)
|
||||||
int64_t until)
|
|
||||||
{
|
{
|
||||||
unsigned char discard[128];
|
unsigned char len[Ipclensz];
|
||||||
size_t keep, part;
|
size_t n;
|
||||||
|
|
||||||
if(cap > 0 && dst == NULL)
|
if(readwait(fd, len, sizeof len, until) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
keep = 0;
|
n = getlen(len);
|
||||||
if(cap > 0)
|
if(n > Ipcfieldmax){
|
||||||
keep = n >= cap ? cap - 1 : n;
|
errno = EPROTO;
|
||||||
if(keep > 0 && readwait(fd, dst, keep, until) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
if(cap > 0)
|
|
||||||
dst[keep] = '\0';
|
|
||||||
n -= keep;
|
|
||||||
while(n > 0){
|
|
||||||
part = n < sizeof discard ? n : sizeof discard;
|
|
||||||
if(readwait(fd, discard, part, until) < 0)
|
|
||||||
return -1;
|
|
||||||
n -= part;
|
|
||||||
}
|
}
|
||||||
*copied = keep;
|
if(readwait(fd, dst, n, until) < 0)
|
||||||
return 0;
|
return -1;
|
||||||
|
dst[n] = '\0';
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ipcreadresp(int fd, int want, char *commit, size_t ccap,
|
ipcreadresp(int fd, int want, char *commit, char *preedit, Ipcresp *resp)
|
||||||
char *preedit, size_t pcap, Ipcresp *resp)
|
|
||||||
{
|
{
|
||||||
unsigned char hdr[Ipcresphdrsz], npreedit[Ipclensz];
|
unsigned char eaten;
|
||||||
size_t wirelen;
|
|
||||||
int64_t until;
|
int64_t until;
|
||||||
|
int n;
|
||||||
|
|
||||||
if(resp == NULL || (ccap > 0 && commit == NULL) ||
|
|
||||||
(pcap > 0 && preedit == NULL))
|
|
||||||
return -1;
|
|
||||||
if(ccap > 0)
|
|
||||||
commit[0] = '\0';
|
commit[0] = '\0';
|
||||||
if(pcap > 0)
|
|
||||||
preedit[0] = '\0';
|
preedit[0] = '\0';
|
||||||
memset(resp, 0, sizeof *resp);
|
memset(resp, 0, sizeof *resp);
|
||||||
until = deadline();
|
until = deadline();
|
||||||
if(until < 0 || readwait(fd, hdr, sizeof hdr, until) < 0)
|
if(readwait(fd, &eaten, 1, until) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
if(hdr[0] > 1){
|
if(eaten > 1){
|
||||||
errno = EPROTO;
|
errno = EPROTO;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
resp->eaten = hdr[0];
|
resp->eaten = eaten;
|
||||||
wirelen = getlen(hdr + 1);
|
n = readfield(fd, commit, until);
|
||||||
if(wirelen > Ipcfieldmax){
|
if(n < 0)
|
||||||
errno = EPROTO;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(readfield(fd, wirelen, commit, ccap, &resp->commitlen, until) < 0)
|
|
||||||
return -1;
|
return -1;
|
||||||
|
resp->commitlen = n;
|
||||||
if(!want)
|
if(!want)
|
||||||
return 0;
|
return 0;
|
||||||
if(readwait(fd, npreedit, sizeof npreedit, until) < 0)
|
n = readfield(fd, preedit, until);
|
||||||
|
if(n < 0)
|
||||||
return -1;
|
return -1;
|
||||||
wirelen = getlen(npreedit);
|
resp->preeditlen = n;
|
||||||
if(wirelen > Ipcfieldmax){
|
return 0;
|
||||||
errno = EPROTO;
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return readfield(fd, wirelen, preedit, pcap, &resp->preeditlen,
|
|
||||||
until);
|
|
||||||
}
|
}
|
||||||
|
|||||||
13
ipc.h
13
ipc.h
@@ -2,7 +2,7 @@
|
|||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Legacy request: [flags, modifiers, key byte 0, ..., key byte 3].
|
* Key request: [flags, modifiers, key byte 0, ..., key byte 3].
|
||||||
* Flags request preedit and distinguish lifecycle reset from physical Escape.
|
* Flags request preedit and distinguish lifecycle reset from physical Escape.
|
||||||
* The server identifies the connection as the engine owner; that identity is
|
* The server identifies the connection as the engine owner; that identity is
|
||||||
* not sent on the wire.
|
* not sent on the wire.
|
||||||
@@ -10,7 +10,8 @@
|
|||||||
* Response: [eaten, commit-length-low, commit-length-high, commit...],
|
* Response: [eaten, commit-length-low, commit-length-high, commit...],
|
||||||
* followed, when requested, by
|
* followed, when requested, by
|
||||||
* [preedit-length-low, preedit-length-high, preedit...].
|
* [preedit-length-low, preedit-length-high, preedit...].
|
||||||
* Lengths are little-endian byte counts; fields are at most Ipcfieldmax bytes.
|
* Lengths are little-endian byte counts; fields are at most Ipcfieldmax bytes,
|
||||||
|
* so callers read them into char[Ipcfieldmax+1].
|
||||||
*
|
*
|
||||||
* Capability control is six bytes: [0x80|want, version, 0, 0, 0, 0].
|
* Capability control is six bytes: [0x80|want, version, 0, 0, 0, 0].
|
||||||
* Caret control is sixteen bytes: [0x80, version, 1, valid, x, y, h],
|
* Caret control is sixteen bytes: [0x80, version, 1, valid, x, y, h],
|
||||||
@@ -58,7 +59,7 @@ enum
|
|||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Ipcunknown = -1,
|
Ipcunknown = -1,
|
||||||
Ipclegacy,
|
Ipckey,
|
||||||
Ipccap,
|
Ipccap,
|
||||||
Ipccaret,
|
Ipccaret,
|
||||||
};
|
};
|
||||||
@@ -72,12 +73,12 @@ struct Ipcresp
|
|||||||
size_t preeditlen;
|
size_t preeditlen;
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t ipckey(uint32_t, uint32_t);
|
uint32_t ipckeysym(uint32_t, uint32_t);
|
||||||
uint32_t ipcmod(uint32_t);
|
uint32_t ipcmod(uint32_t);
|
||||||
void ipcpackreq(unsigned char[Ipcreqsz], int, uint32_t, uint32_t);
|
void ipcpackreq(unsigned char[Ipcreqsz], int, uint32_t, uint32_t);
|
||||||
void ipcpackreset(unsigned char[Ipcreqsz], int);
|
void ipcpackreset(unsigned char[Ipcreqsz], int);
|
||||||
void ipcpackcap(unsigned char[Ipcreqsz], int);
|
void ipcpackcap(unsigned char[Ipcreqsz], int);
|
||||||
int ipcpackcaret(unsigned char[Ipccaretsz], int, int32_t, int32_t, int32_t);
|
void ipcpackcaret(unsigned char[Ipccaretsz], int, int32_t, int32_t, int32_t);
|
||||||
void ipcunpackreq(const unsigned char[Ipcreqsz], int*, uint32_t*, uint32_t*);
|
void ipcunpackreq(const unsigned char[Ipcreqsz], int*, uint32_t*, uint32_t*);
|
||||||
int ipcunpackcaret(const unsigned char[Ipccaretsz], int*, int32_t*, int32_t*, int32_t*);
|
int ipcunpackcaret(const unsigned char[Ipccaretsz], int*, int32_t*, int32_t*, int32_t*);
|
||||||
int ipcreqtype(const unsigned char[Ipcreqsz]);
|
int ipcreqtype(const unsigned char[Ipcreqsz]);
|
||||||
@@ -85,6 +86,6 @@ int ipcreqreset(const unsigned char[Ipcreqsz]);
|
|||||||
int ipcpackresp(unsigned char*, size_t, int, const char*, size_t, const char*, size_t, int);
|
int ipcpackresp(unsigned char*, size_t, int, const char*, size_t, const char*, size_t, int);
|
||||||
int ipcreadn(int, void*, size_t);
|
int ipcreadn(int, void*, size_t);
|
||||||
int ipcsend(int, const void*, size_t);
|
int ipcsend(int, const void*, size_t);
|
||||||
int ipcreadresp(int, int, char*, size_t, char*, size_t, Ipcresp*);
|
int ipcreadresp(int, int, char*, char*, Ipcresp*);
|
||||||
int ipcpath(char*, size_t);
|
int ipcpath(char*, size_t);
|
||||||
int ipcconnect(void);
|
int ipcconnect(void);
|
||||||
|
|||||||
17
main.c
17
main.c
@@ -61,17 +61,12 @@ threadmain(int argc, char **argv)
|
|||||||
mapinit(argv[1]);
|
mapinit(argv[1]);
|
||||||
dictinit(argv[1]);
|
dictinit(argv[1]);
|
||||||
srvinit();
|
srvinit();
|
||||||
if(proccreate(drawthread, nil, 16384) < 0)
|
proccreate(drawthread, nil, 16384);
|
||||||
die("can't create draw worker");
|
proccreate(srvthread, nil, 16384);
|
||||||
if(proccreate(srvthread, nil, 16384) < 0)
|
proccreate(ibusthread, nil, 32768);
|
||||||
die("can't create server worker");
|
|
||||||
if(proccreate(ibusthread, nil, 32768) < 0)
|
|
||||||
die("can't create IBus worker");
|
|
||||||
display = getenv("DISPLAY");
|
display = getenv("DISPLAY");
|
||||||
if(display != nil && display[0] != '\0' &&
|
if(display != nil && display[0] != '\0')
|
||||||
proccreate(ximthread, nil, 32768) < 0)
|
proccreate(ximthread, nil, 32768);
|
||||||
die("xim: cannot create worker");
|
threadcreate(dictthread, nil, 16384);
|
||||||
if(threadcreate(dictthread, nil, 16384) < 0)
|
|
||||||
die("can't create dictionary worker");
|
|
||||||
imthread(nil);
|
imthread(nil);
|
||||||
}
|
}
|
||||||
|
|||||||
85
srv.c
85
srv.c
@@ -11,98 +11,78 @@ static int
|
|||||||
srvreadreq(int fd, Keyreq *kr, int *want)
|
srvreadreq(int fd, Keyreq *kr, int *want)
|
||||||
{
|
{
|
||||||
uchar req[Ipccaretsz];
|
uchar req[Ipccaretsz];
|
||||||
int type, valid;
|
int valid;
|
||||||
int32_t x, y, h;
|
int32_t x, y, h;
|
||||||
u32int ks, mod;
|
|
||||||
|
|
||||||
if(ipcreadn(fd, req, Ipcreqsz) < 0)
|
if(ipcreadn(fd, req, Ipcreqsz) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
type = ipcreqtype(req);
|
*want = 0;
|
||||||
switch(type){
|
kr->ks = 0;
|
||||||
case Ipclegacy:
|
kr->mod = 0;
|
||||||
ipcunpackreq(req, want, &mod, &ks);
|
switch(ipcreqtype(req)){
|
||||||
|
case Ipckey:
|
||||||
|
ipcunpackreq(req, want, &kr->mod, &kr->ks);
|
||||||
kr->op = ipcreqreset(req) ? Keyreset : Keypress;
|
kr->op = ipcreqreset(req) ? Keyreset : Keypress;
|
||||||
kr->ks = ks;
|
return 0;
|
||||||
kr->mod = mod;
|
|
||||||
break;
|
|
||||||
case Ipccap:
|
case Ipccap:
|
||||||
*want = (req[0] & Ipcreqwant) != 0;
|
*want = (req[0] & Ipcreqwant) != 0;
|
||||||
kr->op = Keycap;
|
kr->op = Keycap;
|
||||||
kr->ks = 0;
|
return 0;
|
||||||
kr->mod = 0;
|
|
||||||
break;
|
|
||||||
case Ipccaret:
|
case Ipccaret:
|
||||||
if(ipcreadn(fd, req + Ipcreqsz, Ipccaretsz - Ipcreqsz) < 0 ||
|
if(ipcreadn(fd, req + Ipcreqsz, Ipccaretsz - Ipcreqsz) < 0 ||
|
||||||
ipcunpackcaret(req, &valid, &x, &y, &h) < 0)
|
ipcunpackcaret(req, &valid, &x, &y, &h) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
*want = 0;
|
|
||||||
kr->op = Keycaret;
|
kr->op = Keycaret;
|
||||||
kr->ks = 0;
|
|
||||||
kr->mod = 0;
|
|
||||||
kr->caret.valid = valid;
|
kr->caret.valid = valid;
|
||||||
kr->caret.x = x;
|
kr->caret.x = x;
|
||||||
kr->caret.y = y;
|
kr->caret.y = y;
|
||||||
kr->caret.h = h;
|
kr->caret.h = h;
|
||||||
break;
|
return 0;
|
||||||
default:
|
|
||||||
return -1;
|
|
||||||
}
|
}
|
||||||
return type;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* One Keyreq persists for the connection: the negotiated capability and
|
||||||
|
* the last caret ride along with every request, and the socket closing
|
||||||
|
* releases the engine.
|
||||||
|
*/
|
||||||
static void
|
static void
|
||||||
clientthread(void *arg)
|
clientthread(void *arg)
|
||||||
{
|
{
|
||||||
Channel *reply;
|
|
||||||
int fd;
|
|
||||||
Keyreq kr;
|
Keyreq kr;
|
||||||
Keyres res;
|
Keyres res;
|
||||||
Caret caret;
|
uchar out[Ipcmaxresp], token;
|
||||||
uchar out[Ipcmaxresp];
|
|
||||||
char commit[Maxutf], preedit[Maxutf];
|
char commit[Maxutf], preedit[Maxutf];
|
||||||
int cap, n, ncommit, negotiated, npreedit, type, want;
|
int fd, n, ncommit, npreedit, want;
|
||||||
uchar token;
|
|
||||||
|
|
||||||
fd = (int)(uintptr)arg;
|
fd = (int)(uintptr)arg;
|
||||||
threadsetname("client %d", fd);
|
threadsetname("client %d", fd);
|
||||||
reply = chancreate(sizeof(Keyres), 0);
|
memset(&kr, 0, sizeof kr);
|
||||||
kr.reply = reply;
|
kr.reply = chancreate(sizeof(Keyres), 0);
|
||||||
kr.owner = &fd;
|
kr.owner = &fd;
|
||||||
cap = Cclientpreedit;
|
kr.cap = Cclientpreedit;
|
||||||
negotiated = 0;
|
while(srvreadreq(fd, &kr, &want) >= 0){
|
||||||
memset(&caret, 0, sizeof caret);
|
if(kr.op != Keycaret)
|
||||||
kr.cap = cap;
|
kr.cap = want ? Cclientpreedit : 0;
|
||||||
kr.caret = caret;
|
|
||||||
while((type = srvreadreq(fd, &kr, &want)) >= 0){
|
|
||||||
if(type == Ipccap){
|
|
||||||
cap = want ? Cclientpreedit : 0;
|
|
||||||
negotiated = 1;
|
|
||||||
}else if(type == Ipclegacy && !negotiated)
|
|
||||||
cap = want ? Cclientpreedit : 0;
|
|
||||||
else if(type == Ipccaret)
|
|
||||||
caret = kr.caret;
|
|
||||||
kr.cap = cap;
|
|
||||||
kr.caret = caret;
|
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
chanrecv(reply, &res);
|
chanrecv(kr.reply, &res);
|
||||||
if(type == Ipccaret)
|
if(kr.op == Keycaret)
|
||||||
continue;
|
continue;
|
||||||
ncommit = stoutf(&res.commit, commit, sizeof commit);
|
ncommit = stoutf(&res.commit, commit, sizeof commit);
|
||||||
npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
|
npreedit = stoutf(&res.preedit, preedit, sizeof preedit);
|
||||||
n = ipcpackresp(out, sizeof out,
|
/* A capability reply is always eaten: it marks the extension. */
|
||||||
type == Ipccap ? 1 : res.eaten,
|
n = ipcpackresp(out, sizeof out, kr.op == Keycap || res.eaten,
|
||||||
commit, ncommit, preedit, npreedit, want);
|
commit, ncommit, preedit, npreedit, want);
|
||||||
if(n < 0 || ipcsend(fd, out, n) < 0)
|
if(n < 0 || ipcsend(fd, out, n) < 0)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
kr.op = Keyrelease;
|
kr.op = Keyrelease;
|
||||||
kr.cap = cap;
|
|
||||||
kr.caret = caret;
|
|
||||||
kr.ks = 0;
|
kr.ks = 0;
|
||||||
kr.mod = 0;
|
kr.mod = 0;
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
chanrecv(reply, &res);
|
chanrecv(kr.reply, &res);
|
||||||
chanfree(reply);
|
chanfree(kr.reply);
|
||||||
close(fd);
|
close(fd);
|
||||||
chanrecv(clientc, &token);
|
chanrecv(clientc, &token);
|
||||||
}
|
}
|
||||||
@@ -142,9 +122,6 @@ srvthread(void*)
|
|||||||
close(fd);
|
close(fd);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if(proccreate(clientthread, (void*)(uintptr)fd, 8192) < 0){
|
proccreate(clientthread, (void*)(uintptr)fd, 8192);
|
||||||
chanrecv(clientc, &token);
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ request(Server *s, int fd)
|
|||||||
e.type = Ecaret;
|
e.type = Ecaret;
|
||||||
record(s, &e);
|
record(s, &e);
|
||||||
return 1;
|
return 1;
|
||||||
case Ipclegacy:
|
case Ipckey:
|
||||||
ipcunpackreq(buf, &want, &mod, &key);
|
ipcunpackreq(buf, &want, &mod, &key);
|
||||||
e.want = want;
|
e.want = want;
|
||||||
e.key = key;
|
e.key = key;
|
||||||
@@ -854,9 +854,8 @@ main(int argc, char **argv)
|
|||||||
first = eventcount(&srv);
|
first = eventcount(&srv);
|
||||||
closes = closecount(&srv);
|
closes = closecount(&srv);
|
||||||
gtk_im_context_focus_out(ctx);
|
gtk_im_context_focus_out(ctx);
|
||||||
Check(waitcount(&srv, first + 1) && getevent(&srv, first).type == Ereset,
|
|
||||||
"focus-out reset missing");
|
|
||||||
Check(waitclose(&srv, closes + 1), "focus-out did not close connection");
|
Check(waitclose(&srv, closes + 1), "focus-out did not close connection");
|
||||||
|
Check(eventcount(&srv) == first, "focus-out sent a request before closing");
|
||||||
Check(strcmp(log.event, "CE") == 0, "focus-out clear order was %s", log.event);
|
Check(strcmp(log.event, "CE") == 0, "focus-out clear order was %s", log.event);
|
||||||
|
|
||||||
/* Dispose is repeatable, closes the connection, and emits no preedit. */
|
/* Dispose is repeatable, closes the connection, and emits no preedit. */
|
||||||
|
|||||||
@@ -48,13 +48,13 @@ ipc_masks_modifiers(struct ct *t)
|
|||||||
CT_CHECK(t, ipcreqreset(buf));
|
CT_CHECK(t, ipcreqreset(buf));
|
||||||
|
|
||||||
/* Frontends share one keysym and modifier mapping. */
|
/* Frontends share one keysym and modifier mapping. */
|
||||||
CT_EQ_UINT(t, 'a', ipckey('a', 'a'));
|
CT_EQ_UINT(t, 'a', ipckeysym('a', 'a'));
|
||||||
CT_EQ_UINT(t, '1', ipckey(0xffb1, '1')); /* KP_1 */
|
CT_EQ_UINT(t, '1', ipckeysym(0xffb1, '1')); /* KP_1 */
|
||||||
CT_EQ_UINT(t, Kret, ipckey(0xff0d, '\r'));
|
CT_EQ_UINT(t, Kret, ipckeysym(0xff0d, '\r'));
|
||||||
CT_EQ_UINT(t, Kback, ipckey(0xff08, 8));
|
CT_EQ_UINT(t, Kback, ipckeysym(0xff08, 8));
|
||||||
CT_EQ_UINT(t, Kspec + 0xff, ipckey(0xffff, 0x7f)); /* Delete */
|
CT_EQ_UINT(t, Kspec + 0xff, ipckeysym(0xffff, 0x7f)); /* Delete */
|
||||||
CT_EQ_UINT(t, 0x1f642, ipckey(0x101f642, 0x1f642));
|
CT_EQ_UINT(t, 0x1f642, ipckeysym(0x101f642, 0x1f642));
|
||||||
CT_EQ_UINT(t, 0, ipckey(0xfe03, 0)); /* ISO_Level3_Shift */
|
CT_EQ_UINT(t, 0, ipckeysym(0xfe03, 0)); /* ISO_Level3_Shift */
|
||||||
CT_EQ_UINT(t, Mshift|Mctrl, ipcmod(Mshift|Mctrl|(1<<1)|(1<<4)));
|
CT_EQ_UINT(t, Mshift|Mctrl, ipcmod(Mshift|Mctrl|(1<<1)|(1<<4)));
|
||||||
CT_EQ_UINT(t, Msuper, ipcmod(1<<6));
|
CT_EQ_UINT(t, Msuper, ipcmod(1<<6));
|
||||||
CT_EQ_UINT(t, Msuper, ipcmod(1<<26));
|
CT_EQ_UINT(t, Msuper, ipcmod(1<<26));
|
||||||
@@ -96,7 +96,7 @@ ipc_control_and_caret_frames(struct ct *t)
|
|||||||
CT_EQ_INT(t, 0, want);
|
CT_EQ_INT(t, 0, want);
|
||||||
CT_EQ_UINT(t, 0, key);
|
CT_EQ_UINT(t, 0, key);
|
||||||
|
|
||||||
CT_EQ_INT(t, 0, ipcpackcaret(buf, 1, -2, 0x01020304, 0x506));
|
ipcpackcaret(buf, 1, -2, 0x01020304, 0x506);
|
||||||
CT_EQ_MEM(t, caret, buf, sizeof caret);
|
CT_EQ_MEM(t, caret, buf, sizeof caret);
|
||||||
CT_EQ_INT(t, Ipccaret, ipcreqtype(buf));
|
CT_EQ_INT(t, Ipccaret, ipcreqtype(buf));
|
||||||
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h))){
|
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h))){
|
||||||
@@ -105,17 +105,16 @@ ipc_control_and_caret_frames(struct ct *t)
|
|||||||
CT_EQ_INT(t, 0x01020304, y);
|
CT_EQ_INT(t, 0x01020304, y);
|
||||||
CT_EQ_INT(t, 0x506, h);
|
CT_EQ_INT(t, 0x506, h);
|
||||||
}
|
}
|
||||||
CT_EQ_INT(t, 0, ipcpackcaret(buf, 1, INT32_MIN, INT32_MAX, 0));
|
ipcpackcaret(buf, 1, INT32_MIN, INT32_MAX, 0);
|
||||||
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h))){
|
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h))){
|
||||||
CT_EQ_INT(t, INT32_MIN, x);
|
CT_EQ_INT(t, INT32_MIN, x);
|
||||||
CT_EQ_INT(t, INT32_MAX, y);
|
CT_EQ_INT(t, INT32_MAX, y);
|
||||||
CT_EQ_INT(t, 0, h);
|
CT_EQ_INT(t, 0, h);
|
||||||
}
|
}
|
||||||
CT_EQ_INT(t, 0, ipcpackcaret(buf, 0, -2, 3, 4));
|
ipcpackcaret(buf, 0, -2, 3, 4);
|
||||||
CT_EQ_MEM(t, nocaret, buf, sizeof nocaret);
|
CT_EQ_MEM(t, nocaret, buf, sizeof nocaret);
|
||||||
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h)))
|
if(CT_EQ_INT(t, 0, ipcunpackcaret(buf, &valid, &x, &y, &h)))
|
||||||
CT_EQ_INT(t, 0, valid);
|
CT_EQ_INT(t, 0, valid);
|
||||||
CT_EQ_INT(t, -1, ipcpackcaret(buf, 1, 0, 0, -1));
|
|
||||||
|
|
||||||
memcpy(bad, caret, sizeof bad);
|
memcpy(bad, caret, sizeof bad);
|
||||||
bad[1]++;
|
bad[1]++;
|
||||||
@@ -139,9 +138,9 @@ ipc_control_and_caret_frames(struct ct *t)
|
|||||||
CT_EQ_INT(t, Ipcunknown, ipcreqtype(bad));
|
CT_EQ_INT(t, Ipcunknown, ipcreqtype(bad));
|
||||||
|
|
||||||
ipcpackreq(buf, 1, 0, 'a');
|
ipcpackreq(buf, 1, 0, 'a');
|
||||||
CT_EQ_INT(t, Ipclegacy, ipcreqtype(buf));
|
CT_EQ_INT(t, Ipckey, ipcreqtype(buf));
|
||||||
ipcpackreset(buf, 1);
|
ipcpackreset(buf, 1);
|
||||||
CT_EQ_INT(t, Ipclegacy, ipcreqtype(buf));
|
CT_EQ_INT(t, Ipckey, ipcreqtype(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@@ -162,7 +161,6 @@ ipc_runtime_path(struct ct *t)
|
|||||||
snprint(fallback, sizeof fallback, "/tmp/strans.%d", getuid());
|
snprint(fallback, sizeof fallback, "/tmp/strans.%d", getuid());
|
||||||
CT_EQ_STR(t, fallback, buf);
|
CT_EQ_STR(t, fallback, buf);
|
||||||
CT_EQ_INT(t, -1, ipcpath(buf, 4));
|
CT_EQ_INT(t, -1, ipcpath(buf, 4));
|
||||||
CT_EQ_INT(t, -1, ipcpath(nil, sizeof buf));
|
|
||||||
if(saved != nil){
|
if(saved != nil){
|
||||||
setenv("XDG_RUNTIME_DIR", saved, 1);
|
setenv("XDG_RUNTIME_DIR", saved, 1);
|
||||||
free(saved);
|
free(saved);
|
||||||
@@ -200,22 +198,18 @@ ipc_response_pack_boundaries(struct ct *t)
|
|||||||
CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1,
|
CT_EQ_INT(t, -1, ipcpackresp(out, Ipcmaxresp-1, 1,
|
||||||
(char*)field, sizeof field, (char*)field, sizeof field, 1));
|
(char*)field, sizeof field, (char*)field, sizeof field, 1));
|
||||||
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
|
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
|
||||||
nil, 1, nil, 0, 0));
|
(char*)field, Ipcfieldmax+1, "", 0, 0));
|
||||||
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
|
|
||||||
nil, 0, nil, 1, 1));
|
|
||||||
CT_EQ_INT(t, -1, ipcpackresp(out, sizeof out, 0,
|
|
||||||
(char*)field, Ipcfieldmax+1, nil, 0, 0));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ipc_response_empty_and_preedit(struct ct *t)
|
ipc_response_empty_and_preedit(struct ct *t)
|
||||||
{
|
{
|
||||||
uchar first[Ipcmaxresp], second[Ipcmaxresp];
|
uchar first[Ipcmaxresp], second[Ipcmaxresp];
|
||||||
char commit[16], preedit[16];
|
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
int fd[2], nfirst, nsecond;
|
int fd[2], nfirst, nsecond;
|
||||||
|
|
||||||
nfirst = ipcpackresp(first, sizeof first, 0, nil, 0, nil, 0, 0);
|
nfirst = ipcpackresp(first, sizeof first, 0, "", 0, "", 0, 0);
|
||||||
nsecond = ipcpackresp(second, sizeof second, 1,
|
nsecond = ipcpackresp(second, sizeof second, 1,
|
||||||
"go", 2, "kana", 4, 1);
|
"go", 2, "kana", 4, 1);
|
||||||
if(!CT_CHECK(t, nfirst > 0 && nsecond > 0))
|
if(!CT_CHECK(t, nfirst > 0 && nsecond > 0))
|
||||||
@@ -226,15 +220,13 @@ ipc_response_empty_and_preedit(struct ct *t)
|
|||||||
}
|
}
|
||||||
if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) &&
|
if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) &&
|
||||||
CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) &&
|
CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) &&
|
||||||
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit,
|
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, preedit, &resp))){
|
||||||
nil, 0, &resp))){
|
|
||||||
CT_EQ_INT(t, 0, resp.eaten);
|
CT_EQ_INT(t, 0, resp.eaten);
|
||||||
CT_EQ_SIZE(t, 0, resp.commitlen);
|
CT_EQ_SIZE(t, 0, resp.commitlen);
|
||||||
CT_EQ_SIZE(t, 0, resp.preeditlen);
|
CT_EQ_SIZE(t, 0, resp.preeditlen);
|
||||||
CT_EQ_STR(t, "", commit);
|
CT_EQ_STR(t, "", commit);
|
||||||
}
|
}
|
||||||
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, sizeof commit,
|
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, preedit, &resp))){
|
||||||
preedit, sizeof preedit, &resp))){
|
|
||||||
CT_EQ_INT(t, 1, resp.eaten);
|
CT_EQ_INT(t, 1, resp.eaten);
|
||||||
CT_EQ_SIZE(t, 2, resp.commitlen);
|
CT_EQ_SIZE(t, 2, resp.commitlen);
|
||||||
CT_EQ_SIZE(t, 4, resp.preeditlen);
|
CT_EQ_SIZE(t, 4, resp.preeditlen);
|
||||||
@@ -249,14 +241,14 @@ void
|
|||||||
ipc_response_max_and_drain(struct ct *t)
|
ipc_response_max_and_drain(struct ct *t)
|
||||||
{
|
{
|
||||||
uchar first[Ipcmaxresp], second[Ipcmaxresp], field[Ipcfieldmax];
|
uchar first[Ipcmaxresp], second[Ipcmaxresp], field[Ipcfieldmax];
|
||||||
char commit[8], preedit[8];
|
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
int fd[2], nfirst, nsecond;
|
int fd[2], nfirst, nsecond;
|
||||||
|
|
||||||
memset(field, 'x', sizeof field);
|
memset(field, 'x', sizeof field);
|
||||||
nfirst = ipcpackresp(first, sizeof first, 1,
|
nfirst = ipcpackresp(first, sizeof first, 1,
|
||||||
(char*)field, sizeof field, (char*)field, sizeof field, 1);
|
(char*)field, sizeof field, (char*)field, sizeof field, 1);
|
||||||
nsecond = ipcpackresp(second, sizeof second, 0, "ok", 2, nil, 0, 0);
|
nsecond = ipcpackresp(second, sizeof second, 0, "ok", 2, "", 0, 0);
|
||||||
if(!CT_CHECK(t, nfirst == Ipcmaxresp && nsecond > 0))
|
if(!CT_CHECK(t, nfirst == Ipcmaxresp && nsecond > 0))
|
||||||
return;
|
return;
|
||||||
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
if(socketpair(AF_UNIX, SOCK_STREAM, 0, fd) < 0){
|
||||||
@@ -265,15 +257,15 @@ ipc_response_max_and_drain(struct ct *t)
|
|||||||
}
|
}
|
||||||
if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) &&
|
if(CT_EQ_INT(t, 0, ipcsend(fd[0], first, nfirst)) &&
|
||||||
CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) &&
|
CT_EQ_INT(t, 0, ipcsend(fd[0], second, nsecond)) &&
|
||||||
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, sizeof commit,
|
CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, preedit, &resp))){
|
||||||
preedit, sizeof preedit, &resp))){
|
CT_EQ_SIZE(t, Ipcfieldmax, resp.commitlen);
|
||||||
CT_EQ_SIZE(t, sizeof commit - 1, resp.commitlen);
|
CT_EQ_SIZE(t, Ipcfieldmax, resp.preeditlen);
|
||||||
CT_EQ_SIZE(t, sizeof preedit - 1, resp.preeditlen);
|
CT_EQ_MEM(t, field, commit, Ipcfieldmax);
|
||||||
CT_EQ_STR(t, "xxxxxxx", commit);
|
CT_EQ_MEM(t, field, preedit, Ipcfieldmax);
|
||||||
CT_EQ_STR(t, "xxxxxxx", preedit);
|
CT_EQ_INT(t, 0, commit[Ipcfieldmax]);
|
||||||
|
CT_EQ_INT(t, 0, preedit[Ipcfieldmax]);
|
||||||
}
|
}
|
||||||
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, sizeof commit,
|
if(CT_EQ_INT(t, 0, ipcreadresp(fd[1], 0, commit, preedit, &resp)))
|
||||||
nil, 0, &resp)))
|
|
||||||
CT_EQ_STR(t, "ok", commit);
|
CT_EQ_STR(t, "ok", commit);
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
@@ -283,7 +275,7 @@ void
|
|||||||
ipc_response_fragmented_and_truncated(struct ct *t)
|
ipc_response_fragmented_and_truncated(struct ct *t)
|
||||||
{
|
{
|
||||||
uchar frame[Ipcmaxresp];
|
uchar frame[Ipcmaxresp];
|
||||||
char commit[8], preedit[8];
|
char commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
int fd[2], i, n;
|
int fd[2], i, n;
|
||||||
|
|
||||||
@@ -299,8 +291,8 @@ ipc_response_fragmented_and_truncated(struct ct *t)
|
|||||||
CT_ERRORF(t, "fragment send failed");
|
CT_ERRORF(t, "fragment send failed");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if(i == n && CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1,
|
if(i == n && CT_EQ_INT(t, 0, ipcreadresp(fd[1], 1, commit, preedit,
|
||||||
commit, sizeof commit, preedit, sizeof preedit, &resp))){
|
&resp))){
|
||||||
CT_EQ_STR(t, "abc", commit);
|
CT_EQ_STR(t, "abc", commit);
|
||||||
CT_EQ_STR(t, "xy", preedit);
|
CT_EQ_STR(t, "xy", preedit);
|
||||||
}
|
}
|
||||||
@@ -313,8 +305,7 @@ ipc_response_fragmented_and_truncated(struct ct *t)
|
|||||||
}
|
}
|
||||||
CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n-1));
|
CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n-1));
|
||||||
shutdown(fd[0], SHUT_WR);
|
shutdown(fd[0], SHUT_WR);
|
||||||
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, sizeof commit,
|
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, preedit, &resp));
|
||||||
preedit, sizeof preedit, &resp));
|
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
|
|
||||||
@@ -325,8 +316,7 @@ ipc_response_fragmented_and_truncated(struct ct *t)
|
|||||||
frame[0] = 2;
|
frame[0] = 2;
|
||||||
CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n));
|
CT_EQ_INT(t, 0, ipcsend(fd[0], frame, n));
|
||||||
errno = 0;
|
errno = 0;
|
||||||
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, sizeof commit,
|
CT_EQ_INT(t, -1, ipcreadresp(fd[1], 1, commit, preedit, &resp));
|
||||||
preedit, sizeof preedit, &resp));
|
|
||||||
CT_EQ_INT(t, EPROTO, errno);
|
CT_EQ_INT(t, EPROTO, errno);
|
||||||
close(fd[0]);
|
close(fd[0]);
|
||||||
close(fd[1]);
|
close(fd[1]);
|
||||||
@@ -351,7 +341,7 @@ ipc_broken_peer_send(struct ct *t)
|
|||||||
static void
|
static void
|
||||||
ipcclientdeadlines(struct ct *t)
|
ipcclientdeadlines(struct ct *t)
|
||||||
{
|
{
|
||||||
char fill[4096], commit[8];
|
char fill[4096], commit[Ipcfieldmax+1], preedit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
int fd[2];
|
int fd[2];
|
||||||
int64_t start, elapsed;
|
int64_t start, elapsed;
|
||||||
@@ -363,8 +353,7 @@ ipcclientdeadlines(struct ct *t)
|
|||||||
}
|
}
|
||||||
start = nowms();
|
start = nowms();
|
||||||
errno = 0;
|
errno = 0;
|
||||||
CT_EQ_INT(t, -1, ipcreadresp(fd[0], 0, commit, sizeof commit,
|
CT_EQ_INT(t, -1, ipcreadresp(fd[0], 0, commit, preedit, &resp));
|
||||||
nil, 0, &resp));
|
|
||||||
elapsed = nowms() - start;
|
elapsed = nowms() - start;
|
||||||
CT_EQ_INT(t, ETIMEDOUT, errno);
|
CT_EQ_INT(t, ETIMEDOUT, errno);
|
||||||
CT_CHECK(t, elapsed >= 0 && elapsed < 4*Ipcwaitms);
|
CT_CHECK(t, elapsed >= 0 && elapsed < 4*Ipcwaitms);
|
||||||
|
|||||||
@@ -169,13 +169,12 @@ allowrequest(Enginegate *g)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
readreply(struct ct *t, Testclient *client, int want, char *preedit, int npreedit)
|
readreply(struct ct *t, Testclient *client, int want, char *preedit)
|
||||||
{
|
{
|
||||||
char commit[Maxutf];
|
char commit[Ipcfieldmax+1];
|
||||||
Ipcresp resp;
|
Ipcresp resp;
|
||||||
|
|
||||||
if(ipcreadresp(client->peer, want, commit, sizeof commit,
|
if(ipcreadresp(client->peer, want, commit, preedit, &resp) < 0)
|
||||||
preedit, npreedit, &resp) < 0)
|
|
||||||
return CT_ERRORF(t, "response read failed: %s", strerror(errno));
|
return CT_ERRORF(t, "response read failed: %s", strerror(errno));
|
||||||
CT_EQ_STR(t, "", commit);
|
CT_EQ_STR(t, "", commit);
|
||||||
return resp.eaten;
|
return resp.eaten;
|
||||||
@@ -247,7 +246,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
Keyreq req;
|
Keyreq req;
|
||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
Str shown;
|
Str shown;
|
||||||
char preedit[Maxutf];
|
char preedit[Ipcfieldmax+1];
|
||||||
void *aowner, *bowner, *cowner;
|
void *aowner, *bowner, *cowner;
|
||||||
uchar byte, token;
|
uchar byte, token;
|
||||||
ssize_t n;
|
ssize_t n;
|
||||||
@@ -279,14 +278,14 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
aowner = req.owner;
|
aowner = req.owner;
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
if(!sendkey(t, &a, 1, 0, 'a'))
|
if(!sendkey(t, &a, 1, 0, 'a'))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "か", preedit);
|
CT_EQ_STR(t, "か", preedit);
|
||||||
CT_EQ_PTR(t, aowner, testengineowner());
|
CT_EQ_PTR(t, aowner, testengineowner());
|
||||||
|
|
||||||
@@ -296,7 +295,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
bowner = req.owner;
|
bowner = req.owner;
|
||||||
CT_CHECK(t, bowner != aowner);
|
CT_CHECK(t, bowner != aowner);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
||||||
CT_EQ_STR(t, "ん", preedit);
|
CT_EQ_STR(t, "ん", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
|
|
||||||
@@ -305,14 +304,14 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &gate, Keyreset);
|
req = nextrequest(t, &gate, Keyreset);
|
||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
if(!sendkey(t, &b, 1, 0, Kmodfirst))
|
if(!sendkey(t, &b, 1, 0, Kmodfirst))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, !readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_CHECK(t, !readreply(t, &b, 1, preedit));
|
||||||
CT_EQ_STR(t, "ん", preedit);
|
CT_EQ_STR(t, "ん", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &gate, &a, aowner);
|
disconnectclient(t, &gate, &a, aowner);
|
||||||
@@ -321,12 +320,12 @@ server_connection_ownership(struct ct *t)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
||||||
if(!sendkey(t, &b, 1, 0, 'a'))
|
if(!sendkey(t, &b, 1, 0, 'a'))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
||||||
CT_EQ_STR(t, "にゃ", preedit);
|
CT_EQ_STR(t, "にゃ", preedit);
|
||||||
|
|
||||||
if(!sendreset(t, &b, 1))
|
if(!sendreset(t, &b, 1))
|
||||||
@@ -334,7 +333,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequest(t, &gate, Keyreset);
|
req = nextrequest(t, &gate, Keyreset);
|
||||||
CT_EQ_PTR(t, bowner, req.owner);
|
CT_EQ_PTR(t, bowner, req.owner);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
CT_EQ_PTR(t, bowner, testengineowner());
|
CT_EQ_PTR(t, bowner, testengineowner());
|
||||||
|
|
||||||
@@ -343,7 +342,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
req = nextrequestcap(t, &gate, Keypress, 0);
|
req = nextrequestcap(t, &gate, Keypress, 0);
|
||||||
CT_EQ_PTR(t, bowner, req.owner);
|
CT_EQ_PTR(t, bowner, req.owner);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &b, 0, nil, 0));
|
CT_CHECK(t, readreply(t, &b, 0, preedit));
|
||||||
errno = 0;
|
errno = 0;
|
||||||
n = recv(b.peer, &byte, 1, MSG_PEEK|MSG_DONTWAIT);
|
n = recv(b.peer, &byte, 1, MSG_PEEK|MSG_DONTWAIT);
|
||||||
CT_EQ_INT(t, -1, n);
|
CT_EQ_INT(t, -1, n);
|
||||||
@@ -353,7 +352,7 @@ server_connection_ownership(struct ct *t)
|
|||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_CHECK(t, readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_CHECK(t, readreply(t, &b, 1, preedit));
|
||||||
CT_EQ_STR(t, "か", preedit);
|
CT_EQ_STR(t, "か", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &gate, &b, bowner);
|
disconnectclient(t, &gate, &b, bowner);
|
||||||
@@ -410,7 +409,7 @@ server_extension_stream(struct ct *t)
|
|||||||
Keyreq req;
|
Keyreq req;
|
||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
uchar frame[Ipccaretsz], token;
|
uchar frame[Ipccaretsz], token;
|
||||||
char preedit[Maxutf];
|
char preedit[Ipcfieldmax+1];
|
||||||
void *aowner, *bowner;
|
void *aowner, *bowner;
|
||||||
int gateactive;
|
int gateactive;
|
||||||
|
|
||||||
@@ -442,10 +441,10 @@ server_extension_stream(struct ct *t)
|
|||||||
aowner = req.owner;
|
aowner = req.owner;
|
||||||
CT_EQ_PTR(t, nil, testengineowner());
|
CT_EQ_PTR(t, nil, testengineowner());
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
|
|
||||||
CT_EQ_INT(t, 0, ipcpackcaret(frame, 1, -101, -7, 23));
|
ipcpackcaret(frame, 1, -101, -7, 23);
|
||||||
if(!sendframe(t, &a, frame, Ipccaretsz, 1))
|
if(!sendframe(t, &a, frame, Ipccaretsz, 1))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keycaret);
|
req = nextrequest(t, &gate, Keycaret);
|
||||||
@@ -468,7 +467,7 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_INT(t, -7, req.caret.y);
|
CT_EQ_INT(t, -7, req.caret.y);
|
||||||
CT_EQ_INT(t, 23, req.caret.h);
|
CT_EQ_INT(t, 23, req.caret.h);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
CT_EQ_PTR(t, aowner, testengineowner());
|
CT_EQ_PTR(t, aowner, testengineowner());
|
||||||
|
|
||||||
@@ -479,7 +478,7 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_PTR(t, aowner, req.owner);
|
CT_EQ_PTR(t, aowner, req.owner);
|
||||||
CT_EQ_INT(t, 1, req.caret.valid);
|
CT_EQ_INT(t, 1, req.caret.valid);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 0, nil, 0));
|
CT_EQ_INT(t, 1, readreply(t, &a, 0, preedit));
|
||||||
|
|
||||||
/* Reset is still the old six-byte frame and does not discard caret. */
|
/* Reset is still the old six-byte frame and does not discard caret. */
|
||||||
ipcpackreset(frame, 0);
|
ipcpackreset(frame, 0);
|
||||||
@@ -492,14 +491,14 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_INT(t, -7, req.caret.y);
|
CT_EQ_INT(t, -7, req.caret.y);
|
||||||
CT_EQ_INT(t, 23, req.caret.h);
|
CT_EQ_INT(t, 23, req.caret.h);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 0, nil, 0));
|
CT_EQ_INT(t, 1, readreply(t, &a, 0, preedit));
|
||||||
|
|
||||||
ipcpackcap(frame, Cclientpreedit);
|
ipcpackcap(frame, Cclientpreedit);
|
||||||
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
req = nextrequest(t, &gate, Keycap);
|
req = nextrequest(t, &gate, Keycap);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "", preedit);
|
CT_EQ_STR(t, "", preedit);
|
||||||
ipcpackreq(frame, 1, 0, 'n');
|
ipcpackreq(frame, 1, 0, 'n');
|
||||||
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
if(!sendframe(t, &a, frame, Ipcreqsz, 0))
|
||||||
@@ -508,7 +507,7 @@ server_extension_stream(struct ct *t)
|
|||||||
CT_EQ_INT(t, 1, req.caret.valid);
|
CT_EQ_INT(t, 1, req.caret.valid);
|
||||||
CT_EQ_INT(t, -101, req.caret.x);
|
CT_EQ_INT(t, -101, req.caret.x);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit, sizeof preedit));
|
CT_EQ_INT(t, 1, readreply(t, &a, 1, preedit));
|
||||||
CT_EQ_STR(t, "ん", preedit);
|
CT_EQ_STR(t, "ん", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &gate, &a, aowner);
|
disconnectclient(t, &gate, &a, aowner);
|
||||||
@@ -520,7 +519,7 @@ server_extension_stream(struct ct *t)
|
|||||||
bowner = req.owner;
|
bowner = req.owner;
|
||||||
CT_EQ_INT(t, 0, req.caret.valid);
|
CT_EQ_INT(t, 0, req.caret.valid);
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &b, 1, preedit, sizeof preedit));
|
CT_EQ_INT(t, 1, readreply(t, &b, 1, preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
|
|
||||||
disconnectclient(t, &gate, &b, bowner);
|
disconnectclient(t, &gate, &b, bowner);
|
||||||
@@ -554,7 +553,7 @@ server_rejects_unknown_extension(struct ct *t)
|
|||||||
Keyreq req;
|
Keyreq req;
|
||||||
Drawcmd dc;
|
Drawcmd dc;
|
||||||
uchar frame[Ipccaretsz], token;
|
uchar frame[Ipccaretsz], token;
|
||||||
char preedit[Maxutf];
|
char preedit[Ipcfieldmax+1];
|
||||||
void *owner;
|
void *owner;
|
||||||
int gateactive;
|
int gateactive;
|
||||||
|
|
||||||
@@ -580,7 +579,7 @@ server_rejects_unknown_extension(struct ct *t)
|
|||||||
|
|
||||||
if(!startclient(t, &badver))
|
if(!startclient(t, &badver))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
CT_EQ_INT(t, 0, ipcpackcaret(frame, 1, 3, 4, 5));
|
ipcpackcaret(frame, 1, 3, 4, 5);
|
||||||
frame[1]++;
|
frame[1]++;
|
||||||
if(!sendframe(t, &badver, frame, sizeof frame, 0))
|
if(!sendframe(t, &badver, frame, sizeof frame, 0))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -592,7 +591,7 @@ server_rejects_unknown_extension(struct ct *t)
|
|||||||
|
|
||||||
if(!startclient(t, &badop))
|
if(!startclient(t, &badop))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
CT_EQ_INT(t, 0, ipcpackcaret(frame, 1, 3, 4, 5));
|
ipcpackcaret(frame, 1, 3, 4, 5);
|
||||||
frame[2]++;
|
frame[2]++;
|
||||||
if(!sendframe(t, &badop, frame, sizeof frame, 1))
|
if(!sendframe(t, &badop, frame, sizeof frame, 1))
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
@@ -608,7 +607,7 @@ server_rejects_unknown_extension(struct ct *t)
|
|||||||
req = nextrequest(t, &gate, Keypress);
|
req = nextrequest(t, &gate, Keypress);
|
||||||
owner = req.owner;
|
owner = req.owner;
|
||||||
allowrequest(&gate);
|
allowrequest(&gate);
|
||||||
CT_EQ_INT(t, 1, readreply(t, &good, 1, preedit, sizeof preedit));
|
CT_EQ_INT(t, 1, readreply(t, &good, 1, preedit));
|
||||||
CT_EQ_STR(t, "k", preedit);
|
CT_EQ_STR(t, "k", preedit);
|
||||||
disconnectclient(t, &gate, &good, owner);
|
disconnectclient(t, &gate, &good, owner);
|
||||||
|
|
||||||
|
|||||||
@@ -555,7 +555,7 @@ kpress(Ic *state, xcb_key_press_event_t *ev)
|
|||||||
int n, wasvalid;
|
int n, wasvalid;
|
||||||
|
|
||||||
key = keymaplookup(kstate, ev->detail, ev->state);
|
key = keymaplookup(kstate, ev->detail, ev->state);
|
||||||
key = ipckey(key, xkb_keysym_to_utf32(key));
|
key = ipckeysym(key, xkb_keysym_to_utf32(key));
|
||||||
if(meaningful(key)){
|
if(meaningful(key)){
|
||||||
wasvalid = state->caret.valid;
|
wasvalid = state->caret.valid;
|
||||||
refreshplace(state);
|
refreshplace(state);
|
||||||
|
|||||||
Reference in New Issue
Block a user