atagen

headroom

public
Star0
Watch0
872b0bdcf4abfb7519411a52946efe6a02cf4bc4
1
ssh://brewery@pls.lobotomise.me:33/atagen/headroom.git
nix/nixos-module.nixNix107 lines3.8 KB
1
# NixOS module — system-wide install. headroom is a user-scope daemon
2
# (talks to the user's pipewire session), so this module just:
3
#   1. binary on every login's PATH
4
#   2. systemd user unit in the system-wide location (`systemctl --user enable --now headroom`)
5
#   3. bundled profiles into the system profile's share/ (daemon finds via $XDG_DATA_DIRS)
6
#   4. assert pipewire+wireplumber are enabled
7
self:
8
{
9
  config,
10
  lib,
11
  pkgs,
12
  ...
13
}:
14
15
let
16
  inherit (lib)
17
    mkEnableOption
18
    mkOption
19
    mkIf
20
    types
21
    literalExpression
22
    ;
23
24
  cfg = config.programs.headroom;
25
in
26
{
27
  options.programs.headroom = {
28
    enable = mkEnableOption "Headroom — automatic loudness and per-app volume control (pipewire)";
29
30
    package = mkOption {
31
      type = types.package;
32
      default = self.packages.${pkgs.stdenv.hostPlatform.system}.headroom;
33
      defaultText = literalExpression "headroom.packages.\${pkgs.system}.headroom";
34
      description = ''
35
        The headroom package to install system-wide.
36
      '';
37
    };
38
39
    gui = {
40
      enable = mkEnableOption "the Headroom GUI (iced monitor + control) and its application-launcher entry";
41
42
      package = mkOption {
43
        type = types.package;
44
        default = self.packages.${pkgs.stdenv.hostPlatform.system}.headroom-gui;
45
        defaultText = literalExpression "headroom.packages.\${pkgs.system}.headroom-gui";
46
        description = ''
47
          headroom-gui package installed when `programs.headroom.gui.enable`
48
          is set. ships the `headroom-gui` binary + `.desktop` entry, so it
49
          appears in application launchers automatically.
50
        '';
51
      };
52
    };
53
54
    autoStart = mkOption {
55
      type = types.bool;
56
      default = true;
57
      description = ''
58
        pull the headroom user service into every login's
59
        `default.target` so it autostarts without `systemctl
60
        --user enable headroom`.
61
62
        `systemd.packages` installs the unit but doesn't process its
63
        `[Install]` section, so the `default.target.wants`
64
        symlink is never created (unit sits `linked-runtime`). this
65
        materialises that symlink at the system level. false = unit
66
        install-only, manage activation yourself.
67
      '';
68
    };
69
  };
70
71
  config = mkIf cfg.enable {
72
    # binary on PATH; gui package too when enabled (drops a
73
    # share/applications/.desktop entry NixOS aggregates into the menu)
74
    environment.systemPackages = [ cfg.package ] ++ lib.optional cfg.gui.enable cfg.gui.package;
75
76
    # make the user unit discoverable by `systemctl --user`; materialises
77
    # /etc/systemd/user/headroom.service → package's lib/systemd/user/headroom.service
78
    systemd.packages = [ cfg.package ];
79
80
    # systemd.packages doesn't process [Install] → add a `wantedBy` so NixOS
81
    # emits the default.target.wants symlink. unit body comes from the
82
    # package, so we must NOT author headroom.service here (duplicate-unit error);
83
    # overrideStrategy="asDropin" makes this a drop-in (empty bar the wants link).
84
    # not via environment.etc: /etc/systemd/user is a read-only store symlink.
85
    systemd.user.services.headroom = mkIf cfg.autoStart {
86
      overrideStrategy = "asDropin";
87
      wantedBy = [ "default.target" ];
88
    };
89
90
    # daemon scans each $XDG_DATA_DIRS entry's headroom/profiles/. NixOS only
91
    # links an allowlist of share/ subdirs into the system profile
92
    # (environment.pathsToLink), so opt share/headroom in or the shipped
93
    # profiles get dropped and the daemon sees only the built-in `default`.
94
    environment.pathsToLink = [ "/share/headroom" ];
95
96
    # fail eval (not a confusing runtime error) if headroom is on but pipewire isn't
97
    assertions = [
98
      {
99
        assertion = config.services.pipewire.enable;
100
        message = ''
101
          programs.headroom.enable requires services.pipewire.enable = true;
102
          headroom is a PipeWire-only daemon.
103
        '';
104
      }
105
    ];
106
  };
107
}