The plugin runs inside the input method and sees everything that is typed, so
what it is built from matters. build.sh used to download a tag archive and a
yoga archive without checking them. It now fetches both by commit hash and
verifies the hash afterwards: a tag can be moved and an archive swapped, a
commit hash cannot be faked. A version without a pinned commit is refused
unless FCITX_COMMIT is given. Archive checksums were not used on purpose, GitHub
does not keep the bytes of generated archives stable.
enable-autostart.sh writes paths into an Exec line and a service file and now
refuses paths that would need quoting there.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The block list is now a BlockStore. The file is replaced atomically (temporary
file, fsync, rename), created readable by the owner only, picked up again when it
changes on disk, and a word whose save failed stays hidden in memory and is
written on the next attempt instead of being lost on restart. Words with line
breaks or NUL, over 256 bytes, and lists over 20000 entries are refused.
Removing candidates from the engine's list resets its cursor to the first
candidate when the removal is in front of it, so the highlight jumped while
arrowing through candidates. The filter now puts the cursor back on the
candidate it was on.
Both parts are in headers that the window and the tests include, so the tests
exercise the code that runs: tests/blockstore_test.cpp covers restarts, failed
writes, outside edits and bad input, tests/blockfilter_test.cpp runs the filter
on a real Fcitx5 candidate list.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The menu remembered the index of the candidate it was opened on. Cloud Pinyin
results arrive asynchronously, so the list can be refreshed between the right
click and the click on an action, and the index would then point at a different
word. That word would have been forgotten and added to the block list.
The word itself is stored when the menu opens and compared when an action is
clicked, nothing is done if it is no longer the same.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
The animation frame timer was re-armed with setTime(), setOneShot() and then
setEnabled(true). In the systemd event loop backend setEnabled(true) means
SD_EVENT_ON, a repeating source, and setOneShot() had just set SD_EVENT_ONESHOT.
The re-armed timer was therefore repeating at a time that had already passed,
and the event loop fired it again on every iteration: the main thread of Fcitx5
sat at 100% CPU and typing froze. The first animation was not affected, the
timer is only re-armed from the second one on, which is why it showed up as a
sudden freeze after typing for a while.
setOneShot() alone is correct. tests/timer_rearm.cpp arms a timer twice the way
the window does: with the old calls it fires 198725 times in 200 ms, with the
fix exactly twice.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
- Record words picked with "Forget candidate" in a block list and drop them
from the candidate list before each refresh, so words from read only
dictionaries stay gone.
- Add scripts/enable-autostart.sh for starting with m3ui at login.
- Make the Chinese README the default, keep the English one as README.en.md.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Fork of the classicui addon (Fcitx5 5.1.23) with a Material 3 look, spring
based animations and a right click action menu for candidates.
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>