Skip to content

Instantly share code, notes, and snippets.

@lbonn
Created April 22, 2020 10:55
Show Gist options
  • Save lbonn/89d064cde963cfbacabd77e0d3801398 to your computer and use it in GitHub Desktop.
Save lbonn/89d064cde963cfbacabd77e0d3801398 to your computer and use it in GitHub Desktop.
Window switcher for sway ('rofi -show window' clone)
#!/usr/bin/env bash
set -euo pipefail
tree=$(swaymsg -t get_tree)
readarray -t win_ids <<< "$(jq -r '.. | objects | select(has("app_id")) | .id' <<< "$tree")"
readarray -t win_names <<< "$(jq -r '.. | objects | select(has("app_id")) | .name' <<< "$tree")"
readarray -t win_types <<< "$(jq -r '.. | objects | select(has("app_id")) | .app_id // .window_properties.class' <<< "$tree")"
switch () {
local k
read -r k
swaymsg "[con_id=${win_ids[$k]}] focus"
}
for k in $(seq 0 $((${#win_ids[@]} - 1))); do
echo -e "<span weight=\"bold\">${win_types[$k]}</span> - ${win_names[$k]}"
done | rofi -dmenu -markup-rows -i -p window -format i | switch
@breno-ca
Copy link

breno-ca commented Jan 2, 2025

Great work, everyone! I've tested the solutions above. Since I use fuzzel, I came up with this approach to address the issue with icons and XWayland apps that don't have an app_id.

# Parse the Sway tree to generate a formatted list of windows for fuzzel.
selected_window=$( swaymsg -t get_tree | jq -r '
	..
	# Get workspaces and customize workspace names
	| objects | select(.type == "workspace") as $workspace
	| ( if $workspace.name == "__i3_scratch" 
		then "-" else $workspace.name end 
	  ) as $ws_name 

        | ..
	# Get opened apps and set "focused" decoration
        | objects | select(has("app_id"))
	| (if .focused == true then "🟢" else "" end) as $selected

	# Exclude apps from list
	| select(.app_id == null or (.app_id | test("pavucontrol") | not))
	
	# Manually set icons to fix cases where they are not displayed
	| ( "vivaldi-pjibgclleladliembfgfagdaldikeohf-Default" ) as $spotify
	| ( if .name != null and (.name | test("Spotify")) then $spotify
		elif .app_id == "Firefox" then "firefox" 
		else .app_id // .window_properties.class // .name end
	  ) as $icon
	
	# Fix for displaying app_id when it is null
	| ( if .app_id == null and (.name | test("Spotify")) then "Spotify" 
		else .name end 
	  ) as $app_id

	# Set dmenu item format (keep the icon separated from the rest)
	# Output ex: 📂 (101) [1] 🟢File Explorer 
	| "(\(.id)) [\($ws_name)] \($selected)\($app_id)" +
	  "\u0000icon\u001f\($icon)"' \
	| fuzzel -d -w 50
)

# Focus the selected window.
if [ "$selected_window" != "" ]; then
	window_id=$(echo "$selected_window" | sed 's/.*(\([[:digit:]]*\)).*/\1/')
	swaymsg [con_id="$window_id"] focus
fi

I've also tried to improve the readability by adding comments to make the code easier to understand. Additionally, I published this version in my repository (sway-util-scripts/window_switcher.sh), referencing this gist and some other links I found online.

Cheers from Brazil!🇧🇷

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment