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