nix-dotfiles/modules/desktop/hyprland.nix
2024-12-11 21:24:39 -08:00

352 lines
13 KiB
Nix

{ inputs, lib, config, system, pkgs, ... }:
with lib;
let
cfg = config.modules.desktop.hyprland;
hyprpkgs = inputs.hyprland.packages.${system};
in {
options.modules.desktop.hyprland = {
enable = mkEnableOption "Enable hyprland, a dynamic tiling wayland compositor based on wlroots that doesn't sacrifice on its looks";
package = mkOption {
type = types.package;
default = hyprpkgs.hyprland;
example = "pkgs.hyprland";
};
portalPackage = mkOption {
type = types.package;
default = hyprpkgs.xdg-desktop-portal-hyprland;
example = "pkgs.xdg-desktop-portal-hyprland";
};
};
config = mkIf cfg.enable {
services.displayManager.sessionPackages = [ cfg.package ];
xdg.portal = {
enable = true;
extraPortals = [ pkgs.xdg-desktop-portal-gtk cfg.portalPackage ];
config = {
common = {
default = [ "hyprland" "gtk" ];
};
};
};
# fixes a few things, most notibly, xwayland
programs.hyprland = {
enable = true;
xwayland.enable = true;
package = cfg.package;
portalPackage = cfg.portalPackage;
};
hm.wayland.windowManager.hyprland = {
enable = true;
xwayland.enable = true;
package = cfg.package;
systemd.variables = [ "--all" ];
settings = let
wobSock = config.modules.desktop.wob.sockPath;
in {
source = [];
"$mod" = "SUPER";
bindm = [ # "bind mouse"
# move/resize windows with mod + lmb/rmb and dragging
"$mod, mouse:272, movewindow"
"$mod, mouse:273, resizewindow"
];
bindel = (if config.modules.desktop.wob.enable then [ # "bind held & locked"
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+ && wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/[^0-9]//g' > ${wobSock}"
", XF86AudioLowerVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%- && wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/[^0-9]//g' > ${wobSock}"
", XF86MonBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s +5% | sed -n 's/.*(\\([0-9]*\\)%).*/\\1/p' > ${wobSock}"
", XF86MonBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s 5%- | sed -n 's/.*(\\([0-9]*\\)%).*/\\1/p' > ${wobSock}"
", XF86KbdBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} -d '*:kbd_backlight' s +5% | sed -n 's/.*(\\([0-9]*\\)%).*/\\1/p' > ${wobSock}"
", XF86KbdBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} -d '*:kbd_backlight' s 5%- | sed -n 's/.*(\\([0-9]*\\)%).*/\\1/p' > ${wobSock}"
] else [
", XF86AudioRaiseVolume, exec, wpctl set-volume -l 1 @DEFAULT_AUDIO_SINK@ 5%+"
", XF86AudioLowerVolume, exec, wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-"
", XF86MonBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s +5%"
", XF86MonBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} -c backlight s 5%-"
", XF86KbdBrightnessUp, exec, ${lib.getExe pkgs.brightnessctl} -d '*:kbd_backlight' s +5%"
", XF86KbdBrightnessDown, exec, ${lib.getExe pkgs.brightnessctl} -d '*:kbd_backlight' s 5%-"
]);
bindl = ([ # "bind locked"
",switch:Lid Switch,exec,${lib.getExe config.modules.desktop.hyprlock.package}"
", XF86AudioPlay, exec, ${lib.getExe pkgs.playerctl} play-pause"
", XF86AudioStop, exec, ${lib.getExe pkgs.playerctl} stop"
", XF86AudioPrev, exec, ${lib.getExe pkgs.playerctl} previous"
", XF86AudioNext, exec, ${lib.getExe pkgs.playerctl} next"
", XF86AudioMicMute, exec, wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
] ++ (if config.modules.desktop.wob.enable then [
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle && (wpctl get-volume @DEFAULT_AUDIO_SINK@ | grep -q MUTED && echo 0 > ${wobSock}) || wpctl get-volume @DEFAULT_AUDIO_SINK@ | sed 's/[^0-9]//g' > ${wobSock}"
] else [
", XF86AudioMute, exec, wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle"
]));
bindr = [ # "bind released"
"SUPER, Super_L, exec, ${lib.getExe pkgs.nwg-drawer}"
];
bind = let
screenshotScript = pkgs.writeScript "screenshot" ''
temp_file=$(mktemp)
trap 'rm -f "$temp_file"' EXIT
mode="$1"
case "$mode" in
fullscreen)
mode="output"
;;
area)
mode="area"
;;
*)
echo "usage: $0 [fullscreen|area]" >&2
exit 2
;;
esac
${lib.getExe pkgs.grimblast} --freeze save "$mode" - > "$temp_file" || exit 0 # exit successful, highly unlikely that grimblast failed, and it is more likely that the user cancelled the screenshot
cat "$temp_file" | ${lib.getExe pkgs.wl-clipboard-x11} -selection clipboard -t image/png
action=$(${pkgs.libnotify}/bin/notify-send "Screenshot Captured" \
--app-name="Screenshot" \
--urgency=normal \
--action="default=Edit Image" \
--icon "$temp_file" \
"Click to annotate image")
case "$action" in
default)
${lib.getExe pkgs.satty} --filename "$temp_file"
;;
esac
'';
in [
"$mod, Q, killactive, "
"$mod, F, togglefloating, "
"$mod, P, pseudo, " # dwindle
"$mod, J, togglesplit, " # dwindle
# move focus with mod + arrow keys
"$mod, left, movefocus, l"
"$mod, right, movefocus, r"
"$mod, up, movefocus, u"
"$mod, down, movefocus, d"
# example special workspace (scratchpad)
"$mod, grave, togglespecialworkspace, magic"
"$mod SHIFT, grave, movetoworkspace, special:magic"
# scroll through workspaces with mod + scroll
"$mod, mouse_down, workspace, e+1"
"$mod, mouse_up, workspace, e-1"
# alternatively, scroll through workspaces with mod + brackets
"$mod, bracketleft, workspace, e-1"
"$mod, bracketright, workspace, e+1"
"$mod, R, exec, ${lib.getExe pkgs.rofi-wayland} -show run"
"$mod, T, exec, ${lib.getExe pkgs.wezterm}"
"$mod, L, exec, ${lib.getExe config.modules.desktop.hyprlock.package}"
# screenshot
# area
", Print, exec, ${screenshotScript} area"
"$mod SHIFT, S, exec, ${screenshotScript} area"
# fullscreen
", Print, exec, ${screenshotScript} fullscreen"
"$mod SHIFT CTRL, S, exec, ${screenshotScript} fullscreen"
", XF86LaunchA, exec, ${screenshotScript} area"
", XF86LaunchB, exec, ${lib.getExe pkgs.rofi-rbw-wayland} -a copy -t password --clear-after 20"
", XF86ScreenSaver, exec, ${lib.getExe config.modules.desktop.hyprlock.package}"
# alt-tab emulation
# doesnt activate when we let go of alt sadly
"ALT, Tab, exec, ${lib.getExe pkgs.rofi-wayland} -show window"
] ++ (
# workspaces
# binds $mod + [shift +] {1..10} to [move to] workspace {1..10}
builtins.concatLists (builtins.genList (
x: let
ws = let
c = (x + 1) / 10;
in
builtins.toString (x + 1 - (c * 10));
in [
"$mod, ${ws}, workspace, ${toString (x + 1)}"
"$mod SHIFT, ${ws}, movetoworkspace, ${toString (x + 1)}"
]
)
10)
);
input = {
kb_layout = "us";
follow_mouse = 1;
sensitivity = 0; # -1.0 - 1.0, 0 means no modification
};
monitor=",highrr,auto,auto";
exec-once = [
"${lib.getExe pkgs.networkmanagerapplet}" # network applet
"${pkgs.polkit_gnome}/libexec/polkit-gnome-authentication-agent-1" # polkit agent
"${lib.getExe pkgs.wl-clip-persist} --clipboard regular" # to fix wl clipboards disappearing
] ++ config.modules.desktop.execOnStart;
env = [
"XCURSOR_THEME,${config.modules.desktop.themes.cursorTheme.name}"
"XCURSOR_SIZE,24"
];
general = {
gaps_in = 6;
gaps_out = 6;
border_size = 1;
no_border_on_floating = false;
layout = "dwindle";
resize_on_border = true;
};
windowrulev2 = [
# common popups
# we should totally dedupe these
"float, class:org.gnome.FileRoller"
"size 1100 650, class:org.gnome.FileRoller"
"center, class:org.gnome.FileRoller"
"float, class:org.gnome.Loupe"
"size 1100 650, class:org.gnome.Loupe"
"center class:org.gnome.Loupe"
"float, class:com.gabm.satty"
"size 1100 650, class:com.gabm.satty"
"center 1100 650, class:com.gabm.satty"
"float, initialTitle:^Open Folder$"
"size 1100 650, initialTitle:^Open Folder$"
"center, initialTitle:^Open Folder$"
"float, initialTitle:^Open File$"
"size 1100 650, initialTitle:^Open File$"
"center, initialTitle:^Open File$"
"float, initialTitle:^Open Files$"
"size 1100 650, initialTitle:^Open Files$"
"center, initialTitle:^Open Files$"
"float, initialTitle:^Save As$"
"size 1100 650, initialTitle:^Save As$"
"center, initialTitle:^Save As$"
"float, initialTitle:^Select a file to open$"
"size 1100 650, initialTitle:^Select a file to open$"
"center, initialTitle:^Select a file to open$"
"float, initialTitle:^File Upload$"
"size 1100 650, initialTitle:^File Upload$"
"center, initialTitle:^File Upload$"
"float, class:\.exe$"
# fix focus
"stayfocused, class:^gcr-prompter"
"dimaround, class:^gcr-prompter"
"stayfocused, class:^pinentry-"
"dimaround, class:^pinentry-"
"stayfocused, class:^polkit-"
"dimaround, class:^polkit-"
# firefox pip
"float, title:^Picture-in-Picture$"
"pin, title:^Picture-in-Picture$"
"noborder, title:^Picture-in-Picture$"
"keepaspectratio, title:^Picture-in-Picture$"
# discord pip
"pin, initialTitle:^Discord Popout$"
"float, initialTitle:^Discord Popout$"
# workspace moving
"workspace 1 silent, class:^firefox"
"workspace 2 silent, class:code-url-handler"
"workspace 4 silent, class:vesktop"
];
layerrule = [
"animation slide, notifications"
"animation slide, waybar"
"animation popin, rofi"
"dimaround, rofi"
"blur, gtk-layer-shell"
"blur, wob"
"blur, notifications"
"blur, waybar"
"blur, rofi"
"ignorezero, notifications" # fucks up the blur otherwise, rounded corners
"ignorezero, waybar"
"ignorezero, rofi"
];
decoration = {
rounding = 10;
blur = {
enabled = true;
size = 6;
passes = 3;
# popups and special workspace have blur disabled by default
popups = true;
special = true;
};
drop_shadow = true;
shadow_range = 6;
shadow_render_power = 3;
shadow_ignore_window = true;
};
animations = {
enabled = true;
bezier = [
"outCubic, 0.33, 1, 0.68, 1"
"outExpo, 0.16, 1, 0.3, 1"
];
animation = [
"windows, 1, 5, outExpo, popin"
"windowsOut, 1, 5, outCubic, popin 80%"
"border, 1, 2, outExpo"
"fade, 1, 3, outCubic"
"workspaces, 1, 6, outExpo"
"specialWorkspace, 1, 2, outCubic, fade"
];
};
dwindle = {
pseudotile = "yes"; # master swtich for pseudotiling. enabling is mod + P in the keybinds section
preserve_split = "yes";
};
master = {
new_status = "master";
};
gestures = {
workspace_swipe = true;
workspace_swipe_min_speed_to_force = 0;
workspace_swipe_cancel_ratio = 0.1;
};
misc = {
force_default_wallpaper = 0;
disable_splash_rendering = true;
disable_hyprland_logo = true;
initial_workspace_tracking = 0;
};
};
};
};
}