aboutsummaryrefslogtreecommitdiffhomepage
path: root/nix/hm-module.nix
blob: 505ce9009ba91ffb545be1a6d7f62331f34200c7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
self: {
  config,
  lib,
  pkgs,
  ...
}: let
  cfg = config.wayland.windowManager.hyprland;
  defaultHyprlandPackage = self.packages.${pkgs.stdenv.hostPlatform.system}.default.override {
    enableXWayland = cfg.xwayland.enable;
    hidpiXWayland = cfg.xwayland.hidpi;
    inherit (cfg) nvidiaPatches;
  };
in {
  meta.maintainers = [lib.maintainers.fufexan];

  options.wayland.windowManager.hyprland = {
    enable =
      lib.mkEnableOption null
      // {
        description = lib.mdDoc ''
          Whether to enable Hyprland, the dynamic tiling Wayland compositor
          that doesn't sacrifice on its looks.

          You can manually launch Hyprland by executing {command}`Hyprland` on
          a TTY.

          See <https://wiki.hyprland.org> for more information.
        '';
      };

    package = lib.mkOption {
      type = with lib.types; nullOr package;
      default = defaultHyprlandPackage;
      defaultText = lib.literalExpression ''
        hyprland.packages.''${pkgs.stdenv.hostPlatform.system}.default.override {
          enableXWayland = config.wayland.windowManager.hyprland.xwayland.enable;
          hidpiXWayland = config.wayland.windowManager.hyprland.xwayland.hidpi;
          inherit (config.wayland.windowManager.hyprland) nvidiaPatches;
        }
      '';
      description = lib.mdDoc ''
        Hyprland package to use. Will override the 'xwayland' and
        'nvidiaPatches' options.

        Defaults to the one provided by the flake. Set it to
        {package}`pkgs.hyprland` to use the one provided by nixpkgs or
        if you have an overlay.

        Set to null to not add any Hyprland package to your path. This should
        be done if you want to use the NixOS module to install Hyprland.
      '';
    };

    plugins = lib.mkOption {
      type = with lib.types; listOf (either package path);
      default = [];
      description = lib.mdDoc ''
        List of Hyprland plugins to use. Can either be packages or
        absolute plugin paths.
      '';
    };

    systemdIntegration = lib.mkOption {
      type = lib.types.bool;
      default = pkgs.stdenv.isLinux;
      description = lib.mdDoc ''
        Whether to enable {file}`hyprland-session.target` on
        Hyprland startup. This links to {file}`graphical-session.target`.
        Some important environment variables will be imported to systemd
        and dbus user environment before reaching the target, including
        - {env}`DISPLAY`
        - {env}`HYPRLAND_INSTANCE_SIGNATURE`
        - {env}`WAYLAND_DISPLAY`
        - {env}`XDG_CURRENT_DESKTOP`
      '';
    };

    disableAutoreload =
      lib.mkEnableOption null
      // {
        description = lib.mdDoc ''
          Whether to disable automatically reloading Hyprland's configuration when
          rebuilding the Home Manager profile.
        '';
      };

    xwayland = {
      enable = lib.mkEnableOption (lib.mdDoc "XWayland") // {default = true;};
      hidpi =
        lib.mkEnableOption null
        // {
          description = lib.mdDoc ''
            Enable HiDPI XWayland, based on [XWayland MR 733](https://gitlab.freedesktop.org/xorg/xserver/-/merge_requests/733).
            See <https://wiki.hyprland.org/Nix/Options-Overrides/#xwayland-hidpi> for more info.
          '';
        };
    };

    nvidiaPatches = lib.mkEnableOption (lib.mdDoc "patching wlroots for better Nvidia support.");

    extraConfig = lib.mkOption {
      type = lib.types.nullOr lib.types.lines;
      default = "";
      description = lib.mdDoc ''
        Extra configuration lines to add to {file}`~/.config/hypr/hyprland.conf`.
      '';
    };

    recommendedEnvironment =
      lib.mkEnableOption null
      // {
        description = lib.mdDoc ''
          Whether to set the recommended environment variables.
        '';
      };
  };

  config = lib.mkIf cfg.enable {
    warnings =
      if (cfg.systemdIntegration || cfg.plugins != []) && cfg.extraConfig == null then
        [ ''You have enabled hyprland.systemdIntegration or listed plugins in hyprland.plugins.
            Your Hyprland config will be linked by home manager.
            Set hyprland.extraConfig or unset hyprland.systemdIntegration and hyprland.plugins to remove this warning.'' ]
      else [];

    home.packages =
      lib.optional (cfg.package != null) cfg.package
      ++ lib.optional cfg.xwayland.enable pkgs.xwayland;

    home.sessionVariables =
      lib.mkIf cfg.recommendedEnvironment {NIXOS_OZONE_WL = "1";};

    xdg.configFile."hypr/hyprland.conf" = lib.mkIf (cfg.systemdIntegration || cfg.extraConfig != null || cfg.plugins != []) {
      text =
        (lib.optionalString cfg.systemdIntegration ''
          exec-once=${pkgs.dbus}/bin/dbus-update-activation-environment --systemd DISPLAY WAYLAND_DISPLAY HYPRLAND_INSTANCE_SIGNATURE XDG_CURRENT_DESKTOP && systemctl --user start hyprland-session.target
        '')
        + lib.concatStrings (builtins.map (entry: let
            plugin = if lib.types.package.check entry then "${entry}/lib/lib${entry.pname}.so" else entry;
          in "plugin = ${plugin}\n") cfg.plugins)
        + (if cfg.extraConfig != null then cfg.extraConfig else "");

      onChange = let
        hyprlandPackage =
          if cfg.package == null
          then defaultHyprlandPackage
          else cfg.package;
      in
        lib.mkIf (!cfg.disableAutoreload) ''
          (  # execute in subshell so that `shopt` won't affect other scripts
            shopt -s nullglob  # so that nothing is done if /tmp/hypr/ does not exist or is empty
            for instance in /tmp/hypr/*; do
              HYPRLAND_INSTANCE_SIGNATURE=''${instance##*/} ${hyprlandPackage}/bin/hyprctl reload config-only \
                || true  # ignore dead instance(s)
            done
          )
        '';
    };

    systemd.user.targets.hyprland-session = lib.mkIf cfg.systemdIntegration {
      Unit = {
        Description = "Hyprland compositor session";
        Documentation = ["man:systemd.special(7)"];
        BindsTo = ["graphical-session.target"];
        Wants = ["graphical-session-pre.target"];
        After = ["graphical-session-pre.target"];
      };
    };
  };
}