xim: place popup from input context
This commit is contained in:
@@ -80,6 +80,8 @@ void xim_adapter_key_contract(struct ct*);
|
|||||||
void xim_adapter_release_lifecycle(struct ct*);
|
void xim_adapter_release_lifecycle(struct ct*);
|
||||||
void xim_adapter_free_waits_for_release(struct ct*);
|
void xim_adapter_free_waits_for_release(struct ct*);
|
||||||
void xim_adapter_styles(struct ct*);
|
void xim_adapter_styles(struct ct*);
|
||||||
|
void xim_adapter_placement(struct ct*);
|
||||||
|
void xim_adapter_placement_updates(struct ct*);
|
||||||
void xim_adapter_encoding_negotiation(struct ct*);
|
void xim_adapter_encoding_negotiation(struct ct*);
|
||||||
void xim_adapter_callback_replacement(struct ct*);
|
void xim_adapter_callback_replacement(struct ct*);
|
||||||
void xim_adapter_callback_unicode(struct ct*);
|
void xim_adapter_callback_unicode(struct ct*);
|
||||||
|
|||||||
@@ -134,6 +134,8 @@ static const struct ct_test tests[] = {
|
|||||||
{ "xim/adapter-release-lifecycle", xim_adapter_release_lifecycle },
|
{ "xim/adapter-release-lifecycle", xim_adapter_release_lifecycle },
|
||||||
{ "xim/adapter-free-waits-release", xim_adapter_free_waits_for_release },
|
{ "xim/adapter-free-waits-release", xim_adapter_free_waits_for_release },
|
||||||
{ "xim/styles", xim_adapter_styles },
|
{ "xim/styles", xim_adapter_styles },
|
||||||
|
{ "xim/placement", xim_adapter_placement },
|
||||||
|
{ "xim/placement-updates", xim_adapter_placement_updates },
|
||||||
{ "xim/encoding-negotiation", xim_adapter_encoding_negotiation },
|
{ "xim/encoding-negotiation", xim_adapter_encoding_negotiation },
|
||||||
{ "xim/callback-replacement", xim_adapter_callback_replacement },
|
{ "xim/callback-replacement", xim_adapter_callback_replacement },
|
||||||
{ "xim/callback-unicode", xim_adapter_callback_unicode },
|
{ "xim/callback-unicode", xim_adapter_callback_unicode },
|
||||||
|
|||||||
@@ -1,20 +1,63 @@
|
|||||||
#include <xcb/xcb.h>
|
#include <xcb/xcb.h>
|
||||||
#include <xcb-imdkit/imdkit.h>
|
#include <xcb-imdkit/imdkit.h>
|
||||||
|
|
||||||
|
typedef struct Icbinding Icbinding;
|
||||||
|
struct Icbinding
|
||||||
|
{
|
||||||
|
xcb_im_input_context_t *ic;
|
||||||
|
void *data;
|
||||||
|
xcb_window_t clientwin;
|
||||||
|
xcb_window_t focuswin;
|
||||||
|
uint32_t preattrmask;
|
||||||
|
xcb_im_preedit_attr_t preattr;
|
||||||
|
};
|
||||||
|
|
||||||
|
static Icbinding icbindings[8];
|
||||||
|
|
||||||
|
static Icbinding*
|
||||||
|
wirebinding(xcb_im_input_context_t *ic)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i = 0; i < 8; i++)
|
||||||
|
if(icbindings[i].ic == ic)
|
||||||
|
return &icbindings[i];
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void wirecommit(xcb_im_t*, xcb_im_input_context_t*, uint32_t,
|
static void wirecommit(xcb_im_t*, xcb_im_input_context_t*, uint32_t,
|
||||||
const char*, uint32_t, uint32_t);
|
const char*, uint32_t, uint32_t);
|
||||||
static void wirestart(xcb_im_t*, xcb_im_input_context_t*);
|
static void wirestart(xcb_im_t*, xcb_im_input_context_t*);
|
||||||
static void wiredraw(xcb_im_t*, xcb_im_input_context_t*,
|
static void wiredraw(xcb_im_t*, xcb_im_input_context_t*,
|
||||||
xcb_im_preedit_draw_fr_t*);
|
xcb_im_preedit_draw_fr_t*);
|
||||||
static void wiredone(xcb_im_t*, xcb_im_input_context_t*);
|
static void wiredone(xcb_im_t*, xcb_im_input_context_t*);
|
||||||
static void* wiregetdata(xcb_im_input_context_t*);
|
static xcb_get_geometry_cookie_t wiregeometry(xcb_connection_t*, xcb_drawable_t);
|
||||||
|
static xcb_get_geometry_reply_t* wiregeometryreply(xcb_connection_t*,
|
||||||
|
xcb_get_geometry_cookie_t, xcb_generic_error_t**);
|
||||||
|
static xcb_translate_coordinates_cookie_t wiretranslate(xcb_connection_t*,
|
||||||
|
xcb_window_t, xcb_window_t, int16_t, int16_t);
|
||||||
|
static xcb_translate_coordinates_reply_t* wiretranslatereply(xcb_connection_t*,
|
||||||
|
xcb_translate_coordinates_cookie_t, xcb_generic_error_t**);
|
||||||
static int wireflush(xcb_connection_t*);
|
static int wireflush(xcb_connection_t*);
|
||||||
|
|
||||||
#define xcb_im_commit_string wirecommit
|
#define xcb_im_commit_string wirecommit
|
||||||
#define xcb_im_preedit_start_callback wirestart
|
#define xcb_im_preedit_start_callback wirestart
|
||||||
#define xcb_im_preedit_draw_callback wiredraw
|
#define xcb_im_preedit_draw_callback wiredraw
|
||||||
#define xcb_im_preedit_done_callback wiredone
|
#define xcb_im_preedit_done_callback wiredone
|
||||||
#define xcb_im_input_context_get_data wiregetdata
|
#define xcb_im_input_context_get_data(ic) \
|
||||||
|
(wirebinding(ic) == nil ? nil : wirebinding(ic)->data)
|
||||||
|
#define xcb_im_input_context_get_client_window(ic) \
|
||||||
|
(wirebinding(ic) == nil ? XCB_NONE : wirebinding(ic)->clientwin)
|
||||||
|
#define xcb_im_input_context_get_focus_window(ic) \
|
||||||
|
(wirebinding(ic) == nil ? XCB_NONE : wirebinding(ic)->focuswin)
|
||||||
|
#define xcb_im_input_context_get_preedit_attr_mask(ic) \
|
||||||
|
(wirebinding(ic) == nil ? 0 : wirebinding(ic)->preattrmask)
|
||||||
|
#define xcb_im_input_context_get_preedit_attr(ic) \
|
||||||
|
(wirebinding(ic) == nil ? nil : &wirebinding(ic)->preattr)
|
||||||
|
#define xcb_get_geometry wiregeometry
|
||||||
|
#define xcb_get_geometry_reply wiregeometryreply
|
||||||
|
#define xcb_translate_coordinates wiretranslate
|
||||||
|
#define xcb_translate_coordinates_reply wiretranslatereply
|
||||||
#define xcb_flush wireflush
|
#define xcb_flush wireflush
|
||||||
#include "xim/xim.c"
|
#include "xim/xim.c"
|
||||||
#undef xcb_im_commit_string
|
#undef xcb_im_commit_string
|
||||||
@@ -22,6 +65,14 @@ static int wireflush(xcb_connection_t*);
|
|||||||
#undef xcb_im_preedit_draw_callback
|
#undef xcb_im_preedit_draw_callback
|
||||||
#undef xcb_im_preedit_done_callback
|
#undef xcb_im_preedit_done_callback
|
||||||
#undef xcb_im_input_context_get_data
|
#undef xcb_im_input_context_get_data
|
||||||
|
#undef xcb_im_input_context_get_client_window
|
||||||
|
#undef xcb_im_input_context_get_focus_window
|
||||||
|
#undef xcb_im_input_context_get_preedit_attr_mask
|
||||||
|
#undef xcb_im_input_context_get_preedit_attr
|
||||||
|
#undef xcb_get_geometry
|
||||||
|
#undef xcb_get_geometry_reply
|
||||||
|
#undef xcb_translate_coordinates
|
||||||
|
#undef xcb_translate_coordinates_reply
|
||||||
#undef xcb_flush
|
#undef xcb_flush
|
||||||
#include "cutest/cutest.h"
|
#include "cutest/cutest.h"
|
||||||
|
|
||||||
@@ -51,17 +102,23 @@ struct Wirecall
|
|||||||
u32int feedback[Maxrunes];
|
u32int feedback[Maxrunes];
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Icbinding Icbinding;
|
typedef struct Wirewin Wirewin;
|
||||||
struct Icbinding
|
struct Wirewin
|
||||||
{
|
{
|
||||||
xcb_im_input_context_t *ic;
|
xcb_window_t win;
|
||||||
void *data;
|
int geometryok;
|
||||||
|
int translateok;
|
||||||
|
int samescreen;
|
||||||
|
int rootx;
|
||||||
|
int rooty;
|
||||||
|
int height;
|
||||||
};
|
};
|
||||||
|
|
||||||
static Wirecall wirecalls[Maxwire];
|
static Wirecall wirecalls[Maxwire];
|
||||||
static Icbinding icbindings[8];
|
static Wirewin wirewins[8];
|
||||||
static int nwirecalls;
|
static int nwirecalls;
|
||||||
static int nflush;
|
static int nflush;
|
||||||
|
static int transx, transy;
|
||||||
|
|
||||||
static Wirecall*
|
static Wirecall*
|
||||||
newwire(int op, xcb_im_input_context_t *ic)
|
newwire(int op, xcb_im_input_context_t *ic)
|
||||||
@@ -133,17 +190,80 @@ wiredone(xcb_im_t *im, xcb_im_input_context_t *ic)
|
|||||||
newwire(Wdone, ic);
|
newwire(Wdone, ic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void*
|
static Wirewin*
|
||||||
wiregetdata(xcb_im_input_context_t *ic)
|
wirewindow(xcb_window_t win)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
for(i = 0; i < nelem(icbindings); i++)
|
for(i = 0; i < nelem(wirewins); i++)
|
||||||
if(icbindings[i].ic == ic)
|
if(wirewins[i].win == win)
|
||||||
return icbindings[i].data;
|
return &wirewins[i];
|
||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static xcb_get_geometry_cookie_t
|
||||||
|
wiregeometry(xcb_connection_t *c, xcb_drawable_t drawable)
|
||||||
|
{
|
||||||
|
xcb_get_geometry_cookie_t cookie;
|
||||||
|
|
||||||
|
USED(c);
|
||||||
|
cookie.sequence = drawable;
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xcb_get_geometry_reply_t*
|
||||||
|
wiregeometryreply(xcb_connection_t *c, xcb_get_geometry_cookie_t cookie,
|
||||||
|
xcb_generic_error_t **error)
|
||||||
|
{
|
||||||
|
xcb_get_geometry_reply_t *reply;
|
||||||
|
Wirewin *w;
|
||||||
|
|
||||||
|
USED(c);
|
||||||
|
USED(error);
|
||||||
|
w = wirewindow(cookie.sequence);
|
||||||
|
if(w == nil || !w->geometryok)
|
||||||
|
return nil;
|
||||||
|
reply = calloc(1, sizeof *reply);
|
||||||
|
if(reply != nil)
|
||||||
|
reply->height = w->height;
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xcb_translate_coordinates_cookie_t
|
||||||
|
wiretranslate(xcb_connection_t *c, xcb_window_t src, xcb_window_t dst,
|
||||||
|
int16_t x, int16_t y)
|
||||||
|
{
|
||||||
|
xcb_translate_coordinates_cookie_t cookie;
|
||||||
|
|
||||||
|
USED(c);
|
||||||
|
USED(dst);
|
||||||
|
cookie.sequence = src;
|
||||||
|
transx = x;
|
||||||
|
transy = y;
|
||||||
|
return cookie;
|
||||||
|
}
|
||||||
|
|
||||||
|
static xcb_translate_coordinates_reply_t*
|
||||||
|
wiretranslatereply(xcb_connection_t *c,
|
||||||
|
xcb_translate_coordinates_cookie_t cookie, xcb_generic_error_t **error)
|
||||||
|
{
|
||||||
|
xcb_translate_coordinates_reply_t *reply;
|
||||||
|
Wirewin *w;
|
||||||
|
|
||||||
|
USED(c);
|
||||||
|
USED(error);
|
||||||
|
w = wirewindow(cookie.sequence);
|
||||||
|
if(w == nil || !w->translateok)
|
||||||
|
return nil;
|
||||||
|
reply = calloc(1, sizeof *reply);
|
||||||
|
if(reply != nil){
|
||||||
|
reply->same_screen = w->samescreen;
|
||||||
|
reply->dst_x = w->rootx + transx;
|
||||||
|
reply->dst_y = w->rooty + transy;
|
||||||
|
}
|
||||||
|
return reply;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
wireflush(xcb_connection_t *c)
|
wireflush(xcb_connection_t *c)
|
||||||
{
|
{
|
||||||
@@ -157,8 +277,10 @@ wireclear(void)
|
|||||||
{
|
{
|
||||||
memset(wirecalls, 0, sizeof wirecalls);
|
memset(wirecalls, 0, sizeof wirecalls);
|
||||||
memset(icbindings, 0, sizeof icbindings);
|
memset(icbindings, 0, sizeof icbindings);
|
||||||
|
memset(wirewins, 0, sizeof wirewins);
|
||||||
nwirecalls = 0;
|
nwirecalls = 0;
|
||||||
nflush = 0;
|
nflush = 0;
|
||||||
|
transx = transy = 0;
|
||||||
preowner = nil;
|
preowner = nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -169,6 +291,23 @@ wirebind(int n, xcb_im_input_context_t *ic, Ic *state)
|
|||||||
icbindings[n].data = state;
|
icbindings[n].data = state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static Wirewin*
|
||||||
|
wirewin(int n, xcb_window_t win, int x, int y, int h)
|
||||||
|
{
|
||||||
|
Wirewin *w;
|
||||||
|
|
||||||
|
w = &wirewins[n];
|
||||||
|
memset(w, 0, sizeof *w);
|
||||||
|
w->win = win;
|
||||||
|
w->geometryok = 1;
|
||||||
|
w->translateok = 1;
|
||||||
|
w->samescreen = 1;
|
||||||
|
w->rootx = x;
|
||||||
|
w->rooty = y;
|
||||||
|
w->height = h;
|
||||||
|
return w;
|
||||||
|
}
|
||||||
|
|
||||||
void testengineinit(int);
|
void testengineinit(int);
|
||||||
void testenginehandle(Keyreq*);
|
void testenginehandle(Keyreq*);
|
||||||
void* testengineowner(void);
|
void* testengineowner(void);
|
||||||
@@ -506,6 +645,131 @@ xim_adapter_styles(struct ct *t)
|
|||||||
CT_EQ_INT(t, Cclientpreedit, state.cap);
|
CT_EQ_INT(t, Cclientpreedit, state.cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xim_adapter_placement(struct ct *t)
|
||||||
|
{
|
||||||
|
static const struct {
|
||||||
|
u32int style;
|
||||||
|
u32int mask;
|
||||||
|
int fgeo;
|
||||||
|
int ftrans;
|
||||||
|
int cgeo;
|
||||||
|
int ctrans;
|
||||||
|
int valid;
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} cases[] = {
|
||||||
|
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
|
||||||
|
XCB_XIM_XNSpotLocation_MASK, 1, 1, 1, 1, 1, 103, 204},
|
||||||
|
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
|
||||||
|
XCB_XIM_XNSpotLocation_MASK, 1, 0, 1, 1, 1, 303, 404},
|
||||||
|
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
|
||||||
|
0, 1, 1, 1, 1, 1, 100, 230},
|
||||||
|
{XCB_IM_PreeditNothing | XCB_IM_StatusNothing,
|
||||||
|
XCB_XIM_XNSpotLocation_MASK, 1, 1, 1, 1, 1, 100, 230},
|
||||||
|
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
|
||||||
|
0, 0, 1, 1, 1, 1, 300, 440},
|
||||||
|
{XCB_IM_PreeditPosition | XCB_IM_StatusNothing,
|
||||||
|
0, 0, 1, 0, 1, 0, 0, 0},
|
||||||
|
};
|
||||||
|
xcb_im_input_context_t *ic;
|
||||||
|
Icbinding *b;
|
||||||
|
Wirewin *focus, *client;
|
||||||
|
Ic state;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
ic = (xcb_im_input_context_t*)(uintptr)70;
|
||||||
|
for(i = 0; i < nelem(cases); i++){
|
||||||
|
wireclear();
|
||||||
|
memset(&state, 0, sizeof state);
|
||||||
|
state.xic = ic;
|
||||||
|
state.style = cases[i].style;
|
||||||
|
state.caret.valid = 1;
|
||||||
|
state.caret.x = state.caret.y = 9;
|
||||||
|
wirebind(0, ic, &state);
|
||||||
|
b = &icbindings[0];
|
||||||
|
b->focuswin = 10;
|
||||||
|
b->clientwin = 20;
|
||||||
|
b->preattrmask = cases[i].mask;
|
||||||
|
b->preattr.spot_location.x = 3;
|
||||||
|
b->preattr.spot_location.y = 4;
|
||||||
|
focus = wirewin(0, 10, 100, 200, 30);
|
||||||
|
client = wirewin(1, 20, 300, 400, 40);
|
||||||
|
focus->geometryok = cases[i].fgeo;
|
||||||
|
focus->translateok = cases[i].ftrans;
|
||||||
|
client->geometryok = cases[i].cgeo;
|
||||||
|
client->translateok = cases[i].ctrans;
|
||||||
|
refreshplace(&state);
|
||||||
|
CT_EQ_UINT(t, 10, state.focuswin);
|
||||||
|
CT_EQ_UINT(t, 20, state.clientwin);
|
||||||
|
CT_EQ_INT(t, cases[i].style ==
|
||||||
|
(XCB_IM_PreeditPosition | XCB_IM_StatusNothing) &&
|
||||||
|
cases[i].mask != 0, state.hasspot);
|
||||||
|
CT_EQ_INT(t, cases[i].valid, state.caret.valid);
|
||||||
|
CT_EQ_INT(t, cases[i].x, state.caret.x);
|
||||||
|
CT_EQ_INT(t, cases[i].y, state.caret.y);
|
||||||
|
CT_EQ_INT(t, 0, state.caret.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
xim_adapter_placement_updates(struct ct *t)
|
||||||
|
{
|
||||||
|
xcb_im_packet_header_fr_t hdr;
|
||||||
|
xcb_im_input_context_t *ic;
|
||||||
|
Icbinding *b;
|
||||||
|
Ximfix f;
|
||||||
|
Keyreq req;
|
||||||
|
Keyres res;
|
||||||
|
Ic state;
|
||||||
|
|
||||||
|
ic = (xcb_im_input_context_t*)(uintptr)71;
|
||||||
|
memset(&state, 0, sizeof state);
|
||||||
|
if(!ximbegin(t, &f, LangJP))
|
||||||
|
goto cleanup;
|
||||||
|
wireclear();
|
||||||
|
state.xic = ic;
|
||||||
|
state.style = XCB_IM_PreeditPosition | XCB_IM_StatusNothing;
|
||||||
|
wirebind(0, ic, &state);
|
||||||
|
b = &icbindings[0];
|
||||||
|
b->focuswin = 11;
|
||||||
|
b->clientwin = 21;
|
||||||
|
b->preattrmask = XCB_XIM_XNSpotLocation_MASK;
|
||||||
|
b->preattr.spot_location.x = 5;
|
||||||
|
b->preattr.spot_location.y = 6;
|
||||||
|
wirewin(0, 11, 100, 200, 30);
|
||||||
|
CT_CHECK(t, readattrs(&state));
|
||||||
|
place(&state);
|
||||||
|
CT_CHECK(t, !readattrs(&state));
|
||||||
|
keypress(&state, 'x', 0, &res);
|
||||||
|
req = nexttrace(t, &f, Keypress, &state);
|
||||||
|
CT_CHECK(t, req.caret.valid);
|
||||||
|
CT_EQ_INT(t, 105, req.caret.x);
|
||||||
|
CT_EQ_INT(t, 206, req.caret.y);
|
||||||
|
|
||||||
|
b->preattr.spot_location.x = 15;
|
||||||
|
b->preattr.spot_location.y = 16;
|
||||||
|
memset(&hdr, 0, sizeof hdr);
|
||||||
|
hdr.major_opcode = XCB_XIM_SET_IC_VALUES;
|
||||||
|
callback(nil, nil, ic, &hdr, nil, nil, nil);
|
||||||
|
req = nexttrace(t, &f, Keycaret, &state);
|
||||||
|
CT_CHECK(t, req.caret.valid);
|
||||||
|
CT_EQ_INT(t, 115, req.caret.x);
|
||||||
|
CT_EQ_INT(t, 216, req.caret.y);
|
||||||
|
CT_EQ_INT(t, 15, state.spot.x);
|
||||||
|
CT_EQ_INT(t, 16, state.spot.y);
|
||||||
|
CT_CHECK(t, !readattrs(&state));
|
||||||
|
b->preattrmask = 0;
|
||||||
|
wirewins[0].geometryok = 0;
|
||||||
|
hdr.major_opcode = XCB_XIM_SET_IC_FOCUS;
|
||||||
|
callback(nil, nil, ic, &hdr, nil, nil, nil);
|
||||||
|
req = nexttrace(t, &f, Keycaret, &state);
|
||||||
|
CT_CHECK(t, !req.caret.valid);
|
||||||
|
cleanup:
|
||||||
|
preowner = nil;
|
||||||
|
ximend(&f);
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
xim_adapter_encoding_negotiation(struct ct *t)
|
xim_adapter_encoding_negotiation(struct ct *t)
|
||||||
{
|
{
|
||||||
|
|||||||
132
xim/xim.c
132
xim/xim.c
@@ -21,6 +21,11 @@ struct Ic
|
|||||||
int encoding;
|
int encoding;
|
||||||
int prestarted;
|
int prestarted;
|
||||||
int nprerune;
|
int nprerune;
|
||||||
|
xcb_window_t clientwin;
|
||||||
|
xcb_window_t focuswin;
|
||||||
|
xcb_point_t spot;
|
||||||
|
int hasspot;
|
||||||
|
Caret caret;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Clientenc Clientenc;
|
typedef struct Clientenc Clientenc;
|
||||||
@@ -41,6 +46,7 @@ static xcb_im_t *xim;
|
|||||||
static xcb_keysym_t *kmap;
|
static xcb_keysym_t *kmap;
|
||||||
static uint8_t minkc, maxkc;
|
static uint8_t minkc, maxkc;
|
||||||
static uint8_t symsper;
|
static uint8_t symsper;
|
||||||
|
static xcb_window_t rootwin;
|
||||||
static int opened;
|
static int opened;
|
||||||
static Ic *ics;
|
static Ic *ics;
|
||||||
static Ic *preowner;
|
static Ic *preowner;
|
||||||
@@ -181,6 +187,108 @@ getscreen(int scr)
|
|||||||
return nil;
|
return nil;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
readattrs(Ic *state)
|
||||||
|
{
|
||||||
|
const xcb_im_preedit_attr_t *attr;
|
||||||
|
xcb_window_t clientwin, focuswin;
|
||||||
|
xcb_point_t spot;
|
||||||
|
int changed, hasspot;
|
||||||
|
|
||||||
|
clientwin = xcb_im_input_context_get_client_window(state->xic);
|
||||||
|
focuswin = xcb_im_input_context_get_focus_window(state->xic);
|
||||||
|
spot = state->spot;
|
||||||
|
hasspot = 0;
|
||||||
|
if(state->style == (XCB_IM_PreeditPosition | XCB_IM_StatusNothing) &&
|
||||||
|
(xcb_im_input_context_get_preedit_attr_mask(state->xic) &
|
||||||
|
XCB_XIM_XNSpotLocation_MASK)){
|
||||||
|
attr = xcb_im_input_context_get_preedit_attr(state->xic);
|
||||||
|
if(attr != nil){
|
||||||
|
spot = attr->spot_location;
|
||||||
|
hasspot = 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
changed = clientwin != state->clientwin || focuswin != state->focuswin ||
|
||||||
|
hasspot != state->hasspot || (hasspot &&
|
||||||
|
(spot.x != state->spot.x || spot.y != state->spot.y));
|
||||||
|
state->clientwin = clientwin;
|
||||||
|
state->focuswin = focuswin;
|
||||||
|
state->spot = spot;
|
||||||
|
state->hasspot = hasspot;
|
||||||
|
return changed;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
translate(xcb_window_t win, int x, int y, Caret *caret)
|
||||||
|
{
|
||||||
|
xcb_translate_coordinates_cookie_t cookie;
|
||||||
|
xcb_translate_coordinates_reply_t *reply;
|
||||||
|
|
||||||
|
if(win == XCB_NONE)
|
||||||
|
return 0;
|
||||||
|
cookie = xcb_translate_coordinates(conn, win, rootwin, x, y);
|
||||||
|
reply = xcb_translate_coordinates_reply(conn, cookie, nil);
|
||||||
|
if(reply == nil || !reply->same_screen){
|
||||||
|
free(reply);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
caret->valid = 1;
|
||||||
|
caret->x = reply->dst_x;
|
||||||
|
caret->y = reply->dst_y;
|
||||||
|
caret->h = 0;
|
||||||
|
free(reply);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
placebottom(Ic *state, xcb_window_t win)
|
||||||
|
{
|
||||||
|
xcb_get_geometry_cookie_t gcookie;
|
||||||
|
xcb_get_geometry_reply_t *geometry;
|
||||||
|
int height;
|
||||||
|
|
||||||
|
if(win == XCB_NONE)
|
||||||
|
return 0;
|
||||||
|
gcookie = xcb_get_geometry(conn, win);
|
||||||
|
geometry = xcb_get_geometry_reply(conn, gcookie, nil);
|
||||||
|
if(geometry == nil)
|
||||||
|
return 0;
|
||||||
|
height = geometry->height;
|
||||||
|
free(geometry);
|
||||||
|
if(!translate(win, 0, 0, &state->caret))
|
||||||
|
return 0;
|
||||||
|
state->caret.y += height;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
place(Ic *state)
|
||||||
|
{
|
||||||
|
xcb_window_t win[2];
|
||||||
|
int i, nwin;
|
||||||
|
|
||||||
|
memset(&state->caret, 0, sizeof state->caret);
|
||||||
|
win[0] = state->focuswin;
|
||||||
|
nwin = 1;
|
||||||
|
if(state->clientwin != state->focuswin)
|
||||||
|
win[nwin++] = state->clientwin;
|
||||||
|
if(state->hasspot)
|
||||||
|
for(i = 0; i < nwin; i++)
|
||||||
|
if(translate(win[i], state->spot.x, state->spot.y,
|
||||||
|
&state->caret))
|
||||||
|
return;
|
||||||
|
for(i = 0; i < nwin; i++)
|
||||||
|
if(placebottom(state, win[i]))
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
refreshplace(Ic *state)
|
||||||
|
{
|
||||||
|
readattrs(state);
|
||||||
|
place(state);
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
commit(Ic *state, char *s, int nbyte)
|
commit(Ic *state, char *s, int nbyte)
|
||||||
{
|
{
|
||||||
@@ -281,6 +389,7 @@ sendrequest(Ic *state, int op, u32int key, u32int mod, Keyres *res)
|
|||||||
kr.op = op;
|
kr.op = op;
|
||||||
kr.ks = key;
|
kr.ks = key;
|
||||||
kr.mod = mod & Mmask;
|
kr.mod = mod & Mmask;
|
||||||
|
kr.caret = state->caret;
|
||||||
kr.reply = replyc;
|
kr.reply = replyc;
|
||||||
chansend(keyc, &kr);
|
chansend(keyc, &kr);
|
||||||
chanrecv(replyc, res);
|
chanrecv(replyc, res);
|
||||||
@@ -317,7 +426,7 @@ kpress(Ic *state, xcb_im_input_context_t *ic, xcb_key_press_event_t *ev)
|
|||||||
Keyres res;
|
Keyres res;
|
||||||
char buf[Maxutf];
|
char buf[Maxutf];
|
||||||
u32int key, rune;
|
u32int key, rune;
|
||||||
int n;
|
int n, wasvalid;
|
||||||
|
|
||||||
key = kget(ev->detail, ev->state);
|
key = kget(ev->detail, ev->state);
|
||||||
rune = xkb_keysym_to_utf32(key);
|
rune = xkb_keysym_to_utf32(key);
|
||||||
@@ -327,6 +436,15 @@ kpress(Ic *state, xcb_im_input_context_t *ic, xcb_key_press_event_t *ev)
|
|||||||
key = Kspec + (key - 0xff00);
|
key = Kspec + (key - 0xff00);
|
||||||
else
|
else
|
||||||
key = rune;
|
key = rune;
|
||||||
|
if(meaningful(key)){
|
||||||
|
wasvalid = state->caret.valid;
|
||||||
|
if(!state->engaged)
|
||||||
|
refreshplace(state);
|
||||||
|
else if(readattrs(state))
|
||||||
|
place(state);
|
||||||
|
if(state->engaged && wasvalid && !state->caret.valid)
|
||||||
|
sendrequest(state, Keycaret, 0, 0, &res);
|
||||||
|
}
|
||||||
keypress(state, key, ev->state, &res);
|
keypress(state, key, ev->state, &res);
|
||||||
n = stoutf(&res.commit, buf, sizeof buf);
|
n = stoutf(&res.commit, buf, sizeof buf);
|
||||||
commit(state, buf, n);
|
commit(state, buf, n);
|
||||||
@@ -387,6 +505,7 @@ iccreate(xcb_im_client_t *client, xcb_im_input_context_t *ic)
|
|||||||
state->client = client;
|
state->client = client;
|
||||||
state->encoding = getencoding(client);
|
state->encoding = getencoding(client);
|
||||||
setstyle(state, xcb_im_input_context_get_input_style(ic));
|
setstyle(state, xcb_im_input_context_get_input_style(ic));
|
||||||
|
refreshplace(state);
|
||||||
state->next = ics;
|
state->next = ics;
|
||||||
ics = state;
|
ics = state;
|
||||||
xcb_im_input_context_set_data(ic, state, icfree);
|
xcb_im_input_context_set_data(ic, state, icfree);
|
||||||
@@ -432,6 +551,15 @@ callback(xcb_im_t *im, xcb_im_client_t *client, xcb_im_input_context_t *ic,
|
|||||||
if(ev != nil && (ev->response_type & ~0x80) == XCB_KEY_PRESS)
|
if(ev != nil && (ev->response_type & ~0x80) == XCB_KEY_PRESS)
|
||||||
kpress(state, ic, ev);
|
kpress(state, ic, ev);
|
||||||
break;
|
break;
|
||||||
|
case XCB_XIM_SET_IC_VALUES:
|
||||||
|
case XCB_XIM_SET_IC_FOCUS:
|
||||||
|
refreshplace(state);
|
||||||
|
if(state->engaged){
|
||||||
|
Keyres res;
|
||||||
|
|
||||||
|
sendrequest(state, Keycaret, 0, 0, &res);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case XCB_XIM_DESTROY_IC:
|
case XCB_XIM_DESTROY_IC:
|
||||||
case XCB_XIM_RESET_IC:
|
case XCB_XIM_RESET_IC:
|
||||||
case XCB_XIM_UNSET_IC_FOCUS:
|
case XCB_XIM_UNSET_IC_FOCUS:
|
||||||
@@ -461,6 +589,7 @@ ximclose(void)
|
|||||||
free(state);
|
free(state);
|
||||||
}
|
}
|
||||||
ics = nil;
|
ics = nil;
|
||||||
|
rootwin = XCB_NONE;
|
||||||
free(kmap);
|
free(kmap);
|
||||||
kmap = nil;
|
kmap = nil;
|
||||||
if(conn != nil){
|
if(conn != nil){
|
||||||
@@ -502,6 +631,7 @@ ximinit(void)
|
|||||||
ximlog("cannot find X screen");
|
ximlog("cannot find X screen");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
rootwin = screen->root;
|
||||||
if(kinit() < 0){
|
if(kinit() < 0){
|
||||||
ximlog("cannot read keyboard mapping");
|
ximlog("cannot read keyboard mapping");
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
Reference in New Issue
Block a user