···8383 ]
8484 );
85858686+ # Mark a window and jump to it later, per slot. mod+ctrl+<digit> marks
8787+ # the focused window (by container id) into that slot. mod+<digit> jumps
8888+ # to the marked window: if its workspace is hidden it is moved to the
8989+ # current screen, if it is shown on another screen focus switches there.
9090+ # mod+shift+<digit> always brings the marked window's workspace to the
9191+ # current screen. A stale mark (window closed) is dropped with a note.
9292+ windowMark = pkgs.writeShellApplication {
9393+ name = "sway-window-mark";
9494+ runtimeInputs = [
9595+ pkgs.sway
9696+ pkgs.jq
9797+ pkgs.coreutils
9898+ pkgs.libnotify
9999+ ];
100100+ text = ''
101101+ MARKS="$HOME/.config/sway-window-marks"
102102+ mkdir -p "$MARKS"
103103+104104+ if [ "$1" = "mark" ]; then
105105+ SLOT="$2"
106106+ INFO=$(swaymsg -r -t get_tree | jq -r '
107107+ [ .. | objects | select(.type == "con" and .focused == true) ]
108108+ | .[0] // empty
109109+ | [ .id, (.name // "unknown") ] | @tsv')
110110+ if [ -z "$INFO" ]; then
111111+ notify-send "Window" "no window focused" 2>/dev/null
112112+ exit 0
113113+ fi
114114+ IFS=$'\t' read -r ID NAME <<< "$INFO"
115115+ echo "$ID" > "$MARKS/$SLOT"
116116+ notify-send "Window" "slot $SLOT: $NAME" 2>/dev/null
117117+ exit 0
118118+ fi
119119+120120+ SLOT="$1"
121121+ ID=$(cat "$MARKS/$SLOT" 2>/dev/null || true)
122122+ if [ -z "$ID" ]; then
123123+ notify-send "Window" "no window in slot $SLOT" 2>/dev/null
124124+ exit 0
125125+ fi
126126+127127+ # Workspace that currently contains the marked window (empty if it died).
128128+ WS=$(swaymsg -r -t get_tree | jq -r --argjson id "$ID" '
129129+ . as $t
130130+ | [ path(.. | objects | select(.id == $id)) ] | .[0] as $p
131131+ | if $p == null then empty
132132+ else [ range(1; ($p | length) + 1) as $i
133133+ | $t | getpath($p[0:$i])
134134+ | objects | select(.type == "workspace") | .name
135135+ ] | .[0] // empty
136136+ end')
137137+ if [ -z "$WS" ]; then
138138+ rm -f "$MARKS/$SLOT"
139139+ notify-send "Window" "slot $SLOT: marked window is gone" 2>/dev/null
140140+ exit 0
141141+ fi
142142+143143+ # Screen the user is typing on, captured BEFORE the switch: switching
144144+ # a workspace moves seat focus to the target's output, so the
145145+ # focused output after the switch would be the wrong answer.
146146+ CUR=$(swaymsg -r -t get_outputs | jq -r '.[] | select(.focused == true) | .name')
147147+ # Shown on any output? A plain jump only brings the workspace when
148148+ # it is hidden; "bring" always moves it here.
149149+ SHOWN=$(swaymsg -r -t get_workspaces | jq -r --arg ws "$WS" '[.[] | select(.name == $ws) | .visible] | any')
150150+ MOVE=false
151151+ if [ $# -gt 1 ] && [ "$2" = "bring" ]; then
152152+ MOVE=true
153153+ elif [ "$SHOWN" != "true" ]; then
154154+ MOVE=true
155155+ fi
156156+ swaymsg workspace "$WS"
157157+ # Sway 1.12: nameless "move workspace to output <out>" moves the
158158+ # focused (just-switched) workspace. A named first argument is
159159+ # parsed as a container move to a workspace literally named
160160+ # "<ws> to output <out>".
161161+ if [ "$MOVE" = "true" ]; then
162162+ swaymsg move workspace to output "$CUR"
163163+ fi
164164+ swaymsg "[con_id=$ID] focus"
165165+ '';
166166+ };
167167+168168+ # mod+<digit> = jump to window slot, mod+shift+<digit> = bring its
169169+ # workspace here, mod+ctrl+<digit> = mark focused window into slot.
170170+ windowBindings = lib.concatStringsSep "\n" (
171171+ lib.map
172172+ (n: ''
173173+ bindsym $mod+${toString n} exec ${lib.getExe windowMark} ${toString n}
174174+ bindsym $mod+shift+${toString n} exec ${lib.getExe windowMark} ${toString n} bring
175175+ bindsym $mod+ctrl+${toString n} exec ${lib.getExe windowMark} mark ${toString n}
176176+ '')
177177+ [
178178+ 1
179179+ 2
180180+ 3
181181+ 4
182182+ 5
183183+ 6
184184+ 7
185185+ 8
186186+ 9
187187+ ]
188188+ );
189189+86190in
87191{
88192 # Make goto-workspace available system-wide for workspace switching
···425529 # secondary, ...), mod+ctrl+F<n> marks the current screen as the target.
426530 # While a mark exists, any mod+F<n> jumps to the marked screen.
427531 ${screenBindings}
532532+533533+ # Window marks: mod+<digit> jumps to the window marked into that slot,
534534+ # mod+shift+<digit> brings its workspace to the current screen,
535535+ # mod+ctrl+<digit> marks the focused window into that slot.
536536+ ${windowBindings}
428537429538 # screenlock (random live video/image from ~/wallpaper via swaylock-plugin)
430539 bindsym $mod+F11 exec ${lib.getExe' pkgs.systemd "systemctl"} --user start lock.target