{ pkgs, lib, config, ... }: let inherit (lib) mkOption recursiveUpdate types optionals ; rosePineHyprcursor = pkgs.callPackage ./rose-pine-hyprcursor.nix { }; mkLua = lib.generators.mkLuaInline; mkEnv = name: value: { _args = [ name value ]; }; mkBind = keys: dispatcher: { _args = [ keys (mkLua dispatcher) ]; }; mkMouseBind = keys: dispatcher: { _args = [ keys (mkLua dispatcher) { mouse = true; } ]; }; mkStartHook = commands: { _args = [ "hyprland.start" (mkLua '' function() ${lib.concatMapStrings (command: " hl.exec_cmd(${builtins.toJSON command})\n") commands}end '') ]; }; defaultInput = { kb_layout = "us"; kb_variant = ""; kb_model = ""; kb_options = ""; kb_rules = ""; follow_mouse = true; touchpad = { natural_scroll = true; }; natural_scroll = true; sensitivity = 0.0; }; wallpaperCommand = config.hare.hyprland.wallpaperCommand; startupCommands = [ # "/usr/lib/polkit-kde-authentication-agent-1" # "dunst" "awww-daemon" # "copyq --start-server" # "wl-paste --type text --watch cliphist store" # "wl-paste --type image --watch cliphist store" "eww daemon" "eww open bar" "eww open roundedEdge" ]; reloadCommands = optionals (wallpaperCommand != null) [ wallpaperCommand ] ++ [ "dconf write /org/gnome/desktop/interface/gtk-theme 'Adwaita Dark'" "dconf write /org/gnome/desktop/interface/icon-theme 'Adwaita Dark'" "dconf write /org/gnome/desktop/interface/document-font-name 'Noto Sans Medium 11'" "dconf write /org/gnome/desktop/interface/font-name 'Noto Sans Medium 11'" "dconf write /org/gnome/desktop/interface/monospace-font-name 'Noto Sans Mono Medium 11'" ]; baseConfig = { ecosystem.no_update_news = true; input = defaultInput; general = { layout = "dwindle"; allow_tearing = true; }; dwindle = { preserve_split = true; }; misc = { force_default_wallpaper = false; disable_hyprland_logo = true; disable_splash_rendering = true; }; xwayland = { force_zero_scaling = true; }; }; baseSettings = { menu = { _var = "uwsm app -- $(tofi-drun)"; }; terminal = { _var = "wezterm"; }; lock = { _var = "hyprlock"; }; env = [ (mkEnv "XDG_CURRENT_DESKTOP" "Hyprland") (mkEnv "XDG_SESSION_TYPE" "wayland") (mkEnv "XDG_SESSION_DESKTOP" "Hyprland") # "GDK_SCALE,2" # "XCURSOR_SIZE,32" ]; exec_cmd = reloadCommands; on = mkStartHook startupCommands; window_rule = [ { match.title = "^(.*wofi.*)$"; animation = "windowsIn 0"; } { match.title = "^(.*feh.*)$"; float = true; } { match.title = "^(.*feh.*)$"; center = true; } { match.title = "^(Picture.*)$"; float = true; } { match.title = "^(Picture.*)$"; pin = true; } ]; workspace_rule = [ { workspace = "r[1-9]"; monitor = "DP-1"; } { workspace = "101"; monitor = "DP-2"; default = true; } { workspace = "102"; monitor = "DP-3"; default = true; } ]; bind = [ # Window Movement & Resizing (mkMouseBind "SUPER + mouse:272" "hl.dsp.window.drag()") (mkMouseBind "SUPER + mouse:273" "hl.dsp.window.resize()") # basic (mkBind "SUPER + RETURN" "hl.dsp.exec_cmd(menu)") (mkBind "SUPER + E" "hl.dsp.exec_cmd(terminal)") (mkBind "SUPER + Q" "hl.dsp.window.close()") (mkBind "SUPER + L" "hl.dsp.exec_cmd(lock)") (mkBind "SUPER + SHIFT + L" ''hl.dsp.dpms({ action = "off" })'') (mkBind "SUPER + SHIFT + M" ''hl.dsp.exec_cmd("loginctl terminate-user $USER")'') # prsc (mkBind "Print" ''hl.dsp.exec_cmd("hyprshot -m window -m active --clipboard-only")'') # Clipboard (mkBind "SUPER + C" ''hl.dsp.exec_cmd("copyq show")'') (mkBind "SUPER + V" ''hl.dsp.exec_cmd("clipman pick -t dmenu")'') # Window navigation (mkBind "SUPER + F" "hl.dsp.window.fullscreen()") (mkBind "SUPER + Y" "hl.dsp.window.pin()") (mkBind "SUPER + I" ''hl.dsp.window.float({ action = "toggle" })'') (mkBind "SUPER + O" ''hl.dsp.layout("togglesplit")'') # dwindle (mkBind "SUPER + P" "hl.dsp.window.pseudo()") # dwindle # Window focus (mkBind "SUPER + mouse_down" "hl.dsp.window.cycle_next()") (mkBind "SUPER + mouse_up" "hl.dsp.window.cycle_next({ next = false })") (mkBind "SUPER + left" ''hl.dsp.focus({ direction = "left" })'') (mkBind "SUPER + right" ''hl.dsp.focus({ direction = "right" })'') (mkBind "SUPER + up" ''hl.dsp.focus({ direction = "up" })'') (mkBind "SUPER + down" ''hl.dsp.focus({ direction = "down" })'') (mkBind "SUPER + SHIFT + left" ''hl.dsp.window.move({ direction = "left" })'') (mkBind "SUPER + SHIFT + right" ''hl.dsp.window.move({ direction = "right" })'') (mkBind "SUPER + SHIFT + up" ''hl.dsp.window.move({ direction = "up" })'') (mkBind "SUPER + SHIFT + down" ''hl.dsp.window.move({ direction = "down" })'') # workspaces (mkBind "SUPER + 1" "hl.dsp.focus({ workspace = 1 })") (mkBind "SUPER + 2" "hl.dsp.focus({ workspace = 2 })") (mkBind "SUPER + 3" "hl.dsp.focus({ workspace = 3 })") (mkBind "SUPER + CTRL + left" ''hl.dsp.focus({ workspace = "m-1" })'') (mkBind "SUPER + CTRL + right" ''hl.dsp.focus({ workspace = "m+1" })'') (mkBind "SUPER + CTRL + SHIFT + left" ''hl.dsp.focus({ workspace = "r-1" })'') (mkBind "SUPER + CTRL + SHIFT + right" ''hl.dsp.focus({ workspace = "r+1" })'') ] ++ ( # workspaces # binds $mod + [shift +] {1..9} to [move to] workspace {1..9} builtins.concatLists ( builtins.genList ( i: let ws = i + 1; in [ (mkBind "SUPER + code:1${toString i}" "hl.dsp.focus({ workspace = ${toString ws} })") (mkBind "SUPER + SHIFT + code:1${toString i}" "hl.dsp.window.move({ workspace = ${toString ws} })") ] ) 9 ) ); }; defaultStyle = { general = { gaps_in = 4; gaps_out = 7; border_size = 3; col = { active_border = { colors = [ "rgba(6e848cee)" "rgba(eeeeffee)" ]; angle = 90; }; inactive_border = "rgba(595959aa)"; }; }; decoration = { rounding = 10; blur = { enabled = true; size = 6; passes = 2; noise = 0.01; contrast = 0.8; brightness = 0.5; vibrancy = 0.25; vibrancy_darkness = 0.1; }; shadow = { enabled = false; range = 4; render_power = 3; color = "rgba(1a1a1aee)"; }; dim_inactive = false; }; animations = { enabled = true; animation = [ { leaf = "windowsIn"; enabled = true; speed = 1; bezier = "default"; style = "popin 90%"; } { leaf = "windowsOut"; enabled = true; speed = 100; bezier = "default"; style = "popin 80%"; } { leaf = "windowsMove"; enabled = true; speed = 3; bezier = "default"; } { leaf = "border"; enabled = true; speed = 10; bezier = "default"; } { leaf = "borderangle"; enabled = true; speed = 8; bezier = "default"; } { leaf = "fade"; enabled = true; speed = 7; bezier = "default"; } { leaf = "workspaces"; enabled = true; speed = 5; bezier = "default"; style = "slidefade 10%"; } ]; }; }; styleSettings = recursiveUpdate defaultStyle config.hare.hyprland.style; styleConfig = recursiveUpdate (builtins.removeAttrs styleSettings [ "animations" ]) { animations = builtins.removeAttrs styleSettings.animations [ "animation" ]; }; inputSettings = recursiveUpdate defaultInput config.hare.hyprland.input; in { options.hare.hyprland.style = mkOption { type = types.attrs; default = { }; description = "Overlay of Hyprland style tweaks that will be merged on top of the base settings."; }; options.hare.hyprland.input = mkOption { type = types.attrs; default = { }; description = "Overrides for the Hyprland input block (e.g., sensitivity, accel profiles)."; }; options.hare.hyprland.wallpaperCommand = mkOption { type = types.nullOr types.str; default = null; description = "Command to set the wallpaper (e.g., \"awww img \"); appended to Hyprland's exec list when provided."; }; config = { wayland.windowManager.hyprland = { enable = true; configType = "lua"; systemd.enable = false; settings = recursiveUpdate baseSettings { config = recursiveUpdate (recursiveUpdate baseConfig styleConfig) { input = inputSettings; }; animation = styleSettings.animations.animation; }; plugins = [ ]; }; home.packages = [ rosePineHyprcursor ] ++ (with pkgs; [ awww eww hyprshot ]); home.sessionVariables = { HYPRCURSOR_THEME = "rose-pine-hyprcursor"; HYPRCURSOR_SIZE = "24"; XCURSOR_SIZE = "24"; GTK_BACKEND = "wayland"; QT_QPA_PLATFORM = "wayland;xcb"; QT_QPA_PLATFORMTHEME = "qt5ct"; }; }; }