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.nix628
-rw-r--r--accounts/gkleen@sif/niri/mako.nix115
-rw-r--r--accounts/gkleen@sif/niri/swayosd.nix65
-rw-r--r--accounts/gkleen@sif/niri/waybar.nix341
4 files changed, 0 insertions, 1149 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
deleted file mode 100644
index 4a207589..00000000
--- a/accounts/gkleen@sif/niri/default.nix
+++ /dev/null
@@ -1,628 +0,0 @@
1{ config, hostConfig, pkgs, lib, ... }:
2let
3 niri = config.programs.niri.package;
4 terminal = lib.getExe config.programs.kitty.package;
5 makoctl = lib.getExe' config.services.mako.package "makoctl";
6 loginctl = lib.getExe' hostConfig.systemd.package "loginctl";
7 systemctl = lib.getExe' hostConfig.systemd.package "systemctl";
8 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
9
10 focus_or_spawn = pkgs.writeShellApplication {
11 name = "focus-or-spawn";
12 runtimeInputs = [ niri pkgs.gojq pkgs.gnugrep pkgs.socat ];
13 text = ''
14 window_select="$1"
15 shift
16 workspace_name="$1"
17 shift
18
19 workspaces_json="$(niri msg -j workspaces)"
20 workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")"
21 # active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")"
22 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
23 if [[ $workspace_output != "$active_output" ]]; then
24 niri msg action move-workspace-to-monitor --reference "$workspace_name" "$active_output"
25 # socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}'
26 # niri msg action move-workspace-to-index --reference "$workspace_name" 1
27 fi
28
29 while IFS=$'\n' read -r window_json; do
30 if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then
31 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
32 exit 0
33 fi
34 done < <(niri msg -j windows | jq -c '.[]')
35
36 exec "$@"
37 '';
38 };
39 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
40 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
41
42 with_adjacent_workspace = pkgs.writeShellApplication {
43 name = "with-adjacent-workspace";
44 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
45 text = ''
46 blacklist="$1"
47 shift
48 direction="$1"
49 shift
50 action="$1"
51 shift
52
53 workspaces_json="$(niri msg -j workspaces)"
54 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
55 workspace_output="$(jq -r --arg active_workspace "$active_workspace" '.[] | select(.id == ($active_workspace | tonumber)) | .output' <<<"$workspaces_json")"
56 workspace_idx="$(jq -r '.[] | select(.is_focused) | .idx' <<<"$workspaces_json")"
57
58 jq_script='map(select('
59 case "$direction" in
60 down)
61 # shellcheck disable=SC2016
62 jq_script=''${jq_script}'.idx > ($workspace_idx | tonumber)';;
63 up)
64 # shellcheck disable=SC2016
65 jq_script=''${jq_script}'.idx < ($workspace_idx | tonumber)';;
66 esac
67 # shellcheck disable=SC2016
68 jq_script=''${jq_script}' and .output == $workspace_output and ((.name == null) or (.name | test($blacklist) | not)))) | sort_by(.idx)'
69 [[ $direction == "up" ]] && jq_script=''${jq_script}' | reverse'
70 jq_script=''${jq_script}' | .[0]'
71
72 workspace_json=$(jq -c --arg blacklist "$blacklist" --arg workspace_output "$workspace_output" --arg workspace_idx "$workspace_idx" "$jq_script" <<<"$workspaces_json")
73 [[ -n $workspace_json && $workspace_json != null ]] || exit 0
74 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET"
75 '';
76 };
77 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^pwctl|eff|kpxc|bmgr|edit|term$";
78 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}}}}'';
80
81 with_unnamed_workspace = pkgs.writeShellApplication {
82 name = "with-unnamed-workspace";
83 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
84 text = ''
85 action="$1"
86 shift
87
88 workspaces_json="$(niri msg -j workspaces)"
89 active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")"
90 active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")"
91
92 workspace_json="$(jq -c --arg active_output "$active_output" 'map(select(.output == $active_output and .name == null)) | sort_by(.idx) | .[0]' <<<"$workspaces_json")"
93 [[ -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"
95 '';
96 };
97 with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace);
98
99 with_select_window = pkgs.writeShellApplication {
100 name = "with-select-window";
101 runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ];
102 text = ''
103 window_select="$1"
104 shift
105 action="$1"
106 shift
107
108 windows_json="$(niri msg -j windows)"
109 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
110 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --log-level=warning --dmenu --index)"
111 # shellcheck disable=SC2016
112 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
113
114 [[ -z "$window_json" ]] && exit 1
115
116 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
117 '';
118 };
119 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
120in {
121 imports = [
122 ./waybar.nix
123 ./mako.nix
124 ./swayosd.nix
125 ];
126
127 config = {
128 systemd.user.services.xwayland-satellite = {
129 Unit = {
130 BindsTo = [ "graphical-session.target" ];
131 PartOf = [ "graphical-session.target" ];
132 After = [ "graphical-session.target" ];
133 Requisite = [ "graphical-session.target" ];
134 };
135 Service = {
136 Type = "notify";
137 NotifyAccess = "all";
138 Environment = [ "DISPLAY=:0" ];
139 ExecStart = ''${lib.getExe pkgs.xwayland-satellite-unstable} ''${DISPLAY}'';
140 ExecStartPre = "${systemctl} --user import-environment DISPLAY";
141 StandardOutput = "journal";
142 };
143 Install = {
144 WantedBy = [ "graphical-session.target" ];
145 };
146 };
147
148 services.swayidle = {
149 events = [
150 { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; }
151 ];
152 timeouts = [
153 { timeout = 300;
154 command = "${lib.getExe niri} msg action power-off-monitors";
155 }
156 ];
157 };
158
159 programs.niri.settings = {
160 prefer-no-csd = true;
161 screenshot-path = "${config.home.homeDirectory}/screenshots";
162
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 };
181
182 outputs = {
183 "eDP-1" = {
184 scale = 1.5;
185 position = { x = 0; y = 0; };
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 };
198
199 environment = {
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 };
207
208 debug.render-drm-device = "/dev/dri/by-path/pci-0000:00:02.0-render";
209
210 animations = {
211 slowdown = 0.5;
212 };
213
214 layout = {
215 gaps = 8;
216 struts = { left = 0; right = 0; top = 0; bottom = 0; };
217 focus-ring = {
218 width = 2;
219 active.gradient = {
220 from = "hsla(195 100% 60% 0.75)";
221 to = "hsla(155 100% 50% 0.75)";
222 angle = 29;
223 relative-to = "workspace-view";
224 };
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 ];
240 default-column-width.proportion = 1. / 2.;
241 preset-window-heights = [
242 { proportion = 1. / 3.; }
243 { proportion = 1. / 2.; }
244 { proportion = 2. / 3.; }
245 { proportion = 1.; }
246 ];
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 # geometry-corner-radius =
279 # let
280 # allCorners = r: { bottom-left = r; bottom-right = r; top-left = r; top-right = r; };
281 # in allCorners 4.;
282 # clip-to-geometry = true;
283 # }
284 {
285 matches = [ { app-id = "^com\.saivert\.pwvucontrol$"; } ];
286 open-on-workspace = "pwctl";
287 open-maximized = true;
288 }
289 {
290 matches = [ { app-id = "^com\.github\.wwmm\.easyeffects$"; } ];
291 open-on-workspace = "eff";
292 open-maximized = true;
293 }
294 {
295 matches = [ { app-id = "^\.blueman-manager-wrapped$"; } ];
296 open-on-workspace = "bmgr";
297 open-maximized = true;
298 }
299 {
300 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ];
301 block-out-from = "screencast";
302 }
303 {
304 matches = [ { app-id = "^org\.keepassxc\.KeePassXC$"; } ];
305 excludes = [
306 { title = "^Unlock Database.*"; }
307 { title = "^Access Request.*"; }
308 { title = ".*Passkey credentials$"; }
309 ];
310 open-on-workspace = "kpxc";
311 open-maximized = true;
312 open-focused = false;
313 }
314 {
315 matches = [
316 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Unlock Database.*"; }
317 { app-id = "^org\.keepassxc\.KeePassXC$"; title = "^Access Request.*"; }
318 { app-id = "^org\.keepassxc\.KeePassXC$"; title = ".*Passkey credentials$"; }
319 ];
320 open-focused = true;
321 open-floating = true;
322 }
323 {
324 matches = [ { app-id = "^kitty-scratch$"; } ];
325 open-on-workspace = "term";
326 open-maximized = true;
327 }
328 {
329 matches = [ { title = "^scratch$"; app-id = "^emacs$"; } ];
330 open-on-workspace = "edit";
331 open-maximized = true;
332 }
333 {
334 matches = [
335 { app-id = "^emacs$"; }
336 { app-id = "^firefox$"; }
337 ];
338 default-column-width.proportion = 2. / 3.;
339 }
340 {
341 matches = [
342 { app-id = "^kitty$"; }
343 { app-id = "^kitty-play$"; }
344 ];
345 default-column-width.proportion = 1. / 3.;
346 }
347 {
348 matches = [
349 { app-id = "^thunderbird$"; }
350 { app-id = "^Element$"; }
351 { app-id = "^Rainbow$"; }
352 ];
353 open-on-workspace = "comm";
354 }
355 {
356 matches = [ { app-id = "^firefox$"; } ];
357 open-on-workspace = "web";
358 open-maximized = true;
359 variable-refresh-rate = true;
360 }
361 # {
362 # matches = [
363 # { app-id = "^evince$"; }
364 # { app-id = "^imv$"; }
365 # { app-id = "^org\.pwmt\.zathura$"; }
366 # ];
367 # open-on-workspace = "read";
368 # }
369 {
370 matches = [ { app-id = "^mpv$"; } ];
371 open-on-workspace = "vid";
372 default-column-width.proportion = 1.;
373 variable-refresh-rate = true;
374 }
375 {
376 matches = [ { app-id = "^kitty-play$"; } ];
377 open-on-workspace = "vid";
378 open-focused = false;
379 }
380 # {
381 # matches = [
382 # { app-id = "^qemu$"; }
383 # { app-id = "^virt-manager$"; }
384 # ];
385 # open-on-workspace = "mon";
386 # }
387 {
388 matches = [ { app-id = "^pdfpc$"; } ];
389 default-column-width.proportion = 1.;
390 }
391 {
392 matches = [ { app-id = "^pdfpc$"; title = "^pdfpc - presentation"; } ];
393 open-on-workspace = "bmr";
394 open-fullscreen = true;
395 }
396 {
397 matches = [
398 { app-id = "^Gimp-"; title = "^Quit GIMP$"; }
399 { app-id = "^org\.kde\.polkit-kde-authentication-agent-1$"; }
400 ];
401 open-floating = true;
402 }
403 ];
404 layer-rules = [
405 { matches = [
406 { namespace = "^notifications$"; }
407 { namespace = "^waybar$"; }
408 ];
409 block-out-from = "screencast";
410 }
411 ];
412
413 binds = with config.lib.niri.actions; {
414 "Mod+Slash".action = show-hotkey-overlay;
415
416 "Mod+Return".action = spawn terminal;
417 "Mod+Q".action = close-window;
418 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
419 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
420
421 "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c";
422 "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication {
423 name = "queue-yt-dlp";
424 runtimeInputs = with pkgs; [ wl-clipboard-rs socat ];
425 text = ''
426 socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }'
427 '';
428 }));
429 "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication {
430 name = "queue-yt-dlp";
431 runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ];
432 text = ''
433 exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)"
434 '';
435 }));
436
437 "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication {
438 name = "qalc-fuzzel";
439 runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ];
440 text = ''
441 RESULTS_DIR="$HOME/.cache/qalc-fuzzel"
442 prev() {
443 FOUND=false
444 while IFS= read -r line; do
445 [[ -n "$line" ]] || continue
446 FOUND=true
447 echo "$line"
448 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)
449 $FOUND || echo
450 }
451 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $?
452 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
453 QALC_RES="$FUZZEL_RES"
454 QALC_RET=0
455 else
456 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1)
457 QALC_RET=$?
458 fi
459 [[ -n "$QALC_RES" ]] || exit 1
460 EXISTING=false
461 set +o pipefail
462 grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch
463 [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true
464 set -o pipefail
465 if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then
466 set +o pipefail
467 RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' </dev/random | head -c 10)
468 set -o pipefail
469 cat >"$RES_FILE" <<<"$QALC_RES"
470 fi
471 [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}"
472 [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES"
473 notify-send "$QALC_RES"
474 '';
475 }));
476 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
477 name = "emoji-fuzzel";
478 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
479 text = ''
480 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
481 [[ -n "$FUZZEL_RES" ]] || exit 1
482 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
483 '';
484 }));
485 "Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
486 name = "screenshot";
487 runtimeInputs = with pkgs; [ grim slurp wl-clipboard-rs coreutils ];
488 text = ''
489 grim -g "$(slurp -b 00000080 -c FFFFFFFF -s 00000000 -w 1)" - \
490 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
491 | wl-copy --type image/png
492 '';
493 }));
494 "Shift+Print".action = spawn (lib.getExe (pkgs.writeShellApplication {
495 name = "screenshot";
496 runtimeInputs = with pkgs; [ grim niri gojq wl-clipboard-rs coreutils ];
497 text = ''
498 grim -o "$(niri msg -j workspaces | jq -r '.[] | select(.is_focused) | .output')" - \
499 | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \
500 | wl-copy --type image/png
501 '';
502 }));
503 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
504 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
505
506 "Mod+H".action = focus-column-left;
507 "Mod+T".action = focus-window-down;
508 "Mod+N".action = focus-window-up;
509 "Mod+S".action = focus-column-right;
510
511 "Mod+Shift+H".action = move-column-left;
512 "Mod+Shift+T".action = move-window-down;
513 "Mod+Shift+N".action = move-window-up;
514 "Mod+Shift+S".action = move-column-right;
515
516 "Mod+Control+H".action = focus-monitor-left;
517 "Mod+Control+T".action = focus-monitor-down;
518 "Mod+Control+N".action = focus-monitor-up;
519 "Mod+Control+S".action = focus-monitor-right;
520
521 "Mod+Shift+Control+H".action = move-workspace-to-monitor-left;
522 "Mod+Shift+Control+T".action = move-workspace-to-monitor-down;
523 "Mod+Shift+Control+N".action = move-workspace-to-monitor-up;
524 "Mod+Shift+Control+S".action = move-workspace-to-monitor-right;
525
526 "Mod+G".action = focus-adjacent-workspace "down";
527 "Mod+C".action = focus-adjacent-workspace "up";
528
529 "Mod+Shift+G".action = move-column-to-adjacent-workspace "down";
530 "Mod+Shift+C".action = move-column-to-adjacent-workspace "up";
531
532 "Mod+Shift+Control+G".action = move-workspace-down;
533 "Mod+Shift+Control+C".action = move-workspace-up;
534
535 "Mod+ParenLeft".action = focus-workspace "comm";
536 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm";
537
538 "Mod+ParenRight".action = focus-workspace "web";
539 "Mod+Shift+ParenRight".action = move-column-to-workspace "web";
540
541 "Mod+BraceRight".action = focus-workspace "read";
542 "Mod+Shift+BraceRight".action = move-column-to-workspace "read";
543
544 "Mod+BraceLeft".action = focus-workspace "mon";
545 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon";
546
547 "Mod+Asterisk".action = focus-workspace "vid";
548 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid";
549
550 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
551 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}'';
552
553 "Mod+M".action = consume-or-expel-window-left;
554 "Mod+W".action = consume-or-expel-window-right;
555
556 "Mod+R".action = switch-preset-column-width;
557 "Mod+Shift+R".action = switch-preset-window-height;
558 "Mod+F".action = center-column;
559 "Mod+Shift+F".action = maximize-column;
560 "Mod+Shift+Ctrl+F".action = fullscreen-window;
561
562 "Mod+V".action = switch-focus-between-floating-and-tiling;
563 "Mod+Shift+V".action = toggle-window-floating;
564
565 "Mod+Left".action = set-column-width "-10%";
566 "Mod+Down".action = set-window-height "-10%";
567 "Mod+Up".action = set-window-height "+10%";
568 "Mod+Right".action = set-column-width "+10%";
569
570 "Mod+Shift+Z" = {
571 action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors";
572 allow-when-locked = true;
573 };
574 "Mod+Shift+L".action = spawn loginctl "lock-session";
575 "Mod+Shift+E".action = quit;
576 "Mod+Shift+Minus" = {
577 action = spawn systemctl "suspend";
578 allow-when-locked = true;
579 };
580 "Mod+Shift+Control+Minus" = {
581 action = spawn systemctl "hibernate";
582 allow-when-locked = true;
583 };
584 "Mod+Shift+P" = {
585 action = spawn (lib.getExe pkgs.playerctl) "-a" "pause";
586 allow-when-locked = true;
587 };
588
589 "XF86MonBrightnessUp" = {
590 action = spawn swayosd-client "--brightness" "raise";
591 allow-when-locked = true;
592 };
593 "XF86MonBrightnessDown" = {
594 action = spawn swayosd-client "--brightness" "lower";
595 allow-when-locked = true;
596 };
597 "XF86AudioRaiseVolume" = {
598 action = spawn swayosd-client "--output-volume" "raise";
599 allow-when-locked = true;
600 };
601 "XF86AudioLowerVolume" = {
602 action = spawn swayosd-client "--output-volume" "lower";
603 allow-when-locked = true;
604 };
605 "XF86AudioMute" = {
606 action = spawn swayosd-client "--output-volume" "mute-toggle";
607 allow-when-locked = true;
608 };
609 "XF86AudioMicMute" = {
610 action = spawn swayosd-client "--input-volume" "mute-toggle";
611 allow-when-locked = true;
612 };
613
614 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
615 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
616 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu";
617 "Mod+Comma".action = spawn makoctl "restore";
618
619 "Mod+Control+A".action = focus-or-spawn-action-app_id "com.saivert.pwvucontrol" "pwctl" "pwvucontrol";
620 "Mod+Control+O".action = focus-or-spawn-action-app_id "com.github.wwmm.easyeffects" "eff" "easyeffects";
621 "Mod+Control+P".action = focus-or-spawn-action-app_id "org.keepassxc.KeePassXC" "kpxc" "keepassxc";
622 "Mod+Control+B".action = focus-or-spawn-action-app_id ".blueman-manager-wrapped" "bmgr" "blueman-manager";
623 "Mod+Control+Return".action = focus-or-spawn-action-app_id "kitty-scratch" "term" "kitty" "--app-id" "kitty-scratch";
624 "Mod+Control+E".action = focus-or-spawn-action "select(.app_id == \"emacs\" and .title == \"scratch\")" "edit" "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))";
625 };
626 };
627 };
628}
diff --git a/accounts/gkleen@sif/niri/mako.nix b/accounts/gkleen@sif/niri/mako.nix
deleted file mode 100644
index 0a10555a..00000000
--- a/accounts/gkleen@sif/niri/mako.nix
+++ /dev/null
@@ -1,115 +0,0 @@
1{ config, lib, pkgs, ... }:
2{
3 config = {
4 services.mako = {
5 enable = true;
6 font = "Fira Sans 10";
7 format = "<i>%s</i>\\n%b";
8 margin = "2";
9 maxVisible = -1;
10 backgroundColor = "#000000dd";
11 progressColor = "source #223544ff";
12 width = 384;
13 extraConfig = ''
14 outer-margin=1
15 max-history=100
16 max-icon-size=48
17
18 [grouped]
19 format=<b>(%g)</b> <i>%s</i>\n%b
20
21 [urgency=low]
22 text-color=#999999ff
23
24 [urgency=critical]
25 background-color=#900000dd
26
27 [app-name=Element]
28 group-by=summary
29
30 [mode=silent]
31 invisible=1
32 '';
33 package = pkgs.symlinkJoin {
34 name = "${pkgs.mako.name}-wrapped";
35 paths = with pkgs; [ mako ];
36 inherit (pkgs.mako) meta;
37 postBuild = ''
38 rm -r $out/share/dbus-1
39 '';
40 };
41 };
42 systemd.user.services.mako = {
43 Unit = {
44 Description = "Mako notification daemon";
45 PartOf = [ "graphical-session.target" ];
46 };
47 Install = {
48 WantedBy = [ "graphical-session.target" ];
49 };
50 Service = {
51 Type = "dbus";
52 BusName = "org.freedesktop.Notifications";
53 ExecStart = lib.getExe config.services.mako.package;
54 RestartSec = 5;
55 Restart = "always";
56 };
57 };
58
59 systemd.user.services.mako-follows-focus = {
60 Unit = {
61 BindsTo = [ "niri.service" "mako.service" ];
62 After = [ "niri.service" "mako.service" ];
63 };
64 Service = {
65 Type = "simple";
66 Restart = "always";
67 ExecStart = pkgs.writers.writePython3 "mako-follows-focus" {
68 libraries = with pkgs.python3Packages; [];
69 } ''
70 import os
71 import socket
72 import json
73 import subprocess
74
75
76 current_output = None
77 workspaces = []
78
79
80 def output_changed(new_output):
81 global current_output
82
83 if current_output == new_output:
84 return
85
86 current_output = new_output
87 subprocess.run(["makoctl", "reload"])
88
89
90 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
91 sock.connect(os.environ["NIRI_SOCKET"])
92 sock.send(b"\"EventStream\"\n")
93 for line in sock.makefile(buffering=1, encoding='utf-8'):
94 if line_json := json.loads(line):
95 if "WorkspacesChanged" in line_json:
96 workspaces = line_json["WorkspacesChanged"]["workspaces"]
97 for workspace in workspaces:
98 if not workspace["is_focused"]:
99 continue
100 output_changed(workspace["output"])
101 break
102 if "WorkspaceActivated" in line_json and line_json["WorkspaceActivated"]["focused"]: # noqa: E501
103 for workspace in workspaces:
104 if not workspace["id"] == line_json["WorkspaceActivated"]["id"]: # noqa: E501
105 continue
106 output_changed(workspace["output"])
107 break
108 '';
109 };
110 Install = {
111 WantedBy = [ "mako.service" ];
112 };
113 };
114 };
115}
diff --git a/accounts/gkleen@sif/niri/swayosd.nix b/accounts/gkleen@sif/niri/swayosd.nix
deleted file mode 100644
index 984927c2..00000000
--- a/accounts/gkleen@sif/niri/swayosd.nix
+++ /dev/null
@@ -1,65 +0,0 @@
1{ pkgs, ... }:
2{
3 config = {
4 services.swayosd = {
5 enable = true;
6 topMargin = 0.946154;
7 stylePath = pkgs.runCommand "style.css" {
8 src = pkgs.writeText "style.scss" ''
9 window#osd {
10 padding: 12px 20px;
11 border-radius: 999px;
12 border: none;
13 background: rgba(0, 0, 0, 0.87);
14
15 #container {
16 margin: 16px;
17 }
18
19 image,
20 label {
21 color: rgb(255, 255, 255);
22
23 &:disabled {
24 opacity: 1;
25 color: rgb(84, 84, 84);
26 }
27 }
28
29 progressbar {
30 min-height: 6px;
31 border-radius: 999px;
32 background: transparent;
33 border: none;
34
35 trough, progress {
36 min-height: inherit;
37 border-radius: inherit;
38 border: none;
39 }
40
41 trough {
42 background: rgb(127, 127, 127);
43 }
44 progress {
45 background: rgb(255, 255, 255);
46 }
47
48 &:disabled {
49 opacity: 1;
50
51 trough {
52 background: rgb(19, 19, 19);
53 }
54 progress {
55 background: rgb(38, 38, 38);
56 }
57 }
58 }
59 }
60 '';
61 buildInputs = with pkgs; [sass];
62 } "scss -C --sourcemap=none --style=compact $src $out";
63 };
64 };
65}
diff --git a/accounts/gkleen@sif/niri/waybar.nix b/accounts/gkleen@sif/niri/waybar.nix
deleted file mode 100644
index c3820508..00000000
--- a/accounts/gkleen@sif/niri/waybar.nix
+++ /dev/null
@@ -1,341 +0,0 @@
1{ lib, config, pkgs, ... }:
2let
3 swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client";
4in {
5 config = {
6 programs.waybar = {
7 enable = true;
8 systemd = {
9 enable = true;
10 target = "graphical-session.target";
11 };
12 settings = let
13 windowRewrites = {
14 "(.*) — Mozilla Firefox" = "$1";
15 "(.*) - Mozilla Thunderbird" = "$1";
16 "(.*) - mpv" = "$1";
17 };
18 iconSize = 11;
19 in [
20 {
21 layer = "top";
22 position = "top";
23 height = 14;
24 output = [ "eDP-1" "DP-2" "DP-3" ];
25 modules-left = [ "niri/workspaces" ];
26 modules-center = [ "niri/window" ];
27 modules-right = [ "custom/worktime" "custom/worktime-today"
28 "custom/weather"
29 "custom/keymap"
30 "privacy" "tray" "wireplumber" "backlight" "battery" "idle_inhibitor" "custom/mako" "clock" ];
31
32 "custom/mako" = {
33 format = "{}";
34 return-type = "json";
35 exec = pkgs.writers.writePython3 "mako-silent" { libraries = [ pkgs.python3Packages.dbus-next ]; } ''
36 from dbus_next.aio import MessageBus
37
38 import asyncio
39
40 import json
41
42
43 loop = asyncio.new_event_loop()
44 asyncio.set_event_loop(loop)
45
46
47 async def main():
48 bus = await MessageBus().connect()
49 # the introspection xml would normally be included in your project, but
50 # this is convenient for development
51 introspection = await bus.introspect('org.freedesktop.Notifications', '/fr/emersion/Mako') # noqa: E501
52
53 obj = bus.get_proxy_object('org.freedesktop.Notifications', '/fr/emersion/Mako', introspection) # noqa: E501
54 mako = obj.get_interface('fr.emersion.Mako')
55 properties = obj.get_interface('org.freedesktop.DBus.Properties')
56
57 async def print_mode():
58 modes = await mako.get_modes()
59 is_silent = "silent" in modes
60 icon = "&#xf009b;" if is_silent else "&#xf009a;"
61 text = f"<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>" # noqa: E501
62 if is_silent:
63 text = f"<span color=\"#ffffff\">{text}</span>"
64 print(json.dumps({'text': text}, separators=(',', ':')), flush=True) # noqa: E501
65
66 async def on_properties_changed(interface_name, changed_properties, invalidated_properties): # noqa: E501
67 if "Modes" not in invalidated_properties:
68 return
69
70 await print_mode()
71
72 properties.on_properties_changed(on_properties_changed)
73 await print_mode()
74
75 await loop.create_future()
76
77
78 loop.run_until_complete(main())
79 '';
80 on-click = "makoctl mode -t silent";
81 };
82 "custom/weather" = {
83 format = "{}";
84 tooltip = true;
85 interval = 3600;
86 exec = "${lib.getExe pkgs.wttrbar} --hide-conditions --nerd --custom-indicator \"<span font=\\\"Symbols Nerd Font Mono\\\" size=\\\"100%\\\">{ICON}</span> {FeelsLikeC}°\"";
87 return-type = "json";
88 };
89 "custom/keymap" = {
90 format = "{}";
91 tooltip = true;
92 return-type = "json";
93 exec = pkgs.writers.writePython3 "keymap" {} ''
94 import os
95 import socket
96 import json
97
98
99 def output(keymap):
100 short = keymap
101 if keymap == "English (programmer Dvorak)":
102 short = "dvp"
103 elif keymap == "English (US)":
104 short = "<span color=\"#ffffff\">us</span>"
105 print(json.dumps({'text': short, 'tooltip': keymap}, separators=(',', ':')), flush=True) # noqa: E501
106
107
108 keyboard_layouts = []
109
110 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
111 sock.connect(os.environ["NIRI_SOCKET"])
112 sock.send(b"\"EventStream\"\n")
113 for line in sock.makefile(buffering=1, encoding='utf-8'):
114 if line_json := json.loads(line):
115 if "KeyboardLayoutsChanged" in line_json:
116 keyboard_layouts = line_json["KeyboardLayoutsChanged"]["keyboard_layouts"]["names"] # noqa: E501
117 output(keyboard_layouts[line_json["KeyboardLayoutsChanged"]["keyboard_layouts"]["current_idx"]]) # noqa: E501
118 if "KeyboardLayoutSwitched" in line_json:
119 output(keyboard_layouts[line_json["KeyboardLayoutSwitched"]["idx"]]) # noqa: E501
120 '';
121 on-click = "niri msg action switch-layout next";
122 };
123 "custom/worktime" = {
124 interval = 60;
125 exec = lib.getExe pkgs.worktime;
126 tooltip = false;
127 };
128 "custom/worktime-today" = {
129 interval = 60;
130 exec = "${lib.getExe pkgs.worktime} today";
131 tooltip = false;
132 };
133 "niri/workspaces" = {
134 ignore = ["eff" "pwctl" "kpxc" "bmgr" "edit" "term"];
135 };
136 "niri/window" = {
137 separate-outputs = true;
138 icon = true;
139 icon-size = 14;
140 rewrite = windowRewrites;
141 };
142 clock = {
143 interval = 1;
144 # timezone = "Europe/Berlin";
145 format = "W{:%V-%u %F %H:%M:%S%Ez}";
146 tooltip-format = "<tt><small>{calendar}</small></tt>";
147 calendar = {
148 mode = "year";
149 mode-mon-col = 3;
150 weeks-pos = "left";
151 on-scroll = 1;
152 format = {
153 months = "<span color='#ffead3'><b>{}</b></span>";
154 days = "{}";
155 weeks = "<span color='#99ffdd'><b>{}</b></span>";
156 weekdays = "<span color='#ffcc66'><b>{}</b></span>";
157 today = "<span color='#ff6699'><b>{}</b></span>";
158 };
159 };
160 };
161 battery = {
162 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
163 icon-size = iconSize - 2;
164 states = { warning = 30; critical = 15; };
165 format-icons = ["&#xf008e;" "&#xf007a;" "&#xf007b;" "&#xf007c;" "&#xf007d;" "&#xf007e;" "&#xf007f;" "&#xf0080;" "&#xf0081;" "&#xf0082;" "&#xf0079;" ];
166 format-charging = "&#xf0084;";
167 format-plugged = "&#xf06a5;";
168 tooltip-format = "{capacity}% {timeTo}";
169 interval = 20;
170 };
171 tray = {
172 icon-size = 16;
173 # show-passive-items = true;
174 spacing = 1;
175 };
176 privacy = {
177 icon-spacing = 7;
178 icon-size = iconSize;
179 modules = [
180 { type = "screenshare"; }
181 { type = "audio-in"; }
182 ];
183 };
184 idle_inhibitor = {
185 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
186 icon-size = iconSize;
187 format-icons = { activated = "&#xf0208;"; deactivated = "&#xf0209;"; };
188 timeout = 120;
189 };
190 backlight = {
191 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
192 icon-size = iconSize;
193 tooltip-format = "{percent}%";
194 format-icons = ["&#xf00da;" "&#xf00db;" "&#xf00dc;" "&#xf00dd;" "&#xf00de;" "&#xf00df;" "&#xf00e0;"];
195 on-scroll-up = "${swayosd-client} --brightness raise";
196 on-scroll-down = "${swayosd-client} --brightness lower";
197 };
198 wireplumber = {
199 format = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">{icon}</span>";
200 icon-size = iconSize;
201 tooltip-format = "{volume}% {node_name}";
202 format-icons = ["&#xf057f;" "&#xf0580;" "&#xf057e;"];
203 format-muted = "<span font=\"Symbols Nerd Font Mono\" size=\"90%\">&#xf075f;</span>";
204 # ignored-sinks = ["Easy Effects Sink"];
205 on-scroll-up = "${swayosd-client} --output-volume raise";
206 on-scroll-down = "${swayosd-client} --output-volume lower";
207 on-click = "${swayosd-client} --output-volume mute-toggle";
208 };
209 }
210 {
211 layer = "top";
212 position = "top";
213 height = 14;
214 output = [ "!eDP-1" "!DP-2" "!DP-3" ];
215 modules-left = [ "niri/workspaces" ];
216 modules-center = [ "niri/window" ];
217 modules-right = [ "clock" ];
218
219 "niri/workspaces" = {
220 ignore = ["pwctl" "kpxc" "bmgr" "edit" "term"];
221 };
222 "niri/window" = {
223 separate-outputs = true;
224 icon = true;
225 icon-size = 14;
226 rewrite = windowRewrites;
227 };
228 clock = {
229 interval = 1;
230 # timezone = "Europe/Berlin";
231 format = "{:%H:%M}";
232 tooltip-format = "W{:%V-%u %F %H:%M:%S%Ez}";
233 };
234 }
235 ];
236 style = ''
237 @define-color white #ffffff;
238 @define-color grey #555555;
239 @define-color blue #1a8fff;
240 @define-color green #23fd00;
241 @define-color orange #f28a21;
242 @define-color red #f2201f;
243
244 * {
245 border: none;
246 font-family: "Fira Sans";
247 font-size: 10pt;
248 min-height: 0;
249 }
250
251 window#waybar {
252 background-color: rgba(0, 0, 0, 0.66);
253 color: @white;
254 }
255
256 .modules-left {
257 margin-left: 12px;
258 }
259 .modules-right {
260 margin-right: 12px;
261 }
262
263 .module {
264 margin: 0 5px;
265 }
266
267 #workspaces button {
268 color: @white;
269 padding: 2px 5px;
270 }
271 #workspaces button.empty {
272 color: @grey;
273 }
274 #workspaces button.active {
275 color: @green;
276 }
277 #workspaces button.urgent {
278 color: @red;
279 }
280
281 #custom-weather, #custom-keymap, #custom-worktime, #custom-worktime-today {
282 color: @grey;
283 margin: 0 5px;
284 }
285 #custom-weather {
286 margin-right: 3px;
287 }
288 #custom-keymap {
289 margin-left: 3px;
290 margin-right: 3px;
291 }
292
293 #tray {
294 margin: 0;
295 }
296 #battery, #idle_inhibitor, #backlight, #wireplumber, #custom-mako {
297 color: @grey;
298 margin: 0 5px 0 2px;
299 }
300 #idle_inhibitor {
301 margin-right: 4px;
302 margin-left: 6px;
303 }
304 #custom-mako {
305 margin-right: 2px;
306 margin-left: 3px;
307 }
308 #battery {
309 margin-right: 3px;
310 }
311 #battery.discharging {
312 color: @white;
313 }
314 #battery.warning {
315 color: @orange;
316 }
317 #battery.critical {
318 color: @red;
319 }
320 #battery.charging {
321 color: @white;
322 }
323 #idle_inhibitor.activated {
324 color: @white;
325 }
326
327 #idle_inhibitor {
328 padding-top: 1px;
329 }
330
331 #privacy {
332 color: @red;
333 margin: -1px 4px 0px 3px;
334 }
335 #clock {
336 /* margin-right: 5px; */
337 }
338 '';
339 };
340 };
341}