master hovercats/bin / sh / groups
  1#!/bin/sh
  2#
  3# Copyright (c) 2015 Greduan <me@greduan.com>, licensed under the WTFPL
  4# Adds group-like capabilities, sorta like those you find in CWM and such WMs
  5
  6set -e
  7
  8# Original, unmodified script can be found at https://github.com/wmutils/contrib
  9
 10usage() {
 11    cat << EOF
 12usage: $(basename "$0") [-hCU] [-c wid] [-s wid group] [-tmMu group]
 13       -h shows this help
 14       -c cleans WID from group files (and makes it visible)
 15       -C runs cleanup routine
 16       -s sets WID's group
 17       -t toggle group visibility state
 18       -m maps (shows) group
 19       -M maps group and unmaps all other groups
 20       -u unmaps (hides) group
 21       -U unmaps all the groups
 22EOF
 23
 24    exit 1
 25}
 26
 27# test for no arguments
 28[ $# -eq 0 ] && usage
 29
 30# I suggest it's under /tmp or somewhere that gets cleaned up at reboot or gets
 31# cleaned up after X stops running
 32FSDIR="${FSDIR:-/tmp/groups}"
 33
 34# define our functions
 35
 36# clean WID ($1) from group files
 37clean_wid() {
 38    t="$(mktemp /tmp/groups.XXXXXX)"
 39    for x in "${FSDIR}"/group.*; do
 40        sed "/$1/d" "$x" >"$t"
 41        mv "$t" "$x"
 42    done
 43    rm -f "$t"
 44}
 45
 46# cleans group ($1) from (in)active files
 47clean_status() {
 48    t="$(mktemp /tmp/groups.XXXXXX)"
 49    sed "/$1/d" "${FSDIR}/active" >"$t"
 50    mv "$t" "${FSDIR}/active"
 51    sed "/$1/d" "${FSDIR}/inactive" >"$t"
 52    mv "$t" "${FSDIR}/inactive"
 53}
 54
 55# shows all the windows in group ($1)
 56map_group() {
 57    # safety
 58    if ! grep -q "$1" < "${FSDIR}/all"; then
 59        printf "Group doesn't exist\n"
 60        exit 1
 61    fi
 62
 63    # clean statuses
 64    clean_status "$1"
 65    # add to active
 66    printf "%s\n" "$1" >> "${FSDIR}/active"
 67
 68    # loop through group and map windows
 69	xargs mapw -m <"${FSDIR}/group.$1"
 70}
 71
 72# hides all the windows in group ($1)
 73unmap_group() {
 74    # safety
 75    if ! grep -q "$1" < "${FSDIR}/all"; then
 76        printf "Group doesn't exist\n"
 77        exit 1
 78    fi
 79
 80    # clean statuses
 81    clean_status "$1"
 82    # add to inactive
 83    printf "%s\n" "$1" >> "${FSDIR}/inactive"
 84
 85    # loop through group and unmap windows
 86    while read -r line; do
 87        mapw -u "$line"
 88    done < "${FSDIR}/group.$1"
 89}
 90
 91# assigns WID ($1) to the group ($2)
 92set_group() {
 93    #so that neither grep nor ls in clean_wid complain
 94    #when group.$2 does not exist
 95    touch "${FSDIR}/group.$2"
 96
 97    # make sure we've no duplicates
 98    clean_wid "$1"
 99    clean_status "$2"
100
101    # insert WID into new group if not already there
102    grep -q "$1" < "${FSDIR}/group.$2" || \
103    printf "%s\n" "$1" >> "${FSDIR}/group.$2"
104
105    # if we can't find the group add it to groups and make it active
106    grep -q "$2" < "${FSDIR}/all" || \
107    printf "%s\n" "$2" >> "${FSDIR}/all" && \
108    printf "%s\n" "$2" >> "${FSDIR}/active"
109
110    # map WID if group is active
111    grep -q "$2" < "${FSDIR}/active" && \
112    mapw -m "$1"
113
114    # unmap WID if group is inactive
115    grep -q "$2" < "${FSDIR}/inactive" && \
116    mapw -u "$1"
117}
118
119# toggles visibility state of all the windows in group ($1)
120toggle_group() {
121    # safety
122    if ! grep -q "$1" < "${FSDIR}/all"; then
123        printf "Group doesn't exist\n"
124        return
125    fi
126
127    # search through active groups first
128    grep -q "$1" < "${FSDIR}/active" && \
129    unmap_group "$1" && \
130    return
131
132    # search through inactive groups next
133    grep -q "$1" < "${FSDIR}/inactive" && \
134    map_group "$1" && \
135    return
136}
137
138# removes all the unexistent WIDs from groups
139# removes all group files that don't exist
140# removes from 'all' file all groups that don't exist
141cleanup_everything() {
142    # clean WIDs that don't exist
143    # using `cat` instead of `<` because error suppression
144    cat "${FSDIR}"/group.* 2>/dev/null | while read -r wid; do
145        wattr "${wid}" || \
146        clean_wid "${wid}"
147    done
148
149    # clean group files that are empty
150    for file in "${FSDIR}"/group.*; do
151        # is the group empty?
152        if [ ! -s "${file}" ]; then
153            rm -f "${file}"
154        fi
155    done
156
157    cp "${FSDIR}/all" "${FSDIR}/tmpall"
158    # remove groups that don't exist from 'all'
159    while read -r line; do
160        if [ ! -f "${FSDIR}/group.${line}" ]; then
161            t="$(mktemp /tmp/groups.XXXXXX)"
162            sed "/$line/d" "${FSDIR}/tmpall" >"$t"
163            mv "$t" "${FSDIR}/tmpall"
164            clean_status "${line}"
165        fi
166    done  < "${FSDIR}/all"
167    mv -f "${FSDIR}/tmpall" "${FSDIR}/all"
168}
169
170# actual run logic (including arguments and such)
171
172# check $FSDIR exists
173[ -d "${FSDIR}" ] || mkdir -p "${FSDIR}"
174
175# touch all the files
176[ -f "${FSDIR}/active" ] || :> "${FSDIR}/active"
177[ -f "${FSDIR}/inactive" ] || :> "${FSDIR}/inactive"
178[ -f "${FSDIR}/all" ] || :> "${FSDIR}/all"
179
180cleanup_everything
181
182# getopts yo
183while getopts "hc:Cs:t:m:M:u:U" opt; do
184    case $opt in
185        h)
186            usage
187            ;;
188        c)
189            clean_wid "${OPTARG}"
190            mapw -m "${OPTARG}"
191            break
192            ;;
193        C)
194            cleanup_everything
195            break
196            ;;
197        s)
198            set_group "${OPTARG}" "$(eval printf "\$$OPTIND")"
199            break
200            ;;
201        t)
202            toggle_group "${OPTARG}"
203            break
204            ;;
205        m)
206            map_group "${OPTARG}"
207            break
208            ;;
209        M)
210            for file in "${FSDIR}"/group.*; do
211                group="${file##*.}"
212                unmap_group "${group}"
213            done
214            map_group "${OPTARG}"
215            break
216            ;;
217        u)
218            unmap_group "${OPTARG}"
219            break
220            ;;
221        U)
222            for file in "${FSDIR}"/group.*; do
223                group="${file##*.}"
224                unmap_group "${group}"
225            done
226            break
227            ;;
228        *) 
229            printf "Unrecognized option. use h flag to show usage\n"
230    esac
231done