summaryrefslogtreecommitdiff
path: root/accounts/gkleen@sif/niri/default.nix
diff options
context:
space:
mode:
Diffstat (limited to 'accounts/gkleen@sif/niri/default.nix')
-rw-r--r--accounts/gkleen@sif/niri/default.nix231
1 files changed, 203 insertions, 28 deletions
diff --git a/accounts/gkleen@sif/niri/default.nix b/accounts/gkleen@sif/niri/default.nix
index dc993d66..8752f3e3 100644
--- a/accounts/gkleen@sif/niri/default.nix
+++ b/accounts/gkleen@sif/niri/default.nix
@@ -35,7 +35,11 @@ let
35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then 35 if jq -e '.is_focused' <<<"$window_json" >/dev/null; then
36 niri msg action focus-workspace-previous 36 niri msg action focus-workspace-previous
37 else 37 else
38 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" 38 if [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].is_focused' <<<"$workspaces_json") != "true" ]] && [[ $(jq -r --arg workspace_name "$workspace_name" 'map(select(.name == $workspace_name)) | .[0].id' <<<"$workspaces_json") = $(jq -r '.workspace_id' <<<"$window_json") ]]; then
39 niri msg action focus-workspace "$workspace_name"
40 else
41 niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")"
42 fi
39 fi 43 fi
40 exit 0 44 exit 0
41 fi 45 fi
@@ -45,7 +49,6 @@ let
45 ''; 49 '';
46 }; 50 };
47 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); 51 focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn);
48 focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")'';
49 52
50 with_adjacent_workspace = pkgs.writeShellApplication { 53 with_adjacent_workspace = pkgs.writeShellApplication {
51 name = "with-adjacent-workspace"; 54 name = "with-adjacent-workspace";
@@ -84,7 +87,7 @@ let
84 }; 87 };
85 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; 88 with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$";
86 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 89 focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
87 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 90 move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
88 91
89 with_unnamed_workspace = pkgs.writeShellApplication { 92 with_unnamed_workspace = pkgs.writeShellApplication {
90 name = "with-unnamed-workspace"; 93 name = "with-unnamed-workspace";
@@ -131,7 +134,7 @@ let
131 134
132 windows_json="$(niri msg -j windows)" 135 windows_json="$(niri msg -j windows)"
133 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 136 active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")"
134 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)" 137 window_ix="$(gojq -r --arg active_workspace "$active_workspace" '.[] | select('"$window_select"') | "\(.title)\u0000icon\u001f\(.app_id)"' <<<"$windows_json" | fuzzel --width=60 --log-level=warning --dmenu --index)"
135 # shellcheck disable=SC2016 138 # shellcheck disable=SC2016
136 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" 139 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")"
137 140
@@ -141,6 +144,25 @@ let
141 ''; 144 '';
142 }; 145 };
143 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); 146 with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window);
147
148 with_predicate_window = pred: pkgs.writeShellApplication {
149 name = "with-predicate-window";
150 runtimeInputs = [ niri pkgs.gojq pkgs.socat ];
151 text = ''
152 action="$1"
153 shift
154
155 windows_json="$(niri msg -j windows)"
156 window_json="$(gojq -rc 'map(select(${pred})) | .[0]' <<<"$windows_json")"
157
158 [[ -z "$window_json" || $window_json = "null" ]] && exit 1
159
160 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET"
161 '';
162 };
163
164 with-urgent-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_urgent"));
165 with-focused-window-action = config.lib.niri.actions.spawn (lib.getExe (with_predicate_window ".is_focused"));
144in { 166in {
145 imports = [ 167 imports = [
146 ./waybar.nix 168 ./waybar.nix
@@ -171,6 +193,17 @@ in {
171 type = lib.types.nullOr lib.types.str; 193 type = lib.types.nullOr lib.types.str;
172 default = null; 194 default = null;
173 }; 195 };
196 moveKey = lib.mkOption {
197 type = lib.types.nullOr lib.types.str;
198 default = let
199 keys = lib.splitString "+" config.key;
200 defMoveKey = lib.concatStringsSep "+" (lib.flatten [
201 (lib.take (lib.length keys - 1) keys)
202 ["Shift"]
203 (lib.takeEnd 1 keys)
204 ]);
205 in if config.key == null then null else defMoveKey;
206 };
174 spawn = lib.mkOption { 207 spawn = lib.mkOption {
175 type = lib.types.nullOr (lib.types.listOf lib.types.str); 208 type = lib.types.nullOr (lib.types.listOf lib.types.str);
176 default = null; 209 default = null;
@@ -245,11 +278,11 @@ in {
245 Service = { 278 Service = {
246 Type = "simple"; 279 Type = "simple";
247 Sockets = [ "niri-workspace-history.socket" ]; 280 Sockets = [ "niri-workspace-history.socket" ];
248 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' 281 ExecStart = pkgs.writers.writePython3 "niri-workspace-history" { flakeIgnore = ["E501"]; } ''
249 import os 282 import os
250 import socket 283 import socket
251 import json 284 import json
252 import sys 285 # import sys
253 from collections import defaultdict 286 from collections import defaultdict
254 from threading import Thread, Lock 287 from threading import Thread, Lock
255 from socketserver import StreamRequestHandler, ThreadingTCPServer 288 from socketserver import StreamRequestHandler, ThreadingTCPServer
@@ -274,8 +307,8 @@ in {
274 307
275 def focus_workspace(output, workspace): 308 def focus_workspace(output, workspace):
276 with history_lock: 309 with history_lock:
277 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 310 workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace]
278 print(json.dumps(workspace_history), file=sys.stderr) 311 # print(json.dumps(workspace_history), file=sys.stderr)
279 312
280 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) 313 sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
281 sock.connect(os.environ["NIRI_SOCKET"]) 314 sock.connect(os.environ["NIRI_SOCKET"])
@@ -297,14 +330,14 @@ in {
297 330
298 class RequestHandler(StreamRequestHandler): 331 class RequestHandler(StreamRequestHandler):
299 def handle(self): 332 def handle(self):
300 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 333 with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out:
301 with history_lock: 334 with history_lock:
302 json.dump(workspace_history, out) 335 json.dump(workspace_history, out)
303 336
304 337
305 class Server(ThreadingTCPServer): 338 class Server(ThreadingTCPServer):
306 def __init__(self): 339 def __init__(self):
307 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 340 ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False)
308 self.socket = socket.fromfd(3, self.address_family, self.socket_type) 341 self.socket = socket.fromfd(3, self.address_family, self.socket_type)
309 342
310 343
@@ -330,6 +363,79 @@ in {
330 ''; 363 '';
331 }; 364 };
332 }; 365 };
366 systemd.user.services.niri-workspace-sort = {
367 Unit = {
368 BindsTo = [ "niri.service" ];
369 After = [ "niri.service" ];
370 };
371 Install = {
372 WantedBy = [ "niri.service" ];
373 };
374 Service = {
375 Type = "simple";
376 ExecStart = pkgs.writers.writePython3 "niri-workspace-sort" { flakeIgnore = ["E501"]; } ''
377 import os
378 import sys
379 import socket
380 import json
381
382 outputs = None
383 only = {'HDMI-A-1': {'bmr'}, 'eDP-1': {'vid'}}
384
385
386 class Niri(socket.socket):
387 def __init__(self):
388 super().__init__(socket.AF_UNIX, socket.SOCK_STREAM)
389 super().connect(os.environ["NIRI_SOCKET"])
390 self.fh = super().makefile(mode='rw', buffering=1, encoding='utf-8')
391
392 def cmd(self, obj):
393 print(json.dumps(obj, separators=(',', ':')), flush=True, file=self.fh)
394
395 def event_stream(self):
396 self.cmd("EventStream")
397 return self.fh
398
399
400 with Niri() as niri, Niri().event_stream() as niri_stream:
401 for line in niri_stream:
402 workspaces = None
403 if line_json := json.loads(line):
404 if "WorkspacesChanged" in line_json:
405 workspaces = line_json["WorkspacesChanged"]["workspaces"]
406
407 if workspaces is None:
408 continue
409
410 old_outputs = outputs
411 outputs = {ws["output"] for ws in workspaces}
412 if old_outputs is None:
413 print("Initial outputs: {}".format(outputs), file=sys.stderr)
414 continue
415
416 new_outputs = outputs - old_outputs
417 if not new_outputs:
418 continue
419 print("New outputs: {}".format(new_outputs), file=sys.stderr)
420
421 relevant_workspaces = list(filter(lambda ws: (ws["name"] is not None) or (ws["active_window_id"] is not None), workspaces))
422 target_output = next(iter(outputs - set(only.keys())))
423 if not target_output:
424 continue
425 for ws in relevant_workspaces:
426 ws_ident = ws["name"] if ws["name"] is not None else (ws["output"], ws["idx"])
427 if ws["output"] not in set(only.keys()):
428 continue
429 if ws_ident in only[ws["output"]]:
430 continue
431
432 print("{} -> {}".format(ws_ident, target_output), file=sys.stderr)
433 niri.cmd({"Action": {"MoveWorkspaceToMonitor": {"reference": {"Id": ws["id"]}, "output": target_output}}})
434 '';
435 Restart = "on-failure";
436 RestartSec = 10;
437 };
438 };
333 439
334 programs.niri.scratchspaces = [ 440 programs.niri.scratchspaces = [
335 { name = "pwctl"; 441 { name = "pwctl";
@@ -343,7 +449,7 @@ in {
343 { title = "^Access Request.*"; } 449 { title = "^Access Request.*"; }
344 { title = ".*Passkey credentials$"; } 450 { title = ".*Passkey credentials$"; }
345 ]; 451 ];
346 windowRuleExtra = [ 452 windowRuleExtra = with kdl; [
347 (kdl.leaf "open-focused" false) 453 (kdl.leaf "open-focused" false)
348 ]; 454 ];
349 key = "Mod+Control+P"; 455 key = "Mod+Control+P";
@@ -371,6 +477,20 @@ in {
371 app-id = "com.github.wwmm.easyeffects"; 477 app-id = "com.github.wwmm.easyeffects";
372 spawn = [ "easyeffects" ]; 478 spawn = [ "easyeffects" ];
373 } 479 }
480 { name = "time";
481 key = "Mod+Control+K";
482 app-id = "chrome-kimai.yggdrasil.li__-Default";
483 spawn = [ (toString (pkgs.resholve.writeScript "kimai" {
484 interpreter = pkgs.runtimeShell;
485 inputs = [ pkgs.dex ];
486 execer = [ "cannot:${lib.getExe pkgs.dex}" ];
487 } ''
488 exec dex $HOME/.local/state/nix/profile/share/applications/kimai.desktop
489 '')) ];
490 windowRuleExtra = with kdl; [
491 (leaf "block-out-from" "screencast")
492 ];
493 }
374 ]; 494 ];
375 programs.niri.config = 495 programs.niri.config =
376 let 496 let
@@ -415,6 +535,10 @@ in {
415 ]) 535 ])
416 ]) 536 ])
417 537
538 (plain "gestures" [
539 (plain "hot-corners" [(flag "off")])
540 ])
541
418 (plain "environment" (lib.mapAttrsToList leaf { 542 (plain "environment" (lib.mapAttrsToList leaf {
419 NIXOS_OZONE_WL = "1"; 543 NIXOS_OZONE_WL = "1";
420 QT_QPA_PLATFORM = "wayland"; 544 QT_QPA_PLATFORM = "wayland";
@@ -422,6 +546,10 @@ in {
422 GDK_BACKEND = "wayland"; 546 GDK_BACKEND = "wayland";
423 SDL_VIDEODRIVER = "wayland"; 547 SDL_VIDEODRIVER = "wayland";
424 DISPLAY = ":0"; 548 DISPLAY = ":0";
549 ELECTRON_OZONE_PLATFORM_HINT = "auto";
550 SSH_ASKPASS_REQUIRE = "prefer";
551 SSH_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
552 SUDO_ASKPASS = lib.getExe pkgs.kdePackages.ksshaskpass;
425 })) 553 }))
426 554
427 (node "output" "eDP-1" [ 555 (node "output" "eDP-1" [
@@ -536,7 +664,7 @@ in {
536 (plain "window-rule" [ 664 (plain "window-rule" [
537 (map (title: 665 (map (title:
538 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) 666 (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; })
539 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"]) 667 ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$" "Browser Access Request$"])
540 (leaf "open-focused" true) 668 (leaf "open-focused" true)
541 (leaf "open-floating" true) 669 (leaf "open-floating" true)
542 ]) 670 ])
@@ -565,7 +693,7 @@ in {
565 (plain "window-rule" [ 693 (plain "window-rule" [
566 (leaf "match" { app-id = "^thunderbird$"; }) 694 (leaf "match" { app-id = "^thunderbird$"; })
567 (leaf "match" { app-id = "^Element$"; }) 695 (leaf "match" { app-id = "^Element$"; })
568 (leaf "match" { app-id = "^Rainbow$"; }) 696 (leaf "match" { app-id = "^chrome-web\.openrainbow\.com__-Default$"; })
569 (leaf "open-on-workspace" "comm") 697 (leaf "open-on-workspace" "comm")
570 ]) 698 ])
571 (plain "window-rule" [ 699 (plain "window-rule" [
@@ -584,6 +712,11 @@ in {
584 (leaf "open-focused" false) 712 (leaf "open-focused" false)
585 ]) 713 ])
586 (plain "window-rule" [ 714 (plain "window-rule" [
715 (leaf "match" { app-id = "^chrome-audiobookshelf\.yggdrasil\.li__-Default$"; })
716 (leaf "match" { app-id = "^YouTube Music Desktop App$"; })
717 (leaf "open-on-workspace" "vid")
718 ])
719 (plain "window-rule" [
587 (leaf "match" { app-id = "^pdfpc$"; }) 720 (leaf "match" { app-id = "^pdfpc$"; })
588 (plain "default-column-width" [(leaf "proportion" 1.)]) 721 (plain "default-column-width" [(leaf "proportion" 1.)])
589 ]) 722 ])
@@ -633,6 +766,21 @@ in {
633 "Mod+Slash".action = show-hotkey-overlay; 766 "Mod+Slash".action = show-hotkey-overlay;
634 767
635 "Mod+Return".action = spawn terminal; 768 "Mod+Return".action = spawn terminal;
769 "Mod+Shift+Return".action =
770 let
771 nushellKitty = pkgs.symlinkJoin {
772 name = "nushell-kitty";
773 paths = [ config.programs.kitty.package ];
774 buildInputs = [ pkgs.makeWrapper ];
775 postBuild = ''
776 wrapProgram $out/bin/kitty \
777 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
778 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
779 shell ${lib.getExe config.programs.nushell.package}
780 ''}"
781 '';
782 };
783 in spawn (lib.getExe' nushellKitty "kitty");
636 "Mod+Q".action = close-window; 784 "Mod+Q".action = close-window;
637 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); 785 "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package);
638 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; 786 "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path";
@@ -668,12 +816,12 @@ in {
668 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) 816 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)
669 $FOUND || echo 817 $FOUND || echo
670 } 818 }
671 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $? 819 FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> " --width=60) || exit $?
672 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then 820 if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then
673 QALC_RES="$FUZZEL_RES" 821 QALC_RES="$FUZZEL_RES"
674 QALC_RET=0 822 QALC_RET=0
675 else 823 else
676 QALC_RES=$(qalc "$FUZZEL_RES" 2>&1) 824 QALC_RES=$(qalc -set "autocalc off" "$FUZZEL_RES" 2>&1)
677 QALC_RET=$? 825 QALC_RET=$?
678 fi 826 fi
679 [[ -n "$QALC_RES" ]] || exit 1 827 [[ -n "$QALC_RES" ]] || exit 1
@@ -693,18 +841,33 @@ in {
693 notify-send "$QALC_RES" 841 notify-send "$QALC_RES"
694 ''; 842 '';
695 })); 843 }));
844 "Mod+Shift+U".action =
845 let
846 qalcKitty = pkgs.symlinkJoin {
847 name = "qalc-kitty";
848 paths = [ config.programs.kitty.package ];
849 buildInputs = [ pkgs.makeWrapper ];
850 postBuild = ''
851 wrapProgram $out/bin/kitty \
852 --add-flags "--config ${pkgs.writeText "kitty.conf" ''
853 include $HOME/${config.xdg.configFile."kitty/kitty.conf".target}
854 shell ${lib.getExe pkgs.libqalculate}
855 ''}"
856 '';
857 };
858 in spawn (lib.getExe' qalcKitty "kitty");
696 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { 859 "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication {
697 name = "emoji-fuzzel"; 860 name = "emoji-fuzzel";
698 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; 861 runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ];
699 text = '' 862 text = ''
700 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $? 863 FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " --cache "$HOME"/.cache/fuzzel-emoji --width=60 <"$HOME"/.local/share/emoji-data/list.txt) || exit $?
701 [[ -n "$FUZZEL_RES" ]] || exit 1 864 [[ -n "$FUZZEL_RES" ]] || exit 1
702 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste 865 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste
703 ''; 866 '';
704 })); 867 }));
705 "Print".action = screenshot; 868 "Print".action = screenshot;
706 "Control+Print".action = screenshot-window; 869 "Control+Print".action = screenshot-window;
707 # "Shift+Print".action = screenshot-screen; 870 "Shift+Print".action = kdl.magic-leaf "screenshot-screen";
708 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 871 "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
709 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; 872 "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
710 873
@@ -743,22 +906,22 @@ in {
743 "Mod+Shift+Control+C".action = move-workspace-up; 906 "Mod+Shift+Control+C".action = move-workspace-up;
744 907
745 "Mod+ParenLeft".action = focus-workspace "comm"; 908 "Mod+ParenLeft".action = focus-workspace "comm";
746 "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm"; 909 "Mod+Shift+ParenLeft".action = kdl.magic-leaf "move-column-to-workspace" "comm";
747 910
748 "Mod+ParenRight".action = focus-workspace "web"; 911 "Mod+ParenRight".action = focus-workspace "web";
749 "Mod+Shift+ParenRight".action = move-column-to-workspace "web"; 912 "Mod+Shift+ParenRight".action = kdl.magic-leaf "move-column-to-workspace" "web";
750 913
751 "Mod+BraceRight".action = focus-workspace "read"; 914 "Mod+BraceRight".action = focus-workspace "read";
752 "Mod+Shift+BraceRight".action = move-column-to-workspace "read"; 915 "Mod+Shift+BraceRight".action = kdl.magic-leaf "move-column-to-workspace" "read";
753 916
754 "Mod+BraceLeft".action = focus-workspace "mon"; 917 "Mod+BraceLeft".action = focus-workspace "mon";
755 "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon"; 918 "Mod+Shift+BraceLeft".action = kdl.magic-leaf "move-column-to-workspace" "mon";
756 919
757 "Mod+Asterisk".action = focus-workspace "vid"; 920 "Mod+Asterisk".action = focus-workspace "vid";
758 "Mod+Shift+Asterisk".action = move-column-to-workspace "vid"; 921 "Mod+Shift+Asterisk".action = kdl.magic-leaf "move-column-to-workspace" "vid";
759 922
760 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; 923 "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}'';
761 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; 924 "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}, "focus": true}}}'';
762 925
763 "Mod+M".action = consume-or-expel-window-left; 926 "Mod+M".action = consume-or-expel-window-left;
764 "Mod+W".action = consume-or-expel-window-right; 927 "Mod+W".action = consume-or-expel-window-right;
@@ -766,10 +929,11 @@ in {
766 "Mod+Shift+M".action = toggle-column-tabbed-display; 929 "Mod+Shift+M".action = toggle-column-tabbed-display;
767 930
768 "Mod+R".action = switch-preset-column-width; 931 "Mod+R".action = switch-preset-column-width;
769 "Mod+Shift+R".action = switch-preset-window-height; 932 "Mod+Shift+R".action = maximize-column;
933 "Mod+Shift+Ctrl+R".action = switch-preset-window-height;
770 "Mod+F".action = center-column; 934 "Mod+F".action = center-column;
771 "Mod+Shift+F".action = maximize-column; 935 "Mod+Shift+F".action = toggle-windowed-fullscreen;
772 "Mod+Shift+Ctrl+F".action = fullscreen-window; 936 "Mod+Ctrl+Shift+F".action = fullscreen-window;
773 937
774 "Mod+V".action = switch-focus-between-floating-and-tiling; 938 "Mod+V".action = switch-focus-between-floating-and-tiling;
775 "Mod+Shift+V".action = toggle-window-floating; 939 "Mod+Shift+V".action = toggle-window-floating;
@@ -825,13 +989,24 @@ in {
825 989
826 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; 990 "Mod+Semicolon".action = spawn makoctl "dismiss" "--group";
827 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; 991 "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all";
828 "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu"; 992 "Mod+Period".action = spawn makoctl "menu" "--" (lib.getExe config.programs.fuzzel.package) "--dmenu";
829 "Mod+Comma".action = spawn makoctl "restore"; 993 "Mod+Comma".action = spawn makoctl "restore";
830 994
831 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 995 "Mod+Control+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"FocusWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}";
832 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}}}}"; 996 "Mod+Control+Shift+W".action = with-empty-unnamed-workspace-action "{\"Action\":{\"MoveColumnToWorkspace\":{\"reference\":{\"Id\": $workspace_id}, \"focus\": true}}}";
997
998 "Mod+X".action = set-dynamic-cast-window;
999 "Mod+Shift+X".action = set-dynamic-cast-monitor;
1000 "Mod+Control+Shift+X".action = clear-dynamic-cast-target;
1001
1002 "Mod+D".action = with-urgent-window-action "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}";
1003 "Mod+Shift+D".action = with-focused-window-action "{\"Action\":{\"UnsetUrgent\":{\"id\": .id}}}";
1004
1005 "Mod+K".action = spawn (lib.getExe' pkgs.worktime "worktime-ui");
1006 "Mod+Shift+K".action = spawn (lib.getExe' pkgs.worktime "worktime-stop");
833 })) 1007 }))
834 (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) 1008 (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)
1009 (map ({ name, moveKey, ...}: if moveKey != null then bind moveKey { action = kdl.magic-leaf "move-column-to-workspace" name; } else null) cfg.scratchspaces)
835 ] 1010 ]
836 )) 1011 ))
837 ]; 1012 ];