summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/niri
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/niri')
-rw-r--r--accounts/gkleen@sif/niri/default.nix1119
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix4
2 files changed, 654 insertions, 469 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index ee545ba2..abcb80fc 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -1,6 +1,10 @@
1{ config, hostConfig, pkgs, lib, ... }: 1{ config, hostConfig, pkgs, lib, flakeInputs, ... }:
2let 2let
3 niri = config.programs.niri.package; 3 cfg = config.programs.niri;
4
5 kdl = flakeInputs.niri-flake.lib.kdl;
6
7 niri = cfg.package;
4 terminal = lib.getExe config.programs.kitty.package; 8 terminal = lib.getExe config.programs.kitty.package;
5 makoctl = lib.getExe' config.services.mako.package "makoctl"; 9 makoctl = lib.getExe' config.services.mako.package "makoctl";
6 loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; 10 loginctl = lib.getExe' hostConfig.systemd.package "loginctl";
@@ -28,7 +32,11 @@ let
28 32
29 while IFS=$'\n' read -r window_json; do 33 while IFS=$'\n' read -r window_json; do
30 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then 34 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then
31 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
36 niri msg action focus-workspace-previous
37 else
38 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
39 fi
32 exit 0 40 exit 0
33 fi 41 fi
34 done < <(niri msg -j windows | jq -c '.[]') 42 done < <(niri msg -j windows | jq -c '.[]')
@@ -74,7 +82,7 @@ let
74 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 82 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
75 ''; 83 '';
76 }; 84 };
77 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^pwctl|eff|kpxc|bmgr|edit|term$"; 85 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
78 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 86 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
79 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 87 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
80 88
@@ -89,7 +97,8 @@ let
89 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" 97 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
90 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" 98 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
91 99
92 workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")" 100 history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)"
101 workspace_json="$(jq -c --arg active_output "$active_output" --argjson history "$history_json" 'map(select(.output == $active_output and .name == null)) | map({"value": ., "history_idx": ((. as $workspace | ($history[$active_output] | index($workspace | .id))) as $active_idx | if $active_idx then $active_idx else ($history[$active_output] | length) + 1 end)}) | sort_by(.history_idx, .value.idx) | map(.value) | .[0]' <<<"$workspaces_json")"
93 [[ -n $workspace_json && $workspace_json != null ]] || exit 0 102 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
94 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" 103 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
95 ''; 104 '';
@@ -124,6 +133,54 @@ in {
124 ./swayosd.nix 133 ./swayosd.nix
125 ]; 134 ];
126 135
136 options = {
137 programs.niri.scratchspaces = lib.mkOption {
138 type = lib.types.listOf (lib.types.submodule ({ config, ... }: {
139 options = {
140 name = lib.mkOption {
141 type = lib.types.str;
142 };
143 match = lib.mkOption {
144 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
145 default = [];
146 };
147 exclude = lib.mkOption {
148 type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args);
149 default = [];
150 };
151 windowRuleExtra = lib.mkOption {
152 type = kdl.types.kdl-nodes;
153 default = [];
154 };
155 key = lib.mkOption {
156 type = lib.types.nullOr lib.types.str;
157 default = null;
158 };
159 spawn = lib.mkOption {
160 type = lib.types.nullOr (lib.types.listOf lib.types.str);
161 default = null;
162 };
163 app-id = lib.mkOption {
164 type = lib.types.nullOr lib.types.str;
165 default = null;
166 };
167 selector = lib.mkOption {
168 type = lib.types.nullOr lib.types.str;
169 default = null;
170 };
171 };
172
173 config = lib.mkMerge [
174 (lib.mkIf (config.app-id != null) {
175 match = lib.mkDefault [ { app-id = "^${lib.escapeRegex config.app-id}$"; } ];
176 selector = lib.mkDefault "select(.app_id == \"${config.app-id}\")";
177 })
178 ];
179 }));
180 default = [];
181 };
182 };
183
127 config = { 184 config = {
128 systemd.user.services.xwayland-satellite = { 185 systemd.user.services.xwayland-satellite = {
129 Unit = { 186 Unit = {
@@ -156,474 +213,602 @@ in {
156 ]; 213 ];
157 }; 214 };
158 215
159 programs.niri.settings = { 216 systemd.user.sockets.niri-workspace-history = {
160 prefer-no-csd = true; 217 Socket = {
161 screenshot-path = "${config.home.homeDirectory}/screenshots"; 218 ListenStream = "%t/niri-workspace-history.sock";
162 219 SocketMode = "0600";
163 hotkey-overlay.skip-at-startup = true;
164
165 input = {
166 keyboard = {
167 repeat-delay = 300;
168 repeat-rate = 50;
169
170 xkb = {
171 layout = "us,us";
172 variant = "dvp,";
173 options = "compose:caps,grp:win_space_toggle";
174 };
175 };
176
177 workspace-auto-back-and-forth = true;
178 # focus-follows-mouse.enable = true;
179 warp-mouse-to-focus = true;
180 }; 220 };
181 221 };
182 outputs = { 222 systemd.user.services.niri-workspace-history = {
183 "eDP-1" = { 223 Unit = {
184 scale = 1.5; 224 BindsTo = [ "niri.service" ];
185 position = { x = 0; y = 0; }; 225 After = [ "niri.service" ];
186 };
187 "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" = {
188 scale = 1.5;
189 position = { x = 2560; y = 0; };
190 };
191 "HP Inc. HP 727pu CN4417143K" = {
192 mode = { width = 2560; height = 1440; refresh = 119.998; };
193 scale = 1;
194 position = { x = 2560; y = 0; };
195 variable-refresh-rate = "on-demand";
196 };
197 }; 226 };
198 227 Install = {
199 environment = { 228 WantedBy = [ "niri.service" ];
200 NIXOS_OZONE_WL = "1";
201 QT_QPA_PLATFORM = "wayland";
202 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
203 GDK_BACKEND = "wayland";
204 SDL_VIDEODRIVER = "wayland";
205 DISPLAY = ":0";
206 }; 229 };
207 230 Service = {
208 debug.render-drm-device = "/dev/dri/by-path/pci-0000:00:02.0-render"; 231 Type = "simple";
209 232 Sockets = [ "niri-workspace-history.socket" ];
210 animations = { 233 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} ''
211 slowdown = 0.5; 234 import os
235 import socket
236 import json
237 import sys
238 from collections import defaultdict
239 from threading import Thread, Lock
240 from socketserver import StreamRequestHandler, ThreadingTCPServer
241 from contextlib import contextmanager
242 from io import TextIOWrapper
243
244
245 @contextmanager
246 def detaching(thing):
247 try:
248 yield thing
249 finally:
250 thing.detach()
251
252
253 workspace_history = defaultdict(list)
254 history_lock = Lock()
255
256
257 def monitor_niri():
258 workspaces = list()
259
260 def focus_workspace(output, workspace):
261 global workspace_history, history_lock
262
263 with history_lock:
264 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501
265 print(json.dumps(workspace_history), file=sys.stderr)
266
267 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
268 sock.connect(os.environ["NIRI_SOCKET"])
269 sock.send(b"\"EventStream\"\n")
270 for line in sock.makefile(buffering=1, encoding='utf-8'):
271 if line_json := json.loads(line):
272 if "WorkspacesChanged" in line_json:
273 workspaces = line_json["WorkspacesChanged"]["workspaces"]
274 for ws in workspaces:
275 if ws["is_focused"]:
276 focus_workspace(ws["output"], ws["id"])
277 if "WorkspaceActivated" in line_json:
278 for ws in workspaces:
279 if ws["id"] != line_json["WorkspaceActivated"]["id"]:
280 continue
281 focus_workspace(ws["output"], ws["id"])
282 break
283
284
285 class RequestHandler(StreamRequestHandler):
286 def handle(self):
287 global workspace_history, history_lock
288
289 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501
290 with history_lock:
291 json.dump(workspace_history, out)
292
293
294 class Server(ThreadingTCPServer):
295 def __init__(self):
296 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501
297 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
298
299
300 def run_server():
301 with Server() as server:
302 server.serve_forever()
303
304
305 niri = Thread(target=monitor_niri)
306 niri.daemon = True
307 niri.start()
308
309 server_thread = Thread(target=run_server)
310 server_thread.daemon = True
311 server_thread.start()
312
313 while True:
314 server_thread.join(timeout=0.5)
315 niri.join(timeout=0.5)
316
317 if not (niri.is_alive() and server_thread.is_alive()):
318 break
319 '';
212 }; 320 };
321 };
213 322
214 layout = { 323 programs.niri.scratchspaces = [
215 gaps = 8; 324 { name = "pwctl";
216 struts = { left = 0; right = 0; top = 0; bottom = 0; }; 325 key = "Mod+Control+A";
217 focus-ring = { 326 spawn = ["pwvucontrol"];
218 width = 2; 327 app-id = "com.saivert.pwvucontrol";
219 active.gradient = { 328 }
220 from = "hsla(195 100% 60% 0.75)"; 329 { name = "kpxc";
221 to = "hsla(155 100% 50% 0.75)"; 330 exclude = [
222 angle = 29; 331 { title = "^Unlock Database.*"; }
223 relative-to = "workspace-view"; 332 { title = "^Access Request.*"; }
224 }; 333 { title = ".*Passkey credentials$"; }
225 inactive.gradient = {
226 from = "hsla(0 0% 42% 0.66)";
227 to = "hsla(0 0% 35% 0.66)";
228 angle = 29;
229 relative-to = "workspace-view";
230 };
231 };
232
233 preset-column-widths = [
234 { proportion = 1. / 4.; }
235 { proportion = 1. / 3.; }
236 { proportion = 1. / 2.; }
237 { proportion = 2. / 3.; }
238 { proportion = 3. / 4.; }
239 ]; 334 ];
240 default-column-width.proportion = 1. / 2.; 335 windowRuleExtra = [
241 preset-window-heights = [ 336 (kdl.leaf "open-focused" false)
242 { proportion = 1. / 3.; } 337 ];
243 { proportion = 1. / 2.; } 338 key = "Mod+Control+P";
244 { proportion = 2. / 3.; } 339 app-id = "org.keepassxc.KeePassXC";
245 { proportion = 1.; } 340 spawn = [ "keepassxc" ];
341 }
342 { name = "bmgr";
343 key = "Mod+Control+B";
344 app-id = ".blueman-manager-wrapped";
345 spawn = [ "blueman-manager" ];
346 }
347 { name = "term";
348 key = "Mod+Control+Return";
349 app-id = "kitty-scratch";
350 spawn = [ "kitty" "--app-id" "kitty-scratch" ];
351 }
352 { name = "edit";
353 match = [ { title = "^scratch$"; app-id = "^emacs$"; } ];
354 key = "Mod+Control+E";
355 selector = "select(.app_id == \"emacs\" and .title == \"scratch\")";
356 spawn = [ "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))" ];
357 }
358 { name = "eff";
359 key = "Mod+Control+O";
360 app-id = "com.github.wwmm.easyeffects";
361 spawn = [ "easyeffects" ];
362 }
363 ];
364 programs.niri.config =
365 let
366 inherit (kdl) node plain leaf flag;
367 optional-node = cond: v:
368 if cond
369 then v
370 else null;
371 opt-props = lib.filterAttrs (lib.const (value: value != null));
372 in
373 [ (flag "prefer-no-csd")
374
375 (plain "hotkey-overlay" [
376 (flag "skip-at-startup")
377 ])
378
379 (plain "input" [
380 (plain "keyboard" [
381 (leaf "repeat-delay" 300)
382 (leaf "repeat-rate" 50)
383
384 (plain "xkb" [
385 (leaf "layout" "us,us")
386 (leaf "variant" "dvp,")
387 (leaf "options" "compose:caps,grp:win_space_toggle")
388 ])
389 ])
390
391 (flag "workspace-auto-back-and-forth")
392 # (leaf "focus-follows-mouse" {})
393 # (flag "warp-mouse-to-focus")
394
395 (plain "touchpad" [ (flag "off") ])
396 (plain "trackball" [
397 (leaf "scroll-method" "on-button-down")
398 (leaf "scroll-button" 278)
399 ])
400 ])
401
402 (plain "environment" (lib.mapAttrsToList leaf {
403 NIXOS_OZONE_WL = "1";
404 QT_QPA_PLATFORM = "wayland";
405 QT_WAYLAND_DISABLE_WINDOWDECORATION = "1";
406 GDK_BACKEND = "wayland";
407 SDL_VIDEODRIVER = "wayland";
408 DISPLAY = ":0";
409 }))
410
411 (node "output" "eDP-1" [
412 (leaf "scale" 1.5)
413 (leaf "position" { x = 0; y = 0; })
414 ])
415 (node "output" "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" [
416 (leaf "scale" 1.5)
417 (leaf "position" { x = 2560; y = 0; })
418 ])
419 (node "output" "HP Inc. HP 727pu CN4417143K" [
420 (leaf "mode" "2560x1440@120") # 119.998
421 (leaf "scale" 1)
422 (leaf "position" { x = 2560; y = 0; })
423 (flag "variable-refresh-rate")
424 ])
425
426 (plain "debug" [
427 (leaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render")
428 ])
429
430 (plain "animations" [
431 (leaf "slowdown" 0.5)
432 (plain "workspace-switch" [(flag "off")])
433 ])
434
435 (plain "layout" [
436 (leaf "gaps" 8)
437 (plain "struts" [
438 (leaf "left" 0)
439 (leaf "right" 0)
440 (leaf "top" 0)
441 (leaf "bottom" 0)
442 ])
443 (plain "focus-ring" [
444 (leaf "width" 2)
445 (leaf "active-gradient" {
446 from = "hsla(195 100% 45% 1)";
447 to = "hsla(155 100% 37.5% 1)";
448 angle = 29;
449 relative-to = "workspace-view";
450 })
451 (leaf "inactive-gradient" {
452 from = "hsla(0 0% 27.7% 1)";
453 to = "hsla(0 0% 23% 1)";
454 angle = 29;
455 relative-to = "workspace-view";
456 })
457 ])
458
459 (plain "preset-column-widths" (map (prop: leaf "proportion" prop) [
460 (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.)
461 ]))
462 (plain "default-column-width" [ (leaf "proportion" (1. / 2.)) ])
463 (plain "preset-window-heights" (map (prop: leaf "proportion" prop) [
464 (1. / 3.) (1. / 2.) (2. / 3.) (1.)
465 ]))
466
467 (flag "always-center-single-column")
468
469 (plain "tab-indicator" [
470 (leaf "gap" (-6))
471 (leaf "width" 6)
472 (leaf "length" { total-proportion = 1.; })
473 (leaf "active-gradient" {
474 from = "hsla(195 100% 60% 0.75)";
475 to = "hsla(155 100% 50% 0.75)";
476 angle = 29;
477 relative-to = "workspace-view";
478 })
479 (leaf "inactive-gradient" {
480 from = "hsla(0 0% 42% 0.66)";
481 to = "hsla(0 0% 35% 0.66)";
482 angle = 29;
483 relative-to = "workspace-view";
484 })
485 ])
486 ])
487
488 (plain "cursor" [
489 (flag "hide-when-typing")
490 ])
491
492 (map (name:
493 (node "workspace" name [
494 (leaf "open-on-output" "eDP-1")
495 ])
496 ) (map ({name, ...}: name) cfg.scratchspaces))
497 (map (name:
498 (leaf "workspace" name)
499 ) ["comm" "web" "vid" "bmr"])
500
501 (plain "window-rule" [
502 (leaf "match" { is-floating = true; })
503 (leaf "geometry-corner-radius" 8)
504 (leaf "clip-to-geometry" true)
505 ])
506
507 (plain "window-rule" [
508 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; })
509 (leaf "block-out-from" "screencast")
510 ])
511 (plain "window-rule" [
512 (map (title:
513 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
514 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"])
515 (leaf "open-focused" true)
516 (leaf "open-floating" true)
517 ])
518
519 (map ({ name, match, exclude, windowRuleExtra, ... }:
520 (optional-node (match != []) (plain "window-rule" [
521 (map (leaf "match") match)
522 (map (leaf "exclude") exclude)
523 (leaf "open-on-workspace" name)
524 (leaf "open-maximized" true)
525 windowRuleExtra
526 ]))
527 ) cfg.scratchspaces)
528
529 (plain "window-rule" [
530 (leaf "match" { app-id = "^emacs$"; })
531 (leaf "match" { app-id = "^firefox$"; })
532 (plain "default-column-width" [(leaf "proportion" (2. / 3.))])
533 ])
534 (plain "window-rule" [
535 (leaf "match" { app-id = "^kitty$"; })
536 (leaf "match" { app-id = "^kitty-play$"; })
537 (plain "default-column-width" [(leaf "proportion" (1. / 3.))])
538 ])
539
540 (plain "window-rule" [
541 (leaf "match" { app-id = "^thunderbird$"; })
542 (leaf "match" { app-id = "^Element$"; })
543 (leaf "match" { app-id = "^Rainbow$"; })
544 (leaf "open-on-workspace" "comm")
545 ])
546 (plain "window-rule" [
547 (leaf "match" { app-id = "^firefox$"; })
548 (leaf "open-on-workspace" "web")
549 (leaf "open-maximized" true)
550 ])
551 (plain "window-rule" [
552 (leaf "match" { app-id = "^mpv$"; })
553 (leaf "open-on-workspace" "vid")
554 (plain "default-column-width" [(leaf "proportion" 1.)])
555 ])
556 (plain "window-rule" [
557 (leaf "match" { app-id = "^kitty-play$"; })
558 (leaf "open-on-workspace" "vid")
559 (leaf "open-focused" false)
560 ])
561 (plain "window-rule" [
562 (leaf "match" { app-id = "^pdfpc$"; })
563 (plain "default-column-width" [(leaf "proportion" 1.)])
564 ])
565 (plain "window-rule" [
566 (leaf "match" { app-id = "^pdfpc$"; title = "^pdfpc - presentation$"; })
567 (plain "default-column-width" [(leaf "proportion" 1.)])
568 (leaf "open-fullscreen" true)
569 (leaf "open-on-workspace" "bmr")
570 (leaf "open-focused" false)
571 ])
572 (plain "window-rule" [
573 (map (leaf "match") [
574 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
575 { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; }
576 { app-id = "^xdg-desktop-portal-gtk$"; }
577 ])
578 (leaf "open-floating" true)
579 ])
580
581 (plain "layer-rule" [
582 (leaf "match" { namespace = "^notifications$"; })
583 (leaf "match" { namespace = "^waybar$"; })
584 (leaf "match" { namespace = "^launcher$"; })
585 (leaf "block-out-from" "screencast")
586 ])
587
588 (plain "binds"
589 (let
590 bind = name: cfg: node name (opt-props {
591 cooldown-ms = cfg.cooldown-ms or null;
592 }
593 // (lib.optionalAttrs (!(cfg.repeat or true)) {
594 repeat = false;
595 })
596 // (lib.optionalAttrs (cfg.allow-when-locked or false) {
597 allow-when-locked = true;
598 })) (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"]));
599 in
600 [
601 (lib.mapAttrsToList bind (with config.lib.niri.actions; {
602 "Mod+Slash".action = show-hotkey-overlay;
603
604 "Mod+Return".action = spawn terminal;
605 "Mod+Q".action = close-window;
606 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
607 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
608
609 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
610 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
611 name = "queue-yt-dlp";
612 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
613 text = ''
614 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
615 '';
616 }));
617 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
618 name = "queue-yt-dlp";
619 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
620 text = ''
621 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
622 '';
623 }));
624
625 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
626 name = "qalc-fuzzel";
627 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
628 text = ''
629 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
630 prev() {
631 FOUND=false
632 while IFS= read -r line; do
633 [[ -n "$line" ]] || continue
634 FOUND=true
635 echo "$line"
636 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
637 $FOUND || echo
638 }
639 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $?
640 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
641 QALC_RES="$FUZZEL_RES"
642 QALC_RET=0
643 else
644 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1)
645 QALC_RET=$?
646 fi
647 [[ -n "$QALC_RES" ]] || exit 1
648 EXISTING=false
649 set +o pipefail
650 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
651 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
652 set -o pipefail
653 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
654 set +o pipefail
655 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
656 set -o pipefail
657 cat >"$RES_FILE" <<<"$QALC_RES"
658 fi
659 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
660 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
661 notify-send "$QALC_RES"
662 '';
663 }));
664 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
665 name = "emoji-fuzzel";
666 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
667 text = ''
668 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
669 [[ -n "$FUZZEL_RES" ]] || exit 1
670 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
671 '';
672 }));
673 "Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
674 name = "screenshot";
675 runtimeInputs = with pkgs; [ grim slurp wl-clipboard-rs coreutils ];
676 text = ''
677 grim -g "$(slurp -b 00000080 -c FFFFFFFF -s 00000000 -w 1)" - \
678 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
679 | wl-copy --type image/png
680 '';
681 }));
682 "Shift+Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
683 name = "screenshot";
684 runtimeInputs = with pkgs; [ grim niri gojq wl-clipboard-rs coreutils ];
685 text = ''
686 grim -o "$(niri msg -j workspaces | jq -r '.[] | select(.is_focused) | .output')" - \
687 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
688 | wl-copy --type image/png
689 '';
690 }));
691 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
692 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
693
694 "Mod+H".action = focus-column-left;
695 "Mod+T".action = focus-window-down;
696 "Mod+N".action = focus-window-up;
697 "Mod+S".action = focus-column-right;
698
699 "Mod+Shift+H".action = move-column-left;
700 "Mod+Shift+T".action = move-window-down;
701 "Mod+Shift+N".action = move-window-up;
702 "Mod+Shift+S".action = move-column-right;
703
704 "Mod+Control+H".action = focus-monitor-left;
705 "Mod+Control+T".action = focus-monitor-down;
706 "Mod+Control+N".action = focus-monitor-up;
707 "Mod+Control+S".action = focus-monitor-right;
708
709 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
710 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
711 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
712 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
713
714 "Mod+G".action = focus-adjacent-workspace "down";
715 "Mod+C".action = focus-adjacent-workspace "up";
716
717 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
718 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
719
720 "Mod+Shift+Control+G".action = move-workspace-down;
721 "Mod+Shift+Control+C".action = move-workspace-up;
722
723 "Mod+ParenLeft".action = focus-workspace "comm";
724 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm";
725
726 "Mod+ParenRight".action = focus-workspace "web";
727 "Mod+Shift+ParenRight".action = move-column-to-workspace "web";
728
729 "Mod+BraceRight".action = focus-workspace "read";
730 "Mod+Shift+BraceRight".action = move-column-to-workspace "read";
731
732 "Mod+BraceLeft".action = focus-workspace "mon";
733 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon";
734
735 "Mod+Asterisk".action = focus-workspace "vid";
736 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid";
737
738 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
739 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
740
741 "Mod+M".action = consume-or-expel-window-left;
742 "Mod+W".action = consume-or-expel-window-right;
743
744 "Mod+Shift+M".action = toggle-column-tabbed-display;
745
746 "Mod+R".action = switch-preset-column-width;
747 "Mod+Shift+R".action = switch-preset-window-height;
748 "Mod+F".action = center-column;
749 "Mod+Shift+F".action = maximize-column;
750 "Mod+Shift+Ctrl+F".action = fullscreen-window;
751
752 "Mod+V".action = switch-focus-between-floating-and-tiling;
753 "Mod+Shift+V".action = toggle-window-floating;
754
755 "Mod+Left".action = set-column-width "-10%";
756 "Mod+Down".action = set-window-height "-10%";
757 "Mod+Up".action = set-window-height "+10%";
758 "Mod+Right".action = set-column-width "+10%";
759
760 "Mod+Shift+Z" = {
761 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
762 allow-when-locked = true;
763 };
764 "Mod+Shift+L".action = spawn loginctl "lock-session";
765 "Mod+Shift+E".action = quit;
766 "Mod+Shift+Minus" = {
767 action = spawn systemctl "suspend";
768 allow-when-locked = true;
769 };
770 "Mod+Shift+Control+Minus" = {
771 action = spawn systemctl "hibernate";
772 allow-when-locked = true;
773 };
774 "Mod+Shift+P" = {
775 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
776 allow-when-locked = true;
777 };
778
779 "XF86MonBrightnessUp" = {
780 action = spawn swayosd-client "--brightness" "raise";
781 allow-when-locked = true;
782 };
783 "XF86MonBrightnessDown" = {
784 action = spawn swayosd-client "--brightness" "lower";
785 allow-when-locked = true;
786 };
787 "XF86AudioRaiseVolume" = {
788 action = spawn swayosd-client "--output-volume" "raise";
789 allow-when-locked = true;
790 };
791 "XF86AudioLowerVolume" = {
792 action = spawn swayosd-client "--output-volume" "lower";
793 allow-when-locked = true;
794 };
795 "XF86AudioMute" = {
796 action = spawn swayosd-client "--output-volume" "mute-toggle";
797 allow-when-locked = true;
798 };
799 "XF86AudioMicMute" = {
800 action = spawn swayosd-client "--input-volume" "mute-toggle";
801 allow-when-locked = true;
802 };
803
804 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
805 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
806 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu";
807 "Mod+Comma".action = spawn makoctl "restore";
808 }))
809 (map ({ name, selector, spawn, key, ...}: if key != null && selector != null && spawn != null then bind key { action = focus-or-spawn-action selector name spawn; } else null) cfg.scratchspaces)
810 ]
811 ))
246 ]; 812 ];
247
248 always-center-single-column = true;
249 };
250
251 cursor.hide-when-typing = true;
252
253 input = {
254 touchpad.enable = false;
255 trackball = {
256 scroll-method = "on-button-down";
257 scroll-button = 278;
258 };
259 };
260
261 workspaces = {
262 "001" = { name = "pwctl"; open-on-output = "eDP-1"; };
263 "002" = { name = "kpxc"; open-on-output = "eDP-1"; };
264 "003" = { name = "bmgr"; open-on-output = "eDP-1"; };
265 "004" = { name = "term"; open-on-output = "eDP-1"; };
266 "005" = { name = "edit"; open-on-output = "eDP-1"; };
267 "006" = { name = "eff"; open-on-output = "eDP-1"; };
268 "101".name = "comm";
269 "102".name = "web";
270 # "104".name = "read";
271 # "105".name = "mon";
272 "110".name = "vid";
273 "120".name = "bmr";
274 };
275
276 window-rules = [
277 {
278 matches = [ { is-floating = true; } ];
279 geometry-corner-radius =
280 let
281 allCorners = r: { bottom-left = r; bottom-right = r; top-left = r; top-right = r; };
282 in allCorners 8.;
283 clip-to-geometry = true;
284 }
285 {
286 matches = [ { app-id = "^com\.saivert\.pwvucontrol$"; } ];
287 open-on-workspace = "pwctl";
288 open-maximized = true;
289 }
290 {
291 matches = [ { app-id = "^com\.github\.wwmm\.easyeffects$"; } ];
292 open-on-workspace = "eff";
293 open-maximized = true;
294 }
295 {
296 matches = [ { app-id = "^\.blueman-manager-wrapped$"; } ];
297 open-on-workspace = "bmgr";
298 open-maximized = true;
299 }
300 {
301 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ];
302 block-out-from = "screencast";
303 }
304 {
305 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ];
306 excludes = [
307 { title = "^Unlock Database.*"; }
308 { title = "^Access Request.*"; }
309 { title = ".*Passkey credentials$"; }
310 ];
311 open-on-workspace = "kpxc";
312 open-maximized = true;
313 open-focused = false;
314 }
315 {
316 matches = [
317 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Unlock Database.*"; }
318 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Access Request.*"; }
319 { app-id = "^org\.keepassxc\.KeePassXC$"; title = ".*Passkey credentials$"; }
320 ];
321 open-focused = true;
322 open-floating = true;
323 }
324 {
325 matches = [ { app-id = "^kitty-scratch$"; } ];
326 open-on-workspace = "term";
327 open-maximized = true;
328 }
329 {
330 matches = [ { title = "^scratch$"; app-id = "^emacs$"; } ];
331 open-on-workspace = "edit";
332 open-maximized = true;
333 }
334 {
335 matches = [
336 { app-id = "^emacs$"; }
337 { app-id = "^firefox$"; }
338 ];
339 default-column-width.proportion = 2. / 3.;
340 }
341 {
342 matches = [
343 { app-id = "^kitty$"; }
344 { app-id = "^kitty-play$"; }
345 ];
346 default-column-width.proportion = 1. / 3.;
347 }
348 {
349 matches = [
350 { app-id = "^thunderbird$"; }
351 { app-id = "^Element$"; }
352 { app-id = "^Rainbow$"; }
353 ];
354 open-on-workspace = "comm";
355 }
356 {
357 matches = [ { app-id = "^firefox$"; } ];
358 open-on-workspace = "web";
359 open-maximized = true;
360 variable-refresh-rate = true;
361 }
362 # {
363 # matches = [
364 # { app-id = "^evince$"; }
365 # { app-id = "^imv$"; }
366 # { app-id = "^org\.pwmt\.zathura$"; }
367 # ];
368 # open-on-workspace = "read";
369 # }
370 {
371 matches = [ { app-id = "^mpv$"; } ];
372 open-on-workspace = "vid";
373 default-column-width.proportion = 1.;
374 variable-refresh-rate = true;
375 }
376 {
377 matches = [ { app-id = "^kitty-play$"; } ];
378 open-on-workspace = "vid";
379 open-focused = false;
380 }
381 # {
382 # matches = [
383 # { app-id = "^qemu$"; }
384 # { app-id = "^virt-manager$"; }
385 # ];
386 # open-on-workspace = "mon";
387 # }
388 {
389 matches = [ { app-id = "^pdfpc$"; } ];
390 default-column-width.proportion = 1.;
391 }
392 {
393 matches = [ { app-id = "^pdfpc$"; title = "^pdfpc - presentation"; } ];
394 open-on-workspace = "bmr";
395 open-fullscreen = true;
396 }
397 {
398 matches = [
399 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
400 { app-id = "^org\.kde\.polkit-kde-authentication-agent-1$"; }
401 ];
402 open-floating = true;
403 }
404 ];
405 layer-rules = [
406 { matches = [
407 { namespace = "^notifications$"; }
408 { namespace = "^waybar$"; }
409 ];
410 block-out-from = "screencast";
411 }
412 ];
413
414 binds = with config.lib.niri.actions; {
415 "Mod+Slash".action = show-hotkey-overlay;
416
417 "Mod+Return".action = spawn terminal;
418 "Mod+Q".action = close-window;
419 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
420 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
421
422 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
423 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
424 name = "queue-yt-dlp";
425 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
426 text = ''
427 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
428 '';
429 }));
430 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
431 name = "queue-yt-dlp";
432 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
433 text = ''
434 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
435 '';
436 }));
437
438 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
439 name = "qalc-fuzzel";
440 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
441 text = ''
442 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
443 prev() {
444 FOUND=false
445 while IFS= read -r line; do
446 [[ -n "$line" ]] || continue
447 FOUND=true
448 echo "$line"
449 done < <(export LC_ALL=C.UTF-8; echo; find "$RESULTS_DIR" -type f -printf $'%T@ %p\n' | sort -n | cut -d' ' -f2- | xargs -r cat)
450 $FOUND || echo
451 }
452 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $?
453 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
454 QALC_RES="$FUZZEL_RES"
455 QALC_RET=0
456 else
457 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1)
458 QALC_RET=$?
459 fi
460 [[ -n "$QALC_RES" ]] || exit 1
461 EXISTING=false
462 set +o pipefail
463 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
464 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
465 set -o pipefail
466 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
467 set +o pipefail
468 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
469 set -o pipefail
470 cat >"$RES_FILE" <<<"$QALC_RES"
471 fi
472 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
473 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
474 notify-send "$QALC_RES"
475 '';
476 }));
477 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
478 name = "emoji-fuzzel";
479 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
480 text = ''
481 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
482 [[ -n "$FUZZEL_RES" ]] || exit 1
483 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
484 '';
485 }));
486 "Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
487 name = "screenshot";
488 runtimeInputs = with pkgs; [ grim slurp wl-clipboard-rs coreutils ];
489 text = ''
490 grim -g "$(slurp -b 00000080 -c FFFFFFFF -s 00000000 -w 1)" - \
491 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
492 | wl-copy --type image/png
493 '';
494 }));
495 "Shift+Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
496 name = "screenshot";
497 runtimeInputs = with pkgs; [ grim niri gojq wl-clipboard-rs coreutils ];
498 text = ''
499 grim -o "$(niri msg -j workspaces | jq -r '.[] | select(.is_focused) | .output')" - \
500 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
501 | wl-copy --type image/png
502 '';
503 }));
504 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
505 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
506
507 "Mod+H".action = focus-column-left;
508 "Mod+T".action = focus-window-down;
509 "Mod+N".action = focus-window-up;
510 "Mod+S".action = focus-column-right;
511
512 "Mod+Shift+H".action = move-column-left;
513 "Mod+Shift+T".action = move-window-down;
514 "Mod+Shift+N".action = move-window-up;
515 "Mod+Shift+S".action = move-column-right;
516
517 "Mod+Control+H".action = focus-monitor-left;
518 "Mod+Control+T".action = focus-monitor-down;
519 "Mod+Control+N".action = focus-monitor-up;
520 "Mod+Control+S".action = focus-monitor-right;
521
522 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
523 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
524 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
525 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
526
527 "Mod+G".action = focus-adjacent-workspace "down";
528 "Mod+C".action = focus-adjacent-workspace "up";
529
530 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
531 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
532
533 "Mod+Shift+Control+G".action = move-workspace-down;
534 "Mod+Shift+Control+C".action = move-workspace-up;
535
536 "Mod+ParenLeft".action = focus-workspace "comm";
537 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm";
538
539 "Mod+ParenRight".action = focus-workspace "web";
540 "Mod+Shift+ParenRight".action = move-column-to-workspace "web";
541
542 "Mod+BraceRight".action = focus-workspace "read";
543 "Mod+Shift+BraceRight".action = move-column-to-workspace "read";
544
545 "Mod+BraceLeft".action = focus-workspace "mon";
546 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon";
547
548 "Mod+Asterisk".action = focus-workspace "vid";
549 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid";
550
551 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
552 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
553
554 "Mod+M".action = consume-or-expel-window-left;
555 "Mod+W".action = consume-or-expel-window-right;
556
557 "Mod+R".action = switch-preset-column-width;
558 "Mod+Shift+R".action = switch-preset-window-height;
559 "Mod+F".action = center-column;
560 "Mod+Shift+F".action = maximize-column;
561 "Mod+Shift+Ctrl+F".action = fullscreen-window;
562
563 "Mod+V".action = switch-focus-between-floating-and-tiling;
564 "Mod+Shift+V".action = toggle-window-floating;
565
566 "Mod+Left".action = set-column-width "-10%";
567 "Mod+Down".action = set-window-height "-10%";
568 "Mod+Up".action = set-window-height "+10%";
569 "Mod+Right".action = set-column-width "+10%";
570
571 "Mod+Shift+Z" = {
572 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
573 allow-when-locked = true;
574 };
575 "Mod+Shift+L".action = spawn loginctl "lock-session";
576 "Mod+Shift+E".action = quit;
577 "Mod+Shift+Minus" = {
578 action = spawn systemctl "suspend";
579 allow-when-locked = true;
580 };
581 "Mod+Shift+Control+Minus" = {
582 action = spawn systemctl "hibernate";
583 allow-when-locked = true;
584 };
585 "Mod+Shift+P" = {
586 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
587 allow-when-locked = true;
588 };
589
590 "XF86MonBrightnessUp" = {
591 action = spawn swayosd-client "--brightness" "raise";
592 allow-when-locked = true;
593 };
594 "XF86MonBrightnessDown" = {
595 action = spawn swayosd-client "--brightness" "lower";
596 allow-when-locked = true;
597 };
598 "XF86AudioRaiseVolume" = {
599 action = spawn swayosd-client "--output-volume" "raise";
600 allow-when-locked = true;
601 };
602 "XF86AudioLowerVolume" = {
603 action = spawn swayosd-client "--output-volume" "lower";
604 allow-when-locked = true;
605 };
606 "XF86AudioMute" = {
607 action = spawn swayosd-client "--output-volume" "mute-toggle";
608 allow-when-locked = true;
609 };
610 "XF86AudioMicMute" = {
611 action = spawn swayosd-client "--input-volume" "mute-toggle";
612 allow-when-locked = true;
613 };
614
615 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
616 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
617 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu";
618 "Mod+Comma".action = spawn makoctl "restore";
619
620 "Mod+Control+A".action = focus-or-spawn-action-app_id "com.saivert.pwvucontrol" "pwctl" "pwvucontrol";
621 "Mod+Control+O".action = focus-or-spawn-action-app_id "com.github.wwmm.easyeffects" "eff" "easyeffects";
622 "Mod+Control+P".action = focus-or-spawn-action-app_id "org.keepassxc.KeePassXC" "kpxc" "keepassxc";
623 "Mod+Control+B".action = focus-or-spawn-action-app_id ".blueman-manager-wrapped" "bmgr" "blueman-manager";
624 "Mod+Control+Return".action = focus-or-spawn-action-app_id "kitty-scratch" "term" "kitty" "--app-id" "kitty-scratch";
625 "Mod+Control+E".action = focus-or-spawn-action "select(.app_id == \"emacs\" and .title == \"scratch\")" "edit" "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))";
626 };
627 };
628 }; 813 };
629} 814}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
index 3f1f8119..bae818f6 100644
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ b/accounts/gkleen@sif/niri/waybar.nix
@@ -131,7 +131,7 @@ in {
131 return-type = "json"; 131 return-type = "json";
132 }; 132 };
133 "niri/workspaces" = { 133 "niri/workspaces" = {
134 ignore = ["eff" "pwctl" "kpxc" "bmgr" "edit" "term"]; 134 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
135 }; 135 };
136 "niri/window" = { 136 "niri/window" = {
137 separate-outputs = true; 137 separate-outputs = true;
@@ -217,7 +217,7 @@ in {
217 modules-right = [ "clock" ]; 217 modules-right = [ "clock" ];
218 218
219 "niri/workspaces" = { 219 "niri/workspaces" = {
220 ignore = ["pwctl" "kpxc" "bmgr" "edit" "term"]; 220 ignore = map ({ name, ... }: name) config.programs.niri.scratchspaces;
221 }; 221 };
222 "niri/window" = { 222 "niri/window" = {
223 separate-outputs = true; 223 separate-outputs = true;