{ lib, pkgs, config, inputs, ... }: # Hyprland config migrated from github.com/darman96/hyprland-dotfiles (the # hyprlang `hypr/*.conf` files) into the home-manager lua-style `settings` # (configType defaults to "lua" on stateVersion 26.05). Each top-level # `settings` attr becomes an `hl.(...)` call in ~/.config/hypr/hyprland.lua; # `_args` lists become multi-arg calls, `_var` locals become `local x = ...`, and # `lib.generators.mkLuaInline` values render as raw Lua expressions. # # Imported by home.nix. System-level Hyprland enable (session entry, portals) # lives in ../../services/desktop/desktop-hyprland.nix; this manages the user's # own hyprland.lua. # # Deliberately NOT migrated: # - hyprbars.conf: config for the third-party `hyprbevelbars` plugin, which # isn't packaged in nixpkgs. Load it via # `wayland.windowManager.hyprland.plugins` and re-add its config once # available. (hyprredsquare.conf's plugin was renamed hypr-chrome and # rewritten since - it's wired in below via the `hypr-chrome` flake # input instead, with its own `plugin.hyprchrome` config.) # - hyprqt6engine.conf + `QT_QPA_PLATFORMTHEME=hyprqt6engine`: terra themes Qt # through qtct/Dracula in home.nix, so that env var is left off to avoid a conflict. # - hyprlock.conf: a separate program (use `programs.hyprlock` if wanted). # - the duplicate pamixer/amixer + `.wob` volume binds: kept only the clean # pipewire `wpctl`/`playerctl` set (no wob overlay is configured here). # - `XDG_MENU_PREFIX=arch-` and `VCPKG_ROOT`: Arch-/user-specific. # Many binds reference apps/scripts not packaged on terra yet (vivaldi-stable, # dolphin, vicinae, grimblast, waypaper, discord, gitkraken, qbz, # ~/.config/scripts/start-communications.sh); add them separately. let lua = lib.generators.mkLuaInline; # Wallpaper images aren't checked into this repo (binary blobs) — pulled # from the existing Wallhaven library on /mnt/hdd_01 instead. Picked once # here rather than at runtime, since hyprpaper has no built-in "random" # mode; re-pick and rebuild (or swap in real per-monitor selection) when # this stops being a placeholder. wallpaper = "/mnt/hdd_01/data/Pictures/Wallhaven/wallhaven-4yjyd4.png"; # Dispatchers → the new hl.dsp.* API (signatures verified against hyprland # 0.55's src/config/lua/bindings/LuaBindingsDispatchers.cpp). dsp = { exec = cmd: lua ''hl.dsp.exec_cmd("${cmd}")''; global = name: lua ''hl.dsp.global("${name}")''; exit = lua "hl.dsp.exit()"; killactive = lua "hl.dsp.window.close()"; togglefloating = lua ''hl.dsp.window.float({ action = "toggle" })''; fullscreen = lua "hl.dsp.window.fullscreen()"; # mode 0 maximize = lua ''hl.dsp.window.fullscreen({ mode = "maximized" })''; # mode 1 togglegroup = lua "hl.dsp.group.toggle()"; changegroupactive = lua "hl.dsp.group.next()"; drag = lua "hl.dsp.window.drag()"; resizemouse = lua "hl.dsp.window.resize()"; movefocus = dir: lua ''hl.dsp.focus({ direction = "${dir}" })''; movewindow = dir: lua ''hl.dsp.window.move({ direction = "${dir}" })''; resizeactive = x: y: lua ''hl.dsp.window.resize({ x = ${toString x}, y = ${toString y}, relative = true })''; workspace = n: lua ''hl.dsp.focus({ workspace = ${toString n} })''; workspaceRef = s: lua ''hl.dsp.focus({ workspace = "${s}" })''; movetoworkspace = n: lua ''hl.dsp.window.move({ workspace = ${toString n} })''; togglespecial = name: lua ''hl.dsp.workspace.toggle_special("${name}")''; }; bind = keys: dispatcher: { _args = [ keys dispatcher ]; }; bindo = keys: dispatcher: opts: { _args = [ keys dispatcher opts ]; }; # SUPER + 1..9 → workspaces 1..9, SUPER + 0 → workspace 10. wsKeys = [ { k = "1"; n = 1; } { k = "2"; n = 2; } { k = "3"; n = 3; } { k = "4"; n = 4; } { k = "5"; n = 5; } { k = "6"; n = 6; } { k = "7"; n = 7; } { k = "8"; n = 8; } { k = "9"; n = 9; } { k = "0"; n = 10; } ]; in { services.hyprpaper = { enable = true; settings = { ipc = "on"; splash = false; preload = [ wallpaper ]; wallpaper = [ { monitor = "DP-2"; path = wallpaper; } { monitor = "HDMI-A-1"; path = wallpaper; } ]; }; }; wayland.windowManager.hyprland = { enable = true; plugins = [ inputs.hypr-chrome.packages.${pkgs.stdenv.hostPlatform.system}.default ]; settings = { # ---- colours (from colors.conf) ---- fg_color = { _var = "rgba(eeeeeeff)"; }; fg_accent = { _var = "rgba(ffd063ff)"; }; fg_accent_alt = { _var = "rgba(ff9d42ff)"; }; bg_color = { _var = "rgba(0f1012ff)"; }; bg_accent = { _var = "rgba(963c38ff)"; }; # ---- monitors ---- monitor = [ { output = "DP-2"; mode = "2560x1440@144"; position = "1920x0"; scale = 1; } { output = "HDMI-A-1"; mode = "1920x1080@60"; position = "0x360"; scale = 1; } ]; # ---- variables (general/decoration/input/misc/...) ---- config = { input = { kb_layout = "de"; numlock_by_default = true; follow_mouse = 1; sensitivity = 0; }; debug.disable_logs = false; general = { border_size = 0; col = { inactive_border = lua "bg_accent"; active_border = { colors = [ (lua "fg_accent") (lua "fg_accent_alt") ]; angle = 45; }; }; layout = "dwindle"; gaps_in = 4; gaps_out = 8; }; decoration = { dim_special = 0.3; rounding = 10; blur = { enabled = true; special = true; # blur behind the special workspace size = 6; passes = 2; ignore_opacity = true; }; shadow.enabled = false; active_opacity = 0.9; inactive_opacity = 0.9; }; animations.enabled = true; misc = { close_special_on_empty = true; disable_hyprland_logo = true; disable_splash_rendering = true; }; binds = { hide_special_on_workspace_change = true; workspace_back_and_forth = true; allow_workspace_cycles = true; }; plugin.hyprchrome = { enabled = true; glow_size = 12; glow_strength = 0.85; shadow_size = 24; shadow_color = lua "bg_color"; shadow_offset = lua "{ 4, 8 }"; outline_size = lua "2"; outline_color = lua "fg_color"; }; }; # ---- animations ---- # specialWorkspace, enabled, speed 8, default curve, slidefadevert -50% animation = [ { leaf = "specialWorkspace"; enabled = true; speed = 8; bezier = "default"; style = "slidefadevert -50%"; } ]; # ---- environment (environment.conf) ---- env = [ { _args = [ "HYPRCURSOR_THEME" "Bibata-Modern-Classic" ]; } { _args = [ "HYPRCURSOR_SIZE" "24" ]; } { _args = [ "XCURSOR_THEME" "Bibata-Modern-Classic" ]; } { _args = [ "XCURSOR_SIZE" "24" ]; } { _args = [ "GDK_BACKEND" "wayland,x11" ]; } { _args = [ "SDL_VIDEODRIVER" "wayland" ]; } { _args = [ "CLUTTER_BACKEND" "wayland" ]; } { _args = [ "XDG_CURRENT_DESKTOP" "Hyprland" ]; } { _args = [ "XDG_SESSION_DESKTOP" "Hyprland" ]; } { _args = [ "XDG_SESSION_TYPE" "wayland" ]; } { _args = [ "QT_QPA_PLATFORMTHEME" "qt6ct" ]; } ]; # ---- keybinds (keybinds.conf) ---- bind = [ (bindo "SUPER + SUPER_L" (dsp.exec "bash $HOME/.config/quickshell/open_launcher.sh") { release = true; }) (bind "SUPER + Return" (dsp.exec "alacritty")) # quickshell app-launcher variants (evaluating — pick one) ] ++ (map (n: bind "SUPER + CTRL + ${toString n}" (dsp.global "quickshell:launcher${toString n}")) (lib.range 1 7)) ++ [ # restart quickshell (also starts it if not running) (bind "SUPER + CTRL + 0" (dsp.exec "qs kill; sleep 0.3; qs")) # toggle the Slant sidebar (bind "SUPER + CTRL + S" (dsp.global "quickshell:sidebar")) # toggle the host vitals HUD (bind "SUPER + CTRL + V" (dsp.global "quickshell:vitals")) (bind "SUPER + B" (dsp.exec "vivaldi")) (bind "SUPER + E" (dsp.exec "cosmic-files")) (bind "SUPER + SHIFT + G" (dsp.workspaceRef "game")) (bind "SUPER + S" (dsp.exec "grim -o DP-2 ~/screenshot.png")) (bind "SUPER + SHIFT + S" (dsp.exec "grimblast copy area --freeze")) (bind "Print" (dsp.exec "rishot")) (bind "SUPER + L" (dsp.exec "hyprlock")) (bind "SUPER + W" (dsp.exec "waypaper --random")) # window management (bind "SUPER + Q" dsp.killactive) (bind "SUPER + SHIFT + Q" dsp.exit) (bind "SUPER + F" dsp.maximize) (bind "SUPER + SHIFT + F" dsp.fullscreen) (bind "SUPER + Space" dsp.togglefloating) # focus (bind "SUPER + left" (dsp.movefocus "left")) (bind "SUPER + right" (dsp.movefocus "right")) (bind "SUPER + up" (dsp.movefocus "up")) (bind "SUPER + down" (dsp.movefocus "down")) # move (bind "SUPER + SHIFT + left" (dsp.movewindow "left")) (bind "SUPER + SHIFT + right" (dsp.movewindow "right")) (bind "SUPER + SHIFT + up" (dsp.movewindow "up")) (bind "SUPER + SHIFT + down" (dsp.movewindow "down")) # resize (bind "SUPER + CTRL + left" (dsp.resizeactive (-20) 0)) (bind "SUPER + CTRL + right" (dsp.resizeactive 20 0)) (bind "SUPER + CTRL + up" (dsp.resizeactive 0 (-20))) (bind "SUPER + CTRL + down" (dsp.resizeactive 0 20)) # tabbed / group (bind "SUPER + g" dsp.togglegroup) (bind "SUPER + tab" dsp.changegroupactive) # special workspaces (bind "SUPER + T" (dsp.togglespecial "terminal")) (bind "SUPER + C" (dsp.togglespecial "communications")) (bind "SUPER + M" (dsp.togglespecial "music")) (bind "SUPER + V" (dsp.togglespecial "version_control")) # cycle workspaces (bind "SUPER + ALT + up" (dsp.workspaceRef "e+1")) (bind "SUPER + ALT + down" (dsp.workspaceRef "e-1")) # mouse move / resize (bindo "SUPER + mouse:272" dsp.drag { mouse = true; }) (bindo "SUPER + mouse:273" dsp.resizemouse { mouse = true; }) # multimedia (pipewire) (bindo "XF86AudioRaiseVolume" (dsp.exec "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+") { repeating = true; }) (bindo "XF86AudioLowerVolume" (dsp.exec "wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-") { repeating = true; }) (bind "XF86AudioMute" (dsp.exec "wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle")) (bind "XF86AudioPlay" (dsp.exec "playerctl play-pause")) (bind "XF86AudioPause" (dsp.exec "playerctl play-pause")) (bind "XF86AudioNext" (dsp.exec "playerctl next")) (bind "XF86AudioPrev" (dsp.exec "playerctl previous")) ] ++ (map (w: bind "SUPER + ${w.k}" (dsp.workspace w.n)) wsKeys) ++ (map (w: bind "SUPER + SHIFT + ${w.k}" (dsp.movetoworkspace w.n)) wsKeys); # ---- window rules (windowrules.conf) ---- window_rule = [ { name = "games"; match.class = "gamescope"; workspace = "name:game"; opacity = "1 1 override"; } { name = "vivaldi"; match.title = "(.*)(- YouTube - Vivaldi)"; opacity = "1 1 override"; } { name = "jetbrains"; match.class = "(jetbrains-)(.*)"; no_initial_focus = true; float = true; center = true; } { name = "jetbrains-toolbox"; match.class = "jetbrains-toolbox"; move = "1933 21"; } { name = "comms"; match.class = "discord|org.telegram.desktop"; workspace = "special:communications"; } { name = "music"; match.class = "qbz"; workspace = "special:music"; } { name = "vicinae"; match.class = "vicinae"; stay_focused = true; } { name = "gitkraken"; match.class = "gitkraken"; workspace = "special:version_control"; } ]; # ---- workspace rules (workspacerules.conf) ---- workspace_rule = [ { workspace = "name:game"; monitor = "DP-2"; decorate = false; } { workspace = "special:terminal"; on_created_empty = "alacritty"; gaps_out = 256; } { workspace = "special:communications"; on_created_empty = "${config.home.homeDirectory}/.config/scripts/start-communications.sh"; gaps_out = 128; } { workspace = "special:music"; on_created_empty = "com.blitzfc.qbz"; gaps_out = 128; } { workspace = "special:version_control"; on_created_empty = "com.axosoft.GitKraken"; gaps_out = 128; } ]; # ---- autostart (autostart.conf) ---- on = { _args = [ "hyprland.start" (lua '' function() hl.exec_cmd("systemctl --user start hyprpolkitagent") hl.exec_cmd("cosmic-settings-daemon") hl.exec_cmd("quickshell") hl.exec_cmd("alacritty", { workspace = "special:terminal silent" }) hl.exec_cmd("kbuildsycoca6 --noincremental") end'') ]; }; }; }; xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-cosmic ]; }