ibus: support modern client preedit
This commit is contained in:
@@ -10,13 +10,15 @@ GTK_CFLAGS = $(shell pkg-config --cflags gtk+-3.0)
|
||||
GTK_LIBS = $(shell pkg-config --libs gtk+-3.0)
|
||||
IBUS_CFLAGS = $(shell pkg-config --cflags dbus-1 xkbcommon)
|
||||
IBUS_LIBS = $(shell pkg-config --libs dbus-1 xkbcommon)
|
||||
IBUS_CLIENT_CFLAGS = $(shell pkg-config --cflags ibus-1.0)
|
||||
IBUS_CLIENT_LIBS = $(shell pkg-config --libs ibus-1.0)
|
||||
XIM_CFLAGS = $(shell pkg-config --cflags xcb-imdkit xkbcommon)
|
||||
XIM_LIBS = $(shell pkg-config --libs xcb-imdkit xkbcommon)
|
||||
LIBS = -lthread -lbio $(TEXT_LIBS) $(IBUS_LIBS) $(XIM_LIBS)
|
||||
|
||||
PROG = unit_test
|
||||
LIVE = ibus_live_test gtk_live_test ipc_live_test daemon_collision_test daemon_failure_test \
|
||||
daemon_restart_test
|
||||
LIVE = ibus_live_test ibus_client_smoke gtk_live_test ipc_live_test \
|
||||
daemon_collision_test daemon_failure_test daemon_restart_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 ibus_test.c server_test.c xim_adapter_test.c
|
||||
@@ -31,7 +33,7 @@ all: $(PROG) $(LIVE)
|
||||
|
||||
check test: $(PROG) $(LIVE)
|
||||
./$(PROG) $(TESTARGS)
|
||||
./ibus_live_test ../strans ../map
|
||||
./ibus_live_test ../strans ../map ./ibus_client_smoke
|
||||
./gtk_live_test ../gtk/im-strans.so
|
||||
./ipc_live_test ../strans ../map
|
||||
./daemon_collision_test ../strans ../map
|
||||
@@ -44,6 +46,10 @@ $(PROG): $(OBJS)
|
||||
ibus_live_test: ibus_live_test.c
|
||||
$(HOSTCC) -std=c99 -Wall -Wextra -O2 -g $(DBUS_CFLAGS) -o $@ $< $(DBUS_LIBS)
|
||||
|
||||
ibus_client_smoke: ibus_client_smoke.c
|
||||
$(HOSTCC) -std=c99 -Wall -Wextra -O2 -g $(IBUS_CLIENT_CFLAGS) -o $@ $< \
|
||||
$(IBUS_CLIENT_LIBS)
|
||||
|
||||
gtk_live_test: gtk_live_test.c ../ipc.c ../ipc.h
|
||||
$(HOSTCC) -std=c99 -Wall -Wextra -O2 -g -I.. $(GTK_CFLAGS) -o $@ \
|
||||
gtk_live_test.c ../ipc.c $(GTK_LIBS) -pthread
|
||||
|
||||
154
tests/ibus_client_smoke.c
Normal file
154
tests/ibus_client_smoke.c
Normal file
@@ -0,0 +1,154 @@
|
||||
#define _POSIX_C_SOURCE 200809L
|
||||
#include <ibus.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
typedef struct Log Log;
|
||||
struct Log
|
||||
{
|
||||
GMainLoop *loop;
|
||||
int want;
|
||||
int legacy;
|
||||
int modern;
|
||||
int invalid;
|
||||
int sawtext;
|
||||
int sawempty;
|
||||
};
|
||||
|
||||
static void
|
||||
legacy(IBusInputContext *ctx, IBusText *text, guint cursor,
|
||||
gboolean visible, void *arg)
|
||||
{
|
||||
Log *log;
|
||||
|
||||
(void)ctx;
|
||||
(void)text;
|
||||
(void)cursor;
|
||||
(void)visible;
|
||||
log = arg;
|
||||
log->legacy++;
|
||||
}
|
||||
|
||||
static void
|
||||
modern(IBusInputContext *ctx, IBusText *text, guint cursor,
|
||||
gboolean visible, guint mode, void *arg)
|
||||
{
|
||||
IBusAttrList *attrs;
|
||||
IBusAttribute *a;
|
||||
Log *log;
|
||||
const char *s;
|
||||
|
||||
(void)ctx;
|
||||
log = arg;
|
||||
log->modern++;
|
||||
s = ibus_text_get_text(text);
|
||||
attrs = ibus_text_get_attributes(text);
|
||||
a = ibus_attr_list_get(attrs, 0);
|
||||
if(s[0] != '\0'){
|
||||
if(strcmp(s, "k") != 0 || cursor != 1 || !visible ||
|
||||
mode != IBUS_ENGINE_PREEDIT_CLEAR || a == NULL ||
|
||||
a->type != IBUS_ATTR_TYPE_UNDERLINE ||
|
||||
a->value != IBUS_ATTR_UNDERLINE_SINGLE ||
|
||||
a->start_index != 0 || a->end_index != 1 ||
|
||||
ibus_attr_list_get(attrs, 1) != NULL)
|
||||
log->invalid = 1;
|
||||
else
|
||||
log->sawtext = 1;
|
||||
}else{
|
||||
if(cursor != 0 || visible || mode != IBUS_ENGINE_PREEDIT_CLEAR ||
|
||||
a != NULL)
|
||||
log->invalid = 1;
|
||||
else
|
||||
log->sawempty = 1;
|
||||
}
|
||||
if(log->loop != NULL && log->modern >= log->want)
|
||||
g_main_loop_quit(log->loop);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
timeout(void *arg)
|
||||
{
|
||||
g_main_loop_quit(arg);
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
static int
|
||||
waitmodern(Log *log, int want)
|
||||
{
|
||||
guint timer;
|
||||
|
||||
log->want = want;
|
||||
if(log->modern >= want)
|
||||
return 1;
|
||||
log->loop = g_main_loop_new(NULL, FALSE);
|
||||
timer = g_timeout_add_seconds(4, timeout, log->loop);
|
||||
g_main_loop_run(log->loop);
|
||||
if(g_main_context_find_source_by_id(NULL, timer) != NULL)
|
||||
g_source_remove(timer);
|
||||
g_main_loop_unref(log->loop);
|
||||
log->loop = NULL;
|
||||
return log->modern >= want;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
IBusBus *bus;
|
||||
IBusInputContext *ctx;
|
||||
Log log;
|
||||
int ok;
|
||||
|
||||
if(argc != 2){
|
||||
fprintf(stderr, "usage: ibus_client_smoke address\n");
|
||||
return 2;
|
||||
}
|
||||
if(setenv("IBUS_ADDRESS", argv[1], 1) < 0 ||
|
||||
unsetenv("DBUS_SESSION_BUS_ADDRESS") < 0 || unsetenv("DISPLAY") < 0){
|
||||
perror("ibus_client_smoke: environment");
|
||||
return 1;
|
||||
}
|
||||
memset(&log, 0, sizeof log);
|
||||
ibus_init();
|
||||
bus = ibus_bus_new();
|
||||
if(bus == NULL || !ibus_bus_is_connected(bus)){
|
||||
fprintf(stderr, "ibus_client_smoke: cannot connect to private bus\n");
|
||||
if(bus != NULL) g_object_unref(bus);
|
||||
return 1;
|
||||
}
|
||||
ctx = ibus_bus_create_input_context(bus, "strans-libibus-smoke");
|
||||
if(ctx == NULL){
|
||||
fprintf(stderr, "ibus_client_smoke: cannot create input context\n");
|
||||
g_object_unref(bus);
|
||||
return 1;
|
||||
}
|
||||
g_signal_connect(ctx, "update-preedit-text", G_CALLBACK(legacy), &log);
|
||||
g_signal_connect(ctx, "update-preedit-text-with-mode", G_CALLBACK(modern),
|
||||
&log);
|
||||
ibus_input_context_set_capabilities(ctx, IBUS_CAP_PREEDIT_TEXT);
|
||||
ibus_input_context_set_client_commit_preedit(ctx, TRUE);
|
||||
ibus_input_context_focus_in(ctx);
|
||||
ok = ibus_input_context_process_key_event(ctx, 'n', 0,
|
||||
IBUS_CONTROL_MASK) && waitmodern(&log, 1) &&
|
||||
ibus_input_context_process_key_event(ctx, 'k', 0, 0) &&
|
||||
waitmodern(&log, 2);
|
||||
ibus_input_context_reset(ctx);
|
||||
if(ok)
|
||||
ok = waitmodern(&log, 3);
|
||||
ibus_input_context_focus_out(ctx);
|
||||
if(ok)
|
||||
ok = waitmodern(&log, 4);
|
||||
if(log.legacy != 0 || log.modern != 4 || log.invalid ||
|
||||
!log.sawtext || !log.sawempty)
|
||||
ok = 0;
|
||||
g_object_unref(ctx);
|
||||
g_object_unref(bus);
|
||||
if(!ok){
|
||||
fprintf(stderr,
|
||||
"ibus_client_smoke: legacy=%d modern=%d invalid=%d text=%d empty=%d\n",
|
||||
log.legacy, log.modern, log.invalid, log.sawtext, log.sawempty);
|
||||
return 1;
|
||||
}
|
||||
printf("official libibus client preedit: ok\n");
|
||||
return 0;
|
||||
}
|
||||
@@ -35,6 +35,7 @@ enum
|
||||
};
|
||||
|
||||
typedef struct Daemon Daemon;
|
||||
typedef struct Attrlog Attrlog;
|
||||
typedef struct Siglog Siglog;
|
||||
|
||||
struct Daemon
|
||||
@@ -54,17 +55,31 @@ struct Daemon
|
||||
size_t nerr;
|
||||
};
|
||||
|
||||
struct Attrlog
|
||||
{
|
||||
int n;
|
||||
dbus_uint32_t type;
|
||||
dbus_uint32_t value;
|
||||
dbus_uint32_t start;
|
||||
dbus_uint32_t end;
|
||||
};
|
||||
|
||||
struct Siglog
|
||||
{
|
||||
int invalid;
|
||||
int npreedit;
|
||||
int nlegacy;
|
||||
int nmodern;
|
||||
int ncommit;
|
||||
char preeditpath[96];
|
||||
char commitpath[96];
|
||||
char preedit[256];
|
||||
char commit[256];
|
||||
dbus_uint32_t cursor;
|
||||
dbus_uint32_t mode;
|
||||
dbus_bool_t visible;
|
||||
Attrlog preeditattrs;
|
||||
Attrlog commitattrs;
|
||||
};
|
||||
|
||||
static int
|
||||
@@ -497,10 +512,44 @@ emptyarray(DBusMessageIter *it, int element)
|
||||
}
|
||||
|
||||
static int
|
||||
ibusattrs(DBusMessageIter *it)
|
||||
ibusattribute(DBusMessageIter *it, Attrlog *log)
|
||||
{
|
||||
DBusMessageIter v, st;
|
||||
const char *name;
|
||||
dbus_uint32_t *field[] = {
|
||||
&log->type, &log->value, &log->start, &log->end,
|
||||
};
|
||||
int i;
|
||||
|
||||
if(log->n != 0 || dbus_message_iter_get_arg_type(it) != DBUS_TYPE_VARIANT)
|
||||
return 0;
|
||||
dbus_message_iter_recurse(it, &v);
|
||||
if(dbus_message_iter_get_arg_type(&v) != DBUS_TYPE_STRUCT)
|
||||
return 0;
|
||||
dbus_message_iter_recurse(&v, &st);
|
||||
if(dbus_message_iter_get_arg_type(&st) != DBUS_TYPE_STRING)
|
||||
return 0;
|
||||
dbus_message_iter_get_basic(&st, &name);
|
||||
if(strcmp(name, "IBusAttribute") != 0 || !dbus_message_iter_next(&st) ||
|
||||
!emptyarray(&st, DBUS_TYPE_DICT_ENTRY))
|
||||
return 0;
|
||||
for(i = 0; i < 4; i++){
|
||||
if(!dbus_message_iter_next(&st) ||
|
||||
dbus_message_iter_get_arg_type(&st) != DBUS_TYPE_UINT32)
|
||||
return 0;
|
||||
dbus_message_iter_get_basic(&st, field[i]);
|
||||
}
|
||||
if(dbus_message_iter_next(&st) || dbus_message_iter_next(&v))
|
||||
return 0;
|
||||
log->n++;
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
ibusattrs(DBusMessageIter *it, Attrlog *log)
|
||||
{
|
||||
DBusMessageIter v, st, a;
|
||||
const char *name;
|
||||
|
||||
if(dbus_message_iter_get_arg_type(it) != DBUS_TYPE_VARIANT)
|
||||
return 0;
|
||||
@@ -512,15 +561,23 @@ ibusattrs(DBusMessageIter *it)
|
||||
return 0;
|
||||
dbus_message_iter_get_basic(&st, &name);
|
||||
if(strcmp(name, "IBusAttrList") != 0 || !dbus_message_iter_next(&st) ||
|
||||
!emptyarray(&st, DBUS_TYPE_DICT_ENTRY) ||
|
||||
!dbus_message_iter_next(&st) || !emptyarray(&st, DBUS_TYPE_VARIANT) ||
|
||||
dbus_message_iter_next(&st))
|
||||
!emptyarray(&st, DBUS_TYPE_DICT_ENTRY) || !dbus_message_iter_next(&st) ||
|
||||
dbus_message_iter_get_arg_type(&st) != DBUS_TYPE_ARRAY ||
|
||||
dbus_message_iter_get_element_type(&st) != DBUS_TYPE_VARIANT)
|
||||
return 0;
|
||||
dbus_message_iter_recurse(&st, &a);
|
||||
while(dbus_message_iter_get_arg_type(&a) != DBUS_TYPE_INVALID){
|
||||
if(!ibusattribute(&a, log))
|
||||
return 0;
|
||||
dbus_message_iter_next(&a);
|
||||
}
|
||||
if(dbus_message_iter_next(&st))
|
||||
return 0;
|
||||
return !dbus_message_iter_next(&v);
|
||||
}
|
||||
|
||||
static int
|
||||
ibustext(DBusMessageIter *it, char *text, size_t ntext)
|
||||
ibustext(DBusMessageIter *it, char *text, size_t ntext, Attrlog *attrs)
|
||||
{
|
||||
DBusMessageIter v, st;
|
||||
const char *name, *s;
|
||||
@@ -540,7 +597,7 @@ ibustext(DBusMessageIter *it, char *text, size_t ntext)
|
||||
return 0;
|
||||
dbus_message_iter_get_basic(&st, &s);
|
||||
if(snprintf(text, ntext, "%s", s) >= (int)ntext ||
|
||||
!dbus_message_iter_next(&st) || !ibusattrs(&st) ||
|
||||
!dbus_message_iter_next(&st) || !ibusattrs(&st, attrs) ||
|
||||
dbus_message_iter_next(&st))
|
||||
return 0;
|
||||
return !dbus_message_iter_next(&v);
|
||||
@@ -560,13 +617,15 @@ onsignal(DBusConnection *conn, DBusMessage *m, void *arg)
|
||||
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
|
||||
if(dbus_message_has_member(m, "UpdatePreeditText")){
|
||||
log->npreedit++;
|
||||
log->nlegacy++;
|
||||
path = dbus_message_get_path(m);
|
||||
if(path == NULL || snprintf(log->preeditpath,
|
||||
sizeof log->preeditpath, "%s", path) >=
|
||||
(int)sizeof log->preeditpath ||
|
||||
!dbus_message_has_signature(m, "vub") ||
|
||||
!dbus_message_iter_init(m, &it) ||
|
||||
!ibustext(&it, log->preedit, sizeof log->preedit) ||
|
||||
!ibustext(&it, log->preedit, sizeof log->preedit,
|
||||
&log->preeditattrs) ||
|
||||
!dbus_message_iter_next(&it) ||
|
||||
dbus_message_iter_get_arg_type(&it) != DBUS_TYPE_UINT32){
|
||||
log->invalid = 1;
|
||||
@@ -583,6 +642,38 @@ onsignal(DBusConnection *conn, DBusMessage *m, void *arg)
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
if(dbus_message_has_member(m, "UpdatePreeditTextWithMode")){
|
||||
log->npreedit++;
|
||||
log->nmodern++;
|
||||
path = dbus_message_get_path(m);
|
||||
if(path == NULL || snprintf(log->preeditpath,
|
||||
sizeof log->preeditpath, "%s", path) >=
|
||||
(int)sizeof log->preeditpath ||
|
||||
!dbus_message_has_signature(m, "vubu") ||
|
||||
!dbus_message_iter_init(m, &it) ||
|
||||
!ibustext(&it, log->preedit, sizeof log->preedit,
|
||||
&log->preeditattrs) || !dbus_message_iter_next(&it) ||
|
||||
dbus_message_iter_get_arg_type(&it) != DBUS_TYPE_UINT32){
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
dbus_message_iter_get_basic(&it, &log->cursor);
|
||||
if(!dbus_message_iter_next(&it) ||
|
||||
dbus_message_iter_get_arg_type(&it) != DBUS_TYPE_BOOLEAN){
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
dbus_message_iter_get_basic(&it, &log->visible);
|
||||
if(!dbus_message_iter_next(&it) ||
|
||||
dbus_message_iter_get_arg_type(&it) != DBUS_TYPE_UINT32){
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
dbus_message_iter_get_basic(&it, &log->mode);
|
||||
if(dbus_message_iter_next(&it))
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
}
|
||||
if(dbus_message_has_member(m, "CommitText")){
|
||||
log->ncommit++;
|
||||
path = dbus_message_get_path(m);
|
||||
@@ -591,7 +682,8 @@ onsignal(DBusConnection *conn, DBusMessage *m, void *arg)
|
||||
(int)sizeof log->commitpath ||
|
||||
!dbus_message_has_signature(m, "v") ||
|
||||
!dbus_message_iter_init(m, &it) ||
|
||||
!ibustext(&it, log->commit, sizeof log->commit) ||
|
||||
!ibustext(&it, log->commit, sizeof log->commit,
|
||||
&log->commitattrs) ||
|
||||
dbus_message_iter_next(&it))
|
||||
log->invalid = 1;
|
||||
return DBUS_HANDLER_RESULT_HANDLED;
|
||||
@@ -903,6 +995,43 @@ contentcall(DBusConnection *conn, Siglog *log, char *path,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
clientcommitcall(DBusConnection *conn, Siglog *log, char *path, int enabled)
|
||||
{
|
||||
DBusMessage *m, *reply;
|
||||
DBusMessageIter it, v, st;
|
||||
const char *iface, *property;
|
||||
dbus_bool_t b;
|
||||
|
||||
resetsig(log);
|
||||
iface = "org.freedesktop.IBus.InputContext";
|
||||
property = "ClientCommitPreedit";
|
||||
b = enabled ? TRUE : FALSE;
|
||||
m = method(path, "org.freedesktop.DBus.Properties", "Set");
|
||||
if(m == NULL)
|
||||
return 0;
|
||||
dbus_message_iter_init_append(m, &it);
|
||||
if(!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &iface) ||
|
||||
!dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &property) ||
|
||||
!dbus_message_iter_open_container(&it, DBUS_TYPE_VARIANT, "(b)", &v) ||
|
||||
!dbus_message_iter_open_container(&v, DBUS_TYPE_STRUCT, NULL, &st) ||
|
||||
!dbus_message_iter_append_basic(&st, DBUS_TYPE_BOOLEAN, &b) ||
|
||||
!dbus_message_iter_close_container(&v, &st) ||
|
||||
!dbus_message_iter_close_container(&it, &v)){
|
||||
dbus_message_unref(m);
|
||||
return fail("build Properties.Set ClientCommitPreedit call");
|
||||
}
|
||||
reply = sendcall(conn, m);
|
||||
if(reply == NULL)
|
||||
return 0;
|
||||
if(!dbus_message_has_signature(reply, "")){
|
||||
dbus_message_unref(reply);
|
||||
return fail("Properties.Set ClientCommitPreedit returned a nonempty reply");
|
||||
}
|
||||
dbus_message_unref(reply);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
keycall(DBusConnection *conn, Siglog *log, char *path, dbus_uint32_t sym,
|
||||
dbus_uint32_t state, int *eaten)
|
||||
@@ -1040,11 +1169,22 @@ nosignal(Siglog *log, char *where)
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
preeditattrs(Siglog *log)
|
||||
{
|
||||
if(log->preedit[0] == '\0')
|
||||
return log->preeditattrs.n == 0;
|
||||
return log->preeditattrs.n == 1 && log->preeditattrs.type == 1 &&
|
||||
log->preeditattrs.value == 1 && log->preeditattrs.start == 0 &&
|
||||
log->preeditattrs.end == log->cursor;
|
||||
}
|
||||
|
||||
static int
|
||||
preedit(Siglog *log, char *path, char *text, unsigned int cursor, int visible,
|
||||
char *where)
|
||||
{
|
||||
if(log->invalid || log->npreedit != 1 || log->ncommit != 0 ||
|
||||
if(log->invalid || log->npreedit != 1 || log->nlegacy != 1 ||
|
||||
log->nmodern != 0 || log->ncommit != 0 || !preeditattrs(log) ||
|
||||
strcmp(log->preeditpath, path) != 0 ||
|
||||
strcmp(log->preedit, text) != 0 ||
|
||||
log->cursor != cursor || (log->visible != FALSE) != (visible != 0))
|
||||
@@ -1054,20 +1194,55 @@ preedit(Siglog *log, char *path, char *text, unsigned int cursor, int visible,
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
modernpreedit(Siglog *log, char *path, char *text, unsigned int cursor,
|
||||
int visible, char *where)
|
||||
{
|
||||
if(log->invalid || log->npreedit != 1 || log->nlegacy != 0 ||
|
||||
log->nmodern != 1 || log->ncommit != 0 || log->mode != 0 ||
|
||||
!preeditattrs(log) || strcmp(log->preeditpath, path) != 0 ||
|
||||
strcmp(log->preedit, text) != 0 || log->cursor != cursor ||
|
||||
(log->visible != FALSE) != (visible != 0))
|
||||
return fail("%s modern preedit: legacy=%d modern=%d commit=%d text=%s cursor=%u visible=%d mode=%u attrs=%d",
|
||||
where, log->nlegacy, log->nmodern, log->ncommit, log->preedit,
|
||||
(unsigned)log->cursor, log->visible != FALSE,
|
||||
(unsigned)log->mode, log->preeditattrs.n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
committed(Siglog *log, char *path, char *text, char *where)
|
||||
{
|
||||
if(log->invalid || log->npreedit != 1 || log->ncommit != 1 ||
|
||||
if(log->invalid || log->npreedit != 1 || log->nlegacy != 1 ||
|
||||
log->nmodern != 0 || log->ncommit != 1 ||
|
||||
strcmp(log->preeditpath, path) != 0 ||
|
||||
strcmp(log->commitpath, path) != 0 ||
|
||||
strcmp(log->commit, text) != 0 ||
|
||||
strcmp(log->preedit, "") != 0 || log->cursor != 0 ||
|
||||
log->preeditattrs.n != 0 || log->commitattrs.n != 0 ||
|
||||
log->visible != FALSE)
|
||||
return fail("%s signals: preedit=%d commit=%d text=%s/%s",
|
||||
where, log->npreedit, log->ncommit, log->commit, log->preedit);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
moderncommitted(Siglog *log, char *path, char *text, char *where)
|
||||
{
|
||||
if(log->invalid || log->npreedit != 1 || log->nlegacy != 0 ||
|
||||
log->nmodern != 1 || log->ncommit != 1 || log->mode != 0 ||
|
||||
strcmp(log->preeditpath, path) != 0 ||
|
||||
strcmp(log->commitpath, path) != 0 || strcmp(log->commit, text) != 0 ||
|
||||
strcmp(log->preedit, "") != 0 || log->cursor != 0 ||
|
||||
log->preeditattrs.n != 0 || log->commitattrs.n != 0 ||
|
||||
log->visible != FALSE)
|
||||
return fail("%s modern signals: legacy=%d modern=%d commit=%d text=%s/%s attrs=%d/%d",
|
||||
where, log->nlegacy, log->nmodern, log->ncommit,
|
||||
log->commit, log->preedit, log->commitattrs.n,
|
||||
log->preeditattrs.n);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int
|
||||
expectkey(DBusConnection *conn, Siglog *log, char *path,
|
||||
dbus_uint32_t sym, dbus_uint32_t state, int eaten, char *text, char *where)
|
||||
@@ -1370,6 +1545,30 @@ runpolicy(Daemon *d)
|
||||
!nosignal(&s1, "free-form property") ||
|
||||
!expectkey(c1, &s1, a, 'n', 0, 1, "ん", "free-form resumes"))
|
||||
goto out;
|
||||
|
||||
/* Modern clients receive only WithMode and code-point attribute ranges. */
|
||||
if(!emptycall(c1, &s1, a, "Reset") ||
|
||||
!preedit(&s1, a, "", 0, 0, "modern setup reset") ||
|
||||
!clientcommitcall(c1, &s1, a, 1) ||
|
||||
!nosignal(&s1, "enable client preedit commit") ||
|
||||
!keycall(c1, &s1, a, 'k', 0, &eaten) || !eaten ||
|
||||
!modernpreedit(&s1, a, "k", 1, 1, "modern key k") ||
|
||||
!keycall(c1, &s1, a, 'a', 0, &eaten) || !eaten ||
|
||||
!modernpreedit(&s1, a, "か", 1, 1, "modern key a") ||
|
||||
!keycall(c1, &s1, a, 'n', 0, &eaten) || !eaten ||
|
||||
!modernpreedit(&s1, a, "かん", 2, 1, "modern multibyte") ||
|
||||
!emptycall(c1, &s1, a, "Reset") ||
|
||||
!modernpreedit(&s1, a, "", 0, 0, "modern empty clear") ||
|
||||
!keycall(c1, &s1, a, 'k', 0, &eaten) || !eaten ||
|
||||
!modernpreedit(&s1, a, "k", 1, 1, "modern commit key k") ||
|
||||
!keycall(c1, &s1, a, 'a', 0, &eaten) || !eaten ||
|
||||
!modernpreedit(&s1, a, "か", 1, 1, "modern commit key a") ||
|
||||
!keycall(c1, &s1, a, '0', 0, &eaten) || !eaten ||
|
||||
!moderncommitted(&s1, a, "か", "modern commit") ||
|
||||
!clientcommitcall(c1, &s1, a, 0) ||
|
||||
!nosignal(&s1, "disable client preedit commit") ||
|
||||
!expectkey(c1, &s1, a, 'k', 0, 1, "k", "legacy restored"))
|
||||
goto out;
|
||||
ok = 1;
|
||||
out:
|
||||
closebus(&c1, &s1);
|
||||
@@ -1377,14 +1576,61 @@ out:
|
||||
return ok;
|
||||
}
|
||||
|
||||
static int
|
||||
runclient(Daemon *d, char *program)
|
||||
{
|
||||
struct timespec pause;
|
||||
pid_t pid, n;
|
||||
int status;
|
||||
int64_t deadline;
|
||||
|
||||
pid = fork();
|
||||
if(pid < 0)
|
||||
return fail("fork official libibus client: %s", strerror(errno));
|
||||
if(pid == 0){
|
||||
if(setenv("XDG_RUNTIME_DIR", d->runtime, 1) < 0 ||
|
||||
setenv("XDG_CONFIG_HOME", d->config, 1) < 0 ||
|
||||
setenv("HOME", d->home, 1) < 0)
|
||||
_exit(126);
|
||||
execl(program, program, d->address, (char*)0);
|
||||
dprintf(STDERR_FILENO, "exec %s: %s\n", program, strerror(errno));
|
||||
_exit(127);
|
||||
}
|
||||
pause.tv_sec = 0;
|
||||
pause.tv_nsec = 10000000;
|
||||
deadline = nowms() + Starttimeout;
|
||||
for(;;){
|
||||
n = waitpid(pid, &status, WNOHANG);
|
||||
if(n == pid)
|
||||
break;
|
||||
if(n < 0 && errno == EINTR)
|
||||
continue;
|
||||
if(n < 0)
|
||||
return fail("wait official libibus client: %s", strerror(errno));
|
||||
if(leftms(deadline) == 0){
|
||||
fail("official libibus client timed out");
|
||||
kill(pid, SIGKILL);
|
||||
do
|
||||
n = waitpid(pid, &status, 0);
|
||||
while(n < 0 && errno == EINTR);
|
||||
return 0;
|
||||
}
|
||||
nanosleep(&pause, NULL);
|
||||
}
|
||||
if(!WIFEXITED(status) || WEXITSTATUS(status) != 0)
|
||||
return fail("official libibus client exited with wait status %#x",
|
||||
status);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char **argv)
|
||||
{
|
||||
Daemon daemon;
|
||||
int ok;
|
||||
|
||||
if(argc != 3){
|
||||
fprintf(stderr, "usage: ibus_live_test strans mapdir\n");
|
||||
if(argc != 4){
|
||||
fprintf(stderr, "usage: ibus_live_test strans mapdir libibus-client\n");
|
||||
return 2;
|
||||
}
|
||||
ok = startdaemon(&daemon, argv[1], argv[2]);
|
||||
@@ -1394,6 +1640,8 @@ main(int argc, char **argv)
|
||||
ok = runlifecycle(&daemon);
|
||||
if(ok)
|
||||
ok = runpolicy(&daemon);
|
||||
if(ok)
|
||||
ok = runclient(&daemon, argv[3]);
|
||||
if(!ok)
|
||||
showerrors(&daemon);
|
||||
if(!stopdaemon(&daemon))
|
||||
|
||||
Reference in New Issue
Block a user