diff --git a/home/christoph/default.nix b/home/christoph/default.nix index e1c0ad90..ae136219 100644 --- a/home/christoph/default.nix +++ b/home/christoph/default.nix @@ -89,6 +89,22 @@ rec { enable = true; theme = "Three-Bears"; + keybindings = { + main-mod = "SUPER"; + + mod-bindings = { + "Q" = ["killactive"]; + "V" = ["togglefloating"]; + }; + + bindings = { + "CTRL ALT, R" = [ + "moveworkspacetomonitor, 1 HDMI-A-1" + "moveworkspacetomonitor, 2 HDMI-A-1" + ]; + }; + }; + autostart = [ "kdeconnect-indicator" "nextcloud --background" diff --git a/home/modules/hyprland/default.nix b/home/modules/hyprland/default.nix index 140e093c..15812379 100644 --- a/home/modules/hyprland/default.nix +++ b/home/modules/hyprland/default.nix @@ -7,14 +7,12 @@ mylib, pkgs, ... -}: -with lib; -with mylib.modules; let +}: let cfg = config.modules.hyprland; in { options.modules.hyprland = import ./options.nix {inherit lib mylib;}; - config = mkIf cfg.enable { + config = lib.mkIf cfg.enable { assertions = [ { assertion = nixosConfig.programs.hyprland.enable; @@ -36,124 +34,6 @@ in { size = 16; }; - home.sessionVariables = { - # QT_QPA_PLATFORMTHEME = "qt5ct"; - }; - - # 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 - # Used by mapAttrs - 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}"; - # Makes "HDMI-A-1" = {width=2560;...} to "HDMI-A-1" = "monitor = ..." - monitors-attrs = mapAttrs mkMonitor cfg.monitors; - # Makes "HDMI-A-1" = "monitor = ..." to "monitor = ..." - monitors-values = attrValues monitors-attrs; - monitors = concatStringsSep "\n" monitors-values; - in - monitors; - - # Bind workspaces to monitors - home.file.".config/hypr/workspaces.conf".text = let - # Make a single monitor string - mkWorkspace = monitor: workspace: "workspace = ${toString workspace}, monitor:${toString monitor}"; - # Used by mapAttrs - mkWorkspaces = monitor: workspace-list: map (mkWorkspace monitor) workspace-list; - # Makes {"HDMI-A-1" = [1 2]; ...} to {"HDMI-A-1" = ["monitor = ..." "monitor = ..."] ...} - workspaces-attrs = mapAttrs mkWorkspaces cfg.workspaces; - # Makes {"HDMI-A-1" = [1 2]; ...} to ["monitor = ..." "monitor = ..." ...] - workspaces-values = concatLists (attrValues workspaces-attrs); - workspaces = concatStringsSep "\n" workspaces-values; - in - workspaces; - - # 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" - ]; - - mkExec = prog: "exec-once = ${prog}"; - execs-list = map mkExec (cfg.autostart ++ always-exec); - execs = concatStringsSep "\n" execs-list; - in - execs; - - # 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; - workspace-rules-attrs = mapAttrs mkWorkspaceRules cfg.workspacerules; - workspace-rules-values = concatLists (attrValues workspace-rules-attrs); - workspace-rules = concatStringsSep "\n" workspace-rules-values; - in - workspace-rules; - - # Make windows float - home.file.".config/hypr/floatingrules.conf".text = let - mkFloatingRule = attrs: - "windowrulev2 = float" - + (lib.optionalString (hasAttr "class" attrs) ", class:^(${attrs.class})$") - + (lib.optionalString (hasAttr "title" attrs) ", title:^(${attrs.title})$"); - floating-rules-list = map mkFloatingRule cfg.floating; - floating-rules = concatStringsSep "\n" floating-rules-list; - in - floating-rules; - - # Make windows translucent - home.file.".config/hypr/translucentrules.conf".text = let - opacity = 0.8; - - mkTranslucentRule = class: "windowrulev2 = opacity ${toString opacity} ${toString opacity}, class:^(${class})$"; - translucent-rules-list = map mkTranslucentRule cfg.transparent; - translucent-rules = concatStringsSep "\n" translucent-rules-list; - in - translucent-rules; - - # 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 = - - follow_mouse = 1 - - touchpad { - natural_scroll = no - } - - sensitivity = 0 # -1.0 - 1.0, 0 means no modification. - } - ''; - - # 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-list = map mkWallpaper (attrNames cfg.monitors); - wallpapers = concatStringsSep "\n" wallpapers-list; - in '' - preload = ~/NixFlake/wallpapers/${cfg.theme}.png - ${wallpapers} - ''; - - home.activation = { - # NOTE: Keep the hyprland/waybar 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 = - hm.dag.entryAfter ["writeBoundary"] - (mkLink "~/NixFlake/config/hyprland/hyprland.conf" "~/.config/hypr/hyprland.conf"); - }; - home.packages = with pkgs; [ hyprpaper # Wallpaper setter hyprpicker # Color picker @@ -178,5 +58,156 @@ in { enable = true; }; }; + + 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 + mkBind = key: action: "bind = ${key}, ${action}"; + mkBinds = key: actions: builtins.map (mkBind key) actions; + binds = lib.pipe cfg.keybindings.bindings [ + (builtins.mapAttrs mkBinds) + builtins.attrValues + builtins.concatLists + (builtins.concatStringsSep "\n") + ]; + + mkModBind = key: action: "bind = $mainMod, ${key}, ${action}"; + mkModBinds = key: actions: builtins.map (mkModBind key) actions; + mod-binds = lib.pipe cfg.keybindings.mod-bindings [ + (builtins.mapAttrs mkModBinds) + builtins.attrValues + builtins.concatLists + (builtins.concatStringsSep "\n") + ]; + in '' + $mainMod = ${cfg.keybindings.main-mod} + ${mod-binds} + ${binds} + ''; + + # 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" + ]; + + mkExec = prog: "exec-once = ${prog}"; + in + lib.pipe (cfg.autostart ++ always-exec) [ + (builtins.map mkExec) + (builtins.concatStringsSep "\n") + ]; + + # 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") + ]; + + # 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") + ]; + + # 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") + ]; + + # 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 = + + follow_mouse = 1 + + touchpad { + natural_scroll = no + } + + sensitivity = 0 # -1.0 - 1.0, 0 means no modification. + } + ''; + + # 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} + ''; + + 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"); + }; }; } diff --git a/home/modules/hyprland/options.nix b/home/modules/hyprland/options.nix index 9d9f8910..5bc0ede1 100644 --- a/home/modules/hyprland/options.nix +++ b/home/modules/hyprland/options.nix @@ -102,4 +102,38 @@ with mylib.modules; { ] ''; }; + + keybindings = { + main-mod = mkOption { + type = types.str; + description = "Main modifier key"; + example = '' + "SUPER" + ''; + }; + + mod-bindings = mkOption { + type = types.attrs; + description = "Hyprland keyboard shortcuts using the modifier key"; + example = '' + { + "Q" = ["killactive"]; + "V" = ["togglefloating"]; + } + ''; + }; + + bindings = mkOption { + type = types.attrs; + description = "Hyprland keyboard shortcuts"; + example = '' + { + "CTRL ALT, R" = [ + "moveworkspacetomonitor, 1 HDMI-A-1" + "moveworkspacetomonitor, 2 HDMI-A-1" + ]; + } + ''; + }; + }; }