Commit Graph

36 Commits

Author SHA1 Message Date
ef7fb627c6 compose: one Compose table for the XIM and IBus frontends
An IBus client throws away a dead key its engine did not take — the GTK
module's own comment says so, and Qt does the same — so é and ü were
lost in every IBus application, while XIM composed them with a table of
its own.  That table moves to compose.c, which both frontends now use;
xim.c is the shorter for it.

A finished sequence is text, not a key: the engine is asked to hand back
what it had pending, and the composed text follows it, so the composed
character can no longer land before the syllable typed before it.
2026-08-17 12:16:07 +09:00
c102c87d55 ibus: a key stands for the FocusIn a client may never send
A context that had not sent FocusIn had every key rejected outright, so
the input method was silently dead in a client that omits or delays it,
and in the documented case of two applications whose focus events cross.
ibus-daemon and fcitx5 both treat a key as focus; strans, which plays the
daemon here, now does too.  A release still does not focus, and the
engine's own owner rule is unchanged.
2026-08-17 11:58:08 +09:00
bfa919f623 ibus: name the address file as libibus does under Wayland
libibus looks for the file under WAYLAND_DISPLAY when a session has one,
DISPLAY only otherwise; strans always used DISPLAY, so in a Wayland
session it wrote <machine-id>-unix-0 while every IBus client looked for
<machine-id>-unix-wayland-0 and found nothing.  The machine id now comes
from D-Bus's copy first, as libibus reads it, and a host with neither
file gets libibus's own "machine-id" rather than a daemon that dies.
2026-08-17 11:53:40 +09:00
88ad5f7630 engine: the one capability is a flag
Cclientpreedit was a one-bit mask that every producer set as "want ?
Cclientpreedit : 0" and every consumer masked out again; nothing else
was ever going to join it.  Keyreq carries clientpre, an int that says
whether the client draws the preedit, and the engine and the XIM
context keep it under that name.
2026-08-17 10:57:15 +09:00
46bb8b1d46 ibus: the InputContext interface as a table
onmsg matched the member name, then handleplain matched four of the
names again after checking their empty signature, and the handlers that
take arguments each re-checked theirs with a message of their own.  One
table of member, signature, and handler does the matching and the
checking once; the handlers read arguments a signature has already
vouched for.
2026-08-17 10:55:09 +09:00
a03fb05324 ibus: PostProcessKeyEvent for clients that process keys synchronously
GTK 4's IBus module, and GTK 3's with IBUS_ENABLE_SYNC_MODE=1, waits for
its ProcessKeyEvent reply and cannot take signals meanwhile; since IBus
1.5.29 it then reads the PostProcessKeyEvent property for what the key
produced.  strans answered that read with an error, so every key logged
a warning and a commit made by a key that passed on arrived after the
key: 한 and a comma became ,한.  A context that sets
EffectivePostProcessKeyEvent now has its commits and preedits held
during the key and handed over as the (yv) list IBus defines.
2026-08-17 01:53:51 +09:00
7c9e736996 xim: Compose results of any length, StatusNone styles; ibus: no cursor size check
A Compose sequence whose result is more than one character has no
keysym, so xkb_compose_state_get_one_sym gave nothing and the result was
lost; the UTF-8 the compose state holds is committed instead.  Clients
that ask for a StatusNone style — fcitx5 offers them — failed to create
an input context; the three preedit styles come in both status flavours
now.  IBus SetCursorLocation returned an error for a negative width or
height that nothing reads and no client ever waits for.
2026-08-17 01:49:06 +09:00
cd637be4ca ibus: die where startup fails; print the Plan 9 way; drop what said nothing
ibusinit unwound its server and un-registered its atexit handler on a
failure whose only sequel was ibusthread dying anyway; now each failure
dies with its own message, and the test that existed to walk that
unwind goes with it.  Also gone: an empty watch-toggle callback where
libdbus takes nil, Maxconns as a second name for Maxclients, fprintf
and strerror where the rest of the daemon says fprint and %r, USED()
where a parameter can simply be unnamed, a second findcontext() for the
Properties branch, and emitcommit() taking a connection and path apart
from the context that has both.  Ownerpoll lives once, in dat.h.
2026-08-17 01:34:06 +09:00
bab6077c75 srv, ibus: remove the endpoints on a signal too
A stopped daemon left its socket and IBus address file behind, since
plan9port ends a process on SIGTERM without running exit handlers. Both
files now go on a note as well as on exit, and only while they are still
the ones this daemon made, so a successor is never robbed of its own.
2026-08-16 21:40:42 +09:00
11bf379ad3 fix(engine): a reset or a lost focus commits the pending text
Clicking elsewhere, changing focus, or any client reset dropped the
composition in the GTK module and IBus (only XIM ResetIC handed it
back), so typing 안녕 and clicking Send lost 녕. The engine now returns
the pending text — a moved-to candidate first, as Enter would — on
Keyreset and Keyrelease; the GTK module asks for it before closing on
focus-out and commits it, IBus commits it on FocusOut, Reset and a
switch to a password field, and XIM commits it on focus loss and hands
it back on ResetIC without a separate capability probe.
2026-08-16 21:05:31 +09:00
cdd3e38195 fix(ibus): drop a context on the Service.Destroy libibus really sends
libibus destroys an input context with Destroy on
org.freedesktop.IBus.Service, not on the InputContext interface, so the
call went unanswered and the context slot stayed taken until the whole
connection closed. A long-lived GTK process that opens and closes text
widgets exhausted the 1024 slots and then got LimitsExceeded for every
new field. The live contract test now destroys a context that way and
checks the path is gone.
2026-08-16 20:24:26 +09:00
68678283cd ibus: room for a thousand input contexts
Toolkits keep one IBus context per widget that ever took focus, so 64
across every client could run out in a long session, after which new
widgets silently got no input method. The table is static and small
(about 100 bytes a slot).
2026-08-16 18:25:55 +09:00
03c196a7f6 ibus: keep only the content purpose; nothing read the hints 2026-08-16 16:58:12 +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
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
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
a1ef8a4744 fix(frontends): restart preedit around commits 2026-08-15 15:42:35 +09:00
d29d43f443 fix(frontends): preserve preedit lifecycle 2026-08-15 15:05:49 +09:00
f2fb71cd89 fix(ibus): make the X11 frontend fail truthfully 2026-08-14 22:10:40 +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
2376035524 engine: route popup preedit by client capability 2026-08-14 17:02:46 +09:00
f395f29918 ibus: complete setup before publication 2026-08-14 02:48:49 +09:00
6c0a533c4e ibus: fall back from unreadable machine id 2026-08-14 02:10:16 +09:00
91b3042e66 ibus: provision connection watch capacity 2026-08-14 00:44:16 +09:00
9f4f9ceb14 ibus: cover context ownership through the engine 2026-08-13 23:21:12 +09:00
367cbb6cc3 ibus: make context release explicit 2026-08-13 22:03:27 +09:00
b6a9ccd9d9 cleanup: simplify frontend request ownership 2026-08-13 21:57:32 +09:00
4e90fdd5c7 fix: harden caret and IBus dispatch 2026-08-12 17:34:34 +09:00
cec62cc40f fix: repair IBus context lifecycle 2026-08-12 15:49:28 +09:00
bc5712b6ac fix: retain the active owner's caret 2026-08-12 15:44:04 +09:00
5ba5cf209c fix: assign one active engine owner 2026-08-12 15:41:46 +09:00
9dc116a035 harden ipc and frontend recovery 2026-08-11 19:34:47 +09:00
daadd320f3 ibus preedit 2026-05-28 17:28:51 +09:00
3a203766d5 add ibus supprot 2026-05-28 15:17:31 +09:00