dotfiles/modules/home/graphical/wayland/hyprland.nix
eriedaberrie e1fbf03dff Initial commit
Note: not the actual initial commit.

I swear I will stop repeatedly force pushing to this single commit eventually
ok.
2024-09-08 09:58:54 -07:00

446 lines
15 KiB
Nix

{ pkgs, inputs, config, lib, self, osConfig, theme, ... }:
let
cfg = config.my.graphical.wayland.hyprland;
in {
options.my.graphical.wayland.hyprland = {
enable = lib.mkEnableOption null;
tearing = lib.mkEnableOption null;
mainMod = lib.mkOption {
type = lib.types.str;
default = "SUPER";
};
lockBinary = lib.mkOption {
type = lib.types.str;
};
wallpaper = {
enable = lib.mkEnableOption null // {
default = true;
};
backend = lib.mkOption {
type = lib.types.enum [ "hyprpaper" "swaybg" ];
default = "swaybg";
};
image = lib.mkOption {
type = lib.types.pathInStore;
default = "${self}/assets/snowyMountain.jpg";
};
};
};
config = lib.mkIf cfg.enable (let
toggleOption = pkgs.writeShellScriptBin "hypr-toggle-opt" ''
hyprctl keyword "$1" "$(hyprctl getoption "$1" -j | ${pkgs.jaq}/bin/jaq '1 - .int')"
'';
copyOutput = pkgs.writeShellScript "hypr-copy-output" ''
MONITOR="$(hyprctl monitors -j | ${pkgs.jaq}/bin/jaq -r '.[] | select(.focused).name')"
grim -o "$MONITOR" - | wl-copy -t image/png
'';
copyWindow = pkgs.writeShellScript "hypr-copy-window" ''
WINDOW="$(hyprctl activewindow -j | ${pkgs.jaq}/bin/jaq -r '.address')"
grim -w "$WINDOW" - | wl-copy -t image/png
'';
winShiftS = with pkgs; writeShellScriptBin "win-shift-s" ''
FILENAME="/tmp/win-shift-s-$PPID.png"
MONITOR="$(hyprctl monitors -j | ${_ jaq} -r '.[] | select(.focused)')"
${_ grim} -o "$(${_ jaq} -r '.name' <<< "$MONITOR")" "$FILENAME"
${_ imv} -f "$FILENAME" & IMV_PROC=$!
DIMENSIONS="$(${_ slurp} -f '%wx%h+%X+%Y')"
[ "$?" -eq 0 ] && \
${_ imagemagick} "$FILENAME" -crop "$DIMENSIONS" - | \
${wl-clipboard}/bin/wl-copy -t image/png
kill $IMV_PROC
exec rm "$FILENAME"
'';
timeWindow = let
inherit (inputs.cl-hyprland-ipc.packages.${pkgs.system}) cl-hyprland-ipc;
inherit (cl-hyprland-ipc) asdfFasl faslExt;
sbclWithPackages = pkgs.sbcl.withPackages (_: [ cl-hyprland-ipc ]);
in pkgs.runCommand "time-window" { } ''
${sbclWithPackages}/bin/sbcl --load ${asdfFasl}/asdf.${faslExt} \
--load ${../../scripts/time-window.lisp} \
--eval '(setf uiop:*image-entry-point* #'\''\''time-window:main)' \
--eval '(uiop:dump-image "time-window" :executable t :compression t)'
mkdir -p $out/bin
cp time-window $out/bin
'';
in {
home.packages = [
toggleOption
timeWindow
];
wayland.windowManager.hyprland = let
c = builtins.mapAttrs (_: t: "0xFF${t}") theme;
inherit (cfg) mainMod;
activeBorder = "${c.peach} ${c.mauve} 45deg";
transparent = "0x00000000";
in {
enable = true;
package = osConfig.programs.hyprland.package;
settings = {
exec-once = lib.optional (!osConfig.my.fs.luks.enable) "${pkgs.writeShellScript "start-hyprland" ''
[ -n "$GREETD_SOCK" ] && ${pkgs.swaylock-effects}/bin/swaylock ${
lib.optionalString cfg.wallpaper.enable "-i ${cfg.wallpaper.image}"
} &
''}";
env = [ ]
++ lib.optional config.my.graphical.emacs.enable "VISUAL, emacsclient -c";
monitor = [
"eDP-1, preferred, 0x0, 1.33"
", preferred, auto, 1"
# Manually reserved area for bar
", addreserved, 42, 0, 0, 0"
];
input = {
kb_layout = "us";
repeat_delay = 300;
repeat_rate = 20;
float_switch_override_focus = 2;
touchpad = {
natural_scroll = true;
scroll_factor = 0.3;
};
};
general = {
layout = "dwindle";
allow_tearing = cfg.tearing;
gaps_in = 5;
gaps_out = 13;
border_size = 3;
"col.active_border" = activeBorder;
"col.inactive_border" = transparent;
};
dwindle = {
force_split = 2;
preserve_split = true;
no_gaps_when_only = 1;
special_scale_factor = 0.9;
};
decoration = {
rounding = 11;
dim_special = 0;
drop_shadow = false;
blur = {
enabled = false;
size = 8;
passes = 2;
ignore_opacity = true;
xray = true;
noise = 0;
contrast = 1;
brightness = 1;
};
};
group = {
"col.border_active" = activeBorder;
"col.border_inactive" = transparent;
"col.border_locked_active" = c.red;
"col.border_locked_inactive" = transparent;
groupbar = {
render_titles = false;
height = 3;
"col.active" = c.green;
"col.inactive" = transparent;
"col.locked_active" = c.red;
"col.locked_inactive" = transparent;
};
};
animations = {
enabled = true;
bezier = [
"easeInSine, 0.12, 0, 0.39, 0"
"easeOutSine, 0.61, 1, 0.88, 1"
];
animation = [
"windowsIn, 1, 3, easeOutSine, slide"
"windowsOut, 1, 3, easeInSine, slide"
"windowsMove, 1, 2.5, easeOutSine, slide"
"workspaces, 1, 2.5, easeOutSine, slide"
"specialWorkspace, 1, 6, default, slidevert"
"fade, 0"
];
};
gestures = {
workspace_swipe = true;
};
binds = {
allow_workspace_cycles = true;
};
xwayland = {
use_nearest_neighbor = false;
force_zero_scaling = true;
};
misc = {
vrr = 1;
disable_hyprland_logo = true;
disable_splash_rendering = true;
background_color = c.crust;
disable_autoreload = true;
focus_on_activate = true;
animate_manual_resizes = false;
animate_mouse_windowdragging = false;
new_window_takes_over_fullscreen = 2;
enable_swallow = false;
swallow_regex = "^(foot(client)?|kitty)$";
};
windowrule = [
"tile, ^(Aseprite)$"
"fullscreen, ^(Baba Is You|ADanceOfFireAndIce)$"
"float, ^(EverestSplash-linux)$"
"float, title:^(emacs-everywhere)$"
] ++ lib.optional cfg.tearing
"immediate, ^(ADanceOfFireAndIce|Celeste|hollow_knight\\.x86_64|portal2_linux)$";
windowrulev2 = [
"float, class:^(firefox)$, title:^(Picture-in-Picture)$"
"pin, class:^(firefox)$, title:^(Picture-in-Picture)$"
"tile, class:^(Spotify)$, title:^(?!Ozone X11$).*$"
"float, class:^(Spotify)$, title:^$"
];
bind = [
"${mainMod}, Return, exec, foot"
"${mainMod}, C, killactive,"
"${mainMod} SHIFT, C, exec, hyprctl activewindow -j | ${pkgs.jaq}/bin/jaq -r '.pid' | xargs kill -9"
"${mainMod}, E, exec, thunar"
"${mainMod}, M, exec, emacsclient -c"
"${mainMod} SHIFT, M, exec, emacsclient -e '(emacs-everywhere)'"
"${mainMod} SHIFT, Return, togglefloating,"
"${mainMod}, Space, fullscreen, 1"
"${mainMod} SHIFT, Space, fullscreen, 0"
"${mainMod}, I, exec, dunstctl action"
"${mainMod} SHIFT, I, exec, dunstctl context"
"${mainMod} ALT, I, exec, dunstctl history-pop"
"${mainMod} CTRL, I, exec, dunstctl close"
"${mainMod}, Semicolon, exec, killall fuzzel || fuzzel"
"${mainMod}, Y, pin,"
# Groups
"${mainMod}, F, changegroupactive, f"
"${mainMod} SHIFT, F, togglegroup,"
"${mainMod} CTRL, F, lockactivegroup, toggle"
# Directions
"${mainMod}, Period, layoutmsg, preselect r"
"${mainMod}, Comma, layoutmsg, preselect d"
"${mainMod}, S, layoutmsg, togglesplit"
# Moving windows (with groups)
"${mainMod} SHIFT, left, movewindoworgroup, l"
"${mainMod} SHIFT, right, movewindoworgroup, r"
"${mainMod} SHIFT, up, movewindoworgroup, u"
"${mainMod} SHIFT, down, movewindoworgroup, d"
"${mainMod} SHIFT, H, movewindoworgroup, l"
"${mainMod} SHIFT, L, movewindoworgroup, r"
"${mainMod} SHIFT, K, movewindoworgroup, u"
"${mainMod} SHIFT, J, movewindoworgroup, d"
# Moving windows (without groups)
"${mainMod} ALT, left, movewindow, l"
"${mainMod} ALT, right, movewindow, r"
"${mainMod} ALT, up, movewindow, u"
"${mainMod} ALT, down, movewindow, d"
"${mainMod} ALT, H, movewindow, l"
"${mainMod} ALT, L, movewindow, r"
"${mainMod} ALT, K, movewindow, u"
"${mainMod} ALT, J, movewindow, d"
# Workspaces
"${mainMod} CTRL, P, focusworkspaceoncurrentmonitor, previous"
"${mainMod} CTRL, N, focusworkspaceoncurrentmonitor, empty"
"${mainMod} CTRL SHIFT, P, movetoworkspace, previous"
"${mainMod} CTRL SHIFT, N, movetoworkspace, empty"
# Screenshot
", Print, exec, ${copyOutput}"
"ALT, Print, exec, ${copyWindow}"
"${mainMod} SHIFT, S, exec, grim -g \"$(slurp)\" - | wl-copy -t image/png"
# Move focus
"${mainMod}, left, movefocus, l"
"${mainMod}, right, movefocus, r"
"${mainMod}, up, movefocus, u"
"${mainMod}, down, movefocus, d"
"${mainMod}, H, movefocus, l"
"${mainMod}, L, movefocus, r"
"${mainMod}, K, movefocus, u"
"${mainMod}, J, movefocus, d"
# Switch workspaces with mainMod + [1-9]
"${mainMod}, 1, focusworkspaceoncurrentmonitor, 1"
"${mainMod}, 2, focusworkspaceoncurrentmonitor, 2"
"${mainMod}, 3, focusworkspaceoncurrentmonitor, 3"
"${mainMod}, 4, focusworkspaceoncurrentmonitor, 4"
"${mainMod}, 5, focusworkspaceoncurrentmonitor, 5"
"${mainMod}, 6, focusworkspaceoncurrentmonitor, 6"
"${mainMod}, 7, focusworkspaceoncurrentmonitor, 7"
"${mainMod}, 8, focusworkspaceoncurrentmonitor, 8"
"${mainMod}, 9, focusworkspaceoncurrentmonitor, 9"
# Switch workspaces with mainMod + N/P/O
"${mainMod}, N, focusworkspaceoncurrentmonitor, e+1"
"${mainMod}, P, focusworkspaceoncurrentmonitor, e-1"
"${mainMod} SHIFT, N, movetoworkspace, e+1"
"${mainMod} SHIFT, P, movetoworkspace, e-1"
# Move active window to a workspace with mainMod + SHIFT + [1-9]
"${mainMod} SHIFT, 1, movetoworkspace, 1"
"${mainMod} SHIFT, 2, movetoworkspace, 2"
"${mainMod} SHIFT, 3, movetoworkspace, 3"
"${mainMod} SHIFT, 4, movetoworkspace, 4"
"${mainMod} SHIFT, 5, movetoworkspace, 5"
"${mainMod} SHIFT, 6, movetoworkspace, 6"
"${mainMod} SHIFT, 7, movetoworkspace, 7"
"${mainMod} SHIFT, 8, movetoworkspace, 8"
"${mainMod} SHIFT, 9, movetoworkspace, 9"
# Scroll through existing workspaces with mainMod + scroll/side buttons
"${mainMod}, mouse_down, focusworkspaceoncurrentmonitor, e-1"
"${mainMod}, mouse_up, focusworkspaceoncurrentmonitor, e+1"
"${mainMod}, mouse:275, focusworkspaceoncurrentmonitor, e-1"
"${mainMod}, mouse:276, focusworkspaceoncurrentmonitor, e+1"
# Scratchpads
"${mainMod} SHIFT, 0, movetoworkspace, special:a"
"${mainMod}, 0, togglespecialworkspace, a"
"${mainMod} SHIFT, minus, movetoworkspace, special:b"
"${mainMod}, minus, togglespecialworkspace, b"
"${mainMod} SHIFT, equal, movetoworkspace, special:c"
"${mainMod}, equal, togglespecialworkspace, c"
"${mainMod}, T, exec, ${toggleOption}/bin/hypr-toggle-opt input:touchpad:disable_while_typing"
];
bindl = [
"${mainMod}, Q, exec, ${cfg.lockBinary}"
"${mainMod} ALT, Q, exec, killall ${cfg.lockBinary} .${cfg.lockBinary}-wrapped ; ${cfg.lockBinary}"
"${mainMod} SHIFT, Q, exit,"
", XF86AudioMute, exec, dunst-volume set-mute toggle"
];
binde = [
# Resize windows
"${mainMod} CTRL ALT, left, resizeactive, -10 0"
"${mainMod} CTRL ALT, right, resizeactive, 10 0"
"${mainMod} CTRL ALT, up, resizeactive, 0 -10"
"${mainMod} CTRL ALT, down, resizeactive, 0 10"
"${mainMod} CTRL ALT, H, resizeactive, -10 0"
"${mainMod} CTRL ALT, L, resizeactive, 10 0"
"${mainMod} CTRL ALT, K, resizeactive, 0 -10"
"${mainMod} CTRL ALT, J, resizeactive, 0 10"
# Move floating windows
"${mainMod} CTRL, left, moveactive, -50 0"
"${mainMod} CTRL, right, moveactive, 50 0"
"${mainMod} CTRL, up, moveactive, 0 -50"
"${mainMod} CTRL, down, moveactive, 0 50"
"${mainMod} CTRL, H, moveactive, -50 0"
"${mainMod} CTRL, L, moveactive, 50 0"
"${mainMod} CTRL, K, moveactive, 0 -50"
"${mainMod} CTRL, J, moveactive, 0 50"
];
bindm = [
# Move/resize windows with mainMod + LMB/RMB and dragging
"${mainMod}, mouse:272, movewindow"
"${mainMod}, mouse:273, resizewindow"
];
bindel = [
# Media keys
", XF86AudioRaiseVolume, exec, dunst-volume set-volume 5%+"
", XF86AudioLowerVolume, exec, dunst-volume set-volume 5%-"
", XF86MonBrightnessDown, exec, dunst-brightness 5%+"
", XF86MonBrightnessUp, exec, dunst-brightness 5%-"
];
};
extraConfig = ''
# Passthrough mode
bind = ${mainMod}, Escape, submap, passthrough
submap = passthrough
bind = ${mainMod}, Escape, submap, reset
submap = reset
# OBS
bind = ${mainMod} CTRL, O, submap, OBS
submap = OBS
bind = , Space, pass, ^(com\.obsproject\.Studio)$
bind = , P, pass, ^(com\.obsproject\.Studio)$
bind = , Escape, submap, reset
bind = ${mainMod}, Escape, submap, reset
submap = reset
'';
};
systemd.user.services = lib.mkIf cfg.wallpaper.enable {
hyprpaper = lib.mkIf (cfg.wallpaper.backend == "hyprpaper") {
Unit = {
Description = "Background wallpaper image via hyprpaper";
After = "hyprland-session.target";
};
Service = {
ExecStart = let
hyprpaperConfig = pkgs.writeText "hyprpaper.conf" ''
preload = ${cfg.wallpaper.image}
wallpaper = ,${cfg.wallpaper.image}
ipc = off
splash = off
'';
in "${pkgs.hyprpaper}/bin/hyprpaper -c ${hyprpaperConfig}";
};
Install = {
WantedBy = [ "hyprland-session.target" ];
};
};
swaybg = lib.mkIf (cfg.wallpaper.backend == "swaybg") {
Unit = {
Description = "Background wallpaper image via swaybg";
After = "hyprland-session.target";
};
Service = {
ExecStart = "${pkgs.swaybg}/bin/swaybg -i ${cfg.wallpaper.image} -m fill -o '*'";
};
Install = {
WantedBy = [ "hyprland-session.target" ];
};
};
};
});
}