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

View File

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