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