294 lines
8.2 KiB
Nix
294 lines
8.2 KiB
Nix
|
{
|
||
|
inputs,
|
||
|
pkgs,
|
||
|
lib,
|
||
|
config,
|
||
|
...
|
||
|
}:
|
||
|
{
|
||
|
options =
|
||
|
let
|
||
|
inherit (lib) mkOption types;
|
||
|
in
|
||
|
{
|
||
|
hyprland = {
|
||
|
mod = mkOption {
|
||
|
type = types.str;
|
||
|
default = "SUPER";
|
||
|
};
|
||
|
|
||
|
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 = [ ];
|
||
|
};
|
||
|
|
||
|
autoStart = mkOption {
|
||
|
type = types.listOf types.str;
|
||
|
default = [ ];
|
||
|
};
|
||
|
|
||
|
sensitivity = mkOption {
|
||
|
type = types.float;
|
||
|
default = 0.0;
|
||
|
};
|
||
|
|
||
|
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 = { };
|
||
|
};
|
||
|
|
||
|
binds = mkOption {
|
||
|
type = types.attrsOf types.str;
|
||
|
default = { };
|
||
|
};
|
||
|
|
||
|
};
|
||
|
|
||
|
};
|
||
|
|
||
|
config =
|
||
|
let
|
||
|
cfg = config.hyprland;
|
||
|
in
|
||
|
{
|
||
|
nix.settings = {
|
||
|
substituters = [
|
||
|
"https://hyprland.cachix.org"
|
||
|
];
|
||
|
trusted-public-keys = [
|
||
|
"hyprland.cachix.org-1:a7pgxzMz7+chwVL3/pzj6jIBMioiJM7ypFP8PwtkuGc="
|
||
|
];
|
||
|
};
|
||
|
|
||
|
programs.hyprland = {
|
||
|
enable = true;
|
||
|
withUWSM = true;
|
||
|
package = inputs.hyprland.packages.x86_64-linux.hyprland;
|
||
|
};
|
||
|
|
||
|
xdg.portal.extraPortals = [ pkgs.xdg-desktop-portal-gtk ];
|
||
|
|
||
|
environment.systemPackages = with pkgs; [
|
||
|
grim # For xdg-desktop-portal-hyprland which does not declare this dependency
|
||
|
slurp # Some for this one
|
||
|
];
|
||
|
|
||
|
home-manager.users.kalle = {
|
||
|
home.packages = with pkgs; [
|
||
|
wl-clipboard
|
||
|
cliphist
|
||
|
ulauncher
|
||
|
];
|
||
|
|
||
|
wayland.windowManager.hyprland = {
|
||
|
enable = true;
|
||
|
# Disable systemd integration since we are using UWSM
|
||
|
systemd.enable = false;
|
||
|
|
||
|
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" ];
|
||
|
|
||
|
# TODO: Make these start via UWSM
|
||
|
exec-once = [
|
||
|
"${pkgs.wl-clipboard}/bin/wl-paste --watch ${pkgs.cliphist}/bin/cliphist store"
|
||
|
"${pkgs.ulauncher}/bin/ulauncher --no-window-shadow --hide-window"
|
||
|
# TODO: Replace this with hyprland's polkit agent
|
||
|
"${pkgs.libsForQt5.polkit-kde-agent}/libexec/polkit-kde-authentication-agent-1"
|
||
|
] ++ cfg.autoStart;
|
||
|
|
||
|
env = [
|
||
|
"XCURSOR_SIZE,24"
|
||
|
];
|
||
|
|
||
|
input = {
|
||
|
kb_layout = "us";
|
||
|
kb_variant = "";
|
||
|
kb_options = "";
|
||
|
|
||
|
follow_mouse = 1;
|
||
|
|
||
|
touchpad = {
|
||
|
natural_scroll = "yes";
|
||
|
};
|
||
|
|
||
|
sensitivity = cfg.sensitivity;
|
||
|
accel_profile = "flat";
|
||
|
};
|
||
|
|
||
|
general = {
|
||
|
gaps_in = 5;
|
||
|
gaps_out = 10;
|
||
|
|
||
|
border_size = 1;
|
||
|
# TODO: Make this use system color scheme
|
||
|
"col.active_border" = "rgba(33ccffee) rgba(00ff99ee) 45deg";
|
||
|
"col.inactive_border" = "rgba(595959aa)";
|
||
|
|
||
|
layout = "dwindle";
|
||
|
};
|
||
|
|
||
|
misc.force_default_wallpaper = 1;
|
||
|
|
||
|
decoration = {
|
||
|
rounding = 5;
|
||
|
|
||
|
blur = {
|
||
|
enabled = "yes";
|
||
|
size = 3;
|
||
|
passes = 1;
|
||
|
new_optimizations = "on";
|
||
|
};
|
||
|
};
|
||
|
|
||
|
animations = {
|
||
|
enabled = "yes";
|
||
|
|
||
|
bezier = [
|
||
|
"myBezier, 0.05, 0.9, 0.1, 1.05"
|
||
|
];
|
||
|
|
||
|
animation = [
|
||
|
"windows, 1, 3, myBezier"
|
||
|
"windowsOut, 1, 3, default, popin 80%"
|
||
|
"border, 1, 5, default"
|
||
|
"borderangle, 1, 4, default"
|
||
|
"fade, 1, 3, default"
|
||
|
"workspaces, 1, 2, default"
|
||
|
];
|
||
|
};
|
||
|
|
||
|
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: "name:${m.name}, monitor:${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 = 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)
|
||
|
);
|
||
|
|
||
|
# Create binds to manage windows
|
||
|
windowManagementBinds = [
|
||
|
"${cfg.mod} SHIFT, Q, killactive"
|
||
|
"${cfg.mod}, F, togglefloating"
|
||
|
"${cfg.mod} SHIFT, F, fullscreen"
|
||
|
];
|
||
|
|
||
|
configBinds = lib.mapAttrsToList (k: v: "${k}, ${v}") cfg.binds;
|
||
|
in
|
||
|
configBinds ++ workspaceBinds ++ windowManagementBinds;
|
||
|
|
||
|
bindm = [
|
||
|
"${cfg.mod}, mouse:272, movewindow"
|
||
|
"${cfg.mod}, mouse:273, resizewindow"
|
||
|
];
|
||
|
|
||
|
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);
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
};
|
||
|
}
|