From cc77467709f537339d26d881f57f18cfcf88a9b7 Mon Sep 17 00:00:00 2001 From: Christoph Urlacher Date: Tue, 22 Jul 2025 13:21:14 +0200 Subject: [PATCH] Modules/Hyprland: Use hyprland flake instead of nixpkgs and split config into multiple files --- flake.nix | 24 +-- home/modules/hyprland/autostart.nix | 29 +++ home/modules/hyprland/default.nix | 270 ++-------------------------- home/modules/hyprland/dunst.nix | 36 ++++ home/modules/hyprland/hypridle.nix | 28 +++ home/modules/hyprland/hyprlock.nix | 74 ++++++++ home/modules/hyprland/hyprpaper.nix | 28 +++ home/modules/hyprland/mappings.nix | 81 +++++++++ 8 files changed, 304 insertions(+), 266 deletions(-) create mode 100644 home/modules/hyprland/autostart.nix create mode 100644 home/modules/hyprland/dunst.nix create mode 100644 home/modules/hyprland/hypridle.nix create mode 100644 home/modules/hyprland/hyprlock.nix create mode 100644 home/modules/hyprland/hyprpaper.nix create mode 100644 home/modules/hyprland/mappings.nix diff --git a/flake.nix b/flake.nix index 55019a1e..7248886e 100644 --- a/flake.nix +++ b/flake.nix @@ -32,10 +32,6 @@ nur.url = "github:nix-community/NUR"; nur.inputs.nixpkgs.follows = "nixpkgs"; - # Firefox theme - textfox.url = "github:adriankarlen/textfox"; - textfox.inputs.nixpkgs.follows = "nixpkgs"; - # Nix Package Search - nps nps.url = "github:OleMussmann/nps"; nps.inputs.nixpkgs.follows = "nixpkgs"; @@ -44,6 +40,16 @@ nix-alien.url = "github:thiagokokada/nix-alien"; nix-alien.inputs.nixpkgs.follows = "nixpkgs"; + # Hyprland (use flake so plugins are not built from source) + hyprland.url = "github:hyprwm/Hyprland"; + hyprland.inputs.nixpkgs.follows = "nixpkgs"; + + # HyprPlugins + hyprland-plugins.url = "github:hyprwm/hyprland-plugins"; + hyprland-plugins.inputs.nixpkgs.follows = "nixpkgs"; + hypr-dynamic-cursors.url = "github:VirtCode/hypr-dynamic-cursors"; + hypr-dynamic-cursors.inputs.nixpkgs.follows = "nixpkgs"; + # NeoVim <3 nixvim.url = "github:nix-community/nixvim"; nixvim.inputs.nixpkgs.follows = "nixpkgs"; @@ -52,6 +58,10 @@ # emacs-overlay.url = "github:nix-community/emacs-overlay"; # emacs-overlay.inputs.nixpkgs.follows = "nixpkgs"; + # Firefox theme + textfox.url = "github:adriankarlen/textfox"; + textfox.inputs.nixpkgs.follows = "nixpkgs"; + # Declarative Flatpak nix-flatpak.url = "github:gmodena/nix-flatpak/?ref=latest"; # nix-flatpak.inputs.nixpkgs.follows = "nixpkgs"; # nix-flatpak doesn't have this @@ -60,12 +70,6 @@ # musnix.url = "github:musnix/musnix"; # musnix.inputs.nixpkgs.follows = "nixpkgs"; - # HyprPlugins - # hyprland-plugins.url = "github:hyprwm/hyprland-plugins"; - # hyprland-plugins.inputs.nixpkgs.follows = "nixpkgs"; - # hypr-dynamic-cursors.url = "github:VirtCode/hypr-dynamic-cursors"; - # hypr-dynamic-cursors.inputs.nixpkgs.follows = "nixpkgs"; - # Pinned versions # v4l2loopback-pinned.url = "github:nixos/nixpkgs/4684fd6b0c01e4b7d99027a34c93c2e09ecafee2"; # unityhub-pinned.url = "github:huantianad/nixpkgs/9542b0bc7701e173a10e6977e57bbba68bb3051f"; diff --git a/home/modules/hyprland/autostart.nix b/home/modules/hyprland/autostart.nix new file mode 100644 index 00000000..ccca0635 --- /dev/null +++ b/home/modules/hyprland/autostart.nix @@ -0,0 +1,29 @@ +{ + lib, + pkgs, + config, + hyprland, +}: +builtins.concatLists [ + (lib.optionals hyprland.dunst.enable ["dunst"]) # Notifications + [ + # Start clipboard management + "wl-paste -t text --watch clipman store --no-persist" + "wl-paste -p -t text --watch clipman store -P --histpath=\"~/.local/share/clipman-primary.json\"" + + "hyprctl setcursor Bibata-Modern-Classic 16" + "hyprsunset --identity" + + # HACK: Hyprland doesn't set the xwayland/x11 keymap correctly + "setxkbmap -layout ${hyprland.keyboard.layout} -variant ${hyprland.keyboard.variant} -option ${hyprland.keyboard.option} -model pc104" + + # HACK: Flatpak doesn't find applications in the system PATH + "systemctl --user import-environment PATH && systemctl --user restart xdg-desktop-portal.service" + + # Provide a polkit authentication UI. + # This is used for example when running systemd commands without root. + # "systemctl --user start hyprpolkitagent.service" + # "${pkgs.kdePackages.polkit-kde-agent-1}/libexec/polkit-kde-authentication-agent-1" + "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1" + ] +] diff --git a/home/modules/hyprland/default.nix b/home/modules/hyprland/default.nix index 2ea6b0d9..4e809b1f 100644 --- a/home/modules/hyprland/default.nix +++ b/home/modules/hyprland/default.nix @@ -10,110 +10,14 @@ }: let inherit (config.modules) hyprland color; - always-bind = lib.mergeAttrsList [ - { - # Hyprland control - "$mainMod, a" = ["exec, rofi -drun-show-actions -show drun"]; - "$mainMod, q" = ["killactive"]; - "$mainMod, v" = ["togglefloating"]; - "$mainMod, f" = ["fullscreen"]; - "$mainMod, c" = ["exec, clipman pick --tool=rofi"]; - "$mainMod SHIFT, l" = ["exec, loginctl lock-session"]; - "$mainMod, tab" = ["workspace, previous"]; - "ALT, tab" = ["exec, rofi -show window"]; - # "$mainMod, g" = ["togglegroup"]; - # "ALT, tab" = ["changegroupactive"]; - - # Move focus with mainMod + arrow keys - "$mainMod, h" = ["movefocus, l"]; - "$mainMod, l" = ["movefocus, r"]; - "$mainMod, k" = ["movefocus, u"]; - "$mainMod, j" = ["movefocus, d"]; - - # Swap windows - "$mainMod CTRL, h" = ["movewindow, l"]; - "$mainMod CTRL, l" = ["movewindow, r"]; - "$mainMod CTRL, k" = ["movewindow, u"]; - "$mainMod CTRL, d" = ["movewindow, d"]; - - # Reset workspaces to the defined configuration in hyprland.workspaces: - "CTRL ALT, r" = let - mkWBinding = m: w: - "moveworkspacetomonitor, " - + "${builtins.toString w} ${builtins.toString m}"; - mkWsBindings = m: ws: builtins.map (mkWBinding m) ws; - in - hyprland.workspaces - |> builtins.mapAttrs mkWsBindings - |> builtins.attrValues - |> builtins.concatLists; - } - - # Switch to WS: "$mainMod, 1" = ["workspace, 1"]; - (let - mkWBinding = w: k: {"$mainMod, ${k}" = ["workspace, ${w}"];}; - in - hyprland.keybindings.ws-bindings - |> builtins.mapAttrs mkWBinding - |> builtins.attrValues - |> lib.mergeAttrsList) - - # Toggle special WS: "$mainMod, x" = ["togglespecialworkspace, ferdium"]; - (let - mkSpecialWBinding = w: k: {"$mainMod, ${k}" = ["togglespecialworkspace, ${w}"];}; - in - hyprland.keybindings.special-ws-bindings - |> builtins.mapAttrs mkSpecialWBinding - |> builtins.attrValues - |> lib.mergeAttrsList) - - # Move to WS: "$mainMod SHIFT, 1" = ["movetoworkspace, 1"]; - (let - mkMoveWBinding = w: k: {"$mainMod SHIFT, ${k}" = ["movetoworkspace, ${w}"];}; - in - (hyprland.keybindings.ws-bindings) - |> builtins.mapAttrs mkMoveWBinding - |> builtins.attrValues - |> lib.mergeAttrsList) - - # Move to special WS: "$mainMod SHIFT, x" = ["movetoworkspace, special:ferdium"]; - (let - mkSpecialMoveWBinding = w: k: {"$mainMod SHIFT, ${k}" = ["movetoworkspace, special:${w}"];}; - in - (hyprland.keybindings.special-ws-bindings) - |> builtins.mapAttrs mkSpecialMoveWBinding - |> builtins.attrValues - |> lib.mergeAttrsList) - ]; + always-bind = import ./mappings.nix {inherit lib config hyprland;}; always-bindm = { "$mainMod, mouse:272" = ["movewindow"]; "$mainMod, mouse:273" = ["resizewindow"]; }; - always-exec = builtins.concatLists [ - (lib.optionals hyprland.dunst.enable ["dunst"]) # Notifications - [ - # Start clipboard management - "wl-paste -t text --watch clipman store --no-persist" - "wl-paste -p -t text --watch clipman store -P --histpath=\"~/.local/share/clipman-primary.json\"" - - "hyprctl setcursor Bibata-Modern-Classic 16" - "hyprsunset --identity" - - # HACK: Hyprland doesn't set the xwayland/x11 keymap correctly - "setxkbmap -layout ${hyprland.keyboard.layout} -variant ${hyprland.keyboard.variant} -option ${hyprland.keyboard.option} -model pc104" - - # HACK: Flatpak doesn't find applications in the system PATH - "systemctl --user import-environment PATH && systemctl --user restart xdg-desktop-portal.service" - - # Provide a polkit authentication UI. - # This is used for example when running systemd commands without root. - # "systemctl --user start hyprpolkitagent.service" - # "${pkgs.kdePackages.polkit-kde-agent-1}/libexec/polkit-kde-authentication-agent-1" - "${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1" - ] - ]; + always-exec = import ./autostart.nix {inherit lib pkgs config hyprland;}; in { options.modules.hyprland = import ./options.nix {inherit lib mylib;}; @@ -207,6 +111,9 @@ in { }; programs = { + hyprlock = import ./hyprlock.nix {inherit config hyprland color;}; + + # TODO: IMV shouldn't be part of the hyprland module imv = { enable = true; settings = { @@ -219,176 +126,27 @@ in { }; }; }; - - hyprlock = { - enable = true; - - settings = { - general = { - disable_loading_bar = true; - grace = 0; # Immediately lock - hide_cursor = true; - no_fade_in = false; - }; - - # The widgets start here. - - background = [ - { - path = "${config.paths.nixflake}/wallpapers/${color.wallpaper}.jpg"; - blur_passes = 3; - blur_size = 10; - monitor = ""; - } - ]; - - input-field = [ - # Password input - { - size = "200, 50"; - position = "0, 0"; - monitor = ""; - dots_center = true; - fade_on_empty = false; - font_color = "rgb(${color.hex.accentText})"; - font_family = "${color.font}"; - inner_color = "rgb(${color.hex.accent})"; - outer_color = "rgb(${color.hex.accent})"; - outline_thickness = 2; - placeholder_text = "Password..."; - shadow_passes = 0; - rounding = 4; - halign = "center"; - valign = "center"; - } - ]; - - label = [ - # Date - { - position = "0, 300"; - monitor = ""; - text = ''cmd[update:1000] date -I''; - color = "rgba(${color.hex.text}AA)"; - font_size = 22; - font_family = "${color.font}"; - halign = "center"; - valign = "center"; - } - - # Time - { - position = "0, 200"; - monitor = ""; - text = ''cmd[update:1000] date +"%-H:%M"''; - color = "rgba(${color.hex.text}AA)"; - font_size = 95; - font_family = "${color.font} Extrabold"; - halign = "center"; - valign = "center"; - } - ]; - }; - }; }; services = { - hyprpaper = { - enable = true; - - settings = { - ipc = "on"; - splash = false; - splash_offset = 2.0; - - # Wallpapers have to be preloaded to be displayed - preload = let - mkPreload = name: "${config.paths.nixflake}/wallpapers/${name}.jpg"; - in - color.wallpapers |> builtins.map mkPreload; - - wallpaper = let - mkWallpaper = monitor: - "${monitor}, " - + "${config.paths.nixflake}/wallpapers/${color.wallpaper}.jpg"; - in - hyprland.monitors - |> builtins.attrNames - |> builtins.map mkWallpaper; - }; - }; - - hypridle = { - enable = true; - - settings = { - general = { - # DPMS - Display Powermanagement Signaling. "On" means the monitor is on. - after_sleep_cmd = "hyprctl dispatch dpms on"; - ignore_dbus_inhibit = false; - lock_cmd = "hyprlock"; - }; - - listener = [ - { - timeout = 900; - on-timeout = "hyprlock"; - } - { - timeout = 1200; - on-timeout = "hyprctl dispatch dpms off"; - on-resume = "hyprctl dispatch dpms on"; - } - ]; - }; - }; - - # Notification service - dunst = { - enable = hyprland.dunst.enable; - - iconTheme.package = pkgs.papirus-icon-theme; - iconTheme.name = "Papirus"; - - settings = { - global = { - monitor = config.modules.waybar.monitor; - font = "${color.font} 11"; - offset = "10x10"; - background = color.hexS.base; - foreground = color.hexS.text; - frame_width = 2; - corner_radius = 6; - separator_color = "frame"; - }; - - urgency_low = { - frame_color = color.hexS.green; - }; - - urgency_normal = { - frame_color = color.hexS.green; - }; - - urgency_critical = { - frame_color = color.hexS.red; - }; - }; - }; + # TODO: Dunst shouldn't be part of the hyprland module + dunst = import ./dunst.nix {inherit pkgs config hyprland color;}; + hypridle = import ./hypridle.nix {inherit config hyprland color;}; + hyprpaper = import ./hyprpaper.nix {inherit config hyprland color;}; }; wayland.windowManager.hyprland = { enable = true; + package = inputs.hyprland.packages.${pkgs.system}.hyprland; + portalPackage = inputs.hyprland.packages.${pkgs.system}.xdg-desktop-portal-hyprland; + systemd.enable = true; # Enable hyprland-session.target systemd.variables = ["--all"]; # Import PATH into systemd xwayland.enable = true; plugins = [ - # TODO: Takes ages (compiles all hyprland dependencies locally...) - # Probably have to use hyprland flake to follow... - - # inputs.hypr-dynamic-cursors.packages.${pkgs.system}.hypr-dynamic-cursors - # inputs.hyprland-plugins.packages.${pkgs.system}.hyprbars + inputs.hypr-dynamic-cursors.packages.${pkgs.system}.hypr-dynamic-cursors + inputs.hyprland-plugins.packages.${pkgs.system}.hyprbars ]; settings = { diff --git a/home/modules/hyprland/dunst.nix b/home/modules/hyprland/dunst.nix new file mode 100644 index 00000000..b75f345b --- /dev/null +++ b/home/modules/hyprland/dunst.nix @@ -0,0 +1,36 @@ +{ + pkgs, + config, + hyprland, + color, +}: { + enable = hyprland.dunst.enable; + + iconTheme.package = pkgs.papirus-icon-theme; + iconTheme.name = "Papirus"; + + settings = { + global = { + monitor = config.modules.waybar.monitor; + font = "${color.font} 11"; + offset = "10x10"; + background = color.hexS.base; + foreground = color.hexS.text; + frame_width = 2; + corner_radius = 6; + separator_color = "frame"; + }; + + urgency_low = { + frame_color = color.hexS.green; + }; + + urgency_normal = { + frame_color = color.hexS.green; + }; + + urgency_critical = { + frame_color = color.hexS.red; + }; + }; +} diff --git a/home/modules/hyprland/hypridle.nix b/home/modules/hyprland/hypridle.nix new file mode 100644 index 00000000..ee7a8dd9 --- /dev/null +++ b/home/modules/hyprland/hypridle.nix @@ -0,0 +1,28 @@ +{ + config, + hyprland, + color, +}: { + enable = true; + + settings = { + general = { + # DPMS - Display Powermanagement Signaling. "On" means the monitor is on. + after_sleep_cmd = "hyprctl dispatch dpms on"; + ignore_dbus_inhibit = false; + lock_cmd = "hyprlock"; + }; + + listener = [ + { + timeout = 900; + on-timeout = "hyprlock"; + } + { + timeout = 1200; + on-timeout = "hyprctl dispatch dpms off"; + on-resume = "hyprctl dispatch dpms on"; + } + ]; + }; +} diff --git a/home/modules/hyprland/hyprlock.nix b/home/modules/hyprland/hyprlock.nix new file mode 100644 index 00000000..69647be0 --- /dev/null +++ b/home/modules/hyprland/hyprlock.nix @@ -0,0 +1,74 @@ +{ + config, + hyprland, + color, +}: { + enable = true; + + settings = { + general = { + disable_loading_bar = true; + grace = 0; # Immediately lock + hide_cursor = true; + no_fade_in = false; + }; + + # The widgets start here. + + background = [ + { + path = "${config.paths.nixflake}/wallpapers/${color.wallpaper}.jpg"; + blur_passes = 3; + blur_size = 10; + monitor = ""; + } + ]; + + input-field = [ + # Password input + { + size = "200, 50"; + position = "0, 0"; + monitor = ""; + dots_center = true; + fade_on_empty = false; + font_color = "rgb(${color.hex.accentText})"; + font_family = "${color.font}"; + inner_color = "rgb(${color.hex.accent})"; + outer_color = "rgb(${color.hex.accent})"; + outline_thickness = 2; + placeholder_text = "Password..."; + shadow_passes = 0; + rounding = 4; + halign = "center"; + valign = "center"; + } + ]; + + label = [ + # Date + { + position = "0, 300"; + monitor = ""; + text = ''cmd[update:1000] date -I''; + color = "rgba(${color.hex.text}AA)"; + font_size = 22; + font_family = "${color.font}"; + halign = "center"; + valign = "center"; + } + + # Time + { + position = "0, 200"; + monitor = ""; + text = ''cmd[update:1000] date +"%-H:%M"''; + color = "rgba(${color.hex.text}AA)"; + font_size = 95; + font_family = "${color.font} Extrabold"; + halign = "center"; + valign = "center"; + } + ]; + }; +} diff --git a/home/modules/hyprland/hyprpaper.nix b/home/modules/hyprland/hyprpaper.nix new file mode 100644 index 00000000..1e71b4f6 --- /dev/null +++ b/home/modules/hyprland/hyprpaper.nix @@ -0,0 +1,28 @@ +{ + config, + hyprland, + color, +}: { + enable = true; + + settings = { + ipc = "on"; + splash = false; + splash_offset = 2.0; + + # Wallpapers have to be preloaded to be displayed + preload = let + mkPreload = name: "${config.paths.nixflake}/wallpapers/${name}.jpg"; + in + color.wallpapers |> builtins.map mkPreload; + + wallpaper = let + mkWallpaper = monitor: + "${monitor}, " + + "${config.paths.nixflake}/wallpapers/${color.wallpaper}.jpg"; + in + hyprland.monitors + |> builtins.attrNames + |> builtins.map mkWallpaper; + }; +} diff --git a/home/modules/hyprland/mappings.nix b/home/modules/hyprland/mappings.nix new file mode 100644 index 00000000..5b13ee00 --- /dev/null +++ b/home/modules/hyprland/mappings.nix @@ -0,0 +1,81 @@ +{ + lib, + config, + hyprland, +}: +lib.mergeAttrsList [ + { + # Hyprland control + "$mainMod, a" = ["exec, rofi -drun-show-actions -show drun"]; + "$mainMod, q" = ["killactive"]; + "$mainMod, v" = ["togglefloating"]; + "$mainMod, f" = ["fullscreen"]; + "$mainMod, c" = ["exec, clipman pick --tool=rofi"]; + "$mainMod SHIFT, l" = ["exec, loginctl lock-session"]; + "$mainMod, tab" = ["workspace, previous"]; + "ALT, tab" = ["exec, rofi -show window"]; + # "$mainMod, g" = ["togglegroup"]; + # "ALT, tab" = ["changegroupactive"]; + + # Move focus with mainMod + arrow keys + "$mainMod, h" = ["movefocus, l"]; + "$mainMod, l" = ["movefocus, r"]; + "$mainMod, k" = ["movefocus, u"]; + "$mainMod, j" = ["movefocus, d"]; + + # Swap windows + "$mainMod CTRL, h" = ["movewindow, l"]; + "$mainMod CTRL, l" = ["movewindow, r"]; + "$mainMod CTRL, k" = ["movewindow, u"]; + "$mainMod CTRL, d" = ["movewindow, d"]; + + # Reset workspaces to the defined configuration in hyprland.workspaces: + "CTRL ALT, r" = let + mkWBinding = m: w: + "moveworkspacetomonitor, " + + "${builtins.toString w} ${builtins.toString m}"; + + mkWsBindings = m: ws: builtins.map (mkWBinding m) ws; + in + hyprland.workspaces + |> builtins.mapAttrs mkWsBindings + |> builtins.attrValues + |> builtins.concatLists; + } + + # Switch to WS: "$mainMod, 1" = ["workspace, 1"]; + (let + mkWBinding = w: k: {"$mainMod, ${k}" = ["workspace, ${w}"];}; + in + hyprland.keybindings.ws-bindings + |> builtins.mapAttrs mkWBinding + |> builtins.attrValues + |> lib.mergeAttrsList) + + # Toggle special WS: "$mainMod, x" = ["togglespecialworkspace, ferdium"]; + (let + mkSpecialWBinding = w: k: {"$mainMod, ${k}" = ["togglespecialworkspace, ${w}"];}; + in + hyprland.keybindings.special-ws-bindings + |> builtins.mapAttrs mkSpecialWBinding + |> builtins.attrValues + |> lib.mergeAttrsList) + + # Move to WS: "$mainMod SHIFT, 1" = ["movetoworkspace, 1"]; + (let + mkMoveWBinding = w: k: {"$mainMod SHIFT, ${k}" = ["movetoworkspace, ${w}"];}; + in + (hyprland.keybindings.ws-bindings) + |> builtins.mapAttrs mkMoveWBinding + |> builtins.attrValues + |> lib.mergeAttrsList) + + # Move to special WS: "$mainMod SHIFT, x" = ["movetoworkspace, special:ferdium"]; + (let + mkSpecialMoveWBinding = w: k: {"$mainMod SHIFT, ${k}" = ["movetoworkspace, special:${w}"];}; + in + hyprland.keybindings.special-ws-bindings + |> builtins.mapAttrs mkSpecialMoveWBinding + |> builtins.attrValues + |> lib.mergeAttrsList) +]