atagen

headroom

public
Star0
Watch0
872b0bdcf4abfb7519411a52946efe6a02cf4bc4
1
ssh://brewery@pls.lobotomise.me:33/atagen/headroom.git

Blame: nix/nixos-module.nix

c454b1085466atagen2026-05-27 15:49 UTC1
# NixOS module — system-wide install. headroom is a user-scope daemon
c454b1085466atagen2026-05-27 15:49 UTC2
# (talks to the user's pipewire session), so this module just:
c454b1085466atagen2026-05-27 15:49 UTC3
#   1. binary on every login's PATH
c454b1085466atagen2026-05-27 15:49 UTC4
#   2. systemd user unit in the system-wide location (`systemctl --user enable --now headroom`)
c454b1085466atagen2026-05-27 15:49 UTC5
#   3. bundled profiles into the system profile's share/ (daemon finds via $XDG_DATA_DIRS)
c454b1085466atagen2026-05-27 15:49 UTC6
#   4. assert pipewire+wireplumber are enabled
c454b1085466atagen2026-05-27 15:49 UTC7
self:
c454b1085466atagen2026-05-27 15:49 UTC8
{
c454b1085466atagen2026-05-27 15:49 UTC9
  config,
c454b1085466atagen2026-05-27 15:49 UTC10
  lib,
c454b1085466atagen2026-05-27 15:49 UTC11
  pkgs,
c454b1085466atagen2026-05-27 15:49 UTC12
  ...
c454b1085466atagen2026-05-27 15:49 UTC13
}:
c454b1085466atagen2026-05-27 15:49 UTC14
c454b1085466atagen2026-05-27 15:49 UTC15
let
c454b1085466atagen2026-05-27 15:49 UTC16
  inherit (lib)
c454b1085466atagen2026-05-27 15:49 UTC17
    mkEnableOption
c454b1085466atagen2026-05-27 15:49 UTC18
    mkOption
c454b1085466atagen2026-05-27 15:49 UTC19
    mkIf
c454b1085466atagen2026-05-27 15:49 UTC20
    types
c454b1085466atagen2026-05-27 15:49 UTC21
    literalExpression
c454b1085466atagen2026-05-27 15:49 UTC22
    ;
c454b1085466atagen2026-05-27 15:49 UTC23
c454b1085466atagen2026-05-27 15:49 UTC24
  cfg = config.programs.headroom;
