diff --git a/README.md b/README.md index d43ae51..2072bab 100644 --- a/README.md +++ b/README.md @@ -63,9 +63,10 @@ query; the Hanja dictionary lists one modern Hangul syllable at a time. Each XIM style is offered with StatusNothing and with StatusNone. XIM text travels as `COMPOUND_TEXT`, which carries any UTF-8. A client that -sends `XNSpotLocation` gets the popup at that spot whatever its preedit -style; otherwise the popup sits under the focus window, or under the client -window when no focus window is set. +sends `XNSpotLocation` gets the popup under that spot whatever its preedit +style, and above the line when there is no room below; otherwise the popup +sits under the focus window, or under the client window when no focus +window is set. The popup is an X11 window sized by `GDK_SCALE` on HiDPI displays, XIM is X11-only, and GTK popup placement converts the GTK caret to X11 root diff --git a/tests/xim_adapter_test.c b/tests/xim_adapter_test.c index 7777b4b..275b101 100644 --- a/tests/xim_adapter_test.c +++ b/tests/xim_adapter_test.c @@ -667,7 +667,7 @@ xim_adapter_placement(struct ct *t) { /* Spot location first, then the bottom of the focus window, then of * the client window; an unset focus window is the client window. */ - static const struct { + const struct { u32int mask; int focuswin; int fgeo; @@ -677,14 +677,15 @@ xim_adapter_placement(struct ct *t) int valid; int x; int y; + int h; } cases[] = { - {XCB_XIM_XNSpotLocation_MASK, 10, 1, 1, 1, 1, 1, 103, 204}, - {XCB_XIM_XNSpotLocation_MASK, 10, 1, 0, 1, 1, 1, 300, 440}, - {XCB_XIM_XNSpotLocation_MASK, 0, 1, 1, 1, 1, 1, 303, 404}, - {0, 10, 1, 1, 1, 1, 1, 100, 230}, - {0, 0, 1, 1, 1, 1, 1, 300, 440}, - {0, 10, 0, 1, 1, 1, 1, 300, 440}, - {0, 10, 0, 1, 0, 1, 0, 0, 0}, + {XCB_XIM_XNSpotLocation_MASK, 10, 1, 1, 1, 1, 1, 103, 204-Fontsz, Fontsz}, + {XCB_XIM_XNSpotLocation_MASK, 10, 1, 0, 1, 1, 1, 300, 440, 0}, + {XCB_XIM_XNSpotLocation_MASK, 0, 1, 1, 1, 1, 1, 303, 404-Fontsz, Fontsz}, + {0, 10, 1, 1, 1, 1, 1, 100, 230, 0}, + {0, 0, 1, 1, 1, 1, 1, 300, 440, 0}, + {0, 10, 0, 1, 1, 1, 1, 300, 440, 0}, + {0, 10, 0, 1, 0, 1, 0, 0, 0, 0}, }; xcb_im_input_context_t *ic; Icbinding *b; @@ -716,7 +717,7 @@ xim_adapter_placement(struct ct *t) 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); + CT_EQ_INT(t, cases[i].h, state.caret.h); } } @@ -756,13 +757,13 @@ xim_adapter_placement_updates(struct ct *t) 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); + CT_EQ_INT(t, 206-Fontsz, req.caret.y); wirewins[0].rootx = 150; wirewins[0].rooty = 250; kpress(&state, &ev); req = nexttrace(t, &f, Keypress, &state); CT_EQ_INT(t, 155, req.caret.x); - CT_EQ_INT(t, 256, req.caret.y); + CT_EQ_INT(t, 256-Fontsz, req.caret.y); b->preattr.spot_location.x = 15; b->preattr.spot_location.y = 16; @@ -772,7 +773,7 @@ xim_adapter_placement_updates(struct ct *t) req = nexttrace(t, &f, Keycaret, &state); CT_CHECK(t, req.caret.valid); CT_EQ_INT(t, 165, req.caret.x); - CT_EQ_INT(t, 266, req.caret.y); + CT_EQ_INT(t, 266-Fontsz, req.caret.y); b->preattrmask = 0; wirewins[0].geometryok = 0; hdr.major_opcode = XCB_XIM_SET_IC_FOCUS; diff --git a/xim.c b/xim.c index 28d602e..88b8db7 100644 --- a/xim.c +++ b/xim.c @@ -196,8 +196,13 @@ place(Ic *state) XCB_XIM_XNSpotLocation_MASK){ attr = xcb_im_input_context_get_preedit_attr(state->xic); if(translate(focuswin, attr->spot_location.x, - attr->spot_location.y, &state->caret)) + attr->spot_location.y, &state->caret)){ + /* A spot is a baseline: call the line one row above it, + * so that a popup flipped above it clears the text. */ + state->caret.y -= Fontsz; + state->caret.h = Fontsz; return; + } } if(placebottom(state, focuswin)) return;