413 lines
15 KiB
Nix
413 lines
15 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 config.modules.desktop.nwg-drawer.package}"
|
|
];
|
|
bind = let
|
|
screenshotScript = pkgs.writeShellScript "screenshot" ''
|
|
set -euo pipefail
|
|
|
|
temp_file=$(mktemp)
|
|
trap 'rm -f "$temp_file"' EXIT
|
|
|
|
mode="$1"
|
|
case "$mode" in
|
|
screen)
|
|
mode="output"
|
|
;;
|
|
area)
|
|
mode="area"
|
|
;;
|
|
window)
|
|
mode="active"
|
|
;;
|
|
*)
|
|
echo "usage: $0 [screen|area|window]" >&2
|
|
exit 2
|
|
;;
|
|
esac
|
|
|
|
${lib.getExe pkgs.grimblast} --freeze save "$mode" - > "$temp_file"
|
|
|
|
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
|
|
'';
|
|
pickerScript = pkgs.writeShellScript "picker" ''
|
|
set -euo pipefail
|
|
|
|
${lib.getExe pkgs.hyprpicker} --render-inactive --format hex | sed -z 's/\n//g' | ${lib.getExe pkgs.wl-clipboard-x11} -selection clipboard -t text/plain
|
|
|
|
${pkgs.libnotify}/bin/notify-send "Color Captured" \
|
|
--app-name="Picker" \
|
|
--urgency="normal" \
|
|
"Color copied to clipboard"
|
|
'';
|
|
ocrScript = pkgs.writeShellScript "ocr" ''
|
|
set -euo pipefail
|
|
|
|
output=$(${lib.getExe pkgs.grimblast} --freeze save area - | ${lib.getExe pkgs.tesseract5} - -)
|
|
|
|
echo "$output" | ${lib.getExe pkgs.wl-clipboard-x11} -selection clipboard -t text/plain
|
|
|
|
${pkgs.libnotify}/bin/notify-send "OCR Captured" \
|
|
--app-name="OCR" \
|
|
--urgency="normal" \
|
|
--icon="text-x-generic-symbolic" \
|
|
"Text copied to clipboard"
|
|
'';
|
|
in [
|
|
"$mod, Q, killactive, "
|
|
"$mod, F, togglefloating, "
|
|
"$mod, P, pseudo, " # dwindle
|
|
"$mod, J, togglesplit, " # dwindle
|
|
"$mod SHIFT, F, fullscreen, "
|
|
|
|
# move focus with mod + arrow keys
|
|
"$mod, left, movefocus, l"
|
|
"$mod, right, movefocus, r"
|
|
"$mod, up, movefocus, u"
|
|
"$mod, down, movefocus, d"
|
|
# move windows with mod + shift + arrow keys
|
|
"$mod SHIFT, left, movewindow, l"
|
|
"$mod SHIFT, right, movewindow, r"
|
|
"$mod SHIFT, up, movewindow, u"
|
|
"$mod SHIFT, down, movewindow, 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 config.modules.desktop.rofi.package} -show run"
|
|
"$mod, T, exec, ${lib.getExe config.modules.software.system.wezterm.package}"
|
|
"$mod, L, exec, ${lib.getExe config.modules.desktop.hyprlock.package}"
|
|
"$mod, V, exec, ${lib.getExe config.modules.software.system.wezterm.package} start --class 'clipse' -e '${lib.getExe config.modules.desktop.clipse.package}'"
|
|
"$mod, E, exec, ${lib.getExe pkgs.nautilus}"
|
|
|
|
# screenshot
|
|
# area
|
|
", Print, exec, ${screenshotScript} area"
|
|
"$mod SHIFT, S, exec, ${screenshotScript} area"
|
|
# screen
|
|
"CTRL, Print, exec, ${screenshotScript} screen"
|
|
"$mod SHIFT CTRL, S, exec, ${screenshotScript} screen"
|
|
# window
|
|
"ALT, Print, exec, ${screenshotScript} window"
|
|
"$mod SHIFT ALT, S, exec, ${screenshotScript} window"
|
|
# pick color
|
|
"$mod SHIFT, C, exec, ${pickerScript}"
|
|
# ocr
|
|
"$mod SHIFT, T, exec, ${ocrScript}"
|
|
|
|
", 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}"
|
|
] ++ (
|
|
# 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;
|
|
|
|
# uhm?? why do i have to do this here. should be automatic from libinput
|
|
# whatever. ill just hardcode for now
|
|
# TODO
|
|
touchpad = {
|
|
disable_while_typing = false;
|
|
natural_scroll = true;
|
|
};
|
|
};
|
|
|
|
monitor=",highrr,auto,auto";
|
|
|
|
exec-once = [
|
|
"${lib.getExe pkgs.networkmanagerapplet}" # network applet
|
|
"${lib.getExe pkgs.wl-clip-persist} --clipboard regular" # to fix wl clipboards disappearing
|
|
];
|
|
|
|
env = [
|
|
"XCURSOR_THEME,${config.modules.desktop.themes.cursorTheme.name}"
|
|
"XCURSOR_SIZE,${toString config.modules.desktop.themes.cursorTheme.size}"
|
|
];
|
|
|
|
general = {
|
|
gaps_in = 6;
|
|
gaps_out = 6;
|
|
border_size = 1;
|
|
no_border_on_floating = false;
|
|
|
|
layout = "dwindle";
|
|
|
|
resize_on_border = true;
|
|
};
|
|
|
|
windowrulev2 = [
|
|
# TODO: dedupe
|
|
# commons
|
|
"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:^File Upload$"
|
|
"size 1100 650, initialTitle:^File Upload$"
|
|
"center, initialTitle:^File Upload$"
|
|
"float, initialTitle:^MainPicker$"
|
|
"size 1100 650, initialTitle:^MainPicker$"
|
|
"center, initialTitle:^MainPicker$"
|
|
"float, class:^clipse$"
|
|
"size 1100 650, class:^clipse$"
|
|
"center, class:^clipse$"
|
|
# privacy popups
|
|
"stayfocused, class:^clipse$"
|
|
"dimaround, class:^clipse$"
|
|
"stayfocused, class:^gcr-prompter$"
|
|
"dimaround, class:^gcr-prompter$"
|
|
"stayfocused, class:^pinentry-"
|
|
"dimaround, class:^pinentry-"
|
|
"stayfocused, class:^polkit-"
|
|
"dimaround, class:^polkit-"
|
|
|
|
"float, class:\.exe$"
|
|
"rounding 0, class:\.exe$"
|
|
|
|
# steam notifs
|
|
"rounding 0, title:^notificationtoasts_"
|
|
"pin, title:^notificationtoasts_"
|
|
"noborder, title:^notificationtoasts_"
|
|
"nofocus, title:^notificationtoasts_"
|
|
"noshadow, title:^notificationtoasts_"
|
|
|
|
# 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$"
|
|
"noborder, initialTitle:^Discord Popout$"
|
|
|
|
# workspace moving
|
|
"workspace 1 silent, class:^firefox$"
|
|
"workspace 2 silent, class:^code$"
|
|
"workspace 4 silent, class:^vesktop$"
|
|
];
|
|
|
|
layerrule = [
|
|
"animation slide, notifications"
|
|
"animation slide, waybar"
|
|
"animation popin, rofi"
|
|
"dimaround, rofi"
|
|
"blur, nwg-drawer"
|
|
"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;
|
|
};
|
|
|
|
shadow = {
|
|
enabled = true;
|
|
range = 6;
|
|
render_power = 3;
|
|
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 switch for pseudotiling. enabling is mod + P in the keybinds section
|
|
preserve_split = "yes";
|
|
};
|
|
|
|
gestures = {
|
|
workspace_swipe = true;
|
|
workspace_swipe_min_speed_to_force = 0;
|
|
workspace_swipe_cancel_ratio = 0.1;
|
|
};
|
|
|
|
misc = {
|
|
# disable default eye candy
|
|
force_default_wallpaper = 0;
|
|
disable_splash_rendering = true;
|
|
disable_hyprland_logo = true;
|
|
|
|
# there is zero reason to have this enabled
|
|
# what were they thinking
|
|
initial_workspace_tracking = 0;
|
|
|
|
vfr = true;
|
|
vrr = 2;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
}
|