d101b23351
Update PKGBUILD version / update-pkgver (push) Successful in 5s
Per the committed=English rule. Also documents the windowed-video idle-inhibit added in the same series.
95 lines
7.5 KiB
Markdown
95 lines
7.5 KiB
Markdown
# Moonarch
|
|
|
|
Reproducible Arch Linux setup based on archinstall + post-install automation.
|
|
|
|
## Project Structure
|
|
|
|
- `config/` — archinstall configuration (incl. custom-commands that clone the repo to /opt/moonarch, root-owned)
|
|
- `scripts/` — post-install and helper scripts
|
|
- `packages/` — package lists (official + AUR), maintained separately
|
|
- `defaults/` — XDG configs, shell config, helper binaries, systemd services, udev rules, greetd/moongreet config, wallpaper
|
|
|
|
## Battery Conservation Mode
|
|
|
|
Laptops with `charge_control_end_threshold` support (ThinkPad, Framework, etc.) get a Waybar toggle:
|
|
- Clicking the battery module toggles the charge limit between 80% and 100%
|
|
- When conservation is active, a ♥ icon appears next to the battery indicator
|
|
- State is persisted in `/var/lib/moonarch/batsaver-threshold` and restored on boot via a systemd service (`moonarch-batsaver-restore`)
|
|
- Toggle flow: `moonarch-batsaver-toggle` (user script) reads sysfs, decides 80↔100, calls `pkexec /usr/bin/moonarch-batsaver-apply $NEW` for the privileged sysfs+state write step. Standard pkexec prompt (password once per session cache)
|
|
- On desktops without battery support the feature is hidden entirely
|
|
|
|
## Nightlight (Blue Light Filter)
|
|
|
|
Waybar toggle for wlsunset (Wayland-native blue light filter), persistent state via systemd:
|
|
- `wlsunset.service` (systemd user service) with `After=kanshi.service` — starts only once all outputs are configured
|
|
- **Default OFF** — fresh installs start without the filter. The PKGBUILD deliberately creates NO symlink for `wlsunset` in `/etc/systemd/user/graphical-session.target.wants/`, and post-install.sh does not enable the service.
|
|
- Clicking the nightlight module in `group/brightness` toggles wlsunset on/off (`enable --now` / `disable --now`)
|
|
- State survives reboots (user-scope symlink in `~/.config/systemd/user/...wants/`)
|
|
- Active state shows in Catppuccin Yellow, inactive in the default text color
|
|
- Signal SIGRTMIN+11 for immediate Waybar refresh
|
|
- Scripts: `moonarch-nightlight` (toggle), `moonarch-waybar-nightlight` (status JSON)
|
|
- **Important**: Never create a global-scope symlink at `/etc/systemd/user/...wants/wlsunset.service` — it overrides any user `disable` and makes the filter effectively impossible to turn off.
|
|
|
|
## Waybar Config Merger (moonarch-waybar)
|
|
|
|
Waybar is started via `moonarch-waybar` (not directly). The wrapper merges an optional user config (`~/.config/waybar/userconfig`) with the system config (`/etc/xdg/waybar/config`):
|
|
- `prepend`/`append` keys in the userconfig extend the `modules-left`/`modules-center`/`modules-right` arrays
|
|
- All other top-level keys are inserted as module definitions via object merge
|
|
- The merge runs only on changes (timestamp comparison)
|
|
- On error: `notify-send` + `logger`, Waybar starts with the system config
|
|
- Generates `~/.config/waybar/style.css` with an `@import` of the system styles if not present
|
|
- Requires `jq` (declared as a dependency in the PKGBUILD)
|
|
- The system config must be valid JSON (no JSONC)
|
|
|
|
## mpv + ModernZ OSC
|
|
|
|
The video player is `mpv` with [ModernZ](https://github.com/Samillion/ModernZ) as the OSC, thumbnails via thumbfast:
|
|
- `mpv-modernz-git` provides `modernz.lua` + font + default config to `/etc/mpv/`
|
|
- `mpv-thumbfast-git` provides `thumbfast.lua` to `/etc/mpv/scripts/` (auto-detected by ModernZ)
|
|
- `defaults/etc/mpv/mpv.conf` is installed directly to `/etc/mpv/mpv.conf` by moonarch-git (owned)
|
|
- Stock OSC + title bar disabled, `autofit-larger=80%x80%` caps oversized windows
|
|
- ModernZ overrides via `script-opts-append` in mpv.conf: orange accent → Catppuccin Lavender (`#b4befe`), OSC scale 0.75, `window_title_font_size=18`, `ontop_button=no`
|
|
- **Important**: mpv treats `#` as a mid-line comment; hex colors must be quoted: `script-opts-append="modernz-seekbarfg_color=#b4befe"` (not `\#`, which only escapes and swallows the rest)
|
|
- Niri opens mpv floating (`window-rule` in `defaults/xdg/niri/config.kdl`)
|
|
|
|
## System Health Check (moonarch-doctor / moondoc)
|
|
|
|
Diagnostic script that checks the system state against moonarch defaults:
|
|
- Packages (official.txt + aur.txt installed? Orphans?)
|
|
- System services (NetworkManager, bluetooth, greetd, ufw, auto-cpufreq, etc.)
|
|
- User services (kanshi, wlsunset, stasis, walker, nautilus, cliphist-text, cliphist-image)
|
|
- Config files (SHA256 comparison deployed vs. moonarch default)
|
|
- Helper scripts + symlinks (moonup, moondoc)
|
|
- System config (UFW, pacman/paru repos, default shell)
|
|
- Directories + permissions
|
|
|
|
## Fontconfig Defaults
|
|
|
|
System-wide generic-family defaults via `defaults/etc/fonts/conf.d/65-moonarch-fonts.conf` (owned by moonarch-git):
|
|
- `sans-serif` → UbuntuSans Nerd Font, `monospace` → UbuntuSansMono Nerd Font
|
|
- Number **65**: loads after `60-latin.conf`, so the moonarch prefs beat the stock default (Noto/DejaVu). `local.conf` (at 51 via `51-local.conf`) loads too early and is overridden by 60-latin — therefore **do not** use it (it is also reserved for local user overrides).
|
|
- Aliases need `binding="strong"` — a weak `<prefer>` (fontconfig default) ranks behind the effective generic fallback and does not take effect.
|
|
- Only applies to apps that use generic families (e.g. Firefox web fallback). moonarch apps (Waybar, foot, GTK, walker, swaync) set the font explicitly.
|
|
|
|
## Browser Idle-Inhibit (xdg-desktop-portal)
|
|
|
|
So that windowed browser video (Firefox/Waterfox) keeps the screen awake, via `defaults/etc/xdg-desktop-portal/niri-portals.conf` (owned by moonarch-git, higher priority than niri's `/usr/share/xdg-desktop-portal/niri-portals.conf`):
|
|
- `xdg-desktop-portal-gtk` reports the `Inhibit` interface as success even though nobody implements it under Niri → Firefox believes the idle-inhibit went through the portal and does not use the native Wayland `idle-inhibit`. Result: no inhibitor, screen sleeps.
|
|
- Fix: `org.freedesktop.impl.portal.Inhibit=none` → Firefox falls back to `zwp_idle_inhibit`, which Niri honors. The remaining `[preferred]` lines are taken 1:1 from niri's default (portals.conf is not merged — the highest-priority file applies in full).
|
|
- stasis is uninvolved here: `monitor_media` (pactl) does not capture browser audio by design (non-browser players only); browsers go through the inhibit path.
|
|
- **Activation:** restart xdg-desktop-portal + the browser — Firefox queries portal support at startup.
|
|
|
|
### Windowed / Muted Video: wayland-pipewire-idle-inhibit
|
|
|
|
The portal fix only applies to **fullscreen** video — Firefox/Waterfox send the idle-inhibit only in fullscreen. Windowed video remains unprotected: stasis ignores browser audio (pactl, browser-excluded, no MPRIS backend), Niri gets no inhibitor, the screen sleeps mid-video.
|
|
|
|
Solution: `wayland-pipewire-idle-inhibit` (AUR, systemd user service; in `packages/aur.txt` + `post-install.sh` USER_SERVICES + moonarch-doctor). Holds a Wayland `zwp_idle_inhibit` inhibitor while PipeWire outputs audio (default threshold 5s). Niri then suppresses idle → stasis stays awake, daemon-independent. Releases automatically when audio stops.
|
|
- Catches windowed video **with sound**. Misses muted video (no audio signal) — edge case, accepted.
|
|
- **Never** put `waterfox`/a browser in stasis `inhibit_apps`: that inhibits unconditionally as long as the browser process runs → the system never idles. This exact wrong fix caused the "no idle" bug.
|
|
|
|
## Conventions
|
|
|
|
- Package lists are plain text files, one package per line, comments with `#`
|
|
- Shell scripts must be POSIX-compatible or explicitly bash/zsh
|
|
- All paths in the archinstall config are relative to the install target
|