blob: 571fe93dcc8502501fd037f897dce858ea5eb53e [file] [log] [blame]
Skyler Grey69a999e2024-05-23 00:09:10 +00001{
2 pkgs,
3 config,
4 inputs,
5 system,
6 lib,
7 ...
Skyler Grey035c8d12024-05-26 21:23:33 +00008}:
9{
Skyler Grey69a999e2024-05-23 00:09:10 +000010
11 options.chimera.niri = {
12 enable = lib.mkEnableOption "Use Niri as your window manager";
Skyler Grey035c8d12024-05-26 21:23:33 +000013 xwayland.enable = lib.mkOption {
14 type = lib.types.bool;
15 default = true;
16 description = "Enable xwayland-satellite to run X apps in niri";
17 };
Skyler Grey69a999e2024-05-23 00:09:10 +000018 monitors = lib.mkOption {
Skyler Grey035c8d12024-05-26 21:23:33 +000019 type = lib.types.attrsOf (
20 lib.types.submodule {
21 options = {
22 enable = lib.mkOption {
Skyler Grey69a999e2024-05-23 00:09:10 +000023 type = lib.types.bool;
Skyler Grey035c8d12024-05-26 21:23:33 +000024 default = true;
25 description = "Enable this monitor";
Skyler Grey69a999e2024-05-23 00:09:10 +000026 };
Skyler Grey035c8d12024-05-26 21:23:33 +000027 mode = lib.mkOption {
28 type = lib.types.nullOr (
29 lib.types.submodule {
30 options = {
31 width = lib.mkOption { type = lib.types.int; };
32 height = lib.mkOption { type = lib.types.int; };
33 refresh = lib.mkOption {
34 type = lib.types.nullOr lib.types.float;
35 default = null;
36 };
37 };
38 }
39 );
40 default = null;
Skyler Grey69a999e2024-05-23 00:09:10 +000041 };
Skyler Grey035c8d12024-05-26 21:23:33 +000042 position = lib.mkOption {
43 type = lib.types.nullOr (
44 lib.types.submodule {
45 options = {
46 x = lib.mkOption { type = lib.types.int; };
47 y = lib.mkOption { type = lib.types.int; };
48 };
49 }
50 );
51 default = null;
52 };
53 scale = lib.mkOption {
54 type = lib.types.float;
55 default = 1.0;
56 };
57 transform = {
58 flipped = lib.mkOption {
59 type = lib.types.bool;
60 default = false;
61 };
62 rotation = lib.mkOption {
63 type = lib.types.enum [
64 0
65 90
66 180
67 270
68 ];
69 default = 0;
70 };
71 };
72 variable-refresh-rate = lib.mkEnableOption "Enable Variable Refresh Rate (AMD FreeSync / Nvidia G-Sync)";
Skyler Grey69a999e2024-05-23 00:09:10 +000073 };
Skyler Grey035c8d12024-05-26 21:23:33 +000074 }
75 );
Skyler Grey69a999e2024-05-23 00:09:10 +000076 description = "Atribute set of monitors";
77 default = { };
78 };
Samuel Shuert35d5f652024-07-01 13:09:28 -040079 startupCommands = lib.mkOption {
80 type = lib.types.listOf (lib.types.submodule {
81 options = {
82 command = lib.mkOption {
83 type = lib.types.listOf lib.types.str;
84 description = "Command to run";
85 };
86 };
87 });
88 description = "List of commands to run at startup";
89 default = [ ];
90 };
Skyler Grey69a999e2024-05-23 00:09:10 +000091 };
92
93 config = lib.mkIf config.chimera.niri.enable {
94 chimera.wayland.enable = true;
95
Skyler Grey035c8d12024-05-26 21:23:33 +000096 programs.bash.profileExtra = lib.mkIf config.chimera.shell.bash.enable (
97 lib.mkBefore ''
98 if [ -z $WAYLAND_DISPLAY ] && [ "$(tty)" = "/dev/tty1" ]; then
99 exec ${pkgs.systemd}/bin/systemd-cat -t niri ${pkgs.dbus}/bin/dbus-run-session ${config.programs.niri.package}/bin/niri --session
100 fi
101 ''
102 );
Skyler Grey69a999e2024-05-23 00:09:10 +0000103
Skyler Grey035c8d12024-05-26 21:23:33 +0000104 programs.zsh.profileExtra = lib.mkIf config.chimera.shell.zsh.enable (
105 lib.mkBefore ''
106 if [ -z $WAYLAND_DISPLAY ] && [ "$(tty)" = "/dev/tty1" ]; then
Skyler Greye5084c52024-07-21 12:27:18 +0000107 exec ${pkgs.systemd}/bin/systemd-run --user -u niri ${pkgs.dbus}/bin/dbus-run-session ${config.programs.niri.package}/bin/niri --session
Skyler Grey035c8d12024-05-26 21:23:33 +0000108 fi
109 ''
110 );
Skyler Grey69a999e2024-05-23 00:09:10 +0000111
Skyler Grey035c8d12024-05-26 21:23:33 +0000112 programs.niri =
113 let
114 mod = "Super";
115 mod1 = "Alt";
116 terminal = "${pkgs.kitty}/bin/kitty";
117 menu = (
118 if config.chimera.runner.anyrun.enable then
119 "${inputs.anyrun.packages.${system}.anyrun}/bin/anyrun"
120 else
121 ""
122 );
Skyler Grey69a999e2024-05-23 00:09:10 +0000123
Skyler Grey035c8d12024-05-26 21:23:33 +0000124 lock = ''${pkgs.swaylock}/bin/swaylock -i ${config.chimera.theme.wallpaper} -s fill'';
125 in
126 {
127 enable = true;
128 package = pkgs.niri-stable;
129 settings = {
130 environment = {
131 NIXOS_OZONE_WL = "1";
132 DISPLAY = lib.mkIf config.chimera.niri.xwayland.enable ":0";
Skyler Grey69a999e2024-05-23 00:09:10 +0000133 };
Skyler Grey035c8d12024-05-26 21:23:33 +0000134
135 input.keyboard = {
136 track-layout = "window";
137 repeat-delay = 200;
138 repeat-rate = 25;
139 xkb = {
140 layout = config.chimera.input.keyboard.layout;
141 variant = config.chimera.input.keyboard.variant;
142 };
143 };
Skyler Grey69a999e2024-05-23 00:09:10 +0000144
145 input.mouse.natural-scroll = config.chimera.input.mouse.scrolling.natural;
146 input.touchpad.natural-scroll = config.chimera.input.touchpad.scrolling.natural;
147
148 input.warp-mouse-to-focus = true;
Skyler Grey035c8d12024-05-26 21:23:33 +0000149 input.focus-follows-mouse = {
150 enable = true;
151 max-scroll-amount = "0%";
152 };
Skyler Grey69a999e2024-05-23 00:09:10 +0000153
154 input.power-key-handling.enable = false;
155
156 binds = let
157 inherit (config.lib.niri) actions;
158
159 generateWorkspaceBindings = workspaceNumber: {
160 "${mod}+${builtins.toString (lib.mod workspaceNumber 10)}".action = actions.focus-workspace workspaceNumber;
161 "${mod}+Shift+${builtins.toString (lib.mod workspaceNumber 10)}".action = actions.move-column-to-workspace workspaceNumber;
162 };
163 joinAttrsetList = listOfAttrsets: lib.fold (a: b: a // b) {} listOfAttrsets;
164 in { # General Keybinds
165 "${mod}+Q".action = actions.close-window;
166 "${mod}+Return".action = actions.spawn "${terminal}";
167 "${mod}+L".action = actions.spawn ["sh" "-c" "${config.programs.niri.package}/bin/niri msg action do-screen-transition && ${lock}"];
168 "${mod}+P".action = actions.power-off-monitors;
169
170 "${mod}+R".action = actions.screenshot;
171 "${mod}+Ctrl+R".action = actions.screenshot-screen;
172 "${mod}+Shift+R".action = actions.screenshot-window;
173 "Print".action = actions.screenshot;
174 "Ctrl+Print".action = actions.screenshot-screen;
175 "Shift+Print".action = actions.screenshot-window;
176
177 "${mod}+Space".action = actions."switch-layout" "next";
178 "${mod}+Shift+Space".action = actions."switch-layout" "prev";
179
180 "${mod}+D" = lib.mkIf config.chimera.runner.enable { action = actions.spawn "${menu}"; };
181 "Alt+Space" = lib.mkIf (
182 config.chimera.runner.enable
183 && config.chimera.input.keybinds.alternativeSearch.enable
184 ) { action = actions.spawn "${menu}"; };
185 "${mod}+Shift+Slash".action = actions.show-hotkey-overlay;
186 } // ( # Workspace Keybinds
187 lib.pipe (lib.range 1 10) [
188 (map generateWorkspaceBindings)
189 joinAttrsetList
190 ]
191 ) // ( # Window Manipulation Bindings
192 {
193 "${mod}+BracketLeft".action = actions."consume-or-expel-window-left";
194 "${mod}+BracketRight".action = actions."consume-or-expel-window-right";
195 "${mod}+Shift+BracketLeft".action = actions."consume-window-into-column";
196 "${mod}+Shift+BracketRight".action = actions."expel-window-from-column";
197 "${mod}+Slash".action = actions."switch-preset-column-width";
198 "${mod}+${mod1}+F".action = actions."fullscreen-window";
199
200 # Focus
201 "${mod}+Up".action = actions."focus-window-or-workspace-up";
202 "${mod}+Down".action = actions."focus-window-or-workspace-down";
203
204 # Non Jump Movement
205 "${mod}+Shift+Up".action = actions."move-window-up-or-to-workspace-up";
206 "${mod}+Shift+Down".action = actions."move-window-down-or-to-workspace-down";
207 "${mod}+Shift+Left".action = actions."consume-or-expel-window-left";
208 "${mod}+Shift+Right".action = actions."consume-or-expel-window-right";
209
210 # To Monitor
211 "${mod}+Shift+Ctrl+Up".action = actions."move-window-to-monitor-up";
212 "${mod}+Shift+Ctrl+Down".action = actions."move-window-to-monitor-down";
213 "${mod}+Shift+Ctrl+Left".action = actions."move-window-to-monitor-left";
214 "${mod}+Shift+Ctrl+Right".action = actions."move-window-to-monitor-right";
215
216 # To Workspace
217 "${mod}+Ctrl+Up".action = actions."move-window-to-workspace-up";
218 "${mod}+Ctrl+Down".action = actions."move-window-to-workspace-down";
219
220 # Sizing
221 "${mod}+Equal".action = actions."set-window-height" "+5%";
222 "${mod}+Minus".action = actions."set-window-height" "-5%";
223 }) // ( # Column Manipulation Bindings
224 {
225 # Focus
226 "${mod}+Left".action = actions."focus-column-left";
227 "${mod}+Right".action = actions."focus-column-right";
228 "${mod}+${mod1}+C".action = actions."center-column";
229 "${mod}+F".action = actions."maximize-column";
230
231 # Non Monitor Movement
232 "${mod}+${mod1}+Shift+Up".action = actions."move-column-to-workspace-up";
233 "${mod}+${mod1}+Shift+Down".action = actions."move-column-to-workspace-down";
234 "${mod}+${mod1}+Shift+Left".action = actions."move-column-left";
235 "${mod}+${mod1}+Shift+Right".action = actions."move-column-right";
236
237 # To Monitor
238 "${mod}+${mod1}+Shift+Ctrl+Up".action = actions."move-column-to-monitor-up";
239 "${mod}+${mod1}+Shift+Ctrl+Down".action = actions."move-column-to-monitor-down";
240 "${mod}+${mod1}+Shift+Ctrl+Left".action = actions."move-column-to-monitor-left";
241 "${mod}+${mod1}+Shift+Ctrl+Right".action = actions."move-column-to-monitor-right";
242
243 # Sizing
244 "${mod}+${mod1}+Equal".action = actions."set-column-width" "+5%";
245 "${mod}+${mod1}+Minus".action = actions."set-column-width" "-5%";
246 }) // ( # Workspace Manipulation Bindings
247 {
248 # Focus
249 "${mod}+Page_Up".action = actions."focus-workspace-up";
250 "${mod}+Page_Down".action = actions."focus-workspace-down";
251
252 # Within Itself
253 "${mod}+Shift+Page_Up".action = actions."move-workspace-up";
254 "${mod}+Shift+Page_Down".action = actions."move-workspace-down";
255
256 # To Monitor
257 "${mod}+Shift+Ctrl+Page_Up".action = actions."move-workspace-to-monitor-up";
258 "${mod}+Shift+Ctrl+Page_Down".action = actions."move-workspace-to-monitor-down";
259 "${mod}+Shift+Ctrl+Home".action = actions."move-workspace-to-monitor-left";
260 "${mod}+Shift+Ctrl+End".action = actions."move-workspace-to-monitor-right";
261 }) // { # Audio
262 "XF86AudioRaiseVolume" = {
263 allow-when-locked = true;
264 action = actions.spawn "${pkgs.wireplumber}/bin/wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05+";
265 };
266 "XF86AudioLowerVolume" = {
267 allow-when-locked = true;
268 action = actions.spawn "${pkgs.wireplumber}/bin/wpctl" "set-volume" "@DEFAULT_AUDIO_SINK@" "0.05-";
269 };
270 "XF86AudioMute" = {
271 allow-when-locked = true;
272 action = actions.spawn "${pkgs.wireplumber}/bin/wpctl" "set-mute" "@DEFAULT_AUDIO_SINK@" "toggle";
273 };
274 "XF86AudioMicMute" = {
275 allow-when-locked = true;
276 action = actions.spawn "${pkgs.wireplumber}/bin/wpctl" "set-mute" "@DEFAULT_AUDIO_SOURCE@" "toggle";
277 };
278 };
279
280 outputs = config.chimera.niri.monitors;
281
282 cursor = {
283 size = config.chimera.theme.cursor.size;
284 theme = config.chimera.theme.cursor.name;
285 };
286
287 layout = {
288 gaps = 16;
289
290 center-focused-column = "on-overflow";
291
292 preset-column-widths = [
293 { proportion = 1. / 4.; }
294 { proportion = 1. / 3.; }
295 { proportion = 1. / 2.; }
296 { proportion = 2. / 3.; }
Samuel Shuert4d5c5fb2024-06-09 09:39:11 -0400297 { proportion = 9. / 10.; }
Skyler Grey69a999e2024-05-23 00:09:10 +0000298 ]; # TODO: clicks to PR a docs update for niri-flake
299 };
300
301 prefer-no-csd = true; # No "client-side-decorations" (i.e. client-side window open/close buttons)
302 hotkey-overlay.skip-at-startup = true;
303 screenshot-path = null;
304
305 spawn-at-startup = [
306 {
307 command = [ "${pkgs.waybar}/bin/waybar" ];
308 }
309 {
310 command = [ "${pkgs.swaybg}/bin/swaybg" "-i" "${config.chimera.theme.wallpaper}" "-m" "fill" ];
311 }
Skyler Grey035c8d12024-05-26 21:23:33 +0000312 {
313 command = [ "${pkgs.xwayland-satellite}/bin/xwayland-satellite" ];
314 }
Samuel Shuert35d5f652024-07-01 13:09:28 -0400315 ] ++ config.chimera.niri.startupCommands;
Skyler Grey69a999e2024-05-23 00:09:10 +0000316 };
317 };
318 };
319}