{ config, hostConfig, pkgs, lib, flakeInputs, ... }: let cfg = config.programs.niri; kdl = flakeInputs.niri-flake.lib.kdl; niri = cfg.package; terminal = lib.getExe config.programs.kitty.package; makoctl = lib.getExe' config.services.mako.package "makoctl"; loginctl = lib.getExe' hostConfig.systemd.package "loginctl"; systemctl = lib.getExe' hostConfig.systemd.package "systemctl"; swayosd-client = lib.getExe' config.services.swayosd.package "swayosd-client"; focus_or_spawn = pkgs.writeShellApplication { name = "focus-or-spawn"; runtimeInputs = [ niri pkgs.gojq pkgs.gnugrep pkgs.socat ]; text = '' window_select="$1" shift workspace_name="$1" shift workspaces_json="$(niri msg -j workspaces)" workspace_output="$(jq -r --arg workspace_name "$workspace_name" '.[] | select(.name == $workspace_name) | .output' <<<"$workspaces_json")" # active_workspace="$(jq -r --arg workspace_output "$workspace_output" '.[] | select(.output == $workspace_output and .is_active) | .id' <<<"$workspaces_json")" active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" if [[ $workspace_output != "$active_output" ]]; then niri msg action move-workspace-to-monitor --reference "$workspace_name" "$active_output" # socat STDIO "$NIRI_SOCKET" <<<'{"Action":{"FocusWorkspace":{"reference":{"Id":'"''${active_workspace}"'}}}}' # niri msg action move-workspace-to-index --reference "$workspace_name" 1 fi while IFS=$'\n' read -r window_json; do if [[ -n $(jq -c "$window_select" <<<"$window_json") ]]; then if jq -e '.is_focused' <<<"$window_json" >/dev/null; then niri msg action focus-workspace-previous else niri msg action focus-window --id "$(jq -r '.id' <<<"$window_json")" fi exit 0 fi done < <(niri msg -j windows | jq -c '.[]') exec "$@" ''; }; focus-or-spawn-action = config.lib.niri.actions.spawn (lib.getExe focus_or_spawn); focus-or-spawn-action-app_id = app_id: focus-or-spawn-action ''select(.app_id == "${app_id}")''; with_adjacent_workspace = pkgs.writeShellApplication { name = "with-adjacent-workspace"; runtimeInputs = [ niri pkgs.gojq pkgs.socat ]; text = '' blacklist="$1" shift direction="$1" shift action="$1" shift workspaces_json="$(niri msg -j workspaces)" active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" workspace_output="$(jq -r --arg active_workspace "$active_workspace" '.[] | select(.id == ($active_workspace | tonumber)) | .output' <<<"$workspaces_json")" workspace_idx="$(jq -r '.[] | select(.is_focused) | .idx' <<<"$workspaces_json")" jq_script='map(select(' case "$direction" in down) # shellcheck disable=SC2016 jq_script=''${jq_script}'.idx > ($workspace_idx | tonumber)';; up) # shellcheck disable=SC2016 jq_script=''${jq_script}'.idx < ($workspace_idx | tonumber)';; esac # shellcheck disable=SC2016 jq_script=''${jq_script}' and .output == $workspace_output and ((.name == null) or (.name | test($blacklist) | not)))) | sort_by(.idx)' [[ $direction == "up" ]] && jq_script=''${jq_script}' | reverse' jq_script=''${jq_script}' | .[0]' workspace_json=$(jq -c --arg blacklist "$blacklist" --arg workspace_output "$workspace_output" --arg workspace_idx "$workspace_idx" "$jq_script" <<<"$workspaces_json") [[ -n $workspace_json && $workspace_json != null ]] || exit 0 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" ''; }; with-adjacent-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_adjacent_workspace) "^${lib.concatMapStringsSep "|" ({ name, ...}: name) cfg.scratchspaces}$"; focus-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; move-column-to-adjacent-workspace = direction: with-adjacent-workspace-action direction ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; with_unnamed_workspace = pkgs.writeShellApplication { name = "with-unnamed-workspace"; runtimeInputs = [ niri pkgs.gojq pkgs.socat ]; text = '' action="$1" shift workspaces_json="$(niri msg -j workspaces)" active_output="$(jq -r '.[] | select(.is_focused) | .output' <<<"$workspaces_json")" active_workspace="$(jq -r '.[] | select(.is_focused) | .id' <<<"$workspaces_json")" history_json="$(socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/niri-workspace-history.sock)" 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")" [[ -n $workspace_json && $workspace_json != null ]] || exit 0 jq --arg active_workspace "$active_workspace" -c "$action" <<<"$workspace_json" | tee /dev/stderr | socat STDIO "$NIRI_SOCKET" ''; }; with-unnamed-workspace-action = config.lib.niri.actions.spawn (lib.getExe with_unnamed_workspace); with_select_window = pkgs.writeShellApplication { name = "with-select-window"; runtimeInputs = [ niri pkgs.gojq pkgs.socat config.programs.fuzzel.package pkgs.gawk ]; text = '' window_select="$1" shift action="$1" shift windows_json="$(niri msg -j windows)" active_workspace="$(jq -r '.[] | select(.is_focused) | .workspace_id' <<<"$windows_json")" 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)" # shellcheck disable=SC2016 window_json="$(gojq -rc --arg active_workspace "$active_workspace" --arg window_ix "$window_ix" 'map(select('"$window_select"')) | .[($window_ix | tonumber)]' <<<"$windows_json")" [[ -z "$window_json" ]] && exit 1 jq -c "$action" <<<"$window_json" | socat STDIO "$NIRI_SOCKET" ''; }; with-select-window-action = config.lib.niri.actions.spawn (lib.getExe with_select_window); in { imports = [ ./waybar.nix ./mako.nix ./swayosd.nix ]; options = { programs.niri.scratchspaces = lib.mkOption { type = lib.types.listOf (lib.types.submodule ({ config, ... }: { options = { name = lib.mkOption { type = lib.types.str; }; match = lib.mkOption { type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args); default = []; }; exclude = lib.mkOption { type = lib.types.listOf (lib.types.attrsOf kdl.types.kdl-args); default = []; }; windowRuleExtra = lib.mkOption { type = kdl.types.kdl-nodes; default = []; }; key = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; spawn = lib.mkOption { type = lib.types.nullOr (lib.types.listOf lib.types.str); default = null; }; app-id = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; selector = lib.mkOption { type = lib.types.nullOr lib.types.str; default = null; }; }; config = lib.mkMerge [ (lib.mkIf (config.app-id != null) { match = lib.mkDefault [ { app-id = "^${lib.escapeRegex config.app-id}$"; } ]; selector = lib.mkDefault "select(.app_id == \"${config.app-id}\")"; }) ]; })); default = []; }; }; config = { systemd.user.services.xwayland-satellite = { Unit = { BindsTo = [ "graphical-session.target" ]; PartOf = [ "graphical-session.target" ]; After = [ "graphical-session.target" ]; Requisite = [ "graphical-session.target" ]; }; Service = { Type = "notify"; NotifyAccess = "all"; Environment = [ "DISPLAY=:0" ]; ExecStart = ''${lib.getExe pkgs.xwayland-satellite-unstable} ''${DISPLAY}''; ExecStartPre = "${systemctl} --user import-environment DISPLAY"; StandardOutput = "journal"; }; Install = { WantedBy = [ "graphical-session.target" ]; }; }; services.swayidle = { events = [ { event = "after-resume"; command = "${lib.getExe niri} msg action power-on-monitors"; } ]; timeouts = [ { timeout = 300; command = "${lib.getExe niri} msg action power-off-monitors"; } ]; }; systemd.user.sockets.niri-workspace-history = { Socket = { ListenStream = "%t/niri-workspace-history.sock"; SocketMode = "0600"; }; }; systemd.user.services.niri-workspace-history = { Unit = { BindsTo = [ "niri.service" ]; After = [ "niri.service" ]; }; Install = { WantedBy = [ "niri.service" ]; }; Service = { Type = "simple"; Sockets = [ "niri-workspace-history.socket" ]; ExecStart = pkgs.writers.writePython3 "niri-workspace-history" {} '' import os import socket import json import sys from collections import defaultdict from threading import Thread, Lock from socketserver import StreamRequestHandler, ThreadingTCPServer from contextlib import contextmanager from io import TextIOWrapper @contextmanager def detaching(thing): try: yield thing finally: thing.detach() workspace_history = defaultdict(list) history_lock = Lock() def monitor_niri(): workspaces = list() def focus_workspace(output, workspace): global workspace_history, history_lock with history_lock: workspace_history[output] = [workspace] + [ws for ws in workspace_history[output] if ws != workspace] # noqa: E501 print(json.dumps(workspace_history), file=sys.stderr) sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) sock.connect(os.environ["NIRI_SOCKET"]) sock.send(b"\"EventStream\"\n") for line in sock.makefile(buffering=1, encoding='utf-8'): if line_json := json.loads(line): if "WorkspacesChanged" in line_json: workspaces = line_json["WorkspacesChanged"]["workspaces"] for ws in workspaces: if ws["is_focused"]: focus_workspace(ws["output"], ws["id"]) if "WorkspaceActivated" in line_json: for ws in workspaces: if ws["id"] != line_json["WorkspaceActivated"]["id"]: continue focus_workspace(ws["output"], ws["id"]) break class RequestHandler(StreamRequestHandler): def handle(self): global workspace_history, history_lock with detaching(TextIOWrapper(self.wfile, encoding='utf-8', write_through=True)) as out: # noqa: E501 with history_lock: json.dump(workspace_history, out) class Server(ThreadingTCPServer): def __init__(self): ThreadingTCPServer.__init__(self, ("", 8000), RequestHandler, bind_and_activate=False) # noqa: E501 self.socket = socket.fromfd(3, self.address_family, self.socket_type) def run_server(): with Server() as server: server.serve_forever() niri = Thread(target=monitor_niri) niri.daemon = True niri.start() server_thread = Thread(target=run_server) server_thread.daemon = True server_thread.start() while True: server_thread.join(timeout=0.5) niri.join(timeout=0.5) if not (niri.is_alive() and server_thread.is_alive()): break ''; }; }; programs.niri.scratchspaces = [ { name = "pwctl"; key = "Mod+Control+A"; spawn = ["pwvucontrol"]; app-id = "com.saivert.pwvucontrol"; } { name = "kpxc"; exclude = [ { title = "^Unlock Database.*"; } { title = "^Access Request.*"; } { title = ".*Passkey credentials$"; } ]; windowRuleExtra = [ (kdl.leaf "open-focused" false) ]; key = "Mod+Control+P"; app-id = "org.keepassxc.KeePassXC"; spawn = [ "keepassxc" ]; } { name = "bmgr"; key = "Mod+Control+B"; app-id = ".blueman-manager-wrapped"; spawn = [ "blueman-manager" ]; } { name = "term"; key = "Mod+Control+Return"; app-id = "kitty-scratch"; spawn = [ "kitty" "--app-id" "kitty-scratch" ]; } { name = "edit"; match = [ { title = "^scratch$"; app-id = "^emacs$"; } ]; key = "Mod+Control+E"; selector = "select(.app_id == \"emacs\" and .title == \"scratch\")"; spawn = [ "emacsclient" "-c" "--frame-parameters=(quote (name . \"scratch\"))" ]; } { name = "eff"; key = "Mod+Control+O"; app-id = "com.github.wwmm.easyeffects"; spawn = [ "easyeffects" ]; } ]; programs.niri.config = let inherit (kdl) node plain leaf flag; optional-node = cond: v: if cond then v else null; opt-props = lib.filterAttrs (lib.const (value: value != null)); in [ (flag "prefer-no-csd") (plain "hotkey-overlay" [ (flag "skip-at-startup") ]) (plain "input" [ (plain "keyboard" [ (leaf "repeat-delay" 300) (leaf "repeat-rate" 50) (plain "xkb" [ (leaf "layout" "us,us") (leaf "variant" "dvp,") (leaf "options" "compose:caps,grp:win_space_toggle") ]) ]) (flag "workspace-auto-back-and-forth") # (leaf "focus-follows-mouse" {}) # (flag "warp-mouse-to-focus") (plain "touchpad" [ (flag "off") ]) (plain "trackball" [ (leaf "scroll-method" "on-button-down") (leaf "scroll-button" 278) ]) ]) (plain "environment" (lib.mapAttrsToList leaf { NIXOS_OZONE_WL = "1"; QT_QPA_PLATFORM = "wayland"; QT_WAYLAND_DISABLE_WINDOWDECORATION = "1"; GDK_BACKEND = "wayland"; SDL_VIDEODRIVER = "wayland"; DISPLAY = ":0"; })) (node "output" "eDP-1" [ (leaf "scale" 1.5) (leaf "position" { x = 0; y = 0; }) ]) (node "output" "Ancor Communications Inc ASUS PB287Q 0x0000DD9B" [ (leaf "scale" 1.5) (leaf "position" { x = 2560; y = 0; }) ]) (node "output" "HP Inc. HP 727pu CN4417143K" [ (leaf "mode" "2560x1440@120") # 119.998 (leaf "scale" 1) (leaf "position" { x = 2560; y = 0; }) (flag "variable-refresh-rate") ]) (plain "debug" [ (leaf "render-drm-device" "/dev/dri/by-path/pci-0000:00:02.0-render") ]) (plain "animations" [ (leaf "slowdown" 0.5) (plain "workspace-switch" [(flag "off")]) ]) (plain "layout" [ (leaf "gaps" 8) (plain "struts" [ (leaf "left" 0) (leaf "right" 0) (leaf "top" 0) (leaf "bottom" 0) ]) (plain "focus-ring" [ (leaf "width" 2) (leaf "active-gradient" { from = "hsla(195 100% 45% 1)"; to = "hsla(155 100% 37.5% 1)"; angle = 29; relative-to = "workspace-view"; }) (leaf "inactive-gradient" { from = "hsla(0 0% 27.7% 1)"; to = "hsla(0 0% 23% 1)"; angle = 29; relative-to = "workspace-view"; }) ]) (plain "preset-column-widths" (map (prop: leaf "proportion" prop) [ (1. / 4.) (1. / 3.) (1. / 2.) (2. / 3.) (3. / 4.) ])) (plain "default-column-width" [ (leaf "proportion" (1. / 2.)) ]) (plain "preset-window-heights" (map (prop: leaf "proportion" prop) [ (1. / 3.) (1. / 2.) (2. / 3.) (1.) ])) (flag "always-center-single-column") (plain "tab-indicator" [ (leaf "gap" (-6)) (leaf "width" 6) (leaf "length" { total-proportion = 1.; }) (leaf "active-gradient" { from = "hsla(195 100% 60% 0.75)"; to = "hsla(155 100% 50% 0.75)"; angle = 29; relative-to = "workspace-view"; }) (leaf "inactive-gradient" { from = "hsla(0 0% 42% 0.66)"; to = "hsla(0 0% 35% 0.66)"; angle = 29; relative-to = "workspace-view"; }) ]) ]) (plain "cursor" [ (flag "hide-when-typing") ]) (map (name: (node "workspace" name [ (leaf "open-on-output" "eDP-1") ]) ) (map ({name, ...}: name) cfg.scratchspaces)) (map (name: (leaf "workspace" name) ) ["comm" "web" "vid" "bmr"]) (plain "window-rule" [ (leaf "match" { is-floating = true; }) (leaf "geometry-corner-radius" 8) (leaf "clip-to-geometry" true) ]) (plain "window-rule" [ (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; }) (leaf "block-out-from" "screencast") ]) (plain "window-rule" [ (map (title: (leaf "match" { app-id = "^org\\.keepassxc\\.KeePassXC$"; inherit title; }) ) ["^Unlock Database.*" "^Access Request.*" ".*Passkey credentials$"]) (leaf "open-focused" true) (leaf "open-floating" true) ]) (map ({ name, match, exclude, windowRuleExtra, ... }: (optional-node (match != []) (plain "window-rule" [ (map (leaf "match") match) (map (leaf "exclude") exclude) (leaf "open-on-workspace" name) (leaf "open-maximized" true) windowRuleExtra ])) ) cfg.scratchspaces) (plain "window-rule" [ (leaf "match" { app-id = "^emacs$"; }) (leaf "match" { app-id = "^firefox$"; }) (plain "default-column-width" [(leaf "proportion" (2. / 3.))]) ]) (plain "window-rule" [ (leaf "match" { app-id = "^kitty$"; }) (leaf "match" { app-id = "^kitty-play$"; }) (plain "default-column-width" [(leaf "proportion" (1. / 3.))]) ]) (plain "window-rule" [ (leaf "match" { app-id = "^thunderbird$"; }) (leaf "match" { app-id = "^Element$"; }) (leaf "match" { app-id = "^Rainbow$"; }) (leaf "open-on-workspace" "comm") ]) (plain "window-rule" [ (leaf "match" { app-id = "^firefox$"; }) (leaf "open-on-workspace" "web") (leaf "open-maximized" true) ]) (plain "window-rule" [ (leaf "match" { app-id = "^mpv$"; }) (leaf "open-on-workspace" "vid") (plain "default-column-width" [(leaf "proportion" 1.)]) ]) (plain "window-rule" [ (leaf "match" { app-id = "^kitty-play$"; }) (leaf "open-on-workspace" "vid") (leaf "open-focused" false) ]) (plain "window-rule" [ (leaf "match" { app-id = "^pdfpc$"; }) (plain "default-column-width" [(leaf "proportion" 1.)]) ]) (plain "window-rule" [ (leaf "match" { app-id = "^pdfpc$"; title = "^pdfpc - presentation$"; }) (plain "default-column-width" [(leaf "proportion" 1.)]) (leaf "open-fullscreen" true) (leaf "open-on-workspace" "bmr") (leaf "open-focused" false) ]) (plain "window-rule" [ (map (leaf "match") [ { app-id = "^Gimp-"; title = "^Quit GIMP$"; } { app-id = "^org\\.kde\\.polkit-kde-authentication-agent-1$"; } { app-id = "^xdg-desktop-portal-gtk$"; } ]) (leaf "open-floating" true) ]) (plain "layer-rule" [ (leaf "match" { namespace = "^notifications$"; }) (leaf "match" { namespace = "^waybar$"; }) (leaf "match" { namespace = "^launcher$"; }) (leaf "block-out-from" "screencast") ]) (plain "binds" (let bind = name: cfg: node name (opt-props { cooldown-ms = cfg.cooldown-ms or null; } // (lib.optionalAttrs (!(cfg.repeat or true)) { repeat = false; }) // (lib.optionalAttrs (cfg.allow-when-locked or false) { allow-when-locked = true; })) (lib.mapAttrsToList leaf (lib.removeAttrs cfg.action ["__functor"])); in [ (lib.mapAttrsToList bind (with config.lib.niri.actions; { "Mod+Slash".action = show-hotkey-overlay; "Mod+Return".action = spawn terminal; "Mod+Q".action = close-window; "Mod+O".action = spawn (lib.getExe config.programs.fuzzel.package); "Mod+Shift+O".action = spawn (lib.getExe config.programs.fuzzel.package) "--list-executables-in-path"; "Mod+Alt+E".action = spawn (lib.getExe' config.services.emacs.package "emacsclient") "-c"; "Mod+Alt+Y".action = spawn (lib.getExe (pkgs.writeShellApplication { name = "queue-yt-dlp"; runtimeInputs = with pkgs; [ wl-clipboard-rs socat ]; text = '' socat STDIO UNIX-CONNECT:"$XDG_RUNTIME_DIR"/yt-dlp.sock <<<$'{ "urls": ["'"$(wl-paste)"$'"] }' ''; })); "Mod+Alt+L".action = spawn (lib.getExe (pkgs.writeShellApplication { name = "queue-yt-dlp"; runtimeInputs = with pkgs; [ wl-clipboard-rs config.programs.kitty.package ]; text = '' exec -- kitty --app-id kitty-play --directory "$HOME"/media mpv "$(wl-paste)" ''; })); "Mod+U".action = spawn (lib.getExe (pkgs.writeShellApplication { name = "qalc-fuzzel"; runtimeInputs = with pkgs; [ wl-clipboard-rs libqalculate config.programs.fuzzel.package coreutils findutils libnotify gnugrep ]; text = '' RESULTS_DIR="$HOME/.cache/qalc-fuzzel" prev() { FOUND=false while IFS= read -r line; do [[ -n "$line" ]] || continue FOUND=true echo "$line" 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) $FOUND || echo } FUZZEL_RES=$(prev | fuzzel --dmenu --prompt "qalc> ") || exit $? if [[ "$FUZZEL_RES" =~ .*\ =\ .* ]]; then QALC_RES="$FUZZEL_RES" QALC_RET=0 else QALC_RES=$(qalc "$FUZZEL_RES" 2>&1) QALC_RET=$? fi [[ -n "$QALC_RES" ]] || exit 1 EXISTING=false set +o pipefail grep -Fxrl "$QALC_RES" "$RESULTS_DIR" | xargs -r touch [[ ''${PIPESTATUS[0]} -eq 0 ]] && EXISTING=true set -o pipefail if [[ $QALC_RET -eq 0 ]] && ! $EXISTING; then set +o pipefail RES_FILE="$RESULTS_DIR"/$(date -uIs).$(tr -Cd 'a-zA-Z0-9' "$RES_FILE" <<<"$QALC_RES" fi [[ "$QALC_RES" =~ .*\ =\ (.*) ]] && QALC_RES="''${BASH_REMATCH[1]}" [[ $QALC_RET -eq 0 ]] && wl-copy "$QALC_RES" notify-send "$QALC_RES" ''; })); "Mod+E".action = spawn (lib.getExe (pkgs.writeShellApplication { name = "emoji-fuzzel"; runtimeInputs = with pkgs; [ config.programs.fuzzel.package wtype wl-clipboard-rs ]; text = '' FUZZEL_RES=$(fuzzel --dmenu --prompt "emoji> " <"$HOME"/.local/share/emoji-data/list.txt) || exit $? [[ -n "$FUZZEL_RES" ]] || exit 1 wl-copy "$(cut -d ':' -f 1 <<<"$FUZZEL_RES" | tr -d '\n')" && wtype -k XF86Paste ''; })); "Print".action = spawn (lib.getExe (pkgs.writeShellApplication { name = "screenshot"; runtimeInputs = with pkgs; [ grim slurp wl-clipboard-rs coreutils ]; text = '' grim -g "$(slurp -b 00000080 -c FFFFFFFF -s 00000000 -w 1)" - \ | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \ | wl-copy --type image/png ''; })); "Shift+Print".action = spawn (lib.getExe (pkgs.writeShellApplication { name = "screenshot"; runtimeInputs = with pkgs; [ grim niri gojq wl-clipboard-rs coreutils ]; text = '' grim -o "$(niri msg -j workspaces | jq -r '.[] | select(.is_focused) | .output')" - \ | tee "$HOME/screenshots/$(date +"%Y-%m-%dT%H:%M:%S").png" \ | wl-copy --type image/png ''; })); "Mod+B".action = with-select-window-action ".workspace_id == ($active_workspace | tonumber)" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; "Mod+Shift+B".action = with-select-window-action "true" "{\"Action\":{\"FocusWindow\":{\"id\": .id}}}"; "Mod+H".action = focus-column-left; "Mod+T".action = focus-window-down; "Mod+N".action = focus-window-up; "Mod+S".action = focus-column-right; "Mod+Shift+H".action = move-column-left; "Mod+Shift+T".action = move-window-down; "Mod+Shift+N".action = move-window-up; "Mod+Shift+S".action = move-column-right; "Mod+Control+H".action = focus-monitor-left; "Mod+Control+T".action = focus-monitor-down; "Mod+Control+N".action = focus-monitor-up; "Mod+Control+S".action = focus-monitor-right; "Mod+Shift+Control+H".action = move-workspace-to-monitor-left; "Mod+Shift+Control+T".action = move-workspace-to-monitor-down; "Mod+Shift+Control+N".action = move-workspace-to-monitor-up; "Mod+Shift+Control+S".action = move-workspace-to-monitor-right; "Mod+G".action = focus-adjacent-workspace "down"; "Mod+C".action = focus-adjacent-workspace "up"; "Mod+Shift+G".action = move-column-to-adjacent-workspace "down"; "Mod+Shift+C".action = move-column-to-adjacent-workspace "up"; "Mod+Shift+Control+G".action = move-workspace-down; "Mod+Shift+Control+C".action = move-workspace-up; "Mod+ParenLeft".action = focus-workspace "comm"; "Mod+Shift+ParenLeft".action = move-column-to-workspace "comm"; "Mod+ParenRight".action = focus-workspace "web"; "Mod+Shift+ParenRight".action = move-column-to-workspace "web"; "Mod+BraceRight".action = focus-workspace "read"; "Mod+Shift+BraceRight".action = move-column-to-workspace "read"; "Mod+BraceLeft".action = focus-workspace "mon"; "Mod+Shift+BraceLeft".action = move-column-to-workspace "mon"; "Mod+Asterisk".action = focus-workspace "vid"; "Mod+Shift+Asterisk".action = move-column-to-workspace "vid"; "Mod+Plus".action = with-unnamed-workspace-action ''{"Action":{"FocusWorkspace":{"reference":{"Id": .id}}}}''; "Mod+Shift+Plus".action = with-unnamed-workspace-action ''{"Action":{"MoveColumnToWorkspace":{"reference":{"Id": .id}}}}''; "Mod+M".action = consume-or-expel-window-left; "Mod+W".action = consume-or-expel-window-right; "Mod+Shift+M".action = toggle-column-tabbed-display; "Mod+R".action = switch-preset-column-width; "Mod+Shift+R".action = switch-preset-window-height; "Mod+F".action = center-column; "Mod+Shift+F".action = maximize-column; "Mod+Shift+Ctrl+F".action = fullscreen-window; "Mod+V".action = switch-focus-between-floating-and-tiling; "Mod+Shift+V".action = toggle-window-floating; "Mod+Left".action = set-column-width "-10%"; "Mod+Down".action = set-window-height "-10%"; "Mod+Up".action = set-window-height "+10%"; "Mod+Right".action = set-column-width "+10%"; "Mod+Shift+Z" = { action = spawn (lib.getExe niri) "msg" "action" "power-off-monitors"; allow-when-locked = true; }; "Mod+Shift+L".action = spawn loginctl "lock-session"; "Mod+Shift+E".action = quit; "Mod+Shift+Minus" = { action = spawn systemctl "suspend"; allow-when-locked = true; }; "Mod+Shift+Control+Minus" = { action = spawn systemctl "hibernate"; allow-when-locked = true; }; "Mod+Shift+P" = { action = spawn (lib.getExe pkgs.playerctl) "-a" "pause"; allow-when-locked = true; }; "XF86MonBrightnessUp" = { action = spawn swayosd-client "--brightness" "raise"; allow-when-locked = true; }; "XF86MonBrightnessDown" = { action = spawn swayosd-client "--brightness" "lower"; allow-when-locked = true; }; "XF86AudioRaiseVolume" = { action = spawn swayosd-client "--output-volume" "raise"; allow-when-locked = true; }; "XF86AudioLowerVolume" = { action = spawn swayosd-client "--output-volume" "lower"; allow-when-locked = true; }; "XF86AudioMute" = { action = spawn swayosd-client "--output-volume" "mute-toggle"; allow-when-locked = true; }; "XF86AudioMicMute" = { action = spawn swayosd-client "--input-volume" "mute-toggle"; allow-when-locked = true; }; "Mod+Semicolon".action = spawn makoctl "dismiss" "--group"; "Mod+Shift+Semicolon".action = spawn makoctl "dismiss" "--all"; "Mod+Period".action = spawn makoctl "menu" (lib.getExe config.programs.fuzzel.package) "--dmenu"; "Mod+Comma".action = spawn makoctl "restore"; })) (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) ] )) ]; }; }