1{ lib, config, pkgs, ... }:
2
3with lib;
4let
5 cfg = config.modules.desktop;
6
7 system-shell = "${getExe pkgs.system-shell}";
8 wpctl = "${pkgs.wireplumber}/bin/wpctl";
9 brightnessctl = "${pkgs.brightnessctl}/bin/brightnessctl";
10
11 hyprshot = getExe (pkgs.hyprshot.overrideAttrs (oldAttrs: {
12 postInstall = (oldAttrs.postInstall or "") + ''
13 wrapProgram $out/bin/hyprshot \
14 --set HYPRSHOT_DIR "${config.xdg.userDirs.pictures}/Screenshots"
15 '';
16 }));
17in {
18 options.modules.desktop.hyprland = {
19 enable = mkOption {
20 default = cfg.enable;
21 example = true;
22 description = "Whether to enable Hyprland configuration.";
23 type = types.bool;
24 };
25 };
26
27 config = mkIf cfg.hyprland.enable {
28 wayland.windowManager.hyprland = {
29 enable = true;
30
31 package = null;
32 portalPackage = null;
33 systemd.enable = false;
34 xwayland.enable = false;
35 plugins = with pkgs.hyprlandPlugins; [ hyprspace ];
36
37 settings = {
38 source = [ "/etc/hypr/hyprland.conf" ];
39
40 general = {
41 gaps_out = 9;
42 gaps_in = 4;
43 allow_tearing = true;
44 resize_on_border = true;
45 hover_icon_on_border = false;
46 no_border_on_floating = true;
47 extend_border_grab_area = 10;
48 border_size = 1;
49 "col.active_border" = "0xB35A5A5A";
50 "col.inactive_border" = "0x8C3A3A3A";
51 };
52
53 decoration = {
54 rounding = 9;
55 dim_inactive = true;
56 dim_strength = 0.12;
57
58 blur = {
59 enabled = true;
60 size = 6;
61 passes = 4;
62 contrast = 0.74;
63 brightness = 0.45;
64 vibrancy = 0.15;
65 vibrancy_darkness = 0.1;
66 ignore_opacity = false;
67 popups_ignorealpha = 0.1;
68 input_methods_ignorealpha = 0.1;
69 noise = 0.012;
70 };
71
72 shadow = {
73 color = "0x81000000";
74 range = 40;
75 render_power = 2;
76 offset = "5, 5";
77 };
78 };
79
80 gestures = {
81 workspace_swipe = true;
82 workspace_swipe_invert = false;
83 workspace_swipe_cancel_ratio = 0.2;
84 workspace_swipe_distance = 560;
85 };
86
87 misc = {
88 middle_click_paste = false;
89 focus_on_activate = true;
90 key_press_enables_dpms = true;
91 disable_hyprland_logo = true;
92 disable_splash_rendering = true;
93 vrr = 1;
94 };
95
96 debug.error_position = 1;
97
98 plugin.overview = {
99 autoDrag = true;
100 hideOverlayLayers = false;
101 exitOnSwitch = true;
102 reverseSwipe = true;
103 dragAlpha = 0.85;
104 workspaceMargin = 16;
105 panelHeight = 150;
106 reservedArea = 38;
107 };
108
109 bindm = [
110 "SUPER, mouse:272, movewindow"
111 "SUPERSHIFT, mouse:272, resizewindow"
112 ];
113
114 bindel = [
115 ", XF86AudioRaiseVolume, exec, ${wpctl} set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 3%+"
116 ", XF86AudioLowerVolume, exec, ${wpctl} set-volume -l 1.0 @DEFAULT_AUDIO_SINK@ 3%-"
117 ", XF86MonBrightnessDown, exec, ${brightnessctl} set 3%-"
118 ", XF86MonBrightnessUp, exec, ${brightnessctl} set +3%"
119 ];
120
121 bindl = [
122 ", XF86AudioMute, exec, ${wpctl} set-mute @DEFAULT_AUDIO_SINK@ toggle"
123 ", XF86AudioMicMute, exec, ${wpctl} set-mute @DEFAULT_AUDIO_SOURCE@ toggle"
124 ", XF86AudioPlay, exec, ${system-shell} play_pause"
125 ", XF86AudioPause, exec, ${system-shell} play_pause"
126 ", XF86AudioNext, exec, ${system-shell} play_next"
127 ", XF86AudioPrev, exec, ${system-shell} play_previous"
128 ];
129
130 bindp = [
131 ", F11, fullscreen, 0"
132 "SUPER, W, killactive"
133
134 "SUPER, H, movefocus, l"
135 "SUPER, J, movefocus, d"
136 "SUPER, K, movefocus, u"
137 "SUPER, L, movefocus, r"
138 "SUPER_SHIFT, H, movewindow, l"
139 "SUPER_SHIFT, J, movewindow, d"
140 "SUPER_SHIFT, K, movewindow, u"
141 "SUPER_SHIFT, L, movewindow, r"
142
143 "SUPER_CONTROL, K, overview:toggle, all"
144 "SUPER_CONTROL, H, workspace, m-1"
145 "SUPER_CONTROL, L, workspace, m+1"
146 "SUPER_CONTROL_SHIFT, H, movetoworkspace, -1"
147 "SUPER_CONTROL_SHIFT, L, movetoworkspace, +1"
148
149 "SUPER, up, overview:toggle, all"
150 "SUPER, left, workspace, m-1"
151 "SUPER, right, workspace, m+1"
152 "SUPER_SHIFT, left, movetoworkspace, m-1"
153 "SUPER_SHIFT, right, movetoworkspace, m+1"
154
155 "SUPER_CONTROL, left, focusmonitor, -1"
156 "SUPER_CONTROL, right, focusmonitor, +1"
157 "SUPER_CONTROL_SHIFT, left, movecurrentworkspacetomonitor, -1"
158 "SUPER_CONTROL_SHIFT, right, movecurrentworkspacetomonitor, +1"
159 ];
160
161 bind = [
162 "SUPER, SUPER_L, exec, ${system-shell} launcher"
163
164 "SUPER, T, exec, uwsm-app ghostty"
165 "SUPER, B, exec, uwsm-app zen-beta"
166
167 "SUPER_SHIFT, F, fullscreen, 1"
168
169 "SUPER, 1, workspace, 1"
170 "SUPER, 2, workspace, 2"
171 "SUPER, 3, workspace, 3"
172 "SUPER, 4, workspace, 4"
173 "SUPER, 5, workspace, 5"
174 "SUPER, 6, workspace, 6"
175 "SUPER, 7, workspace, 7"
176 "SUPER, 8, workspace, 8"
177 "SUPER, 9, workspace, 9"
178 "SUPER, 0, workspace, 10"
179
180 "SUPER_SHIFT, 2, exec, ${hyprshot} -z -m window -m active"
181 "SUPER_SHIFT, 3, exec, ${hyprshot} -z -m output -m active"
182 "SUPER_SHIFT, 4, exec, ${hyprshot} -z -m region"
183 ", Print, exec, ${hyprshot} -z -m window -m active"
184 "SUPER, Print, exec, ${hyprshot} -z -m output -m active"
185 "SUPER_SHIFT, Print, exec, ${hyprshot} -z -m region"
186 ];
187
188 windowrule = [
189 "suppressevent maximize, class:.*"
190
191 "nofocus, class:^$, title:^$, xwayland:1, floating:1, fullscreen:0, pinned:0"
192 "tag +games, initialClass:^(.*)[.]exe$, fullscreenstate:* 2"
193
194 "immediate, fullscreenstate:2"
195 "immediate, fullscreenstate:3"
196 "syncfullscreen, fullscreen:1"
197 "idleinhibit, fullscreen:1"
198
199 "content game, tag:games"
200 "tag +games, content:game"
201
202 "opaque, tag:games"
203 "immediate, tag:games"
204 "idleinhibit fullscreen, tag:games"
205 "fullscreenstate:3 3, tag:games, fullscreen:1"
206 "float, tag:games, fullscreen:1"
207
208 "float, class:zen-beta,initialTitle:^(Picture-in-Picture)$"
209 "pin, class:zen-beta,initialTitle:^(Picture-in-Picture)$"
210 "idleinhibit fullscreen,class:zen-beta"
211
212 "float,title:^(Open)$"
213 "float,title:^(Choose Files)$"
214 "float,title:^(Save As)$"
215 "float,title:^(Confirm to replace files)$"
216 "float,title:^(File Operation Progress)$"
217 ];
218
219 layerrule = [
220 "blur, system-shell"
221 "ignorezero, system-shell"
222 "animation slide, system-shell"
223 "abovelock, system-shell"
224
225 "blur, system-bar"
226 "xray on, system-bar"
227 "ignorezero, system-bar"
228 "animation slide, system-bar"
229 ];
230 };
231 };
232
233 home.packages = with pkgs; [ nautilus ];
234
235 xdg.configFile."uwsm/env".source = let
236 inherit (config.home) sessionVariables;
237 export = k: v: "export ${builtins.toString k}=${builtins.toString v}";
238 env = strings.concatLines (attrsets.mapAttrsToList export sessionVariables);
239 in pkgs.writeText "env" env;
240
241 services = {
242 hyprpolkitagent.enable = true;
243 hypridle = {
244 enable = true;
245 settings = {
246 general = {
247 lock_cmd = "pidof hyprlock || hyprlock";
248 before_sleep_cmd = "loginctl lock-session";
249 after_sleep_cmd = "hyprctl dispatch dpms on";
250 };
251 listener = [
252 {
253 timeout = 300;
254 on-timeout = "loginctl lock-session";
255 }
256 {
257 timeout = 330;
258 on-timeout = "hyprctl dispatch dpms off";
259 on-resume = "hyprctl dispatch dpms on";
260 }
261 {
262 timeout = 600;
263 on-timeout = "systemctl suspend";
264 }
265 ];
266 };
267 };
268 wpaperd = {
269 enable = true;
270 package = pkgs.wpaperd.overrideAttrs (old: {
271 cargoBuildFlags = [ "--no-default-features" ];
272 });
273 settings.default = {
274 path = "${config.xdg.userDirs.pictures}/Wallpapers";
275 mode = "center";
276 duration = "8h";
277 sorting = "random";
278 };
279 };
280 };
281
282 programs.hyprlock = {
283 enable = true;
284 package = null;
285 settings = {
286 general = {
287 disable_loading_bar = true;
288 grace = 10;
289 hide_cursor = true;
290 no_fade_in = false;
291 };
292 background = [
293 {
294 path = "";
295 blur_passes = 3;
296 blur_size = 8;
297 }
298 ];
299 input-field = [
300 {
301 size = "200, 50";
302 position = "0, -80";
303 dots_center = true;
304 fade_on_empty = false;
305 font_color = "rgb(202, 211, 245)";
306 inner_color = "rgb(91, 96, 120)";
307 outer_color = "rgb(24, 25, 38)";
308 outline_thickness = 5;
309 shadow_passes = 2;
310 }
311 ];
312 };
313 };
314
315 systemd.user.services = {
316 hyprpolkitagent.Service.Slice = "session.slice";
317 hypridle.Service.Slice = "session.slice";
318 wpaperd.Service.Slice = "session.slice";
319
320 system-shell-notifd = {
321 Install.WantedBy = [ "system-shell.service" ];
322 Service = {
323 ExecStart = "${pkgs.astal.notifd}/bin/astal-notifd -d";
324 Restart = "on-failure";
325 RestartSec = 5;
326 Slice = "background.slice";
327 };
328 Unit = {
329 After = [ config.wayland.systemd.target ];
330 PartOf = [ config.wayland.systemd.target ];
331 };
332 };
333
334 system-shell = {
335 Install.WantedBy = [ "graphical-session.target" ];
336 Service = {
337 ExecStart = "${system-shell}";
338 Restart = "on-failure";
339 RestartSec = 10;
340 Environment = [ "GSK_RENDERER=ngl" ];
341 Slice = "session.slice";
342 };
343 Unit = {
344 After = [ config.wayland.systemd.target ];
345 ConditionEnvironment = "WAYLAND_DISPLAY";
346 PartOf = [ config.wayland.systemd.target ];
347 };
348 };
349 };
350 };
351}