#!/bin/sh # # DESCRIPTION: # wrapper for `swaymsg exec` with many useful additions # set -e [ -n "$DEBUG" ] && set -x # check requirements for app in swaymsg jq swq centercon; do if ! command -v "$app" >/dev/null; then printf "%s: %s not install but required" "$0" "$app" >&2 exit 1 fi done patience= border= wspace= output= geometry= termify= rotate= sticky= floating= autotile= into_scratchpad= mark= term_title= while getopts b:w:o:g:I:r:stfF:aSM:T:h name; do case "$name" in b) # border border="${OPTARG}" ;; w) # move to workspace wspace="${OPTARG}" ;; o) # move to output output="${OPTARG}" ;; g) # geometry geometry="${OPTARG}" ;; t) # termify termify=1 ;; r) # rotate if ! command -v cage >/dev/null; then printf "%s: cage not installed but required to rotate containers" "$0" >&2 exit 1 fi rotate="${OPTARG}" ;; s) # set container to sticky sticky=1 ;; f) # set container to float floating=1 ;; F) floating="${OPTARG}" ;; a) # auto-tiling enabled autotile=1 ;; S) # launch into scratchpad into_scratchpad=1 ;; M) # mark mark="${OPTARG}" ;; T) # set terminal title term_title="${OPTARG}" ;; h|?) printf "usage: %s [-bwogIrsfoSMT] COMMAND\n" "$(basename "$0")" printf "\n" printf " -t \t\trun COMMAND in \$TERM\n" printf " -b BORDER \tset border property\n" printf " -w WORKSPACE \tmove to workspace\n" printf " -o OUTPUT \tmove to output\n" printf " -g GEOMETRY \tresize/position window\n" printf " -r ROTATION \trotate the container, requires cage(1)\n" printf " -s \t\tmake COMMAND a sticky window, appearing on all workspaces\n" printf " -f \t\tmake COMMAND a floating window\n" printf " -F OPTIONS\tmake COMMAND a floating window\n\t\tsee centercon(1) for possible options\n" printf " -a \t\tauto-tiling; always open COMMAND on the shorter edge of\n\t\tthe current container\n" printf " -S \t\tmove the container into the scratchpad\n" printf " -M MARK\t\set MARK on the container\n" printf " -T TERM_TITLE\t\set a title on the terminal (only makes sense with -t)\n" printf "\n" printf "See sway(5) for possible options for BORDER, WORKSPACE, OUTPUT and GEOMETRY.\n" exit 2 ;; esac # block until we have a con_id matching on pid of the spawned process patience=1 done shift $((OPTIND - 1)) arg0=$(basename "$1") if [ -z "${arg0}" ]; then exec "$0" -h fi shift command="${arg0} ${*}" # needs to be termified? # spawn a $TERM instance and exec that if [ -n "${termify}" ]; then case ${TERM:-foot} in alacritty) term_args="--title=${term_title:-${arg0}} --class=${term_title:-${arg0}} --command" ;; foot) term_args="--title=${term_title:-${arg0}} --app-id=${term_title:-${arg0}} --" ;; *) term_args="" ;; esac command="${TERM} ${term_args} ${command}" fi # needs to be rotated # spawn a cage(1) instance and exec that, takes previous $command if [ -n "${rotate}" ]; then # figure out how many "-r" flags we need rotate_args="" while [ $(( (rotate / 90) >= 1 )) = 1 ]; do rotate_args="${rotate_args} -r" rotate=$((rotate - 90)) done # allow for the firefox workaround that spawns a kiosk window # under firejail (to avoid profile folder issues) if echo "$command" | grep -E 'firefox'; then # command="firejail --overlay-tmpfs --profile=firefox ${command} --no-remote --kiosk" command="firefox-kiosk ${command}" fi command="cage -d ${rotate_args} -- \"${command}\"" fi if [ -n "${autotile}" ]; then layout=$(swq current con | jq -r '.layout') # layout=$(swq current workspace | jq -r '.. | select(.type?=="con" and .name?==null) | .layout') # notify-send swx "${layout}" case "${layout}" in split*) if [ "$(swq current con | jq '.rect | .width > .height')" = "true" ]; then swaymsg splith else swaymsg splitv fi ;; esac fi swaymsg exec -- "${command}" >/dev/null [ $? ] || { printf "error: failed to spawn \"${command}\"\n"; exit 1; } [ -z "$patience" ] && exit 0 # waiting for container to appear con_id="$(swaymsg -t subscribe '["window"]' | jq -s '.[]|select(.change=="new")|.container.id')" sway_props_done= while [ -z "${sway_props_done}" ]; do if [ -n "${floating}" ]; then swaymsg -- [con_id="${con_id}"] floating enable [ "${floating}" = "1" ] || centercon -w ${floating} fi if [ -n "${into_scratchpad}" ]; then swaymsg -- [con_id="${con_id}"] move to scratchpad fi if [ -n "${mark}" ]; then swaymsg -- [con_id="${con_id}"] mark --add "${mark}" fi if [ -n "${geometry}" ]; then swaymsg -- [con_id="${con_id}"] floating enable wh=$(printf "%s" "${geometry}" | cut -d' ' -f2) swaymsg -- [con_id="${con_id}"] resize set \ width "$(printf "%s" "${wh}" | cut -d'x' -f1)" px \ height "$(printf "%s" "${wh}" | cut -d'x' -f2)" px xy=$(printf "%s" "${geometry}" | cut -d' ' -f1) swaymsg -- [con_id="${con_id}"] move absolute position \ "$(printf "%s" "${xy}" | cut -d',' -f1)" px \ "$(printf "%s" "${xy}" | cut -d',' -f2)" px fi if [ -n "${output}" ]; then swaymsg -- [con_id="${con_id}"] move output "${output}" fi if [ -n "${wspace}" ]; then swaymsg -- [con_id="${con_id}"] move workspace "${wspace}" fi if [ -n "${sticky}" ]; then swaymsg -- [con_id="${con_id}"] sticky enable fi if [ -n "${border}" ]; then swaymsg -- [con_id="${con_id}"] border "${border}" fi sway_props_done=1 done >/dev/null