c454b1085466atagen2026-05-27 15:49 UTC25
in
c454b1085466atagen2026-05-27 15:49 UTC26
{
c454b1085466atagen2026-05-27 15:49 UTC27
  options.programs.headroom = {
c454b1085466atagen2026-05-27 15:49 UTC28
    enable = mkEnableOption "Headroom — automatic loudness and per-app volume control (pipewire)";
c454b1085466atagen2026-05-27 15:49 UTC29
c454b1085466atagen2026-05-27 15:49 UTC30
    package = mkOption {
c454b1085466atagen2026-05-27 15:49 UTC31
      type = types.package;
c454b1085466atagen2026-05-27 15:49 UTC32
      default = self.packages.${pkgs.stdenv.hostPlatform.system}.headroom;
c454b1085466atagen2026-05-27 15:49 UTC33
      defaultText = literalExpression "headroom.packages.\${pkgs.system}.headroom";
c454b1085466atagen2026-05-27 15:49 UTC34
      description = ''
c454b1085466atagen2026-05-27 15:49 UTC35
        The headroom package to install system-wide.
c454b1085466atagen2026-05-27 15:49 UTC36
      '';
c454b1085466atagen2026-05-27 15:49 UTC37
    };
c454b1085466atagen2026-05-27 15:49 UTC38
c454b1085466atagen2026-05-27 15:49 UTC39
    gui = {
c454b1085466atagen2026-05-27 15:49 UTC40
      enable = mkEnableOption "the Headroom GUI (iced monitor + control) and its application-launcher entry";
c454b1085466atagen2026-05-27 15:49 UTC41
c454b1085466atagen2026-05-27 15:49 UTC42
      package = mkOption {
c454b1085466atagen2026-05-27 15:49 UTC43
        type = types.package;
c454b1085466atagen2026-05-27 15:49 UTC44
        default = self.packages.${pkgs.stdenv.hostPlatform.system}.headroom-gui;
c454b1085466atagen2026-05-27 15:49 UTC45
        defaultText = literalExpression "headroom.packages.\${pkgs.system}.headroom-gui";
c454b1085466atagen2026-05-27 15:49 UTC46
        description = ''
c454b1085466atagen2026-05-27 15:49 UTC47
          headroom-gui package installed when `programs.headroom.gui.enable`
c454b1085466atagen2026-05-27 15:49 UTC48
          is set. ships the `headroom-gui` binary + `.desktop` entry, so it
c454b1085466atagen2026-05-27 15:49 UTC49
          appears in application launchers automatically.
c454b1085466atagen2026-05-27 15:49 UTC50
        '';
c454b1085466atagen2026-05-27 15:49 UTC51
      };
c454b1085466atagen2026-05-27 15:49 UTC52
    };
c454b1085466atagen2026-05-27 15:49 UTC53
c454b1085466atagen2026-05-27 15:49 UTC54
    autoStart = mkOption {
c454b1085466atagen2026-05-27 15:49 UTC55
      type = types.bool;
c454b1085466atagen2026-05-27 15:49 UTC56
      default = true;
c454b1085466atagen2026-05-27 15:49 UTC57
      description = ''
c454b1085466atagen2026-05-27 15:49 UTC58
        pull the headroom user service into every login's
c454b1085466atagen2026-05-27 15:49 UTC59
        `default.target` so it autostarts without `systemctl
c454b1085466atagen2026-05-27 15:49 UTC60
        --user enable headroom`.
c454b1085466atagen2026-05-27 15:49 UTC61
c454b1085466atagen2026-05-27 15:49 UTC62
        `systemd.packages` installs the unit but doesn't process its
c454b1085466atagen2026-05-27 15:49 UTC63
        `[Install]` section, so the `default.target.wants`
c454b1085466atagen2026-05-27 15:49 UTC64
        symlink is never created (unit sits `linked-runtime`). this
c454b1085466atagen2026-05-27 15:49 UTC65
        materialises that symlink at the system level. false = unit
c454b1085466atagen2026-05-27 15:49 UTC66
        install-only, manage activation yourself.
c454b1085466atagen2026-05-27 15:49 UTC67
      '';
c454b1085466atagen2026-05-27 15:49 UTC68
    };
c454b1085466atagen2026-05-27 15:49 UTC69
  };
c454b1085466atagen2026-05-27 15:49 UTC70
c454b1085466atagen2026-05-27 15:49 UTC71
  config = mkIf cfg.enable {
c454b1085466atagen2026-05-27 15:49 UTC72
    # binary on PATH; gui package too when enabled (drops a
c454b1085466atagen2026-05-27 15:49 UTC73
    # share/applications/.desktop entry NixOS aggregates into the menu)
c454b1085466atagen2026-05-27 15:49 UTC74
    environment.systemPackages = [ cfg.package ] ++ lib.optional cfg.gui.enable cfg.gui.package;
c454b1085466atagen2026-05-27 15:49 UTC75
c454b1085466atagen2026-05-27 15:49 UTC76
    # make the user unit discoverable by `systemctl --user`; materialises
c454b1085466atagen2026-05-27 15:49 UTC77
    # /etc/systemd/user/headroom.service → package's lib/systemd/user/headroom.service
c454b1085466atagen2026-05-27 15:49 UTC78
    systemd.packages = [ cfg.package ];
c454b1085466atagen2026-05-27 15:49 UTC79
c454b1085466atagen2026-05-27 15:49 UTC80
    # systemd.packages doesn't process [Install] → add a `wantedBy` so NixOS
c454b1085466atagen2026-05-27 15:49 UTC81
    # emits the default.target.wants symlink. unit body comes from the
c454b1085466atagen2026-05-27 15:49 UTC82
    # package, so we must NOT author headroom.service here (duplicate-unit error);
c454b1085466atagen2026-05-27 15:49 UTC83
    # overrideStrategy="asDropin" makes this a drop-in (empty bar the wants link).
c454b1085466atagen2026-05-27 15:49 UTC84
    # not via environment.etc: /etc/systemd/user is a read-only store symlink.
c454b1085466atagen2026-05-27 15:49 UTC85
    systemd.user.services.headroom = mkIf cfg.autoStart {
c454b1085466atagen2026-05-27 15:49 UTC86
      overrideStrategy = "asDropin";
c454b1085466atagen2026-05-27 15:49 UTC87
      wantedBy = [ "default.target" ];
c454b1085466atagen2026-05-27 15:49 UTC88
    };
c454b1085466atagen2026-05-27 15:49 UTC89
c454b1085466atagen2026-05-27 15:49 UTC90
    # daemon scans each $XDG_DATA_DIRS entry's headroom/profiles/. NixOS only
c454b1085466atagen2026-05-27 15:49 UTC91
    # links an allowlist of share/ subdirs into the system profile
c454b1085466atagen2026-05-27 15:49 UTC92
    # (environment.pathsToLink), so opt share/headroom in or the shipped
c454b1085466atagen2026-05-27 15:49 UTC93
    # profiles get dropped and the daemon sees only the built-in `default`.
c454b1085466atagen2026-05-27 15:49 UTC94
    environment.pathsToLink = [ "/share/headroom" ];
c454b1085466atagen2026-05-27 15:49 UTC95
c454b1085466atagen2026-05-27 15:49 UTC96
    # fail eval (not a confusing runtime error) if headroom is on but pipewire isn't
c454b1085466atagen2026-05-27 15:49 UTC97
    assertions = [
c454b1085466atagen2026-05-27 15:49 UTC98
      {
c454b1085466atagen2026-05-27 15:49 UTC99
        assertion = config.services.pipewire.enable;
c454b1085466atagen2026-05-27 15:49 UTC100
        message = ''
c454b1085466atagen2026-05-27 15:49 UTC101
          programs.headroom.enable requires services.pipewire.enable = true;
c454b1085466atagen2026-05-27 15:49 UTC102
          headroom is a PipeWire-only daemon.
c454b1085466atagen2026-05-27 15:49 UTC103
        '';
c454b1085466atagen2026-05-27 15:49 UTC104
      }
c454b1085466atagen2026-05-27 15:49 UTC105
    ];
c454b1085466atagen2026-05-27 15:49 UTC106
  };
c454b1085466atagen2026-05-27 15:49 UTC107
}