{ pkgs, config, lib, self, inputs, osConfig, theme, ... }: let cfg = config.my.graphical.wayland.hyprland; in { options.my.graphical.wayland.hyprland = { enable = lib.mkEnableOption null; tearing = lib.mkEnableOption null; hyprcursor = lib.mkEnableOption null // { default = true; }; mainMod = lib.mkOption { type = lib.types.str; default = "SUPER"; }; lockBinary = lib.mkOption { type = lib.types.str; }; wallpaper = { enable = lib.mkEnableOption null // { default = true; }; backend = lib.mkOption { type = lib.types.enum [ "hyprpaper" "swaybg" ]; default = "swaybg"; }; image = lib.mkOption { type = lib.types.pathInStore; default = "${self}/assets/snowyMountain.jpg"; }; }; }; config = lib.mkIf cfg.enable (let toggleOption = pkgs.writeShellScriptBin "hypr-toggle-opt" '' hyprctl keyword "$1" "$(hyprctl getoption "$1" -j | ${pkgs.jaq}/bin/jaq '1 - .int')" ''; copyOutput = pkgs.writeShellScript "hypr-copy-output" '' MONITOR="$(hyprctl monitors -j | ${pkgs.jaq}/bin/jaq -r '.[] | select(.focused).name')" grim -o "$MONITOR" - | wl-copy -t image/png ''; copyWindow = pkgs.writeShellScript "hypr-copy-window" '' WINDOW="$(hyprctl activewindow -j | ${pkgs.jaq}/bin/jaq -r '.address')" grim -w "$WINDOW" - | wl-copy -t image/png ''; winShiftS = with pkgs; writeShellScriptBin "win-shift-s" '' FILENAME="/tmp/win-shift-s-$PPID.png" MONITOR="$(hyprctl monitors -j | ${_ jaq} -r '.[] | select(.focused)')" ${_ grim} -o "$(${_ jaq} -r '.name' <<< "$MONITOR")" "$FILENAME" ${_ imv} -f "$FILENAME" & IMV_PROC=$! DIMENSIONS="$(${_ slurp} -f '%wx%h+%X+%Y')" [ "$?" -eq 0 ] && \ ${_ imagemagick} "$FILENAME" -crop "$DIMENSIONS" - | \ ${wl-clipboard}/bin/wl-copy -t image/png kill $IMV_PROC exec rm "$FILENAME" ''; in { home.packages = [ toggleOption ]; wayland.windowManager.hyprland = let c = builtins.mapAttrs (_: t: "0xFF${t}") theme; inherit (cfg) mainMod; activeBorder = "${c.peach} ${c.mauve} 45deg"; transparent = "0x00000000"; in { enable = true; package = osConfig.programs.hyprland.package; plugins = [ inputs.hy3.packages.${pkgs.system}.hy3 ]; settings = { exec-once = lib.optional (!osConfig.my.fs.luks.enable) "${pkgs.writeShellScript "start-hyprland" '' [ -n "$GREETD_SOCK" ] && ${pkgs.swaylock-effects}/bin/swaylock ${ lib.optionalString cfg.wallpaper.enable "-i ${cfg.wallpaper.image}" } & ''}"; env = [ ] ++ lib.optional config.my.graphical.emacs.enable "VISUAL, emacsclient -c"; monitor = [ "eDP-1, preferred, 0x0, 1.33" ", preferred, auto, 1" # Manually reserved area for bar ", addreserved, 42, 0, 0, 0" ]; input = { kb_layout = "us"; kb_options = "numpad:mac"; repeat_delay = 300; repeat_rate = 20; float_switch_override_focus = 2; touchpad = { natural_scroll = true; scroll_factor = 0.3; }; }; general = { layout = "hy3"; allow_tearing = cfg.tearing; gaps_in = 5; gaps_out = 13; border_size = 3; "col.active_border" = activeBorder; "col.inactive_border" = transparent; }; dwindle = { force_split = 2; preserve_split = true; special_scale_factor = 0.9; }; decoration = { rounding = 11; dim_special = 0; blur = { enabled = false; size = 8; passes = 2; ignore_opacity = true; xray = true; noise = 0; contrast = 1; brightness = 1; }; shadow = { enabled = false; }; }; group = { "col.border_active" = activeBorder; "col.border_inactive" = transparent; "col.border_locked_active" = c.red; "col.border_locked_inactive" = transparent; groupbar = { render_titles = false; height = 3; "col.active" = c.green; "col.inactive" = transparent; "col.locked_active" = c.red; "col.locked_inactive" = transparent; }; }; animations = { enabled = true; bezier = [ "easeInSine, 0.12, 0, 0.39, 0" "easeOutSine, 0.61, 1, 0.88, 1" ]; animation = [ "windowsIn, true, 2, easeOutSine, slide" "windowsOut, true, 2, easeInSine, slide" "windowsMove, true, 1.5, easeOutSine, slide" "workspaces, true, 1, easeOutSine, slide" "specialWorkspace, true, 3, default, slidevert" "fade, 0" ]; }; gestures = { workspace_swipe = true; }; binds = { allow_workspace_cycles = true; }; xwayland = { use_nearest_neighbor = false; force_zero_scaling = true; }; misc = { vrr = 1; disable_hyprland_logo = true; disable_splash_rendering = true; background_color = c.crust; disable_autoreload = true; focus_on_activate = true; animate_manual_resizes = false; animate_mouse_windowdragging = false; new_window_takes_over_fullscreen = 2; enable_swallow = false; swallow_regex = "^(foot(client)?|kitty)$"; }; plugin.hy3 = { # NOTE: only needed for the interaction with tab bars no_gaps_when_only = 1; group_inset = 16; tabs = { render_text = false; height = 8; rounding = 4; "col.active" = c.green; "col.urgent" = c.maroon; "col.inactive" = transparent; }; }; workspace = [ "s[false] w[t1], gapsout:0" "s[false] f[1], gapsout:0" "s[true], gapsout:50, gapsin:20" ]; windowrulev2 = [ "noborder, onworkspace:s[false] w[t1], floating:false" "norounding, onworkspace:s[false] w[t1], floating:false" "noborder, onworkspace:s[false] f[1], floating:false" "norounding, onworkspace:s[false] f[1], floating:false" "tile, class:^(Aseprite)$" "fullscreen, class:^(Baba Is You|ADanceOfFireAndIce)$" "float, class:^(EverestSplash-linux)$" "float, title:^(emacs-everywhere)$" "float, class:^(Eddie)$, title:^$" "float, class:^(firefox)$, title:^(Picture-in-Picture)$" "pin, class:^(firefox)$, title:^(Picture-in-Picture)$" "tile, class:^(Spotify)$, title:^(?!Ozone X11$).*$" "float, class:^(Spotify)$, title:^$" ] ++ lib.optional cfg.tearing "immediate, class:^(ADanceOfFireAndIce|Celeste|hollow_knight\\.x86_64|portal2_linux)$"; layerrule = [ "noanim, ^(notifications)$" ]; bind = [ "${mainMod}, Return, exec, foot" "${mainMod}, C, hy3:killactive," "${mainMod} SHIFT, C, exec, hyprctl activewindow -j | ${pkgs.jaq}/bin/jaq -r '.pid' | xargs kill -9" "${mainMod}, E, exec, nautilus" "${mainMod}, M, exec, emacsclient -c" "${mainMod} SHIFT, M, exec, emacsclient -e '(emacs-everywhere)'" "${mainMod} SHIFT, Return, togglefloating," "${mainMod}, Space, fullscreen, 1" "${mainMod} SHIFT, Space, fullscreen, 0" "${mainMod}, I, exec, dunstctl action" "${mainMod} SHIFT, I, exec, dunstctl context" "${mainMod} ALT, I, exec, dunstctl history-pop" "${mainMod} CTRL, I, exec, dunstctl close" "${mainMod}, Semicolon, exec, killall fuzzel || fuzzel" "${mainMod}, Y, pin," "${mainMod}, V, hy3:togglefocuslayer," "${mainMod} CTRL, V, hy3:warpcursor" # Change ephemeralness (I think that is a word) "${mainMod}, Grave, hy3:setephemeral, true" "${mainMod} SHIFT, Grave, hy3:setephemeral, false" # Tabs "${mainMod}, B, hy3:focustab, l, wrap" "${mainMod}, F, hy3:focustab, r, wrap" "${mainMod} SHIFT, F, hy3:changegroup, toggletab" "${mainMod} CTRL, F, hy3:makegroup, tab, ephemeral" # Directions "${mainMod}, Period, hy3:makegroup, h, ephemeral" "${mainMod}, Comma, hy3:makegroup, v, ephemeral" "${mainMod}, S, hy3:changegroup, opposite" # Moving windows "${mainMod} SHIFT, Left, hy3:movewindow, l, once, visible" "${mainMod} SHIFT, Right, hy3:movewindow, r, once, visible" "${mainMod} SHIFT, Up, hy3:movewindow, u, once, visible" "${mainMod} SHIFT, Down, hy3:movewindow, d, once, visible" "${mainMod} SHIFT, H, hy3:movewindow, l, once, visible" "${mainMod} SHIFT, L, hy3:movewindow, r, once, visible" "${mainMod} SHIFT, K, hy3:movewindow, u, once, visible" "${mainMod} SHIFT, J, hy3:movewindow, d, once, visible" # Moving windows (within groups) "${mainMod} ALT, Left, hy3:movewindow, l, once" "${mainMod} ALT, Right, hy3:movewindow, r, once" "${mainMod} ALT, Up, hy3:movewindow, u, once" "${mainMod} ALT, Down, hy3:movewindow, d, once" "${mainMod} ALT, H, hy3:movewindow, l, once" "${mainMod} ALT, L, hy3:movewindow, r, once" "${mainMod} ALT, K, hy3:movewindow, u, once" "${mainMod} ALT, J, hy3:movewindow, d, once" # Workspaces "${mainMod} CTRL, P, focusworkspaceoncurrentmonitor, previous" "${mainMod} CTRL, N, focusworkspaceoncurrentmonitor, empty" "${mainMod} CTRL SHIFT, P, hy3:movetoworkspace, previous" "${mainMod} CTRL SHIFT, N, hy3:movetoworkspace, empty" # Screenshot ", Print, exec, ${copyOutput}" "ALT, Print, exec, ${copyWindow}" "${mainMod} SHIFT, S, exec, grim -g \"$(slurp)\" - | wl-copy -t image/png" # Move focus "${mainMod}, Left, hy3:movefocus, l, visible" "${mainMod}, Right, hy3:movefocus, r, visible" "${mainMod}, Up, hy3:movefocus, u, visible" "${mainMod}, Down, hy3:movefocus, d, visible" "${mainMod}, H, hy3:movefocus, l, visible" "${mainMod}, L, hy3:movefocus, r, visible" "${mainMod}, K, hy3:movefocus, u, visible" "${mainMod}, J, hy3:movefocus, d, visible" # Change focus "${mainMod}, U, hy3:changefocus, raise" "${mainMod}, D, hy3:changefocus, lower" "${mainMod} SHIFT, U, hy3:changefocus, top" # Switch workspaces with mainMod + [1-9] "${mainMod}, 1, focusworkspaceoncurrentmonitor, 1" "${mainMod}, 2, focusworkspaceoncurrentmonitor, 2" "${mainMod}, 3, focusworkspaceoncurrentmonitor, 3" "${mainMod}, 4, focusworkspaceoncurrentmonitor, 4" "${mainMod}, 5, focusworkspaceoncurrentmonitor, 5" "${mainMod}, 6, focusworkspaceoncurrentmonitor, 6" "${mainMod}, 7, focusworkspaceoncurrentmonitor, 7" "${mainMod}, 8, focusworkspaceoncurrentmonitor, 8" "${mainMod}, 9, focusworkspaceoncurrentmonitor, 9" # Switch workspaces with mainMod + N/P/O "${mainMod}, N, focusworkspaceoncurrentmonitor, e+1" "${mainMod}, P, focusworkspaceoncurrentmonitor, e-1" "${mainMod} SHIFT, N, hy3:movetoworkspace, e+1" "${mainMod} SHIFT, P, hy3:movetoworkspace, e-1" # Move active window to a workspace with mainMod + SHIFT + [1-9] "${mainMod} SHIFT, 1, hy3:movetoworkspace, 1" "${mainMod} SHIFT, 2, hy3:movetoworkspace, 2" "${mainMod} SHIFT, 3, hy3:movetoworkspace, 3" "${mainMod} SHIFT, 4, hy3:movetoworkspace, 4" "${mainMod} SHIFT, 5, hy3:movetoworkspace, 5" "${mainMod} SHIFT, 6, hy3:movetoworkspace, 6" "${mainMod} SHIFT, 7, hy3:movetoworkspace, 7" "${mainMod} SHIFT, 8, hy3:movetoworkspace, 8" "${mainMod} SHIFT, 9, hy3:movetoworkspace, 9" # Scroll through existing workspaces with mainMod + scroll/side buttons "${mainMod}, mouse_down, focusworkspaceoncurrentmonitor, e-1" "${mainMod}, mouse_up, focusworkspaceoncurrentmonitor, e+1" "${mainMod}, mouse:275, focusworkspaceoncurrentmonitor, e-1" "${mainMod}, mouse:276, focusworkspaceoncurrentmonitor, e+1" # Scratchpads "${mainMod} SHIFT, 0, hy3:movetoworkspace, special:a" "${mainMod}, 0, togglespecialworkspace, a" "${mainMod} SHIFT, Minus, hy3:movetoworkspace, special:b" "${mainMod}, Minus, togglespecialworkspace, b" "${mainMod} SHIFT, Equal, hy3:movetoworkspace, special:c" "${mainMod}, Equal, togglespecialworkspace, c" "${mainMod}, Q, exec, ${cfg.lockBinary}" "${mainMod}, T, exec, ${toggleOption}/bin/hypr-toggle-opt input:touchpad:disable_while_typing" ]; bindn = [ # Unfocus everything on escape ", Escape, hy3:changefocus, bottom" # Click on hy3 tabs ", mouse:272, hy3:focustab, mouse" ]; bindl = [ "${mainMod} SHIFT, Q, exit," ", XF86AudioMute, exec, dunst-volume set-mute toggle" ]; binde = [ # Resize windows "${mainMod} CTRL ALT, Left, resizeactive, -10 0" "${mainMod} CTRL ALT, Right, resizeactive, 10 0" "${mainMod} CTRL ALT, Up, resizeactive, 0 -10" "${mainMod} CTRL ALT, Down, resizeactive, 0 10" "${mainMod} CTRL ALT, H, resizeactive, -10 0" "${mainMod} CTRL ALT, L, resizeactive, 10 0" "${mainMod} CTRL ALT, K, resizeactive, 0 -10" "${mainMod} CTRL ALT, J, resizeactive, 0 10" # Move floating windows "${mainMod} CTRL, Left, moveactive, -50 0" "${mainMod} CTRL, Right, moveactive, 50 0" "${mainMod} CTRL, Up, moveactive, 0 -50" "${mainMod} CTRL, Down, moveactive, 0 50" "${mainMod} CTRL, H, moveactive, -50 0" "${mainMod} CTRL, L, moveactive, 50 0" "${mainMod} CTRL, K, moveactive, 0 -50" "${mainMod} CTRL, J, moveactive, 0 50" ]; bindm = [ # Move/resize windows with mainMod + LMB/RMB and dragging "${mainMod}, mouse:272, movewindow" "${mainMod}, mouse:273, resizewindow" ]; bindel = [ # Media keys ", XF86AudioRaiseVolume, exec, dunst-volume set-volume 5%+" ", XF86AudioLowerVolume, exec, dunst-volume set-volume 5%-" ", XF86MonBrightnessDown, exec, dunst-brightness 5%+" ", XF86MonBrightnessUp, exec, dunst-brightness 5%-" ]; }; extraConfig = '' # Passthrough mode bind = ${mainMod}, Escape, submap, passthrough submap = passthrough bind = ${mainMod}, Escape, submap, reset submap = reset # OBS bind = ${mainMod} CTRL, O, submap, OBS submap = OBS bind = , Space, pass, ^(com\.obsproject\.Studio)$ bind = , P, pass, ^(com\.obsproject\.Studio)$ bind = , Escape, submap, reset bind = ${mainMod}, Escape, submap, reset submap = reset ''; }; systemd.user.services = lib.mkIf cfg.wallpaper.enable { hyprpaper = lib.mkIf (cfg.wallpaper.backend == "hyprpaper") { Unit = { Description = "Background wallpaper image via hyprpaper"; After = "hyprland-session.target"; }; Service = { ExecStart = let hyprpaperConfig = pkgs.writeText "hyprpaper.conf" '' preload = ${cfg.wallpaper.image} wallpaper = ,${cfg.wallpaper.image} ipc = off splash = off ''; in "${pkgs.hyprpaper}/bin/hyprpaper -c ${hyprpaperConfig}"; }; Install = { WantedBy = [ "hyprland-session.target" ]; }; }; swaybg = lib.mkIf (cfg.wallpaper.backend == "swaybg") { Unit = { Description = "Background wallpaper image via swaybg"; After = "hyprland-session.target"; }; Service = { ExecStart = "${pkgs.swaybg}/bin/swaybg -i ${cfg.wallpaper.image} -m fill -o '*'"; }; Install = { WantedBy = [ "hyprland-session.target" ]; }; }; }; }); }