* Unify input methods with the installer keyboard selection
* Preserve inherited input keys and later keyboard changes
* Exercise input engines across desktop toolkits
* Show input modes in the keyboard indicator
* Keep Pinyin setup prompts visible
* Remember input selections before an app gains focus
* Remove the Japanese input welcome notification
* Show explicit choices on notification cards
* Suppress the Cloudpinyin first-use prompt
* Show the input switching shortcut in keyboard hints
* Verify input setup and composition stay quiet
* Use Super+I for input switching independently of Fcitx keys
* Restore linked input settings and attribute test notifications to Fcitx
* Correct the input setup shortcut hint
* Keep input tooltips to the name and switching shortcut
* Place the input language selector with the right bar widgets
* Show input switching only for multiple layouts or methods
* Unify input method and keyboard layout switching
* Select keyboard layouts and input methods in the Typing menu
* Apply typing selections immediately from the menu
* Use installer keyboard choices and keep typing selections accurate
* Queue typing changes and wait for saved selections
* Keep queued typing selections when reopening the menu
* Cycle keyboard layouts alongside composition engines
* Avoid shadowing Python typing and retain pending mixed input selections
* Keep input clicks working through controller and compositor failures
* Move the keyboard layout widget to the right side of existing bars
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Map keyboard choices to the layouts the installer sets
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep the switching order when changing input methods
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Set input method fonts only after the selection saves
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Restore confirmed picker checks when an immediate change fails
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Route Super+I through the shell's input reader so unfocused choices stick
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Restore the input group when the font preference cannot be written
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Drop the azerty conversion now that the installer no longer offers it
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Apply the owner's keyboard layout once before persisting the input choice
A quattro merge kept a second apply_keyboard after the retry loop, which
re-ran loadkeys and firstboot, ignored their failure, and overwrote the
XKB layout setup supplies for keymaps kbd-model-map lacks.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Give the Lao keyboard choice a Lao desktop layout
The row used la-latin1, kbd's Latin American Spanish keymap, so Lao
installs typed Spanish. There is no Lao console keymap; like Korean, the
console stays US and the desktop gets la, which Omarchy keeps behind US
as a non-Latin layout.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Load engines installed after Fcitx started when they are selected
The Typing menu refused an engine whose package an update had installed,
since Fcitx discovers engines only at startup. Restart input once and wait
for the engine; name the package when it really is not installed.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Cycle input methods back with Super+Shift+I
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Drop notification action buttons now that the Pinyin prompt is suppressed
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Cycle input only through the shell's reader
Without the shell there is no bar or menu either, so the one-shot cycling
path only duplicated the reader's logic.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Add engines from the command line through the Typing menu's path
omarchy setup input <engine> had its own restart, append, select and
live-rollback code in configure.py, parallel to the menu's. It now
installs the packages and appends through typing_setup, leaving
configure.py with install-time seeding and update defaults.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Keep Ctrl+Space out of Fcitx's toggles instead of probing for it
The terminal prefix bind read the Fcitx config and profile on every press
to avoid fighting a Ctrl+Space toggle. configure --defaults now removes
that key from every trigger list, so the bind only checks for a terminal.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
* Run the input-method scripts with the system Python
A bare python resolves through PATH, so a mise, pyenv or venv interpreter
could run them without the system's PyGObject.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Keep the migrations themselves for late-updaters. Drop the tests that only
exercised frozen file rewrites from 4.0.0, and keep live invariants,
privileged repairs, and the migrator.
Nothing stood between "memory is tight" and "processes die at random":
the kernel OOM killer only fires after an allocation has already failed,
so a machine under pressure thrashes in reclaim until something breaks
somewhere fatal — seen in practice as Hyprland taking SIGBUS mid-memcpy
from a client shm pool that memory pressure was tearing down.
Enable systemd-oomd, which keys on PSI stall time rather than free
pages, and mark app.slice — and only app.slice — as its kill candidate.
Hyprland runs in session.slice, so the compositor is structurally
ineligible as a victim: oomd takes the app that caused the pressure and
the session survives. Thresholds (50% stall over 20s, Fedora's desktop
defaults) live in an oomd.conf.d drop-in; candidacy ships as a vendor
drop-in under /usr/lib/systemd/user so existing users get it on package
upgrade with no per-user seeding.
New installs enable the daemon from enable-services.sh; a migration
covers existing ones, restarting an already-running oomd so it doesn't
keep stale thresholds until reboot.
Deliberately not earlyoom: it triggers only when free RAM and free swap
are both under threshold, so Omarchy's large, mostly-idle swapfiles
keep it asleep through exactly this failure.
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
fcitx5 is what turns the CapsLock compose sequences in ~/.XCompose into
text for Wayland clients -- CapsLock m s for an emoji, CapsLock space n
for your name. It was launched fire-and-forget from Hyprland's autostart
via uwsm-app, so nothing supervised it, nothing restarted it, and it
logged nowhere. When it went away, every compose sequence stopped
working for the rest of the session with no visible symptom beyond
"emoji input is busted", and no record of why.
That is not hypothetical: it was found dead on a running machine with no
coredump, no OOM kill, and nothing in the journal to explain it.
Move it to a systemd user service:
- Restart=always, not on-failure. fcitx5 exits 0 when it finds another
instance already owning org.fcitx.Fcitx5, and a clean exit still
leaves the user with no input method.
- After=/PartOf=graphical-session.target. It needs WAYLAND_DISPLAY and
DISPLAY, which uwsm imports into the user manager before reaching the
target, and its wayland connection dies with the compositor.
- ConditionEnvironment=WAYLAND_DISPLAY. After= is ordering only and does
not stop the unit from being started while the target is inactive. An
update over SSH has a live user manager (pam_systemd) and no graphical
session, and a fcitx5 started there comes up blind -- then stays
active, so the later target activation won't pull in a working one,
because Wants= does not restart what is already running. Skipping the
start leaves the unit enabled and healthy for the next graphical login.
The migration hands over inside a live session only: it enables without
--now, and only when graphical-session.target is active does it drop the
autostart-launched process and start the unit. Because that kills a
fcitx5 that was working a moment ago, a failed start is reported instead
of leaving the session mute with the migration marked complete.
omarchy-restart-xcompose now drives the unit. It still clears any fcitx5
running outside it first: that process owns the bus name, so the unit's
instance would exit on arrival and the stale one would keep serving the
old table -- a restart that reports success and changes nothing.
Side benefit: fcitx5 now logs to the journal under its own unit, so the
next disappearance leaves a record.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
omarchy-migrate-notify.service is a Type=oneshot wanted by
graphical-session.target, and systemd complements a target's Wants= with an
implicit After=, so the target waited for the notifier to exit. The notifier
does not exit quickly: it sends the notification through systemd-run --scope,
which is synchronous, and omarchy-notification-send -a blocks until the user
clicks. The target stayed in activating for as long as the toast was up.
wayland-wm-app-daemon.service is After=graphical-session.target and nothing
wants it, so uwsm-app starts it on demand. Clicking the notification runs
omarchy-launch-floating-terminal-with-presentation, which execs uwsm-app,
which blocks on a systemctl --user restart of that daemon -- a job queued
behind the very target the clicked notifier was holding open. The terminal
never opened; uwsm-app gave up on its own pipe timeout instead.
Declaring After= on the wanted unit suppresses the implicit dependency rather
than forming a cycle, so the target is reached without waiting and the
notifier runs behind it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
omarchy-update-user-notify.path watched /usr/share/omarchy/migrations, but
pacman writes that directory during every update, including the blessed
omarchy update, which runs omarchy-migrate a step later. The watcher fired a
critical notification for the migrations the update was already applying in
the visible terminal. A watcher cannot tell that apart from a bypassed
pacman -Syu, so the only trigger that never collides with a running update is
a once-per-login check.
The service that already ran at graphical-session.target is now the whole
mechanism, renamed after the command it runs. That is also all the second-user
case needs: markers are per-user, so anyone who did not run the update finds
them missing at their next login.
Login timing means the toast can be sent before the shell has claimed
org.freedesktop.Notifications, so the notifier waits for a live server first.
The wait is omarchy-first-run's, lifted into omarchy-notification-wait rather
than duplicated.
The package keeps omarchy-update-user-notify.service as a symlink onto the new
unit. Existing users hold an absolute wants symlink to the old path, and the
migration that repoints it only runs for users who run an update, which is the
opposite of who the notifier is for.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
omarchy-update-user-notify.path used PathExistsGlob= on the packaged
migrations directory. That directive is level-triggered: systemd re-checks
it every time the triggered unit deactivates and fires again while the glob
still matches. Since applied migrations stay on disk forever (state lives in
~/.local/state/omarchy/migrations), the glob always matches, so the oneshot
notifier re-triggered itself in a tight loop (~26-66 starts/sec) — burning
about a core and flooding the journal for the whole session.
The loop existed since the unit was introduced, but the default start-rate
limit killed it after 5 iterations, taking the .path unit down with
'unit-start-limit-hit'. That symptom was reported as #6174 and fixed
yesterday by setting StartLimitIntervalSec=0 — which removed the only brake
and turned the capped hiccup into an unbounded busy-loop.
Fix the actual cause instead:
* Drop PathExistsGlob= from the .path unit, keeping the edge-triggered
PathModified= watch for updates that land mid-session.
* Revert the StartLimitIntervalSec=0 override; with the level trigger gone
there is no self-re-fire to trip the limit, and the default limit is a
useful backstop again.
* Preserve the once-per-login pending check the glob used to provide by
giving the service its own WantedBy=graphical-session.target, enabled at
first-run alongside the other user units.
* Add a migration that daemon-reloads, revives a rate-limit-killed .path,
restarts the watcher, and enables the login-time notifier on existing
installs.
Verified with transient path/service units: the old config runs the service
200 times in 3 seconds; the new config runs it zero times while idle and
exactly once when a new migration file lands.
Thanks to @HANCORE-Linux for finding and diagnosing the problem.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Reorganizes Omarchy 4 around three layers for populating $HOME:
Seed: omarchy-settings ships defaults to /etc/skel; useradd -m
copies them on user creation
Finalize: omarchy-finalize-user (renamed from omarchy-setup-user)
handles only the runtime tweaks /etc/skel can't do — skill
symlinks, xdg-user-dirs, default browser/mailto, vconsole→hypr
keyboard sync, and install/user/all.sh
Resync: omarchy-reinstall-configs is the explicit, destructive
resync of /etc/skel into an existing user's $HOME
Package-owned files move out of config/ into default/, where the
omarchy-settings PKGBUILD installs them to real system paths:
config/environment.d/fcitx.conf -> /usr/lib/environment.d/
config/fontconfig/fonts.conf -> /usr/share/fontconfig/conf.avail/
config/mimeapps.list -> /usr/share/applications/
config/omarchy.ttf -> /usr/share/fonts/omarchy/
config/systemd/user/*.service -> /usr/lib/systemd/user/
config/uwsm/default -> /usr/share/omarchy/default/uwsm/
config/uwsm/env -> /usr/share/uwsm/env.d/10-omarchy
config/xdg-terminals.list -> /usr/share/xdg-terminal-exec/
omarchy-upgrade-to-4 grows a 'retire' action (renamed from 'move' to
clarify nothing is copied — the system path is owned by the new package
once the user's hash-matched ~/.config copy is removed). Mismatched
copies are kept as backups so user overrides survive the upgrade.
Other simplifications:
- Single env bootstrap at default/bash/env-bootstrap sourced by
/etc/profile.d/omarchy.sh, /etc/skel/.bashrc,
/usr/share/uwsm/env.d/10-omarchy, and default/bash/envs. PATH
prepend only in dev-link mode (production uses /usr/bin/omarchy-*).
- omarchy-refresh-config reads from /etc/skel/.config so refresh
means 'snap to skel'.
- omarchy-reinstall-configs collapses to 'cp -af /etc/skel/. ~/'
plus limine/plymouth/nvim refresh.
- omarchy-font-set uses awk against our own 30-omarchy.conf instead
of xmlstarlet; xmlstarlet dropped from omarchy-base.packages.
- Defer user systemd enables (bt-agent, sleep-lock,
recover-internal-monitor) to first-run via
install/user/first-run/enable-user-units.sh; delete
omarchy-user-systemctl-enable and the per-hardware install
scripts that called it.
- Wireplumber bluetooth-a2dp-autoconnect.conf moves to config/ so
/etc/skel ships it; install/user/hardware/bluetooth.sh deleted.
- Default terminal switched to foot.desktop.
- docs/file-layout.md documents the three-layer model and the
build-time repo→path map.