xim: clear callback preedit on owner loss
This commit is contained in:
139
xim/xim.c
139
xim/xim.c
@@ -1,6 +1,10 @@
|
||||
#include "dat.h"
|
||||
#include "fn.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <xcb/xcb.h>
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include <xcb-imdkit/imdkit.h>
|
||||
@@ -52,6 +56,7 @@ static Ic *ics;
|
||||
static Ic *preowner;
|
||||
static Clientenc clientenc[Maxclients];
|
||||
static Channel *replyc;
|
||||
static int wakefd[2] = {-1, -1};
|
||||
|
||||
static char *encs[] = {"COMPOUND_TEXT", "UTF8_STRING"};
|
||||
static u32int styles[] = {
|
||||
@@ -75,6 +80,71 @@ stylecap(u32int style, int *cap)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
wakeinit(void)
|
||||
{
|
||||
int fd[2];
|
||||
int flags, i;
|
||||
|
||||
if(wakefd[0] >= 0)
|
||||
return 0;
|
||||
if(pipe(fd) < 0)
|
||||
return -1;
|
||||
for(i = 0; i < nelem(fd); i++){
|
||||
flags = fcntl(fd[i], F_GETFL);
|
||||
if(flags < 0 || fcntl(fd[i], F_SETFL,
|
||||
flags | O_NONBLOCK) < 0)
|
||||
goto fail;
|
||||
flags = fcntl(fd[i], F_GETFD);
|
||||
if(flags < 0 || fcntl(fd[i], F_SETFD,
|
||||
flags | FD_CLOEXEC) < 0)
|
||||
goto fail;
|
||||
}
|
||||
wakefd[0] = fd[0];
|
||||
wakefd[1] = fd[1];
|
||||
return 0;
|
||||
fail:
|
||||
close(fd[0]);
|
||||
close(fd[1]);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* imthread only leaves a wake token; XIM ownership stays on the XIM thread. */
|
||||
void
|
||||
ximownernotify(void)
|
||||
{
|
||||
uchar token;
|
||||
int n;
|
||||
|
||||
if(wakefd[1] < 0)
|
||||
return;
|
||||
token = 0;
|
||||
do
|
||||
n = write(wakefd[1], &token, 1);
|
||||
while(n < 0 && errno == EINTR);
|
||||
/* EAGAIN means a pending byte will already wake the XIM poll loop. */
|
||||
}
|
||||
|
||||
static int
|
||||
wakedrain(void)
|
||||
{
|
||||
uchar buf[32];
|
||||
int n, total;
|
||||
|
||||
total = 0;
|
||||
for(;;){
|
||||
n = read(wakefd[0], buf, sizeof buf);
|
||||
if(n > 0){
|
||||
total += n;
|
||||
continue;
|
||||
}
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
static int
|
||||
getencoding(xcb_im_client_t *client)
|
||||
{
|
||||
@@ -272,11 +342,9 @@ place(Ic *state)
|
||||
nwin = 1;
|
||||
if(state->clientwin != state->focuswin)
|
||||
win[nwin++] = state->clientwin;
|
||||
if(state->hasspot)
|
||||
for(i = 0; i < nwin; i++)
|
||||
if(translate(win[i], state->spot.x, state->spot.y,
|
||||
&state->caret))
|
||||
return;
|
||||
if(state->hasspot && translate(state->focuswin,
|
||||
state->spot.x, state->spot.y, &state->caret))
|
||||
return;
|
||||
for(i = 0; i < nwin; i++)
|
||||
if(placebottom(state, win[i]))
|
||||
return;
|
||||
@@ -395,6 +463,25 @@ sendrequest(Ic *state, int op, u32int key, u32int mod, Keyres *res)
|
||||
chanrecv(replyc, res);
|
||||
}
|
||||
|
||||
static void
|
||||
checkpreowner(void)
|
||||
{
|
||||
Keyres res;
|
||||
|
||||
if(preowner == nil)
|
||||
return;
|
||||
sendrequest(preowner, Keycap, 0, 0, &res);
|
||||
if(!res.eaten)
|
||||
clearpreedit(preowner);
|
||||
}
|
||||
|
||||
static void
|
||||
checkownerwake(void)
|
||||
{
|
||||
if(wakedrain() > 0)
|
||||
checkpreowner();
|
||||
}
|
||||
|
||||
static void
|
||||
keypress(Ic *state, u32int key, u32int mod, Keyres *res)
|
||||
{
|
||||
@@ -611,6 +698,10 @@ ximinit(void)
|
||||
ximlog("cannot create reply channel");
|
||||
return -1;
|
||||
}
|
||||
if(wakeinit() < 0){
|
||||
ximlog("cannot create owner wake pipe");
|
||||
return -1;
|
||||
}
|
||||
st.nStyles = nelem(styles);
|
||||
st.styles = styles;
|
||||
enc.nEncodings = nelem(encs);
|
||||
@@ -653,8 +744,10 @@ ximinit(void)
|
||||
void
|
||||
ximthread(void *arg)
|
||||
{
|
||||
struct pollfd pfd[2];
|
||||
xcb_generic_event_t *ev;
|
||||
uint8_t type;
|
||||
int fd, n;
|
||||
|
||||
USED(arg);
|
||||
threadsetname("xim");
|
||||
@@ -662,17 +755,35 @@ ximthread(void *arg)
|
||||
ximclose();
|
||||
return;
|
||||
}
|
||||
fd = xcb_get_file_descriptor(conn);
|
||||
pfd[0].fd = fd;
|
||||
pfd[0].events = POLLIN;
|
||||
pfd[1].fd = wakefd[0];
|
||||
pfd[1].events = POLLIN;
|
||||
for(;;){
|
||||
ev = xcb_wait_for_event(conn);
|
||||
if(ev == nil)
|
||||
pfd[0].revents = pfd[1].revents = 0;
|
||||
n = poll(pfd, nelem(pfd), -1);
|
||||
if(n < 0){
|
||||
if(errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
if(pfd[1].revents & POLLIN)
|
||||
checkownerwake();
|
||||
if(pfd[0].revents)
|
||||
while((ev = xcb_poll_for_event(conn)) != nil){
|
||||
type = ev->response_type & ~0x80;
|
||||
if(type == XCB_MAPPING_NOTIFY){
|
||||
if(kinit() < 0)
|
||||
ximlog("cannot refresh keyboard mapping");
|
||||
}else
|
||||
xcb_im_filter_event(xim, ev);
|
||||
free(ev);
|
||||
/* Ownership changes outrank the next queued X event. */
|
||||
checkownerwake();
|
||||
}
|
||||
if(pfd[0].revents & (POLLERR|POLLHUP|POLLNVAL))
|
||||
break;
|
||||
type = ev->response_type & ~0x80;
|
||||
if(type == XCB_MAPPING_NOTIFY){
|
||||
if(kinit() < 0)
|
||||
ximlog("cannot refresh keyboard mapping");
|
||||
}else
|
||||
xcb_im_filter_event(xim, ev);
|
||||
free(ev);
|
||||
}
|
||||
if(xcb_connection_has_error(conn))
|
||||
ximlog("X server disconnected");
|
||||
|
||||
Reference in New Issue
Block a user