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:
489
ibus.c
489
ibus.c
@@ -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++)
|
||||
if(*p == '/'){
|
||||
*p = '\0';
|
||||
mkdir(tmp, 0700);
|
||||
*p = '/';
|
||||
}
|
||||
mkdir(tmp, 0700);
|
||||
}
|
||||
for(p = dir+1; *p; p++)
|
||||
if(*p == '/'){
|
||||
*p = '\0';
|
||||
mkdir(dir, 0700);
|
||||
*p = '/';
|
||||
}
|
||||
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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user