Files
dotfiles/config/modules/hyprland/doloro-settings.nix
T
2026-09-15 11:49:20 +01:00

508 lines
18 KiB
Nix

{ modules, ... }:
{
modules.hyprland = {
provides = {
doloro-settings = {
includes = [
modules.dunst
];
homeManager =
{
pkgs,
lib,
...
}:
let
tofiCfg = pkgs.writeTextFile {
name = "hyprland-tofi-config";
text = ''
width = 100%
height = 100%
border-width = 0
outline-width = 0
padding-left = 35%
padding-top = 35%
result-spacing = 25
num-results = 5
font = monospace
background-color = #000A
'';
};
meowScript = pkgs.writeShellScript "meow" ''
fish -c 'grim -g $(slurp) -t png - &| wl-copy -t image/png; killall wayfreeze'
'';
mreowScript = pkgs.writeShellScript "mreow" ''
exec $(tofi-drun -c ${tofiCfg})
'';
mainMod = "SUPER";
# Each `settings.<fn>` list entry renders as `hl.<fn>(<table>)`.
# `_args` renders a multi-argument call instead of one Lua table,
# and mkLuaInline passes raw Lua through for dispatchers.
dsp = lib.generators.mkLuaInline;
bind = key: dispatcher: {
_args = [
key
dispatcher
];
};
bezier = name: points: {
_args = [
name
{
type = "bezier";
inherit points;
}
];
};
wsBinds = lib.concatLists (
builtins.genList (
i:
let
ws = toString (i + 1);
in
[
(bind "${mainMod} + ${ws}" (dsp "hl.dsp.focus({ workspace = ${ws} })"))
(bind "${mainMod} + SHIFT + ${ws}" (dsp "hl.dsp.window.move({ workspace = ${ws} })"))
]
) 9
);
in
{
home.packages = [
pkgs.hyprcursor
pkgs.hyprshutdown
pkgs.tofi
pkgs.killall
pkgs.grim
pkgs.slurp
pkgs.wayclip
];
# wlogout menu. Default layout, except Shutdown hands off to
# hyprshutdown so apps close gracefully before poweroff.
# programs.wlogout only accepts one command per button, so
# --post-cmd carries the actual poweroff.
programs.wlogout = {
enable = true;
layout = [
{
label = "lock";
action = "loginctl lock-session";
text = "Lock";
keybind = "l";
}
{
label = "hibernate";
action = "systemctl hibernate";
text = "Hibernate";
keybind = "h";
}
{
label = "logout";
action = "loginctl terminate-user $USER";
text = "Logout";
keybind = "e";
}
{
label = "shutdown";
action = "hyprshutdown --post-cmd 'systemctl poweroff'";
text = "Shutdown";
keybind = "s";
}
{
label = "suspend";
action = "systemctl suspend";
text = "Suspend";
keybind = "u";
}
{
label = "reboot";
action = "hyprshutdown --post-cmd 'systemctl reboot'";
text = "Reboot";
keybind = "r";
}
];
};
home.pointerCursor = {
enable = true;
name = "rose-pine-hyprcursor";
package = pkgs.rose-pine-hyprcursor;
hyprcursor.enable = true;
};
services.hyprpaper = {
enable = true;
settings = {
splash = true;
wallpaper = [
{
monitor = "HDMI-A-1";
path = "/home/doloro/Wallpaper.jpg";
}
{
monitor = "DP-2";
path = "/home/doloro/Wallpaper.jpg";
}
];
};
};
# The systemd session activation hooks (hyprland-session.target
# start/stop + dbus-update-activation-environment --systemd --all)
# are still generated by Home Manager; only the imperative tail of
# the config needs raw Lua.
wayland.windowManager.hyprland = {
settings = {
config = {
general = {
gaps_in = 1;
gaps_out = 1;
border_size = 1;
resize_on_border = false;
allow_tearing = true;
layout = "dwindle";
};
input = {
follow_mouse = 2;
kb_layout = "gb";
};
decoration = {
rounding = 4;
rounding_power = 1;
active_opacity = 1.0;
inactive_opacity = 1.0;
shadow.enabled = false;
blur = {
enabled = true;
passes = 1;
new_optimizations = true;
ignore_opacity = false;
};
};
cursor.default_monitor = "DP-2";
cursor.no_hardware_cursors = false;
dwindle.preserve_split = true;
misc = {
force_default_wallpaper = -1;
disable_hyprland_logo = false;
enable_anr_dialog = false;
};
};
monitor = [
{
output = "HDMI-A-1";
mode = "1920x1080@60";
position = "0x0";
scale = "1";
}
{
output = "DP-2";
mode = "1920x1080@120";
position = "1920x0";
scale = "1";
}
];
workspace_rule = [
{
workspace = "2";
monitor = "DP-2";
default = true;
}
]
++ builtins.genList (i: {
workspace = toString (i + 2);
monitor = "DP-2";
}) 9;
device = {
name = "default";
kb_layout = "gb";
sensitivity = -0.5;
};
# Curves are sorted ahead of animations by the module's
# `importantPrefixes` default, so the beziers exist by name.
curve = [
(bezier "easeOutQuint" [
[
0.23
1
]
[
0.32
1
]
])
(bezier "easeInOutCubic" [
[
0.65
0.05
]
[
0.36
1
]
])
(bezier "linear" [
[
0
0
]
[
1
1
]
])
(bezier "almostLinear" [
[
0.5
0.5
]
[
0.75
1
]
])
(bezier "quick" [
[
0.15
0
]
[
0.1
1
]
])
];
animation = [
{
leaf = "global";
enabled = true;
speed = 10;
bezier = "default";
}
{
leaf = "border";
enabled = true;
speed = 5.39;
bezier = "easeOutQuint";
}
{
leaf = "windows";
enabled = true;
speed = 2.79;
bezier = "easeOutQuint";
}
{
leaf = "windowsIn";
enabled = true;
speed = 1;
bezier = "easeOutQuint";
style = "popin 87%";
}
{
leaf = "windowsOut";
enabled = true;
speed = 1;
bezier = "linear";
style = "popin 87%";
}
{
leaf = "windowsMove";
enabled = true;
speed = 1;
bezier = "easeInOutCubic";
}
{
leaf = "fadeIn";
enabled = true;
speed = 0.5;
bezier = "almostLinear";
}
{
leaf = "fadeOut";
enabled = true;
speed = 0.5;
bezier = "almostLinear";
}
{
leaf = "fade";
enabled = true;
speed = 1;
bezier = "quick";
}
{
leaf = "layers";
enabled = true;
speed = 3.81;
bezier = "easeOutQuint";
}
{
leaf = "layersIn";
enabled = true;
speed = 4;
bezier = "easeOutQuint";
style = "fade";
}
{
leaf = "layersOut";
enabled = true;
speed = 1.5;
bezier = "linear";
style = "fade";
}
{
leaf = "fadeLayersIn";
enabled = true;
speed = 1.79;
bezier = "almostLinear";
}
{
leaf = "fadeLayersOut";
enabled = true;
speed = 1.39;
bezier = "almostLinear";
}
{
leaf = "workspaces";
enabled = true;
speed = 1;
bezier = "almostLinear";
style = "slide";
}
{
leaf = "workspacesIn";
enabled = true;
speed = 1;
bezier = "easeInOutCubic";
style = "slide";
}
{
leaf = "workspacesOut";
enabled = true;
speed = 1;
bezier = "easeInOutCubic";
style = "slide";
}
{
leaf = "zoomFactor";
enabled = true;
speed = 7;
bezier = "quick";
}
];
bind = [
(bind "${mainMod} + R" (dsp ''hl.dsp.exec_cmd("${mreowScript}")''))
(bind "${mainMod} + C" (dsp "hl.dsp.window.close()"))
(bind "${mainMod} + M" (dsp ''hl.dsp.exec_cmd("uwsm stop")''))
(bind "${mainMod} + Q" (dsp ''hl.dsp.exec_cmd("kitty")''))
(bind "${mainMod} + V" (dsp ''hl.dsp.window.float({ action = "toggle" })''))
(bind "${mainMod} + left" (dsp ''hl.dsp.focus({ direction = "left" })''))
(bind "${mainMod} + right" (dsp ''hl.dsp.focus({ direction = "right" })''))
(bind "${mainMod} + up" (dsp ''hl.dsp.focus({ direction = "up" })''))
(bind "${mainMod} + down" (dsp ''hl.dsp.focus({ direction = "down" })''))
(bind "${mainMod} + L" (dsp ''hl.dsp.exec_cmd("wlogout")''))
(bind "${mainMod} + S" (dsp ''hl.dsp.exec_cmd("wayfreeze --after-freeze-cmd '${meowScript}'")''))
(bind "${mainMod} + F" (dsp ''hl.dsp.window.fullscreen({ action = "toggle" })''))
(bind "${mainMod} + SHIFT + Q" (dsp "hl.dsp.window.close()"))
(bind "${mainMod} + mouse_down" (dsp ''hl.dsp.focus({ workspace = "e+1" })''))
(bind "${mainMod} + mouse_up" (dsp ''hl.dsp.focus({ workspace = "e-1" })''))
# Mouse binds
(bind "${mainMod} + mouse:272" (dsp "hl.dsp.window.drag()"))
(bind "${mainMod} + mouse:273" (dsp "hl.dsp.window.resize()"))
# Media keys
(bind "XF86AudioLowerVolume" (dsp ''hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%-")''))
(bind "XF86AudioRaiseVolume" (dsp ''hl.dsp.exec_cmd("wpctl set-volume @DEFAULT_AUDIO_SINK@ 5%+")''))
(bind "XF86AudioMute" (dsp ''hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle")''))
(bind "XF86AudioPlay" (dsp ''hl.dsp.exec_cmd("playerctl play-pause")''))
(bind "XF86AudioNext" (dsp ''hl.dsp.exec_cmd("playerctl next")''))
(bind "XF86AudioPrev" (dsp ''hl.dsp.exec_cmd("playerctl previous")''))
(bind "XF86AudioMicMute" (dsp ''hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle")''))
(bind "home" (dsp ''hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SINK@ toggle")''))
(bind "end" (dsp ''hl.dsp.exec_cmd("wpctl set-mute @DEFAULT_AUDIO_SOURCE@ toggle")''))
(bind "F8" (dsp "hl.dsp.pass({ window = [[match:class:^(com.obsproject.Studio)$]] })"))
# Workspaces
(bind "${mainMod} + 0" (dsp "hl.dsp.focus({ workspace = 10 })"))
(bind "${mainMod} + SHIFT + 0" (dsp "hl.dsp.window.move({ workspace = 10 })"))
]
++ wsBinds;
window_rule = [
{ suppress_event = "maximize"; }
{
match.class = "gamescope";
workspace = "5";
immediate = true;
confine_pointer = true;
}
{
match.initial_title = "OBS Studio Crash Detected";
pin = true;
}
# Steam, Discord (equibop), Telegram, Spotify and OBS
# always open on their own workspace regardless of how
# they were launched. These sit before the "Discord
# Popout" rule: window rules apply in declaration order
# and the last match wins, so popouts still land on
# workspace 1.
{
match.class = "steam";
workspace = "6 silent";
}
{
match.class = "equibop";
workspace = "8 silent";
}
{
match.class = "org.telegram.desktop";
workspace = "8 silent";
}
{
match.class = "spotify";
workspace = "9 silent";
}
{
match.class = "com.obsproject.Studio";
workspace = "10 silent";
}
{
match.initial_title = "Discord Popout";
workspace = "1 silent";
}
];
layer_rule = [
{
match.namespace = "notifications";
no_screen_share = true;
}
];
};
# Host-specific overrides: load ~/.config/hypr/hyprland-local.lua
# if present (must be valid Lua). Runs last so a host can override
# anything set above.
extraConfig = ''
local home = os.getenv("HOME")
if home then
local localPath = home .. '/.config/hypr/hyprland-local.lua'
local f = io.open(localPath, 'r')
if f then
f:close()
local chunk, err = loadfile(localPath)
if chunk then chunk() else io.stderr:write('hyprland-local.lua error: ' .. err .. '\n') end
end
end
'';
};
};
};
};
};
}