ibus: make context release explicit

This commit is contained in:
2026-08-13 22:03:27 +09:00
parent b6a9ccd9d9
commit 367cbb6cc3
5 changed files with 92 additions and 22 deletions

33
ibus.c
View File

@@ -19,12 +19,6 @@ enum
Ibussupermask = 1<<26,
};
typedef struct Watch Watch;
struct Watch
{
DBusWatch *w;
};
typedef struct Ictx Ictx;
struct Ictx
{
@@ -34,7 +28,7 @@ struct Ictx
Caret caret;
};
static Watch watches[Maxwatches];
static DBusWatch *watches[Maxwatches];
static int nwatches;
static DBusConnection *conns[Maxconns];
static int nconns;
@@ -205,13 +199,13 @@ addwatch(DBusWatch *w, void *_)
USED(_);
for(i = 0; i < nwatches; i++)
if(watches[i].w == nil){
watches[i].w = w;
if(watches[i] == nil){
watches[i] = w;
return TRUE;
}
if(nwatches >= Maxwatches)
return FALSE;
watches[nwatches++].w = w;
watches[nwatches++] = w;
return TRUE;
}
@@ -222,8 +216,8 @@ removewatch(DBusWatch *w, void *_)
USED(_);
for(i = 0; i < nwatches; i++)
if(watches[i].w == w){
watches[i].w = nil;
if(watches[i] == w){
watches[i] = nil;
return;
}
}
@@ -309,11 +303,10 @@ releasecontext(Ictx *ctx)
{
Keyres res;
if(replyc != nil)
if(ctx->focused)
sendrequest(ctx, Keyrelease, 0, 0, &res);
ctx->focused = 0;
memset(&ctx->caret, 0, sizeof ctx->caret);
}
static void
@@ -752,17 +745,17 @@ ibusthread(void *_)
for(;;){
n = 0;
for(i = 0; i < nwatches && n < Maxwatches; i++){
if(watches[i].w == nil)
if(watches[i] == nil)
continue;
if(!dbus_watch_get_enabled(watches[i].w))
if(!dbus_watch_get_enabled(watches[i]))
continue;
pfds[n].fd = dbus_watch_get_unix_fd(watches[i].w);
pfds[n].fd = dbus_watch_get_unix_fd(watches[i]);
pfds[n].events = 0;
f = dbus_watch_get_flags(watches[i].w);
f = dbus_watch_get_flags(watches[i]);
if(f & DBUS_WATCH_READABLE) pfds[n].events |= POLLIN;
if(f & DBUS_WATCH_WRITABLE) pfds[n].events |= POLLOUT;
wi[n] = i;
polled[n] = watches[i].w;
polled[n] = watches[i];
n++;
}
rv = poll(pfds, n, 200);
@@ -771,7 +764,7 @@ ibusthread(void *_)
for(i = 0; i < n; i++){
if(pfds[i].revents == 0)
continue;
if(watches[wi[i]].w != polled[i])
if(watches[wi[i]] != polled[i])
continue;
f = 0;
if(pfds[i].revents & POLLIN) f |= DBUS_WATCH_READABLE;

View File

@@ -3,12 +3,14 @@ LD = 9l
CFLAGS = -std=c99 -Wall -Wextra -O2 -g -I.. -I../cutest
FT_CFLAGS = $(shell pkg-config --cflags freetype2)
FT_LIBS = $(shell pkg-config --libs freetype2)
LIBS = -lthread -lbio $(FT_LIBS)
IBUS_CFLAGS = $(shell pkg-config --cflags dbus-1 xkbcommon)
IBUS_LIBS = $(shell pkg-config --libs dbus-1 xkbcommon)
LIBS = -lthread -lbio $(FT_LIBS) $(IBUS_LIBS)
PROG = unit_test
TESTSRC = unit_test.c test_util.c str_test.c hash_test.c trie_test.c \
ko_test.c vi_test.c engine_test.c dict_test.c ipc_test.c \
popup_test.c font_test.c
popup_test.c font_test.c ibus_test.c
TESTOBJ = $(TESTSRC:.c=.o)
PARENTSRC = str.c hash.c trie.c dict.c ko.c vi.c ipc.c popup_layout.c \
font.c
@@ -25,6 +27,8 @@ $(PROG): $(OBJS)
$(TESTOBJ): test.h ../dat.h ../fn.h ../ipc.h ../cutest/cutest.h
engine_test.o: ../strans.c
ibus_test.o: CFLAGS += $(IBUS_CFLAGS)
ibus_test.o: ../ibus.c
unit_font.o: CFLAGS += $(FT_CFLAGS)
unit_%.o: ../%.c ../dat.h ../fn.h ../ipc.h

71
tests/ibus_test.c Normal file
View File

@@ -0,0 +1,71 @@
#include "../ibus.c"
#include "../cutest/cutest.h"
void
ibus_context_lifecycle(struct ct *t)
{
Channel *oldkeyc, *oldreplyc;
DBusConnection *c1, *c2;
Ictx *a, *b;
Keyreq req;
Keyres res;
oldkeyc = keyc;
oldreplyc = replyc;
keyc = chancreate(sizeof(Keyreq), 2);
replyc = chancreate(sizeof(Keyres), 2);
memset(contexts, 0, sizeof contexts);
c1 = malloc(1);
c2 = malloc(1);
if(!CT_CHECK(t, c1 != nil && c2 != nil))
goto cleanup;
a = newcontext(c1, "/context/one");
b = newcontext(c2, "/context/one");
if(!CT_CHECK(t, a != nil && b != nil && a != b))
goto cleanup;
CT_EQ_PTR(t, a, findcontext(c1, "/context/one"));
CT_EQ_PTR(t, b, findcontext(c2, "/context/one"));
CT_EQ_PTR(t, nil, findcontext(c1, "/context/missing"));
a->caret.valid = 1;
releasecontext(a);
CT_CHECK(t, channbrecv(keyc, &req) <= 0);
CT_CHECK(t, !a->caret.valid);
a->focused = 1;
a->caret.valid = 1;
memset(&res, 0, sizeof res);
chansend(replyc, &res);
releasecontext(a);
if(CT_CHECK(t, channbrecv(keyc, &req) > 0)){
CT_EQ_PTR(t, a, req.owner);
CT_EQ_INT(t, Keyrelease, req.op);
CT_EQ_PTR(t, replyc, req.reply);
}
CT_CHECK(t, !a->focused);
CT_CHECK(t, !a->caret.valid);
releasecontext(a);
CT_CHECK(t, channbrecv(keyc, &req) <= 0);
dropcontext(a);
CT_CHECK(t, channbrecv(keyc, &req) <= 0);
CT_EQ_PTR(t, nil, findcontext(c1, "/context/one"));
CT_EQ_PTR(t, a, newcontext(c1, "/context/reused"));
b->focused = 1;
chansend(replyc, &res);
dropcontext(b);
if(CT_CHECK(t, channbrecv(keyc, &req) > 0)){
CT_EQ_PTR(t, b, req.owner);
CT_EQ_INT(t, Keyrelease, req.op);
}
CT_EQ_PTR(t, nil, findcontext(c2, "/context/one"));
cleanup:
memset(contexts, 0, sizeof contexts);
free(c1);
free(c2);
chanfree(keyc);
chanfree(replyc);
keyc = oldkeyc;
replyc = oldreplyc;
}

View File

@@ -70,3 +70,4 @@ void ipc_response_empty_and_preedit(struct ct*);
void ipc_response_max_and_drain(struct ct*);
void ipc_response_fragmented_and_truncated(struct ct*);
void ipc_broken_peer_send(struct ct*);
void ibus_context_lifecycle(struct ct*);

View File

@@ -124,6 +124,7 @@ static const struct ct_test tests[] = {
{ "ipc/response-max-drain", ipc_response_max_and_drain },
{ "ipc/response-fragmented-truncated", ipc_response_fragmented_and_truncated },
{ "ipc/broken-peer-send", ipc_broken_peer_send },
{ "ibus/context-lifecycle", ibus_context_lifecycle },
};
void