Commit Graph

186 Commits

Author SHA1 Message Date
849bf1278b popup: one text drawing call; drop what the draw thread never reaches
font.c exported three wrappers for one function, and the fit == -1 mode
existed only for the tests; textdraw() takes fit and colour. win.c
tested the empty picture in the thread and again in winshow, interned
two atoms by hand next to getatom(), kept a consumer-side drain that the
producer's already guarantees never finds anything, zeroed ten globals
before returning from the only thread that read them, and re-checked
sizes that resizebacking had just established. The page marker is laid
out once and drawn from the layout instead of being recomputed.
2026-08-16 16:22:37 +09:00
eaf31da0d1 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.
2026-08-16 16:20:10 +09:00
c2baa47026 fix(xim): follow keyboard layout changes
kinit() sets up the XKB extension, after which the server stops sending
core MappingNotify to this client, so the refresh branch never fired and
strans kept its startup keymap; setxkbmap after launch left every XIM
key resolved against the old layout. Select XKB NewKeyboardNotify and
MapNotify (with the map parts, or MapNotify is never delivered) and
rebuild the keymap on those events instead.
2026-08-16 16:16:44 +09:00
a70cfc42e3 xim: drop what no client uses; poll for owner loss like IBus
XIM text always went out through imdkit's COMPOUND_TEXT converter,
which already wraps every UTF-8 string in ESC%G; the UTF8_STRING
negotiation, the per-client encoding list, ximtext.c's fallback and its
wrapper never changed a byte on the wire. The spot location is honoured
for every style now (GTK's XIM module sends it with PreeditCallbacks)
and an unset focus window means the client window, as the spec says,
so those clients get the popup at the caret. readattrs/place kept four
transient fields to pass values between them; ximclose tore down state
right before die(); the OOM passthrough context was a third policy for
one small calloc where emalloc dies like everything else. Both frontends
now poll for engine-owner loss only while a preedit shows instead of
XIM waking on a pipe the engine had to know about; ibus stops waking
five times a second when idle. keymeaningful() is the engine's own
predicate. The standalone xim_test moved into the unit suite, so
xim/Makefile is gone.
2026-08-16 16:16:31 +09:00
9080bb833c engine: trim the key dispatch
mapget and maplookup were one trie probe with two predicates; mapmatch
returns the match kind and mapget is its exact case. movedelta is a
switch. searchkey's modifier test was unreachable behind transition's,
searchlang's Alt/Super test behind both callers' earlier returns, and
picksearch's range check behind numberedkouho. Korean key folding runs
once at the top of transition. commit() on an empty preedit is a no-op,
so the Ctrl branch and startsearch lose their haspre guards and repeated
commit/reset pairs. Ctrl+language inside a search now commits the shown
query as it does elsewhere instead of dropping it. Language ids are
documented as the Ctrl codes they are; Im parameters no longer shadow
the file's Im.
2026-08-16 16:09:05 +09:00
68869e2589 engine: redraw when the picture changes, not when the state might have
Every key copied the whole Im and Search rune by rune, compared them
after the transition, and combined the answer with 'eaten', a commit
count that is always zero, and a force flag for caret and owner changes,
while redraw() kept a separate 'visible' bit to know when to send an
empty popup. redraw() now compares the snapshot with the last one sent
and treats two empty popups as equal, so imhandlekey just ends in
redraw(). keystroke() was only a test entry point and moves there.
2026-08-16 16:06:42 +09:00
a557fb114a engine: one trans contract for every language
Japanese was never dispatched through the Lang table: dotrans and
transstr both special-cased it into transjp, which edited Im in place
and wrote commits through a side argument, while transko popped and
cleared a pre that every caller overwrote anyway, and Vietnamese kept
its key history in dotrans. Emit now carries the new raw state next to
the new pre; transjp, transko and transvi are pure functions of (Im,
key), and dotrans and transstr have a single path. Vietnamese history
bookkeeping lives in vi.c, where the full-history flush no longer
resets the caret as a side effect; istone was toneidx() >= 0.
2026-08-16 16:04:57 +09:00
abaea77248 engine: look dictionaries up synchronously
The dictionary thread ran in imthread's own proc, so a lookup could
only start once the engine blocked, and it was a trie probe anyway; the
emoji and Hanja searches already called dictlookup directly. The
request/result channels, sequence numbers, staleness checks and the
second draw per Japanese key are gone; dictqjp fills the candidates
in place. Emit.dict and Lang.dictq only ever triggered lookups for
Vietnamese, which has no dictionary. dictlookup(Lang*, key, out, max)
returns the count. The Hanja lookup no longer pre-checks for a single
syllable; a reading either has an entry or it does not.
2026-08-16 16:02:09 +09:00
ebcec3af6b fix(engine): send clients the composed Telex text, not the keys
For Vietnamese the preedit is the map key ('as', 'oong'); only the popup
and the commit path looked it up. Clients with inline preedit therefore
showed 'as' while Enter committed 'á'. impre() now maps once for every
reader, and snapshot() no longer maps a second time.
2026-08-16 15:57:55 +09:00
c7718ece52 data: one trie for maps and dictionaries, one loader
The hash map served a single exact-match lookup that the trie already
answers, at the price of a second container, a second file loader with
its own drift, and a Str-to-UTF-8 conversion on every chain probe. The
files are small (kanji.dict is 7.5k lines), so the trie holds both.
trieopen validates keys and each space-separated value word against Str
and reports path:line; trielookup takes the Str every caller holds and
treats a nil trie as an unloaded map; trienew/trieput exist for tests.
The overflow guards on growth, Trie.root (always 0) and the per-language
init loop written twice are gone.
2026-08-16 15:56:32 +09:00
eb0f88f764 ipc: strip machinery no peer uses; keep client state in one Keyreq
ipc.c: an AF_UNIX nonblocking connect completes at once or fails with
EAGAIN, so the EINPROGRESS/poll/SO_ERROR path and the fcntl juggling
were dead; the deadline plumbing checked a clock that cannot fail and
re-tested the deadline before every transfer although only waitfd
blocks; readfield's truncation and discard loop served the unit test,
since every caller owns char[Ipcfieldmax+1]; NULL-argument checks on
in-tree encoders are gone (peer validation stays). The primary key frame
is Ipckey, not 'legacy'; ipckeysym names the keysym mapping.

srv.c: the per-connection capability and caret already lived in the
persistent Keyreq; the mirror locals and 'negotiated' flag guarded a
protocol rule no client relied on. proccreate never fails in libthread.

gtk: focus-out no longer round-trips a reset before closing the socket
that releases the engine; the caret dedup compares the packed frame;
srvconnect's preedit no-ops and the insimple flag are gone.
2026-08-16 15:53:08 +09:00
43b469f70b ipc: share one keysym and modifier mapping across frontends
The keysym-to-engine-key rule lived in ibus.c, xim/xim.c and gtk/main.c,
and the copies disagreed: GTK sent keypad digits as special keys while
IBus and XIM sent '1'..'9'. Modifiers were rebuilt bit by bit in two
places although Mmask already is the X core layout; only the virtual
Super bit (26) that GDK and IBus set needs folding. ipckey/ipcmod in
ipc.c serve the daemon, the module and the tests.
2026-08-16 15:47:47 +09:00
66ea2892f8 bench, docs: let the client detect readiness; say what Enter commits
bench.sh copied ipcpath() and the IBus address-file discovery into shell,
although the benchmark client only speaks IPC; retrying the client itself
is the readiness test. It also forwarded arguments to a daemon that takes
exactly one. README claimed Enter confirms the selection, but Enter and Tab
commit the reading unless a candidate was moved to.
2026-08-16 15:46:28 +09:00
d3c9813f6e build: scope IBus flags, rebuild containers with clean, dedup gtk install
Only ibus.o needs the D-Bus and xkbcommon flags, so give them the same
per-object scoping as the popup and XIM objects. The docker targets used
-B, which recursive makes inherit: the daemon was linked three times and
the live tests built twice per docker-check. gtk/Makefile repeated the
module-directory check and cache refresh in install and uninstall.
2026-08-16 15:46:00 +09:00
61840fc108 build: ignore the stress test binary 2026-08-16 15:45:18 +09:00
c1971c8096 fix(popup): accept depth-24 roots regardless of colormap precision
bits_per_rgb_value is the colormap component precision, not the pixel
layout; the NVIDIA driver reports 11 for its ordinary x8r8g8b8 visuals,
which left the popup disabled there. Depth, class, masks, byte order and
the pixmap format already pin the layout that putimage writes.
2026-08-16 15:45:09 +09:00
7047c57d29 fix(gtk): unset cache override during install 2026-08-15 16:10:34 +09:00
a1ef8a4744 fix(frontends): restart preedit around commits 2026-08-15 15:42:35 +09:00
67ed2ef478 fix(engine): redraw only for visible caret changes 2026-08-15 15:07:13 +09:00
f489c56fb1 fix(ipc): retry nonblocking I/O until deadline 2026-08-15 15:07:07 +09:00
d29d43f443 fix(frontends): preserve preedit lifecycle 2026-08-15 15:05:49 +09:00
aeb6010f3c fix(runtime): restart daemon in background 2026-08-15 00:09:15 +09:00
f0abace40b fix(gtk): install prebuilt modules without development files 2026-08-14 23:54:41 +09:00
7468d573ec test: make container Valgrind runnable 2026-08-14 23:25:07 +09:00
133cc97e55 fix(runtime): make startup and GTK installation explicit 2026-08-14 23:17:18 +09:00
516ec98a70 test: separate quick, live, and stress checks 2026-08-14 23:13:32 +09:00
bfe83d0119 fix(data): reject partial and malformed map data 2026-08-14 23:09:55 +09:00
38475318db fix(popup): fit the current X11 monitor 2026-08-14 22:54:15 +09:00
59482d00f3 fix(engine): compare logical transition state
Avoid reading inactive Str storage when deciding whether to publish a redraw. Keep the focused engine suite compact by retaining one case for each page, navigation, and empty-result invariant.
2026-08-14 22:46:42 +09:00
8df43cecd8 fix(ipc): reject unconnected backlog clients 2026-08-14 22:46:29 +09:00
a637f457f7 fix(xim): honor reset and X11 keyboard state 2026-08-14 22:34:37 +09:00
9804c1f55c fix(gtk): restore compose fallback and clean lifecycle 2026-08-14 22:29:14 +09:00
534ddcd9bb fix(ipc): preserve legacy preedit and bound client waits 2026-08-14 22:17:59 +09:00
5dc2530951 fix(engine): make composition transitions deterministic 2026-08-14 22:13:16 +09:00
f2fb71cd89 fix(ibus): make the X11 frontend fail truthfully 2026-08-14 22:10:40 +09:00
77c6dd66ca test: make clean checks trustworthy 2026-08-14 22:06:54 +09:00
0471d58dec popup: stabilize the input panel width 2026-08-14 21:13:49 +09:00
f222b4d573 popup: refine the input panel 2026-08-14 20:54:09 +09:00
3576c4ea68 tests: cover frontend input-panel protocols 2026-08-14 20:09:49 +09:00
e4fc327ffd popup: show the candidate page 2026-08-14 20:06:53 +09:00
193ed009bd popup: place and bound the input panel 2026-08-14 20:00:36 +09:00
7619d2bd9d ibus: support modern client preedit 2026-08-14 19:59:52 +09:00
a841894015 ibus: honor preedit and private-input policy 2026-08-14 19:41:07 +09:00
4cac6f1a15 engine: use stable candidate pages 2026-08-14 19:27:22 +09:00
2e6d7d8e48 xim: clear callback preedit on owner loss 2026-08-14 19:17:37 +09:00
76f9e1a21f gtk: honor preedit policy and cursor placement 2026-08-14 19:12:53 +09:00
6a58b63223 ipc: negotiate preedit capability and caret messages 2026-08-14 18:53:14 +09:00
b536573622 engine: update active preedit capability 2026-08-14 18:44:52 +09:00
9a3a92170e engine: reject stale dictionary results 2026-08-14 18:43:12 +09:00
76af1a022f xim: refresh placement before each key 2026-08-14 17:43:56 +09:00