ibus: one reply path, no ceremony around calls that cannot fail

Six handlers built method returns by hand and only two of them checked
for a nil message; reply() builds them all and dies on OOM like the
rest of the daemon. DBusError objects were initialised and freed but
never read: libdbus accepts nil. Properties.Get always errored, so it
is one line in onmsg; the introspection XML served nobody (libibus
never asks) and had to be kept in sync by hand. Ibushinthidden was not
an IBus hint, so that term of hidden() never fired. writeaddr uses the
syscalls directly and the address file's dev/ino is the ownership
proof; buildaddrpath makes the directory in place. An empty
UpdatePreeditText goes out only to the context that shows a preedit.
This commit is contained in:
2026-08-16 16:20:10 +09:00
parent c2baa47026
commit eaf31da0d1
2 changed files with 174 additions and 316 deletions

481
ibus.c
View File

@@ -22,7 +22,6 @@ enum
Ibuscappreedit = 1<<0, Ibuscappreedit = 1<<0,
Ibuspurposepassword = 8, Ibuspurposepassword = 8,
Ibuspurposepin = 9, Ibuspurposepin = 9,
Ibushinthidden = 1<<12,
Ibusattrunderline = 1, Ibusattrunderline = 1,
Ibusunderlinesingle = 1, Ibusunderlinesingle = 1,
Ibuspreeditclear = 0, Ibuspreeditclear = 0,
@@ -50,27 +49,24 @@ static Ictx contexts[Maxcontexts];
static char addrfile[512]; static char addrfile[512];
static dev_t addrdev; static dev_t addrdev;
static ino_t addrino; static ino_t addrino;
static int addrowned;
static int icctr; static int icctr;
static int busctr; static int busctr;
static Channel *replyc; static Channel *replyc;
static const char ibusowner[] = ":1.0"; static const char ibusowner[] = ":1.0";
static Ictx *preowner; static Ictx *preowner;
static DBusHandlerResult onmsg(DBusConnection*, DBusMessage*, void*); /* Removes the address file only while it is still the one we wrote. */
static DBusHandlerResult handleerror(DBusConnection*, DBusMessage*,
const char*, const char*);
static void checkpreowner(void);
static void static void
unlinkaddr(void) unlinkaddr(void)
{ {
struct stat st; struct stat st;
if(addrowned && lstat(addrfile, &st) == 0 && if(addrfile[0] != '\0' && lstat(addrfile, &st) == 0 &&
st.st_dev == addrdev && st.st_ino == addrino) st.st_dev == addrdev && st.st_ino == addrino)
unlink(addrfile); unlink(addrfile);
addrowned = 0; addrfile[0] = '\0';
addrdev = 0;
addrino = 0;
} }
static void static void
@@ -136,12 +132,12 @@ xdisplay(char *host, int hsz, char *num, int nsz)
num[n] = '\0'; num[n] = '\0';
} }
/* The IBus address file lives where libibus looks: config/ibus/bus/. */
static int static int
buildaddrpath(char *buf, int sz) buildaddrpath(char *buf, int sz)
{ {
char mid[64], host[64], num[8], *cfg, *home, *explicit; char mid[64], host[64], num[8], dir[512];
struct stat st; char *cfg, *home, *explicit, *p;
char dir[512];
int n; int n;
explicit = getenv("IBUS_ADDRESS_FILE"); explicit = getenv("IBUS_ADDRESS_FILE");
@@ -164,69 +160,45 @@ buildaddrpath(char *buf, int sz)
} }
if(n < 0 || n >= (int)sizeof dir) if(n < 0 || n >= (int)sizeof dir)
return -1; return -1;
if(stat(dir, &st) < 0){ for(p = dir+1; *p; p++)
char tmp[512];
char *p;
strncpy(tmp, dir, sizeof(tmp));
tmp[sizeof(tmp)-1] = '\0';
for(p = tmp+1; *p; p++)
if(*p == '/'){ if(*p == '/'){
*p = '\0'; *p = '\0';
mkdir(tmp, 0700); mkdir(dir, 0700);
*p = '/'; *p = '/';
} }
mkdir(tmp, 0700); mkdir(dir, 0700);
}
n = snprintf(buf, sz, "%s/%s-%s-%s", dir, mid, host, num); n = snprintf(buf, sz, "%s/%s-%s-%s", dir, mid, host, num);
return n < 0 || n >= sz ? -1 : 0; return n < 0 || n >= sz ? -1 : 0;
} }
/* Publishes the address atomically and remembers the file's identity. */
static int static int
writeaddr(char *path, char *addr) writeaddr(char *path, char *addr)
{ {
char tmp[576]; char tmp[576], text[256];
FILE *fp;
struct stat st; struct stat st;
int fd, n, ok; int fd, n, ok;
n = snprintf(tmp, sizeof tmp, "%s.tmp.XXXXXX", path); n = snprintf(tmp, sizeof tmp, "%s.tmp.XXXXXX", path);
if(n < 0 || n >= (int)sizeof tmp) if(n < 0 || n >= (int)sizeof tmp)
return -1; return -1;
n = snprintf(text, sizeof text, "IBUS_ADDRESS=%s\nIBUS_DAEMON_PID=%d\n",
addr, (int)getpid());
if(n < 0 || n >= (int)sizeof text)
return -1;
fd = mkstemp(tmp); fd = mkstemp(tmp);
if(fd < 0) if(fd < 0)
return -1; return -1;
ok = 0; ok = write(fd, text, n) == n && fsync(fd) == 0 &&
fp = nil; fstat(fd, &st) == 0;
if(fchmod(fd, 0600) < 0) close(fd);
goto out; if(!ok || rename(tmp, path) < 0){
fp = fdopen(fd, "w"); unlink(tmp);
if(fp == nil) return -1;
goto out;
fd = -1;
if(fprintf(fp, "IBUS_ADDRESS=%s\n", addr) < 0 ||
fprintf(fp, "IBUS_DAEMON_PID=%d\n", (int)getpid()) < 0 ||
fflush(fp) < 0 || fsync(fileno(fp)) < 0 ||
fstat(fileno(fp), &st) < 0)
goto out;
if(fclose(fp) < 0){
fp = nil;
goto out;
} }
fp = nil;
if(rename(tmp, path) < 0)
goto out;
addrdev = st.st_dev; addrdev = st.st_dev;
addrino = st.st_ino; addrino = st.st_ino;
addrowned = 1; return 0;
ok = 1;
out:
if(fp != nil)
fclose(fp);
if(fd >= 0)
close(fd);
if(!ok)
unlink(tmp);
return ok ? 0 : -1;
} }
static dbus_bool_t static dbus_bool_t
@@ -350,20 +322,7 @@ static int
hidden(Ictx *ctx) hidden(Ictx *ctx)
{ {
return ctx->purpose == Ibuspurposepassword || return ctx->purpose == Ibuspurposepassword ||
ctx->purpose == Ibuspurposepin || ctx->purpose == Ibuspurposepin;
(ctx->hints & Ibushinthidden) != 0;
}
static int
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
{
if(state & Relmask || !ctx->focused || hidden(ctx))
return 0;
sendrequest(ctx, Keypress, ipckeysym(sym, xkb_keysym_to_utf32(sym)),
ipcmod(state), res);
if(preowner != nil && preowner != ctx)
checkpreowner();
return 1;
} }
static void static void
@@ -379,11 +338,21 @@ setcursor(Ictx *ctx, int x, int y, int h)
sendrequest(ctx, Keycaret, 0, 0, &res); sendrequest(ctx, Keycaret, 0, 0, &res);
} }
/* Every IBus serializable carries an (empty) attachment dictionary. */
static void
emptydict(DBusMessageIter *it)
{
DBusMessageIter d;
dbus_message_iter_open_container(it, DBUS_TYPE_ARRAY, "{sv}", &d);
dbus_message_iter_close_container(it, &d);
}
/* IBusText: (sa{sv}sv) holding an IBusAttrList of IBusAttributes. */
static void static void
appendibustext(DBusMessageIter *it, const char *s, int underline) appendibustext(DBusMessageIter *it, const char *s, int underline)
{ {
DBusMessageIter v, st, attach, alv, ali, attr, alist; DBusMessageIter v, st, alv, ali, alist, av, ai;
DBusMessageIter av, ai, aattach;
const char *name = "IBusText"; const char *name = "IBusText";
const char *aname = "IBusAttrList"; const char *aname = "IBusAttrList";
const char *iname = "IBusAttribute"; const char *iname = "IBusAttribute";
@@ -392,14 +361,12 @@ appendibustext(DBusMessageIter *it, const char *s, int underline)
dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, "(sa{sv}sv)", &v); dbus_message_iter_open_container(it, DBUS_TYPE_VARIANT, "(sa{sv}sv)", &v);
dbus_message_iter_open_container(&v, DBUS_TYPE_STRUCT, nil, &st); dbus_message_iter_open_container(&v, DBUS_TYPE_STRUCT, nil, &st);
dbus_message_iter_append_basic(&st, DBUS_TYPE_STRING, &name); dbus_message_iter_append_basic(&st, DBUS_TYPE_STRING, &name);
dbus_message_iter_open_container(&st, DBUS_TYPE_ARRAY, "{sv}", &attach); emptydict(&st);
dbus_message_iter_close_container(&st, &attach);
dbus_message_iter_append_basic(&st, DBUS_TYPE_STRING, &s); dbus_message_iter_append_basic(&st, DBUS_TYPE_STRING, &s);
dbus_message_iter_open_container(&st, DBUS_TYPE_VARIANT, "(sa{sv}av)", &alv); dbus_message_iter_open_container(&st, DBUS_TYPE_VARIANT, "(sa{sv}av)", &alv);
dbus_message_iter_open_container(&alv, DBUS_TYPE_STRUCT, nil, &ali); dbus_message_iter_open_container(&alv, DBUS_TYPE_STRUCT, nil, &ali);
dbus_message_iter_append_basic(&ali, DBUS_TYPE_STRING, &aname); dbus_message_iter_append_basic(&ali, DBUS_TYPE_STRING, &aname);
dbus_message_iter_open_container(&ali, DBUS_TYPE_ARRAY, "{sv}", &attr); emptydict(&ali);
dbus_message_iter_close_container(&ali, &attr);
dbus_message_iter_open_container(&ali, DBUS_TYPE_ARRAY, "v", &alist); dbus_message_iter_open_container(&ali, DBUS_TYPE_ARRAY, "v", &alist);
if(underline && s[0] != '\0'){ if(underline && s[0] != '\0'){
type = Ibusattrunderline; type = Ibusattrunderline;
@@ -410,9 +377,7 @@ appendibustext(DBusMessageIter *it, const char *s, int underline)
"(sa{sv}uuuu)", &av); "(sa{sv}uuuu)", &av);
dbus_message_iter_open_container(&av, DBUS_TYPE_STRUCT, nil, &ai); dbus_message_iter_open_container(&av, DBUS_TYPE_STRUCT, nil, &ai);
dbus_message_iter_append_basic(&ai, DBUS_TYPE_STRING, &iname); dbus_message_iter_append_basic(&ai, DBUS_TYPE_STRING, &iname);
dbus_message_iter_open_container(&ai, DBUS_TYPE_ARRAY, "{sv}", emptydict(&ai);
&aattach);
dbus_message_iter_close_container(&ai, &aattach);
dbus_message_iter_append_basic(&ai, DBUS_TYPE_UINT32, &type); dbus_message_iter_append_basic(&ai, DBUS_TYPE_UINT32, &type);
dbus_message_iter_append_basic(&ai, DBUS_TYPE_UINT32, &value); dbus_message_iter_append_basic(&ai, DBUS_TYPE_UINT32, &value);
dbus_message_iter_append_basic(&ai, DBUS_TYPE_UINT32, &start); dbus_message_iter_append_basic(&ai, DBUS_TYPE_UINT32, &start);
@@ -427,22 +392,33 @@ appendibustext(DBusMessageIter *it, const char *s, int underline)
dbus_message_iter_close_container(it, &v); dbus_message_iter_close_container(it, &v);
} }
static DBusMessage*
newsignal(const char *path, const char *name)
{
DBusMessage *sig;
sig = dbus_message_new_signal(path, "org.freedesktop.IBus.InputContext",
name);
if(sig == nil)
die("ibus: out of memory");
dbus_message_set_sender(sig, ibusowner);
return sig;
}
static void static void
emitcommit(DBusConnection *c, const char *path, const char *text) emitcommit(DBusConnection *c, const char *path, const char *text)
{ {
DBusMessage *sig; DBusMessage *sig;
DBusMessageIter it; DBusMessageIter it;
sig = dbus_message_new_signal(path, "org.freedesktop.IBus.InputContext", "CommitText"); sig = newsignal(path, "CommitText");
if(sig == nil)
return;
dbus_message_iter_init_append(sig, &it); dbus_message_iter_init_append(sig, &it);
appendibustext(&it, text, 0); appendibustext(&it, text, 0);
dbus_message_set_sender(sig, ibusowner);
dbus_connection_send(c, sig, nil); dbus_connection_send(c, sig, nil);
dbus_message_unref(sig); dbus_message_unref(sig);
} }
/* preowner is the one context showing a preedit; clearing anyone else's is moot. */
static void static void
emitpreedit(Ictx *ctx, const char *text) emitpreedit(Ictx *ctx, const char *text)
{ {
@@ -450,14 +426,11 @@ emitpreedit(Ictx *ctx, const char *text)
DBusMessageIter it; DBusMessageIter it;
dbus_uint32_t cursor, mode; dbus_uint32_t cursor, mode;
dbus_bool_t visible; dbus_bool_t visible;
const char *name;
name = ctx->clientcommitpreedit ? if(text[0] == '\0' && preowner != ctx)
"UpdatePreeditTextWithMode" : "UpdatePreeditText";
sig = dbus_message_new_signal(ctx->path,
"org.freedesktop.IBus.InputContext", name);
if(sig == nil)
return; return;
sig = newsignal(ctx->path, ctx->clientcommitpreedit ?
"UpdatePreeditTextWithMode" : "UpdatePreeditText");
dbus_message_iter_init_append(sig, &it); dbus_message_iter_init_append(sig, &it);
appendibustext(&it, text, 1); appendibustext(&it, text, 1);
cursor = utflen((char*)text); cursor = utflen((char*)text);
@@ -468,7 +441,6 @@ emitpreedit(Ictx *ctx, const char *text)
mode = Ibuspreeditclear; mode = Ibuspreeditclear;
dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &mode); dbus_message_iter_append_basic(&it, DBUS_TYPE_UINT32, &mode);
} }
dbus_message_set_sender(sig, ibusowner);
if(dbus_connection_send(ctx->conn, sig, nil)){ if(dbus_connection_send(ctx->conn, sig, nil)){
if(text[0] != '\0') if(text[0] != '\0')
preowner = ctx; preowner = ctx;
@@ -478,6 +450,7 @@ emitpreedit(Ictx *ctx, const char *text)
dbus_message_unref(sig); dbus_message_unref(sig);
} }
/* Another frontend may have taken the engine; then our preedit is stale. */
static void static void
checkpreowner(void) checkpreowner(void)
{ {
@@ -492,10 +465,62 @@ checkpreowner(void)
emitpreedit(ctx, ""); emitpreedit(ctx, "");
} }
static int
processkey(Ictx *ctx, u32int sym, u32int state, Keyres *res)
{
if(state & Relmask || !ctx->focused || hidden(ctx))
return 0;
sendrequest(ctx, Keypress, ipckeysym(sym, xkb_keysym_to_utf32(sym)),
ipcmod(state), res);
if(preowner != nil && preowner != ctx)
checkpreowner();
return 1;
}
static DBusHandlerResult
handleerror(DBusConnection *c, DBusMessage *m, const char *name,
const char *text)
{
DBusMessage *r;
r = dbus_message_new_error(m, name, text);
if(r == nil)
die("ibus: out of memory");
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
}
/* Replies with one argument of the given D-Bus type, or none. */
static DBusHandlerResult
reply(DBusConnection *c, DBusMessage *m, int type, void *v)
{
DBusMessage *r;
r = dbus_message_new_method_return(m);
if(r == nil)
die("ibus: out of memory");
if(type != DBUS_TYPE_INVALID)
dbus_message_append_args(r, type, v, DBUS_TYPE_INVALID);
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
replybool(DBusConnection *c, DBusMessage *m, int value)
{
dbus_bool_t b;
b = value ? TRUE : FALSE;
return reply(c, m, DBUS_TYPE_BOOLEAN, &b);
}
/* We are the bus as well as the engine: Hello names the caller. */
static DBusHandlerResult static DBusHandlerResult
handlehello(DBusConnection *c, DBusMessage *m) handlehello(DBusConnection *c, DBusMessage *m)
{ {
DBusMessage *r;
char name[32]; char name[32];
const char *np; const char *np;
@@ -505,122 +530,66 @@ handlehello(DBusConnection *c, DBusMessage *m)
busctr++; busctr++;
snprintf(name, sizeof(name), ":1.%d", busctr); snprintf(name, sizeof(name), ":1.%d", busctr);
np = name; np = name;
r = dbus_message_new_method_return(m); return reply(c, m, DBUS_TYPE_STRING, &np);
dbus_message_append_args(r, DBUS_TYPE_STRING, &np, DBUS_TYPE_INVALID);
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
} }
static DBusHandlerResult static DBusHandlerResult
handlenameowner(DBusConnection *c, DBusMessage *m) handlenameowner(DBusConnection *c, DBusMessage *m)
{ {
DBusError err;
DBusMessage *r;
const char *name, *owner; const char *name, *owner;
dbus_error_init(&err); if(!dbus_message_get_args(m, nil, DBUS_TYPE_STRING, &name,
if(!dbus_message_get_args(m, &err, DBUS_TYPE_STRING, &name, DBUS_TYPE_INVALID))
DBUS_TYPE_INVALID)){
dbus_error_free(&err);
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"GetNameOwner expects one bus name"); "GetNameOwner expects one bus name");
}
if(strcmp(name, "org.freedesktop.IBus") != 0) if(strcmp(name, "org.freedesktop.IBus") != 0)
return handleerror(c, m, DBUS_ERROR_NAME_HAS_NO_OWNER, return handleerror(c, m, DBUS_ERROR_NAME_HAS_NO_OWNER,
"bus name has no owner"); "bus name has no owner");
owner = ibusowner; owner = ibusowner;
r = dbus_message_new_method_return(m); return reply(c, m, DBUS_TYPE_STRING, &owner);
if(r == nil)
return DBUS_HANDLER_RESULT_NEED_MEMORY;
dbus_message_append_args(r, DBUS_TYPE_STRING, &owner, DBUS_TYPE_INVALID);
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
handleerror(DBusConnection *c, DBusMessage *m, const char *name,
const char *text)
{
DBusMessage *r;
r = dbus_message_new_error(m, name, text);
if(r != nil){
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
}
return DBUS_HANDLER_RESULT_HANDLED;
}
static DBusHandlerResult
handlebool(DBusConnection *c, DBusMessage *m, int value)
{
DBusMessage *r;
dbus_bool_t b;
r = dbus_message_new_method_return(m);
b = value ? TRUE : FALSE;
dbus_message_append_args(r, DBUS_TYPE_BOOLEAN, &b, DBUS_TYPE_INVALID);
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
} }
static DBusHandlerResult static DBusHandlerResult
handlecreate(DBusConnection *c, DBusMessage *m) handlecreate(DBusConnection *c, DBusMessage *m)
{ {
DBusMessage *r;
char path[64]; char path[64];
const char *pp; const char *pp;
Ictx *ctx; Ictx *ctx;
int n;
if(!dbus_message_has_signature(m, "s")) if(!dbus_message_has_signature(m, "s"))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"CreateInputContext expects one client name"); "CreateInputContext expects one client name");
icctr++; icctr++;
n = snprintf(path, sizeof(path), snprintf(path, sizeof(path),
"/org/freedesktop/IBus/InputContext_%d", icctr); "/org/freedesktop/IBus/InputContext_%d", icctr);
if(n < 0 || n >= (int)sizeof path)
return handleerror(c, m, DBUS_ERROR_LIMITS_EXCEEDED,
"input context path exhausted");
ctx = newcontext(c, path); ctx = newcontext(c, path);
if(ctx == nil) if(ctx == nil)
return handleerror(c, m, DBUS_ERROR_LIMITS_EXCEEDED, return handleerror(c, m, DBUS_ERROR_LIMITS_EXCEEDED,
"too many input contexts"); "too many input contexts");
pp = path; pp = path;
r = dbus_message_new_method_return(m); return reply(c, m, DBUS_TYPE_OBJECT_PATH, &pp);
dbus_message_append_args(r, DBUS_TYPE_OBJECT_PATH, &pp, DBUS_TYPE_INVALID);
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
} }
static DBusHandlerResult static DBusHandlerResult
handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx) handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
DBusError err;
dbus_uint32_t sym, code, state; dbus_uint32_t sym, code, state;
Keyres res; Keyres res;
char commit[Maxutf], preedit[Maxutf]; char commit[Maxutf], preedit[Maxutf];
int restart; int restart;
dbus_error_init(&err); if(!dbus_message_get_args(m, nil,
if(!dbus_message_get_args(m, &err,
DBUS_TYPE_UINT32, &sym, DBUS_TYPE_UINT32, &sym,
DBUS_TYPE_UINT32, &code, DBUS_TYPE_UINT32, &code,
DBUS_TYPE_UINT32, &state, DBUS_TYPE_UINT32, &state,
DBUS_TYPE_INVALID)){ DBUS_TYPE_INVALID))
dbus_error_free(&err);
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"ProcessKeyEvent expects three unsigned integers"); "ProcessKeyEvent expects three unsigned integers");
}
USED(code);
if(!processkey(ctx, sym, state, &res)) if(!processkey(ctx, sym, state, &res))
return handlebool(c, m, 0); return replybool(c, m, 0);
stoutf(&res.commit, commit, sizeof commit); stoutf(&res.commit, commit, sizeof commit);
stoutf(&res.preedit, preedit, sizeof preedit); stoutf(&res.preedit, preedit, sizeof preedit);
/* A commit ends the preedit around it, so clients place it right. */
restart = clientpreedit(ctx) && commit[0] != '\0' && preowner == ctx; restart = clientpreedit(ctx) && commit[0] != '\0' && preowner == ctx;
if(restart) if(restart)
emitpreedit(ctx, ""); emitpreedit(ctx, "");
@@ -628,18 +597,7 @@ handlekey(DBusConnection *c, DBusMessage *m, Ictx *ctx)
emitcommit(c, dbus_message_get_path(m), commit); emitcommit(c, dbus_message_get_path(m), commit);
if(clientpreedit(ctx) && (!restart || preedit[0] != '\0')) if(clientpreedit(ctx) && (!restart || preedit[0] != '\0'))
emitpreedit(ctx, preedit); emitpreedit(ctx, preedit);
return handlebool(c, m, res.eaten); return replybool(c, m, res.eaten);
}
static DBusHandlerResult
handlenoop(DBusConnection *c, DBusMessage *m)
{
DBusMessage *r;
r = dbus_message_new_method_return(m);
dbus_connection_send(c, r, nil);
dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED;
} }
static DBusHandlerResult static DBusHandlerResult
@@ -650,14 +608,14 @@ handlereset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
sendrequest(ctx, Keyreset, 0, 0, &res); sendrequest(ctx, Keyreset, 0, 0, &res);
if(clientpreedit(ctx)) if(clientpreedit(ctx))
emitpreedit(ctx, ""); emitpreedit(ctx, "");
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
static DBusHandlerResult static DBusHandlerResult
handlefocusin(DBusConnection *c, DBusMessage *m, Ictx *ctx) handlefocusin(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
ctx->focused = 1; ctx->focused = 1;
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
static DBusHandlerResult static DBusHandlerResult
@@ -666,25 +624,21 @@ handlefocusout(DBusConnection *c, DBusMessage *m, Ictx *ctx)
releasecontext(ctx); releasecontext(ctx);
if(clientpreedit(ctx)) if(clientpreedit(ctx))
emitpreedit(ctx, ""); emitpreedit(ctx, "");
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
static DBusHandlerResult static DBusHandlerResult
handlecap(DBusConnection *c, DBusMessage *m, Ictx *ctx) handlecap(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
DBusError err;
dbus_uint32_t cap; dbus_uint32_t cap;
Keyres res; Keyres res;
char preedit[Maxutf]; char preedit[Maxutf];
u32int old; u32int old;
dbus_error_init(&err); if(!dbus_message_get_args(m, nil, DBUS_TYPE_UINT32, &cap,
if(!dbus_message_get_args(m, &err, DBUS_TYPE_UINT32, &cap, DBUS_TYPE_INVALID))
DBUS_TYPE_INVALID)){
dbus_error_free(&err);
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"SetCapabilities expects one unsigned integer"); "SetCapabilities expects one unsigned integer");
}
old = ctx->cap; old = ctx->cap;
ctx->cap = cap; ctx->cap = cap;
if(ctx->focused){ if(ctx->focused){
@@ -697,7 +651,7 @@ handlecap(DBusConnection *c, DBusMessage *m, Ictx *ctx)
emitpreedit(ctx, ""); emitpreedit(ctx, "");
} }
} }
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
static int static int
@@ -740,6 +694,7 @@ getcontent(DBusMessageIter *value, u32int *purpose, u32int *hints)
return 1; return 1;
} }
/* Only ContentType and ClientCommitPreedit are settable; none is readable. */
static DBusHandlerResult static DBusHandlerResult
handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx) handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
@@ -768,7 +723,7 @@ handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
if(clientpreedit(ctx)) if(clientpreedit(ctx))
emitpreedit(ctx, ""); emitpreedit(ctx, "");
} }
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
if(strcmp(name, "ClientCommitPreedit") == 0){ if(strcmp(name, "ClientCommitPreedit") == 0){
if(dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRUCT) if(dbus_message_iter_get_arg_type(&value) != DBUS_TYPE_STRUCT)
@@ -783,60 +738,31 @@ handlepropertyset(DBusConnection *c, DBusMessage *m, Ictx *ctx)
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"ClientCommitPreedit expects (b)"); "ClientCommitPreedit expects (b)");
ctx->clientcommitpreedit = b != FALSE; ctx->clientcommitpreedit = b != FALSE;
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
return handleerror(c, m, DBUS_ERROR_UNKNOWN_PROPERTY, return handleerror(c, m, DBUS_ERROR_UNKNOWN_PROPERTY,
"unknown input context property"); "unknown input context property");
} }
static DBusHandlerResult static DBusHandlerResult
handlepropertyget(DBusConnection *c, DBusMessage *m, Ictx *ctx) handlepropertygetall(DBusConnection *c, DBusMessage *m)
{
DBusError err;
const char *iface, *name;
USED(ctx);
dbus_error_init(&err);
if(!dbus_message_get_args(m, &err,
DBUS_TYPE_STRING, &iface, DBUS_TYPE_STRING, &name,
DBUS_TYPE_INVALID)){
dbus_error_free(&err);
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"Properties.Get expects interface and property names");
}
if(strcmp(iface, "org.freedesktop.IBus.InputContext") != 0)
return handleerror(c, m, DBUS_ERROR_UNKNOWN_INTERFACE,
"unknown property interface");
USED(name);
return handleerror(c, m, DBUS_ERROR_UNKNOWN_PROPERTY,
"input context properties are write-only");
}
static DBusHandlerResult
handlepropertygetall(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
DBusMessage *r; DBusMessage *r;
DBusMessageIter it, a; DBusMessageIter it;
DBusError err;
const char *iface; const char *iface;
USED(ctx); if(!dbus_message_get_args(m, nil, DBUS_TYPE_STRING, &iface,
dbus_error_init(&err); DBUS_TYPE_INVALID))
if(!dbus_message_get_args(m, &err, DBUS_TYPE_STRING, &iface,
DBUS_TYPE_INVALID)){
dbus_error_free(&err);
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"Properties.GetAll expects an interface name"); "Properties.GetAll expects an interface name");
}
if(strcmp(iface, "org.freedesktop.IBus.InputContext") != 0) if(strcmp(iface, "org.freedesktop.IBus.InputContext") != 0)
return handleerror(c, m, DBUS_ERROR_UNKNOWN_INTERFACE, return handleerror(c, m, DBUS_ERROR_UNKNOWN_INTERFACE,
"unknown property interface"); "unknown property interface");
r = dbus_message_new_method_return(m); r = dbus_message_new_method_return(m);
if(r == nil) if(r == nil)
return DBUS_HANDLER_RESULT_NEED_MEMORY; die("ibus: out of memory");
dbus_message_iter_init_append(r, &it); dbus_message_iter_init_append(r, &it);
dbus_message_iter_open_container(&it, DBUS_TYPE_ARRAY, "{sv}", &a); emptydict(&it);
dbus_message_iter_close_container(&it, &a);
dbus_connection_send(c, r, nil); dbus_connection_send(c, r, nil);
dbus_message_unref(r); dbus_message_unref(r);
return DBUS_HANDLER_RESULT_HANDLED; return DBUS_HANDLER_RESULT_HANDLED;
@@ -846,99 +772,54 @@ static DBusHandlerResult
handledestroy(DBusConnection *c, DBusMessage *m, Ictx *ctx) handledestroy(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
dropcontext(ctx); dropcontext(ctx);
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
static DBusHandlerResult static DBusHandlerResult
handlecursor(DBusConnection *c, DBusMessage *m, Ictx *ctx) handlecursor(DBusConnection *c, DBusMessage *m, Ictx *ctx)
{ {
DBusError err;
dbus_int32_t x, y, w, h; dbus_int32_t x, y, w, h;
dbus_error_init(&err); if(!dbus_message_get_args(m, nil,
if(!dbus_message_get_args(m, &err,
DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y, DBUS_TYPE_INT32, &x, DBUS_TYPE_INT32, &y,
DBUS_TYPE_INT32, &w, DBUS_TYPE_INT32, &h, DBUS_TYPE_INT32, &w, DBUS_TYPE_INT32, &h,
DBUS_TYPE_INVALID)){ DBUS_TYPE_INVALID))
dbus_error_free(&err);
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"SetCursorLocation expects four integers"); "SetCursorLocation expects four integers");
}
if(w < 0 || h < 0) if(w < 0 || h < 0)
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"cursor dimensions must not be negative"); "cursor dimensions must not be negative");
setcursor(ctx, x, y, h); setcursor(ctx, x, y, h);
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
static const char introspectxml[] = /* Argument-free InputContext calls, checked for an empty signature. */
"<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\"\n"
" \"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
"<node>\n"
" <interface name=\"org.freedesktop.IBus\">\n"
" <method name=\"CreateInputContext\">\n"
" <arg direction=\"in\" type=\"s\"/>\n"
" <arg direction=\"out\" type=\"o\"/>\n"
" </method>\n"
" </interface>\n"
" <interface name=\"org.freedesktop.IBus.InputContext\">\n"
" <method name=\"ProcessKeyEvent\">\n"
" <arg direction=\"in\" type=\"u\"/>\n"
" <arg direction=\"in\" type=\"u\"/>\n"
" <arg direction=\"in\" type=\"u\"/>\n"
" <arg direction=\"out\" type=\"b\"/>\n"
" </method>\n"
" <method name=\"FocusIn\"/>\n"
" <method name=\"FocusOut\"/>\n"
" <method name=\"Reset\"/>\n"
" <method name=\"Destroy\"/>\n"
" <method name=\"SetCapabilities\"><arg direction=\"in\" type=\"u\"/></method>\n"
" <method name=\"SetCursorLocation\">"
"<arg direction=\"in\" type=\"i\"/><arg direction=\"in\" type=\"i\"/>"
"<arg direction=\"in\" type=\"i\"/><arg direction=\"in\" type=\"i\"/></method>\n"
" <method name=\"SetEngine\"><arg direction=\"in\" type=\"s\"/></method>\n"
" <property name=\"ContentType\" type=\"(uu)\" access=\"write\"/>\n"
" <property name=\"ClientCommitPreedit\" type=\"(b)\" access=\"write\"/>\n"
" <signal name=\"CommitText\"><arg type=\"v\"/></signal>\n"
" <signal name=\"UpdatePreeditText\">"
"<arg type=\"v\"/><arg type=\"u\"/><arg type=\"b\"/></signal>\n"
" <signal name=\"UpdatePreeditTextWithMode\">"
"<arg type=\"v\"/><arg type=\"u\"/><arg type=\"b\"/>"
"<arg type=\"u\"/></signal>\n"
" </interface>\n"
" <interface name=\"org.freedesktop.DBus.Properties\">\n"
" <method name=\"Get\"><arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"in\" type=\"s\"/><arg direction=\"out\" type=\"v\"/></method>\n"
" <method name=\"Set\"><arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"in\" type=\"s\"/><arg direction=\"in\" type=\"v\"/></method>\n"
" <method name=\"GetAll\"><arg direction=\"in\" type=\"s\"/>"
"<arg direction=\"out\" type=\"a{sv}\"/></method>\n"
" </interface>\n"
"</node>\n";
static DBusHandlerResult static DBusHandlerResult
handleintrospect(DBusConnection *c, DBusMessage *m) handleplain(DBusConnection *c, DBusMessage *m, Ictx *ctx, const char *member)
{ {
DBusMessage *r;
const char *xml = introspectxml;
if(!dbus_message_has_signature(m, "")) if(!dbus_message_has_signature(m, ""))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"Introspect expects no arguments"); "this call takes no arguments");
r = dbus_message_new_method_return(m); if(strcmp(member, "FocusIn") == 0)
dbus_message_append_args(r, DBUS_TYPE_STRING, &xml, DBUS_TYPE_INVALID); return handlefocusin(c, m, ctx);
dbus_connection_send(c, r, nil); if(strcmp(member, "FocusOut") == 0)
dbus_message_unref(r); return handlefocusout(c, m, ctx);
return DBUS_HANDLER_RESULT_HANDLED; if(strcmp(member, "Reset") == 0)
return handlereset(c, m, ctx);
return handledestroy(c, m, ctx);
} }
/*
* One handler for everything a client sends: the tiny slice of the bus
* that libibus needs, then the InputContext interface. Unhandled calls
* get libdbus's UnknownMethod error.
*/
static DBusHandlerResult static DBusHandlerResult
onmsg(DBusConnection *c, DBusMessage *m, void *_) onmsg(DBusConnection *c, DBusMessage *m, void*)
{ {
const char *iface, *member, *path; const char *iface, *member, *path;
Ictx *ctx; Ictx *ctx;
USED(_);
if(dbus_message_get_type(m) != DBUS_MESSAGE_TYPE_METHOD_CALL) if(dbus_message_get_type(m) != DBUS_MESSAGE_TYPE_METHOD_CALL)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
iface = dbus_message_get_interface(m); iface = dbus_message_get_interface(m);
@@ -946,9 +827,6 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
path = dbus_message_get_path(m); path = dbus_message_get_path(m);
if(iface == nil || member == nil || path == nil) if(iface == nil || member == nil || path == nil)
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
if(strcmp(iface, "org.freedesktop.DBus.Introspectable") == 0
&& strcmp(member, "Introspect") == 0)
return handleintrospect(c, m);
if(strcmp(iface, "org.freedesktop.DBus") == 0){ if(strcmp(iface, "org.freedesktop.DBus") == 0){
if(strcmp(member, "Hello") == 0) if(strcmp(member, "Hello") == 0)
return handlehello(c, m); return handlehello(c, m);
@@ -959,7 +837,7 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
if(!dbus_message_has_signature(m, "s")) if(!dbus_message_has_signature(m, "s"))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"match rule must be one string"); "match rule must be one string");
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
} }
if(strcmp(iface, "org.freedesktop.IBus") == 0){ if(strcmp(iface, "org.freedesktop.IBus") == 0){
@@ -967,16 +845,16 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
return handlecreate(c, m); return handlecreate(c, m);
} }
if(strcmp(iface, "org.freedesktop.DBus.Properties") == 0){ if(strcmp(iface, "org.freedesktop.DBus.Properties") == 0){
ctx = findcontext(c, path); if(findcontext(c, path) == nil)
if(ctx == nil)
return handleerror(c, m, DBUS_ERROR_UNKNOWN_OBJECT, return handleerror(c, m, DBUS_ERROR_UNKNOWN_OBJECT,
"unknown input context"); "unknown input context");
if(strcmp(member, "Set") == 0) if(strcmp(member, "Set") == 0)
return handlepropertyset(c, m, ctx); return handlepropertyset(c, m, findcontext(c, path));
if(strcmp(member, "Get") == 0) if(strcmp(member, "Get") == 0)
return handlepropertyget(c, m, ctx); return handleerror(c, m, DBUS_ERROR_UNKNOWN_PROPERTY,
"input context properties are write-only");
if(strcmp(member, "GetAll") == 0) if(strcmp(member, "GetAll") == 0)
return handlepropertygetall(c, m, ctx); return handlepropertygetall(c, m);
} }
if(strcmp(iface, "org.freedesktop.IBus.InputContext") == 0){ if(strcmp(iface, "org.freedesktop.IBus.InputContext") == 0){
ctx = findcontext(c, path); ctx = findcontext(c, path);
@@ -985,30 +863,11 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
"unknown input context"); "unknown input context");
if(strcmp(member, "ProcessKeyEvent") == 0) if(strcmp(member, "ProcessKeyEvent") == 0)
return handlekey(c, m, ctx); return handlekey(c, m, ctx);
if(strcmp(member, "FocusIn") == 0){ if(strcmp(member, "FocusIn") == 0 ||
if(!dbus_message_has_signature(m, "")) strcmp(member, "FocusOut") == 0 ||
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, strcmp(member, "Reset") == 0 ||
"FocusIn expects no arguments"); strcmp(member, "Destroy") == 0)
return handlefocusin(c, m, ctx); return handleplain(c, m, ctx, member);
}
if(strcmp(member, "FocusOut") == 0){
if(!dbus_message_has_signature(m, ""))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"FocusOut expects no arguments");
return handlefocusout(c, m, ctx);
}
if(strcmp(member, "Reset") == 0){
if(!dbus_message_has_signature(m, ""))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"Reset expects no arguments");
return handlereset(c, m, ctx);
}
if(strcmp(member, "Destroy") == 0){
if(!dbus_message_has_signature(m, ""))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"Destroy expects no arguments");
return handledestroy(c, m, ctx);
}
if(strcmp(member, "SetCursorLocation") == 0) if(strcmp(member, "SetCursorLocation") == 0)
return handlecursor(c, m, ctx); return handlecursor(c, m, ctx);
if(strcmp(member, "SetCapabilities") == 0) if(strcmp(member, "SetCapabilities") == 0)
@@ -1017,7 +876,7 @@ onmsg(DBusConnection *c, DBusMessage *m, void *_)
if(!dbus_message_has_signature(m, "s")) if(!dbus_message_has_signature(m, "s"))
return handleerror(c, m, DBUS_ERROR_INVALID_ARGS, return handleerror(c, m, DBUS_ERROR_INVALID_ARGS,
"SetEngine expects one engine name"); "SetEngine expects one engine name");
return handlenoop(c, m); return reply(c, m, DBUS_TYPE_INVALID, nil);
} }
} }
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED; return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;

View File

@@ -358,7 +358,6 @@ ibus_private_input_policy(struct ct *t)
{ Ibuspurposepassword, 0, 1 }, { Ibuspurposepassword, 0, 1 },
{ Ibuspurposepin, 0, 1 }, { Ibuspurposepin, 0, 1 },
{ 0, 1<<11, 0 }, { 0, 1<<11, 0 },
{ 0, Ibushinthidden, 1 },
{ 37, 1<<20, 0 }, { 37, 1<<20, 0 },
}; };
Ibusfix f; Ibusfix f;