master ohmu/wmutils / scripts / tile
ohmu  ·  2026-07-25
  1#!/bin/sh
  2
  3GAP=$1
  4MASTER_RATIO=0.6
  5MASTER_SIZE=1
  6
  7STATE_DIR="/tmp/2bwm-tiling"
  8mkdir -p "$STATE_DIR"
  9
 10get_master_windows() {
 11    [ -f "$STATE_DIR/master" ] && cat "$STATE_DIR/master" || echo ""
 12}
 13
 14get_stack_windows() {
 15    [ -f "$STATE_DIR/stack" ] && cat "$STATE_DIR/stack" || echo ""
 16}
 17
 18save_windows() {
 19    master="$1"
 20    stack="$2"
 21    echo "$master" > "$STATE_DIR/master"
 22    echo "$stack" > "$STATE_DIR/stack"
 23}
 24
 25get_focused_window() {
 26    lsw | head -1
 27}
 28
 29tile() {
 30    root=$(lsw -r)
 31    windows=$(lsw | grep -v "^$root$")
 32    
 33    if [ -z "$windows" ]; then
 34        exit 0
 35    fi
 36
 37    screen_w=$(wattr w $root)
 38    screen_h=$(wattr h $root)
 39    count=$(echo "$windows" | wc -l)
 40
 41    if [ $count -eq 3 ]; then
 42        master=$(echo "$windows" | head -1)
 43        stack_windows=$(echo "$windows" | tail -n +2)
 44        
 45        master_w=$(( (screen_w - GAP * 3) / 2 ))
 46        wtp $GAP $GAP $master_w $((screen_h - GAP * 2)) $master
 47        
 48        stack_x=$((master_w + GAP * 2))
 49        stack_w=$((screen_w - stack_x - GAP))
 50        stack_h=$(( (screen_h - GAP * 3) / 2 ))
 51        
 52        i=0
 53        for win in $stack_windows; do
 54            y=$((GAP + i * (stack_h + GAP)))
 55            wtp $stack_x $y $stack_w $stack_h $win
 56            i=$((i + 1))
 57        done
 58        exit 0
 59    fi
 60
 61    case $count in
 62        1) cols=1; rows=1 ;;
 63        2) cols=2; rows=1 ;;
 64        4) cols=2; rows=2 ;;
 65        5|6) cols=3; rows=2 ;;
 66        7|8) cols=4; rows=2 ;;
 67        9) cols=3; rows=3 ;;
 68        *) cols=4; rows=$(( (count + cols - 1) / cols )) ;;
 69    esac
 70
 71    cell_w=$(( (screen_w - GAP * (cols + 1)) / cols ))
 72    cell_h=$(( (screen_h - GAP * (rows + 1)) / rows ))
 73
 74    i=0
 75    for win in $windows; do
 76        if [ $i -lt $((cols * rows)) ]; then
 77            col=$((i % cols))
 78            row=$((i / cols))
 79            x=$((GAP + col * (cell_w + GAP)))
 80            y=$((GAP + row * (cell_h + GAP)))
 81            wtp $x $y $cell_w $cell_h $win
 82            i=$((i + 1))
 83        fi
 84    done
 85}
 86
 87tile_master_stack() {
 88    root=$(lsw -r)
 89    all_windows=$(lsw | grep -v "^$root$")
 90    
 91    if [ -z "$all_windows" ]; then
 92        exit 0
 93    fi
 94
 95    master_windows=$(get_master_windows)
 96    stack_windows=$(get_stack_windows)
 97    
 98    if [ -z "$master_windows" ]; then
 99        master_windows=$(echo "$all_windows" | head -$MASTER_SIZE)
100        stack_windows=$(echo "$all_windows" | tail -n +$((MASTER_SIZE + 1)))
101        save_windows "$master_windows" "$stack_windows"
102    fi
103
104    screen_w=$(wattr w $root)
105    screen_h=$(wattr h $root)
106    
107    master_width=$(( (screen_w - GAP * 3) * MASTER_RATIO / 1 ))
108    stack_width=$((screen_w - master_width - GAP * 3))
109    
110    master_count=$(echo "$master_windows" | wc -l)
111    stack_count=$(echo "$stack_windows" | wc -l)
112    
113    if [ $master_count -gt 0 ]; then
114        master_window_height=$(( (screen_h - GAP * (master_count + 1)) / master_count ))
115        i=0
116        for win in $master_windows; do
117            y=$((GAP + i * (master_window_height + GAP)))
118            wtp $GAP $y $master_width $master_window_height $win
119            i=$((i + 1))
120        done
121    fi
122    
123    if [ $stack_count -gt 0 ]; then
124        stack_window_height=$(( (screen_h - GAP * (stack_count + 1)) / stack_count ))
125        i=0
126        for win in $stack_windows; do
127            y=$((GAP + i * (stack_window_height + GAP)))
128            x=$((master_width + GAP * 2))
129            wtp $x $y $stack_width $stack_window_height $win
130            i=$((i + 1))
131        done
132    fi
133}
134
135focus_master() {
136    master_windows=$(get_master_windows)
137    if [ -n "$master_windows" ]; then
138        first_master=$(echo "$master_windows" | head -1)
139        chwso -r "$first_master"
140    fi
141}
142
143focus_next() {
144    current=$(get_focused_window)
145    all_windows=$(lsw | grep -v "^$(lsw -r)$")
146    if [ -n "$all_windows" ]; then
147        next=$(echo "$all_windows" | grep -A1 "^$current$" | tail -1)
148        if [ "$next" != "$current" ] && [ -n "$next" ]; then
149            chwso -r "$next"
150        else
151            first=$(echo "$all_windows" | head -1)
152            chwso -r "$first"
153        fi
154    fi
155}
156
157focus_prev() {
158    current=$(get_focused_window)
159    all_windows=$(lsw | grep -v "^$(lsw -r)$")
160    if [ -n "$all_windows" ]; then
161        prev=$(echo "$all_windows" | grep -B1 "^$current$" | head -1)
162        if [ "$prev" != "$current" ] && [ -n "$prev" ]; then
163            chwso -r "$prev"
164        else
165            last=$(echo "$all_windows" | tail -1)
166            chwso -r "$last"
167        fi
168    fi
169}
170
171promote_to_master() {
172    window=$(get_focused_window)
173    master_windows=$(get_master_windows)
174    stack_windows=$(get_stack_windows)
175    
176    if echo "$stack_windows" | grep -q "^$window$"; then
177        new_stack=$(echo "$stack_windows" | grep -v "^$window$")
178        new_master=$(echo -e "$window\n$master_windows" | head -$MASTER_SIZE)
179        save_windows "$new_master" "$new_stack"
180        tile_master_stack
181    fi
182}
183
184demote_to_stack() {
185    window=$(get_focused_window)
186    master_windows=$(get_master_windows)
187    stack_windows=$(get_stack_windows)
188    
189    if echo "$master_windows" | grep -q "^$window$"; then
190        new_master=$(echo "$master_windows" | grep -v "^$window$")
191        new_stack=$(echo -e "$window\n$stack_windows")
192        save_windows "$new_master" "$new_stack"
193        tile_master_stack
194    fi
195}
196
197swap_master() {
198    master_windows=$(get_master_windows)
199    if [ -n "$master_windows" ]; then
200        first_master=$(echo "$master_windows" | head -1)
201        second_master=$(echo "$master_windows" | head -2 | tail -1)
202        if [ -n "$second_master" ]; then
203            new_master=$(echo "$master_windows" | sed "1s/^$first_master$/$second_master/; 2s/^$second_master$/$first_master/")
204            save_windows "$new_master" "$(get_stack_windows)"
205            tile_master_stack
206            chwso -r "$first_master"
207        fi
208    fi
209}
210
211increase_master() {
212    MASTER_SIZE=$((MASTER_SIZE + 1))
213    all_windows=$(lsw | grep -v "^$(lsw -r)$")
214    master_windows=$(echo "$all_windows" | head -$MASTER_SIZE)
215    stack_windows=$(echo "$all_windows" | tail -n +$((MASTER_SIZE + 1)))
216    save_windows "$master_windows" "$stack_windows"
217    tile_master_stack
218}
219
220decrease_master() {
221    if [ $MASTER_SIZE -gt 1 ]; then
222        MASTER_SIZE=$((MASTER_SIZE - 1))
223        all_windows=$(lsw | grep -v "^$(lsw -r)$")
224        master_windows=$(echo "$all_windows" | head -$MASTER_SIZE)
225        stack_windows=$(echo "$all_windows" | tail -n +$((MASTER_SIZE + 1)))
226        save_windows "$master_windows" "$stack_windows"
227        tile_master_stack
228    fi
229}
230
231rotate_stack() {
232    stack_windows=$(get_stack_windows)
233    if [ -n "$stack_windows" ]; then
234        first=$(echo "$stack_windows" | head -1)
235        rest=$(echo "$stack_windows" | tail -n +2)
236        new_stack=$(echo -e "$rest\n$first")
237        save_windows "$(get_master_windows)" "$new_stack"
238        tile_master_stack
239    fi
240}
241
242rebalance() {
243    save_windows "" ""
244    tile_master_stack
245}
246
247if [ $# -eq 0 ]; then
248    tile
249    exit 0
250fi
251
252tile