Merge pull request #6398 from basecamp/supervise-fcitx5
Supervise fcitx5 so XCompose sequences can't silently die
This commit is contained in:
@@ -2,4 +2,9 @@
|
||||
|
||||
# omarchy:summary=Restart the XCompose input method service (fcitx5) to apply new compose key settings.
|
||||
|
||||
omarchy-restart-app fcitx5 --disable notificationitem
|
||||
# A fcitx5 running outside the unit owns org.fcitx.Fcitx5, so the unit's
|
||||
# instance would exit on arrival and the stale process would keep serving the
|
||||
# old ~/.XCompose -- a restart that reports success and changes nothing.
|
||||
systemctl --user stop omarchy-fcitx5.service
|
||||
pkill -x fcitx5 >/dev/null 2>&1 || true
|
||||
systemctl --user start omarchy-fcitx5.service
|
||||
|
||||
@@ -4,7 +4,6 @@ hl.on("hyprland.start", function()
|
||||
hl.exec_cmd("dbus-update-activation-environment --systemd --all")
|
||||
|
||||
hl.exec_cmd("quickshell -n -p $OMARCHY_PATH/shell")
|
||||
hl.exec_cmd(o.launch("fcitx5 --disable notificationitem"))
|
||||
hl.exec_cmd("omarchy-first-run")
|
||||
hl.exec_cmd("omarchy-powerprofiles-init")
|
||||
hl.exec_cmd(o.launch("omarchy-hyprland-monitor-watch"))
|
||||
|
||||
@@ -0,0 +1,31 @@
|
||||
[Unit]
|
||||
Description=Fcitx5 input method (XCompose sequences)
|
||||
# fcitx5 turns the CapsLock compose sequences in ~/.XCompose into text for
|
||||
# Wayland clients.
|
||||
#
|
||||
# Wait for the compositor: fcitx5 needs WAYLAND_DISPLAY and DISPLAY, which uwsm
|
||||
# imports into the user manager before it reaches graphical-session.target.
|
||||
After=graphical-session.target
|
||||
# The wayland connection dies with the compositor, so follow the session rather
|
||||
# than linger against a socket that is gone.
|
||||
PartOf=graphical-session.target
|
||||
# After= is ordering only -- it does not stop anything from starting this unit
|
||||
# while the target is inactive. An `omarchy update` over SSH has a live user
|
||||
# manager (pam_systemd) and no graphical session, and a fcitx5 started there
|
||||
# comes up with no WAYLAND_DISPLAY and no way to reach any client. Worse, it
|
||||
# stays active, so the later graphical-session.target activation won't pull in a
|
||||
# working one -- Wants= does not restart what is already running. Skip the start
|
||||
# instead; the unit stays enabled and starts for real at graphical login.
|
||||
ConditionEnvironment=WAYLAND_DISPLAY
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
# notificationitem duplicates the tray entry omarchy already renders itself.
|
||||
ExecStart=/usr/bin/fcitx5 --disable notificationitem
|
||||
# always, not on-failure: fcitx5 exits 0 when it detects another instance owning
|
||||
# its bus name, and a clean exit still leaves the user with no input method.
|
||||
Restart=always
|
||||
RestartSec=2
|
||||
|
||||
[Install]
|
||||
WantedBy=graphical-session.target
|
||||
+2
-1
@@ -228,7 +228,8 @@ systemd instance:
|
||||
Voxtype post-update hook.
|
||||
- `install/user/first-run/enable-user-units.sh` — `systemctl --user enable`
|
||||
the shipped user units (`bt-agent`, `omarchy-sleep-lock`,
|
||||
`omarchy-recover-internal-monitor`, `omarchy-migrate-notify.service`).
|
||||
`omarchy-recover-internal-monitor`, `omarchy-migrate-notify.service`,
|
||||
`omarchy-fcitx5.service`).
|
||||
Done here, not at finalize, because
|
||||
the user manager isn't reachable from the ISO chroot; `ConditionPath*`
|
||||
in the unit files keeps services inert when they don't apply.
|
||||
|
||||
@@ -16,4 +16,5 @@ systemctl --user enable --now \
|
||||
bt-agent.service \
|
||||
omarchy-recover-internal-monitor.service \
|
||||
omarchy-sleep-lock.service \
|
||||
omarchy-migrate-notify.service
|
||||
omarchy-migrate-notify.service \
|
||||
omarchy-fcitx5.service
|
||||
|
||||
@@ -0,0 +1,38 @@
|
||||
echo "Supervise fcitx5 so CapsLock compose sequences can't silently die"
|
||||
|
||||
# fcitx5 was launched fire-and-forget from Hyprland's autostart. Nothing
|
||||
# restarted it and nothing noticed when it went away, so a single lost start
|
||||
# left every ~/.XCompose sequence (CapsLock m s -> emoji) dead for the rest of
|
||||
# the session. It's a systemd user service with Restart=always now.
|
||||
|
||||
systemctl --user daemon-reload >/dev/null 2>&1 || true
|
||||
|
||||
# Enable without --now, and start by hand further down only when there is a
|
||||
# session to start into. `systemctl enable` needs a live user manager, which an
|
||||
# `omarchy update` from a TTY does not have, so fall back to writing exactly the
|
||||
# symlink it would have written rather than silently leaving this unenabled.
|
||||
if ! systemctl --user enable omarchy-fcitx5.service >/dev/null 2>&1; then
|
||||
wants_dir="$HOME/.config/systemd/user/graphical-session.target.wants"
|
||||
mkdir -p "$wants_dir"
|
||||
ln -sfn /usr/lib/systemd/user/omarchy-fcitx5.service \
|
||||
"$wants_dir/omarchy-fcitx5.service"
|
||||
fi
|
||||
|
||||
# Outside a graphical session -- an update over SSH -- there is nothing to hand
|
||||
# over: no autostart-launched fcitx5 to kill, and the unit's own
|
||||
# ConditionEnvironment would skip the start anyway. The enablement above is the
|
||||
# whole job; the next graphical login starts it.
|
||||
if systemctl --user is-active --quiet graphical-session.target; then
|
||||
# The service and the autostart-launched process can't coexist: a second
|
||||
# fcitx5 sees the first owning org.fcitx.Fcitx5 and exits 0, which
|
||||
# Restart=always would turn into a restart loop. Drop the stray first.
|
||||
pkill -x fcitx5 >/dev/null 2>&1 || true
|
||||
|
||||
# Report what systemctl actually said. This kills a fcitx5 that was working a
|
||||
# moment ago, so a start failure here has to be loud instead of leaving the
|
||||
# session with no input method and a migration marked complete.
|
||||
if ! error=$(systemctl --user start omarchy-fcitx5.service 2>&1); then
|
||||
echo "Could not start omarchy-fcitx5.service: $error"
|
||||
echo "Compose sequences (CapsLock m s) will not work until the next login."
|
||||
fi
|
||||
fi
|
||||
@@ -139,6 +139,7 @@ package_defaults = [
|
||||
("default/systemd/user/omarchy-recover-internal-monitor.service", "/usr/lib/systemd/user/omarchy-recover-internal-monitor.service", "systemd/user/omarchy-recover-internal-monitor.service"),
|
||||
("default/systemd/user/omarchy-migrate-notify.service", "/usr/lib/systemd/user/omarchy-migrate-notify.service", "systemd/user/omarchy-migrate-notify.service"),
|
||||
("default/systemd/user/omarchy-tailscale-receive.service", "/usr/lib/systemd/user/omarchy-tailscale-receive.service", "systemd/user/omarchy-tailscale-receive.service"),
|
||||
("default/systemd/user/omarchy-fcitx5.service", "/usr/lib/systemd/user/omarchy-fcitx5.service", "systemd/user/omarchy-fcitx5.service"),
|
||||
("default/systemd/zram-generator.conf.d/90-omarchy.conf", "/usr/lib/systemd/zram-generator.conf.d/90-omarchy.conf", "systemd/zram-generator.conf.d/90-omarchy.conf"),
|
||||
("default/fonts/omarchy/omarchy.ttf", "/usr/share/fonts/omarchy/omarchy.ttf", "omarchy.ttf"),
|
||||
("default/snapper/root", "/etc/snapper/config-templates/omarchy", "snapper/root"),
|
||||
|
||||
@@ -46,3 +46,33 @@ grep -F 'omarchy-migrate-notify.service' "$first_run_units" >/dev/null ||
|
||||
grep -F 'omarchy-update-user-notify' "$first_run_units" >/dev/null &&
|
||||
fail "first-run still enables the retired notifier units"
|
||||
pass "first-run enables the login-only migration notifier"
|
||||
|
||||
fcitx_service="$ROOT/default/systemd/user/omarchy-fcitx5.service"
|
||||
grep -Fx 'ExecStart=/usr/bin/fcitx5 --disable notificationitem' "$fcitx_service" >/dev/null
|
||||
grep -Fx 'Restart=always' "$fcitx_service" >/dev/null ||
|
||||
fail "fcitx5 exits 0 on a duplicate bus name, so on-failure would leave the user with no input method"
|
||||
grep -Fx 'After=graphical-session.target' "$fcitx_service" >/dev/null ||
|
||||
fail "fcitx5 needs WAYLAND_DISPLAY, which uwsm imports before it reaches graphical-session.target"
|
||||
grep -Fx 'PartOf=graphical-session.target' "$fcitx_service" >/dev/null ||
|
||||
fail "fcitx5 must stop with the compositor instead of lingering against a dead wayland socket"
|
||||
grep -Fx 'WantedBy=graphical-session.target' "$fcitx_service" >/dev/null ||
|
||||
fail "fcitx5 is never pulled in at login without a WantedBy"
|
||||
grep -Fx 'ConditionEnvironment=WAYLAND_DISPLAY' "$fcitx_service" >/dev/null ||
|
||||
fail "an update over SSH has a live user manager and no display; starting fcitx5 there wedges the unit active-but-blind, and Wants= will not replace it at graphical login"
|
||||
|
||||
fcitx_migration="$ROOT/migrations/1785167800.sh"
|
||||
grep -F 'is-active --quiet graphical-session.target' "$fcitx_migration" >/dev/null ||
|
||||
fail "migration kills fcitx5 and starts the unit outside a graphical session"
|
||||
grep -F 'systemctl --user enable omarchy-fcitx5.service' "$fcitx_migration" >/dev/null ||
|
||||
fail "migration must enable without --now; --now starts the unit before the session-gate check"
|
||||
grep -F 'Could not start omarchy-fcitx5.service' "$fcitx_migration" >/dev/null ||
|
||||
fail "migration pkills a working fcitx5, so a failed handover must be reported instead of marked complete"
|
||||
|
||||
grep -F 'pkill -x fcitx5' "$ROOT/bin/omarchy-restart-xcompose" >/dev/null ||
|
||||
fail "restart-xcompose cannot reload a fcitx5 running outside the unit, so it silently keeps serving the old table"
|
||||
|
||||
grep -F 'omarchy-fcitx5.service' "$first_run_units" >/dev/null ||
|
||||
fail "first-run does not enable the input method, so ~/.XCompose sequences never resolve"
|
||||
grep -F 'fcitx5' "$ROOT/default/hypr/autostart.lua" >/dev/null &&
|
||||
fail "fcitx5 is autostarted from Hyprland; an unsupervised launch dies silently and takes every compose sequence with it"
|
||||
pass "fcitx5 runs supervised, so a lost input method comes back instead of killing XCompose until logout"
|
||||
|
||||
Reference in New Issue
Block a user