diff --git a/home/modules/hyprland/default.nix b/home/modules/hyprland/default.nix index dd59e2ed..596ef4fa 100644 --- a/home/modules/hyprland/default.nix +++ b/home/modules/hyprland/default.nix @@ -26,36 +26,6 @@ in { iconTheme.name = "Papirus"; }; - # TODO: catppuccin-cursors - home.pointerCursor = { - gtk.enable = true; - x11.enable = true; - package = pkgs.bibata-cursors; - name = "Bibata-Modern-Classic"; - # package = pkgs.catppuccin-cursors.latteMauve; - # name = "Catppuccin-Latte-Mauve-Cursors"; - size = 16; - }; - - home.packages = with pkgs; [ - hyprpaper # Wallpaper setter - hyprpicker # Color picker - - wl-clipboard - clipman # Clipboard manager (wl-paste) - libnotify - inotifyTools # inotifywait etc. - - moc # Audio player - ncpamixer # ncurses pavucontrol - slurp # Region selector for screensharing - grim # Grab images from compositor - - # xfce.thunar - # xfce.tumbler # Thunar thumbnails - libsForQt5.polkit-kde-agent - ]; - programs = { imv = { enable = true; @@ -104,155 +74,194 @@ in { }; }; - home.sessionVariables = { - }; - - # - # Generate many individual config files from the options - # - - # Polkit - home.file.".config/hypr/polkit.conf".text = '' - exec-once = ${pkgs.libsForQt5.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1 - ''; - - # Monitors for different systems - home.file.".config/hypr/monitors.conf".text = let - mkMonitor = name: conf: "monitor = ${name}, ${toString conf.width}x${toString conf.height}@${toString conf.rate}, ${toString conf.x}x${toString conf.y}, ${toString conf.scale}"; - in - lib.pipe cfg.monitors [ - (builtins.mapAttrs mkMonitor) - builtins.attrValues - (builtins.concatStringsSep "\n") - ]; - - # Bind workspaces to monitors - home.file.".config/hypr/workspaces.conf".text = let - mkWorkspace = monitor: workspace: "workspace = ${toString workspace}, monitor:${toString monitor}"; - mkWorkspaces = monitor: workspace-list: map (mkWorkspace monitor) workspace-list; - in - lib.pipe cfg.workspaces [ - (builtins.mapAttrs mkWorkspaces) - builtins.attrValues - builtins.concatLists - (builtins.concatStringsSep "\n") - ]; - - # Keybindings - home.file.".config/hypr/keybindings.conf".text = let - always-bind = { - # Hyprland control - "$mainMod, Q" = ["killactive"]; - "$mainMod, V" = ["togglefloating"]; - "$mainMod, F" = ["fullscreen"]; - "$mainMod, C" = ["exec, clipman pick --tool=rofi"]; - "$mainMod, G" = ["togglegroup"]; - "ALT, tab" = ["changegroupactive"]; + home = { + # TODO: catppuccin-cursors + pointerCursor = { + gtk.enable = true; + x11.enable = true; + package = pkgs.bibata-cursors; + name = "Bibata-Modern-Classic"; + # package = pkgs.catppuccin-cursors.latteMauve; + # name = "Catppuccin-Latte-Mauve-Cursors"; + size = 16; }; - mkBind = key: action: "bind = ${key}, ${action}"; - mkBinds = key: actions: builtins.map (mkBind key) actions; - binds = lib.pipe (lib.mergeAttrs cfg.keybindings.bindings always-bind) [ - (builtins.mapAttrs mkBinds) - builtins.attrValues - builtins.concatLists - (builtins.concatStringsSep "\n") - ]; - in '' - $mainMod = ${cfg.keybindings.main-mod} - ${binds} - ''; + packages = with pkgs; [ + hyprpaper # Wallpaper setter + hyprpicker # Color picker - # Autostart applications - home.file.".config/hypr/autostart.conf".text = let - # Stuff that is not negotiable - always-exec = [ - "dunst" # Notifications - "hyprpaper" - "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" + wl-clipboard + clipman # Clipboard manager (wl-paste) + libnotify + inotifyTools # inotifywait etc. + + moc # Audio player + ncpamixer # ncurses pavucontrol + slurp # Region selector for screensharing + grim # Grab images from compositor + + # xfce.thunar + # xfce.tumbler # Thunar thumbnails + libsForQt5.polkit-kde-agent ]; - mkExec = prog: "exec-once = ${prog}"; - in - lib.pipe (cfg.autostart ++ always-exec) [ - (builtins.map mkExec) - (builtins.concatStringsSep "\n") - ]; + sessionVariables = { + }; - # Assign windows to workspaces - home.file.".config/hypr/workspacerules.conf".text = let - mkWorkspaceRule = workspace: class: "windowrulev2 = workspace ${workspace}, class:^(${class})$"; - mkWorkspaceRules = workspace: class-list: map (mkWorkspaceRule workspace) class-list; - in - lib.pipe cfg.workspacerules [ - (builtins.mapAttrs mkWorkspaceRules) - builtins.attrValues - builtins.concatLists - (builtins.concatStringsSep "\n") - ]; + # + # Generate many individual config files from the options + # - # Make windows float - home.file.".config/hypr/floatingrules.conf".text = let - mkFloatingRule = attrs: - "windowrulev2 = float" - + (lib.optionalString (builtins.hasAttr "class" attrs) ", class:^(${attrs.class})$") - + (lib.optionalString (builtins.hasAttr "title" attrs) ", title:^(${attrs.title})$"); - in - lib.pipe cfg.floating [ - (builtins.map mkFloatingRule) - (builtins.concatStringsSep "\n") - ]; + file = { + # Polkit + ".config/hypr/polkit.conf".text = '' + exec-once = ${pkgs.libsForQt5.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1 + ''; - # Make windows translucent - home.file.".config/hypr/translucentrules.conf".text = let - opacity = 0.8; - mkTranslucentRule = class: "windowrulev2 = opacity ${toString opacity} ${toString opacity}, class:^(${class})$"; - in - lib.pipe cfg.transparent [ - (builtins.map mkTranslucentRule) - (builtins.concatStringsSep "\n") - ]; + # Monitors for different systems + ".config/hypr/monitors.conf".text = let + mkMonitor = name: conf: "monitor = ${name}, ${toString conf.width}x${toString conf.height}@${toString conf.rate}, ${toString conf.x}x${toString conf.y}, ${toString conf.scale}"; + in + lib.pipe cfg.monitors [ + (builtins.mapAttrs mkMonitor) + builtins.attrValues + (builtins.concatStringsSep "\n") + ]; - # Set wallpaper for each configured monitor - home.file.".config/hypr/hyprpaper.conf".text = let - mkWallpaper = monitor: "wallpaper = ${monitor}, ${config.home.homeDirectory}/NixFlake/wallpapers/${cfg.theme}.png"; - wallpapers = lib.pipe cfg.monitors [ - builtins.attrNames - (builtins.map mkWallpaper) - (builtins.concatStringsSep "\n") - ]; - in '' - preload = ~/NixFlake/wallpapers/${cfg.theme}.png - ${wallpapers} - ''; + # Bind workspaces to monitors + ".config/hypr/workspaces.conf".text = let + mkWorkspace = monitor: workspace: "workspace = ${toString workspace}, monitor:${toString monitor}"; + mkWorkspaces = monitor: workspace-list: map (mkWorkspace monitor) workspace-list; + in + lib.pipe cfg.workspaces [ + (builtins.mapAttrs mkWorkspaces) + builtins.attrValues + builtins.concatLists + (builtins.concatStringsSep "\n") + ]; - # Keyboard layout - home.file.".config/hypr/input.conf".text = '' - input { - kb_layout = ${cfg.kb-layout} - kb_variant = ${cfg.kb-variant} - kb_model = pc104 - kb_options = - kb_rules = + # Keybindings + ".config/hypr/keybindings.conf".text = let + always-bind = { + # Hyprland control + "$mainMod, Q" = ["killactive"]; + "$mainMod, V" = ["togglefloating"]; + "$mainMod, F" = ["fullscreen"]; + "$mainMod, C" = ["exec, clipman pick --tool=rofi"]; + "$mainMod, G" = ["togglegroup"]; + "ALT, tab" = ["changegroupactive"]; + }; - follow_mouse = 1 + mkBind = key: action: "bind = ${key}, ${action}"; + mkBinds = key: actions: builtins.map (mkBind key) actions; + binds = lib.pipe (lib.mergeAttrs cfg.keybindings.bindings always-bind) [ + (builtins.mapAttrs mkBinds) + builtins.attrValues + builtins.concatLists + (builtins.concatStringsSep "\n") + ]; + in '' + $mainMod = ${cfg.keybindings.main-mod} + ${binds} + ''; - touchpad { - natural_scroll = no + # Autostart applications + ".config/hypr/autostart.conf".text = let + # Stuff that is not negotiable + always-exec = [ + "dunst" # Notifications + "hyprpaper" + "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" + ]; + + # NOTE: The sleep is a hack for tray icons, they need to be launched after waybar + sleepTime = 5; + mkDelayedStart = str: "hyprctl dispatch exec \"sleep ${builtins.toString sleepTime}s && ${str}\""; + delayed-exec = builtins.map mkDelayedStart cfg.autostart.delayed; + + mkExec = prog: "exec-once = ${prog}"; + in + lib.pipe (always-exec ++ cfg.autostart.immediate ++ delayed-exec) [ + (builtins.map mkExec) + (builtins.concatStringsSep "\n") + ]; + + # Assign windows to workspaces + ".config/hypr/workspacerules.conf".text = let + mkWorkspaceRule = workspace: class: "windowrulev2 = workspace ${workspace}, class:^(${class})$"; + mkWorkspaceRules = workspace: class-list: builtins.map (mkWorkspaceRule workspace) class-list; + in + lib.pipe cfg.workspacerules [ + (builtins.mapAttrs mkWorkspaceRules) + builtins.attrValues + builtins.concatLists + (builtins.concatStringsSep "\n") + ]; + + # Make windows float + ".config/hypr/floatingrules.conf".text = let + mkFloatingRule = attrs: + "windowrulev2 = float" + + (lib.optionalString (builtins.hasAttr "class" attrs) ", class:^(${attrs.class})$") + + (lib.optionalString (builtins.hasAttr "title" attrs) ", title:^(${attrs.title})$"); + in + lib.pipe cfg.floating [ + (builtins.map mkFloatingRule) + (builtins.concatStringsSep "\n") + ]; + + # Make windows translucent + ".config/hypr/translucentrules.conf".text = let + opacity = 0.8; + mkTranslucentRule = class: "windowrulev2 = opacity ${toString opacity} ${toString opacity}, class:^(${class})$"; + in + lib.pipe cfg.transparent [ + (builtins.map mkTranslucentRule) + (builtins.concatStringsSep "\n") + ]; + + # Set wallpaper for each configured monitor + ".config/hypr/hyprpaper.conf".text = let + mkWallpaper = monitor: "wallpaper = ${monitor}, ${config.home.homeDirectory}/NixFlake/wallpapers/${cfg.theme}.png"; + wallpapers = lib.pipe cfg.monitors [ + builtins.attrNames + (builtins.map mkWallpaper) + (builtins.concatStringsSep "\n") + ]; + in '' + preload = ~/NixFlake/wallpapers/${cfg.theme}.png + ${wallpapers} + ''; + + # Keyboard layout + ".config/hypr/input.conf".text = '' + input { + kb_layout = ${cfg.kb-layout} + kb_variant = ${cfg.kb-variant} + kb_model = pc104 + kb_options = + kb_rules = + + follow_mouse = 1 + + touchpad { + natural_scroll = no + } + + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. } + ''; + }; - sensitivity = 0 # -1.0 - 1.0, 0 means no modification. - } - ''; - - home.activation = { - # NOTE: Keep the hyprland config symlinked, to allow easy changes with hotreload - # TODO: Don't symlink at all, why not just tell Hyprland where the config is? Much easier - linkHyprlandConfig = - lib.hm.dag.entryAfter ["writeBoundary"] - (mylib.modules.mkLink "~/NixFlake/config/hyprland/hyprland.conf" "~/.config/hypr/hyprland.conf"); + activation = { + # TODO: Don't symlink at all, why not just tell Hyprland where the config is? Much easier + # NOTE: Keep the hyprland config symlinked, to allow easy changes with hotreload + linkHyprlandConfig = + lib.hm.dag.entryAfter ["writeBoundary"] + (mylib.modules.mkLink "~/NixFlake/config/hyprland/hyprland.conf" "~/.config/hypr/hyprland.conf"); + }; }; }; } diff --git a/home/modules/hyprland/options.nix b/home/modules/hyprland/options.nix index 90d53560..a17a1e3e 100644 --- a/home/modules/hyprland/options.nix +++ b/home/modules/hyprland/options.nix @@ -53,15 +53,27 @@ with mylib.modules; { ''; }; - autostart = mkOption { - type = types.listOf types.str; - description = "Programs to launch when Hyprland starts"; - example = '' - [ - "keepassxc" - "nextcloud --background" - ] - ''; + autostart = { + immediate = mkOption { + type = types.listOf types.str; + description = "Programs to launch when Hyprland starts"; + example = '' + [ + "kitty" + ] + ''; + }; + + delayed = mkOption { + type = types.listOf types.str; + description = "Programs to launch with a delay when Hyprland starts (e.g. to wait for the waybar tray)"; + example = '' + [ + "keepassxc" + "nextcloud --background" + ] + ''; + }; }; workspacerules = mkOption {