dotfiles/hyprland/default.nix

434 lines
11 KiB
Nix

{ inputs
, lib
, config
, pkgs
, ...
}:
{
options =
let
inherit (lib) mkOption types;
in
{
hyprland = {
mod = mkOption {
type = types.str;
default = "SUPER";
};
autoStart = mkOption {
type = types.listOf types.str;
default = [ ];
};
primaryMonitor = mkOption {
type = types.str;
};
monitors = mkOption {
type = types.listOf (types.submodule {
options = {
name = mkOption {
type = types.str;
};
width = mkOption {
type = types.int;
};
height = mkOption {
type = types.int;
};
refreshRate = mkOption {
type = types.int;
default = 60;
};
x = mkOption {
type = types.int;
default = 0;
};
y = mkOption {
type = types.int;
default = 0;
};
transform = mkOption {
type = types.int;
default = 0;
};
vrr = mkOption {
type = types.int;
default = 0;
};
enabled = mkOption {
type = types.bool;
default = true;
};
};
});
default = [ ];
};
environment = mkOption {
type = types.attrsOf types.str;
default = { };
};
sensitivity = mkOption {
type = types.float;
default = 0.0;
};
keyboard = {
layout = mkOption {
type = types.str;
default = "us";
};
variant = mkOption {
type = types.str;
default = "qwerty";
};
options = mkOption {
type = types.str;
default = "";
};
};
inner_gaps = mkOption { type = types.int; };
outer_gaps = mkOption { type = types.int; };
border = {
size = mkOption { type = types.int; };
active = mkOption { type = types.str; };
inactive = mkOption { type = types.str; };
};
animations = {
enable = mkOption {
type = types.bool;
default = true;
};
beziers = mkOption {
type = types.listOf types.str;
default = [
"myBezier, 0.05, 0.9, 0.1, 1.05"
];
};
windows = mkOption {
type = types.str;
default = "1, 3, myBezier";
};
windowsOut = mkOption {
type = types.str;
default = "1, 3, default, popin 80%";
};
border = mkOption {
type = types.str;
default = "1, 5, default";
};
borderangle = mkOption {
type = types.str;
default = "1, 4, default";
};
fade = mkOption {
type = types.str;
default = "1, 3, default";
};
workspaces = mkOption {
type = types.str;
default = "1, 2, default";
};
};
layout = mkOption { type = types.str; };
rounding = mkOption { type = types.int; };
blur = {
enable = mkOption {
type = types.bool;
default = true;
};
size = mkOption {
type = types.int;
default = 3;
};
passes = mkOption {
type = types.int;
default = 1;
};
};
shadow = {
enable = mkOption {
type = types.bool;
default = true;
};
range = mkOption {
type = types.int;
default = 4;
};
strength = mkOption {
type = types.int;
default = 3;
};
color = mkOption {
type = types.str;
default = "rgba(1a1a1aee)";
};
};
layerRules = mkOption {
type = types.attrsOf (types.listOf types.str);
default = { };
};
windowRules = mkOption {
type = types.attrsOf (types.listOf types.str);
default = { };
};
windowRulesV2 = mkOption {
type = types.attrsOf (types.listOf types.str);
default = { };
};
generateWorkspaceBinds = mkOption {
type = types.bool;
default = true;
};
generateWindowManagementBinds = mkOption {
type = types.bool;
default = true;
};
binds = mkOption {
type = types.attrsOf types.str;
default = { };
};
mouseBinds = mkOption {
type = types.attrsOf types.str;
default = { };
};
};
};
config =
let
cfg = config.hyprland;
in
{
home.packages = with pkgs; [
wl-clipboard
cliphist
ulauncher
];
wayland.windowManager.hyprland = {
enable = true;
settings = {
monitor = map
(m:
let
resolution = "${toString m.width}x${toString m.height}@${toString m.refreshRate}";
position = "${toString m.x}x${toString m.y}";
vrr = if m.vrr != 0 then ",vrr,${toString m.vrr}" else "";
transform = if m.transform != 0 then ",transform,${toString m.transform}" else "";
in
"${m.name},${if m.enabled then "${resolution},${position},1${vrr}${transform}" else "disable"}"
)
(cfg.monitors)
# Automatically detect newly connected monitors
++ [ ",preferred,auto,auto" ];
exec-once = [
"${pkgs.wl-clipboard}/bin/wl-paste --watch ${pkgs.cliphist}/bin/cliphist store"
"${pkgs.ulauncher}/bin/ulauncher --no-window-shadow --hide-window"
"${pkgs.libsForQt5.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1"
# kde-connect (somehow, wasnt working well last time)
] ++ cfg.autoStart;
env = lib.mapAttrsToList (k: v: "${toString k},${v}") cfg.environment;
input = {
kb_layout = cfg.keyboard.layout;
kb_variant = cfg.keyboard.variant;
kb_options = cfg.keyboard.options;
follow_mouse = 1;
touchpad = {
natural_scroll = "yes";
};
sensitivity = cfg.sensitivity;
accel_profile = "flat";
};
general = {
gaps_in = cfg.inner_gaps;
gaps_out = cfg.outer_gaps;
border_size = cfg.border.size;
"col.active_border" = cfg.border.active;
"col.inactive_border" = cfg.border.inactive;
layout = cfg.layout;
};
misc = {
force_default_wallpaper = 2;
};
decoration = {
rounding = cfg.rounding;
blur = {
enabled = if cfg.blur.enable then "yes" else "no";
size = cfg.blur.size;
passes = cfg.blur.passes;
new_optimizations = "on";
};
drop_shadow = if cfg.shadow.enable then "yes" else "no";
shadow_range = cfg.shadow.range;
shadow_render_power = cfg.shadow.strength;
"col.shadow" = cfg.shadow.color;
};
dwindle = {
pseudotile = "yes";
preserve_split = "yes";
};
master = {
new_is_master = true;
};
gestures = {
workspace_swipe = "on";
};
animations = {
enabled = if cfg.animations.enable then "yes" else "no";
# Some default animations, see https://wiki.hyprland.org/Configuring/Animations/ for more
bezier = cfg.animations.beziers;
animation = [
"windows, ${cfg.animations.windows}"
"windowsOut, ${cfg.animations.windowsOut}"
"border, ${cfg.animations.border}"
"borderangle, ${cfg.animations.borderangle}"
"fade, ${cfg.animations.fade}"
"workspaces, ${cfg.animations.workspaces}"
];
};
layerrule =
let
y = ident: value: "${value},${ident}";
x = ident: values: map (y ident) values;
in
lib.flatten (lib.mapAttrsToList x cfg.layerRules);
workspace =
let
# Create one work space for each non primary monitor
perMonitorWorkspaces = map
(m: "${m.name}, name:${m.name}")
(lib.filter
(m: m.name != cfg.primaryMonitor)
cfg.monitors
);
# Create 10 work spaces on the primary monitor
primaryMonitorWorkspaces = map (i: "${toString i}, monitor:${cfg.primaryMonitor}") (lib.range 1 10);
in
primaryMonitorWorkspaces ++ perMonitorWorkspaces;
bind =
let
# Create binds to switch workspaces and move windows between them
workspaceBinds =
if cfg.generateWorkspaceBinds then
lib.flatten
(map
(i:
let
k = if i == 10 then 0 else i;
in
[
"${cfg.mod}, ${toString k}, workspace, ${toString i}"
"${cfg.mod} SHIFT, ${toString k}, movetoworkspace, ${toString i}"
]
)
(lib.range 1 10)
)
else
[ ];
# Create binds to manage wiwdows
windowManagementBinds =
if cfg.generateWindowManagementBinds then [
"${cfg.mod} SHIFT, Q, killactive"
"${cfg.mod}, F, togglefloating"
"${cfg.mod} SHIFT, F, fullscreen"
]
else
[ ];
configBinds = lib.mapAttrsToList (k: v: "${k}, ${v}") cfg.binds;
in
configBinds ++ workspaceBinds ++ windowManagementBinds;
bindm =
let
windowManagementBinds =
if cfg.generateWindowManagementBinds then [
"${cfg.mod}, mouse:272, movewindow"
"${cfg.mod}, mouse:273, resizewindow"
]
else
[ ];
configBinds = lib.mapAttrsToList (k: v: "${k}, ${v}") cfg.mouseBinds;
in
configBinds ++ windowManagementBinds;
windowrule =
let
y = ident: value: "${value},${ident}";
x = ident: values: map (y ident) values;
in
lib.flatten (lib.mapAttrsToList x cfg.windowRules);
windowrulev2 =
let
y = ident: value: "${value},${ident}";
x = ident: values: map (y ident) values;
in
lib.flatten (lib.mapAttrsToList x cfg.windowRulesV2);
};
};
};
}