fix(gtk): restore compose fallback and clean lifecycle
This commit is contained in:
164
gtk/main.c
164
gtk/main.c
@@ -1,3 +1,4 @@
|
||||
#include <errno.h>
|
||||
#include <limits.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
@@ -12,12 +13,14 @@
|
||||
typedef struct Im Im;
|
||||
struct Im
|
||||
{
|
||||
GtkIMContext parent;
|
||||
GtkIMContextSimple parent;
|
||||
int fd;
|
||||
int usepreedit;
|
||||
int effective;
|
||||
int ext;
|
||||
int private;
|
||||
int simpleactive;
|
||||
int insimple;
|
||||
int simpledone;
|
||||
char pre[Ipcfieldmax+1];
|
||||
int prelen;
|
||||
GdkWindow *win;
|
||||
@@ -33,10 +36,12 @@ struct Im
|
||||
typedef struct ImClass ImClass;
|
||||
struct ImClass
|
||||
{
|
||||
GtkIMContextClass parent;
|
||||
GtkIMContextSimpleClass parent;
|
||||
};
|
||||
|
||||
static GType imtype;
|
||||
static GObjectClass *parentobject;
|
||||
static GtkIMContextClass *parentim;
|
||||
|
||||
static void
|
||||
setpreedit(Im *im, const char *s, int n)
|
||||
@@ -60,15 +65,32 @@ setpreedit(Im *im, const char *s, int n)
|
||||
}
|
||||
|
||||
static void
|
||||
srvclose(Im *im)
|
||||
srvdrop(Im *im, int notify)
|
||||
{
|
||||
if(im->fd >= 0)
|
||||
close(im->fd);
|
||||
im->fd = -1;
|
||||
im->ext = 0;
|
||||
im->effective = 1;
|
||||
im->caretsent = 0;
|
||||
setpreedit(im, "", 0);
|
||||
if(notify)
|
||||
setpreedit(im, "", 0);
|
||||
else{
|
||||
im->pre[0] = '\0';
|
||||
im->prelen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
srvclose(Im *im)
|
||||
{
|
||||
srvdrop(im, 1);
|
||||
}
|
||||
|
||||
static int
|
||||
validtext(const char *s, size_t n)
|
||||
{
|
||||
return s[n] == '\0' && memchr(s, '\0', n) == NULL &&
|
||||
g_utf8_validate(s, n, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
@@ -80,6 +102,11 @@ readresp(Im *im, int want, int update, char *commit, int ncommit,
|
||||
if(ipcreadresp(im->fd, want, commit, ncommit, pre, sizeof pre,
|
||||
resp) < 0)
|
||||
return -1;
|
||||
if(!validtext(commit, resp->commitlen) ||
|
||||
(want && !validtext(pre, resp->preeditlen))){
|
||||
errno = EPROTO;
|
||||
return -1;
|
||||
}
|
||||
if(update)
|
||||
setpreedit(im, pre, resp->preeditlen);
|
||||
return 0;
|
||||
@@ -188,8 +215,7 @@ srvconnect(Im *im)
|
||||
return -1;
|
||||
}
|
||||
im->ext = resp.eaten != 0;
|
||||
im->effective = im->ext ? im->usepreedit : 1;
|
||||
if(!im->effective)
|
||||
if(!im->usepreedit)
|
||||
setpreedit(im, "", 0);
|
||||
if(im->ext && sendcaret(im) < 0){
|
||||
srvclose(im);
|
||||
@@ -228,6 +254,40 @@ mget(uint32_t state)
|
||||
return m;
|
||||
}
|
||||
|
||||
static void
|
||||
simplecommit(GtkIMContext *ctx, const char *s, Im *im)
|
||||
{
|
||||
(void)ctx;
|
||||
(void)s;
|
||||
if(im->insimple)
|
||||
im->simpledone = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
simpleend(GtkIMContext *ctx, Im *im)
|
||||
{
|
||||
(void)ctx;
|
||||
if(im->insimple)
|
||||
im->simpledone = 1;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
simplefilter(GtkIMContext *ctx, GdkEventKey *ev, int release)
|
||||
{
|
||||
Im *im;
|
||||
gboolean r;
|
||||
|
||||
im = (Im*)ctx;
|
||||
im->simpleactive = 1;
|
||||
im->simpledone = 0;
|
||||
im->insimple = 1;
|
||||
r = parentim->filter_keypress(ctx, ev);
|
||||
im->insimple = 0;
|
||||
if((!r && !release) || im->simpledone)
|
||||
im->simpleactive = 0;
|
||||
return r;
|
||||
}
|
||||
|
||||
static void
|
||||
sendreset(Im *im)
|
||||
{
|
||||
@@ -239,9 +299,9 @@ sendreset(Im *im)
|
||||
setpreedit(im, "", 0);
|
||||
return;
|
||||
}
|
||||
ipcpackreset(buf, im->effective);
|
||||
ipcpackreset(buf, im->usepreedit);
|
||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||
readresp(im, im->effective, 0, commit,
|
||||
readresp(im, im->usepreedit, 0, commit,
|
||||
sizeof commit, &resp) < 0){
|
||||
srvclose(im);
|
||||
return;
|
||||
@@ -249,22 +309,6 @@ sendreset(Im *im)
|
||||
setpreedit(im, "", 0);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
plaincommit(GtkIMContext *ctx, uint32_t key, uint32_t mod)
|
||||
{
|
||||
char u[8];
|
||||
int n;
|
||||
|
||||
if(mod & (Mctrl|Malt|Msuper))
|
||||
return FALSE;
|
||||
if(key < 0x20 || key >= Kspec)
|
||||
return FALSE;
|
||||
n = g_unichar_to_utf8(key, u);
|
||||
u[n] = '\0';
|
||||
g_signal_emit_by_name(ctx, "commit", u);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
||||
{
|
||||
@@ -275,33 +319,36 @@ kpress(GtkIMContext *ctx, GdkEventKey *ev)
|
||||
Ipcresp resp;
|
||||
|
||||
im = (Im*)ctx;
|
||||
if(ev->type != GDK_KEY_PRESS)
|
||||
if(ev->type != GDK_KEY_PRESS){
|
||||
if(im->simpleactive)
|
||||
return simplefilter(ctx, ev, 1);
|
||||
return FALSE;
|
||||
}
|
||||
if(im->simpleactive)
|
||||
return simplefilter(ctx, ev, 0);
|
||||
key = kget(ev->keyval);
|
||||
if(key == 0)
|
||||
return FALSE;
|
||||
mod = mget(ev->state);
|
||||
if(im->private)
|
||||
return plaincommit(ctx, key, mod);
|
||||
if(im->private || key == 0)
|
||||
return simplefilter(ctx, ev, 0);
|
||||
if(srvconnect(im) < 0)
|
||||
return plaincommit(ctx, key, mod);
|
||||
return simplefilter(ctx, ev, 0);
|
||||
/* A retained GDK window may have moved since the last cursor report. */
|
||||
if(sendcaret(im) < 0){
|
||||
srvclose(im);
|
||||
return plaincommit(ctx, key, mod);
|
||||
return simplefilter(ctx, ev, 0);
|
||||
}
|
||||
ipcpackreq(buf, im->effective, mod, key);
|
||||
ipcpackreq(buf, im->usepreedit, mod, key);
|
||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||
readresp(im, im->effective, im->effective, commit,
|
||||
readresp(im, im->usepreedit, im->usepreedit, commit,
|
||||
sizeof commit, &resp) < 0){
|
||||
srvclose(im);
|
||||
return plaincommit(ctx, key, mod);
|
||||
return simplefilter(ctx, ev, 0);
|
||||
}
|
||||
if(commit[0] != '\0')
|
||||
g_signal_emit_by_name(ctx, "commit", commit);
|
||||
if(resp.eaten)
|
||||
return TRUE;
|
||||
return plaincommit(ctx, key, mod);
|
||||
return simplefilter(ctx, ev, 0);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -312,6 +359,10 @@ getpreedit(GtkIMContext *ctx, gchar **str, PangoAttrList **attrs,
|
||||
PangoAttribute *u;
|
||||
|
||||
im = (Im*)ctx;
|
||||
if(im->simpleactive){
|
||||
parentim->get_preedit_string(ctx, str, attrs, cursor_pos);
|
||||
return;
|
||||
}
|
||||
if(str)
|
||||
*str = g_strdup(im->pre);
|
||||
if(attrs){
|
||||
@@ -330,6 +381,9 @@ getpreedit(GtkIMContext *ctx, gchar **str, PangoAttrList **attrs,
|
||||
static void
|
||||
reset(GtkIMContext *ctx)
|
||||
{
|
||||
if(parentim->reset != NULL)
|
||||
parentim->reset(ctx);
|
||||
((Im*)ctx)->simpleactive = 0;
|
||||
sendreset((Im*)ctx);
|
||||
}
|
||||
|
||||
@@ -339,6 +393,9 @@ focusout(GtkIMContext *ctx)
|
||||
Im *im;
|
||||
|
||||
im = (Im*)ctx;
|
||||
if(parentim->focus_out != NULL)
|
||||
parentim->focus_out(ctx);
|
||||
im->simpleactive = 0;
|
||||
sendreset(im);
|
||||
/* Closing the context connection releases engine ownership. */
|
||||
srvclose(im);
|
||||
@@ -354,13 +411,15 @@ setusepreedit(GtkIMContext *ctx, gboolean use)
|
||||
|
||||
im = (Im*)ctx;
|
||||
use = use != FALSE;
|
||||
if(parentim->set_use_preedit != NULL)
|
||||
parentim->set_use_preedit(ctx, use);
|
||||
if(im->usepreedit == use)
|
||||
return;
|
||||
im->usepreedit = use;
|
||||
if(im->fd < 0 || !im->ext){
|
||||
im->effective = im->ext ? use : 1;
|
||||
if(!use)
|
||||
setpreedit(im, "", 0);
|
||||
if(im->fd < 0 || !im->ext)
|
||||
return;
|
||||
}
|
||||
ipcpackcap(buf, use);
|
||||
if(ipcsend(im->fd, buf, sizeof buf) < 0 ||
|
||||
readresp(im, use, use, commit, sizeof commit, &resp) < 0 ||
|
||||
@@ -368,9 +427,6 @@ setusepreedit(GtkIMContext *ctx, gboolean use)
|
||||
srvclose(im);
|
||||
return;
|
||||
}
|
||||
im->effective = use;
|
||||
if(!use)
|
||||
setpreedit(im, "", 0);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -381,6 +437,8 @@ setclientwindow(GtkIMContext *ctx, GdkWindow *win)
|
||||
im = (Im*)ctx;
|
||||
if(win != NULL && gdk_window_is_destroyed(win))
|
||||
win = NULL;
|
||||
if(parentim->set_client_window != NULL)
|
||||
parentim->set_client_window(ctx, win);
|
||||
if(im->win == win)
|
||||
return;
|
||||
if(win != NULL)
|
||||
@@ -397,6 +455,8 @@ setcursorlocation(GtkIMContext *ctx, GdkRectangle *area)
|
||||
Im *im;
|
||||
|
||||
im = (Im*)ctx;
|
||||
if(parentim->set_cursor_location != NULL)
|
||||
parentim->set_cursor_location(ctx, area);
|
||||
if(im->win != NULL && gdk_window_is_destroyed(im->win))
|
||||
dropwindow(im);
|
||||
if(area == NULL || im->win == NULL)
|
||||
@@ -432,18 +492,18 @@ purposechanged(GObject *obj, GParamSpec *pspec, gpointer data)
|
||||
return;
|
||||
im->private = private;
|
||||
if(private)
|
||||
sendreset(im);
|
||||
reset(GTK_IM_CONTEXT(im));
|
||||
}
|
||||
|
||||
static void
|
||||
finalize(GObject *obj)
|
||||
dispose(GObject *obj)
|
||||
{
|
||||
Im *im;
|
||||
|
||||
im = (Im*)obj;
|
||||
srvclose(im);
|
||||
srvdrop(im, 0);
|
||||
dropwindow(im);
|
||||
G_OBJECT_CLASS(g_type_class_peek_parent(G_OBJECT_GET_CLASS(obj)))->finalize(obj);
|
||||
parentobject->dispose(obj);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -453,12 +513,13 @@ init(Im *im)
|
||||
|
||||
im->fd = -1;
|
||||
im->usepreedit = 1;
|
||||
im->effective = 1;
|
||||
im->pre[0] = '\0';
|
||||
g_object_get(im, "input-purpose", &purpose, NULL);
|
||||
im->private = isprivate(purpose);
|
||||
g_signal_connect(im, "notify::input-purpose",
|
||||
G_CALLBACK(purposechanged), NULL);
|
||||
g_signal_connect(im, "commit", G_CALLBACK(simplecommit), im);
|
||||
g_signal_connect(im, "preedit-end", G_CALLBACK(simpleend), im);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -469,6 +530,8 @@ classinit(ImClass *klass)
|
||||
|
||||
ic = GTK_IM_CONTEXT_CLASS(klass);
|
||||
oc = G_OBJECT_CLASS(klass);
|
||||
parentim = g_type_class_peek_parent(klass);
|
||||
parentobject = G_OBJECT_CLASS(parentim);
|
||||
ic->filter_keypress = kpress;
|
||||
ic->get_preedit_string = getpreedit;
|
||||
ic->reset = reset;
|
||||
@@ -476,7 +539,7 @@ classinit(ImClass *klass)
|
||||
ic->set_use_preedit = setusepreedit;
|
||||
ic->set_client_window = setclientwindow;
|
||||
ic->set_cursor_location = setcursorlocation;
|
||||
oc->finalize = finalize;
|
||||
oc->dispose = dispose;
|
||||
}
|
||||
|
||||
static const GtkIMContextInfo info = {
|
||||
@@ -501,7 +564,8 @@ im_module_init(GTypeModule *mod)
|
||||
0,
|
||||
(GInstanceInitFunc)init,
|
||||
};
|
||||
imtype = g_type_module_register_type(mod, GTK_TYPE_IM_CONTEXT, "strans-gtk", &ti, 0);
|
||||
imtype = g_type_module_register_type(mod, GTK_TYPE_IM_CONTEXT_SIMPLE,
|
||||
"strans-gtk", &ti, 0);
|
||||
}
|
||||
|
||||
G_MODULE_EXPORT void
|
||||
|
||||
Reference in New Issue
Block a user