{ config, inputs, lib, pkgs, ... }: with lib; let cfg = config.myOptions.programs.hypr.land; inherit (config.myOptions.other.system) username; hmCfg = config.home-manager.users.${username}; isAmdGpuPresent = elem "amdgpu" config.boot.initrd.kernelModules; smwPresent = elem inputs.split-monitor-workspaces.packages.${pkgs.system}.split-monitor-workspaces cfg.extraPlugins; inherit (inputs.nixpkgs-wayland.packages.${pkgs.system}) foot wl-clipboard swww wlsunset; inherit (inputs.anyrun.packages.${pkgs.system}) anyrun; hyprcontrib = inputs.hyprcontrib.packages.${pkgs.system}; inherit (inputs.shadower.packages.${pkgs.system}) shadower; inherit (inputs.hyprland.packages.${pkgs.system}) hyprland; inherit (inputs.hyprlock.packages.${pkgs.system}) hyprlock; inherit (inputs.waybar.packages.${pkgs.system}) waybar; in { options.myOptions.programs.hypr.land = { enable = mkEnableOption "hiper ląd"; startupSound = mkOption { type = with types; nullOr path; description = "sound to play on hyprland startup"; default = null; }; tearing = mkOption { type = types.bool; description = "enable tearing"; default = false; }; extraSettings = mkOption { type = types.attrs; description = "extra per host hyprland settings"; default = {}; }; extraPlugins = mkOption { type = with types; listOf package; description = "extra per host hyprland plugins"; default = []; }; }; disabledModules = [ "programs/hyprland.nix" ]; config = mkIf cfg.enable { nix.settings = { substituters = [ "https://hyprland.cachix.org" ]; trusted-public-keys = [ "hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc=" ]; }; environment.sessionVariables = { XDG_CURRENT_DESKTOP = "Hyprland"; XDG_SESSION_TYPE = "wayland"; XDG_SESSION_DESKTOP = "Hyprland"; SDL_VIDEODRIVER = "wayland"; _JAVA_AWT_WM_NONEREPARENTING = "1"; CLUTTER_BACKEND = "wayland"; GDK_BACKEND = "wayland"; QT_QPA_PLATFORM = "wayland"; LIBSEAT_BACKEND = "logind"; }; xdg.portal = { enable = true; extraPortals = [ pkgs.xdg-desktop-portal-gtk inputs.hyprland.packages.${pkgs.system}.xdg-desktop-portal-hyprland ]; # TODO look into and make use of this config.common.default = "*"; }; home-manager.users.${username} = { # TODO swap back to this whenever fufexan or anyone else # adds an equivalent of hm's settings to this module #imports = [ inputs.hyprland.homeManagerModules.default ]; xdg.dataFile = mkIf (cfg.startupSound != null) { "hypr/startup_sound".source = cfg.startupSound; }; wayland.windowManager.hyprland = { enable = true; package = inputs.hyprland.packages.${pkgs.system}.hyprland; #portalPackage = inputs.hyprland.packages.${pkgs.system}.xdg-desktop-portal-hyprland; plugins = [ inputs.hyprland-plugins.packages.${pkgs.system}.csgo-vulkan-fix ] ++ cfg.extraPlugins; # TODO make these work with the config below (infinite recursion) # and make this file stop hanging my neovim every 2 seconds # and figure out why it triggers E79 every single time I edit something extraConfig = '' bind=$mainMod, W, exec, ${removeSuffix " %U" hmCfg.xdg.desktopEntries.firefox-schizo.exec} bind=$mainMod SHIFT, W, exec, ${removeSuffix " %U" hmCfg.xdg.desktopEntries.firefox-unschizo.exec} ${if (cfg.startupSound != null) then "exec-once=${pkgs.mpv}/bin/mpv --no-video --volume=100 ${hmCfg.xdg.dataHome}/hypr/startup_sound" else ""} ''; settings = { "$mainMod" = "SUPER"; monitor = [ # laptop "eDP-1, 2560x1440@165, 0x0, 1" # second monitor "HDMI-A-1, 2560x1440@144, 2560x0, 1" ]; workspace = [ # laptop "1, monitor:eDP-1, default:true" "2, monitor:eDP-1" "3, monitor:eDP-1" "4, monitor:eDP-1" "5, monitor:eDP-1" "6, monitor:eDP-1" "7, monitor:eDP-1" "8, monitor:eDP-1" "9, monitor:eDP-1" "10, monitor:eDP-1" # second monitor "11, monitor:HDMI-A-1, default:true" "12, monitor:HDMI-A-1" "13, monitor:HDMI-A-1" "14, monitor:HDMI-A-1" "15, monitor:HDMI-A-1" "16, monitor:HDMI-A-1" "17, monitor:HDMI-A-1" "18, monitor:HDMI-A-1" "19, monitor:HDMI-A-1" "20, monitor:HDMI-A-1" # scratchpads "special:btop, decorate:false" (mkIf isAmdGpuPresent "special:amdgpu_top, decorate:false") "special:pipewire, decorate:false" "special:nixos, decorate:false" (mkIf config.services.asusd.enable "special:rog, decorate:false") "special:keepassxc, decorate:false" ]; input = { kb_layout = "pl,ru"; kb_variant = ""; kb_model = ""; kb_options = ""; kb_rules = ""; follow_mouse = true; touchpad = { disable_while_typing = false; }; repeat_rate = 50; repeat_delay = 250; touchdevice = { output = "eDP-1"; }; tablet = { output = "eDP-1"; }; }; general = { sensitivity = 1.0; gaps_in = 5; gaps_out = 5; border_size = 2; apply_sens_to_raw = 0; #no_border_on_floating = true; allow_tearing = mkIf cfg.tearing true; "col.active_border" = "0xFFF5C2E7"; "col.inactive_border" = "0xFF45475A"; #col.group_border_active = "0xFFA6E3A1"; #col.group_border = "0xFF45475A"; }; env = optionals cfg.tearing [ "WLR_DRM_NO_ATOMIC,1" ]; decoration = { rounding = 10; blur = { enabled = true; size = 3; passes = 2; }; drop_shadow = 1; shadow_range = 15; shadow_render_power = 2; shadow_ignore_window = 1; shadow_offset = "2 4"; shadow_scale = 1; "col.shadow" = "0xAF1E1E2E"; }; gestures = { workspace_swipe = 1; workspace_swipe_distance = 200; workspace_swipe_invert = 1; workspace_swipe_min_speed_to_force = 20; workspace_swipe_cancel_ratio = 0.5; }; bezier = [ "dupa, 0.1, 0.9, 0.1, 1.05" ]; animations = { enabled = true; animation = [ "windows, 1, 4, dupa, popin" "windowsOut, 1, 7, dupa, slide" "border, 1, 15, default" "fade, 1, 10, default" "workspaces, 1, 5, dupa, slidevert" ]; }; dwindle = { no_gaps_when_only = true; }; misc = { enable_swallow = false; swallow_regex = "foot"; focus_on_activate = true; vrr = 1; vfr = true; animate_manual_resizes = false; animate_mouse_windowdragging = false; force_default_wallpaper = 0; }; windowrulev2 = [ "float, class:^(Tor Browser)$" "float, class:^(Mullvad Browser)$" "float, class:^(foot)$" "float, class:^(mpv)$" "float, class:^(imv)$" "float, class:^(Vieb)$" "float, title:^(Picture-in-Picture)$" "float, title:^(.*)(Choose User Profile)(.*)$" "float, title:^(blob:null/)(.*)$" "float, class:^(xdg-desktop-portal-gtk)$" "float, class:^(code), title: ^(Open*)" "size 70% 70%, class:^(code), title: ^(Open*)" "center, class: ^(code), title: ^(Open*)" "float, class:^(org.keepassxc.KeePassXC)$" (mkIf config.services.asusd.enable "size 960 670, title:^(ROG Control Center)$") (mkIf cfg.tearing "immediate, class:^(osu!)$") ]; bind = [ "$mainMod, RETURN, exec, ${foot}/bin/${if config.myOptions.programs.foot.server then "footclient" else "foot"}" "$mainMod, Q, killactive" "$mainMod, F, fullscreen, 0" "$mainMod, M, fullscreen, 1" "$mainMod, D, exec, ${pkgs.procps}/bin/pkill anyrun || ${anyrun}/bin/anyrun" "$mainMod, SPACE, togglefloating, active" "$mainMod SHIFT, C, centerwindow" "$mainMod CONTROL, R, bringactivetotop" "$mainMod SHIFT, P, pin" # workspaces "$mainMod, 1, ${if smwPresent then "split-" else ""}workspace, 1" "$mainMod, 2, ${if smwPresent then "split-" else ""}workspace, 2" "$mainMod, 3, ${if smwPresent then "split-" else ""}workspace, 3" "$mainMod, 4, ${if smwPresent then "split-" else ""}workspace, 4" "$mainMod, 5, ${if smwPresent then "split-" else ""}workspace, 5" "$mainMod, 6, ${if smwPresent then "split-" else ""}workspace, 6" "$mainMod, 7, ${if smwPresent then "split-" else ""}workspace, 7" "$mainMod, 8, ${if smwPresent then "split-" else ""}workspace, 8" "$mainMod, 9, ${if smwPresent then "split-" else ""}workspace, 9" "$mainMod, 0, ${if smwPresent then "split-" else ""}workspace, 10" "$mainMod SHIFT, 1, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 1" "$mainMod SHIFT, 2, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 2" "$mainMod SHIFT, 3, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 3" "$mainMod SHIFT, 4, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 4" "$mainMod SHIFT, 5, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 5" "$mainMod SHIFT, 6, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 6" "$mainMod SHIFT, 7, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 7" "$mainMod SHIFT, 8, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 8" "$mainMod SHIFT, 9, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 9" "$mainMod SHIFT, 0, ${if smwPresent then "split-" else ""}movetoworkspacesilent, 10" # screenshots "$mainMod, S, exec, ${hyprcontrib.grimblast}/bin/grimblast save area - | ${pkgs.coreutils-full}/bin/tee \"$(${pkgs.xdg-user-dirs}/bin/xdg-user-dir PICTURES)/Screenshots/$(date +'screenshot-%Y%m%d%H%M%S.png')\" | ${wl-clipboard}/bin/wl-copy && ${pkgs.libnotify}/bin/notify-send \"Screenshot taken\"" "$mainMod SHIFT, S, exec, ${hyprcontrib.grimblast}/bin/grimblast save area - | ${shadower}/bin/shadower | ${pkgs.coreutils-full}/bin/tee \"$(${pkgs.xdg-user-dirs}/bin/xdg-user-dir PICTURES)/Screenshots/$(date +'screenshot-%Y%m%d%H%M%S.png')\" | ${wl-clipboard}/bin/wl-copy && ${pkgs.libnotify}/bin/notify-send \"Screenshot taken (shadower)\"" "$mainMod CONTROL, S, exec, ${hyprcontrib.grimblast}/bin/grimblast save area - | ${pkgs.swappy}/bin/swappy -f - -o - | ${pkgs.coreutils-full}/bin/tee \"$(${pkgs.xdg-user-dirs}/bin/xdg-user-dir PICTURES)/Screenshots/$(date +'screenshot-%Y%m%d%H%M%S.png')\" | ${wl-clipboard}/bin/wl-copy && ${pkgs.libnotify}/bin/notify-send \"Screenshot taken\"" "$mainMod SHIFT CONTROL, S, exec, ${hyprcontrib.grimblast}/bin/grimblast save area - | ${pkgs.swappy}/bin/swappy -f - -o - | ${shadower}/bin/shadower | ${pkgs.coreutils-full}/bin/tee \"$(${pkgs.xdg-user-dirs}/bin/xdg-user-dir PICTURES)/Screenshots/$(date +'screenshot-%Y%m%d%H%M%S.png')\" | ${wl-clipboard}/bin/wl-copy && ${pkgs.libnotify}/bin/notify-send \"Screenshot taken (shadower)\"" "$mainMod SHIFT, R, exec, ${hyprland}/bin/hyprctl reload" (mkIf config.services.asusd.enable ", XF86Launch3, exec, ${config.services.asusd.package}/bin/asusctl led-mode -n") (mkIf config.services.asusd.enable ", XF86Launch4, exec, ${config.services.asusd.package}/bin/asusctl profile -n") # TODO what the fuck is this ", XF86TouchpadToggle, exec, " # TODO fix this maybe "$mainMod, T, exec, grim -g \"$(slurp)\" -t ppm - | tesseract -l pol - - | wl-copy && notify-send \"Copied text: \" \"\\\"$(wl-paste)\\\"\"" # TODO fix this "$mainMod, SEMICOLON, exec, ~/.config/rofi/powermenu/type-2/powermenu.sh" "$mainMod, G, togglegroup" # this sometimes fixes the portal "$mainMod CONTROL, K, exec, ${pkgs.systemd}/bin/systemctl --user restart xdg-desktop-portal-hyprland" "$mainMod SHIFT, K, exec, ${hyprland}/bin/hyprctl kill" # scratchpad binds "$mainMod, B, togglespecialworkspace, btop" (mkIf isAmdGpuPresent "$mainMod, A, togglespecialworkspace, amdgpu_top") "$mainMod, V, togglespecialworkspace, pipewire" "$mainMod, N, togglespecialworkspace, nixos" # rog button on laptop keyboard (mkIf config.services.asusd.enable ", XF86Launch1, togglespecialworkspace, rog") (mkIf config.services.asusd.enable "$mainMod, R, togglespecialworkspace, rog") "$mainMod, X, togglespecialworkspace, keepassxc" "$mainMod, C, exec, ${hyprlock}/bin/hyprlock" # toggle waybar "$mainMod CONTROL, B, exec, ${pkgs.procps}/bin/pkill waybar || ${waybar}/bin/waybar" "$mainMod CONTROL, minus, exec, ${hyprland}/bin/hyprctl keyword misc:cursor_zoom_factor 2" "$mainMod CONTROL, apostrophe, exec, ${hyprland}/bin/hyprctl keyword misc:cursor_zoom_factor 1" ]; # repeat binde = [ # window focus "$mainMod, J, movefocus, d" "$mainMod, K, movefocus, u" # monitor focus "$mainMod, H, focusmonitor, l" "$mainMod, L, focusmonitor, r" # keyboard brightness (mkIf config.services.asusd.enable ", XF86KbdBrightnessUp, exec, ${config.services.asusd.package}/bin/asusctl -n") (mkIf config.services.asusd.enable ", XF86KbdBrightnessDown, exec, ${config.services.asusd.package}/bin/asusctl -p") "$mainMod SHIFT, G, changegroupactive, f" "$mainMod CONTROL, G, changegroupactive, b" "$mainMod, minus, exec, ${hyprland}/bin/hyprctl keyword misc:cursor_zoom_factor \"$(${hyprland}/bin/hyprctl getoption misc:cursor_zoom_factor | rg float | awk '{print $2 + 0.05}')\"" "$mainMod, apostrophe, exec, ${hyprland}/bin/hyprctl keyword misc:cursor_zoom_factor \"$(${hyprland}/bin/hyprctl getoption misc:cursor_zoom_factor | rg float | awk '{if($2 != 1) {print $2 - 0.05}}')\"" ]; # locked bindl = let play-pause = "${pkgs.playerctl}/bin/playerctl play-pause"; stop = "${pkgs.playerctl}/bin/playerctl stop"; prev = "${pkgs.playerctl}/bin/playerctl previous"; next = "${pkgs.playerctl}/bin/playerctl next"; toggle-mute = "${pkgs.pamixer}/bin/pamixer --toggle-mute"; in [ ", XF86AudioMedia, exec, ${play-pause}" ", XF86AudioPlay, exec, ${play-pause}" "$mainMod, Y, exec, ${play-pause}" ", XF86AudioStop, exec, ${stop}" "$mainMod, U, exec, ${stop}" ", XF86AudioPrev, exec, ${prev}" "$mainMod, I, exec, ${prev}" ", XF86AudioNext, exec, ${next}" "$mainMod, O, exec, ${next}" ", XF86AudioMute, exec, ${toggle-mute}" "$mainMod, P, exec, ${toggle-mute}" ]; # locked + repeat bindle = let brightness_up = "${pkgs.brightnessctl}/bin/brightnessctl set +5%"; brightness_down = "${pkgs.brightnessctl}/bin/brightnessctl set 5%-"; volume_up = "${pkgs.pamixer}/bin/pamixer -ui 5"; volume_down = "${pkgs.pamixer}/bin/pamixer -ud 5"; in [ # TODO integrate the scripts from https://codeberg.org/jacekpoz/dotconfig/src/branch/master/Scripts ", XF86MonBrightnessUp, exec, ${brightness_up}" "$mainMod SHIFT, Z, exec, ${brightness_up}" ", XF86MonBrightnessDown, exec, ${brightness_down}" "$mainMod SHIFT, X, exec, ${brightness_down}" ", XF86AudioRaiseVolume, exec, ${volume_up}" "$mainMod SHIFT, C, exec, ${volume_up}" ", XF86AudioLowerVolume, exec, ${volume_down}" "$mainMod SHIFT, V, exec, ${volume_down}" ]; # mouse bindm = [ "$mainMod, mouse:272, movewindow" "$mainMod, mouse:273, resizewindow" ]; binds = { pass_mouse_when_bound = false; movefocus_cycles_fullscreen = false; }; exec-once = let # https://wiki.hyprland.org/IPC/#how-to-use-socket2-with-bash handle_hyprland_events = pkgs.writeShellScriptBin "handle_hyprland_events" '' #!/bin/sh handle() { case $1 in configreloaded*) ${hyprland}/bin/hyprctl notify 1 2500 "" " Reloading Hyprland..." ;; esac } ${pkgs.socat}/bin/socat -U - UNIX-CONNECT:/tmp/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock | while read -r line; do handle "$line" done ''; in [ "${waybar}/bin/waybar" # run persistent special workspace windows "[workspace special:nixos silent;tile] cd ~/niksos; ${foot}/bin/foot" (mkIf config.services.asusd.enable "[workspace special:rog silent;tile] ${config.services.asusd.package}/bin/rog-control-center") "[workspace special:keepassxc silent;tile] ${pkgs.keepassxc}/bin/keepassxc" (if config.myOptions.programs.foot.server then "sleep 0.5 && ${pkgs.systemd}/bin/systemctl --user restart foot.service" else ";") "${hyprland}/bin/hyprctl setcursor Bibata-Modern-Classic 24" # TODO do something with this #"${wl-clipboard}/bin/wl-paste --watch cliphist store" "${swww}/bin/swww init" "${wlsunset}/bin/wlsunset -S 06:00 -s 20:00" # TODO fix fcitx5 #"fcitx5" # TODO do these do anything anymore "${pkgs.systemd}/bin/systemctl --user import-environment WAYLAND_DISPLAY XDG_CURRENT_DESKTOP" "${pkgs.dbus}/bin/dbus-update-activation-environment --systemd WAYLAND_DISPLAY XDG_CURRENT_DESKTOP=$XDG_CURRENT_DESKTOP" "${handle_hyprland_events}/bin/handle_hyprland_events" ]; exec = [ # kill (almost) everything on special workspaces "${pkgs.procps}/bin/pkill btop" (mkIf isAmdGpuPresent "${pkgs.procps}/bin/pkill amdgpu_top") "${pkgs.procps}/bin/pkill helvum" "${pkgs.procps}/bin/pkill pavucontrol" # and run it all again "[workspace special:btop silent;tile] ${foot}/bin/foot -e ${pkgs.btop}/bin/btop" (mkIf isAmdGpuPresent "[workspace special:amdgpu_top silent;tile] ${foot}/bin/foot -e ${pkgs.amdgpu_top}/bin/amdgpu_top -i 0") (mkIf isAmdGpuPresent "[workspace special:amdgpu_top silent;tile] ${foot}/bin/foot -e ${pkgs.amdgpu_top}/bin/amdgpu_top -i 1") "[workspace special:pipewire silent;tile] ${pkgs.helvum}/bin/helvum" "[workspace special:pipewire silent;tile] ${pkgs.pavucontrol}/bin/pavucontrol" # wait a bit then set the wallpapers "sleep 0.5 && ${swww}/bin/swww img -o eDP-1 ${./catppuccin-wall0.png}" "sleep 0.5 && ${swww}/bin/swww img -o HDMI-A-1 ${./catppuccin-wall1.png}" "${pkgs.networkmanagerapplet}/bin/nm-applet --indicator" "${pkgs.blueman}/bin/blueman-applet" ]; layerrule = [ # no black border on grimblast screenshots "noanim, ^(selection)$" "blur, ^(waybar)$" "blur, ^(eww)$" # TODO maybe this isn't needed # temporary fix to swaylock screenshoting rofi before locking #"noanim, ^(rofi)$" "blur, ^(anyrun)$" ]; plugin = { csgo-vulkan-fix = { res_w = 2560; res_h = 1440; }; split-monitor-workspaces = { count = 10; keep_focused = true; }; }; } // cfg.extraSettings; }; }; }; }