xim: place popup from input context
This commit is contained in:
@@ -1,20 +1,63 @@
|
||||
#include <xcb/xcb.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,
|
||||
const char*, uint32_t, uint32_t);
|
||||
static void wirestart(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*);
|
||||
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*);
|
||||
|
||||
#define xcb_im_commit_string wirecommit
|
||||
#define xcb_im_preedit_start_callback wirestart
|
||||
#define xcb_im_preedit_draw_callback wiredraw
|
||||
#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
|
||||
#include "xim/xim.c"
|
||||
#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_done_callback
|
||||
#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
|
||||
#include "cutest/cutest.h"
|
||||
|
||||
@@ -51,17 +102,23 @@ struct Wirecall
|
||||
u32int feedback[Maxrunes];
|
||||
};
|
||||
|
||||
typedef struct Icbinding Icbinding;
|
||||
struct Icbinding
|
||||
typedef struct Wirewin Wirewin;
|
||||
struct Wirewin
|
||||
{
|
||||
xcb_im_input_context_t *ic;
|
||||
void *data;
|
||||
xcb_window_t win;
|
||||
int geometryok;
|
||||
int translateok;
|
||||
int samescreen;
|
||||
int rootx;
|
||||
int rooty;
|
||||
int height;
|
||||
};
|
||||
|
||||
static Wirecall wirecalls[Maxwire];
|
||||
static Icbinding icbindings[8];
|
||||
static Wirewin wirewins[8];
|
||||
static int nwirecalls;
|
||||
static int nflush;
|
||||
static int transx, transy;
|
||||
|
||||
static Wirecall*
|
||||
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);
|
||||
}
|
||||
|
||||
static void*
|
||||
wiregetdata(xcb_im_input_context_t *ic)
|
||||
static Wirewin*
|
||||
wirewindow(xcb_window_t win)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < nelem(icbindings); i++)
|
||||
if(icbindings[i].ic == ic)
|
||||
return icbindings[i].data;
|
||||
for(i = 0; i < nelem(wirewins); i++)
|
||||
if(wirewins[i].win == win)
|
||||
return &wirewins[i];
|
||||
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
|
||||
wireflush(xcb_connection_t *c)
|
||||
{
|
||||
@@ -157,8 +277,10 @@ wireclear(void)
|
||||
{
|
||||
memset(wirecalls, 0, sizeof wirecalls);
|
||||
memset(icbindings, 0, sizeof icbindings);
|
||||
memset(wirewins, 0, sizeof wirewins);
|
||||
nwirecalls = 0;
|
||||
nflush = 0;
|
||||
transx = transy = 0;
|
||||
preowner = nil;
|
||||
}
|
||||
|
||||
@@ -169,6 +291,23 @@ wirebind(int n, xcb_im_input_context_t *ic, Ic *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 testenginehandle(Keyreq*);
|
||||
void* testengineowner(void);
|
||||
@@ -506,6 +645,131 @@ xim_adapter_styles(struct ct *t)
|
||||
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
|
||||
xim_adapter_encoding_negotiation(struct ct *t)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user