#!/usr/bin/env bash # # DESCRIPTION: # convenience queries into the sway container tree # swtree() { swaymsg -t get_tree } has_appid() { swtree | jq "[ .. | (select(.app_id?) | select(.app_id | test(\"$1\"))) // (select(.window_properties?.class?) | select(.window_properties.class | test(\"$1\"))) ]" } has_pid() { q='' IFS=$' ' for pid in $1; do if [[ -n $q ]]; then q=".pid?==$pid or $q" else q=".pid?==$pid" fi done swtree | jq "[ .. | select($q) ]" } has_exe() { pid_of_win="$(pgrep -x "$1" -d' ')" if [[ -z "$pid_of_win" ]]; then echo "process not found" >&2 exit 1 fi ppid_of_proc="$(ps -q "$(echo "$pid_of_win" | tr ' ' ',')" -o ppid= | tr -d ' ' | tr '\n' ',' | sed 's/,$//')" if [[ -z "$ppid_of_proc" ]]; then echo "parent process not found" >&2 fi IFS=$'\n' for comm in $(ps -q "$ppid_of_proc" -o pid=,comm=); do if [[ "$comm" =~ ^.*sh$ ]]; then # parent process is a shell # need to get parent process of shell (the terminal emulator) pid_of_win="$pid_of_win $(ps -p "$(echo "$comm" | awk '{print $1}')" -o ppid= | tr -d ' ')" fi done if [[ -z "$pid_of_win" ]]; then echo "process not found" >&2 exit 1 fi has_pid "$pid_of_win" } has_ws() { swtree | jq --arg name "$1" '[ .. | select(.type?=="workspace" and .name?==$name) ]' } has_id() { swtree | jq --argjson arg "{\"id\":$1}" '[ .. | select(.id?==$arg.id) ]' } locate_output_for_con() { swtree | jq --argjson arg "{\"con_id\":$1}" '[ .. | select(.type?=="output") as $o | .. | select(.id?==$arg.con_id) | $o ]' } latest() { swtree | jq --arg type "$1" '[ .. | select(.type? and (.type|test($type))) ] | max_by(.id)' } list() { swtree | jq --arg type "$1" '[ .. | select(.type? and (.type|test($type))) ]' } moveto() { if [ ! -t 0 ]; then read -r -i -e conId sway [con_id="$conId"] move to workspace "$1" else sway [app_id="$1"] move to workspace "$2" fi } case "$1" in has) shift case "$1" in appid) has_appid "$2" ;; pid) has_pid "$2" ;; exe) has_exe "$2" ;; ws) has_ws "$2" ;; id) has_id "$2" ;; *) printf 'usage: swq has COMMAND \n' printf '\nCOMMANDS:\n' printf ' appid: returns json of the window filtered by app_id/class (fuzzy matching)\n' printf ' pid: returns json of the window filtered by pid\n' printf ' exe: returns json of the window filtered by process name\n' printf ' ws: returns json of the window filtered by workspace\n' printf ' id: returns json of the window filtered by id\n' printf '\n' exit 2 ;; esac ;; locate) shift case "$1" in output-for-con) locate_output_for_con "$2" ;; *) printf 'usage: swq locate COMMAND \n' printf '\nCOMMANDS:\n' printf ' output-for-con: returns output containing con_id\n' printf '\n' exit 2 ;; esac ;; latest) shift case "$1" in workspace | ws) latest workspace ;; container | con) latest con ;; output) latest output ;; *) printf 'usage: swq latest \n\n' exit 2 ;; esac ;; list | ls) shift [ -n "$1" ] || { echo "usage: swq list " exit 1 } [ "$1" == "ws" ] && list workspace list "$1" ;; current | cur) shift case "$1" in window) _current con ;; con) swtree | jq '.. | select((.type? | test("con")?) and .focused?)' ;; ws) _current workspace ;; workspace) swtree | jq '.. | select(.type?=="workspace") | . as $parent | .. | select(.focused?==true) | $parent' ;; output) $0 current workspace | jq -r '.output' ;; output-full) $0 list output | jq ".[] | select((.type?==\"output\") and (.name?==\"$($0 current output)\"))" ;; *) printf 'usage: swq current \n\n' exit 2 ;; esac ;; pick) shift pos=$(slurp -p -f '{"x":%x,"y":%y}') case "${1:-con}" in con) swtree | jq --argjson p "$pos" '[.. | select((.type? | test("con")?) and .visible?==true and ($p.x >= .rect.x and $p.x <= (.rect.x + .rect.width)) and ($p.y >= .rect.y and $p.y <= (.rect.y + .rect.height)))]' ;; *) printf 'usage: swq pick \n\n' exit 2 ;; esac ;; geometry) shift first_or_last=${1:-last} jq -r "[..|select(.type? and (.type|test(\"con\")))]|${first_or_last}|.rect|[([.x,.y]|join(\",\")),([.width,.height]|join(\"x\"))]|join(\" \")" ;; focus) shift first_or_last=${1:-last} jq -r "[..|select(.type? and (.type|test(\"con\")))]|${first_or_last}|.id" | xargs -I{} sway [con_id={}] focus ;; moveto) shift moveto $@ ;; -h | --help | help) printf 'usage: swq COMMAND\n' printf '\n' printf 'QUERY COMMANDS:\n' printf ' has: get object by criteria\n' printf ' latest: get newest objects\n' printf ' list: list objects\n' printf ' current: get focused objects\n' printf ' pick: use slurp to identify\n' printf '\n' printf 'ACTION COMMANDS:\n' printf ' focus: focus a container (takes stdin)\n' printf ' moveto : move container with to \n' printf ' geometry: print slurp-like `%%x,%%y %%w,%%h` expression (takes stdin)\n' printf '\n' exit 2 ;; *) swtree ;; esac