1
0
mirror of https://github.com/nix-community/home-manager synced 2024-06-30 10:28:31 +02:00
home-manager/modules/services/window-managers/hyprland.nix
Nara Díaz Viñolas defbb9c585
hyprland: add option sourceFirst
Add the option sourceFirst to the hyprland module. When this option is
enabled source entries will be put near the top of the file, so that
the variables declared in other files can be used by the other
configuration entries.

Add "source" to the list of important prefixes when the former option
is enabled.

Resolves #4729
2023-12-10 11:12:06 +01:00

274 lines
8.7 KiB
Nix

{ config, lib, pkgs, ... }:
let
cfg = config.wayland.windowManager.hyprland;
variables = builtins.concatStringsSep " " cfg.systemd.variables;
extraCommands = builtins.concatStringsSep " "
(map (f: "&& ${f}") cfg.systemd.extraCommands);
systemdActivation = ''
exec-once = ${pkgs.dbus}/bin/dbus-update-activation-environment --systemd ${variables} ${extraCommands}
'';
in {
meta.maintainers = [ lib.maintainers.fufexan ];
# A few option removals and renames to aid those migrating from the upstream
# module.
imports = [
(lib.mkRemovedOptionModule # \
[ "wayland" "windowManager" "hyprland" "disableAutoreload" ]
"Autoreloading now always happens")
(lib.mkRemovedOptionModule # \
[ "wayland" "windowManager" "hyprland" "recommendedEnvironment" ]
"Recommended environment variables are now always set")
(lib.mkRemovedOptionModule # \
[ "wayland" "windowManager" "hyprland" "xwayland" "hidpi" ]
"HiDPI patches are deprecated. Refer to https://wiki.hyprland.org/Configuring/XWayland")
(lib.mkRenamedOptionModule # \
[ "wayland" "windowManager" "hyprland" "nvidiaPatches" ] # \
[ "wayland" "windowManager" "hyprland" "enableNvidiaPatches" ])
(lib.mkRenamedOptionModule # \
[ "wayland" "windowManager" "hyprland" "systemdIntegration" ] # \
[ "wayland" "windowManager" "hyprland" "systemd" "enable" ])
];
options.wayland.windowManager.hyprland = {
enable = lib.mkEnableOption "Hyprland wayland compositor";
package = lib.mkPackageOption pkgs "hyprland" { };
finalPackage = lib.mkOption {
type = lib.types.package;
readOnly = true;
default = cfg.package.override {
enableXWayland = cfg.xwayland.enable;
enableNvidiaPatches = cfg.enableNvidiaPatches;
};
defaultText = lib.literalMD
"`wayland.windowManager.hyprland.package` with applied configuration";
description = ''
The Hyprland package after applying configuration.
'';
};
plugins = lib.mkOption {
type = with lib.types; listOf (either package path);
default = [ ];
description = ''
List of Hyprland plugins to use. Can either be packages or
absolute plugin paths.
'';
};
systemd = {
enable = lib.mkEnableOption null // {
default = true;
description = ''
Whether to enable {file}`hyprland-session.target` on
hyprland startup. This links to `graphical-session.target`.
Some important environment variables will be imported to systemd
and D-Bus user environment before reaching the target, including
- `DISPLAY`
- `HYPRLAND_INSTANCE_SIGNATURE`
- `WAYLAND_DISPLAY`
- `XDG_CURRENT_DESKTOP`
'';
};
variables = lib.mkOption {
type = with lib.types; listOf str;
default = [
"DISPLAY"
"HYPRLAND_INSTANCE_SIGNATURE"
"WAYLAND_DISPLAY"
"XDG_CURRENT_DESKTOP"
];
example = [ "-all" ];
description = ''
Environment variables to be imported in the systemd & D-Bus user
environment.
'';
};
extraCommands = lib.mkOption {
type = with lib.types; listOf str;
default = [
"systemctl --user stop hyprland-session.target"
"systemctl --user start hyprland-session.target"
];
description = "Extra commands to be run after D-Bus activation.";
};
};
xwayland.enable = lib.mkEnableOption "XWayland" // { default = true; };
enableNvidiaPatches =
lib.mkEnableOption "patching wlroots for better Nvidia support";
settings = lib.mkOption {
type = with lib.types;
let
valueType = nullOr (oneOf [
bool
int
float
str
path
(attrsOf valueType)
(listOf valueType)
]) // {
description = "Hyprland configuration value";
};
in valueType;
default = { };
description = ''
Hyprland configuration written in Nix. Entries with the same key
should be written as lists. Variables' and colors' names should be
quoted. See <https://wiki.hyprland.org> for more examples.
::: {.note}
Use the [](#opt-wayland.windowManager.hyprland.plugins) option to
declare plugins.
:::
'';
example = lib.literalExpression ''
{
decoration = {
shadow_offset = "0 5";
"col.shadow" = "rgba(00000099)";
};
"$mod" = "SUPER";
bindm = [
# mouse movements
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
"$mod ALT, mouse:272, resizewindow"
];
}
'';
};
extraConfig = lib.mkOption {
type = lib.types.lines;
default = "";
example = ''
# window resize
bind = $mod, S, submap, resize
submap = resize
binde = , right, resizeactive, 10 0
binde = , left, resizeactive, -10 0
binde = , up, resizeactive, 0 -10
binde = , down, resizeactive, 0 10
bind = , escape, submap, reset
submap = reset
'';
description = ''
Extra configuration lines to add to `~/.config/hypr/hyprland.conf`.
'';
};
sourceFirst = lib.mkEnableOption ''
putting source entries at the top of the configuration
'' // {
default = true;
};
};
config = lib.mkIf cfg.enable {
assertions = [
(lib.hm.assertions.assertPlatform "wayland.windowManager.hyprland" pkgs
lib.platforms.linux)
];
warnings = let
inconsistent = (cfg.systemd.enable || cfg.plugins != [ ])
&& cfg.extraConfig == "" && cfg.settings == { };
warning =
"You have enabled hyprland.systemd.enable or listed plugins in hyprland.plugins but do not have any configuration in hyprland.settings or hyprland.extraConfig. This is almost certainly a mistake.";
in lib.optional inconsistent warning;
home.packages = lib.optional (cfg.package != null) cfg.finalPackage;
xdg.configFile."hypr/hyprland.conf" = let
combinedSettings = cfg.settings // {
plugin = let
mkEntry = entry:
if lib.types.package.check entry then
"${entry}/lib/lib${entry.pname}.so"
else
entry;
in map mkEntry cfg.plugins;
};
shouldGenerate = cfg.systemd.enable || cfg.extraConfig != ""
|| combinedSettings != { };
toHyprconf = with lib;
attrs: indentLevel:
let
indent = concatStrings (replicate indentLevel " ");
mkSection = n: attrs: ''
${indent}${n} {
${toHyprconf attrs (indentLevel + 1)}${indent}}
'';
sections = filterAttrs (n: v: isAttrs v) attrs;
mkFields = generators.toKeyValue {
listsAsDuplicateKeys = true;
inherit indent;
};
allFields = filterAttrs (n: v: !(isAttrs v)) attrs;
importantFields = filterAttrs (n: _:
(hasPrefix "$" n) || (hasPrefix "bezier" n)
|| (cfg.sourceFirst && (hasPrefix "source" n))) allFields;
fields = builtins.removeAttrs allFields
(mapAttrsToList (n: _: n) importantFields);
in mkFields importantFields
+ concatStringsSep "\n" (mapAttrsToList mkSection sections)
+ mkFields fields;
in lib.mkIf shouldGenerate {
text = lib.optionalString cfg.systemd.enable systemdActivation
+ lib.optionalString (combinedSettings != { })
(toHyprconf combinedSettings 0)
+ lib.optionalString (cfg.extraConfig != "") cfg.extraConfig;
onChange = lib.mkIf (cfg.package != null) ''
( # 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##*/} ${cfg.finalPackage}/bin/hyprctl reload config-only \
|| true # ignore dead instance(s)
done
)
'';
};
systemd.user.targets.hyprland-session = lib.mkIf cfg.systemd.enable {
Unit = {
Description = "Hyprland compositor session";
Documentation = [ "man:systemd.special(7)" ];
BindsTo = [ "graphical-session.target" ];
Wants = [ "graphical-session-pre.target" ];
After = [ "graphical-session-pre.target" ];
};
};
systemd.user.targets.tray = {
Unit = {
Description = "Home Manager System Tray";
Requires = [ "graphical-session-pre.target" ];
};
};
};
}