123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- #!/bin/bash
- me="$(basename "$0")"
- ##########################################################################
- # USER CONFIGURATION
- # please fill this space-separated array to your liking.
- # each word stands for an application's class or classname that will be
- # searched for, case insensitively, in xwininfo's output.
- # please check with:
- # xprop | grep -E '^WM_CLASS'
- # or
- # xwininfo -root -tree | grep -iE '(.*myapp.*)' where myapp is one
- # of the words to be added.
- excludeapps=( tint2 conky xfce4-panel glava )
- # array of commands (or functions) to execute before cycling through all windows
- executes=( borgbackup-off transmission-off "audtool --mainwin-show off" amule-off )
- # if this string is non-empty it denotes a filename to store debug info in.
- #~ debug_log="$HOME/${me}.$(date +%s).debug"
- debug_log=""
- ###########################################################################
- #~ identifier=$(date +%s)
- #~ identifier="urxvt${identifier%??}"
- # the close-all-windows-wrapper is using this same identifier as window class.
- #~ excludeapps_winid[j]="$(echo "ibase=10;obase=16;$WINDOWID"|bc)" # the window we're currently in
- # window id to hex. variations:
- # - xwininfo seems to not use leading zeroes, but a leading 0x
- # - wmctrl seems to always pad to 8 digits + a leading 0x
- #~ self="$(printf "0x%08x" "$WINDOWID")"
- ############################################################################
- # FUNCTIONS
- debug() {
- [ -w "$debug_log" ] && echo -e "$@" >> "$debug_log"
- }
- amule-off() {
- while pidof -x amule >/dev/null 2>&1; do
- echo "Waiting for amule to shut down"
- sleep 1
- done
- }
- transmission-off() {
- if pidof transmission-daemon >/dev/null 2>&1; then
- read -n1 -p "Do you want to close transmission-daemon [Y/n]? " answer
- [[ "$answer" =~ [Nn] ]] && return
- transmission-remote --authenv --exit
- echo "Waiting for transmission-daemon to shut down"
- while pidof transmission-daemon >/dev/null 2>&1; do
- sleep 0.1
- echo -n "."
- done
- echo " Success!"
- fi
- }
- borgbackup-off(){
- borgdelay=10
- if pidof -x borgbackup.sh >/dev/null 2>&1; then
- echo "Cannot exit while borgbackup.sh is running!"
- while pidof -x borgbackup.sh >/dev/null 2>&1; do
- echo "Checking again in $borgdelay seconds."
- sleep $borgdelay
- done
- while pidof -x borgbackup.sh >/dev/null 2>&1; do
- echo "Checking again in $borgdelay seconds."
- sleep $borgdelay
- done
- echo "Finished!"
- # Because the above might've taken a very long time,
- # wiggle the mouse to disable screensaver:
- xdotool mousemove_relative --sync -p 0 100; sleep 0.1; xdotool mousemove_relative --sync -p 180 100
- fi
- }
- ############################################################################
- # MAIN
- # simple dependency check
- for dep in grep xwininfo wmctrl; do
- type -f $dep >/dev/null || exit 1
- done
- sep="$(stty size)"
- sep="${sep#* }"
- ((sep > 10 )) && sep="$(for (( ; sep > 0 ; sep-- )); do printf "-"; done)" || sep="----------"
- echo "Gracefully closing all windows."
- debug "Debugging $me on $(date)\n$sep\n$(wmctrl -m 2>&1)\n$sep$(wmctrl -l 2>&1)\n$sep\n$(wmctrl -d 2>&1)\n$sep"
- for cmd in "${executes[@]}"; do
- echo -e "$sep\nExecuting: $cmd"
- $cmd
- done
- excludeapps_winid=()
- for (( i=0,j=0 ; i<${#excludeapps[@]} ; i++ ))
- do
- debug "checking for app $i - ${excludeapps[i]}:"
- while read excludeapps_winid[j]
- do
- debug "Matching output line $j - ${excludeapps_winid[j]}"
- if [[ "x${excludeapps_winid[j]}" != "x" ]]
- then
- debug "Is on the list of excludeapps."
- excludeapps_winid[j]="${excludeapps_winid[j]%% *}"
- debug "Exclude app $j: ${excludeapps_winid[j]}"
- j=$((j + 1))
- else
- debug "Got an empty string :-("
- fi
- done <<< "$(xwininfo -root -tree -int | grep -i "(.*${excludeapps[i]}.*)")"
- # dump all window info, with IDs in decimal, and grep for classes/names,
- # in brackets like: ("urxvt" "URxvt")
- done
- # Add this window to the array of excluded apps
- # WINDOWID uses the same decimal format, just append it to the array
- excludeapps_winid=( ${excludeapps_winid[@]} $WINDOWID )
- echo "$sep
- List of classes/names to exclude: \"${excludeapps[@]}\" and self.
- $sep
- Window IDs to exclude: ${excludeapps_winid[@]}"
- debug "$sep\nMatching 'wmctrl -l' output against excludeapps winids:"
- while read -r line
- do
- debug "$sep\nLine $i - $line"
- for (( i=0 ; i<${#excludeapps_winid[@]} ; i++ ))
- do
- excludeapps_winid[i]="0x$(printf '%08x' ${excludeapps_winid[i]})"
- debug "${line%% *} = ${excludeapps_winid[i]} - are they the same?"
- if [[ "${line%% *}" == "${excludeapps_winid[i]}" ]]
- then
- debug "Yes they are! Skipping!"
- line=''
- break
- else
- debug "No they aren't."
- fi
- done
- if [[ "x$line" != "x" ]]
- then
- echo -e "$sep\nClosing: ${line/$HOSTNAME/}"
- # go to the desktop in question...
- wmctrl -s "${line:10:3}"
- # ...and close:
- wmctrl -ic "${line%% *}"
- # checking if it's really closed now:
- if wmctrl -l | grep -E "^${line%% *}" >/dev/null 2>&1
- then
- debug "${line%% *} hasn't shut down yet. waiting..."
- # wait, presumably for user action:
- echo -n "Waiting . "
- while wmctrl -l | grep -E "^${line%% *}" >/dev/null 2>&1
- do
- sleep 0.1; echo -n '.'
- done
- echo
- debug "${line%% *} has finally shut down!"
- fi
- fi
- done <<< "$(wmctrl -l)"
- debug "$sep\nComing back to $me - winid $WINDOWID"
- wmctrl -ia "0x$(printf '%08x' $WINDOWID)" >/dev/null 2>&1
- debug "$sep\nThat's it - see what's left:\n$(wmctrl -m 2>&1)\n$sep
- $(wmctrl -l 2>&1)\n$sep\n$(wmctrl -d 2>&1)\n$sep"
- echo "$sep
- Press <Enter> for \"$@\" or anything else to continue."
- oldifs="$IFS"
- IFS=
- read -s -n 1 key
- # -s: do not echo input character. -n 1: read only 1 character
- if [ -z "$key" ]; then
- IFS="$oldifs"
- debug "Doing \"$@\""
- while :
- do
- $@
- sleep 2
- done
- else
- IFS="$oldifs"
- debug "Doing Nothing"
- fi
|