The media keys called wpctl/brightnessctl directly with no visual feedback — changing volume showed nothing on screen. Now they drive swayosd-client, which performs the action AND shows a themed OSD. - modules/home/osd.nix: services.swayosd, style.css generated from the palette (base bg, accent progress/border); nomarchy.osd.enable. - hyprland media binds → swayosd-client (--output-volume raise/lower/ mute-toggle, --input-volume mute-toggle, --brightness raise/lower). - modules/nixos: services.udev.packages = [ swayosd ] installs the backlight rule (chgrp video + g+w) so brightness works for video-group users without root (the installer/live user is in video). swaync is unaffected (it was already running — this was purely the missing OSD). Verified: flake check green, swayosd.service bound to graphical-session.target, hyprland config verifies, swayosd in the live ISO closure. On-screen rendering needs a real session to confirm. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
211 lines
8.7 KiB
Nix
211 lines
8.7 KiB
Nix
# Nomarchy — reusable system layer (NixOS 26.05).
|
||
#
|
||
# This module is the distro: import it from any host (see
|
||
# nixosModules.nomarchy in flake.nix) and layer your machine specifics
|
||
# (bootloader, hostname, users, hardware) on top. Host concerns are
|
||
# deliberately NOT set here. Everything user-facing (Hyprland config,
|
||
# Waybar, Ghostty, theming) lives in modules/home.
|
||
{ config, lib, pkgs, ... }:
|
||
|
||
let
|
||
cfg = config.nomarchy.system;
|
||
in
|
||
{
|
||
imports = [ ./options.nix ./plymouth.nix ./file-manager.nix ];
|
||
|
||
config = {
|
||
# The safe half of distro branding: distroName flows into
|
||
# /etc/os-release PRETTY_NAME, systemd-boot entry titles and the
|
||
# ISO boot-menu label. distroId stays "nixos" on purpose — it feeds
|
||
# DEFAULT_HOSTNAME and upstream isNixos checks (see roadmap).
|
||
system.nixos.distroName = lib.mkDefault "Nomarchy";
|
||
|
||
# Unfree allowed distro-wide: pragmatic-desktop territory (claude-code
|
||
# for the menu's ask-Claude module, vendor drivers, …). The custom
|
||
# nixpkgs-config type can't carry a nested mkDefault; disagree with
|
||
# `nixpkgs.config = lib.mkForce { allowUnfree = false; }`.
|
||
nixpkgs.config.allowUnfree = true;
|
||
|
||
# ── Wayland session: Hyprland ────────────────────────────────────
|
||
# Installs the binary, registers the session, wires up
|
||
# xdg-desktop-portal-hyprland. Configuration is Home Manager's job.
|
||
programs.hyprland.enable = lib.mkDefault true;
|
||
|
||
xdg.portal = {
|
||
enable = lib.mkDefault true;
|
||
extraPortals = [ pkgs.xdg-desktop-portal-gtk ]; # file pickers, etc.
|
||
};
|
||
|
||
services.greetd = lib.mkIf cfg.greeter.enable {
|
||
enable = lib.mkDefault true;
|
||
settings = {
|
||
default_session = {
|
||
# start-hyprland is Hyprland 0.55's watchdog launcher; running
|
||
# the bare binary makes every session print a warning.
|
||
command = lib.mkDefault "${pkgs.tuigreet}/bin/tuigreet --time --remember --cmd start-hyprland";
|
||
user = "greeter";
|
||
};
|
||
# Boot straight into the session once; logout → normal greeter.
|
||
initial_session = lib.mkIf (cfg.greeter.autoLogin != null) {
|
||
command = "start-hyprland";
|
||
user = cfg.greeter.autoLogin;
|
||
};
|
||
};
|
||
};
|
||
|
||
# ── Audio: Pipewire ──────────────────────────────────────────────
|
||
security.rtkit.enable = lib.mkDefault cfg.audio.enable;
|
||
services.pulseaudio.enable = lib.mkDefault false;
|
||
services.pipewire = lib.mkIf cfg.audio.enable {
|
||
enable = lib.mkDefault true;
|
||
alsa.enable = true;
|
||
alsa.support32Bit = true;
|
||
pulse.enable = true;
|
||
wireplumber.enable = true;
|
||
};
|
||
|
||
# ── Desktop services ─────────────────────────────────────────────
|
||
security.polkit.enable = lib.mkDefault true;
|
||
services.gnome.gnome-keyring.enable = lib.mkDefault true;
|
||
services.dbus.enable = lib.mkDefault true;
|
||
services.upower.enable = lib.mkDefault true;
|
||
networking.networkmanager.enable = lib.mkDefault true;
|
||
|
||
hardware.bluetooth.enable = lib.mkDefault cfg.bluetooth.enable;
|
||
services.blueman.enable = lib.mkDefault cfg.bluetooth.enable;
|
||
|
||
# ── Firmware ─────────────────────────────────────────────────────
|
||
# Blobs for in-kernel drivers: wifi (iwlwifi/ath/rtw/brcm), SOF
|
||
# audio, Bluetooth. Drivers ship with the kernel, but without these
|
||
# a real machine can boot with no wifi — QEMU never catches it.
|
||
# nixos-generate-config also keys CPU microcode off this flag.
|
||
hardware.enableRedistributableFirmware = lib.mkDefault true;
|
||
|
||
# ── BTRFS timeline snapshots (ported from the previous iteration) ─
|
||
# Guarded on the actual filesystem so enabling it on an ext4 machine
|
||
# is a clean no-op rather than a failing timer.
|
||
services.snapper.configs = lib.mkIf
|
||
(cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
||
{
|
||
root = {
|
||
SUBVOLUME = "/";
|
||
TIMELINE_CREATE = true;
|
||
TIMELINE_CLEANUP = true;
|
||
TIMELINE_LIMIT_HOURLY = "5";
|
||
TIMELINE_LIMIT_DAILY = "7";
|
||
TIMELINE_LIMIT_WEEKLY = "0";
|
||
TIMELINE_LIMIT_MONTHLY = "0";
|
||
TIMELINE_LIMIT_YEARLY = "0";
|
||
};
|
||
};
|
||
|
||
# ── Fonts ────────────────────────────────────────────────────────
|
||
# The ten most popular Nerd Fonts ship by default, so any of them
|
||
# can be named in the theme state's fonts.mono and actually resolve
|
||
# (nomarchy-theme-sync warns when a configured font is missing).
|
||
fonts = {
|
||
packages = with pkgs; [
|
||
nerd-fonts.jetbrains-mono
|
||
nerd-fonts.fira-code
|
||
nerd-fonts.caskaydia-cove
|
||
nerd-fonts.hack
|
||
nerd-fonts.sauce-code-pro
|
||
nerd-fonts.meslo-lg
|
||
nerd-fonts.roboto-mono
|
||
nerd-fonts.ubuntu-mono
|
||
# iosevka would be next by popularity, but its package is 1.1 GB
|
||
# (every weight × variant) — too heavy for the ISO and closures.
|
||
nerd-fonts.mononoki
|
||
nerd-fonts.inconsolata
|
||
inter
|
||
noto-fonts
|
||
noto-fonts-color-emoji
|
||
# The legacy-ported waybar identities (summer-day/night) use
|
||
# FontAwesome codepoints in their layouts and list it in css.
|
||
font-awesome
|
||
];
|
||
fontconfig.defaultFonts = {
|
||
monospace = lib.mkDefault [ "JetBrainsMono Nerd Font" ];
|
||
sansSerif = lib.mkDefault [ "Inter" ];
|
||
emoji = lib.mkDefault [ "Noto Color Emoji" ];
|
||
};
|
||
};
|
||
|
||
# ── Essential packages ───────────────────────────────────────────
|
||
environment.systemPackages = with pkgs; [
|
||
nomarchy-theme-sync # provided by overlays.default
|
||
|
||
# Friendly wrappers for the two rebuild paths (README §3). Run as
|
||
# your user: `nix flake update` must NOT run as root (libgit2
|
||
# refuses the user-owned flake repo) — sudo happens inside, only
|
||
# for the system switch.
|
||
(pkgs.writeShellScriptBin "sys-update" ''
|
||
set -e
|
||
if [ "$(id -u)" -eq 0 ]; then
|
||
echo "sys-update: run as your normal user (it sudos the rebuild itself)" >&2
|
||
exit 1
|
||
fi
|
||
flake="''${NOMARCHY_PATH:-$HOME/.nomarchy}"
|
||
echo "sys-update: updating flake inputs in $flake"
|
||
nix flake update --flake "$flake"
|
||
if command -v nixos-rebuild-snap >/dev/null 2>&1; then
|
||
sudo nixos-rebuild-snap "$@" # BTRFS snapshot first
|
||
else
|
||
sudo nixos-rebuild switch --flake "$flake#default" "$@"
|
||
fi
|
||
'')
|
||
(pkgs.writeShellScriptBin "home-update" ''
|
||
set -e
|
||
exec home-manager switch --flake "''${NOMARCHY_PATH:-$HOME/.nomarchy}" "$@"
|
||
'')
|
||
|
||
git
|
||
vim
|
||
wget
|
||
curl
|
||
jq
|
||
brightnessctl
|
||
playerctl
|
||
pamixer
|
||
wl-clipboard
|
||
grim
|
||
slurp
|
||
] ++ lib.optional (cfg.snapper.enable && (config.fileSystems."/".fsType or "") == "btrfs")
|
||
# Snapshot, then rebuild — rollback material for system changes
|
||
# (theme changes don't need it; HM generations already roll back).
|
||
(pkgs.writeShellScriptBin "nixos-rebuild-snap" ''
|
||
if [ "$(id -u)" -ne 0 ]; then
|
||
echo "This script must be run as root (use sudo)" >&2
|
||
exit 1
|
||
fi
|
||
echo "Creating pre-rebuild snapshot..."
|
||
${pkgs.snapper}/bin/snapper -c root create \
|
||
-d "Pre-rebuild $(date +'%Y-%m-%d %H:%M:%S')" \
|
||
--cleanup-algorithm number
|
||
echo "Rebuilding..."
|
||
nixos-rebuild switch --flake /etc/nixos#default "$@"
|
||
'');
|
||
|
||
# Don't let boot entries fill the ESP over the years.
|
||
boot.loader.systemd-boot.configurationLimit = lib.mkDefault 10;
|
||
|
||
# Backlight udev rule (chgrp video + g+w on /sys/class/backlight) so
|
||
# the desktop's swayosd brightness control works for video-group
|
||
# users without root. Harmless baseline even if the OSD is disabled.
|
||
services.udev.packages = [ pkgs.swayosd ];
|
||
|
||
# ── Nix itself ───────────────────────────────────────────────────
|
||
nix = {
|
||
settings = {
|
||
experimental-features = [ "nix-command" "flakes" ];
|
||
auto-optimise-store = lib.mkDefault true;
|
||
};
|
||
gc = {
|
||
automatic = lib.mkDefault true;
|
||
dates = lib.mkDefault "weekly";
|
||
options = lib.mkDefault "--delete-older-than 14d";
|
||
};
|
||
};
|
||
};
|
||
}
|