{ config , lib , pkgs , inputs , ... } @ args: let inherit (lib) mkOption mkEnableOption mkIf types getExe genAttrs optionalAttrs optional; cfg = config.my.programs.hyprland; hyprland = inputs.hyprland.packages.${pkgs.system}.default; in { options.my.programs.hyprland = { enable = mkEnableOption "hyprland"; nvidiaSupport = mkEnableOption "enable nvidia Support"; blur = mkOption { type = types.bool; description = "enable window blurring"; default = true; }; shadows = mkOption { type = types.bool; description = "enable window shadows"; default = true; }; keyboardLayouts = mkOption { type = types.listOf types.str; description = "list of keyboard layouts"; default = [ "de" "us" ]; }; monitors = mkOption { type = types.attrsOf ( let sub = types.submodule { options = { resolution = mkOption { type = types.strMatching "\(preferred\)|\([[:digit:]]+x[[:digit:]]+\(@[[:digit:]]+\)\?\)"; default = "preferred"; }; position = mkOption { type = types.strMatching "\(auto\)|\(-\?[[:digit:]]+x-?[[:digit:]]+\)"; default = "auto"; }; disabled = mkEnableOption "disabled"; scale = mkOption { type = types.oneOf [ types.float (types.strMatching "auto") ]; default = 1.0; apply = x: if lib.isFloat x then lib.strings.floatToString x else x; }; extra = mkOption { type = types.listOf types.str; default = [ ]; apply = lib.concatStringsSep ","; }; }; }; in sub ); description = "monitor setting"; }; extraConfig = mkOption { type = types.str; default = ""; }; }; config = mkIf cfg.enable { my = { nixpkgs.overlays = [ inputs.hypr-contrib.overlays.default ]; programs = { wallpaper.enable = true; # foot.enable = true; kitty.enable = true; rofi.enable = true; hyprland.monitors."" = lib.mkDefault { }; hyprland.monitors."Unknown-1" = { disabled = true; }; }; wallpapers.enable = true; services = { dunst.enable = true; wallpaper = { enable = true; target = "hyprland-session.target"; }; spotify-player.target = "hyprland-session.target"; }; }; programs.hyprland = { enable = true; package = hyprland; portalPackage = inputs.hyprland.packages.${pkgs.system}.xdg-desktop-portal-hyprland; }; home-manager.users.moritz = { # enable home-manager module wayland.windowManager.hyprland = { enable = true; extraConfig = import ./_config.nix args; systemd.extraCommands = [ "systemctl --user stop hyprland-session.target" "sleep 1.5" "systemctl --user start hyprland-session.target" "systemctl --user start xdg-desktop-portal-hyprland.service" ]; }; # add waybar as a status bar programs.waybar = { enable = true; package = pkgs.waybar.overrideAttrs (old: { patches = old.patches or [ ] ++ [ (pkgs.fetchpatch { url = "https://gitlab.archlinux.org/archlinux/packaging/packages/waybar/-/raw/0306af03fcb6de6aee1e288f42b0bf1b223513bd/a544f4b2cdcf632f1a4424b89f6e3d85ef5aaa85.patch"; sha256 = "sha256-S/1oUj9Aj6BElNTsDY8CTcKtS1j7Gl54JFgCywH05pg="; }) ]; }); # start using systemd service systemd = { enable = true; target = "hyprland-session.target"; }; settings = { mainBar = { start_hidden = true; layer = "top"; position = "top"; height = 24; modules-left = [ "hyprland/workspaces" ]; modules-center = [ "hyprland/window" ]; modules-right = [ "hyprland/language" "network" "memory" "cpu" "battery" "clock" ]; }; }; }; # lock screen after timeout programs.swaylock = { enable = true; settings = { color = "000000"; }; }; services.swayidle = { enable = true; events = [ { event = "before-sleep"; command = "${getExe pkgs.swaylock} -fF"; } { event = "lock"; command = "${getExe pkgs.swaylock} -fF"; } ]; timeouts = let lockTimeout = 10; in [ { timeout = lockTimeout * 60 - 10; command = "${pkgs.libnotify}/bin/notify-send 'Locking screen!'"; } { timeout = lockTimeout * 60; command = "${hyprland}/bin/hyprctl dispatch dpms off"; resumeCommand = "${hyprland}/bin/hyprctl dispatch dpms on"; } { timeout = lockTimeout * 60 + 10; command = "${pkgs.systemd}/bin/loginctl lock-session"; } ] ++ optional (!cfg.nvidiaSupport) # TODO https://github.com/hyprwm/Hyprland/issues/1728 { timeout = 30 * 60; command = "${pkgs.systemd}/bin/systemctl suspend-and-hibernate"; }; systemdTarget = "hyprland-session.target"; }; }; # adds pam module for swaylock security.pam.services.swaylock = { }; # add user packages for wayland and hyprland in particular users.users.moritz.packages = with pkgs; [ brightnessctl # control brightness grimblast # screenshot tool for hyprland pamixer # pulse audio cli playerctl # control media playback slurp # region select for wayland (for screensharing) wdisplays # manage monitors wl-clipboard # clipboard tool for wayland ]; # additional environment variables environment.sessionVariables = { XDG_CURRENT_DESKTOP = "Hyprland"; XDG_SESSION_TYPE = "wayland"; XDG_SESSION_DESKTOP = "Hyprland"; QT_AUTO_SCREEN_SCALE_FACTOR = "1"; QT_QPA_PLATFORM = "wayland;xcb"; QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; QT_QPA_PLATFORMTHEME = "qt5ct"; _JAVA_AWT_WM_NONEREPARENTING = "1"; } // (optionalAttrs cfg.nvidiaSupport { LIBVA_DRIVER_NAME = "nvidia"; GBM_BACKEND = "nvidia-drm"; __GLX_VENDOR_LIBRARY_NAME = "nvidia"; WLR_NO_HARDWARE_CURSORS = "1"; __GL_VRR_ALLOWED = "0"; }); services = { dbus.enable = true; # use pipewire (needed for screensharing) pipewire = { enable = true; alsa.enable = true; alsa.support32Bit = true; pulse.enable = true; }; xserver = { enable = true; displayManager = { lightdm.enable = true; autoLogin = { enable = true; user = "moritz"; }; defaultSession = "hyprland"; }; }; }; security.rtkit.enable = true; home-manager.users.moritz.systemd.user.services = let units = [ "waybar" ]; mkAfter = _: { Unit = { After = [ "hyprland-session.target" ]; Wants = [ "hyprland-session.target" ]; }; }; in genAttrs units mkAfter; systemd.user.services = let units = [ "pipewire" "xdg-desktop-portal" "xdg-desktop-portal-hyprland" "wireplumber" ]; mkAfter = _: { after = [ "hyprland-session.target" ]; wants = [ "hyprland-session.target" ]; }; in genAttrs units mkAfter; }; }