Merge remote-tracking branch 'origin/quattro' into fix-snapshot-locate-and-timeline-leak
# Conflicts: # docs/file-layout.md
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
# Speaker tunings
|
||||
|
||||
Laptop speakers ship voiced by the vendor's Windows DSP layer, which Linux does
|
||||
not get. A tuning restores that as a PipeWire filter-chain in front of the
|
||||
internal speaker sink: a declarative graph hosted by a small PipeWire client, with
|
||||
no GUI app and no binary blob.
|
||||
|
||||
```
|
||||
default/audio/tunings/<vendor>-<model>/
|
||||
├── tuning.conf # description, match, provenance, measurements
|
||||
└── filter-chain.conf # the graph, with @SPEAKER_SINK@ substituted on install
|
||||
```
|
||||
|
||||
`on` renders the graph into `~/.config/pipewire/omarchy-speaker-tuning.conf.d/`
|
||||
and runs it as its own PipeWire client via `omarchy-speaker-tuning.service`, rather than
|
||||
loading it into the audio daemon. The daemon only reads its own config at startup,
|
||||
so a daemon-loaded tuning could only be switched by restarting PipeWire — which
|
||||
drops every PulseAudio client's connection, and applications that do not reconnect
|
||||
(Spotify) then have to be restarted by hand. Hosting it separately makes switching
|
||||
a start/stop of one small process, and contains failure: a malformed tuning breaks
|
||||
only that service instead of stopping PipeWire from starting at all.
|
||||
|
||||
Tunings apply automatically: `install/hardware/speaker-tuning.sh` installs the
|
||||
LV2 dependency and `install/user/first-run/audio-tuning.sh` applies the tuning,
|
||||
both gated on the match. Machines without a matching tuning are untouched.
|
||||
|
||||
Switching it on happens at first-run, not at finalize-user time, because finalize-user
|
||||
also runs in the ISO chroot where there is no audio server: the sink a tuning has
|
||||
to target does not exist there, so nothing could be written — and nothing would
|
||||
retry, since the finalizer marks all shipped migrations complete on a fresh
|
||||
install. Matching itself deliberately does not consult the audio graph, so the
|
||||
LV2 dependency is still installed in the chroot.
|
||||
|
||||
```bash
|
||||
omarchy audio tuning on # install the matching tuning
|
||||
omarchy audio tuning off # remove it, back to raw speakers
|
||||
omarchy audio tuning status # installed? in use? what matches?
|
||||
```
|
||||
|
||||
`match` and `fronted-sink` are also accepted; they exist for the install hooks
|
||||
and the sink-listing scripts rather than for daily use.
|
||||
|
||||
## Adding a tuning
|
||||
|
||||
Add a directory with a `tuning.conf` and a `filter-chain.conf`. No new command is
|
||||
needed: matching is data. A tuning declares how to recognise its hardware, plus the
|
||||
`sink_pattern` its graph targets:
|
||||
|
||||
| Key | Matches on | Notes |
|
||||
|---|---|---|
|
||||
| `match_sku` | DMI product SKU, whole value | Most precise. Vendors key speaker firmware on it, so it identifies the hardware rather than a marketing name |
|
||||
| `match_dmi` | DMI product name or family, substring | Convenient, but a short string widens fast — `product_family` here is `Dell Laptops` |
|
||||
| `match_command` | Any predicate you name | For hardware needing a sharper test than either |
|
||||
|
||||
`match_sku` and `match_dmi` are lists, so one tuning can cover several models it has
|
||||
been validated on:
|
||||
|
||||
```bash
|
||||
match_sku=("0DB9" "0DBA") # XPS 14 and XPS 16
|
||||
```
|
||||
|
||||
`sink_pattern` is required whichever method you use, since the graph's target sink
|
||||
is substituted from it.
|
||||
|
||||
Gate narrowly and widen as models are validated; a tuning aimed at the wrong
|
||||
drivers can sound worse than none and can stress them. When a tuning covers a model
|
||||
it was not measured on, say so in `tuning.conf` — the provenance fields are there to
|
||||
keep that distinction visible rather than implied.
|
||||
|
||||
Two hard requirements:
|
||||
|
||||
- **End in a limiter.** Peaks must stay under 0 dBFS with headroom.
|
||||
- **Do not boost what the drivers cannot deliver.** The XPS 14 tuning
|
||||
deliberately *cuts* 40 Hz by around 18 dB. Excursion down there buys nothing
|
||||
and costs distortion.
|
||||
|
||||
## Building one
|
||||
|
||||
Measuring a laptop and fitting a filter-chain to it is a separate job with its own
|
||||
tools, in [omarchy-audio-tuner](https://github.com/omacom-io/omarchy-audio-tuner).
|
||||
It is not installed by default — almost nobody authoring a tuning, and it needs
|
||||
python, ffmpeg and mpv.
|
||||
|
||||
```bash
|
||||
omarchy pkg add omarchy-audio-tuner
|
||||
```
|
||||
|
||||
Its README is the walkthrough, and covers both cases: copying a reference that
|
||||
already sounds right (how the XPS 14 tuning was made, no microphone needed), and
|
||||
designing from scratch, which needs a *calibrated* measurement mic and a target
|
||||
curve that measurement alone cannot give you.
|
||||
|
||||
## What a tuning must report
|
||||
|
||||
A tuning is not reviewable on "sounds better to me". Record these, measured, in
|
||||
`tuning.conf`:
|
||||
|
||||
| Field | What it is |
|
||||
|---|---|
|
||||
| `magnitude_rms_db` | Deviation from the reference or target it was fitted to |
|
||||
| `bass_group_delay_swing_ms` | Max minus min group delay, 30–300 Hz |
|
||||
| `limiter_headroom_db` | Worst-case peak against the limiter threshold |
|
||||
| `dynamic_range_delta_lu` | LRA change against the reference |
|
||||
|
||||
Measure electrically by capturing the physical speaker sink's monitor, which sits
|
||||
upstream of the volume control, so results are independent of listening level.
|
||||
|
||||
## How this fits the audio graph
|
||||
|
||||
Two things about the surrounding system are worth knowing, because both caused
|
||||
real bugs:
|
||||
|
||||
- **Volume lives downstream of the tuning.** A tuning is a virtual sink that
|
||||
becomes the default output, and changing *its* volume would alter the level
|
||||
going into the processing — moving the display while the speakers stay put, and
|
||||
changing the tone of anything with a compressor or limiter in it.
|
||||
`omarchy-audio-output-sink` is the single definition of "which sink does this
|
||||
output's volume really use": it resolves a sink through any DSP sink to the
|
||||
physical one, and with no argument resolves the current default output. The
|
||||
volume keys, the output switcher's OSD and the audio panel all use it, so they
|
||||
cannot disagree. Resolving the *current default* rather than "whatever a tuning
|
||||
fronts" is what keeps it correct when headphones or HDMI are selected while a
|
||||
tuning still exists.
|
||||
- **The fronted sink is hidden.** The tuning and the physical speakers both exist
|
||||
in the graph, and selecting the physical one would only bypass the tuning. So
|
||||
`omarchy-audio-sink-availability` reports it unavailable and
|
||||
`omarchy-audio-output-switch` skips it, leaving one speaker entry in the panel.
|
||||
A WirePlumber smart filter would remove the need for both — it leaves the real
|
||||
device as the default output — but on PipeWire 1.6.8 / WirePlumber 0.5.15 the
|
||||
graph loads and links correctly as a smart filter and then passes audio through
|
||||
unprocessed. Revisit when that is understood.
|
||||
- **EasyEffects cannot coexist with a tuning.** It moves any stream that follows
|
||||
the default sink to its own sink, so it would grab audio back from a
|
||||
filter-chain. `on` refuses while it is running rather than installing a graph
|
||||
that would be bypassed.
|
||||
- **The tuning's own output must not be moved.** A filter-chain's output is a
|
||||
playback stream like any other, so anything rerouting "all streams" to a newly
|
||||
selected output would drag the processing with it — onto headphones, or into the
|
||||
tuning's own sink, which is a cycle. The tuning sets `node.dont-move`, and
|
||||
`omarchy-audio-output-set-default` moves only streams that carry an
|
||||
`application.name`.
|
||||
+22
-13
@@ -97,6 +97,7 @@ default/** ──► omarchy-settings /usr/share/omarchy
|
||||
│ → /etc/skel/.bashrc (post_install cp -f)
|
||||
├─ hypr/toggles/flags.lua /etc/skel/.local/state/omarchy/toggles/hypr/
|
||||
├─ nautilus-python/extensions/*.py /etc/skel/.local/share/nautilus-python/extensions/
|
||||
├─ tensaku/state.toml /etc/skel/.local/state/tensaku/state.toml
|
||||
├─ uwsm/env.d/10-omarchy /usr/share/uwsm/env.d/
|
||||
├─ environment.d/*.conf /usr/lib/environment.d/
|
||||
├─ fontconfig/conf.avail/50-omarchy.conf /usr/share/fontconfig/conf.avail/
|
||||
@@ -105,6 +106,7 @@ default/** ──► omarchy-settings /usr/share/omarchy
|
||||
├─ applications/mimeapps.list /usr/share/applications/mimeapps.list
|
||||
├─ systemd/user/*.{service,path} /usr/lib/systemd/user/
|
||||
├─ systemd/system-sleep/unmount-fuse /usr/lib/systemd/system-sleep/
|
||||
├─ systemd/zram-generator.conf.d/90-omarchy.conf /usr/lib/systemd/zram-generator.conf.d/
|
||||
├─ fonts/omarchy/omarchy.ttf /usr/share/fonts/omarchy/
|
||||
├─ sddm/omarchy/ /usr/share/sddm/themes/omarchy/
|
||||
├─ sddm/hyprland.lua /usr/share/sddm/hyprland.lua
|
||||
@@ -195,13 +197,19 @@ migration. Migrations run as the user; privileged work should invoke the
|
||||
appropriate helper or privilege prompt. Migrations must be idempotent;
|
||||
machine-wide repairs should no-op when another user already applied them.
|
||||
|
||||
Each graphical user has `omarchy-update-user-notify.path` watching the packaged
|
||||
migration directory for changes, and `omarchy-update-user-notify.service` is
|
||||
also started once per login via its own `WantedBy=graphical-session.target`.
|
||||
Either way the service runs `omarchy-migrate-notify` as that user. The notifier checks
|
||||
`omarchy-migrate --pending`. If this user has missing migration state, it shows a
|
||||
notification that opens a terminal for `omarchy-migrate`. The notifier never runs
|
||||
migrations in the background.
|
||||
Each graphical user has `omarchy-migrate-notify.service`, started once per login
|
||||
through `WantedBy=graphical-session.target`. The package also ships
|
||||
`omarchy-update-user-notify.service` as a symlink onto it, so users enabled
|
||||
under the old unit name keep working before they reach migration `1785095882`.
|
||||
It runs `omarchy-migrate-notify` as
|
||||
that user, which checks `omarchy-migrate --pending`. If this user has missing
|
||||
migration state, it shows a notification that opens a terminal for
|
||||
`omarchy-migrate`. The notifier never runs migrations in the background.
|
||||
|
||||
Login is the only trigger. Nothing watches the packaged migration directory: a
|
||||
watcher cannot tell a bypassed `pacman -Syu` from the package transaction inside
|
||||
a normal `omarchy update`, so it notified about migrations that `omarchy-migrate`
|
||||
was already applying in the visible update terminal.
|
||||
|
||||
`omarchy-migrate` waits for any active pacman transaction to finish, then runs
|
||||
pending migrations. It does not need `--force`; migrations happen when state
|
||||
@@ -219,8 +227,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-update-user-notify.path`,
|
||||
`omarchy-update-user-notify.service`). Done here, not at finalize, because
|
||||
`omarchy-recover-internal-monitor`, `omarchy-migrate-notify.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.
|
||||
- `install/user/first-run/gnome-theme.sh`,
|
||||
@@ -247,14 +255,14 @@ the legacy finalization marker from `~/.local/state/omarchy/` into `done/`.
|
||||
`omarchy-setup-system` (root, in chroot) runs target-side setup at ISO
|
||||
finalization. It sources:
|
||||
|
||||
- `install/config/*.sh` — theme links, lockout limits, lockscreen PAM,
|
||||
- `install/config/all.sh` — theme links, lockout limits, lockscreen PAM,
|
||||
powerprofilesctl shebang fix, docker setup, Snapper retention, locate
|
||||
index tuning, service enablement, firewall.
|
||||
- `install/hardware/all.sh` via `omarchy-setup-hardware` — vendor- and
|
||||
device-specific kernel modules, udev rules, microcode, wireless regdom,
|
||||
ASUS / Framework / Intel / Apple / Lenovo quirks.
|
||||
- `install/login/*.sh` — SDDM theme/session config.
|
||||
- `install/post-install/*.sh` — final pacman/udev/localdb passes.
|
||||
- `install/login/all.sh` — SDDM theme/session config.
|
||||
- `install/post-install/all.sh` — final pacman/udev/localdb passes.
|
||||
|
||||
Logging goes to `/var/log/omarchy-install.log` via
|
||||
`install/helpers/logging.sh`.
|
||||
@@ -288,8 +296,9 @@ return to the packaged default.
|
||||
| Package-owned system file (e.g. systemd user service/path in `/usr/lib`) | `default/`, document the mapping in `default/package-defaults.tsv`, then add the `install -Dm644` line in `omarchy-settings` PKGBUILD |
|
||||
| Per-user file that's static but lives outside `~/.config` | `default/`, then add `install -Dm644 ... $pkgdir/etc/skel/...` in `omarchy-settings` PKGBUILD |
|
||||
| Runtime tweak that needs `$HOME` or live system state | extend `omarchy-finalize-user`, or add a per-user leaf under `install/user/` and wire into `install/user/all.sh` |
|
||||
| One-time root-side setup step | `install/config/*.sh` or `install/hardware/*.sh`, wire into `omarchy-setup-system` or `install/hardware/all.sh` |
|
||||
| One-time root-side setup step | `install/config/*.sh` or `install/hardware/*.sh`, wire into `install/config/all.sh` or `install/hardware/all.sh` |
|
||||
| One-time fix for existing installs | `migrations/<unix-timestamp>.sh` |
|
||||
| Package-owned path something else may already write | Prefer a path nothing else writes, such as a vendor drop-in under `/usr/lib`. Otherwise the `--overwrite` entry in `bin/omarchy-update-system-pkgs` has to ship a release before the file |
|
||||
| User-facing `omarchy-*` command | `bin/omarchy-<group>-<verb>` — see `GROUP_DESCRIPTIONS` in `bin/omarchy` |
|
||||
| New stock theme | `themes/<name>/` (+ matching templates under `default/themed/` if they need theme colors) |
|
||||
| User-installed theme | `~/.config/omarchy/themes/<name>/` |
|
||||
|
||||
+11
-9
@@ -43,16 +43,9 @@ omarchy-hook post-update
|
||||
`omarchy-migrate` waits for any active pacman transaction to finish, then runs
|
||||
all pending migrations for the current user in the visible update terminal.
|
||||
|
||||
### During direct pacman updates
|
||||
### At login
|
||||
|
||||
Raw `sudo pacman -Syu` is guarded. Users should normally run:
|
||||
|
||||
```bash
|
||||
omarchy update
|
||||
```
|
||||
|
||||
If a user explicitly bypasses the guard, user sessions watch the packaged
|
||||
migration directory and run a notifier. The notifier checks:
|
||||
Every graphical login starts `omarchy-migrate-notify.service`, which checks:
|
||||
|
||||
```bash
|
||||
omarchy-migrate --pending
|
||||
@@ -67,6 +60,15 @@ omarchy-migrate
|
||||
|
||||
The notifier never runs migrations silently in the background.
|
||||
|
||||
This is what covers users who did not run the update themselves: someone who
|
||||
bypassed the pacman guard with `sudo env OMARCHY_ALLOW_DIRECT_PACMAN=1 pacman
|
||||
-Syu`, and any second user on the machine, whose migration markers are per-user
|
||||
and therefore still missing after another user updated.
|
||||
|
||||
Login is the only trigger on purpose. Watching the packaged migration directory
|
||||
also fires during a normal `omarchy update`, which prompts for migrations that
|
||||
`omarchy-migrate` is about to run in the visible update terminal.
|
||||
|
||||
### Manually
|
||||
|
||||
Users can safely run:
|
||||
|
||||
+36
-9
@@ -118,6 +118,7 @@ omarchy-update
|
||||
├─ create snapper snapshot, if snapper is installed
|
||||
└─ run update pipeline
|
||||
├─ block system sleep and temporarily enable shell stay-awake mode
|
||||
├─ omarchy-update-dev
|
||||
├─ omarchy-update-keyring
|
||||
├─ omarchy-update-system-pkgs
|
||||
├─ omarchy-migrate
|
||||
@@ -133,6 +134,8 @@ omarchy-update
|
||||
|
||||
Important behavior:
|
||||
|
||||
- In dev-link mode, `omarchy update` fast-forwards the active checkout from its
|
||||
configured upstream before changing system packages or running migrations.
|
||||
- `omarchy update` checks/runs migrations in the same visible terminal via
|
||||
`omarchy-migrate` after pacman finishes.
|
||||
- A failure should leave enough output in `/tmp/omarchy-update.log` and the
|
||||
@@ -146,20 +149,37 @@ High-level flow:
|
||||
sudo pacman -Syu
|
||||
├─ pre-transaction guard aborts and tells the user to run omarchy update
|
||||
└─ if explicitly bypassed, upgrades omarchy and related packages
|
||||
└─ user session notices migration directory changes
|
||||
├─ omarchy-update-user-notify.path triggers, if enabled
|
||||
└─ at that user's next login
|
||||
├─ omarchy-migrate-notify.service starts with graphical-session.target
|
||||
├─ omarchy-migrate-notify checks omarchy-migrate --pending
|
||||
├─ if this user has missing migration state, show notification
|
||||
└─ click opens terminal: omarchy-migrate
|
||||
```
|
||||
|
||||
Login is deliberately the only trigger. A watcher on the packaged migration
|
||||
directory cannot distinguish a bypassed `pacman -Syu` from the package
|
||||
transaction inside a normal `omarchy update`, so it fired notifications for
|
||||
migrations that `omarchy-migrate` was about to apply in the visible update
|
||||
terminal. The retired unit was `omarchy-update-user-notify.path`.
|
||||
|
||||
Fallbacks:
|
||||
|
||||
- `omarchy-first-run` enables the user notification path unit.
|
||||
- `omarchy-first-run` also invokes `omarchy-migrate-notify` on graphical
|
||||
startup, so users who updated before the path unit existed still get prompted
|
||||
if they have missing migration state.
|
||||
- `omarchy-first-run` enables `omarchy-migrate-notify.service`, which also
|
||||
covers users created after install: their per-user migration markers are
|
||||
missing, so their first login prompts them to run every shipped migration.
|
||||
- The package ships `omarchy-update-user-notify.service` as a symlink onto
|
||||
`omarchy-migrate-notify.service`. Users set up before the rename hold an
|
||||
absolute `graphical-session.target.wants` symlink to the old path, and the
|
||||
migration that repoints it only runs for users who run an update — the
|
||||
opposite of who the notifier is for. The alias can be dropped once installs
|
||||
have run migration `1785095882`.
|
||||
- The notifier waits for a live notification server before sending, because
|
||||
`graphical-session.target` can be reached before the shell claims
|
||||
`org.freedesktop.Notifications`.
|
||||
- The notifier is only a prompt. It does not run migrations in the background.
|
||||
- A session that is already open when another user updates is not re-checked;
|
||||
it picks the migrations up at its next login, or whenever that user runs
|
||||
`omarchy-migrate` or `omarchy update`.
|
||||
- Direct pacman updates do not run `omarchy-hook post-update` unless the user
|
||||
explicitly runs that hook; without a package-update marker, the only pending
|
||||
state we can derive is missing per-user migration markers.
|
||||
@@ -172,11 +192,16 @@ The bar widget `omarchy.system-update` runs:
|
||||
omarchy-update-available
|
||||
```
|
||||
|
||||
`omarchy-update-available` checks the installed Omarchy package for updates:
|
||||
`omarchy-update-available` checks the active Omarchy sources for updates:
|
||||
|
||||
- new upstream commits for the active dev-linked checkout
|
||||
- `omarchy-dev`, when installed
|
||||
- otherwise `omarchy`, when installed
|
||||
|
||||
The dev check fetches the checkout's configured upstream before comparing it
|
||||
with `HEAD`. A failed fetch is quiet and falls back to the existing remote-
|
||||
tracking state.
|
||||
|
||||
Exit codes:
|
||||
|
||||
- `0` — Omarchy updates are available; stdout is the update list.
|
||||
@@ -196,11 +221,12 @@ scripts.
|
||||
| `omarchy-update` | Public user command. Adds transcript logging, lock, confirmation, snapshot, sleep/idle inhibitors, package updates, migrations, hooks, update-state refresh, and restart checks. | **Keep.** This is the blessed entry point and owns the update pipeline. |
|
||||
| `omarchy-update-perform` | Hidden compatibility wrapper for `omarchy-update -y`. | **Temporary.** Keep only for old callers; new code should call `omarchy-update` directly. |
|
||||
| `omarchy-update-confirm` | Gum confirmation copy for `omarchy update`. | **Question.** Could be inlined into `omarchy-update`; separate file only helps keep copy isolated. |
|
||||
| `omarchy-update-dev` | Fast-forwards the active dev-linked checkout from its configured upstream; no-ops for package-backed installs. | **Keep.** Runs before package updates so a checkout conflict stops the update before system mutation. |
|
||||
| `omarchy-update-keyring` | Ensures Omarchy keyring and Arch keyring are current before the main transaction. | **Keep, but review.** It uses targeted `pacman -Sy` for keyring bootstrapping; acceptable for this special case but should remain tightly scoped. |
|
||||
| `omarchy-update-system-pkgs` | Runs `sudo env OMARCHY_UPDATE_PACMAN=1 pacman -Syu --noconfirm` with targeted transition `--overwrite` entries so the ALPM guard allows the transaction and early package-layout conflicts are handled. | **Keep for now.** Small leaf command, clear/testable. |
|
||||
| `omarchy-migrate` | Public migration command. Waits for pacman, then runs all pending migrations for the current user. Supports `--pending`. | **Keep.** This replaces the discarded `omarchy-update-user-finalize` name and no longer needs `--force`. |
|
||||
| `omarchy-update-pacman-guard` | ALPM pre-transaction guard that aborts direct `pacman -Syu` style upgrades unless Omarchy set `OMARCHY_UPDATE_PACMAN=1` or the user explicitly set `OMARCHY_ALLOW_DIRECT_PACMAN=1`. | **Keep internal/hidden.** This is what nudges users back to `omarchy update`. |
|
||||
| `omarchy-migrate-notify` | Internal notification helper for direct pacman updates. Uses `omarchy-migrate --pending` and shows notification only when this user has pending migrations. | **Keep internal/hidden.** Clear name now that the public command is `omarchy-migrate`. |
|
||||
| `omarchy-migrate-notify` | Internal login-time notification helper. Uses `omarchy-migrate --pending` and shows a notification only when this user has pending migrations. | **Keep internal/hidden.** Clear name now that the public command is `omarchy-migrate`. |
|
||||
| `omarchy-update-user-notify` | Hidden compatibility wrapper for `omarchy-migrate-notify`. | **Temporary.** Keep only for old callers. |
|
||||
| `omarchy-update-available` | Update checker for shell widget and post-update refresh. | **Keep.** Could eventually be renamed `omarchy-update-check`, but current name matches widget semantics. |
|
||||
| `omarchy-update-aur-pkgs` | Updates AUR packages with `yay -Sua` if foreign packages exist and AUR is reachable. | **Question.** Omarchy is package-backed now, but users may still install AUR packages. Keep for now. |
|
||||
@@ -220,7 +246,8 @@ scripts.
|
||||
idempotent when they repair machine-wide state.
|
||||
|
||||
2. **Migration notification naming**
|
||||
- The real helper is `omarchy-migrate-notify`.
|
||||
- The real helper is `omarchy-migrate-notify`, started by
|
||||
`omarchy-migrate-notify.service`.
|
||||
- `omarchy-update-user-notify` remains only as a hidden compatibility wrapper.
|
||||
|
||||
3. **Update pipeline ownership**
|
||||
|
||||
Reference in New Issue
Block a user