commit 33e58f5

ohmu  ·  2026-07-25 03:43:18 +0300 MSK
parent 545e2d7
init
118 files changed,  +7977, -0
+14, -0
 1@@ -0,0 +1,14 @@
 2+Copyright (c) 2014-2015, brosephs <dcat at iotek dot org>,
 3+                             	  <willy at mailoo dot org>
 4+
 5+Permission to use, copy, modify, and/or distribute this software for any
 6+purpose with or without fee is hereby granted, provided that the above
 7+copyright notice and this permission notice appear in all copies.
 8+
 9+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15+PERFORMANCE OF THIS SOFTWARE.
+99, -0
  1@@ -0,0 +1,99 @@
  2+contrib
  3+=======
  4+
  5+Repository hosting inspirational wmutils snippets.
  6+
  7+### tile.sh
  8+Arrange your windows in a tiled pattern consisting of one master area, and a
  9+stacking area. Uses `$GAP` and `$MASTER` from environment.
 10+
 11+    usage: tile.sh
 12+
 13+### fullscreen.sh
 14+Set a window in fullscreen mode, removing borders from it and putting it in
 15+front of all other windows. There can only be one window in fullscreen at a
 16+time. Uses `$FSFILE` from environment.
 17+
 18+    usage: fullscreen.sh <wid>
 19+
 20+### focus.sh
 21+Focus either a specific window, or the next/previous window in the stack. Then
 22+set borders accordingly. Uses `$BW`, `$ACTIVE` and `$INACTIVE` from environment.
 23+
 24+    usage: focus.sh <next|prev|wid>
 25+
 26+### focus\_watcher.sh
 27+Focus a new window (using focus.sh) upon its creation.
 28+
 29+Depends on `wew(1)` (opt repo)  and `focus.sh` (contrib repo)
 30+
 31+    usage: focus_watcher.sh
 32+
 33+### rainbow.sh
 34+Make the current window border cycle all the rainbow colors. Uses `$FREQ` from
 35+environment.
 36+
 37+    usage: rainbow.sh
 38+
 39+### closest.sh
 40+Focus the closest window in a specific direction.
 41+
 42+    usage: closest.sh <direction>
 43+
 44+### underneath.sh
 45+Produce window id directely underneath cursor.
 46+
 47+Example sxhkd binding:
 48+
 49+    ~button1
 50+        focus.sh $(underneath.sh)
 51+
 52+### switch\_grid.sh
 53+A simpler version of OS X Mission Control feature, or GNOME Shell's Overview
 54+feature.
 55+
 56+Depends on `wew(1)` (opt repo)  and `focus.sh` (contrib repo)
 57+
 58+    usage: switch_grid.sh
 59+
 60+### deletelock.sh
 61+Set a custom xprop variable which can be used to test if a window is able to
 62+be deleted or not when using killw in a custom script with `wew(1)`.
 63+
 64+Depends on xorg-xprop
 65+
 66+    usage: deletelock.sh <lock|unlock|toggle|status> <wid>
 67+
 68+### groups.sh
 69+Adds group-like capabilities, sorta like those you find in CWM and such WMs.
 70+
 71+    usage: groups.sh [-hCU] [-c wid] [-s wid group] [-tmMu group]
 72+           -h shows this help
 73+           -c cleans WID from group files (and makes it visible)
 74+           -C runs cleanup routine
 75+           -s sets WID's group
 76+           -t toggle group visibility state
 77+           -m maps (shows) group
 78+           -M maps group and unmaps all other groups
 79+           -u unmaps (hides) group
 80+           -U unmaps all the groups
 81+
 82+### wmenu.sh
 83+
 84+Uses wname and dmenu to produce a window selection menu similar to CWM's
 85+menu-window option. Upon selection the script outputs the chosen window id that
 86+can then be piped to a focus script.
 87+
 88+### workspace.sh
 89+Groups windows into workspaces. Stores the current workspace index in /tmp/workspaces/curr by default.
 90+
 91+	usage: workspace.sh [-hinp] [-g ws_num] [-m ws_num] 
 92+		-h: Displays this message
 93+		-i: Initialize workspaces. Should be called once in a startup script.
 94+		-n: Move up one workspace
 95+		-p: Move down one workspace
 96+		-g, <ws_num>: go to the workspace specified by <ws_num>
 97+		-m, <ws_num>: move the currently focused window to the worskpace specified by <ws_num>
 98+
 99+
100+*... to be continued*
+58, -0
 1@@ -0,0 +1,58 @@
 2+#!/bin/sh
 3+# focus.sh
 4+
 5+. ~/.theme
 6+
 7+# get current window id
 8+CUR=$(pfw)
 9+
10+usage() {
11+    echo "usage: $(basename $0) <next|prev|wid>"
12+    exit 1
13+}
14+
15+setborder() {
16+    ROOT=$(lsw -r)
17+    wattr $2 || return
18+    test "$(wattr xywh $2)" = "$(wattr xywh $ROOT)" && return
19+
20+    pkill -f "chwb.*$2" 2>/dev/null
21+    
22+    case $1 in
23+		active)   chwb -s $TBW -c $ACTIVE $2 ;;
24+        inactive)   chwb -s $TBW -c $INACTIVE $2 ;;
25+    esac
26+}
27+
28+case $1 in
29+    next) wid=$(lsw|grep -v $CUR|sed '1 p;d') ;;
30+    prev) wid=$(lsw|grep -v $CUR|sed '$ p;d') ;;
31+    0x*) wattr $1 && wid=$1 ;;
32+    *) usage ;;
33+esac
34+
35+if [ -z "$wid" ]; then
36+    for w in $(lsw); do
37+        setborder active $w
38+    done
39+    exit 0
40+fi
41+
42+chwso -r $wid
43+wtf $wid
44+
45+geom=$(wattr xywh $wid)
46+set -- $geom
47+x=$1; y=$2; w=$3; h=$4
48+center_x=$((x + w/2))
49+center_y=$((y + h/2))
50+#wmp -a $center_x $center_y
51+
52+for w in $(lsw); do
53+    if [ "$w" != "$wid" ]; then
54+        setborder inactive $w
55+    fi
56+done
57+
58+sleep 0.01
59+setborder active $wid
+45, -0
 1@@ -0,0 +1,45 @@
 2+#!/bin/bash
 3+
 4+LOCKFILE="/tmp/ws_switch.lock"
 5+
 6+wew | while read -r ev wid; do
 7+    if [ -f "$LOCKFILE" ]; then
 8+        continue
 9+    fi
10+
11+    case $ev in
12+        CREATE)
13+            if ! wattr o "$wid"; then
14+                (
15+                    sleep 0.15
16+                    if [ ! -f "$LOCKFILE" ] && wattr o "$wid" >/dev/null 2>&1; then
17+                        for w in $(lsw); do
18+                            chwb -s "$TBW" -c "$INACTIVE" "$w"
19+                        done
20+                        chwb -s "$TBW" -c "$ACTIVE" "$wid"
21+                        wtf "$wid"
22+                    fi
23+                ) &
24+            fi
25+            ;;
26+        MAP)
27+            if [ ! -f "$LOCKFILE" ] && ! wattr o "$wid"; then
28+                for w in $(lsw); do
29+                    chwb -s "$TBW" -c "$INACTIVE" "$w"
30+                done
31+                chwb -s "$TBW" -c "$ACTIVE" "$wid"
32+                wtf "$wid"
33+            fi
34+            ;;
35+        ENTER)
36+            if [ ! -f "$LOCKFILE" ] && ! wattr o "$wid"; then
37+                for w in $(lsw); do
38+                    chwb -s "$TBW" -c "$INACTIVE" "$w"
39+                done
40+                chwb -s "$TBW" -c "$ACTIVE" "$wid"
41+                wtf "$wid"
42+                chwso -r "$wid"
43+            fi
44+            ;;
45+    esac
46+done
+50, -0
 1@@ -0,0 +1,50 @@
 2+#!/bin/sh
 3+
 4+. ~/.theme
 5+
 6+if [ $# -ne 2 ]; then
 7+    echo "Usage: $0 {x|y|xy} wid"
 8+    exit 1
 9+fi
10+
11+OLD_WIN=$2
12+OLD_X=$(wattr x $OLD_WIN)
13+OLD_Y=$(wattr y $OLD_WIN)
14+
15+CURSOR=$(wmp -r)
16+CURSOR_X=$(echo $CURSOR | cut -d' ' -f1)
17+CURSOR_Y=$(echo $CURSOR | cut -d' ' -f2)
18+
19+REL_X=$((CURSOR_X - OLD_X))
20+REL_Y=$((CURSOR_Y - OLD_Y))
21+
22+ROOT_W=$(wattr w $(lsw -r))
23+ROOT_H=$(wattr h $(lsw -r))
24+
25+WIN_W=$(wattr w $OLD_WIN)
26+WIN_H=$(wattr h $OLD_WIN)
27+
28+NEW_X=$(((ROOT_W - WIN_W) / 2))
29+NEW_Y=$(((ROOT_H - WIN_H) / 2))
30+
31+case $1 in
32+    xy)
33+        wtp $NEW_X $NEW_Y $WIN_W $WIN_H $OLD_WIN
34+        ;;
35+    x)
36+        wtp $NEW_X $OLD_Y $WIN_W $WIN_H $OLD_WIN
37+        ;;
38+    y)
39+        wtp $OLD_X $NEW_Y $WIN_W $WIN_H $OLD_WIN
40+        ;;
41+    *)
42+        echo "Invalid argument. Use: x, y, xy"
43+        exit 1
44+        ;;
45+esac
46+
47+NEW_CURSOR_X=$((NEW_X + WIN_W/2))
48+NEW_CURSOR_Y=$((NEW_Y + WIN_H/2))
49+
50+#wmp -a $NEW_CURSOR_X $NEW_CURSOR_Y
51+
+40, -0
 1@@ -0,0 +1,40 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# find and focus the closest window in a specific direction
 6+# depends on: focus.sh
 7+
 8+# get current window id
 9+CUR=$(pfw)
10+
11+usage() {
12+    echo "usage: $(basename $0) <direction>" >&2
13+    exit 1
14+}
15+
16+next_west() {
17+    lsw | xargs wattr xi | sort -nr | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
18+}
19+
20+next_east() {
21+    lsw | xargs wattr xi | sort -n | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
22+}
23+
24+next_north() {
25+    lsw | xargs wattr yi | sort -nr | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
26+}
27+
28+next_south() {
29+    lsw | xargs wattr yi | sort -n | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
30+}
31+
32+# Use the specification of your choice: WASD, HJKL, ←↑↓→, west/north/south/east
33+case $1 in
34+    h|a|west|left)  wid=$(next_west)  ;;
35+    j|s|south|down) wid=$(next_south) ;;
36+    k|w|north|up)   wid=$(next_north) ;;
37+    l|d|east|right) wid=$(next_east)  ;;
38+    *)              usage             ;;
39+esac
40+
41+test ! -z "$wid" && /home/$USER/.wmutils/scripts/focus.sh "$wid"
+54, -0
 1@@ -0,0 +1,54 @@
 2+#!/bin/sh
 3+#
 4+# wildefyr - 2015 (c) wtfpl
 5+# toggle delete lock for current window
 6+
 7+usage() {
 8+    echo "usage: $(basename $0) <lock|unlock|toggle|status> <wid>"
 9+    exit 1
10+}
11+
12+wid=$(pfw)
13+
14+case $2 in
15+    0x*)
16+        wid=$2
17+        ;;
18+    *)
19+        usage
20+        ;;
21+esac
22+
23+case $1 in
24+    lock)
25+        xprop -id $wid -f _WMUTILS_DELETELOCK 8i -set _WMUTILS_DELETELOCK '1'
26+        ;;
27+    unlock)
28+        xprop -id $wid -remove _WMUTILS_DELETELOCK
29+        ;;
30+    toggle)
31+        lockStatus=$(xprop -id $wid _WMUTILS_DELETELOCK | cut -d\  -f 3)
32+        case $lockStatus in
33+            1)
34+                $(basename $0) unlock $wid 
35+                ;;
36+            *)
37+                $(basename $0) lock $wid 
38+                ;;
39+        esac
40+        ;;
41+    status)
42+        lockStatus=$(xprop -id $wid _WMUTILS_DELETELOCK | cut -d\  -f 3)
43+        case $lockStatus in
44+            1)
45+                echo "1"
46+                ;;
47+            *)
48+                echo "0"
49+                ;;
50+        esac
51+        ;;
52+    *)
53+        usage
54+        ;;
55+esac
+5, -0
1@@ -0,0 +1,5 @@
2+#!/bin/sh
3+
4+wtf "$1"
5+
6+chwso -r "$1"
+58, -0
 1@@ -0,0 +1,58 @@
 2+#!/bin/sh
 3+# focus.sh
 4+
 5+. ~/.theme
 6+
 7+# get current window id
 8+CUR=$(pfw)
 9+
10+usage() {
11+    echo "usage: $(basename $0) <next|prev|wid>"
12+    exit 1
13+}
14+
15+setborder() {
16+    ROOT=$(lsw -r)
17+    wattr $2 || return
18+    test "$(wattr xywh $2)" = "$(wattr xywh $ROOT)" && return
19+
20+    pkill -f "chwb2.*$2" 2>/dev/null
21+    
22+    case $1 in
23+        active)   chwb2 -I $ACTIVE -O $OBC -i $IBW -o $OBW $2 -w & ;;
24+        inactive) chwb2 -I $INACTIVE -O $OBC -i $IBW -o $OBW $2 -w & ;;
25+    esac
26+}
27+
28+case $1 in
29+    next) wid=$(lsw|grep -v $CUR|sed '1 p;d') ;;
30+    prev) wid=$(lsw|grep -v $CUR|sed '$ p;d') ;;
31+    0x*) wattr $1 && wid=$1 ;;
32+    *) usage ;;
33+esac
34+
35+if [ -z "$wid" ]; then
36+    for w in $(lsw); do
37+        setborder active $w
38+    done
39+    exit 0
40+fi
41+
42+chwso -r $wid
43+wtf $wid
44+
45+geom=$(wattr xywh $wid)
46+set -- $geom
47+x=$1; y=$2; w=$3; h=$4
48+center_x=$((x + w/2))
49+center_y=$((y + h/2))
50+#wmp -a $center_x $center_y
51+
52+for w in $(lsw); do
53+    if [ "$w" != "$wid" ]; then
54+        setborder inactive $w
55+    fi
56+done
57+
58+sleep 0.01
59+setborder active $wid
+41, -0
 1@@ -0,0 +1,41 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# toggle the fullscreen state of a window
 6+# depends on: focus.sh
 7+
 8+# this file is used to store the previous geometry of a window
 9+FSFILE=${FSFILE:-~/.fwin}
10+
11+# it's pretty simple, but anyway...
12+usage() {
13+    echo "usage: $(basename $0) <wid>"
14+    exit 1
15+}
16+
17+# exit if no argument given
18+test -z "$1" && usage
19+
20+# this will unset the fullscreen state of any fullscreen window if there is one.
21+# this way, there will only be one window in fullscreen at a time, and no window
22+# will loose their previous geometry info
23+test -f $FSFILE && wtp $(cat $FSFILE)
24+
25+# if file exist and contain our window id, it means that out window is in
26+# fullscreen mode
27+if test -f $FSFILE && grep -q $1 $FSFILE; then
28+    # if the window we removed was our window, delete the file, so we can
29+    # fullscreen it again later 
30+    rm -f $FSFILE
31+
32+else
33+    # if not, then put the current window in fullscreen mode, after saving its
34+    # geometry and id to $FSFILE we also remove any border from this window.
35+    wattr xywhi $1 > $FSFILE
36+    chwb -s 0 $1
37+    wtp $(wattr xywh `lsw -r`) $1
38+fi
39+
40+# now focus the window, and put it in front, no matter which state we're in, and
41+# put the cursor on its bottom-right corner (for consistency)
42+focus.sh $1
+223, -0
  1@@ -0,0 +1,223 @@
  2+#!/bin/sh
  3+#
  4+# Copyright (c) 2015 Greduan <me@greduan.com>, licensed under the WTFPL
  5+# Adds group-like capabilities, sorta like those you find in CWM and such WMs
  6+
  7+usage() {
  8+    cat << EOF
  9+usage: $(basename $0) [-hCU] [-c wid] [-s wid group] [-tmMu group]
 10+       -h shows this help
 11+       -c cleans WID from group files (and makes it visible)
 12+       -C runs cleanup routine
 13+       -s sets WID's group
 14+       -t toggle group visibility state
 15+       -m maps (shows) group
 16+       -M maps group and unmaps all other groups
 17+       -u unmaps (hides) group
 18+       -U unmaps all the groups
 19+EOF
 20+
 21+    exit 1
 22+}
 23+
 24+# test for no arguments
 25+test $# -eq 0 && usage
 26+
 27+# I suggest it's under /tmp or somewhere that gets cleaned up at reboot or gets
 28+# cleaned up after X stops running
 29+FSDIR=${FSDIR:-/tmp/groups.sh}
 30+
 31+# define our functions
 32+
 33+# clean WID ($1) from group files
 34+clean_wid() {
 35+    t=$(mktemp /tmp/groups.XXXXXX)
 36+    for x in $(ls $FSDIR/group.*); do
 37+        sed "/$1/d" "$x" >"$t"
 38+        mv "$t" "$x"
 39+    done
 40+    rm -f "$t"
 41+}
 42+
 43+# cleans group ($1) from (in)active files
 44+clean_status() {
 45+    t=$(mktemp /tmp/groups.XXXXXX)
 46+    sed "/$1/d" $FSDIR/active >"$t"
 47+    mv "$t" $FSDIR/active
 48+    sed "/$1/d" $FSDIR/inactive >"$t"
 49+    mv "$t" $FSDIR/inactive
 50+}
 51+
 52+# shows all the windows in group ($1)
 53+map_group() {
 54+    # safety
 55+    if ! grep -q $1 < $FSDIR/all; then
 56+        echo "Group doesn't exist"
 57+        exit 1
 58+    fi
 59+
 60+    # clean statuses
 61+    clean_status $1
 62+    # add to active
 63+    echo $1 >> $FSDIR/active
 64+
 65+    # loop through group and map windows
 66+	xargs mapw -m <$FSDIR/group.$1
 67+}
 68+
 69+# hides all the windows in group ($1)
 70+unmap_group() {
 71+    # safety
 72+    if ! grep -q $1 < $FSDIR/all; then
 73+        echo "Group doesn't exist"
 74+        exit 1
 75+    fi
 76+
 77+    # clean statuses
 78+    clean_status $1
 79+    # add to inactive
 80+    echo $1 >> $FSDIR/inactive
 81+
 82+    # loop through group and unmap windows
 83+    while read line; do
 84+        mapw -u $line
 85+    done < $FSDIR/group.$1
 86+}
 87+
 88+# assigns WID ($1) to the group ($2)
 89+set_group() {
 90+    #so that neither grep nor ls in clean_wid complain
 91+    #when group.$2 does not exist
 92+    touch $FSDIR/group.$2
 93+
 94+    # make sure we've no duplicates
 95+    clean_wid $1
 96+    clean_status $2
 97+
 98+    # insert WID into new group if not already there
 99+    grep -q $1 < $FSDIR/group.$2 || \
100+    echo $1 >> $FSDIR/group.$2
101+
102+    # if we can't find the group add it to groups and make it active
103+    grep -q $2 < $FSDIR/all || \
104+    echo $2 >> $FSDIR/all && \
105+    echo $2 >> $FSDIR/active
106+
107+    # map WID if group is active
108+    grep -q $2 < $FSDIR/active && \
109+    mapw -m $1
110+
111+    # unmap WID if group is inactive
112+    grep -q $2 < $FSDIR/inactive && \
113+    mapw -u $1
114+}
115+
116+# toggles visibility state of all the windows in group ($1)
117+toggle_group() {
118+    # safety
119+    if ! grep -q $1 < $FSDIR/all; then
120+        echo "Group doesn't exist"
121+        return
122+    fi
123+
124+    # search through active groups first
125+    grep -q $1 < $FSDIR/active && \
126+    unmap_group $1 && \
127+    return
128+
129+    # search through inactive groups next
130+    grep -q $1 < $FSDIR/inactive && \
131+    map_group $1 && \
132+    return
133+}
134+
135+# removes all the unexistent WIDs from groups
136+# removes all group files that don't exist
137+# removes from 'all' file all groups that don't exist
138+cleanup_everything() {
139+    # clean WIDs that don't exist
140+    # using `cat` instead of `<` because error suppression
141+    cat $FSDIR/group.* 2>/dev/null | while read wid; do
142+        wattr $wid || \
143+        clean_wid $wid
144+    done
145+
146+    # clean group files that are empty
147+    for file in $FSDIR/group.*; do
148+        # is the group empty?
149+        if [ ! -s $file ]; then
150+            rm -f $file
151+        fi
152+    done
153+
154+    # remove groups that don't exist from 'all'
155+    while read line; do
156+        if [ ! -f $FSDIR/group.$line ]; then
157+            t=$(mktemp /tmp/groups.XXXXXX)
158+            sed "/$line/d" $FSDIR/all >"$t"
159+            mv "$t" $FSDIR/all
160+            clean_status $line
161+        fi
162+    done < $FSDIR/all
163+}
164+
165+# actual run logic (including arguments and such)
166+
167+# check $FSDIR exists
168+test -d $FSDIR || mkdir -p $FSDIR
169+
170+# touch all the files
171+test -f $FSDIR/active || :> $FSDIR/active
172+test -f $FSDIR/inactive || :> $FSDIR/inactive
173+test -f $FSDIR/all || :> $FSDIR/all
174+
175+cleanup_everything
176+
177+# getopts yo
178+while getopts "hc:Cs:t:m:M:u:U" opt; do
179+    case $opt in
180+        h)
181+            usage
182+            ;;
183+        c)
184+            clean_wid $OPTARG
185+            mapw -m $OPTARG
186+            break
187+            ;;
188+        C)
189+            cleanup_everything
190+            break
191+            ;;
192+        s)
193+            set_group $OPTARG $(eval echo "\$$OPTIND")
194+            break
195+            ;;
196+        t)
197+            toggle_group $OPTARG
198+            break
199+            ;;
200+        m)
201+            map_group $OPTARG
202+            break
203+            ;;
204+        M)
205+            for file in $FSDIR/group.*; do
206+                group=${file##*.}
207+                unmap_group $group
208+            done
209+            map_group $OPTARG
210+            break
211+            ;;
212+        u)
213+            unmap_group $OPTARG
214+            break
215+            ;;
216+        U)
217+            for file in $FSDIR/group.*; do
218+                group=${file##*.}
219+                unmap_group $group
220+            done
221+            break
222+            ;;
223+    esac
224+done
+56, -0
 1@@ -0,0 +1,56 @@
 2+#!/bin/sh
 3+
 4+. ~/.theme
 5+
 6+if [ $# -ne 2 ]; then
 7+    echo "Usage: $0 {left|right} wid"
 8+    echo "  left  - snap window to left side"
 9+    echo "  right - snap window to right side"
10+    exit 1
11+fi
12+
13+DIRECTION=$1
14+WIN=$2
15+
16+# Get screen dimensions
17+ROOT_W=$(wattr w $(lsw -r))
18+ROOT_H=$(wattr h $(lsw -r))
19+
20+# Get window dimensions
21+WIN_W=$(wattr w $WIN)
22+WIN_H=$(wattr h $WIN)
23+
24+# Define gaps (adjust these values as needed)
25+GAP_TOP=30
26+GAP_BOTTOM=30
27+GAP_SIDE=30
28+
29+# Calculate new window size (full height minus gaps)
30+NEW_H=$((ROOT_H - GAP_TOP - GAP_BOTTOM))
31+NEW_W=$((WIN_W))  # Keep original width or set to half screen? Let's keep original
32+
33+# Option: Uncomment below to make window take half of screen width
34+# NEW_W=$(((ROOT_W - GAP_SIDE * 3) / 2))
35+
36+case $DIRECTION in
37+    right)
38+        NEW_X=$((ROOT_W - NEW_W - GAP_SIDE))
39+        NEW_Y=$GAP_TOP
40+        ;;
41+    left)
42+        NEW_X=$GAP_SIDE
43+        NEW_Y=$GAP_TOP
44+        ;;
45+    *)
46+        echo "Invalid argument. Use: left or right"
47+        exit 1
48+        ;;
49+esac
50+
51+# Move and resize window
52+wtp $NEW_X $NEW_Y $NEW_W $NEW_H $WIN
53+
54+# Optionally move cursor to center of window
55+# NEW_CURSOR_X=$((NEW_X + NEW_W/2))
56+# NEW_CURSOR_Y=$((NEW_Y + NEW_H/2))
57+# wmp -a $NEW_CURSOR_X $NEW_CURSOR_Y
+11, -0
 1@@ -0,0 +1,11 @@
 2+#!/bin/sh
 3+
 4+groups.sh -U
 5+
 6+for i in 1 2 3 4 5; do
 7+    touch /tmp/groups.sh/group.$i
 8+    echo $i >> /tmp/groups.sh/all
 9+    echo $i >> /tmp/groups.sh/active
10+done
11+
12+lsw > /tmp/groups.sh/group.1
+38, -0
 1@@ -0,0 +1,38 @@
 2+include config.mk
 3+
 4+HDR = arg.h util.h
 5+SRC =           \
 6+	killwa.c
 7+
 8+OBJ = $(SRC:.c=.o)
 9+BIN = $(SRC:.c=)
10+
11+.POSIX:
12+.SUFFIXES: .1 .1.gz
13+
14+all: binutils
15+
16+binutils: $(BIN)
17+
18+$(OBJ): $(HDR) util.o
19+
20+.o:
21+	@echo "LD $@"
22+	@$(LD) $< util.o -o $@ $(LDFLAGS)
23+
24+.c.o:
25+	@echo "CC $<"
26+	@$(CC) -c $< -o $@ $(CFLAGS)
27+
28+install: $(BIN)
29+	mkdir -p $(DESTDIR)$(PREFIX)/bin/
30+	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/
31+
32+uninstall:
33+	@echo "uninstalling binaries"
34+	@for util in $(BIN); do \
35+		rm -f $(DESTDIR)$(PREFIX)/bin/$$util; \
36+	done
37+
38+clean :
39+	rm -f $(OBJ) $(BIN) util.o
+63, -0
 1@@ -0,0 +1,63 @@
 2+/*
 3+ * Copy me if you can.
 4+ * by 20h
 5+ */
 6+
 7+#ifndef ARG_H__
 8+#define ARG_H__
 9+
10+extern char *argv0;
11+
12+/* use main(int argc, char *argv[]) */
13+#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
14+					argv[0] && argv[0][1]\
15+					&& argv[0][0] == '-';\
16+					argc--, argv++) {\
17+				char argc_;\
18+				char **argv_;\
19+				int brk_;\
20+				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
21+					argv++;\
22+					argc--;\
23+					break;\
24+				}\
25+				for (brk_ = 0, argv[0]++, argv_ = argv;\
26+						argv[0][0] && !brk_;\
27+						argv[0]++) {\
28+					if (argv_ != argv)\
29+						break;\
30+					argc_ = argv[0][0];\
31+					switch (argc_)
32+
33+/* Handles obsolete -NUM syntax */
34+#define ARGNUM				case '0':\
35+					case '1':\
36+					case '2':\
37+					case '3':\
38+					case '4':\
39+					case '5':\
40+					case '6':\
41+					case '7':\
42+					case '8':\
43+					case '9'
44+
45+#define ARGEND			}\
46+			}
47+
48+#define ARGC()		argc_
49+
50+#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))
51+
52+#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
53+				((x), abort(), (char *)0) :\
54+				(brk_ = 1, (argv[0][1] != '\0')?\
55+					(&argv[0][1]) :\
56+					(argc--, argv++, argv[0])))
57+
58+#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
59+				(char *)0 :\
60+				(brk_ = 1, (argv[0][1] != '\0')?\
61+					(&argv[0][1]) :\
62+					(argc--, argv++, argv[0])))
63+
64+#endif
+7, -0
1@@ -0,0 +1,7 @@
2+PREFIX = /usr
3+
4+CC      = cc
5+LD      = $(CC)
6+
7+CFLAGS  = -std=c99 -pedantic -Wall -Os
8+LDFLAGS = -lxcb -lxcb-icccm
+88, -0
 1@@ -0,0 +1,88 @@
 2+// Created by https://github.com/onodera-punpun
 3+
 4+#include <string.h>
 5+#include <stdbool.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <err.h>
 9+#include <xcb/xcb.h>
10+#include <xcb/xcb_icccm.h>
11+
12+#include "util.h"
13+
14+static xcb_connection_t *conn;
15+
16+static void usage(char *);
17+
18+static void
19+usage (char *name)
20+{
21+	fprintf(stderr, "usage: %s <wid> [wid...]\n", name);
22+	exit(1);
23+}
24+
25+static
26+xcb_atom_t xcb_atom_get(xcb_connection_t *conn, char *name)
27+{
28+	xcb_intern_atom_cookie_t cookie = xcb_intern_atom(conn ,0, strlen(name), name);
29+	xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL);
30+
31+	if (!reply)
32+		return XCB_ATOM_STRING;
33+
34+	return reply->atom;
35+}
36+
37+void
38+delete_window(xcb_window_t win)
39+{
40+	xcb_client_message_event_t ev;
41+
42+	ev.response_type = XCB_CLIENT_MESSAGE;
43+	ev.sequence = 0;
44+	ev.format = 32;
45+	ev.window = win;
46+	ev.type = xcb_atom_get(conn, "WM_PROTOCOLS");
47+	ev.data.data32[0] = xcb_atom_get(conn, "WM_DELETE_WINDOW");
48+	ev.data.data32[1] = XCB_CURRENT_TIME;
49+
50+	xcb_send_event(conn, 0, win, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
51+}
52+
53+int
54+main(int argc, char **argv)
55+{	
56+	xcb_window_t win = 0;
57+
58+	if (argc < 2)
59+		usage(argv[0]);
60+
61+	init_xcb(&conn);
62+
63+	/* assume remaining arguments are windows */
64+	while (*argv)
65+		win = strtoul(*argv++, NULL, 16);
66+
67+		xcb_icccm_get_wm_protocols_reply_t reply;
68+		unsigned int i = 0;
69+		bool got = false;
70+
71+		if (xcb_icccm_get_wm_protocols_reply(conn, xcb_icccm_get_wm_protocols(conn, win, xcb_atom_get(conn, "WM_PROTOCOLS")), &reply, NULL)) {
72+			for (; i != reply.atoms_len; ++i)
73+				if ((got = reply.atoms[i] == xcb_atom_get(conn, "WM_DELETE_WINDOW")))
74+					break;
75+
76+			xcb_icccm_get_wm_protocols_reply_wipe(&reply);
77+		}
78+		
79+		if (got)
80+			delete_window(win);
81+		else
82+			xcb_kill_client(conn, win);
83+
84+	xcb_flush(conn);
85+
86+	kill_xcb(&conn);
87+
88+	return 0;
89+}
+105, -0
  1@@ -0,0 +1,105 @@
  2+#include <err.h>
  3+#include <stdlib.h>
  4+#include <string.h>
  5+#include <xcb/xcb.h>
  6+
  7+#include "util.h"
  8+
  9+void
 10+init_xcb(xcb_connection_t **con)
 11+{
 12+	*con = xcb_connect(NULL, NULL);
 13+	if (xcb_connection_has_error(*con))
 14+		errx(1, "unable connect to the X server");
 15+}
 16+
 17+void
 18+kill_xcb(xcb_connection_t **con)
 19+{
 20+	if (*con)
 21+		xcb_disconnect(*con);
 22+}
 23+
 24+void
 25+get_screen(xcb_connection_t *con, xcb_screen_t **scr)
 26+{
 27+	*scr = xcb_setup_roots_iterator(xcb_get_setup(con)).data;
 28+	if (*scr == NULL)
 29+		errx(1, "unable to retrieve screen informations");
 30+}
 31+
 32+int
 33+exists(xcb_connection_t *con, xcb_window_t w)
 34+{
 35+	xcb_get_window_attributes_cookie_t c;
 36+	xcb_get_window_attributes_reply_t  *r;
 37+
 38+	c = xcb_get_window_attributes(con, w);
 39+	r = xcb_get_window_attributes_reply(con, c, NULL);
 40+
 41+	if (r == NULL)
 42+		return 0;
 43+
 44+	free(r);
 45+	return 1;
 46+}
 47+
 48+int
 49+mapped(xcb_connection_t *con, xcb_window_t w)
 50+{
 51+	int ms;
 52+	xcb_get_window_attributes_cookie_t c;
 53+	xcb_get_window_attributes_reply_t  *r;
 54+
 55+	c = xcb_get_window_attributes(con, w);
 56+	r = xcb_get_window_attributes_reply(con, c, NULL);
 57+
 58+	if (r == NULL)
 59+		return 0;
 60+
 61+	ms = r->map_state;
 62+
 63+	free(r);
 64+	return ms == XCB_MAP_STATE_VIEWABLE;
 65+}
 66+
 67+int
 68+ignore(xcb_connection_t *con, xcb_window_t w)
 69+{
 70+	int or;
 71+	xcb_get_window_attributes_cookie_t c;
 72+	xcb_get_window_attributes_reply_t  *r;
 73+
 74+	c = xcb_get_window_attributes(con, w);
 75+	r = xcb_get_window_attributes_reply(con, c, NULL);
 76+
 77+	if (r == NULL)
 78+		return 0;
 79+
 80+	or = r->override_redirect;
 81+
 82+	free(r);
 83+	return or;
 84+}
 85+
 86+int
 87+get_windows(xcb_connection_t *con, xcb_window_t w, xcb_window_t **l)
 88+{
 89+	uint32_t childnum = 0;
 90+	xcb_query_tree_cookie_t c;
 91+	xcb_query_tree_reply_t *r;
 92+
 93+	c = xcb_query_tree(con, w);
 94+	r = xcb_query_tree_reply(con, c, NULL);
 95+	if (r == NULL)
 96+		errx(1, "0x%08x: no such window", w);
 97+
 98+	*l = malloc(sizeof(xcb_window_t) * r->children_len);
 99+	memcpy(*l, xcb_query_tree_children(r),
100+			sizeof(xcb_window_t) * r->children_len);
101+
102+	childnum = r->children_len;
103+
104+	free(r);
105+	return childnum;
106+}
+14, -0
 1@@ -0,0 +1,14 @@
 2+#ifndef UTIL_H__
 3+#define UTIL_H__
 4+
 5+void init_xcb(xcb_connection_t **);
 6+void kill_xcb(xcb_connection_t **);
 7+
 8+void get_screen(xcb_connection_t *, xcb_screen_t **);
 9+int get_windows(xcb_connection_t *, xcb_window_t, xcb_window_t **);
10+
11+int exists(xcb_connection_t *, xcb_window_t);
12+int mapped(xcb_connection_t *, xcb_window_t);
13+int ignore(xcb_connection_t *, xcb_window_t);
14+
15+#endif
+49, -0
 1@@ -0,0 +1,49 @@
 2+#!/bin/sh
 3+
 4+. ~/.theme
 5+
 6+if [ $# -ne 1 ]; then
 7+    echo "Usage: $0 {up|down|left|right}"
 8+    exit 1
 9+fi
10+
11+case $1 in
12+    up)
13+        dx=0
14+        dy=-40
15+        ;;
16+    down)
17+        dx=0
18+        dy=40
19+        ;;
20+    left)
21+        dx=-40
22+        dy=0
23+        ;;
24+    right)
25+        dx=40
26+        dy=0
27+        ;;
28+    *)
29+        echo "Invalid direction. Use: up, down, left, right"
30+        exit 1
31+        ;;
32+esac
33+
34+CUR=$(pfw)
35+geom=$(wattr xywh $CUR)
36+set -- $geom
37+x=$1; y=$2; w=$3; h=$4
38+center_x=$((x + w/2))
39+center_y=$((y + h/2))
40+wmp -a $center_x $center_y
41+
42+wmv $dx $dy $CUR
43+
44+geom=$(wattr xywh $CUR)
45+set -- $geom
46+x=$1; y=$2; w=$3; h=$4
47+center_x=$((x + w/2))
48+center_y=$((y + h/2))
49+wmp -a $center_x $center_y
50+
+45, -0
 1@@ -0,0 +1,45 @@
 2+#!/bin/bash
 3+wid=$(pfw)
 4+root_wid=$(lsw -r | head -n 1)
 5+screen_w=$(wattr w $root_wid)
 6+screen_h=$(wattr h $root_wid)
 7+win_w=$(wattr w $wid)
 8+win_h=$(wattr h $wid)
 9+
10+border=${TBW}
11+border_total=$((border * 2))
12+
13+margin_x=${2:-0}
14+margin_y=$((${3:-0}))
15+
16+case $1 in
17+    lu)
18+        pos_x=$margin_x
19+        pos_y=$margin_y
20+        ;;
21+    ld)
22+        pos_x=$margin_x
23+        pos_y=$((screen_h - win_h - margin_y - border_total))
24+        ;;
25+    ru)
26+        pos_x=$((screen_w - win_w - margin_x - border_total))
27+        pos_y=$margin_y
28+        ;;
29+    rd)
30+        pos_x=$((screen_w - win_w - margin_x - border_total))
31+        pos_y=$((screen_h - win_h - margin_y - border_total))
32+        ;;
33+    *)
34+        echo "Неверный аргумент: $1"
35+        exit 1
36+        ;;
37+esac
38+
39+[ $pos_x -lt 0 ] && pos_x=0
40+[ $pos_y -lt 0 ] && pos_y=0
41+
42+wtp $pos_x $pos_y $win_w $win_h $wid
43+
44+center_x=$((pos_x + win_w / 2))
45+center_y=$((pos_y + win_h / 2))
46+#wmp -a $center_x $center_y
+40, -0
 1@@ -0,0 +1,40 @@
 2+#!/bin/sh
 3+
 4+. ~/.theme
 5+
 6+COLORS="
 7+FF0000 FF1100 FF2200 FF3300 FF4400 FF5500 FF6600 FF7700 FF8800 FF9900
 8+FFAA00 FFBB00 FFCC00 FFDD00 FFEE00 FFFF00 EEFF00 DDFF00 CCFF00 BBFF00
 9+AAFF00 99FF00 88FF00 77FF00 66FF00 55FF00 44FF00 33FF00 22FF00 11FF00
10+00FF00 00FF11 00FF22 00FF33 00FF44 00FF55 00FF66 00FF77 00FF88 00FF99
11+00FFAA 00FFBB 00FFCC 00FFDD 00FFEE 00FFFF 00EEFF 00DDFF 00CCFF 00BBFF
12+00AAFF 0099FF 0088FF 0077FF 0066FF 0055FF 0044FF 0033FF 0022FF 0011FF
13+0000FF 1100FF 2200FF 3300FF 4400FF 5500FF 6600FF 7700FF 8800FF 9900FF
14+AA00FF BB00FF CC00FF DD00FF EE00FF FF00FF FF00EE FF00DD FF00CC FF00BB
15+FF00AA FF0099 FF0088 FF0077 FF0066 FF0055 FF0044 FF0033 FF0022 FF0011
16+"
17+
18+
19+FREQ=${FREQ:-0.08}
20+
21+while :; do
22+    for c in $COLORS; do
23+        CUR=$(pfw)
24+	case "$1" in
25+            -I)
26+                chwb2 -I $c -O $OBC -i $IBW -o $OBW -w $CUR &
27+		sleep $FREQ
28+		pkill chwb2
29+                ;;
30+            -O)
31+                chwb2 -I $ACTIVE -O $c -i $IBW -o $OBW -w $CUR &
32+		sleep $FREQ
33+		pkill chwb2
34+                ;;
35+        -1)
36+                chwb -s "$TBW" -c "$c" "$CUR" &
37+        sleep "$FREQ"
38+	esac
39+    done
40+done
41+
+80, -0
 1@@ -0,0 +1,80 @@
 2+#!/bin/sh
 3+#
 4+# wmutils/contrib>: snap.sh, 9/12/15 kekler 
 5+# snaps focued window to the left, right, top, or bottom edge
 6+
 7+usage() {
 8+    echo "usage: $(basename $0) <direction>" >&2
 9+    exit 1
10+}
11+
12+# default values for gaps and master area
13+TOP_PANEL=${PANEL:-20}
14+GAP=${GAP:-5}
15+
16+# get current window id and its borderwidth
17+PFW=$(pfw)
18+BW=$(wattr b $PFW)
19+
20+# get root window's size
21+ROOT=$(lsw -r)
22+SW=$(wattr w $ROOT)
23+SH=$(wattr h $ROOT)
24+
25+# calculate usable screen size (without borders and gaps)
26+SH=$((SH - TOP_PANEL))
27+
28+snap_up() 
29+{
30+    wtp $GAP $((GAP + TOP_PANEL)) $((SW - 2*GAP - 2*BW)) $((SH/2 - 2*BW - GAP - GAP/2)) $PFW
31+}
32+
33+snap_right() 
34+{
35+    wtp $((SW - SW/2 + GAP/2)) $((GAP + TOP_PANEL)) $((SW/2 - 2*BW - GAP - GAP/2)) $((SH - 2*BW - 2*GAP)) $PFW
36+}
37+
38+snap_down() 
39+{
40+    wtp $GAP $((SH - SH/2 + GAP/2 + TOP_PANEL)) $((SW - 2*GAP - 2*BW)) $((SH/2 - 2*BW - GAP - GAP/2)) $PFW
41+}
42+
43+snap_left()
44+{
45+    wtp $GAP $((GAP + TOP_PANEL)) $((SW/2 - 2*BW - GAP - GAP/2)) $((SH - 2*BW - 2*GAP)) $PFW
46+}
47+
48+HSW=$((SW/2 - 2*BW - GAP - GAP/2))
49+HSH=$((SH/2 - 2*BW - GAP - GAP/2))
50+
51+snap_tr()
52+{
53+    wtp $((SW - SW/2 + GAP/2)) $((GAP + TOP_PANEL)) $HSW $HSH $PFW
54+}
55+
56+snap_br()
57+{
58+    wtp $((SW - SW/2 + GAP/2)) $((SH - SH/2 + GAP/2 + TOP_PANEL)) $HSW $HSH $PFW
59+}
60+
61+snap_tl()
62+{
63+    wtp $GAP $((GAP + TOP_PANEL)) $HSW $HSH $PFW
64+}
65+
66+snap_bl()
67+{
68+    wtp $GAP $((SH - SH/2 + GAP/2 + TOP_PANEL)) $HSW $HSH $PFW
69+}
70+
71+case $1 in
72+    h|a|west|left)  snap_left ;;
73+    j|s|south|down) snap_down ;;
74+    k|w|north|up)   snap_up ;;
75+    l|d|east|right) snap_right ;;
76+    tr|northeast)   snap_tr ;;
77+    br|southeast)   snap_br ;;
78+    tl|northwest)   snap_tl ;;
79+    bl|southwest)   snap_bl ;;
80+esac
81+
+93, -0
 1@@ -0,0 +1,93 @@
 2+#!/bin/sh
 3+#
 4+# Copyright (c) 2015 Greduan <me@greduan.com>, licensed under the WTFPL license
 5+# Credit where credit is due, the grid algorithm was written by z3bra
 6+#
 7+# When used puts all the windows in a grid and when you focus one of the windows
 8+# it puts all the windows back to their original location and focuses the window
 9+# you switched to.
10+# depends on: wew focus.sh
11+
12+TEMP=$(mktemp) && wattr xywhi $(lsw) > $TEMP
13+NB=$(wc -l < $TEMP) # NB as in NumBer of windows
14+
15+# just safety
16+if [ $NB -eq 1 ]; then
17+    exit
18+fi
19+
20+# user defined
21+BW=${BW:-4} # width of your borders
22+GAP=${GAP:-20} # gap between windows
23+
24+# get monitor dimensions
25+ROOT=$(lsw -r)
26+SW=$(wattr w $ROOT)
27+SH=$(wattr h $ROOT)
28+# reduce screen useable screen area to improve later expressions
29+SW=$(( SW - GAP - 2*BW ))
30+SH=$(( SH - GAP - 2*BW ))
31+
32+# calculate the size of the grid using the square root of the number of windows
33+ROWS=$(echo "sqrt($NB)" | bc)
34+COLS=$ROWS
35+
36+# FOLLOWING WAS WRITTEN BY Z3BRA, don't give me credit for this awesome logic
37+# for each row...
38+for r in `seq 1 $ROWS`; do
39+
40+    # .. if we're on the last row, display all the remaining windows
41+    # eg: if we have 12 windows, the square root would be 3 (truncated).
42+    # so the script would draw a 3x3 grid. This would leave 3 windows apart. To
43+    # avoid this, we set the number of columns of the last row as
44+    #
45+    #    12 - 3 * (3-1)
46+    # => 12 - 3 * 2
47+    # => 12 - 6
48+    # == 6
49+    # so we will have 6 windows on the last row, instead of 3.
50+    # This do not lead to the best looking grid, I know (the best one would be
51+    # 3x4), but it's the simplest algo I've found. Don't forget we're playing
52+    # with shell scripts here, not matlab..
53+    test $r -eq $ROWS && COLS=$(( NB - ROWS * (ROWS-1) ))
54+
55+    # for each column of each row..
56+    for c in `seq 1 $COLS`; do
57+
58+        # exit if we don't have other windows to display
59+        test $(( (r-1)*r + c )) -gt $NB && break
60+
61+        # heigh of windows (total heigh minus gaps and borders)
62+        H=$(( SH/ROWS - GAP - BW ))
63+        # same for width
64+        W=$(( SW/COLS - GAP - BW ))
65+
66+        # and the tricky part..
67+        # The X offset is the width * the actual column (starting from 0) + the
68+        # gaps/borders multiplied by the column number (draw it on a sheet of
69+        # paper like me, it will make much more sense!
70+        X=$(( W * (c-1) + c*(GAP + BW) ))
71+        # same for the Y offset
72+        Y=$(( H * (r-1) + r*(GAP + BW) ))
73+
74+        # finally, teleport the window to the place we just calculated.
75+        # the sed trick is used to get the corresponding line number in the file
76+        # holding the window infos.
77+        wtp $X $Y $W $H $(sed "$(( (r-1)*r + c ))p;d" $TEMP | cut -d\  -f5)
78+    done
79+done
80+# END Z3BRA
81+
82+# listen to wew for our desired event
83+wew -m 4 | while IFS=: read ev wid; do
84+    if [ $ev -eq 4 ]; then
85+        while read line; do
86+            wtp $line
87+        done < $TEMP
88+        focus.sh $wid
89+        killall wew
90+    fi
91+done
92+
93+# cleanup
94+rm $TEMP
+252, -0
  1@@ -0,0 +1,252 @@
  2+#!/bin/sh
  3+
  4+GAP=$1
  5+MASTER_RATIO=0.6
  6+MASTER_SIZE=1
  7+
  8+STATE_DIR="/tmp/2bwm-tiling"
  9+mkdir -p "$STATE_DIR"
 10+
 11+get_master_windows() {
 12+    [ -f "$STATE_DIR/master" ] && cat "$STATE_DIR/master" || echo ""
 13+}
 14+
 15+get_stack_windows() {
 16+    [ -f "$STATE_DIR/stack" ] && cat "$STATE_DIR/stack" || echo ""
 17+}
 18+
 19+save_windows() {
 20+    master="$1"
 21+    stack="$2"
 22+    echo "$master" > "$STATE_DIR/master"
 23+    echo "$stack" > "$STATE_DIR/stack"
 24+}
 25+
 26+get_focused_window() {
 27+    lsw | head -1
 28+}
 29+
 30+tile() {
 31+    root=$(lsw -r)
 32+    windows=$(lsw | grep -v "^$root$")
 33+    
 34+    if [ -z "$windows" ]; then
 35+        exit 0
 36+    fi
 37+
 38+    screen_w=$(wattr w $root)
 39+    screen_h=$(wattr h $root)
 40+    count=$(echo "$windows" | wc -l)
 41+
 42+    if [ $count -eq 3 ]; then
 43+        master=$(echo "$windows" | head -1)
 44+        stack_windows=$(echo "$windows" | tail -n +2)
 45+        
 46+        master_w=$(( (screen_w - GAP * 3) / 2 ))
 47+        wtp $GAP $GAP $master_w $((screen_h - GAP * 2)) $master
 48+        
 49+        stack_x=$((master_w + GAP * 2))
 50+        stack_w=$((screen_w - stack_x - GAP))
 51+        stack_h=$(( (screen_h - GAP * 3) / 2 ))
 52+        
 53+        i=0
 54+        for win in $stack_windows; do
 55+            y=$((GAP + i * (stack_h + GAP)))
 56+            wtp $stack_x $y $stack_w $stack_h $win
 57+            i=$((i + 1))
 58+        done
 59+        exit 0
 60+    fi
 61+
 62+    case $count in
 63+        1) cols=1; rows=1 ;;
 64+        2) cols=2; rows=1 ;;
 65+        4) cols=2; rows=2 ;;
 66+        5|6) cols=3; rows=2 ;;
 67+        7|8) cols=4; rows=2 ;;
 68+        9) cols=3; rows=3 ;;
 69+        *) cols=4; rows=$(( (count + cols - 1) / cols )) ;;
 70+    esac
 71+
 72+    cell_w=$(( (screen_w - GAP * (cols + 1)) / cols ))
 73+    cell_h=$(( (screen_h - GAP * (rows + 1)) / rows ))
 74+
 75+    i=0
 76+    for win in $windows; do
 77+        if [ $i -lt $((cols * rows)) ]; then
 78+            col=$((i % cols))
 79+            row=$((i / cols))
 80+            x=$((GAP + col * (cell_w + GAP)))
 81+            y=$((GAP + row * (cell_h + GAP)))
 82+            wtp $x $y $cell_w $cell_h $win
 83+            i=$((i + 1))
 84+        fi
 85+    done
 86+}
 87+
 88+tile_master_stack() {
 89+    root=$(lsw -r)
 90+    all_windows=$(lsw | grep -v "^$root$")
 91+    
 92+    if [ -z "$all_windows" ]; then
 93+        exit 0
 94+    fi
 95+
 96+    master_windows=$(get_master_windows)
 97+    stack_windows=$(get_stack_windows)
 98+    
 99+    if [ -z "$master_windows" ]; then
100+        master_windows=$(echo "$all_windows" | head -$MASTER_SIZE)
101+        stack_windows=$(echo "$all_windows" | tail -n +$((MASTER_SIZE + 1)))
102+        save_windows "$master_windows" "$stack_windows"
103+    fi
104+
105+    screen_w=$(wattr w $root)
106+    screen_h=$(wattr h $root)
107+    
108+    master_width=$(( (screen_w - GAP * 3) * MASTER_RATIO / 1 ))
109+    stack_width=$((screen_w - master_width - GAP * 3))
110+    
111+    master_count=$(echo "$master_windows" | wc -l)
112+    stack_count=$(echo "$stack_windows" | wc -l)
113+    
114+    if [ $master_count -gt 0 ]; then
115+        master_window_height=$(( (screen_h - GAP * (master_count + 1)) / master_count ))
116+        i=0
117+        for win in $master_windows; do
118+            y=$((GAP + i * (master_window_height + GAP)))
119+            wtp $GAP $y $master_width $master_window_height $win
120+            i=$((i + 1))
121+        done
122+    fi
123+    
124+    if [ $stack_count -gt 0 ]; then
125+        stack_window_height=$(( (screen_h - GAP * (stack_count + 1)) / stack_count ))
126+        i=0
127+        for win in $stack_windows; do
128+            y=$((GAP + i * (stack_window_height + GAP)))
129+            x=$((master_width + GAP * 2))
130+            wtp $x $y $stack_width $stack_window_height $win
131+            i=$((i + 1))
132+        done
133+    fi
134+}
135+
136+focus_master() {
137+    master_windows=$(get_master_windows)
138+    if [ -n "$master_windows" ]; then
139+        first_master=$(echo "$master_windows" | head -1)
140+        chwso -r "$first_master"
141+    fi
142+}
143+
144+focus_next() {
145+    current=$(get_focused_window)
146+    all_windows=$(lsw | grep -v "^$(lsw -r)$")
147+    if [ -n "$all_windows" ]; then
148+        next=$(echo "$all_windows" | grep -A1 "^$current$" | tail -1)
149+        if [ "$next" != "$current" ] && [ -n "$next" ]; then
150+            chwso -r "$next"
151+        else
152+            first=$(echo "$all_windows" | head -1)
153+            chwso -r "$first"
154+        fi
155+    fi
156+}
157+
158+focus_prev() {
159+    current=$(get_focused_window)
160+    all_windows=$(lsw | grep -v "^$(lsw -r)$")
161+    if [ -n "$all_windows" ]; then
162+        prev=$(echo "$all_windows" | grep -B1 "^$current$" | head -1)
163+        if [ "$prev" != "$current" ] && [ -n "$prev" ]; then
164+            chwso -r "$prev"
165+        else
166+            last=$(echo "$all_windows" | tail -1)
167+            chwso -r "$last"
168+        fi
169+    fi
170+}
171+
172+promote_to_master() {
173+    window=$(get_focused_window)
174+    master_windows=$(get_master_windows)
175+    stack_windows=$(get_stack_windows)
176+    
177+    if echo "$stack_windows" | grep -q "^$window$"; then
178+        new_stack=$(echo "$stack_windows" | grep -v "^$window$")
179+        new_master=$(echo -e "$window\n$master_windows" | head -$MASTER_SIZE)
180+        save_windows "$new_master" "$new_stack"
181+        tile_master_stack
182+    fi
183+}
184+
185+demote_to_stack() {
186+    window=$(get_focused_window)
187+    master_windows=$(get_master_windows)
188+    stack_windows=$(get_stack_windows)
189+    
190+    if echo "$master_windows" | grep -q "^$window$"; then
191+        new_master=$(echo "$master_windows" | grep -v "^$window$")
192+        new_stack=$(echo -e "$window\n$stack_windows")
193+        save_windows "$new_master" "$new_stack"
194+        tile_master_stack
195+    fi
196+}
197+
198+swap_master() {
199+    master_windows=$(get_master_windows)
200+    if [ -n "$master_windows" ]; then
201+        first_master=$(echo "$master_windows" | head -1)
202+        second_master=$(echo "$master_windows" | head -2 | tail -1)
203+        if [ -n "$second_master" ]; then
204+            new_master=$(echo "$master_windows" | sed "1s/^$first_master$/$second_master/; 2s/^$second_master$/$first_master/")
205+            save_windows "$new_master" "$(get_stack_windows)"
206+            tile_master_stack
207+            chwso -r "$first_master"
208+        fi
209+    fi
210+}
211+
212+increase_master() {
213+    MASTER_SIZE=$((MASTER_SIZE + 1))
214+    all_windows=$(lsw | grep -v "^$(lsw -r)$")
215+    master_windows=$(echo "$all_windows" | head -$MASTER_SIZE)
216+    stack_windows=$(echo "$all_windows" | tail -n +$((MASTER_SIZE + 1)))
217+    save_windows "$master_windows" "$stack_windows"
218+    tile_master_stack
219+}
220+
221+decrease_master() {
222+    if [ $MASTER_SIZE -gt 1 ]; then
223+        MASTER_SIZE=$((MASTER_SIZE - 1))
224+        all_windows=$(lsw | grep -v "^$(lsw -r)$")
225+        master_windows=$(echo "$all_windows" | head -$MASTER_SIZE)
226+        stack_windows=$(echo "$all_windows" | tail -n +$((MASTER_SIZE + 1)))
227+        save_windows "$master_windows" "$stack_windows"
228+        tile_master_stack
229+    fi
230+}
231+
232+rotate_stack() {
233+    stack_windows=$(get_stack_windows)
234+    if [ -n "$stack_windows" ]; then
235+        first=$(echo "$stack_windows" | head -1)
236+        rest=$(echo "$stack_windows" | tail -n +2)
237+        new_stack=$(echo -e "$rest\n$first")
238+        save_windows "$(get_master_windows)" "$new_stack"
239+        tile_master_stack
240+    fi
241+}
242+
243+rebalance() {
244+    save_windows "" ""
245+    tile_master_stack
246+}
247+
248+if [ $# -eq 0 ]; then
249+    tile
250+    exit 0
251+fi
252+
253+tile
+39, -0
 1@@ -0,0 +1,39 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# arrange windows in a tiled pattern
 6+
 7+# default values for gaps and master area
 8+PANEL=${PANEL:-0}
 9+GAP=${GAP:-20}
10+MASTER=${MASTER:-1400}
11+
12+# get current window id and its borderwidth
13+PFW=$(pfw)
14+BW=$(wattr b $PFW)
15+
16+# get root window's size (beware, multi-head setups...)
17+ROOT=$(lsw -r)
18+SW=$(wattr w $ROOT)
19+SH=$(wattr h $ROOT)
20+
21+# get the number of windows to put in the stacking area
22+MAX=$(lsw|grep -v $PFW|wc -l)
23+
24+# calculate usable screen size (without borders and gaps)
25+SW=$((SW - GAP - 2*BW))
26+SH=$((SH - GAP - PANEL))
27+
28+Y=$((0 + GAP + PANEL))
29+# put current window in master area
30+wtp $GAP $Y $((MASTER - GAP - 2*BW)) $((SH - GAP - 2*BW)) $PFW
31+
32+# and now, stack up all remaining windows on the right
33+X=$((MASTER + GAP))
34+W=$((SW - MASTER - GAP))
35+H=$((SH / MAX - GAP - 2*BW))
36+
37+for wid in $(lsw|grep -v $PFW); do
38+    wtp $X $Y $W $H $wid
39+    Y=$((Y + H + GAP + 2*BW))
40+done
+8, -0
1@@ -0,0 +1,8 @@
2+#!/bin/bash
3+
4+if pgrep -x "rainbow.sh" > /dev/null; then
5+    pkill -x "rainbow.sh"
6+    focus.sh $(pfw)
7+else
8+    $HOME/.wmutils/scripts/rainbow.sh $1 &
9+fi
+41, -0
 1@@ -0,0 +1,41 @@
 2+#!/bin/sh
 3+#
 4+# wildefyr - 2016 (c) MIT
 5+# print window id directly underneath mouse
 6+
 7+# fuck sh
 8+intCheck() {
 9+    test $1 -ne 0 2> /dev/null
10+    test $? -ne 2 || return 1
11+}
12+
13+# find current mouse location or check input for XY coordinates
14+test $# -eq 0 && {
15+    pointerX="$(wmp | cut -d\  -f 1)"
16+    pointerY="$(wmp | cut -d\  -f 2)"
17+} || {
18+    intCheck $1 && pointerX=$1 || return 1
19+    intCheck $2 && pointerY=$2 || return 1
20+}
21+
22+# start from the currently highest stacked window
23+for wid in $(lsw | tac); do
24+    windowX="$(wattr x $wid)"
25+    windowY="$(wattr y $wid)"
26+
27+    # we won't get a match if the left and top edges are greater than X or Y
28+    test "$windowX" -gt "$pointerX" && continue
29+    test "$windowY" -gt "$pointerY" && continue
30+
31+    windowW="$(wattr w $wid)"
32+    windowH="$(wattr h $wid)"
33+
34+    # we won't get a match if the right and bottom edges are less than X or Y
35+    test "$((windowX + windowW))" -lt "$pointerX" && continue
36+    test "$((windowY + windowH))" -lt "$pointerY" && continue
37+
38+    # print match!
39+    printf '%s\n' "$wid" 
40+    unset -v wid
41+    exit
42+done
+51, -0
 1@@ -0,0 +1,51 @@
 2+#!/bin/bash
 3+
 4+LOCKFILE="/tmp/ws_switch.lock"
 5+
 6+wew | while read -r ev wid; do
 7+    if [ -f "$LOCKFILE" ]; then
 8+        continue
 9+    fi
10+    
11+    . $HOME/.theme
12+
13+    case $ev in
14+        CREATE)
15+            if ! wattr o "$wid"; then
16+                (
17+                    sleep 0.15
18+                    if [ ! -f "$LOCKFILE" ] && wattr o "$wid" >/dev/null 2>&1; then
19+                       for w in $(lsw); do
20+                           chwb2 -s "$TBW" -c "$INACTIVE" "$w"
21+                       done
22+                       pkill -f "#chwb2.*$2" 2>/dev/null
23+                       chwb2 -I $ACTIVE -O $OBC -i $IBW -o $OBW  -w "$wid" &
24+                       wtf "$wid"
25+                       tile.sh
26+                    fi
27+                ) &
28+            fi
29+            ;;
30+        MAP)
31+            if [ ! -f "$LOCKFILE" ] && ! wattr o "$wid"; then
32+                for w in $(lsw); do
33+                    chwb2 -s "$TBW" -c "$INACTIVE" "$w"
34+                done
35+                pkill -f "#chwb2.*$2" 2>/dev/null
36+                chwb2 -I $ACTIVE -O $OBC -i $IBW -o $OBW  -w "$wid" &
37+                wtf "$wid"
38+            fi
39+            ;;
40+        ENTER)
41+            if [ ! -f "$LOCKFILE" ] && ! wattr o "$wid"; then
42+                for w in $(lsw); do
43+                    chwb2 -s "$TBW" -c "$INACTIVE" "$w"
44+                done
45+                pkill -f "#chwb2.*$2" 2>/dev/null
46+                chwb2 -I $ACTIVE -O $OBC -i $IBW -o $OBW  -w "$wid" &
47+                wtf "$wid"
48+                chwso -r "$wid"
49+            fi
50+            ;;
51+    esac
52+done
+14, -0
 1@@ -0,0 +1,14 @@
 2+#!/bin/sh
 3+#
 4+# fyr | 2019 (c) MIT
 5+# dmenu wrapper to select windows based on their window title
 6+# use xprop -id $wid WM_NAME or WM_CLASS for better matching
 7+
 8+LINES=$(lsw | wc -l)
 9+
10+wid=$(\
11+    for wid in $(lsw); do
12+        printf '%s\n' "$wid | $(wname $wid)"
13+    done | dmenu -p "Window:" | cut -d\  -f 1)
14+
15+test -n "$wid" && focus.sh "$wid"
+162, -0
  1@@ -0,0 +1,162 @@
  2+#!/bin/sh
  3+# Constructs and groups windows into workspaces to switch between using your favorite keybinder.
  4+
  5+NUM_WS=9
  6+LOCKFILE="/tmp/ws_switch.lock"
  7+
  8+help() {
  9+    cat << EOF
 10+usage: $(basename $0) [-hinp] [-g ws_num] [-m ws_num]
 11+    -h: Displays this message
 12+    -i: Initialize workspaces. Should be called once in a startup script.
 13+    -n: Move up one workspace
 14+    -p: Move down one workspace
 15+    -g, <ws_num>: go to the workspace specified by <ws_num>
 16+    -m, <ws_num>: move the currently focused window to the worskpace specified by <ws_num>
 17+EOF
 18+    exit 1
 19+}
 20+
 21+# Save focused window for current workspace
 22+save_ws_focus() {
 23+    ws=$1
 24+    focused=$(pfw 2>/dev/null)
 25+    if [ -n "$focused" ]; then
 26+        echo "$focused" > "/tmp/workspaces/ws${ws}_focus"
 27+    fi
 28+}
 29+
 30+# Restore focused window for workspace
 31+restore_ws_focus() {
 32+    ws=$1
 33+    focus_file="/tmp/workspaces/ws${ws}_focus"
 34+    
 35+    if [ -f "$focus_file" ]; then
 36+        wid=$(cat "$focus_file")
 37+        if wattr "$wid" 2>/dev/null; then
 38+            echo "$wid"
 39+            return 0
 40+        fi
 41+    fi
 42+    
 43+    # Get first window from workspace file
 44+    ws_file="/tmp/workspaces/ws$ws"
 45+    if [ -f "$ws_file" ]; then
 46+        head -n1 "$ws_file"
 47+    else
 48+        echo ""
 49+    fi
 50+}
 51+
 52+# Initializes us in workspace 0.
 53+ws_init() {
 54+    mkdir -p /tmp/workspaces/
 55+    i=0
 56+    while [ $i -le $NUM_WS ]; do
 57+        :> /tmp/workspaces/ws"$i"
 58+        i=$(expr $i + 1)
 59+    done
 60+    echo 0 > /tmp/workspaces/curr
 61+}
 62+
 63+# Saves all mapped windows to the current workspace.
 64+save_ws() {
 65+    curr=$(cat /tmp/workspaces/curr)
 66+    lsw > /tmp/workspaces/ws"$curr"
 67+}
 68+
 69+move_to_ws() {
 70+    ws_num=$1
 71+    if [ $ws_num -gt $NUM_WS ] || [ $ws_num -lt 0 ]; then
 72+        echo "Workspace not found"
 73+        return
 74+    fi
 75+    curr_ws=$(cat /tmp/workspaces/curr);
 76+    if [ $ws_num == $curr_ws ]; then
 77+        # same workspace. ignore flicker
 78+        return
 79+    fi
 80+    
 81+    touch "$LOCKFILE"
 82+    
 83+    # Save current focus before switching
 84+    save_ws_focus "$curr_ws"
 85+    
 86+    save_ws
 87+    curr_windows=$(lsw)
 88+    if [ "$curr_windows" ]; then
 89+        mapw -u $(lsw)
 90+    fi
 91+    new_windows="$(cat /tmp/workspaces/ws$ws_num)"
 92+    if [ "$new_windows" ]; then
 93+        mapw -m $new_windows
 94+    fi
 95+    echo $ws_num > /tmp/workspaces/curr
 96+    
 97+    # Restore focus for new workspace
 98+    focused=$(restore_ws_focus "$ws_num")
 99+    if [ -n "$focused" ] && wattr "$focused" 2>/dev/null; then
100+        wtf "$focused"
101+    fi
102+    
103+    (
104+        sleep 0.3
105+        rm -f "$LOCKFILE"
106+    ) &
107+}
108+
109+next_ws() {
110+    curr=$(cat /tmp/workspaces/curr)
111+    curr=$(expr $curr + 1)
112+    if [ $curr -gt $NUM_WS ]; then
113+        curr=0
114+    fi
115+    move_to_ws $curr
116+}
117+
118+prev_ws() {
119+    curr=$(cat /tmp/workspaces/curr)
120+    curr=$(expr $curr - 1)
121+    if [ $curr -lt 0 ]; then
122+        curr=$NUM_WS
123+    fi
124+    move_to_ws $curr
125+}
126+
127+move_focused_window() {
128+    ws_num=$1
129+    if [ $ws_num -gt $NUM_WS ] || [ $ws_num -lt 0 ]; then
130+        echo "Workspace not found"
131+        return
132+    fi
133+    wid=$(pfw)
134+    curr_ws=$(cat /tmp/workspaces/curr);
135+    if [ $ws_num != $curr_ws ]; then
136+        touch "$LOCKFILE"
137+        
138+        pfw >> /tmp/workspaces/ws"$1"
139+        mapw -u $wid
140+        
141+        (
142+            sleep 0.3
143+            rm -f "$LOCKFILE"
144+        ) &
145+    fi
146+}
147+
148+while getopts ":m:g:npi" opt; do
149+    case $opt in
150+        n)
151+            next_ws;;
152+        p)
153+            prev_ws;;
154+        g)
155+            move_to_ws $OPTARG;;
156+        m)
157+            move_focused_window $OPTARG;;
158+        i)
159+            ws_init;;
160+        \?)
161+            help;;
162+    esac
163+done
+14, -0
 1@@ -0,0 +1,14 @@
 2+Copyright (c) 2014-2015, brosephs <dcat at iotek dot org>,
 3+                             	  <willy at mailoo dot org>
 4+
 5+Permission to use, copy, modify, and/or distribute this software for any
 6+purpose with or without fee is hereby granted, provided that the above
 7+copyright notice and this permission notice appear in all copies.
 8+
 9+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
10+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
11+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
12+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
13+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
14+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
15+PERFORMANCE OF THIS SOFTWARE.
+99, -0
  1@@ -0,0 +1,99 @@
  2+contrib
  3+=======
  4+
  5+Repository hosting inspirational wmutils snippets.
  6+
  7+### tile.sh
  8+Arrange your windows in a tiled pattern consisting of one master area, and a
  9+stacking area. Uses `$GAP` and `$MASTER` from environment.
 10+
 11+    usage: tile.sh
 12+
 13+### fullscreen.sh
 14+Set a window in fullscreen mode, removing borders from it and putting it in
 15+front of all other windows. There can only be one window in fullscreen at a
 16+time. Uses `$FSFILE` from environment.
 17+
 18+    usage: fullscreen.sh <wid>
 19+
 20+### focus.sh
 21+Focus either a specific window, or the next/previous window in the stack. Then
 22+set borders accordingly. Uses `$BW`, `$ACTIVE` and `$INACTIVE` from environment.
 23+
 24+    usage: focus.sh <next|prev|wid>
 25+
 26+### focus\_watcher.sh
 27+Focus a new window (using focus.sh) upon its creation.
 28+
 29+Depends on `wew(1)` (opt repo)  and `focus.sh` (contrib repo)
 30+
 31+    usage: focus_watcher.sh
 32+
 33+### rainbow.sh
 34+Make the current window border cycle all the rainbow colors. Uses `$FREQ` from
 35+environment.
 36+
 37+    usage: rainbow.sh
 38+
 39+### closest.sh
 40+Focus the closest window in a specific direction.
 41+
 42+    usage: closest.sh <direction>
 43+
 44+### underneath.sh
 45+Produce window id directely underneath cursor.
 46+
 47+Example sxhkd binding:
 48+
 49+    ~button1
 50+        focus.sh $(underneath.sh)
 51+
 52+### switch\_grid.sh
 53+A simpler version of OS X Mission Control feature, or GNOME Shell's Overview
 54+feature.
 55+
 56+Depends on `wew(1)` (opt repo)  and `focus.sh` (contrib repo)
 57+
 58+    usage: switch_grid.sh
 59+
 60+### deletelock.sh
 61+Set a custom xprop variable which can be used to test if a window is able to
 62+be deleted or not when using killw in a custom script with `wew(1)`.
 63+
 64+Depends on xorg-xprop
 65+
 66+    usage: deletelock.sh <lock|unlock|toggle|status> <wid>
 67+
 68+### groups.sh
 69+Adds group-like capabilities, sorta like those you find in CWM and such WMs.
 70+
 71+    usage: groups.sh [-hCU] [-c wid] [-s wid group] [-tmMu group]
 72+           -h shows this help
 73+           -c cleans WID from group files (and makes it visible)
 74+           -C runs cleanup routine
 75+           -s sets WID's group
 76+           -t toggle group visibility state
 77+           -m maps (shows) group
 78+           -M maps group and unmaps all other groups
 79+           -u unmaps (hides) group
 80+           -U unmaps all the groups
 81+
 82+### wmenu.sh
 83+
 84+Uses wname and dmenu to produce a window selection menu similar to CWM's
 85+menu-window option. Upon selection the script outputs the chosen window id that
 86+can then be piped to a focus script.
 87+
 88+### workspace.sh
 89+Groups windows into workspaces. Stores the current workspace index in /tmp/workspaces/curr by default.
 90+
 91+	usage: workspace.sh [-hinp] [-g ws_num] [-m ws_num] 
 92+		-h: Displays this message
 93+		-i: Initialize workspaces. Should be called once in a startup script.
 94+		-n: Move up one workspace
 95+		-p: Move down one workspace
 96+		-g, <ws_num>: go to the workspace specified by <ws_num>
 97+		-m, <ws_num>: move the currently focused window to the worskpace specified by <ws_num>
 98+
 99+
100+*... to be continued*
+40, -0
 1@@ -0,0 +1,40 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# find and focus the closest window in a specific direction
 6+# depends on: focus.sh
 7+
 8+# get current window id
 9+CUR=$(pfw)
10+
11+usage() {
12+    echo "usage: $(basename $0) <direction>" >&2
13+    exit 1
14+}
15+
16+next_west() {
17+    lsw | xargs wattr xi | sort -nr | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
18+}
19+
20+next_east() {
21+    lsw | xargs wattr xi | sort -n | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
22+}
23+
24+next_north() {
25+    lsw | xargs wattr yi | sort -nr | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
26+}
27+
28+next_south() {
29+    lsw | xargs wattr yi | sort -n | sed "0,/$CUR/d" | sed "1s/^[0-9]* //p;d"
30+}
31+
32+# Use the specification of your choice: WASD, HJKL, ←↑↓→, west/north/south/east
33+case $1 in
34+    h|a|west|left)  wid=$(next_west)  ;;
35+    j|s|south|down) wid=$(next_south) ;;
36+    k|w|north|up)   wid=$(next_north) ;;
37+    l|d|east|right) wid=$(next_east)  ;;
38+    *)              usage             ;;
39+esac
40+
41+test ! -z "$wid" && focus.sh "$wid"
+54, -0
 1@@ -0,0 +1,54 @@
 2+#!/bin/sh
 3+#
 4+# wildefyr - 2015 (c) wtfpl
 5+# toggle delete lock for current window
 6+
 7+usage() {
 8+    echo "usage: $(basename $0) <lock|unlock|toggle|status> <wid>"
 9+    exit 1
10+}
11+
12+wid=$(pfw)
13+
14+case $2 in
15+    0x*)
16+        wid=$2
17+        ;;
18+    *)
19+        usage
20+        ;;
21+esac
22+
23+case $1 in
24+    lock)
25+        xprop -id $wid -f _WMUTILS_DELETELOCK 8i -set _WMUTILS_DELETELOCK '1'
26+        ;;
27+    unlock)
28+        xprop -id $wid -remove _WMUTILS_DELETELOCK
29+        ;;
30+    toggle)
31+        lockStatus=$(xprop -id $wid _WMUTILS_DELETELOCK | cut -d\  -f 3)
32+        case $lockStatus in
33+            1)
34+                $(basename $0) unlock $wid 
35+                ;;
36+            *)
37+                $(basename $0) lock $wid 
38+                ;;
39+        esac
40+        ;;
41+    status)
42+        lockStatus=$(xprop -id $wid _WMUTILS_DELETELOCK | cut -d\  -f 3)
43+        case $lockStatus in
44+            1)
45+                echo "1"
46+                ;;
47+            *)
48+                echo "0"
49+                ;;
50+        esac
51+        ;;
52+    *)
53+        usage
54+        ;;
55+esac
+50, -0
 1@@ -0,0 +1,50 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# window focus wrapper that sets borders and can focus next/previous window
 6+
 7+BW=${BW:-2}                    # border width
 8+ACTIVE=${ACTIVE:-0xffffff}     # active border color
 9+INACTIVE=${INACTIVE:-0x333333} # inactive border color
10+
11+# get current window id
12+CUR=$(pfw)
13+
14+usage() {
15+    echo "usage: $(basename $0) <next|prev|wid>"
16+    exit 1
17+}
18+
19+setborder() {
20+    ROOT=$(lsw -r)
21+
22+    # check if window exists
23+    wattr $2 || return
24+
25+    # do not modify border of fullscreen windows
26+    test "$(wattr xywh $2)" = "$(wattr xywh $ROOT)" && return
27+
28+    case $1 in
29+        active)   chwb -s $BW -c $ACTIVE $2 ;;
30+        inactive) chwb -s $BW -c $INACTIVE $2 ;;
31+    esac
32+}
33+
34+case $1 in
35+    next) wid=$(lsw|grep -v $CUR|sed '1 p;d') ;;
36+    prev) wid=$(lsw|grep -v $CUR|sed '$ p;d') ;;
37+    0x*) wattr $1 && wid=$1 ;;
38+    *) usage ;;
39+esac
40+
41+# exit if we can't find another window to focus
42+test -z "$wid" && echo "$(basename $0): can't find a window to focus" >&2 && exit 1
43+
44+setborder inactive $CUR # set inactive border on current window
45+setborder active $wid   # activate the new window
46+chwso -r $wid           # put it on top of the stack
47+wtf $wid                # set focus on it
48+
49+# you might want to remove this for sloppy focus
50+wmp -a $(wattr xy $wid) # move the mouse cursor to
51+wmp -r $(wattr wh $wid) # .. its bottom right corner
+12, -0
 1@@ -0,0 +1,12 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# focus a window when it is created
 6+# depends on: wew focus.sh
 7+
 8+wew | while read ev wid args; do
 9+    case $ev in
10+        # occurs on mapping requests
11+        MAP) wattr o $wid || focus.sh $wid ;;
12+    esac
13+done
+41, -0
 1@@ -0,0 +1,41 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# toggle the fullscreen state of a window
 6+# depends on: focus.sh
 7+
 8+# this file is used to store the previous geometry of a window
 9+FSFILE=${FSFILE:-~/.fwin}
10+
11+# it's pretty simple, but anyway...
12+usage() {
13+    echo "usage: $(basename $0) <wid>"
14+    exit 1
15+}
16+
17+# exit if no argument given
18+test -z "$1" && usage
19+
20+# this will unset the fullscreen state of any fullscreen window if there is one.
21+# this way, there will only be one window in fullscreen at a time, and no window
22+# will loose their previous geometry info
23+test -f $FSFILE && wtp $(cat $FSFILE)
24+
25+# if file exist and contain our window id, it means that out window is in
26+# fullscreen mode
27+if test -f $FSFILE && grep -q $1 $FSFILE; then
28+    # if the window we removed was our window, delete the file, so we can
29+    # fullscreen it again later 
30+    rm -f $FSFILE
31+
32+else
33+    # if not, then put the current window in fullscreen mode, after saving its
34+    # geometry and id to $FSFILE we also remove any border from this window.
35+    wattr xywhi $1 > $FSFILE
36+    chwb -s 0 $1
37+    wtp $(wattr xywh `lsw -r`) $1
38+fi
39+
40+# now focus the window, and put it in front, no matter which state we're in, and
41+# put the cursor on its bottom-right corner (for consistency)
42+focus.sh $1
+223, -0
  1@@ -0,0 +1,223 @@
  2+#!/bin/sh
  3+#
  4+# Copyright (c) 2015 Greduan <me@greduan.com>, licensed under the WTFPL
  5+# Adds group-like capabilities, sorta like those you find in CWM and such WMs
  6+
  7+usage() {
  8+    cat << EOF
  9+usage: $(basename $0) [-hCU] [-c wid] [-s wid group] [-tmMu group]
 10+       -h shows this help
 11+       -c cleans WID from group files (and makes it visible)
 12+       -C runs cleanup routine
 13+       -s sets WID's group
 14+       -t toggle group visibility state
 15+       -m maps (shows) group
 16+       -M maps group and unmaps all other groups
 17+       -u unmaps (hides) group
 18+       -U unmaps all the groups
 19+EOF
 20+
 21+    exit 1
 22+}
 23+
 24+# test for no arguments
 25+test $# -eq 0 && usage
 26+
 27+# I suggest it's under /tmp or somewhere that gets cleaned up at reboot or gets
 28+# cleaned up after X stops running
 29+FSDIR=${FSDIR:-/tmp/groups.sh}
 30+
 31+# define our functions
 32+
 33+# clean WID ($1) from group files
 34+clean_wid() {
 35+    t=$(mktemp /tmp/groups.XXXXXX)
 36+    for x in $(ls $FSDIR/group.*); do
 37+        sed "/$1/d" "$x" >"$t"
 38+        mv "$t" "$x"
 39+    done
 40+    rm -f "$t"
 41+}
 42+
 43+# cleans group ($1) from (in)active files
 44+clean_status() {
 45+    t=$(mktemp /tmp/groups.XXXXXX)
 46+    sed "/$1/d" $FSDIR/active >"$t"
 47+    mv "$t" $FSDIR/active
 48+    sed "/$1/d" $FSDIR/inactive >"$t"
 49+    mv "$t" $FSDIR/inactive
 50+}
 51+
 52+# shows all the windows in group ($1)
 53+map_group() {
 54+    # safety
 55+    if ! grep -q $1 < $FSDIR/all; then
 56+        echo "Group doesn't exist"
 57+        exit 1
 58+    fi
 59+
 60+    # clean statuses
 61+    clean_status $1
 62+    # add to active
 63+    echo $1 >> $FSDIR/active
 64+
 65+    # loop through group and map windows
 66+	xargs mapw -m <$FSDIR/group.$1
 67+}
 68+
 69+# hides all the windows in group ($1)
 70+unmap_group() {
 71+    # safety
 72+    if ! grep -q $1 < $FSDIR/all; then
 73+        echo "Group doesn't exist"
 74+        exit 1
 75+    fi
 76+
 77+    # clean statuses
 78+    clean_status $1
 79+    # add to inactive
 80+    echo $1 >> $FSDIR/inactive
 81+
 82+    # loop through group and unmap windows
 83+    while read line; do
 84+        mapw -u $line
 85+    done < $FSDIR/group.$1
 86+}
 87+
 88+# assigns WID ($1) to the group ($2)
 89+set_group() {
 90+    #so that neither grep nor ls in clean_wid complain
 91+    #when group.$2 does not exist
 92+    touch $FSDIR/group.$2
 93+
 94+    # make sure we've no duplicates
 95+    clean_wid $1
 96+    clean_status $2
 97+
 98+    # insert WID into new group if not already there
 99+    grep -q $1 < $FSDIR/group.$2 || \
100+    echo $1 >> $FSDIR/group.$2
101+
102+    # if we can't find the group add it to groups and make it active
103+    grep -q $2 < $FSDIR/all || \
104+    echo $2 >> $FSDIR/all && \
105+    echo $2 >> $FSDIR/active
106+
107+    # map WID if group is active
108+    grep -q $2 < $FSDIR/active && \
109+    mapw -m $1
110+
111+    # unmap WID if group is inactive
112+    grep -q $2 < $FSDIR/inactive && \
113+    mapw -u $1
114+}
115+
116+# toggles visibility state of all the windows in group ($1)
117+toggle_group() {
118+    # safety
119+    if ! grep -q $1 < $FSDIR/all; then
120+        echo "Group doesn't exist"
121+        return
122+    fi
123+
124+    # search through active groups first
125+    grep -q $1 < $FSDIR/active && \
126+    unmap_group $1 && \
127+    return
128+
129+    # search through inactive groups next
130+    grep -q $1 < $FSDIR/inactive && \
131+    map_group $1 && \
132+    return
133+}
134+
135+# removes all the unexistent WIDs from groups
136+# removes all group files that don't exist
137+# removes from 'all' file all groups that don't exist
138+cleanup_everything() {
139+    # clean WIDs that don't exist
140+    # using `cat` instead of `<` because error suppression
141+    cat $FSDIR/group.* 2>/dev/null | while read wid; do
142+        wattr $wid || \
143+        clean_wid $wid
144+    done
145+
146+    # clean group files that are empty
147+    for file in $FSDIR/group.*; do
148+        # is the group empty?
149+        if [ ! -s $file ]; then
150+            rm -f $file
151+        fi
152+    done
153+
154+    # remove groups that don't exist from 'all'
155+    while read line; do
156+        if [ ! -f $FSDIR/group.$line ]; then
157+            t=$(mktemp /tmp/groups.XXXXXX)
158+            sed "/$line/d" $FSDIR/all >"$t"
159+            mv "$t" $FSDIR/all
160+            clean_status $line
161+        fi
162+    done < $FSDIR/all
163+}
164+
165+# actual run logic (including arguments and such)
166+
167+# check $FSDIR exists
168+test -d $FSDIR || mkdir -p $FSDIR
169+
170+# touch all the files
171+test -f $FSDIR/active || :> $FSDIR/active
172+test -f $FSDIR/inactive || :> $FSDIR/inactive
173+test -f $FSDIR/all || :> $FSDIR/all
174+
175+cleanup_everything
176+
177+# getopts yo
178+while getopts "hc:Cs:t:m:M:u:U" opt; do
179+    case $opt in
180+        h)
181+            usage
182+            ;;
183+        c)
184+            clean_wid $OPTARG
185+            mapw -m $OPTARG
186+            break
187+            ;;
188+        C)
189+            cleanup_everything
190+            break
191+            ;;
192+        s)
193+            set_group $OPTARG $(eval echo "\$$OPTIND")
194+            break
195+            ;;
196+        t)
197+            toggle_group $OPTARG
198+            break
199+            ;;
200+        m)
201+            map_group $OPTARG
202+            break
203+            ;;
204+        M)
205+            for file in $FSDIR/group.*; do
206+                group=${file##*.}
207+                unmap_group $group
208+            done
209+            map_group $OPTARG
210+            break
211+            ;;
212+        u)
213+            unmap_group $OPTARG
214+            break
215+            ;;
216+        U)
217+            for file in $FSDIR/group.*; do
218+                group=${file##*.}
219+                unmap_group $group
220+            done
221+            break
222+            ;;
223+    esac
224+done
+38, -0
 1@@ -0,0 +1,38 @@
 2+include config.mk
 3+
 4+HDR = arg.h util.h
 5+SRC =           \
 6+	killwa.c
 7+
 8+OBJ = $(SRC:.c=.o)
 9+BIN = $(SRC:.c=)
10+
11+.POSIX:
12+.SUFFIXES: .1 .1.gz
13+
14+all: binutils
15+
16+binutils: $(BIN)
17+
18+$(OBJ): $(HDR) util.o
19+
20+.o:
21+	@echo "LD $@"
22+	@$(LD) $< util.o -o $@ $(LDFLAGS)
23+
24+.c.o:
25+	@echo "CC $<"
26+	@$(CC) -c $< -o $@ $(CFLAGS)
27+
28+install: $(BIN)
29+	mkdir -p $(DESTDIR)$(PREFIX)/bin/
30+	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/
31+
32+uninstall:
33+	@echo "uninstalling binaries"
34+	@for util in $(BIN); do \
35+		rm -f $(DESTDIR)$(PREFIX)/bin/$$util; \
36+	done
37+
38+clean :
39+	rm -f $(OBJ) $(BIN) util.o
+63, -0
 1@@ -0,0 +1,63 @@
 2+/*
 3+ * Copy me if you can.
 4+ * by 20h
 5+ */
 6+
 7+#ifndef ARG_H__
 8+#define ARG_H__
 9+
10+extern char *argv0;
11+
12+/* use main(int argc, char *argv[]) */
13+#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
14+					argv[0] && argv[0][1]\
15+					&& argv[0][0] == '-';\
16+					argc--, argv++) {\
17+				char argc_;\
18+				char **argv_;\
19+				int brk_;\
20+				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
21+					argv++;\
22+					argc--;\
23+					break;\
24+				}\
25+				for (brk_ = 0, argv[0]++, argv_ = argv;\
26+						argv[0][0] && !brk_;\
27+						argv[0]++) {\
28+					if (argv_ != argv)\
29+						break;\
30+					argc_ = argv[0][0];\
31+					switch (argc_)
32+
33+/* Handles obsolete -NUM syntax */
34+#define ARGNUM				case '0':\
35+					case '1':\
36+					case '2':\
37+					case '3':\
38+					case '4':\
39+					case '5':\
40+					case '6':\
41+					case '7':\
42+					case '8':\
43+					case '9'
44+
45+#define ARGEND			}\
46+			}
47+
48+#define ARGC()		argc_
49+
50+#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))
51+
52+#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
53+				((x), abort(), (char *)0) :\
54+				(brk_ = 1, (argv[0][1] != '\0')?\
55+					(&argv[0][1]) :\
56+					(argc--, argv++, argv[0])))
57+
58+#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
59+				(char *)0 :\
60+				(brk_ = 1, (argv[0][1] != '\0')?\
61+					(&argv[0][1]) :\
62+					(argc--, argv++, argv[0])))
63+
64+#endif
+7, -0
1@@ -0,0 +1,7 @@
2+PREFIX = /usr
3+
4+CC      = cc
5+LD      = $(CC)
6+
7+CFLAGS  = -std=c99 -pedantic -Wall -Os
8+LDFLAGS = -lxcb -lxcb-icccm
+88, -0
 1@@ -0,0 +1,88 @@
 2+// Created by https://github.com/onodera-punpun
 3+
 4+#include <string.h>
 5+#include <stdbool.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <err.h>
 9+#include <xcb/xcb.h>
10+#include <xcb/xcb_icccm.h>
11+
12+#include "util.h"
13+
14+static xcb_connection_t *conn;
15+
16+static void usage(char *);
17+
18+static void
19+usage (char *name)
20+{
21+	fprintf(stderr, "usage: %s <wid> [wid...]\n", name);
22+	exit(1);
23+}
24+
25+static
26+xcb_atom_t xcb_atom_get(xcb_connection_t *conn, char *name)
27+{
28+	xcb_intern_atom_cookie_t cookie = xcb_intern_atom(conn ,0, strlen(name), name);
29+	xcb_intern_atom_reply_t *reply = xcb_intern_atom_reply(conn, cookie, NULL);
30+
31+	if (!reply)
32+		return XCB_ATOM_STRING;
33+
34+	return reply->atom;
35+}
36+
37+void
38+delete_window(xcb_window_t win)
39+{
40+	xcb_client_message_event_t ev;
41+
42+	ev.response_type = XCB_CLIENT_MESSAGE;
43+	ev.sequence = 0;
44+	ev.format = 32;
45+	ev.window = win;
46+	ev.type = xcb_atom_get(conn, "WM_PROTOCOLS");
47+	ev.data.data32[0] = xcb_atom_get(conn, "WM_DELETE_WINDOW");
48+	ev.data.data32[1] = XCB_CURRENT_TIME;
49+
50+	xcb_send_event(conn, 0, win, XCB_EVENT_MASK_NO_EVENT, (char *)&ev);
51+}
52+
53+int
54+main(int argc, char **argv)
55+{	
56+	xcb_window_t win = 0;
57+
58+	if (argc < 2)
59+		usage(argv[0]);
60+
61+	init_xcb(&conn);
62+
63+	/* assume remaining arguments are windows */
64+	while (*argv)
65+		win = strtoul(*argv++, NULL, 16);
66+
67+		xcb_icccm_get_wm_protocols_reply_t reply;
68+		unsigned int i = 0;
69+		bool got = false;
70+
71+		if (xcb_icccm_get_wm_protocols_reply(conn, xcb_icccm_get_wm_protocols(conn, win, xcb_atom_get(conn, "WM_PROTOCOLS")), &reply, NULL)) {
72+			for (; i != reply.atoms_len; ++i)
73+				if ((got = reply.atoms[i] == xcb_atom_get(conn, "WM_DELETE_WINDOW")))
74+					break;
75+
76+			xcb_icccm_get_wm_protocols_reply_wipe(&reply);
77+		}
78+		
79+		if (got)
80+			delete_window(win);
81+		else
82+			xcb_kill_client(conn, win);
83+
84+	xcb_flush(conn);
85+
86+	kill_xcb(&conn);
87+
88+	return 0;
89+}
+105, -0
  1@@ -0,0 +1,105 @@
  2+#include <err.h>
  3+#include <stdlib.h>
  4+#include <string.h>
  5+#include <xcb/xcb.h>
  6+
  7+#include "util.h"
  8+
  9+void
 10+init_xcb(xcb_connection_t **con)
 11+{
 12+	*con = xcb_connect(NULL, NULL);
 13+	if (xcb_connection_has_error(*con))
 14+		errx(1, "unable connect to the X server");
 15+}
 16+
 17+void
 18+kill_xcb(xcb_connection_t **con)
 19+{
 20+	if (*con)
 21+		xcb_disconnect(*con);
 22+}
 23+
 24+void
 25+get_screen(xcb_connection_t *con, xcb_screen_t **scr)
 26+{
 27+	*scr = xcb_setup_roots_iterator(xcb_get_setup(con)).data;
 28+	if (*scr == NULL)
 29+		errx(1, "unable to retrieve screen informations");
 30+}
 31+
 32+int
 33+exists(xcb_connection_t *con, xcb_window_t w)
 34+{
 35+	xcb_get_window_attributes_cookie_t c;
 36+	xcb_get_window_attributes_reply_t  *r;
 37+
 38+	c = xcb_get_window_attributes(con, w);
 39+	r = xcb_get_window_attributes_reply(con, c, NULL);
 40+
 41+	if (r == NULL)
 42+		return 0;
 43+
 44+	free(r);
 45+	return 1;
 46+}
 47+
 48+int
 49+mapped(xcb_connection_t *con, xcb_window_t w)
 50+{
 51+	int ms;
 52+	xcb_get_window_attributes_cookie_t c;
 53+	xcb_get_window_attributes_reply_t  *r;
 54+
 55+	c = xcb_get_window_attributes(con, w);
 56+	r = xcb_get_window_attributes_reply(con, c, NULL);
 57+
 58+	if (r == NULL)
 59+		return 0;
 60+
 61+	ms = r->map_state;
 62+
 63+	free(r);
 64+	return ms == XCB_MAP_STATE_VIEWABLE;
 65+}
 66+
 67+int
 68+ignore(xcb_connection_t *con, xcb_window_t w)
 69+{
 70+	int or;
 71+	xcb_get_window_attributes_cookie_t c;
 72+	xcb_get_window_attributes_reply_t  *r;
 73+
 74+	c = xcb_get_window_attributes(con, w);
 75+	r = xcb_get_window_attributes_reply(con, c, NULL);
 76+
 77+	if (r == NULL)
 78+		return 0;
 79+
 80+	or = r->override_redirect;
 81+
 82+	free(r);
 83+	return or;
 84+}
 85+
 86+int
 87+get_windows(xcb_connection_t *con, xcb_window_t w, xcb_window_t **l)
 88+{
 89+	uint32_t childnum = 0;
 90+	xcb_query_tree_cookie_t c;
 91+	xcb_query_tree_reply_t *r;
 92+
 93+	c = xcb_query_tree(con, w);
 94+	r = xcb_query_tree_reply(con, c, NULL);
 95+	if (r == NULL)
 96+		errx(1, "0x%08x: no such window", w);
 97+
 98+	*l = malloc(sizeof(xcb_window_t) * r->children_len);
 99+	memcpy(*l, xcb_query_tree_children(r),
100+			sizeof(xcb_window_t) * r->children_len);
101+
102+	childnum = r->children_len;
103+
104+	free(r);
105+	return childnum;
106+}
+14, -0
 1@@ -0,0 +1,14 @@
 2+#ifndef UTIL_H__
 3+#define UTIL_H__
 4+
 5+void init_xcb(xcb_connection_t **);
 6+void kill_xcb(xcb_connection_t **);
 7+
 8+void get_screen(xcb_connection_t *, xcb_screen_t **);
 9+int get_windows(xcb_connection_t *, xcb_window_t, xcb_window_t **);
10+
11+int exists(xcb_connection_t *, xcb_window_t);
12+int mapped(xcb_connection_t *, xcb_window_t);
13+int ignore(xcb_connection_t *, xcb_window_t);
14+
15+#endif
+15, -0
 1@@ -0,0 +1,15 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2015 (c) wtfpl
 5+# make the current window "rainbowish"... Awesome idea from xero@nixers.net !
 6+
 7+FREQ=${FREQ:-0.1}
 8+COLORS="888888 8064cc 6480cc 64cccc 80cc64 cccc64 cc6464"
 9+CUR=$(pfw)
10+
11+while :; do
12+    for c in $COLORS; do
13+        chwb -c $c $(pfw) 
14+        sleep $FREQ
15+    done
16+done
+80, -0
 1@@ -0,0 +1,80 @@
 2+#!/bin/sh
 3+#
 4+# wmutils/contrib>: snap.sh, 9/12/15 kekler 
 5+# snaps focued window to the left, right, top, or bottom edge
 6+
 7+usage() {
 8+    echo "usage: $(basename $0) <direction>" >&2
 9+    exit 1
10+}
11+
12+# default values for gaps and master area
13+TOP_PANEL=${PANEL:-20}
14+GAP=${GAP:-5}
15+
16+# get current window id and its borderwidth
17+PFW=$(pfw)
18+BW=$(wattr b $PFW)
19+
20+# get root window's size
21+ROOT=$(lsw -r)
22+SW=$(wattr w $ROOT)
23+SH=$(wattr h $ROOT)
24+
25+# calculate usable screen size (without borders and gaps)
26+SH=$((SH - TOP_PANEL))
27+
28+snap_up() 
29+{
30+    wtp $GAP $((GAP + TOP_PANEL)) $((SW - 2*GAP - 2*BW)) $((SH/2 - 2*BW - GAP - GAP/2)) $PFW
31+}
32+
33+snap_right() 
34+{
35+    wtp $((SW - SW/2 + GAP/2)) $((GAP + TOP_PANEL)) $((SW/2 - 2*BW - GAP - GAP/2)) $((SH - 2*BW - 2*GAP)) $PFW
36+}
37+
38+snap_down() 
39+{
40+    wtp $GAP $((SH - SH/2 + GAP/2 + TOP_PANEL)) $((SW - 2*GAP - 2*BW)) $((SH/2 - 2*BW - GAP - GAP/2)) $PFW
41+}
42+
43+snap_left()
44+{
45+    wtp $GAP $((GAP + TOP_PANEL)) $((SW/2 - 2*BW - GAP - GAP/2)) $((SH - 2*BW - 2*GAP)) $PFW
46+}
47+
48+HSW=$((SW/2 - 2*BW - GAP - GAP/2))
49+HSH=$((SH/2 - 2*BW - GAP - GAP/2))
50+
51+snap_tr()
52+{
53+    wtp $((SW - SW/2 + GAP/2)) $((GAP + TOP_PANEL)) $HSW $HSH $PFW
54+}
55+
56+snap_br()
57+{
58+    wtp $((SW - SW/2 + GAP/2)) $((SH - SH/2 + GAP/2 + TOP_PANEL)) $HSW $HSH $PFW
59+}
60+
61+snap_tl()
62+{
63+    wtp $GAP $((GAP + TOP_PANEL)) $HSW $HSH $PFW
64+}
65+
66+snap_bl()
67+{
68+    wtp $GAP $((SH - SH/2 + GAP/2 + TOP_PANEL)) $HSW $HSH $PFW
69+}
70+
71+case $1 in
72+    h|a|west|left)  snap_left ;;
73+    j|s|south|down) snap_down ;;
74+    k|w|north|up)   snap_up ;;
75+    l|d|east|right) snap_right ;;
76+    tr|northeast)   snap_tr ;;
77+    br|southeast)   snap_br ;;
78+    tl|northwest)   snap_tl ;;
79+    bl|southwest)   snap_bl ;;
80+esac
81+
+93, -0
 1@@ -0,0 +1,93 @@
 2+#!/bin/sh
 3+#
 4+# Copyright (c) 2015 Greduan <me@greduan.com>, licensed under the WTFPL license
 5+# Credit where credit is due, the grid algorithm was written by z3bra
 6+#
 7+# When used puts all the windows in a grid and when you focus one of the windows
 8+# it puts all the windows back to their original location and focuses the window
 9+# you switched to.
10+# depends on: wew focus.sh
11+
12+TEMP=$(mktemp) && wattr xywhi $(lsw) > $TEMP
13+NB=$(wc -l < $TEMP) # NB as in NumBer of windows
14+
15+# just safety
16+if [ $NB -eq 1 ]; then
17+    exit
18+fi
19+
20+# user defined
21+BW=${BW:-4} # width of your borders
22+GAP=${GAP:-20} # gap between windows
23+
24+# get monitor dimensions
25+ROOT=$(lsw -r)
26+SW=$(wattr w $ROOT)
27+SH=$(wattr h $ROOT)
28+# reduce screen useable screen area to improve later expressions
29+SW=$(( SW - GAP - 2*BW ))
30+SH=$(( SH - GAP - 2*BW ))
31+
32+# calculate the size of the grid using the square root of the number of windows
33+ROWS=$(echo "sqrt($NB)" | bc)
34+COLS=$ROWS
35+
36+# FOLLOWING WAS WRITTEN BY Z3BRA, don't give me credit for this awesome logic
37+# for each row...
38+for r in `seq 1 $ROWS`; do
39+
40+    # .. if we're on the last row, display all the remaining windows
41+    # eg: if we have 12 windows, the square root would be 3 (truncated).
42+    # so the script would draw a 3x3 grid. This would leave 3 windows apart. To
43+    # avoid this, we set the number of columns of the last row as
44+    #
45+    #    12 - 3 * (3-1)
46+    # => 12 - 3 * 2
47+    # => 12 - 6
48+    # == 6
49+    # so we will have 6 windows on the last row, instead of 3.
50+    # This do not lead to the best looking grid, I know (the best one would be
51+    # 3x4), but it's the simplest algo I've found. Don't forget we're playing
52+    # with shell scripts here, not matlab..
53+    test $r -eq $ROWS && COLS=$(( NB - ROWS * (ROWS-1) ))
54+
55+    # for each column of each row..
56+    for c in `seq 1 $COLS`; do
57+
58+        # exit if we don't have other windows to display
59+        test $(( (r-1)*r + c )) -gt $NB && break
60+
61+        # heigh of windows (total heigh minus gaps and borders)
62+        H=$(( SH/ROWS - GAP - BW ))
63+        # same for width
64+        W=$(( SW/COLS - GAP - BW ))
65+
66+        # and the tricky part..
67+        # The X offset is the width * the actual column (starting from 0) + the
68+        # gaps/borders multiplied by the column number (draw it on a sheet of
69+        # paper like me, it will make much more sense!
70+        X=$(( W * (c-1) + c*(GAP + BW) ))
71+        # same for the Y offset
72+        Y=$(( H * (r-1) + r*(GAP + BW) ))
73+
74+        # finally, teleport the window to the place we just calculated.
75+        # the sed trick is used to get the corresponding line number in the file
76+        # holding the window infos.
77+        wtp $X $Y $W $H $(sed "$(( (r-1)*r + c ))p;d" $TEMP | cut -d\  -f5)
78+    done
79+done
80+# END Z3BRA
81+
82+# listen to wew for our desired event
83+wew -m 4 | while IFS=: read ev wid; do
84+    if [ $ev -eq 4 ]; then
85+        while read line; do
86+            wtp $line
87+        done < $TEMP
88+        focus.sh $wid
89+        killall wew
90+    fi
91+done
92+
93+# cleanup
94+rm $TEMP
+39, -0
 1@@ -0,0 +1,39 @@
 2+#!/bin/sh
 3+#
 4+# z3bra - 2014 (c) wtfpl
 5+# arrange windows in a tiled pattern
 6+
 7+# default values for gaps and master area
 8+PANEL=${PANEL:-0}
 9+GAP=${GAP:-20}
10+MASTER=${MASTER:-900}
11+
12+# get current window id and its borderwidth
13+PFW=$(pfw)
14+BW=$(wattr b $PFW)
15+
16+# get root window's size (beware, multi-head setups...)
17+ROOT=$(lsw -r)
18+SW=$(wattr w $ROOT)
19+SH=$(wattr h $ROOT)
20+
21+# get the number of windows to put in the stacking area
22+MAX=$(lsw|grep -v $PFW|wc -l)
23+
24+# calculate usable screen size (without borders and gaps)
25+SW=$((SW - GAP - 2*BW))
26+SH=$((SH - GAP - PANEL))
27+
28+Y=$((0 + GAP + PANEL))
29+# put current window in master area
30+wtp $GAP $Y $((MASTER - GAP - 2*BW)) $((SH - GAP - 2*BW)) $PFW
31+
32+# and now, stack up all remaining windows on the right
33+X=$((MASTER + GAP))
34+W=$((SW - MASTER - GAP))
35+H=$((SH / MAX - GAP - 2*BW))
36+
37+for wid in $(lsw|grep -v $PFW); do
38+    wtp $X $Y $W $H $wid
39+    Y=$((Y + H + GAP + 2*BW))
40+done
+41, -0
 1@@ -0,0 +1,41 @@
 2+#!/bin/sh
 3+#
 4+# wildefyr - 2016 (c) MIT
 5+# print window id directly underneath mouse
 6+
 7+# fuck sh
 8+intCheck() {
 9+    test $1 -ne 0 2> /dev/null
10+    test $? -ne 2 || return 1
11+}
12+
13+# find current mouse location or check input for XY coordinates
14+test $# -eq 0 && {
15+    pointerX="$(wmp | cut -d\  -f 1)"
16+    pointerY="$(wmp | cut -d\  -f 2)"
17+} || {
18+    intCheck $1 && pointerX=$1 || return 1
19+    intCheck $2 && pointerY=$2 || return 1
20+}
21+
22+# start from the currently highest stacked window
23+for wid in $(lsw | tac); do
24+    windowX="$(wattr x $wid)"
25+    windowY="$(wattr y $wid)"
26+
27+    # we won't get a match if the left and top edges are greater than X or Y
28+    test "$windowX" -gt "$pointerX" && continue
29+    test "$windowY" -gt "$pointerY" && continue
30+
31+    windowW="$(wattr w $wid)"
32+    windowH="$(wattr h $wid)"
33+
34+    # we won't get a match if the right and bottom edges are less than X or Y
35+    test "$((windowX + windowW))" -lt "$pointerX" && continue
36+    test "$((windowY + windowH))" -lt "$pointerY" && continue
37+
38+    # print match!
39+    printf '%s\n' "$wid" 
40+    unset -v wid
41+    exit
42+done
+14, -0
 1@@ -0,0 +1,14 @@
 2+#!/bin/sh
 3+#
 4+# fyr | 2019 (c) MIT
 5+# dmenu wrapper to select windows based on their window title
 6+# use xprop -id $wid WM_NAME or WM_CLASS for better matching
 7+
 8+LINES=$(lsw | wc -l)
 9+
10+wid=$(\
11+    for wid in $(lsw); do
12+        printf '%s\n' "$wid | $(wname $wid)"
13+    done | dmenu -name "wmenu" -l $LINES -p "Window:" | cut -d\  -f 1)
14+
15+test -n "$wid" && focus.sh "$wid"
+107, -0
  1@@ -0,0 +1,107 @@
  2+#!/bin/sh
  3+# Constructs and groups windows into workspaces to switch between using your favorite keybinder.
  4+
  5+NUM_WS=9
  6+
  7+help() {
  8+	cat << EOF
  9+usage: $(basename $0) [-hinp] [-g ws_num] [-m ws_num]
 10+	-h: Displays this message
 11+	-i: Initialize workspaces. Should be called once in a startup script.
 12+	-n: Move up one workspace
 13+	-p: Move down one workspace
 14+	-g, <ws_num>: go to the workspace specified by <ws_num>
 15+	-m, <ws_num>: move the currently focused window to the worskpace specified by <ws_num>
 16+EOF
 17+	exit 1
 18+}
 19+# Initializes us in workspace 0.
 20+ws_init() {
 21+	mkdir -p /tmp/workspaces/
 22+	i=0
 23+	while [ $i -le $NUM_WS ]; do
 24+		:> /tmp/workspaces/ws"$i"
 25+		i=$(expr $i + 1)
 26+	done
 27+	echo 0 > /tmp/workspaces/curr
 28+}
 29+# Saves all mapped windows to the current workspace.
 30+save_ws() {
 31+	curr=$(cat /tmp/workspaces/curr)
 32+	lsw > /tmp/workspaces/ws"$curr"
 33+}
 34+move_to_ws() {
 35+	ws_num=$1
 36+	if [ $ws_num -gt $NUM_WS ] || [ $ws_num -lt 0 ]; then
 37+		echo "Workspace not found"
 38+		return
 39+	fi
 40+	curr_ws=$(cat /tmp/workspaces/curr);
 41+	if [ $ws_num == $curr_ws ]; then
 42+		# same workspace. ignore flicker
 43+		return
 44+	fi
 45+	save_ws
 46+	curr_windows=$(lsw)
 47+	if [ "$curr_windows" ]; then
 48+		mapw -u $(lsw)
 49+	fi
 50+	new_windows="$(cat /tmp/workspaces/ws$ws_num)"
 51+	if [ "$new_windows" ]; then
 52+		mapw -m $new_windows
 53+	fi
 54+	echo $ws_num > /tmp/workspaces/curr
 55+}
 56+next_ws() {
 57+	# Get what ws we're currently in.
 58+	curr=$(cat /tmp/workspaces/curr)
 59+	curr=$(expr $curr + 1)
 60+
 61+	# Take care of loopback.
 62+	if [ $curr -gt $NUM_WS ]; then
 63+		curr=0
 64+	fi
 65+
 66+	move_to_ws $curr
 67+}
 68+prev_ws() {
 69+	# Get what ws we're currently in.
 70+	curr=$(cat /tmp/workspaces/curr)
 71+	curr=$(expr $curr - 1)
 72+
 73+	# Take care of loopback.
 74+	if [ $curr -lt 0 ]; then
 75+		curr=$NUM_WS
 76+	fi
 77+
 78+	move_to_ws $curr
 79+}
 80+move_focused_window() {
 81+	ws_num=$1
 82+	if [ $ws_num -gt $NUM_WS ] || [ $ws_num -lt 0 ]; then
 83+		echo "Workspace not found"
 84+		return
 85+	fi
 86+	wid=$(pfw)
 87+	curr_ws=$(cat /tmp/workspaces/curr);
 88+	if [ $ws_num != $curr_ws ]; then
 89+		pfw >> /tmp/workspaces/ws"$1"
 90+		mapw -u $wid
 91+	fi
 92+}
 93+while getopts ":m:g:npi" opt; do
 94+	case $opt in
 95+		n)
 96+			next_ws;;
 97+		p)
 98+			prev_ws;;
 99+		g)
100+			move_to_ws $OPTARG;;
101+		m)
102+			move_focused_window $OPTARG;;
103+		i)
104+			ws_init;;
105+		\?)
106+			help;;
107+	esac
108+done
+16, -0
 1@@ -0,0 +1,16 @@
 2+ISC License
 3+
 4+Copyright (c) 2014-2016 brosephs <dcat at iotek dot org>,
 5+                                 <willy at mailoo dot org>
 6+
 7+Permission to use, copy, modify, and distribute this software for any
 8+purpose with or without fee is hereby granted, provided that the above
 9+copyright notice and this permission notice appear in all copies.
10+
11+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17+PERFORMANCE OF THIS SOFTWARE.
+56, -0
 1@@ -0,0 +1,56 @@
 2+include config.mk
 3+
 4+HDR = arg.h util.h
 5+SRC =           \
 6+	pfw.c   \
 7+	pdw.c   \
 8+	lsw.c   \
 9+	mapw.c  \
10+	killw.c \
11+	wattr.c \
12+	wtp.c   \
13+	wmv.c   \
14+	chwso.c \
15+	wtf.c   \
16+	wrs.c   \
17+	chwb.c  \
18+	ignw.c  \
19+	wmp.c   \
20+	slw.c   \
21+	atomx.c
22+
23+OBJ = $(SRC:.c=.o)
24+BIN = $(SRC:.c=)
25+MAN = $(SRC:.c=.1)
26+
27+.POSIX:
28+.SUFFIXES: .1 .1.gz
29+
30+all: binutils
31+
32+binutils: $(BIN)
33+
34+$(OBJ): $(HDR) util.o
35+
36+.o:
37+	@echo "LD $@"
38+	@$(LD) $< util.o -o $@ $(LDFLAGS)
39+
40+.c.o:
41+	@echo "CC $<"
42+	@$(CC) -c $< -o $@ $(CFLAGS)
43+
44+install: $(BIN)
45+	mkdir -p $(DESTDIR)$(PREFIX)/bin/
46+	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/
47+	cd man; $(MAKE) install
48+
49+uninstall:
50+	@echo "uninstalling binaries"
51+	@for util in $(BIN); do \
52+		rm -f $(DESTDIR)$(PREFIX)/bin/$$util; \
53+	done
54+	cd man; $(MAKE) uninstall
55+
56+clean :
57+	rm -f $(OBJ) $(BIN) util.o
+103, -0
  1@@ -0,0 +1,103 @@
  2+wmutils' core
  3+=============
  4+
  5+wmutils' core is a set of tools for X windows manipulation. Each tool only has
  6+one purpose, to make it as flexible and reliable as possible.
  7+
  8+Here's a quick example. This snippet will put the currently focused window in
  9+the middle of the screen:
 10+
 11+    #!/bin/sh
 12+
 13+    # get current window id, width and height
 14+    WID=$(pfw)
 15+    WW=$(wattr w $WID)
 16+    WH=$(wattr h $WID)
 17+
 18+    # get screen width and height
 19+    ROOT=$(lsw -r)
 20+    SW=$(wattr w $ROOT)
 21+    SH=$(wattr h $ROOT)
 22+
 23+    # move the current window to the center of the screen
 24+    wtp $(((SW - WW)/2)) $(((SH - WH)/2)) $WW $WH $WID
 25+
 26+You also might want to check [sxhkd](https://github.com/baskerville/sxhkd), a
 27+daemon which allow binding applications to hot keys.
 28+
 29+utilities
 30+---------
 31+
 32+* chwb  - change window's border
 33+* chwso - change window's stacking order
 34+* ignw  - ignore/unignore window
 35+* killw - kill windows
 36+* lsw   - list windows
 37+* mapw  - map/unmap windows
 38+* pfw   - print focused window
 39+* pdw   - print decoration window
 40+* slw   - select window interactively
 41+* wattr - show window's attributes
 42+* wmp   - move the mouse pointer
 43+* wmv   - move a window
 44+* wrs   - resize a window
 45+* wtf   - focus a window
 46+* wtp   - teleport a window
 47+* atomx - modify atoms on a window
 48+
 49+All these tools come with a manpage ! read them for further informations.
 50+
 51+dependencies
 52+------------
 53+
 54+wmutils only relies on the XCB library.
 55+
 56+license
 57+-------
 58+
 59+All the code of this project is released under the
 60+[ISC](http://www.openbsd.org/policy.html) license. See LICENSE file.
 61+
 62+build & install
 63+---------------
 64+
 65+System-wide installation (default PREFIX is `/usr`):
 66+
 67+    $ make
 68+    # make install
 69+
 70+Here are the variables you can override, along with their default values:
 71+
 72+    CC         =  cc
 73+    LD         =  $(CC)
 74+    CFLAGS     =  -std=c99 -pedantic -Wall -Os
 75+    LDFLAGS    =  -lxcb
 76+    PREFIX     =  /usr
 77+    MANPREFIX  =  $(PREFIX)/man
 78+    DESTDIR    =
 79+
 80+You can override them by passing them on the command line:
 81+
 82+    make DESTDIR=/newroot install
 83+
 84+Or by setting them via the environment:
 85+
 86+    CC=c99; export CC
 87+    make -e
 88+
 89+contribute
 90+----------
 91+
 92+You can contribute to the project in many ways; be it by testing the software,
 93+reporting bugs, submitting patches, or simply talking about it to other
 94+people!
 95+The official IRC channel for wmutils' talks is #wmutils @irc.freenode.net.
 96+
 97+If you find a bug in the software, please report an issue. Same goes for
 98+feature requests, if they match the project's philosophy.
 99+
100+When submitting pull requests, please reference the issue number. If there is
101+no issue to reference, then create one and wait for a validation of the bug
102+before submitting the pull request.
103+
104+IF YOUR PULL REQUEST DOESN'T REFER TO A VALID ISSUE, IT WILL BE DISCARDED.
+63, -0
 1@@ -0,0 +1,63 @@
 2+/*
 3+ * Copy me if you can.
 4+ * by 20h
 5+ */
 6+
 7+#ifndef ARG_H__
 8+#define ARG_H__
 9+
10+extern char *argv0;
11+
12+/* use main(int argc, char *argv[]) */
13+#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
14+					argv[0] && argv[0][1]\
15+					&& argv[0][0] == '-';\
16+					argc--, argv++) {\
17+				char argc_;\
18+				char **argv_;\
19+				int brk_;\
20+				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
21+					argv++;\
22+					argc--;\
23+					break;\
24+				}\
25+				for (brk_ = 0, argv[0]++, argv_ = argv;\
26+						argv[0][0] && !brk_;\
27+						argv[0]++) {\
28+					if (argv_ != argv)\
29+						break;\
30+					argc_ = argv[0][0];\
31+					switch (argc_)
32+
33+/* Handles obsolete -NUM syntax */
34+#define ARGNUM				case '0':\
35+					case '1':\
36+					case '2':\
37+					case '3':\
38+					case '4':\
39+					case '5':\
40+					case '6':\
41+					case '7':\
42+					case '8':\
43+					case '9'
44+
45+#define ARGEND			}\
46+			}
47+
48+#define ARGC()		argc_
49+
50+#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))
51+
52+#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
53+				((x), abort(), (char *)0) :\
54+				(brk_ = 1, (argv[0][1] != '\0')?\
55+					(&argv[0][1]) :\
56+					(argc--, argv++, argv[0])))
57+
58+#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
59+				(char *)0 :\
60+				(brk_ = 1, (argv[0][1] != '\0')?\
61+					(&argv[0][1]) :\
62+					(argc--, argv++, argv[0])))
63+
64+#endif
+145, -0
  1@@ -0,0 +1,145 @@
  2+/* See LICENSE file for copyright and license details. */
  3+
  4+#include <err.h>
  5+#include <stdio.h>
  6+#include <stdlib.h>
  7+#include <string.h>
  8+#include <xcb/xcb.h>
  9+#include <xcb/xcb_aux.h>
 10+
 11+#include "util.h"
 12+#include "arg.h"
 13+
 14+#define MAXLEN 512
 15+
 16+static xcb_connection_t *conn;
 17+
 18+void
 19+usage(char *name)
 20+{
 21+	fprintf(stderr, "%s [-d] atom[=value] wid\n", name);
 22+}
 23+
 24+xcb_atom_t
 25+add_atom(xcb_atom_t type, char *name, size_t len)
 26+{
 27+	xcb_atom_t atom;
 28+	xcb_intern_atom_cookie_t c;
 29+	xcb_intern_atom_reply_t *r;
 30+
 31+	c = xcb_intern_atom(conn, 0, len, name);
 32+	r = xcb_intern_atom_reply(conn, c, NULL);
 33+	if (!r)
 34+		return 0;
 35+
 36+	atom = r->atom;
 37+	free(r);
 38+
 39+	return atom;
 40+}
 41+
 42+int
 43+set_atom(xcb_window_t wid, xcb_atom_t atom, xcb_atom_t type, size_t len, void *data)
 44+{
 45+	int errcode;
 46+	xcb_void_cookie_t c;
 47+	xcb_generic_error_t *e;
 48+
 49+	c = xcb_change_property_checked(conn, XCB_PROP_MODE_REPLACE,
 50+		wid, atom, type, 8, len, data);
 51+	e = xcb_request_check(conn, c);
 52+	if (!e)
 53+		return 0;
 54+
 55+	errcode = e->error_code;
 56+	free(e);
 57+
 58+	return errcode;
 59+}
 60+
 61+int
 62+get_atom(xcb_window_t wid, xcb_atom_t atom, char *data, xcb_atom_t *type)
 63+{
 64+	size_t n;
 65+	xcb_get_property_cookie_t c;
 66+	xcb_get_property_reply_t *r;
 67+
 68+	c = xcb_get_property(conn, 0, wid, atom, XCB_ATOM_ANY, 0, MAXLEN);
 69+	r = xcb_get_property_reply(conn, c, NULL);
 70+	if (!r)
 71+		return -1;
 72+
 73+	if (!(n = xcb_get_property_value_length(r))) {
 74+		free(r);
 75+		return -1;
 76+	}
 77+
 78+	strncpy(data, xcb_get_property_value(r), n);
 79+	data[n] = 0;
 80+
 81+	*type = r->type;
 82+
 83+	free(r);
 84+
 85+	return 0;
 86+}
 87+
 88+
 89+int
 90+main(int argc, char **argv)
 91+{
 92+	int i, dflag = 0;
 93+	char *key, *val, *argv0;
 94+	char data[MAXLEN];
 95+	xcb_window_t wid;
 96+	xcb_atom_t atom;
 97+
 98+	ARGBEGIN {
 99+	case 'd':
100+		dflag = 1;
101+		break;
102+	default:
103+		usage(argv0);
104+		return -1;
105+	} ARGEND;
106+
107+	if (argc < 1)
108+		return -1;
109+
110+	key = strtok(argv[0], "=");
111+	val = strtok(NULL, "=");
112+
113+	init_xcb(&conn);
114+
115+	for (i = 0; i < argc - 1; i++) {
116+		wid = strtoul(argv[i+1], NULL, 16);
117+
118+		/* retrieve atom ID from server */
119+		atom = add_atom(XCB_ATOM_STRING, key, strlen(key));
120+		if (!atom)
121+			return -1;
122+
123+		/* set property on window (must be a string) */
124+		if (val)
125+			set_atom(wid, atom, XCB_ATOM_STRING, strlen(val), val);
126+
127+		/* remove property from window */
128+		if (dflag)
129+			xcb_delete_property(conn, wid, atom);
130+
131+		/* retrieve and print atom value to stdout */
132+		xcb_atom_t type;
133+		if (!get_atom(wid, atom, data, &type))
134+			switch (type) {
135+				case XCB_ATOM_INTEGER:
136+					printf("%d\n", *data);
137+					break;
138+				default:
139+					printf("%s\n", data);
140+			}
141+	}
142+
143+	kill_xcb(&conn);
144+
145+	return 0;
146+}
+96, -0
 1@@ -0,0 +1,96 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <xcb/xcb.h>
 5+#include <xcb/xcb_aux.h>
 6+#include <stdlib.h>
 7+#include <stdio.h>
 8+#include <err.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+
15+static void usage(char *name);
16+static void set_border(int, int, xcb_window_t);
17+
18+static void
19+usage(char *name)
20+{
21+	fprintf(stderr, "usage: %s <-sc ...> <wid> [wid...]\n", name);
22+	exit(1);
23+}
24+
25+static void
26+set_border(int width, int color, xcb_window_t win)
27+{
28+	uint32_t values[3];
29+	uint16_t curr_width;
30+	int mask;
31+	xcb_get_geometry_reply_t *geom;
32+
33+	if (width != -1) {
34+		geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
35+		if (!geom)
36+			return;
37+
38+		/* Windows track position based on the top left corner of the border.
39+		 * To make the border move instead of the window, we move the window up and left
40+		 * by the amount the border would have shifted it down and right.*/
41+		curr_width = geom->border_width;
42+		values[0] = geom->x + curr_width - width;
43+		values[1] = geom->y + curr_width - width;
44+		values[2] = width;
45+
46+		mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_BORDER_WIDTH ;
47+		xcb_configure_window(conn, win, mask, values);
48+
49+		xcb_aux_sync(conn);
50+
51+		free(geom);
52+	}
53+
54+	if (color != -1) {
55+		values[0] = color;
56+		mask = XCB_CW_BORDER_PIXEL;
57+		xcb_change_window_attributes(conn, win, mask, values);
58+
59+		xcb_aux_sync(conn);
60+	}
61+}
62+
63+int
64+main(int argc, char **argv)
65+{
66+	char *argv0;
67+	int color,width;
68+
69+	color = width = -1;
70+
71+	if (argc < 2)
72+		usage(argv[0]);
73+
74+	ARGBEGIN {
75+		case 's':
76+			width = strtoul(EARGF(usage(argv0)), NULL, 10);
77+			break;
78+		case 'c':
79+			color = strtoul(EARGF(usage(argv0)), NULL, 16);
80+			break;
81+		default:
82+			usage(argv0);
83+			/* NOTREACHED */
84+	} ARGEND
85+
86+	init_xcb(&conn);
87+
88+	/* assume remaining arguments are windows */
89+	while (*argv)
90+		set_border(width, color, strtoul(*argv++, NULL, 16));
91+
92+	xcb_aux_sync(conn);
93+
94+	kill_xcb(&conn);
95+
96+	return 0;
97+}
+244, -0
  1@@ -0,0 +1,244 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <xcb/xcb.h>
  4+#include <xcb/xcb_aux.h>
  5+#include <stdlib.h>
  6+#include <stdio.h>
  7+#include <string.h>
  8+#include <err.h>
  9+#include "arg.h"
 10+#include "util.h"
 11+
 12+static xcb_connection_t *conn;
 13+static void usage(char *name);
 14+static void set_border(int, int, xcb_window_t);
 15+static void set2border(xcb_window_t, int, int, int, int);
 16+static void monitor_and_update(xcb_window_t, int, int, int, int);
 17+
 18+static void
 19+usage(char *name)
 20+{
 21+	fprintf(stderr, "usage: %s <-s size> <-c color> | <-I icolor> <-O ocolor> <-i isize> <-o osize> [-w] <wid> [wid...]\n", name);
 22+	fprintf(stderr, "  -w: watch mode - continuously update borders on window resize\n");
 23+	exit(1);
 24+}
 25+
 26+static void
 27+set_border(int width, int color, xcb_window_t win)
 28+{
 29+	uint32_t values[3];
 30+	uint16_t curr_width;
 31+	int mask;
 32+	xcb_get_geometry_reply_t *geom;
 33+
 34+	if (width != -1) {
 35+		geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 36+		if (!geom)
 37+			return;
 38+
 39+		curr_width = geom->border_width;
 40+		values[0] = geom->x + curr_width - width;
 41+		values[1] = geom->y + curr_width - width;
 42+		values[2] = width;
 43+		mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_BORDER_WIDTH;
 44+		xcb_configure_window(conn, win, mask, values);
 45+		xcb_aux_sync(conn);
 46+		free(geom);
 47+	}
 48+
 49+	if (color != -1) {
 50+		values[0] = color;
 51+		mask = XCB_CW_BORDER_PIXEL;
 52+		xcb_change_window_attributes(conn, win, mask, values);
 53+		xcb_aux_sync(conn);
 54+	}
 55+}
 56+
 57+static void
 58+set2border(xcb_window_t win, int oc, int os, int ic, int is)
 59+{
 60+	if (os < 0 || oc < 0 || is < 0 || ic < 0)
 61+		return;
 62+
 63+	uint32_t values[3];
 64+	uint16_t curr_width;
 65+	int mask;
 66+	short w, h, b, o;
 67+	
 68+	xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(conn,
 69+			xcb_get_geometry(conn, win), NULL);
 70+	
 71+	if (geom == NULL)
 72+		return;
 73+
 74+	b = (unsigned short)(is + os);
 75+	curr_width = geom->border_width;
 76+	
 77+	/* Set border width first if needed */
 78+	if (curr_width != b) {
 79+		values[0] = geom->x + curr_width - b;
 80+		values[1] = geom->y + curr_width - b;
 81+		values[2] = b;
 82+		mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_BORDER_WIDTH;
 83+		xcb_configure_window(conn, win, mask, values);
 84+		xcb_flush(conn);
 85+		
 86+		/* Re-get geometry after border width change */
 87+		free(geom);
 88+		geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 89+		if (geom == NULL)
 90+			return;
 91+	}
 92+
 93+	w = (short)geom->width;
 94+	h = (short)geom->height;
 95+	o = (unsigned short)os;
 96+
 97+	xcb_rectangle_t inner[] = {
 98+		{w, 0, b - o, h + b - o},
 99+		{w + b + o, 0, b - o, h + b - o},
100+		{0, h, w + b - o, b - o},
101+		{0, h + b + o, w + b - o, b - o},
102+		{w + b + o, b + h + o, b, b}
103+	};
104+
105+	xcb_rectangle_t outer[] = {
106+		{w + b - o, 0, o, h + b * 2},
107+		{w + b, 0, o, h + b * 2},
108+		{0, h + b - o, w + b * 2, o},
109+		{0, h + b, w + b * 2, o},
110+		{1, 1, 1, 1}
111+	};
112+
113+	xcb_pixmap_t pmap = xcb_generate_id(conn);
114+	xcb_create_pixmap(conn, geom->depth, pmap, win,
115+			w + (b * 2),
116+			h + (b * 2));
117+
118+	xcb_gcontext_t gc = xcb_generate_id(conn);
119+	xcb_create_gc(conn, gc, pmap, 0, NULL);
120+
121+	values[0] = oc;
122+	xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, values);
123+	xcb_poly_fill_rectangle(conn, pmap, gc, 5, outer);
124+
125+	values[0] = ic;
126+	xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, values);
127+	xcb_poly_fill_rectangle(conn, pmap, gc, 5, inner);
128+
129+	values[0] = pmap;
130+	xcb_change_window_attributes(conn, win, XCB_CW_BORDER_PIXMAP, values);
131+
132+	xcb_flush(conn);
133+	xcb_free_pixmap(conn, pmap);
134+	xcb_free_gc(conn, gc);
135+	free(geom);
136+}
137+
138+static void
139+monitor_and_update(xcb_window_t win, int oc, int os, int ic, int is)
140+{
141+	uint32_t mask = XCB_CW_EVENT_MASK;
142+	uint32_t values[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY };
143+	
144+	xcb_change_window_attributes(conn, win, mask, values);
145+	xcb_flush(conn);
146+
147+	set2border(win, oc, os, ic, is);
148+
149+	xcb_generic_event_t *ev;
150+	uint16_t last_w = 0, last_h = 0;
151+
152+	while ((ev = xcb_wait_for_event(conn))) {
153+		switch (ev->response_type & ~0x80) {
154+			case XCB_CONFIGURE_NOTIFY: {
155+				xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t *)ev;
156+				if (e->window == win) {
157+					if (e->width != last_w || e->height != last_h) {
158+						last_w = e->width;
159+						last_h = e->height;
160+						set2border(win, oc, os, ic, is);
161+					}
162+				}
163+				break;
164+			}
165+			case XCB_DESTROY_NOTIFY: {
166+				xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *)ev;
167+				if (e->window == win) {
168+					free(ev);
169+					return;
170+				}
171+				break;
172+			}
173+		}
174+		free(ev);
175+	}
176+}
177+
178+int
179+main(int argc, char **argv)
180+{
181+	char *argv0;
182+	int color, width;
183+	int oc, os, ic, is;
184+	int use_double_border = 0;
185+	int watch_mode = 0;
186+
187+	color = width = -1;
188+	oc = os = ic = is = -1;
189+
190+	if (argc < 2)
191+		usage(argv[0]);
192+
193+	ARGBEGIN {
194+		case 's':
195+			width = strtoul(EARGF(usage(argv0)), NULL, 10);
196+			break;
197+		case 'c':
198+			color = strtoul(EARGF(usage(argv0)), NULL, 16);
199+			break;
200+		case 'I':
201+			ic = strtoul(EARGF(usage(argv0)), NULL, 16);
202+			use_double_border = 1;
203+			break;
204+		case 'O':
205+			oc = strtoul(EARGF(usage(argv0)), NULL, 16);
206+			use_double_border = 1;
207+			break;
208+		case 'i':
209+			is = strtoul(EARGF(usage(argv0)), NULL, 10);
210+			use_double_border = 1;
211+			break;
212+		case 'o':
213+			os = strtoul(EARGF(usage(argv0)), NULL, 10);
214+			use_double_border = 1;
215+			break;
216+		case 'w':
217+			watch_mode = 1;
218+			break;
219+		default:
220+			usage(argv0);
221+	} ARGEND
222+
223+	init_xcb(&conn);
224+
225+	if (watch_mode && use_double_border && *argv) {
226+		/* Watch mode: only works with one window */
227+		xcb_window_t win = strtoul(*argv, NULL, 16);
228+		monitor_and_update(win, oc, os, ic, is);
229+	} else {
230+		/* Normal mode: set borders once */
231+		while (*argv) {
232+			xcb_window_t win = strtoul(*argv++, NULL, 16);
233+			if (use_double_border)
234+				set2border(win, oc, os, ic, is);
235+			else
236+				set_border(width, color, win);
237+		}
238+	}
239+
240+	xcb_aux_sync(conn);
241+	kill_xcb(&conn);
242+
243+	return 0;
244+}
245+
+67, -0
 1@@ -0,0 +1,67 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <xcb/xcb.h>
 5+#include <xcb/xcb_aux.h>
 6+#include <stdlib.h>
 7+#include <stdio.h>
 8+#include <err.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+
15+static void usage(char *);
16+static void stack(xcb_window_t, uint32_t[1]);
17+
18+static void
19+usage(char *name)
20+{
21+	fprintf(stderr, "usage: %s -rli <wid>\n", name);
22+	exit(1);
23+}
24+
25+static void
26+stack(xcb_window_t win, uint32_t values[1])
27+{
28+	xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_STACK_MODE, values);
29+}
30+
31+int
32+main(int argc, char **argv)
33+{
34+	xcb_window_t win;
35+	uint32_t values[1];
36+	char *argv0 = NULL;
37+
38+	if (argc != 3)
39+		usage(argv[0]);
40+
41+	init_xcb(&conn);
42+
43+	win = strtoul(argv[2], NULL, 16);
44+	if (!win)
45+		return 1;
46+
47+	ARGBEGIN {
48+		case 'r':
49+			values[0] = XCB_STACK_MODE_ABOVE;
50+			break;
51+		case 'l':
52+			values[0] = XCB_STACK_MODE_BELOW;
53+			break;
54+		case 'i':
55+			values[0] = XCB_STACK_MODE_OPPOSITE;
56+			break;
57+		default:
58+			usage(argv0);
59+			break;
60+	} ARGEND
61+
62+	stack(win, values);
63+	xcb_aux_sync(conn);
64+
65+	kill_xcb(&conn);
66+
67+	return 0;
68+}
+9, -0
 1@@ -0,0 +1,9 @@
 2+PREFIX = /usr
 3+MANPREFIX = $(PREFIX)/man
 4+
 5+CC      = cc
 6+LD      = $(CC)
 7+
 8+CFLAGS  = -std=c99 -pedantic -Wall -Os -I/usr/X11R6/include
 9+LDFLAGS = -lxcb -lxcb-util -lxcb-cursor -L/usr/X11R6/lib
10+
+55, -0
 1@@ -0,0 +1,55 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <err.h>
 7+#include <xcb/xcb.h>
 8+#include <xcb/xcb_aux.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+
15+static void usage(char *);
16+static void set_override(xcb_window_t, int);
17+
18+static void
19+usage(char *name)
20+{
21+	fprintf(stderr, "usage: %s [-sr] <wid> [wid..]\n", name);
22+	exit(1);
23+}
24+
25+static void
26+set_override(xcb_window_t w, int or)
27+{
28+	uint32_t mask = XCB_CW_OVERRIDE_REDIRECT;
29+	uint32_t val[] = { or };
30+
31+	xcb_change_window_attributes(conn, w, mask, val);
32+}
33+
34+int
35+main(int argc, char **argv)
36+{
37+	int setflag = 0;
38+	char *argv0;
39+
40+	ARGBEGIN {
41+		case 's': setflag = 1; break;
42+		case 'r': setflag = 0; break;
43+		default: usage(argv0);
44+	} ARGEND;
45+
46+	init_xcb(&conn);
47+
48+	while (*argv)
49+		set_override(strtoul(*argv++, NULL, 16), setflag);
50+
51+	xcb_aux_sync(conn);
52+
53+	kill_xcb(&conn);
54+
55+	return 0;
56+}
+54, -0
 1@@ -0,0 +1,54 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <err.h>
 7+#include <xcb/xcb.h>
 8+#include <xcb/xcb_aux.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+
15+static void usage(char *);
16+
17+static void
18+usage (char *name)
19+{
20+	fprintf(stderr, "usage: %s [-p] <wid> [wid...]\n", name);
21+	exit(1);
22+}
23+
24+int
25+main(int argc, char **argv)
26+{
27+	int parent = 0;
28+	char *argv0;
29+
30+	if (argc < 2)
31+		usage(argv[0]);
32+
33+	ARGBEGIN{
34+	case 'p': parent=1; break;
35+	default: usage(argv0);
36+	}ARGEND;
37+
38+	init_xcb(&conn);
39+
40+	/* assume remaining arguments are windows */
41+	while (*argv) {
42+		if (parent) {
43+			/* kills the client whose WID belongs to */
44+			xcb_kill_client(conn, strtoul(*argv++, NULL, 16));
45+		} else {
46+			/* destroy the given window and all its children */
47+			xcb_destroy_window(conn, strtoul(*argv++, NULL, 16));
48+		}
49+	}
50+
51+	xcb_aux_sync(conn);
52+	kill_xcb(&conn);
53+
54+	return 0;
55+}
+96, -0
 1@@ -0,0 +1,96 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <err.h>
 7+#include <xcb/xcb.h>
 8+#include <xcb/xcb_aux.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+static xcb_screen_t *scrn;
15+
16+static void usage(char *);
17+static int should_list(xcb_window_t, int);
18+static void list_windows(xcb_window_t, int);
19+
20+enum {
21+	LIST_HIDDEN = 1 << 0,
22+	LIST_IGNORE = 1 << 1,
23+	LIST_ALL    = 1 << 2
24+};
25+
26+static void
27+usage(char *name)
28+{
29+	fprintf(stderr, "usage: %s [-houra] [wid...]\n", name);
30+	exit(1);
31+}
32+
33+static int
34+should_list(xcb_window_t w, int mask)
35+{
36+	if ((mask & LIST_ALL)
37+		|| (!mapped(conn, w) && mask & LIST_HIDDEN)
38+		|| (ignore(conn, w) && mask & LIST_IGNORE)
39+		|| (mapped(conn, w)
40+			&& !ignore(conn, w)
41+			&& mask == 0))
42+		return 1;
43+
44+	return 0;
45+}
46+
47+static void
48+list_windows(xcb_window_t w, int listmask)
49+{
50+	int i, wn;
51+	xcb_window_t *wc;
52+
53+	wn = get_windows(conn, w, &wc);
54+
55+	if (wc == NULL)
56+		errx(1, "0x%08x: unable to retrieve children", w);
57+
58+	for (i=0; i<wn; i++) {
59+		if (should_list(wc[i], listmask))
60+			printf("0x%08x\n", wc[i]);
61+	}
62+
63+	free(wc);
64+}
65+
66+int
67+main(int argc, char **argv)
68+{
69+	int listmask = 0, rootflag = 0;
70+	char *argv0;
71+
72+	ARGBEGIN {
73+		case 'a': listmask |= LIST_ALL; break;
74+		case 'u': listmask |= LIST_HIDDEN; break;
75+		case 'o': listmask |= LIST_IGNORE; break;
76+		case 'r': rootflag = 1; break;
77+		default : usage(argv0);
78+	} ARGEND;
79+
80+	init_xcb(&conn);
81+	get_screen(conn, &scrn);
82+
83+	if (rootflag == 1) {
84+		printf("0x%08x\n", scrn->root);
85+		return 0;
86+	}
87+
88+	if (argc == 0)
89+		list_windows(scrn->root, listmask);
90+
91+	while (*argv)
92+		list_windows(strtoul(*argv++, NULL, 16), listmask);
93+
94+	kill_xcb(&conn);
95+
96+	return 0;
97+}
+31, -0
 1@@ -0,0 +1,31 @@
 2+include ../config.mk
 3+
 4+MAN =           \
 5+	pfw.1   \
 6+	lsw.1   \
 7+	mapw.1  \
 8+	killw.1 \
 9+	wattr.1 \
10+	wtp.1   \
11+	wmv.1   \
12+	chwso.1 \
13+	wtf.1   \
14+	wrs.1   \
15+	chwb.1  \
16+	ignw.1  \
17+	wmp.1   \
18+	slw.1   \
19+	atomx.1 \
20+	wmutils.1
21+
22+.POSIX:
23+
24+install: $(MAN)
25+	mkdir -p $(DESTDIR)$(MANPREFIX)/man1/
26+	cp -f $(MAN) $(DESTDIR)$(MANPREFIX)/man1/
27+
28+uninstall:
29+	@echo "uninstalling manpages"
30+	@for page in $(MAN); do \
31+		rm -f $(DESTDIR)$(MANPREFIX)/man1/$$page; \
32+	done
+43, -0
 1@@ -0,0 +1,43 @@
 2+.Dd November 21, 2019
 3+.Dt ATOMX 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm atomx
 7+.Nd manage X atoms on a window
 8+.Sh SYNOPSIS
 9+.Nm atomx
10+.Op Fl d
11+.Ar atom
12+.Op Ar =value
13+.Ar wid
14+.Sh DESCRIPTION
15+.Nm
16+will print, add, change and remove X atoms on the window with ID
17+.Ar wid .
18+By default
19+.Nm
20+will print the value of the atom
21+.Ar atom
22+if it exists.
23+.Pp
24+To set an atom on a window, you must specify it as
25+.Ar atom=value .
26+.Bl -tag -width Ds
27+.It Fl d
28+Delete atom
29+.Ar atom
30+from the window.
31+.Sh ENVIRONMENT
32+.Nm
33+acts on the X display specified by the
34+.Ev DISPLAY
35+variable.
36+.Sh EXAMPLES
37+Print value of property "WM_CLASS"
38+.Dl $ atomx WM_CLASS 0x00e00005
39+.Pp
40+Change window name to "atomx"
41+.Dl $ atomx WM_NAME=atomx 0x00e00005
42+.Pp
43+Delete property "IS_FULLSCREEN" on a window
44+.Dl $ atomx -d IS_FULLSCREEN 0x00e00005
+40, -0
 1@@ -0,0 +1,40 @@
 2+.Dd December 13, 2014
 3+.Dt CHWB 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm chwb
 7+.Nd change window borders
 8+.Sh SYNOPSIS
 9+.Nm chwb
10+.Op Fl c Ar color
11+.Op Fl s Ar size
12+.Ar wid Op Ar ...
13+.Sh DESCRIPTION
14+.Nm
15+changes the border size or color of the window
16+.Ar wid .
17+.Bl -tag -width Ds
18+.It Fl c Ar color
19+Set border color of
20+.Ar wid
21+to
22+.Ar color .
23+Colors should be passed as numerical values (see
24+.Xr strtoul 3 )
25+in RGB format.
26+.It Fl s Ar size
27+Set border width of
28+.Ar wid
29+to
30+.Ar size .
31+.El
32+.Sh ENVIRONMENT
33+.Nm
34+acts on the X display specified by the
35+.Ev DISPLAY
36+variable.
37+.Sh EXAMPLES
38+Set the border color to 128 red, 100 green, 204 blue:
39+.Dl $ chwb -c 0x8064cc
40+.Sh SEE ALSO
41+.Xr strtoul 3
+33, -0
 1@@ -0,0 +1,33 @@
 2+.Dd December 13, 2014
 3+.Dt CHWSO 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm chwso
 7+.Nd change window stacking order
 8+.Sh SYNOPSIS
 9+.Nm chwso
10+.Op Fl ilr
11+.Ar wid
12+.Sh DESCRIPTION
13+.Nm
14+will change the place of a window in the server\(cqs window stack,
15+putting it in either the foreground or the background.
16+.Bl -tag -width Ds
17+.It Fl i
18+Invert
19+.Ar wid Ns \(cqs
20+position in the window stack.
21+.It Fl l
22+Put
23+.Ar wid
24+at the bottom of the window stack.
25+.It Fl r
26+Put
27+.Ar wid
28+on top of the window stack.
29+.El
30+.Sh ENVIRONMENT
31+.Nm
32+acts on the X display specified by the
33+.Ev DISPLAY
34+variable.
+37, -0
 1@@ -0,0 +1,37 @@
 2+.Dd December 13, 2014
 3+.Dt IGNW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm ignw
 7+.Nd ignore window
 8+.Sh SYNOPSIS
 9+.Nm ignw
10+.Fl rs
11+.Ar wid Op ...
12+.Sh DESCRIPTION
13+.Nm
14+changes the value of the
15+.Em override_redirect
16+attribute of a window to either 0 or 1.
17+This affects whether the window manager ignores the window.
18+.Bl -tag -width Ds
19+.It Fl r
20+Reset
21+.Ar wid Ns \(cqs
22+.Em override_redirect
23+value to 0, unignoring the window.
24+.It Fl s
25+Set
26+.Ar wid Ns \(cqs
27+.Em override_redirect
28+value to 1, ignoring the window.
29+.El
30+.Sh ENVIRONMENT
31+.Nm
32+acts on the X display specified by the
33+.Ev DISPLAY
34+variable.
35+.Sh SEE ALSO
36+.Xr lsw 1 ,
37+.Xr wattr 1 ,
38+.Xr xcb_get_window_attributes 3
+25, -0
 1@@ -0,0 +1,25 @@
 2+.Dd December 13, 2014
 3+.Dt KILLW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm killw
 7+.Nd kill windows
 8+.Sh SYNOPSIS
 9+.Nm killw
10+.Op Fl p
11+.Ar wid Op ...
12+.Sh DESCRIPTION
13+.Nm
14+will destroy the window passed as an argument, and all its children.
15+.Sh OPTIONS
16+.Bl -tag -width Ds
17+.It Fl p
18+Kill the parent application of the window instead of the window itself.
19+This is useful to terminate frozen applications (This will close all the windows
20+belonging to the applications).
21+.El
22+.Sh ENVIRONMENT
23+.Nm
24+acts on the X display specified by the
25+.Ev DISPLAY
26+variable.
+43, -0
 1@@ -0,0 +1,43 @@
 2+.Dd December 13, 2014
 3+.Dt LSW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm lsw
 7+.Nd list child windows
 8+.Sh SYNOPSIS
 9+.Nm lsw
10+.Op Fl arou
11+.Op Ar wid ...
12+.Sh DESCRIPTION
13+.Nm
14+lists child windows of the given window.
15+If no windows are given,
16+.Nm
17+lists the children of the root window.
18+.Pp
19+By default,
20+.Nm
21+lists only windows that are mapped (visible) and with the
22+.Em override_redirect
23+value set to 0 (i.e., unignored).
24+.Bl -tag -width Ds
25+.It Fl a
26+List all windows.
27+.It Fl r
28+Print the ID of the root window.
29+.It Fl o
30+List windows whose
31+.Em override_redirect
32+attribute is set to 1.
33+.It Fl u
34+List unmapped (invisible) windows.
35+.El
36+.Sh ENVIRONMENT
37+.Nm
38+acts on the X display specified by the
39+.Ev DISPLAY
40+variable.
41+.Sh SEE ALSO
42+.Xr ignw 1 ,
43+.Xr mapw 1 ,
44+.Xr xargs 1
+32, -0
 1@@ -0,0 +1,32 @@
 2+.Dd December 13, 2014
 3+.Dt MAPW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm mapw
 7+.Nd map or unmap window
 8+.Sh SYNOPSIS
 9+.Nm mapw
10+.Op Fl mtu
11+.Ar wid Op ...
12+.Sh DESCRIPTION
13+.Nm
14+will either map or unmap a window from the screen,
15+thus modifying the visibility state of the window.
16+.Bl -tag -width Ds
17+.It Fl m
18+Map (show)
19+.Ar wid .
20+.It Fl t
21+Toggle
22+.Ar wid Ns \(cqs visibility.
23+.It Fl u
24+Unmap (hide)
25+.Ar wid .
26+.El
27+.Sh ENVIRONMENT
28+.Nm
29+acts on the X display specified by the
30+.Ev DISPLAY
31+variable.
32+.Sh SEE ALSO
33+.Xr lsw 1
+24, -0
 1@@ -0,0 +1,24 @@
 2+.Dd July 01, 2022
 3+.Dt PDW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm pdw
 7+.Nd print decoration window
 8+.Sh SYNOPSIS
 9+.Nm pdw
10+.Op Ar wid
11+.Sh DESCRIPTION
12+Print the ID of the highest parent related to
13+.Ar wid
14+(or currently focused window when
15+.Ar wid
16+is omitted).
17+.Pp
18+In reparenting environments, this is usually the decoration window.
19+.Sh ENVIRONMENT
20+.Nm
21+acts on the X display specified by the
22+.Ev DISPLAY
23+variable.
24+.Sh SEE ALSO
25+.Xr pfw 1
+16, -0
 1@@ -0,0 +1,16 @@
 2+.Dd December 13, 2014
 3+.Dt PFW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm pfw
 7+.Nd print focused window
 8+.Sh SYNOPSIS
 9+.Nm pfw
10+.Sh DESCRIPTION
11+Print the ID of the currently focused window to
12+.Dv stdout .
13+.Sh ENVIRONMENT
14+.Nm
15+acts on the X display specified by the
16+.Ev DISPLAY
17+variable.
+17, -0
 1@@ -0,0 +1,17 @@
 2+.Dd October 14, 2019
 3+.Dt SLW 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm slw
 7+.Nd select window interactively
 8+.Sh SYNOPSIS
 9+.Nm slw
10+.Sh DESCRIPTION
11+Wait for a button press event and print the window ID that got the
12+event to
13+.Dv stdout .
14+.Sh ENVIRONMENT
15+.Nm
16+acts on the X display specified by the
17+.Ev DISPLAY
18+variable.
+81, -0
 1@@ -0,0 +1,81 @@
 2+'\" e
 3+.Dd December 13, 2014
 4+.Dt WATTR 1
 5+.Os wmutils
 6+.Sh NAME
 7+.Nm wattr
 8+.Nd get window attributes
 9+.Sh SYNOPSIS
10+.Nm wattr
11+.Op Cm bmiowhxy
12+.Ar wid
13+.Sh DESCRIPTION
14+.Nm
15+prints information about the window
16+.Ar wid
17+to
18+.Dv stdout .
19+.Pp
20+What information is presented depends on the commands given to
21+.Nm .
22+The queried arguments are printed in the order they are requested,
23+separated by a space.
24+If no commands are given,
25+.Nm
26+will return 0 if
27+.Ar wid
28+exists, and 1 otherwise.
29+.Bl -tag -width Ds
30+.It Cm i
31+Print
32+.Ar wid
33+.It Cm b
34+Print
35+.Ar wid Ns \(cqs border width.
36+.It Cm x
37+Print
38+.Ar wid Ns \(cqs
39+.EQ
40+x
41+.EN
42+offset.
43+.It Cm y
44+Print
45+.Ar wid Ns \(cqs
46+.EQ
47+y
48+.EN
49+offset.
50+.It Cm w
51+Print
52+.Ar wid Ns \(cqs width.
53+.It Cm h
54+Print
55+.Ar wid Ns \(cqs
56+height.
57+.It Cm o
58+.Nm
59+returns 0 if the override_redirect attribute is set on the window.
60+.It Cm m
61+.Nm
62+returns 0 if
63+.Ar wid
64+is mapped on screen, and 1 otherwise.
65+.El
66+.Sh ENVIRONMENT
67+.Nm
68+acts on the X display specified by the
69+.Ev DISPLAY
70+variable.
71+.Sh EXAMPLES
72+.Dl $ wattr m 0x01000006 && echo ismapped
73+.Dl ismapped
74+.Pp
75+.Dl $ wattr whxy 0x01000006
76+.Dl 484 244 756 166
77+.Pp
78+.Dl $ wattr xyhw 0x01000006
79+.Dl 756 166 244 484
80+.Pp
81+.Dl $ wattr 0x00000000 ; echo $?
82+.Dl 1
+37, -0
 1@@ -0,0 +1,37 @@
 2+.Dd December 17, 2014
 3+.Dt WMP 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm wmp
 7+.Nd warp mouse cursor
 8+.Sh SYNOPSIS
 9+.Nm wmp
10+.Fl [ ar
11+.Ar <x> <y> ]
12+.Ar [ wid ]
13+.Sh DESCRIPTION
14+.Nm
15+warps cursor to an absolute or relative position, passed by
16+.Ar x
17+and
18+.Ar y .
19+Returns the position relative to the root window, or
20+.Ar wid .
21+.Sh ENVIRONMENT
22+.Nm
23+acts on the X display specified by the
24+.Ev DISPLAY
25+variable.
26+.Sh EXAMPLES
27+.Pp
28+.Dl $ wmp -a $(wattr xy $(pfw))
29+.Pp
30+.Dl $ wmp -r 100 0
31+.Pp
32+.Dl $ wmp -r -- -100 0
33+.Pp
34+.Dl $ wmp 0x01600006
35+.Dl 311 49
36+.Pp
37+.Dl $ wmp
38+.Dl 915 548
+64, -0
 1@@ -0,0 +1,64 @@
 2+.Dd June 9, 2015
 3+.Dt WMUTILS 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm wmutils
 7+.Nd window manipulation utilities
 8+.Sh DESCRIPTION
 9+.Nm
10+is a compilation of utilities for manipulating windows in X
11+.Sh COMMANDS
12+.Bl -tag -width Ds -offset 60
13+.It chwb
14+change window's border
15+.It chwso
16+change window's stacking order
17+.It ignw
18+ignore/unignore window
19+.It killw
20+kill windows
21+.It lsw
22+list windows
23+.It mapw
24+map/unmap windows
25+.It pfw
26+print focused window
27+.It pdw
28+print decoration window
29+.It wattr
30+show window's attributes
31+.It wmp
32+move the mouse pointer
33+.It wmv
34+move a window
35+.It wrs
36+resize a window
37+.It wtf
38+focus a window
39+.It wtp
40+teleport a window
41+.It atomx
42+modify atoms on a window
43+.El
44+.Sh ENVIRONMENT
45+.Nm
46+acts on the X display specified by the
47+.Ev DISPLAY
48+variable.
49+.Sh SEE ALSO
50+.Xr chwb 1 ,
51+.Xr chwso 1 ,
52+.Xr ignw 1 ,
53+.Xr killw 1 ,
54+.Xr lsw 1 ,
55+.Xr mapw 1 ,
56+.Xr pfw 1 ,
57+.Xr pdw 1 ,
58+.Xr wattr 1 ,
59+.Xr wmp 1 ,
60+.Xr wmv 1 ,
61+.Xr wname 1 ,
62+.Xr wrs 1 ,
63+.Xr wtf 1 ,
64+.Xr wtp 1 ,
65+.Xr atomx 1
+41, -0
 1@@ -0,0 +1,41 @@
 2+'\" e
 3+.Dd December 13, 2014
 4+.Dt WMV 1
 5+.Os wmutils
 6+.Sh NAME
 7+.Nm wmv
 8+.Nd move windows
 9+.Sh SYNOPSIS
10+.Nm wmv
11+.Op Fl a
12+.Ar x y wid
13+.Sh DESCRIPTION
14+.Nm wmv
15+repositions
16+.Ar wid
17+relatively,
18+.Ar x
19+pixels in the
20+.EQ
21+x
22+.EN
23+direction and
24+.Ar y
25+pixels in the
26+.EQ
27+y
28+.EN
29+direction.
30+.Bl -tag -width Ds
31+.It Fl a
32+Absolute mode. The window will be centered to the 
33+.Ar x
34+and
35+.Ar y
36+coordinates.
37+.El
38+.Sh ENVIRONMENT
39+.Nm
40+acts on the X display specified by the
41+.Ev DISPLAY
42+variable.
+31, -0
 1@@ -0,0 +1,31 @@
 2+.Dd December 13, 2014
 3+.Dt WRS 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm wrs
 7+.Nd resize windows
 8+.Sh SYNOPSIS
 9+.Nm wrs
10+.Op Fl a
11+.Ar x y wid Op ...
12+.Sh DESCRIPTION
13+.Nm
14+resizes the window
15+.Ar wid
16+based on the relative pixel values
17+.Ar x
18+and
19+.Ar y .
20+.Bl -tag -width Ds
21+.It Fl a
22+Absolute mode. The window will be resized up to the 
23+.Ar x
24+and
25+.Ar y
26+coordinates.
27+.El
28+.Sh ENVIRONMENT
29+.Nm
30+acts on the X display specified by the
31+.Ev DISPLAY
32+variable.
+19, -0
 1@@ -0,0 +1,19 @@
 2+.Dd December 13, 2014
 3+.Dt WTF 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm wtf
 7+.Nd transfer window focus
 8+.Sh SYNOPSIS
 9+.Nm wtf
10+.Ar wid
11+.Sh DESCRIPTION
12+.Nm
13+sets the keyboard input focus to the window
14+.Ar wid
15+if it exists and is viewable.
16+.Sh ENVIRONMENT
17+.Nm
18+acts on the X display specified by the
19+.Ev DISPLAY
20+variable.
+27, -0
 1@@ -0,0 +1,27 @@
 2+.Dd December 13, 2014
 3+.Dt WTP 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm wtp
 7+.Nd teleport window (absolutely)
 8+.Sh SYNOPSIS
 9+.Nm wtp
10+.Ar x y w h wid
11+.Sh DESCRIPTION
12+.Nm
13+moves (or teleports) the window
14+.Ar wid
15+to the position given by
16+.Ar x
17+and
18+.Ar y ,
19+and resize it to width
20+.Ar w
21+and height
22+.Ar h .
23+Value are absolute value from the the upper-left-hand corner.
24+.Sh ENVIRONMENT
25+.Nm
26+acts on the X display specified by the
27+.Ev DISPLAY
28+variable.
+71, -0
 1@@ -0,0 +1,71 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <err.h>
 7+#include <xcb/xcb.h>
 8+#include <xcb/xcb_aux.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+enum {
14+	MAP     = 1 << 0,
15+	UNMAP   = 1 << 1,
16+	TOGGLE  = 1 << 2
17+};
18+
19+static xcb_connection_t *conn;
20+
21+static void usage(char *);
22+
23+static void
24+usage(char *name)
25+{
26+	fprintf(stderr, "usage: %s [-h] [-mut <wid> [wid..]]\n", name);
27+	exit(1);
28+}
29+
30+int
31+main(int argc, char **argv)
32+{
33+	int mapflag = 0;
34+	xcb_window_t w = 0;
35+	char *argv0;
36+
37+	ARGBEGIN {
38+		case 'm': mapflag = MAP;    break;
39+		case 'u': mapflag = UNMAP;  break;
40+		case 't': mapflag = TOGGLE; break;
41+		default : usage(argv0);
42+	} ARGEND;
43+
44+	if (argc < 1 || mapflag == 0)
45+		usage(argv0);
46+
47+	init_xcb(&conn);
48+
49+	while (*argv) {
50+		w = strtoul(*argv++, NULL, 16);
51+
52+		switch (mapflag) {
53+		case MAP:
54+			xcb_map_window(conn, w);
55+			break;
56+		case UNMAP:
57+			xcb_unmap_window(conn, w);
58+			break;
59+		case TOGGLE:
60+			if (mapped(conn, w))
61+				xcb_unmap_window(conn, w);
62+			else
63+				xcb_map_window(conn, w);
64+			break;
65+		}
66+	}
67+	xcb_aux_sync(conn);
68+
69+	kill_xcb(&conn);
70+
71+	return 0;
72+}
+81, -0
 1@@ -0,0 +1,81 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <err.h>
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <string.h>
 8+#include <xcb/xcb.h>
 9+#include <xcb/xcb_aux.h>
10+
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+static xcb_screen_t *scrn;
15+
16+static void usage(char *);
17+static xcb_window_t focus_window(void);
18+static xcb_window_t parent(xcb_window_t);
19+
20+static void
21+usage(char *name)
22+{
23+	fprintf(stderr, "usage: %s [wid]\n", name);
24+	exit(1);
25+}
26+
27+static xcb_window_t
28+focus_window(void)
29+{
30+	xcb_window_t w = 0;
31+	xcb_get_input_focus_cookie_t c;
32+	xcb_get_input_focus_reply_t *r;
33+
34+	c = xcb_get_input_focus(conn);
35+	r = xcb_get_input_focus_reply(conn, c, NULL);
36+	if (r == NULL)
37+		errx(1, "xcb_get_input_focus");
38+
39+	w = r->focus;
40+	free(r);
41+
42+	if (w == XCB_NONE || w == XCB_INPUT_FOCUS_POINTER_ROOT)
43+		errx(1, "focus not set");
44+
45+	return w;
46+}
47+
48+static xcb_window_t
49+parent(xcb_window_t w)
50+{
51+	xcb_query_tree_cookie_t c;
52+	xcb_query_tree_reply_t *r;
53+
54+	c = xcb_query_tree(conn, w);
55+	r = xcb_query_tree_reply(conn, c, NULL);
56+	if (r == NULL)
57+		errx(1, "failed to get parent");
58+
59+	w = (!r->parent || r->parent == scrn->root) ? w : parent(r->parent);
60+	free(r);
61+
62+	return w;
63+}
64+
65+int
66+main(int argc, char **argv)
67+{
68+	xcb_window_t w;
69+
70+	if (argc > 2 || (argc > 1 && (!strncmp(argv[1], "-h", 2))))
71+		usage(argv[0]);
72+
73+	init_xcb(&conn);
74+	get_screen(conn, &scrn);
75+
76+	w = (argc > 1) ? strtoul(argv[1], NULL, 16) : focus_window();
77+
78+	printf("0x%08x\n", parent(w));
79+
80+	kill_xcb(&conn);
81+	return 0;
82+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <err.h>
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <xcb/xcb.h>
 8+#include <xcb/xcb_aux.h>
 9+
10+#include "util.h"
11+
12+static xcb_connection_t *conn;
13+
14+static xcb_window_t focus_window(void);
15+
16+static xcb_window_t
17+focus_window(void)
18+{
19+	xcb_window_t w = 0;
20+	xcb_get_input_focus_cookie_t c;
21+	xcb_get_input_focus_reply_t *r;
22+
23+	c = xcb_get_input_focus(conn);
24+	r = xcb_get_input_focus_reply(conn, c, NULL);
25+	if (r == NULL)
26+		errx(1, "xcb_get_input_focus");
27+
28+	w = r->focus;
29+	free(r);
30+
31+	if (w == XCB_NONE || w == XCB_INPUT_FOCUS_POINTER_ROOT)
32+		errx(1, "focus not set");
33+
34+	return w;
35+}
36+
37+int
38+main(int argc, char **argv)
39+{
40+	init_xcb(&conn);
41+
42+	printf("0x%08x\n", focus_window());
43+
44+	kill_xcb(&conn);
45+	return 0;
46+}
+71, -0
 1@@ -0,0 +1,71 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <err.h>
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <xcb/xcb.h>
 8+#include <xcb/xcb_aux.h>
 9+#include <xcb/xcb_cursor.h>
10+
11+#include "util.h"
12+
13+/* use "heart" to show us your love! */
14+#define XHAIR "tcross"
15+
16+static xcb_connection_t *conn;
17+static xcb_screen_t *scr;
18+
19+static xcb_window_t
20+select_window(void)
21+{
22+	uint32_t val[] = { XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE  };
23+	xcb_window_t w = 0;
24+	xcb_cursor_t p;
25+	xcb_cursor_context_t *ctx;
26+	xcb_grab_pointer_cookie_t c;
27+	xcb_grab_pointer_reply_t *r;
28+	xcb_generic_event_t *e;
29+
30+	if (xcb_cursor_context_new(conn, scr, &ctx) < 0)
31+		errx(1, "cannot instantiate cursor");
32+
33+	p = xcb_cursor_load_cursor(ctx, XHAIR);
34+	xcb_flush(conn);
35+
36+	c = xcb_grab_pointer(conn, 0, scr->root,
37+		XCB_EVENT_MASK_BUTTON_PRESS | XCB_EVENT_MASK_BUTTON_RELEASE,
38+		XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, p,
39+		XCB_CURRENT_TIME);
40+
41+	r = xcb_grab_pointer_reply(conn, c, NULL);
42+	if (!r || r->status != XCB_GRAB_STATUS_SUCCESS)
43+		errx(1, "couldn't grab pointer");
44+
45+	xcb_change_window_attributes(conn, scr->root, XCB_CW_EVENT_MASK, val);
46+	xcb_flush(conn);
47+
48+	for (;;) {
49+		e = xcb_wait_for_event(conn);
50+		switch ((e->response_type & ~0x80)) {
51+		case XCB_BUTTON_PRESS:
52+			w = ((xcb_button_press_event_t*)e)->child;
53+			break;
54+		case XCB_BUTTON_RELEASE:
55+			xcb_cursor_context_free(ctx);
56+			return w;
57+			break; /* NOTREACHED */
58+		}
59+	}
60+}
61+
62+int
63+main(int argc, char **argv)
64+{
65+	init_xcb(&conn);
66+	get_screen(conn, &scr);
67+
68+	printf("0x%08x\n", select_window());
69+
70+	kill_xcb(&conn);
71+	return 0;
72+}
+106, -0
  1@@ -0,0 +1,106 @@
  2+#include <err.h>
  3+#include <stdlib.h>
  4+#include <string.h>
  5+#include <xcb/xcb.h>
  6+#include <xcb/xcb_aux.h>
  7+
  8+#include "util.h"
  9+
 10+void
 11+init_xcb(xcb_connection_t **con)
 12+{
 13+	*con = xcb_connect(NULL, NULL);
 14+	if (xcb_connection_has_error(*con))
 15+		errx(1, "unable connect to the X server");
 16+}
 17+
 18+void
 19+kill_xcb(xcb_connection_t **con)
 20+{
 21+	if (*con)
 22+		xcb_disconnect(*con);
 23+}
 24+
 25+void
 26+get_screen(xcb_connection_t *con, xcb_screen_t **scr)
 27+{
 28+	*scr = xcb_setup_roots_iterator(xcb_get_setup(con)).data;
 29+	if (*scr == NULL)
 30+		errx(1, "unable to retrieve screen informations");
 31+}
 32+
 33+int
 34+exists(xcb_connection_t *con, xcb_window_t w)
 35+{
 36+	xcb_get_window_attributes_cookie_t c;
 37+	xcb_get_window_attributes_reply_t  *r;
 38+
 39+	c = xcb_get_window_attributes(con, w);
 40+	r = xcb_get_window_attributes_reply(con, c, NULL);
 41+
 42+	if (r == NULL)
 43+		return 0;
 44+
 45+	free(r);
 46+	return 1;
 47+}
 48+
 49+int
 50+mapped(xcb_connection_t *con, xcb_window_t w)
 51+{
 52+	int ms;
 53+	xcb_get_window_attributes_cookie_t c;
 54+	xcb_get_window_attributes_reply_t  *r;
 55+
 56+	c = xcb_get_window_attributes(con, w);
 57+	r = xcb_get_window_attributes_reply(con, c, NULL);
 58+
 59+	if (r == NULL)
 60+		return 0;
 61+
 62+	ms = r->map_state;
 63+
 64+	free(r);
 65+	return ms == XCB_MAP_STATE_VIEWABLE;
 66+}
 67+
 68+int
 69+ignore(xcb_connection_t *con, xcb_window_t w)
 70+{
 71+	int or;
 72+	xcb_get_window_attributes_cookie_t c;
 73+	xcb_get_window_attributes_reply_t  *r;
 74+
 75+	c = xcb_get_window_attributes(con, w);
 76+	r = xcb_get_window_attributes_reply(con, c, NULL);
 77+
 78+	if (r == NULL)
 79+		return 0;
 80+
 81+	or = r->override_redirect;
 82+
 83+	free(r);
 84+	return or;
 85+}
 86+
 87+int
 88+get_windows(xcb_connection_t *con, xcb_window_t w, xcb_window_t **l)
 89+{
 90+	uint32_t childnum = 0;
 91+	xcb_query_tree_cookie_t c;
 92+	xcb_query_tree_reply_t *r;
 93+
 94+	c = xcb_query_tree(con, w);
 95+	r = xcb_query_tree_reply(con, c, NULL);
 96+	if (r == NULL)
 97+		errx(1, "0x%08x: no such window", w);
 98+
 99+	*l = malloc(sizeof(xcb_window_t) * r->children_len);
100+	memcpy(*l, xcb_query_tree_children(r),
101+			sizeof(xcb_window_t) * r->children_len);
102+
103+	childnum = r->children_len;
104+
105+	free(r);
106+	return childnum;
107+}
+14, -0
 1@@ -0,0 +1,14 @@
 2+#ifndef UTIL_H__
 3+#define UTIL_H__
 4+
 5+void init_xcb(xcb_connection_t **);
 6+void kill_xcb(xcb_connection_t **);
 7+
 8+void get_screen(xcb_connection_t *, xcb_screen_t **);
 9+int get_windows(xcb_connection_t *, xcb_window_t, xcb_window_t **);
10+
11+int exists(xcb_connection_t *, xcb_window_t);
12+int mapped(xcb_connection_t *, xcb_window_t);
13+int ignore(xcb_connection_t *, xcb_window_t);
14+
15+#endif
+118, -0
  1@@ -0,0 +1,118 @@
  2+/* See LICENSE file for copyright and license details. */
  3+
  4+#include <stdio.h>
  5+#include <stdlib.h>
  6+#include <string.h>
  7+#include <err.h>
  8+#include <xcb/xcb.h>
  9+#include <xcb/xcb_aux.h>
 10+
 11+#include "util.h"
 12+
 13+static xcb_connection_t *conn;
 14+
 15+static void usage(char *);
 16+static int get_attribute(xcb_window_t, int);
 17+
 18+enum {
 19+	ATTR_W = 1 << 0,
 20+	ATTR_H = 1 << 1,
 21+	ATTR_X = 1 << 2,
 22+	ATTR_Y = 1 << 3,
 23+	ATTR_B = 1 << 4,
 24+	ATTR_M = 1 << 5,
 25+	ATTR_I = 1 << 6,
 26+	ATTR_MAX
 27+};
 28+
 29+static void
 30+usage(char *name)
 31+{
 32+	fprintf(stderr, "usage: %s [-h] [bmiowhxy] <wid>\n", name);
 33+	exit(1);
 34+}
 35+
 36+static int
 37+get_attribute(xcb_window_t w, int attr)
 38+{
 39+	xcb_get_geometry_cookie_t c;
 40+	xcb_get_geometry_reply_t *r;
 41+
 42+	c = xcb_get_geometry(conn, w);
 43+	r = xcb_get_geometry_reply(conn, c, NULL);
 44+
 45+	if (r == NULL)
 46+		errx(1, "0x%08x: no such window", w);
 47+
 48+	switch (attr) {
 49+		case ATTR_X: attr = r->x; break;
 50+		case ATTR_Y: attr = r->y; break;
 51+		case ATTR_W: attr = r->width; break;
 52+		case ATTR_H: attr = r->height; break;
 53+		case ATTR_B: attr = r->border_width; break;
 54+	}
 55+
 56+	free(r);
 57+	return attr;
 58+}
 59+
 60+int
 61+main(int argc, char **argv)
 62+{
 63+	int c, ret = 0;
 64+	size_t i;
 65+	xcb_window_t w = 0;
 66+
 67+	if (argc < 2 || (strncmp(argv[1], "-h", 2) == 0)) {
 68+		usage(argv[0]);
 69+	}
 70+
 71+	init_xcb(&conn);
 72+
 73+	if (argc == 2) {
 74+		w = strtoul(argv[1], NULL, 16);
 75+		ret = exists(conn, w) ? 0 : 1;
 76+		goto end;
 77+	}
 78+
 79+	for (c=2; argv[c]; c++) {
 80+		w = strtoul(argv[c], NULL, 16);
 81+
 82+		for (i=0; i<strlen(argv[1]); i++) {
 83+			switch (argv[1][i]) {
 84+				case 'i':
 85+					printf("0x%08x", w);
 86+					break;
 87+				case 'b':
 88+					printf("%d", get_attribute(w, ATTR_B));
 89+					break;
 90+				case 'h': 
 91+					printf("%d", get_attribute(w, ATTR_H));
 92+					break;
 93+				case 'x':
 94+					printf("%d", get_attribute(w, ATTR_X));
 95+					break;
 96+				case 'y':
 97+					printf("%d", get_attribute(w, ATTR_Y));
 98+					break;
 99+				case 'w':
100+					printf("%d", get_attribute(w, ATTR_W));
101+					break;
102+				case 'o':
103+					ret = ignore(conn, w) ? 0 : 1;
104+					goto end;
105+				case 'm':
106+					ret = mapped(conn, w) ? 0 : 1;
107+					goto end;
108+				default: kill_xcb(&conn); usage(argv[0]);
109+			}
110+			/* add a space if more attribute come after */
111+			putc(i+1 < strlen(argv[1]) ? ' ' : '\n',stdout);
112+		}
113+	}
114+
115+end:
116+	kill_xcb(&conn);
117+
118+	return ret;
119+}
+92, -0
 1@@ -0,0 +1,92 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <xcb/xcb.h>
 5+#include <xcb/xcb_aux.h>
 6+#include <stdlib.h>
 7+#include <stdio.h>
 8+#include <err.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+enum {
14+	ABSOLUTE = 0,
15+	RELATIVE = 1
16+};
17+
18+static xcb_screen_t *scr;
19+static xcb_connection_t *conn;
20+
21+static void usage(char *);
22+static void spot_cursor(int, uint32_t);
23+static void warp_cursor(int, int, int);
24+
25+static void
26+usage(char *name)
27+{
28+	fprintf(stderr, "usage: %s [-ar <x> <y>] [wid]\n", name);
29+	exit(1);
30+}
31+
32+static void
33+spot_cursor(int mode, uint32_t win)
34+{
35+	xcb_query_pointer_reply_t *r;
36+	xcb_query_pointer_cookie_t c;
37+
38+	c = xcb_query_pointer(conn, win);
39+	r = xcb_query_pointer_reply(conn, c, NULL);
40+
41+	if (r == NULL)
42+		errx(1, "cannot retrieve pointer position");
43+
44+	if (r->child != XCB_NONE) {
45+		printf("%d %d\n", r->win_x, r->win_y);
46+	} else {
47+		printf("%d %d\n", r->root_x, r->root_y);
48+	}
49+}
50+
51+static void
52+warp_cursor(int x, int y, int mode)
53+{
54+	xcb_warp_pointer(conn, XCB_NONE, mode ? XCB_NONE : scr->root,
55+			0, 0, 0, 0, x, y);
56+}
57+
58+int
59+main(int argc, char **argv)
60+{
61+	char *argv0;
62+	int mode = ABSOLUTE;
63+	uint32_t win;
64+
65+	ARGBEGIN {
66+		case 'a': mode = ABSOLUTE;
67+			  break;
68+		case 'r': mode = RELATIVE;
69+			  break;
70+		default : usage(argv0);
71+	} ARGEND;
72+
73+	init_xcb(&conn);
74+	get_screen(conn, &scr);
75+
76+	switch (argc) {
77+		case 0:
78+		case 1:
79+			win = argc > 0 ? strtoul(*argv, NULL, 16) : scr->root;
80+			spot_cursor(mode, win);
81+			break;
82+		case 2:
83+			warp_cursor(atoi(argv[0]), atoi(argv[1]), mode);
84+			break;
85+		default:
86+			usage(argv0);
87+	}
88+	
89+	xcb_aux_sync(conn);
90+
91+	kill_xcb(&conn);
92+	return 0;
93+}
+100, -0
  1@@ -0,0 +1,100 @@
  2+/* See LICENSE file for copyright and license details. */
  3+
  4+#include <xcb/xcb.h>
  5+#include <xcb/xcb_aux.h>
  6+#include <stdio.h>
  7+#include <stdlib.h>
  8+#include <err.h>
  9+
 10+#include "util.h"
 11+
 12+enum {
 13+	ABSOLUTE = 0,
 14+	RELATIVE = 1
 15+};
 16+
 17+static xcb_connection_t *conn;
 18+static xcb_screen_t *scr;
 19+
 20+static void usage(char *);
 21+static void move(xcb_window_t, int, int, int);
 22+
 23+static void
 24+usage(char *name)
 25+{
 26+	fprintf(stderr, "usage: %s [-a] <x> <y> <win>\n", name);
 27+	exit(1);
 28+}
 29+
 30+static void
 31+move(xcb_window_t win, int mode, int x, int y)
 32+{
 33+	uint32_t values[2];
 34+	int real;
 35+	xcb_get_geometry_reply_t *geom;
 36+
 37+	if (!win || win == scr->root)
 38+		return;
 39+
 40+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 41+	if (!geom)
 42+		return;
 43+
 44+	if (mode == ABSOLUTE) {
 45+		x -= geom->x + geom->width /2;
 46+		y -= geom->y + geom->height/2;
 47+	}
 48+	values[0] = x ? geom->x + x : geom->x;
 49+	values[1] = y ? geom->y + y : geom->y;
 50+
 51+	if (x)
 52+	{
 53+		real = geom->width + (geom->border_width * 2);
 54+		if (geom->x + x < 1)
 55+			values[0] = 0;
 56+		if (geom->x + x > scr->width_in_pixels - real)
 57+			values[0] = scr->width_in_pixels - real;
 58+	}
 59+
 60+	if (y)
 61+	{
 62+		real = geom->height + (geom->border_width * 2);
 63+		if (geom->y + y < 1)
 64+			values[1] = 0;
 65+		if (geom->y + y > scr->height_in_pixels - real)
 66+			values[1] = scr->height_in_pixels - real;
 67+	}
 68+
 69+	xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X
 70+			| XCB_CONFIG_WINDOW_Y, values);
 71+
 72+	free(geom);
 73+}
 74+
 75+int
 76+main(int argc, char **argv)
 77+{
 78+	int x, y, mode = RELATIVE;
 79+	if (argc < 4)
 80+		usage(argv[0]);
 81+
 82+	init_xcb(&conn);
 83+	get_screen(conn, &scr);
 84+
 85+	if (argv[1][0] == '-' && argv[1][1] == 'a') {
 86+		mode = ABSOLUTE;
 87+		argv++;
 88+	}
 89+
 90+	x = atoi(*(++argv));
 91+	y = atoi(*(++argv));
 92+
 93+	while (*argv)
 94+		move(strtoul(*argv++, NULL, 16), mode, x, y);
 95+
 96+	xcb_aux_sync(conn);
 97+
 98+	kill_xcb(&conn);
 99+
100+	return 0;
101+}
+93, -0
 1@@ -0,0 +1,93 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <xcb/xcb.h>
 5+#include <xcb/xcb_aux.h>
 6+#include <stdio.h>
 7+#include <stdlib.h>
 8+#include <err.h>
 9+
10+#include "util.h"
11+
12+enum {
13+	ABSOLUTE = 0,
14+	RELATIVE = 1
15+};
16+
17+static xcb_connection_t *conn;
18+static xcb_screen_t *scr;
19+
20+static void usage(char *);
21+static void resize(xcb_window_t, int, int, int);
22+
23+static void
24+usage(char *name)
25+{
26+	fprintf(stderr, "usage: %s [-a] <x> <y> <wid> [wid..]\n", name);
27+	exit(1);
28+}
29+
30+static void
31+resize(xcb_window_t w, int mode, int x, int y)
32+{
33+	uint32_t val[3];
34+	uint32_t mask = XCB_CONFIG_WINDOW_WIDTH
35+	              | XCB_CONFIG_WINDOW_HEIGHT
36+	              | XCB_CONFIG_WINDOW_STACK_MODE;
37+	xcb_get_geometry_cookie_t c;
38+	xcb_get_geometry_reply_t *r;
39+
40+	c = xcb_get_geometry(conn, w);
41+	r = xcb_get_geometry_reply(conn, c, NULL);
42+
43+	if (r == NULL)
44+		return;
45+
46+	if (mode == ABSOLUTE) {
47+		x -= r->x + r->width;
48+		y -= r->y + r->height;
49+	}
50+
51+	if ((r->x + r->width + 2*r->border_width + x) > scr->width_in_pixels)
52+		x = scr->width_in_pixels - (
53+				r->x + r->width + (2*r->border_width));
54+
55+	if ((r->y + r->height + 2*r->border_width + y) > scr->height_in_pixels)
56+		y = scr->height_in_pixels - (
57+				r->y + r->height + (2*r->border_width));
58+
59+	val[0] = r->width  + x;
60+	val[1] = r->height + y;
61+	val[2] = XCB_STACK_MODE_ABOVE;
62+
63+	xcb_configure_window(conn, w, mask, val);
64+
65+	free(r);
66+}
67+
68+int
69+main(int argc, char **argv)
70+{
71+	int x, y, mode = RELATIVE;
72+	if (argc < 4)
73+		usage(argv[0]);
74+
75+	init_xcb(&conn);
76+	get_screen(conn, &scr);
77+
78+	if (argv[1][0] == '-' && argv[1][1] == 'a') {
79+		mode = ABSOLUTE;
80+		argv++;
81+	}
82+
83+	x = atoi(*(++argv));
84+	y = atoi(*(++argv));
85+
86+	while (*argv)
87+		resize(strtoul(*argv++, NULL, 16), mode, x, y);
88+
89+	xcb_aux_sync(conn);
90+
91+	kill_xcb(&conn);
92+
93+	return 0;
94+}
+44, -0
 1@@ -0,0 +1,44 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <xcb/xcb.h>
 5+#include <xcb/xcb_aux.h>
 6+#include <stdlib.h>
 7+#include <stdio.h>
 8+#include <string.h>
 9+#include <err.h>
10+
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+
15+static void usage (char *);
16+
17+static void
18+usage(char *name)
19+{
20+	fprintf(stderr, "usage: %s <wid>\n", name);
21+	exit(1);
22+}
23+
24+int
25+main(int argc, char **argv)
26+{
27+	xcb_window_t win;
28+
29+	if (argc != 2 || strncmp(argv[0], "-h", 2) == 0)
30+		usage(argv[0]);
31+
32+	init_xcb(&conn);
33+
34+	win = strtoul(argv[1], NULL, 16);
35+
36+	if (win) {
37+		xcb_set_input_focus(conn, XCB_INPUT_FOCUS_POINTER_ROOT, win,
38+				XCB_CURRENT_TIME);
39+
40+		xcb_aux_sync(conn);
41+	}
42+
43+	kill_xcb(&conn);
44+	return 0;
45+}
+61, -0
 1@@ -0,0 +1,61 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <xcb/xcb.h>
 5+#include <xcb/xcb_aux.h>
 6+#include <stdlib.h>
 7+#include <stdio.h>
 8+#include <err.h>
 9+
10+#include "util.h"
11+
12+static xcb_connection_t *conn;
13+
14+static void usage(char *name);
15+static void teleport(xcb_window_t, int, int, int, int);
16+
17+static void
18+usage(char *name)
19+{
20+	fprintf(stderr, "usage: %s <x> <y> <w> <h> <wid>\n", name);
21+	exit(1);
22+}
23+
24+static void
25+teleport(xcb_window_t win, int x, int y, int w, int h)
26+{
27+	uint32_t values[4];
28+	uint32_t mask =   XCB_CONFIG_WINDOW_X
29+                        | XCB_CONFIG_WINDOW_Y
30+                        | XCB_CONFIG_WINDOW_WIDTH
31+	                | XCB_CONFIG_WINDOW_HEIGHT;
32+
33+	values[0] = x;
34+	values[1] = y;
35+	values[2] = w;
36+	values[3] = h;
37+
38+	xcb_configure_window(conn, win, mask, values);
39+}
40+
41+int
42+main(int argc, char **argv)
43+{
44+	xcb_window_t win;
45+
46+	if (argc != 6)
47+		usage(argv[0]);
48+
49+	init_xcb(&conn);
50+
51+	win = strtoul(argv[5], NULL, 16);
52+	if (!win)
53+		errx(1, "cannot get window");
54+
55+	teleport(win, atoi(argv[1]), atoi(argv[2]),
56+			atoi(argv[3]), atoi(argv[4]));
57+	xcb_aux_sync(conn);
58+
59+	kill_xcb(&conn);
60+
61+	return 0;
62+}
+16, -0
 1@@ -0,0 +1,16 @@
 2+ISC License
 3+
 4+Copyright (c) 2014-2016 brosephs <dcat at iotek dot org>,
 5+                                 <willy at mailoo dot org>
 6+
 7+Permission to use, copy, modify, and distribute this software for any
 8+purpose with or without fee is hereby granted, provided that the above
 9+copyright notice and this permission notice appear in all copies.
10+
11+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
12+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
13+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
14+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
15+LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
16+OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
17+PERFORMANCE OF THIS SOFTWARE.
+49, -0
 1@@ -0,0 +1,49 @@
 2+include config.mk
 3+
 4+HDR = arg.h util.h
 5+SRC =           \
 6+	wew.c   \
 7+	chwb2.c \
 8+	wname.c \
 9+	xmmv.c  \
10+	xmrs.c  \
11+	chwn.c  \
12+	mwmd.c \
13+	mwtitle.c
14+
15+OBJ = $(SRC:.c=.o)
16+BIN = $(SRC:.c=)
17+
18+.POSIX:
19+
20+all: binutils
21+
22+binutils: $(BIN)
23+
24+manpages:
25+	cd man; $(MAKE) $(MFLAGS)
26+
27+$(OBJ): $(HDR) util.o
28+
29+.o:
30+	@echo "LD $@"
31+	@$(LD) $< util.o -o $@ $(LDFLAGS)
32+
33+.c.o:
34+	@echo "CC $<"
35+	@$(CC) -c $< -o $@ $(CFLAGS)
36+
37+install: $(BIN)
38+	mkdir -p $(DESTDIR)$(PREFIX)/bin/
39+	cp -f $(BIN) $(DESTDIR)$(PREFIX)/bin/
40+	cd man; $(MAKE) $(MFLAGS) install
41+
42+uninstall:
43+	@echo "uninstalling binaries"
44+	@for util in $(BIN); do \
45+		rm -f $(DESTDIR)$(PREFIX)/bin/$$util; \
46+	done
47+	cd man; $(MAKE) $(MFLAGS) uninstall
48+
49+clean:
50+	rm -f $(OBJ) $(BIN) util.o
+41, -0
 1@@ -0,0 +1,41 @@
 2+wmutils' opt
 3+=============
 4+
 5+opt is a set of optional utilities meant to accompany
 6+[core](https://github.com/wmutils/core).
 7+
 8+Just as the core programs, each utility does one job
 9+and does it well, like dealing with window events or names.
10+
11+utilities
12+---------
13+
14+opt has less utilities than core, here is a little overview:
15+
16+* chwb2 - control two different window borders
17+* wew   - print window events
18+* wname - print a window's name
19+* xmmv  - move a window with the mouse
20+* xmrs  - resize a window with the mouse
21+
22+For more information, refer to the programs manpages.
23+
24+dependencies
25+------------
26+
27+Like core, opt depends only on the XCB library.
28+
29+license
30+-------
31+
32+This project and all its code is licensed under the [ISC](http://www.openbsd.org/policy.html)
33+license. See the LICENSE file.
34+
35+build & install
36+---------------
37+
38+    $ make
39+    # make install
40+
41+In the file config.mk you can override build options,
42+such as the compiler flags or the installation path.
+63, -0
 1@@ -0,0 +1,63 @@
 2+/*
 3+ * Copy me if you can.
 4+ * by 20h
 5+ */
 6+
 7+#ifndef ARG_H__
 8+#define ARG_H__
 9+
10+extern char *argv0;
11+
12+/* use main(int argc, char *argv[]) */
13+#define ARGBEGIN	for (argv0 = *argv, argv++, argc--;\
14+					argv[0] && argv[0][1]\
15+					&& argv[0][0] == '-';\
16+					argc--, argv++) {\
17+				char argc_;\
18+				char **argv_;\
19+				int brk_;\
20+				if (argv[0][1] == '-' && argv[0][2] == '\0') {\
21+					argv++;\
22+					argc--;\
23+					break;\
24+				}\
25+				for (brk_ = 0, argv[0]++, argv_ = argv;\
26+						argv[0][0] && !brk_;\
27+						argv[0]++) {\
28+					if (argv_ != argv)\
29+						break;\
30+					argc_ = argv[0][0];\
31+					switch (argc_)
32+
33+/* Handles obsolete -NUM syntax */
34+#define ARGNUM				case '0':\
35+					case '1':\
36+					case '2':\
37+					case '3':\
38+					case '4':\
39+					case '5':\
40+					case '6':\
41+					case '7':\
42+					case '8':\
43+					case '9'
44+
45+#define ARGEND			}\
46+			}
47+
48+#define ARGC()		argc_
49+
50+#define ARGNUMF(base)	(brk_ = 1, estrtol(argv[0], (base)))
51+
52+#define EARGF(x)	((argv[0][1] == '\0' && argv[1] == NULL)?\
53+				((x), abort(), (char *)0) :\
54+				(brk_ = 1, (argv[0][1] != '\0')?\
55+					(&argv[0][1]) :\
56+					(argc--, argv++, argv[0])))
57+
58+#define ARGF()		((argv[0][1] == '\0' && argv[1] == NULL)?\
59+				(char *)0 :\
60+				(brk_ = 1, (argv[0][1] != '\0')?\
61+					(&argv[0][1]) :\
62+					(argc--, argv++, argv[0])))
63+
64+#endif
+243, -0
  1@@ -0,0 +1,243 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <xcb/xcb.h>
  4+#include <xcb/xcb_aux.h>
  5+#include <stdlib.h>
  6+#include <stdio.h>
  7+#include <string.h>
  8+#include <err.h>
  9+#include "arg.h"
 10+#include "util.h"
 11+
 12+static xcb_connection_t *conn;
 13+static void usage(char *name);
 14+static void set_border(int, int, xcb_window_t);
 15+static void set2border(xcb_window_t, int, int, int, int);
 16+static void monitor_and_update(xcb_window_t, int, int, int, int);
 17+
 18+static void
 19+usage(char *name)
 20+{
 21+	fprintf(stderr, "usage: %s <-s size> <-c color> | <-I icolor> <-O ocolor> <-i isize> <-o osize> [-w] <wid> [wid...]\n", name);
 22+	fprintf(stderr, "  -w: watch mode - continuously update borders on window resize\n");
 23+	exit(1);
 24+}
 25+
 26+static void
 27+set_border(int width, int color, xcb_window_t win)
 28+{
 29+	uint32_t values[3];
 30+	uint16_t curr_width;
 31+	int mask;
 32+	xcb_get_geometry_reply_t *geom;
 33+
 34+	if (width != -1) {
 35+		geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 36+		if (!geom)
 37+			return;
 38+
 39+		curr_width = geom->border_width;
 40+		values[0] = geom->x + curr_width - width;
 41+		values[1] = geom->y + curr_width - width;
 42+		values[2] = width;
 43+		mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_BORDER_WIDTH;
 44+		xcb_configure_window(conn, win, mask, values);
 45+		xcb_aux_sync(conn);
 46+		free(geom);
 47+	}
 48+
 49+	if (color != -1) {
 50+		values[0] = color;
 51+		mask = XCB_CW_BORDER_PIXEL;
 52+		xcb_change_window_attributes(conn, win, mask, values);
 53+		xcb_aux_sync(conn);
 54+	}
 55+}
 56+
 57+static void
 58+set2border(xcb_window_t win, int oc, int os, int ic, int is)
 59+{
 60+	if (os < 0 || oc < 0 || is < 0 || ic < 0)
 61+		return;
 62+
 63+	uint32_t values[3];
 64+	uint16_t curr_width;
 65+	int mask;
 66+	short w, h, b, o;
 67+	
 68+	xcb_get_geometry_reply_t *geom = xcb_get_geometry_reply(conn,
 69+			xcb_get_geometry(conn, win), NULL);
 70+	
 71+	if (geom == NULL)
 72+		return;
 73+
 74+	b = (unsigned short)(is + os);
 75+	curr_width = geom->border_width;
 76+	
 77+	/* Set border width first if needed */
 78+	if (curr_width != b) {
 79+		values[0] = geom->x + curr_width - b;
 80+		values[1] = geom->y + curr_width - b;
 81+		values[2] = b;
 82+		mask = XCB_CONFIG_WINDOW_X | XCB_CONFIG_WINDOW_Y | XCB_CONFIG_WINDOW_BORDER_WIDTH;
 83+		xcb_configure_window(conn, win, mask, values);
 84+		xcb_flush(conn);
 85+		
 86+		/* Re-get geometry after border width change */
 87+		free(geom);
 88+		geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 89+		if (geom == NULL)
 90+			return;
 91+	}
 92+
 93+	w = (short)geom->width;
 94+	h = (short)geom->height;
 95+	o = (unsigned short)os;
 96+
 97+	xcb_rectangle_t inner[] = {
 98+		{w, 0, b - o, h + b - o},
 99+		{w + b + o, 0, b - o, h + b - o},
100+		{0, h, w + b - o, b - o},
101+		{0, h + b + o, w + b - o, b - o},
102+		{w + b + o, b + h + o, b, b}
103+	};
104+
105+	xcb_rectangle_t outer[] = {
106+		{w + b - o, 0, o, h + b * 2},
107+		{w + b, 0, o, h + b * 2},
108+		{0, h + b - o, w + b * 2, o},
109+		{0, h + b, w + b * 2, o},
110+		{1, 1, 1, 1}
111+	};
112+
113+	xcb_pixmap_t pmap = xcb_generate_id(conn);
114+	xcb_create_pixmap(conn, geom->depth, pmap, win,
115+			w + (b * 2),
116+			h + (b * 2));
117+
118+	xcb_gcontext_t gc = xcb_generate_id(conn);
119+	xcb_create_gc(conn, gc, pmap, 0, NULL);
120+
121+	values[0] = oc;
122+	xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, values);
123+	xcb_poly_fill_rectangle(conn, pmap, gc, 5, outer);
124+
125+	values[0] = ic;
126+	xcb_change_gc(conn, gc, XCB_GC_FOREGROUND, values);
127+	xcb_poly_fill_rectangle(conn, pmap, gc, 5, inner);
128+
129+	values[0] = pmap;
130+	xcb_change_window_attributes(conn, win, XCB_CW_BORDER_PIXMAP, values);
131+
132+	xcb_flush(conn);
133+	xcb_free_pixmap(conn, pmap);
134+	xcb_free_gc(conn, gc);
135+	free(geom);
136+}
137+
138+static void
139+monitor_and_update(xcb_window_t win, int oc, int os, int ic, int is)
140+{
141+	uint32_t mask = XCB_CW_EVENT_MASK;
142+	uint32_t values[] = { XCB_EVENT_MASK_STRUCTURE_NOTIFY };
143+	
144+	xcb_change_window_attributes(conn, win, mask, values);
145+	xcb_flush(conn);
146+
147+	set2border(win, oc, os, ic, is);
148+
149+	xcb_generic_event_t *ev;
150+	uint16_t last_w = 0, last_h = 0;
151+
152+	while ((ev = xcb_wait_for_event(conn))) {
153+		switch (ev->response_type & ~0x80) {
154+			case XCB_CONFIGURE_NOTIFY: {
155+				xcb_configure_notify_event_t *e = (xcb_configure_notify_event_t *)ev;
156+				if (e->window == win) {
157+					if (e->width != last_w || e->height != last_h) {
158+						last_w = e->width;
159+						last_h = e->height;
160+						set2border(win, oc, os, ic, is);
161+					}
162+				}
163+				break;
164+			}
165+			case XCB_DESTROY_NOTIFY: {
166+				xcb_destroy_notify_event_t *e = (xcb_destroy_notify_event_t *)ev;
167+				if (e->window == win) {
168+					free(ev);
169+					return;
170+				}
171+				break;
172+			}
173+		}
174+		free(ev);
175+	}
176+}
177+
178+int
179+main(int argc, char **argv)
180+{
181+	char *argv0;
182+	int color, width;
183+	int oc, os, ic, is;
184+	int use_double_border = 0;
185+	int watch_mode = 0;
186+
187+	color = width = -1;
188+	oc = os = ic = is = -1;
189+
190+	if (argc < 2)
191+		usage(argv[0]);
192+
193+	ARGBEGIN {
194+		case 's':
195+			width = strtoul(EARGF(usage(argv0)), NULL, 10);
196+			break;
197+		case 'c':
198+			color = strtoul(EARGF(usage(argv0)), NULL, 16);
199+			break;
200+		case 'I':
201+			ic = strtoul(EARGF(usage(argv0)), NULL, 16);
202+			use_double_border = 1;
203+			break;
204+		case 'O':
205+			oc = strtoul(EARGF(usage(argv0)), NULL, 16);
206+			use_double_border = 1;
207+			break;
208+		case 'i':
209+			is = strtoul(EARGF(usage(argv0)), NULL, 10);
210+			use_double_border = 1;
211+			break;
212+		case 'o':
213+			os = strtoul(EARGF(usage(argv0)), NULL, 10);
214+			use_double_border = 1;
215+			break;
216+		case 'w':
217+			watch_mode = 1;
218+			break;
219+		default:
220+			usage(argv0);
221+	} ARGEND
222+
223+	init_xcb(&conn);
224+
225+	if (watch_mode && use_double_border && *argv) {
226+		/* Watch mode: only works with one window */
227+		xcb_window_t win = strtoul(*argv, NULL, 16);
228+		monitor_and_update(win, oc, os, ic, is);
229+	} else {
230+		/* Normal mode: set borders once */
231+		while (*argv) {
232+			xcb_window_t win = strtoul(*argv++, NULL, 16);
233+			if (use_double_border)
234+				set2border(win, oc, os, ic, is);
235+			else
236+				set_border(width, color, win);
237+		}
238+	}
239+
240+	xcb_aux_sync(conn);
241+	kill_xcb(&conn);
242+
243+	return 0;
244+}
+45, -0
 1@@ -0,0 +1,45 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <err.h>
 5+#include <stdio.h>
 6+#include <stdlib.h>
 7+#include <string.h>
 8+#include <xcb/xcb.h>
 9+
10+#include "arg.h"
11+#include "util.h"
12+
13+static xcb_connection_t *conn;
14+
15+static void usage(char *);
16+static void set_title(xcb_connection_t *, xcb_window_t, char *);
17+
18+static void
19+usage(char *name)
20+{
21+	fprintf(stderr, "usage: %s <name> <wid>\n", name);
22+	exit(1);
23+}
24+
25+void
26+set_title(xcb_connection_t *con, xcb_window_t w, char *name)
27+{
28+	xcb_change_property(con, XCB_PROP_MODE_REPLACE, w, XCB_ATOM_WM_NAME,
29+		XCB_ATOM_STRING, 8, strlen(name), name);
30+	xcb_flush(con);
31+}
32+
33+int
34+main(int argc, char **argv)
35+{
36+	if (argc != 3)
37+		usage(argv[0]);
38+
39+	init_xcb(&conn);
40+
41+	set_title(conn, strtoul(argv[2], NULL, 16), argv[1]);
42+
43+	kill_xcb(&conn);
44+
45+	return 0;
46+}
+8, -0
1@@ -0,0 +1,8 @@
2+PREFIX = /usr
3+MANPREFIX = $(PREFIX)/share/man
4+
5+CC = cc
6+LD = $(CC)
7+
8+CFLAGS += -std=c99 -pedantic -Wall -Os
9+LDFLAGS += -lxcb -lxcb-util
+21, -0
 1@@ -0,0 +1,21 @@
 2+include ../config.mk
 3+
 4+MAN =           \
 5+	wew.1   \
 6+	chwb2.1 \
 7+	wname.1 \
 8+	xmmv.1  \
 9+	chwn.1  \
10+	xmrs.1
11+
12+.POSIX:
13+
14+install: $(MAN)
15+	mkdir -p $(DESTDIR)$(MANPREFIX)/man1/
16+	cp -f $(MAN) $(DESTDIR)$(MANPREFIX)/man1/
17+
18+uninstall:
19+	@echo "uninstalling manpages"
20+	@for page in $(MAN); do \
21+		rm -f $(DESTDIR)$(MANPREFIX)/man1/$$page; \
22+	done
+45, -0
 1@@ -0,0 +1,45 @@
 2+.Dd December 13, 2014
 3+.Dt CHWB2 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm chwb2
 7+.Nd change window double-borders
 8+.Sh SYNOPSIS
 9+.Nm chwb2
10+.Op Fl I Ar inner color
11+.Op Fl O Ar outer color
12+.Op Fl i Ar inner size
13+.Op Fl o Ar outer size
14+.Ar wid Op Ar ...
15+.Sh DESCRIPTION
16+.Nm
17+applies a double pixmap border to
18+.Ar wid .
19+.Bl -tag -width Ds
20+.It Fl I Ar inner color
21+.It Fl O Ar outer color
22+Set the inner/outer border color of
23+.Ar wid
24+to
25+.Ar color .
26+Colors should be passed as a hex triplet without the '#' prefix (see
27+.Xr strtoul 3 )
28+in RGB format.
29+.It Fl i Ar size
30+.It Fl o Ar size
31+Sets the inner/outer border width of
32+.Ar wid
33+to
34+.Ar size .
35+.El
36+.Sh ENVIRONMENT
37+.Nm
38+acts on the X display specified by the
39+.Ev DISPLAY
40+variable.
41+.Sh EXAMPLES
42+Set the inner border of the current window to yellow with a black outer rim:
43+.Dl $ chwb2 -O 000000 -I ffff00 -i 3 -o 1 $(pfw)
44+.Sh SEE ALSO
45+.Xr chwb 1
46+.Xr strtoul 3
+22, -0
 1@@ -0,0 +1,22 @@
 2+'\" e
 3+.Dd September 26, 2016
 4+.Dt CHWN 1
 5+.Os wmutils
 6+.Sh NAME
 7+.Nm chwn
 8+.Nd set WM_NAME atom of a window
 9+.Sh SYNOPSIS
10+.Nm chwn
11+.Ar name wid
12+.Sh DESCRIPTION
13+.Nm chwn
14+sets the WM_NAME atom of
15+.Ar wid
16+to
17+.Ar name.
18+This is most of the time equivalent to renaming the window.
19+.Sh ENVIRONMENT
20+.Nm
21+acts on the X display specified by the
22+.Ev DISPLAY
23+variable.
+102, -0
  1@@ -0,0 +1,102 @@
  2+.Dd December 17, 2014
  3+.Dt WEW 1
  4+.Os wmutils
  5+.Sh NAME
  6+.Nm wew
  7+.Nd window event watcher
  8+.Sh SYNOPSIS
  9+.Nm wew
 10+.Op Fl l
 11+.Op Fl m Ar mask
 12+.Sh DESCRIPTION
 13+.Nm
 14+is a daemon that prints X events to stdout in the form:
 15+.Pp
 16+.Bd -literral
 17+.Ar event wid [args]
 18+.Ed
 19+.Pp
 20+See section EVENT VALUES for the possible values of
 21+.Ar event .
 22+.Bl -tag -width Ds
 23+.It Fl l
 24+List event mask values
 25+.It Fl m Ar mask
 26+Set new windows event mask to
 27+.Ar mask
 28+Multiple events are registered by performing a bitwise OR of their values.
 29+(defaults to STRUCTURE_NOTIFY|ENTER_NOTIFY|FOCUS_CHANGE). The events
 30+registered on the root window cannot be modified.
 31+.El
 32+.Sh EVENT VALUES
 33+Events will be reported according to these names:
 34+.Pp
 35+.Bl -bullet -compact
 36+.It
 37+.Dv CREATE
 38+.It
 39+.Dv DESTROY
 40+.It
 41+.Dv BUTTON_PRESS
 42+.It
 43+.Dv BUTTON_RELEASE
 44+.It
 45+.Dv MOTION
 46+.It
 47+.Dv ENTER
 48+.It
 49+.Dv LEAVE
 50+.It
 51+.Dv CONFIGURE
 52+.It
 53+.Dv KEY_PRESS
 54+.It
 55+.Dv FOCUS_IN
 56+.It
 57+.Dv FOCUS_OUT
 58+.It
 59+.Dv KEYMAP
 60+.It
 61+.Dv EXPOSE
 62+.It
 63+.Dv GRAPHICS_EXPOSURE
 64+.It
 65+.Dv NO_EXPOSURE
 66+.It
 67+.Dv VISIBILITY
 68+.It
 69+.Dv UNMAP
 70+.It
 71+.Dv MAP
 72+.It
 73+.Dv MAP_REQUEST
 74+.It
 75+.Dv REPARENT
 76+.It
 77+.Dv CONFIGURE_REQUEST
 78+.It
 79+.Dv GRAVITY
 80+.It
 81+.Dv RESIZE_REQUEST
 82+.It
 83+.Dv CIRCULATE
 84+.It
 85+.Dv PROPERTY
 86+.It
 87+.Dv SELECTION_CLEAR
 88+.It
 89+.Dv SELECTION_REQUEST
 90+.It
 91+.Dv SELECTION
 92+.It
 93+.Dv COLORMAP
 94+.It
 95+.Dv CLIENT_MESSAGE
 96+.It
 97+.Dv MAPPING
 98+.El
 99+.Sh ENVIRONMENT
100+.Nm
101+acts on the X display specified by the
102+.Ev DISPLAY
103+variable.
+18, -0
 1@@ -0,0 +1,18 @@
 2+.Dd December 13, 2014
 3+.Dt WNAME 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm wname
 7+.Nd print window name
 8+.Sh SYNOPSIS
 9+.Nm wname
10+.Ar wid Op ...
11+.Sh DESCRIPTION
12+.Nm
13+prints the name of the window IDs given as arguments,
14+one name per line.
15+.Sh ENVIRONMENT
16+.Nm
17+acts on the X display specified by the
18+.Ev DISPLAY
19+variable.
+20, -0
 1@@ -0,0 +1,20 @@
 2+.Dd June 10, 2015
 3+.Dt XMMV 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm xmmv
 7+.Nd X mouse move
 8+.Sh SYNOPSIS
 9+.Nm
10+.Ar <wid>
11+.Sh DESCRIPTION
12+.Nm
13+moves windows with mouse, places window on keydown
14+.Sh ENVIRONMENT
15+.Nm
16+acts on the X display specified by the
17+.Ev DISPLAY
18+variable.
19+.Sh SEE ALSO
20+.Xr chwb 1 ,
21+.Xr strtoul 3
+20, -0
 1@@ -0,0 +1,20 @@
 2+.Dd June 10, 2015
 3+.Dt XMRS 1
 4+.Os wmutils
 5+.Sh NAME
 6+.Nm xmrs
 7+.Nd X mouse resize
 8+.Sh SYNOPSIS
 9+.Nm
10+.Ar <wid>
11+.Sh DESCRIPTION
12+.Nm
13+resizes windows with mouse, places window on keydown
14+.Sh ENVIRONMENT
15+.Nm
16+acts on the X display specified by the
17+.Ev DISPLAY
18+variable.
19+.Sh SEE ALSO
20+.Xr chwb 1 ,
21+.Xr strtoul 3
+354, -0
  1@@ -0,0 +1,354 @@
  2+/* mwmd - window manager daemon for move/resize */
  3+// vibecoded, for educational purposes only
  4+#include <xcb/xcb.h>
  5+#include <xcb/xcb_aux.h>
  6+#include <stdlib.h>
  7+#include <stdio.h>
  8+#include <err.h>
  9+#include <string.h>
 10+#include <signal.h>
 11+#include <unistd.h>
 12+
 13+static xcb_connection_t *conn;
 14+static xcb_screen_t *scr;
 15+static int running = 1;
 16+
 17+static void
 18+cleanup(void)
 19+{
 20+	if (conn)
 21+		xcb_disconnect(conn);
 22+}
 23+
 24+static void
 25+signal_handler(int sig)
 26+{
 27+	(void)sig;
 28+	running = 0;
 29+}
 30+
 31+static void
 32+init_xcb(void)
 33+{
 34+	conn = xcb_connect(NULL, NULL);
 35+	if (xcb_connection_has_error(conn))
 36+		errx(1, "cannot connect to X server");
 37+}
 38+
 39+static void
 40+get_screen(void)
 41+{
 42+	const xcb_setup_t *setup = xcb_get_setup(conn);
 43+	xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
 44+	scr = iter.data;
 45+}
 46+
 47+static void
 48+grab_keys(void)
 49+{
 50+	// Mod1 = Alt, Mod4 = Super
 51+	uint32_t mods[] = { XCB_MOD_MASK_4 };
 52+	
 53+	for (int i = 0; i < 2; i++) {
 54+		// Alt+Left Click = Move
 55+		xcb_grab_button(conn, 0, scr->root,
 56+				XCB_EVENT_MASK_BUTTON_PRESS
 57+				| XCB_EVENT_MASK_BUTTON_RELEASE
 58+				| XCB_EVENT_MASK_POINTER_MOTION,
 59+				XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
 60+				scr->root, XCB_NONE,
 61+				XCB_BUTTON_INDEX_1, mods[i]);
 62+		
 63+		// Alt+Right Click = Resize
 64+		xcb_grab_button(conn, 0, scr->root,
 65+				XCB_EVENT_MASK_BUTTON_PRESS
 66+				| XCB_EVENT_MASK_BUTTON_RELEASE
 67+				| XCB_EVENT_MASK_POINTER_MOTION,
 68+				XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
 69+				scr->root, XCB_NONE,
 70+				XCB_BUTTON_INDEX_3, mods[i]);
 71+	}
 72+	
 73+	xcb_flush(conn);
 74+}
 75+
 76+static xcb_window_t
 77+get_window_at_pointer(void)
 78+{
 79+	xcb_query_pointer_reply_t *ptr;
 80+	xcb_window_t child = XCB_NONE;
 81+	
 82+	ptr = xcb_query_pointer_reply(conn,
 83+			xcb_query_pointer(conn, scr->root), NULL);
 84+	if (!ptr)
 85+		return XCB_NONE;
 86+	
 87+	child = ptr->child;
 88+	free(ptr);
 89+	return child;
 90+}
 91+
 92+static void
 93+move_window(xcb_window_t win)
 94+{
 95+	uint32_t values[2];
 96+	xcb_get_geometry_reply_t *geom;
 97+	xcb_generic_event_t *ev = NULL;
 98+	int orig_x, orig_y;
 99+	int start_x, start_y;
100+	int button_pressed = 1;
101+
102+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
103+	if (!geom)
104+		return;
105+
106+	orig_x = geom->x;
107+	orig_y = geom->y;
108+	
109+	xcb_query_pointer_reply_t *ptr;
110+	ptr = xcb_query_pointer_reply(conn,
111+			xcb_query_pointer(conn, scr->root), NULL);
112+	if (ptr) {
113+		start_x = ptr->root_x;
114+		start_y = ptr->root_y;
115+		free(ptr);
116+	}
117+	
118+	free(geom);
119+
120+	while ((ev = xcb_wait_for_event(conn))) {
121+		switch (ev->response_type & ~0x80) {
122+		case XCB_MOTION_NOTIFY: {
123+			if (!button_pressed)
124+				break;
125+				
126+			xcb_motion_notify_event_t *m = (xcb_motion_notify_event_t *)ev;
127+			
128+			int new_x = orig_x + (m->root_x - start_x);
129+			int new_y = orig_y + (m->root_y - start_y);
130+			
131+			if (new_x < 0) new_x = 0;
132+			if (new_y < 0) new_y = 0;
133+			if (new_x + 10 > scr->width_in_pixels)
134+				new_x = scr->width_in_pixels - 10;
135+			if (new_y + 10 > scr->height_in_pixels)
136+				new_y = scr->height_in_pixels - 10;
137+			
138+			values[0] = new_x;
139+			values[1] = new_y;
140+			
141+			xcb_configure_window(conn, win,
142+					XCB_CONFIG_WINDOW_X
143+					| XCB_CONFIG_WINDOW_Y,
144+					values);
145+			xcb_flush(conn);
146+			break;
147+		}
148+		case XCB_BUTTON_RELEASE: {
149+			xcb_button_release_event_t *b = (xcb_button_release_event_t *)ev;
150+			if (b->detail == XCB_BUTTON_INDEX_1 && button_pressed) {
151+				button_pressed = 0;
152+				free(ev);
153+				return;
154+			}
155+			break;
156+		}
157+		}
158+		free(ev);
159+	}
160+}
161+
162+static int
163+get_corner(xcb_window_t win, int root_x, int root_y)
164+{
165+	xcb_get_geometry_reply_t *geom;
166+	int corner = 3;
167+	
168+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
169+	if (!geom)
170+		return 3;
171+	
172+	int win_w = geom->width;
173+	int win_h = geom->height;
174+	int border = geom->border_width;
175+	
176+	int rx = root_x - geom->x - border;
177+	int ry = root_y - geom->y - border;
178+	
179+	int dist_tl = rx*rx + ry*ry;
180+	int dist_tr = (win_w - rx)*(win_w - rx) + ry*ry;
181+	int dist_bl = rx*rx + (win_h - ry)*(win_h - ry);
182+	int dist_br = (win_w - rx)*(win_w - rx) + (win_h - ry)*(win_h - ry);
183+	
184+	int min_dist = dist_tl;
185+	corner = 0;
186+	if (dist_tr < min_dist) { min_dist = dist_tr; corner = 1; }
187+	if (dist_bl < min_dist) { min_dist = dist_bl; corner = 2; }
188+	if (dist_br < min_dist) { min_dist = dist_br; corner = 3; }
189+	
190+	free(geom);
191+	return corner;
192+}
193+
194+static void
195+resize_window(xcb_window_t win)
196+{
197+	uint32_t values[4];
198+	xcb_get_geometry_reply_t *geom;
199+	xcb_generic_event_t *ev = NULL;
200+	int orig_x, orig_y, orig_w, orig_h;
201+	int start_x, start_y;
202+	int corner;
203+	int button_pressed = 1;
204+
205+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
206+	if (!geom)
207+		return;
208+
209+	orig_x = geom->x;
210+	orig_y = geom->y;
211+	orig_w = geom->width;
212+	orig_h = geom->height;
213+	
214+	xcb_query_pointer_reply_t *ptr;
215+	ptr = xcb_query_pointer_reply(conn,
216+			xcb_query_pointer(conn, scr->root), NULL);
217+	if (ptr) {
218+		start_x = ptr->root_x;
219+		start_y = ptr->root_y;
220+		corner = get_corner(win, ptr->root_x, ptr->root_y);
221+		free(ptr);
222+	}
223+	
224+	free(geom);
225+
226+	while ((ev = xcb_wait_for_event(conn))) {
227+		switch (ev->response_type & ~0x80) {
228+		case XCB_MOTION_NOTIFY: {
229+			if (!button_pressed)
230+				break;
231+				
232+			xcb_motion_notify_event_t *m = (xcb_motion_notify_event_t *)ev;
233+			
234+			int new_x = orig_x;
235+			int new_y = orig_y;
236+			int new_w = orig_w;
237+			int new_h = orig_h;
238+			
239+			int dx = m->root_x - start_x;
240+			int dy = m->root_y - start_y;
241+			
242+			switch (corner) {
243+			case 0:
244+				new_x = orig_x + dx;
245+				new_y = orig_y + dy;
246+				new_w = orig_w - dx;
247+				new_h = orig_h - dy;
248+				break;
249+			case 1:
250+				new_y = orig_y + dy;
251+				new_w = orig_w + dx;
252+				new_h = orig_h - dy;
253+				break;
254+			case 2:
255+				new_x = orig_x + dx;
256+				new_w = orig_w - dx;
257+				new_h = orig_h + dy;
258+				break;
259+			case 3:
260+			default:
261+				new_w = orig_w + dx;
262+				new_h = orig_h + dy;
263+				break;
264+			}
265+			
266+			if (new_w < 10) new_w = 10;
267+			if (new_h < 10) new_h = 10;
268+			if (new_x + new_w + 2 > scr->width_in_pixels)
269+				new_w = scr->width_in_pixels - new_x - 2;
270+			if (new_y + new_h + 2 > scr->height_in_pixels)
271+				new_h = scr->height_in_pixels - new_y - 2;
272+			if (new_x < 0) {
273+				new_w += new_x;
274+				new_x = 0;
275+			}
276+			if (new_y < 0) {
277+				new_h += new_y;
278+				new_y = 0;
279+			}
280+			if (new_w < 10) new_w = 10;
281+			if (new_h < 10) new_h = 10;
282+			
283+			values[0] = new_x;
284+			values[1] = new_y;
285+			values[2] = new_w;
286+			values[3] = new_h;
287+			
288+			xcb_configure_window(conn, win,
289+					XCB_CONFIG_WINDOW_X
290+					| XCB_CONFIG_WINDOW_Y
291+					| XCB_CONFIG_WINDOW_WIDTH
292+					| XCB_CONFIG_WINDOW_HEIGHT,
293+					values);
294+			xcb_flush(conn);
295+			break;
296+		}
297+		case XCB_BUTTON_RELEASE: {
298+			xcb_button_release_event_t *b = (xcb_button_release_event_t *)ev;
299+			if ((b->detail == XCB_BUTTON_INDEX_1 || 
300+			     b->detail == XCB_BUTTON_INDEX_3) && button_pressed) {
301+				button_pressed = 0;
302+				free(ev);
303+				return;
304+			}
305+			break;
306+		}
307+		}
308+		free(ev);
309+	}
310+}
311+
312+int
313+main(void)
314+{
315+	xcb_generic_event_t *ev;
316+	
317+	init_xcb();
318+	get_screen();
319+	atexit(cleanup);
320+	
321+	signal(SIGINT, signal_handler);
322+	signal(SIGTERM, signal_handler);
323+	
324+	grab_keys();
325+	
326+	printf("mwmd started. Use Alt+Click to move, Alt+RightClick to resize\n");
327+	
328+	while (running && (ev = xcb_wait_for_event(conn))) {
329+		switch (ev->response_type & ~0x80) {
330+		case XCB_BUTTON_PRESS: {
331+			xcb_button_press_event_t *b = (xcb_button_press_event_t *)ev;
332+			xcb_window_t win = b->child;
333+			
334+			if (win == XCB_NONE)
335+				win = get_window_at_pointer();
336+			
337+			if (win == scr->root || win == XCB_NONE) {
338+				free(ev);
339+				continue;
340+			}
341+			
342+			if (b->detail == XCB_BUTTON_INDEX_1) {
343+				move_window(win);
344+			} else if (b->detail == XCB_BUTTON_INDEX_3) {
345+				resize_window(win);
346+			}
347+			break;
348+		}
349+		}
350+		free(ev);
351+	}
352+	
353+	cleanup();
354+	return 0;
355+}
+324, -0
  1@@ -0,0 +1,324 @@
  2+/* mwtitle - titlebar daemon */
  3+// vibecoded, for educational purposes only
  4+
  5+#include <xcb/xcb.h>
  6+#include <stdlib.h>
  7+#include <stdio.h>
  8+#include <string.h>
  9+#include <err.h>
 10+#include <signal.h>
 11+#include <unistd.h>
 12+
 13+static xcb_connection_t *conn;
 14+static xcb_screen_t *scr;
 15+static int running = 1;
 16+
 17+typedef struct {
 18+	xcb_window_t win;
 19+	xcb_window_t title;
 20+	int height;
 21+} Client;
 22+
 23+static Client *clients = NULL;
 24+static int client_count = 0;
 25+
 26+static void
 27+cleanup(void)
 28+{
 29+	if (conn)
 30+		xcb_disconnect(conn);
 31+	free(clients);
 32+}
 33+
 34+static void
 35+signal_handler(int sig)
 36+{
 37+	(void)sig;
 38+	running = 0;
 39+}
 40+
 41+static void
 42+init_xcb(void)
 43+{
 44+	conn = xcb_connect(NULL, NULL);
 45+	if (xcb_connection_has_error(conn))
 46+		errx(1, "cannot connect to X server");
 47+}
 48+
 49+static void
 50+get_screen(void)
 51+{
 52+	const xcb_setup_t *setup = xcb_get_setup(conn);
 53+	xcb_screen_iterator_t iter = xcb_setup_roots_iterator(setup);
 54+	scr = iter.data;
 55+}
 56+
 57+static int
 58+find_client(xcb_window_t win)
 59+{
 60+	for (int i = 0; i < client_count; i++) {
 61+		if (clients[i].win == win)
 62+			return i;
 63+	}
 64+	return -1;
 65+}
 66+
 67+static int
 68+is_titlebar(xcb_window_t win)
 69+{
 70+	for (int i = 0; i < client_count; i++) {
 71+		if (clients[i].title == win)
 72+			return 1;
 73+	}
 74+	return 0;
 75+}
 76+
 77+static void
 78+remove_client(int idx)
 79+{
 80+	if (idx < 0 || idx >= client_count)
 81+		return;
 82+	
 83+	if (clients[idx].title)
 84+		xcb_destroy_window(conn, clients[idx].title);
 85+	xcb_flush(conn);
 86+	
 87+	if (idx < client_count - 1) {
 88+		memmove(&clients[idx], &clients[idx + 1],
 89+				(client_count - idx - 1) * sizeof(Client));
 90+	}
 91+	client_count--;
 92+	clients = realloc(clients, client_count * sizeof(Client));
 93+}
 94+
 95+static int
 96+window_is_visible(xcb_window_t win)
 97+{
 98+	xcb_get_window_attributes_reply_t *attrs;
 99+	attrs = xcb_get_window_attributes_reply(conn,
100+			xcb_get_window_attributes(conn, win), NULL);
101+	if (!attrs)
102+		return 0;
103+	
104+	int visible = (attrs->map_state == XCB_MAP_STATE_VIEWABLE && 
105+	               !attrs->override_redirect);
106+	free(attrs);
107+	return visible;
108+}
109+
110+static void
111+add_titlebar(xcb_window_t win, int height)
112+{
113+	xcb_get_geometry_reply_t *geom;
114+	xcb_window_t title_win;
115+	uint32_t values[8];
116+	uint32_t mask;
117+	
118+	if (is_titlebar(win))
119+		return;
120+	
121+	if (find_client(win) >= 0)
122+		return;
123+	
124+	if (!window_is_visible(win) || win == scr->root)
125+		return;
126+	
127+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
128+	if (!geom)
129+		return;
130+	
131+	if (geom->width < 10 || geom->height < 10) {
132+		free(geom);
133+		return;
134+	}
135+	
136+	xcb_translate_coordinates_reply_t *trans;
137+	trans = xcb_translate_coordinates_reply(conn,
138+			xcb_translate_coordinates(conn, win, scr->root, 0, 0), NULL);
139+	
140+	int win_x = geom->x;
141+	int win_y = geom->y;
142+	if (trans) {
143+		win_x = trans->dst_x;
144+		win_y = trans->dst_y;
145+		free(trans);
146+	}
147+	
148+	title_win = xcb_generate_id(conn);
149+	
150+	mask = XCB_CW_BACK_PIXEL | 
151+	       XCB_CW_BORDER_PIXEL | 
152+	       XCB_CW_OVERRIDE_REDIRECT |
153+	       XCB_CW_EVENT_MASK;
154+	
155+	values[0] = 0x000000;
156+	values[1] = 0x000000;
157+	values[2] = 1;
158+	values[3] = XCB_EVENT_MASK_EXPOSURE;
159+	
160+	xcb_create_window(conn, XCB_COPY_FROM_PARENT, title_win, scr->root,
161+			win_x, win_y - height,
162+			geom->width, height,
163+			0,
164+			XCB_WINDOW_CLASS_INPUT_OUTPUT,
165+			scr->root_visual,
166+			mask, values);
167+	
168+	clients = realloc(clients, (client_count + 1) * sizeof(Client));
169+	clients[client_count].win = win;
170+	clients[client_count].title = title_win;
171+	clients[client_count].height = height;
172+	client_count++;
173+	
174+	xcb_map_window(conn, title_win);
175+	
176+	uint32_t stack_values[] = { XCB_STACK_MODE_ABOVE };
177+	xcb_configure_window(conn, title_win,
178+			XCB_CONFIG_WINDOW_STACK_MODE, stack_values);
179+	
180+	xcb_flush(conn);
181+	
182+	free(geom);
183+}
184+
185+static void
186+update_titlebar(xcb_window_t win)
187+{
188+	int idx = find_client(win);
189+	if (idx < 0)
190+		return;
191+	
192+	xcb_get_geometry_reply_t *geom;
193+	uint32_t values[4];
194+	
195+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
196+	if (!geom)
197+		return;
198+	
199+	xcb_translate_coordinates_reply_t *trans;
200+	trans = xcb_translate_coordinates_reply(conn,
201+			xcb_translate_coordinates(conn, win, scr->root, 0, 0), NULL);
202+	
203+	int win_x = geom->x;
204+	int win_y = geom->y;
205+	if (trans) {
206+		win_x = trans->dst_x;
207+		win_y = trans->dst_y;
208+		free(trans);
209+	}
210+	
211+	values[0] = win_x;
212+	values[1] = win_y - clients[idx].height;
213+	values[2] = geom->width;
214+	values[3] = clients[idx].height;
215+	
216+	xcb_configure_window(conn, clients[idx].title,
217+			XCB_CONFIG_WINDOW_X |
218+			XCB_CONFIG_WINDOW_Y |
219+			XCB_CONFIG_WINDOW_WIDTH |
220+			XCB_CONFIG_WINDOW_HEIGHT,
221+			values);
222+	
223+	uint32_t stack_values[] = { XCB_STACK_MODE_ABOVE };
224+	xcb_configure_window(conn, clients[idx].title,
225+			XCB_CONFIG_WINDOW_STACK_MODE, stack_values);
226+	
227+	xcb_flush(conn);
228+	free(geom);
229+}
230+
231+static void
232+scan_existing_windows(int height)
233+{
234+	xcb_query_tree_reply_t *tree;
235+	xcb_window_t *children;
236+	
237+	tree = xcb_query_tree_reply(conn, xcb_query_tree(conn, scr->root), NULL);
238+	if (!tree)
239+		return;
240+	
241+	children = xcb_query_tree_children(tree);
242+	int num_children = xcb_query_tree_children_length(tree);
243+	
244+	for (int i = 0; i < num_children; i++) {
245+		xcb_window_t win = children[i];
246+		add_titlebar(win, height);
247+	}
248+	
249+	free(tree);
250+}
251+
252+int
253+main(int argc, char **argv)
254+{
255+	xcb_generic_event_t *ev;
256+	int height = 30;
257+	
258+	init_xcb();
259+	get_screen();
260+	atexit(cleanup);
261+	
262+	signal(SIGINT, signal_handler);
263+	signal(SIGTERM, signal_handler);
264+	
265+	uint32_t values[] = { 
266+		XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY |
267+		XCB_EVENT_MASK_PROPERTY_CHANGE
268+	};
269+	xcb_change_window_attributes(conn, scr->root, XCB_CW_EVENT_MASK, values);
270+	xcb_flush(conn);
271+	
272+	scan_existing_windows(height);
273+	
274+	printf("mwtitle started. Height: %dpx\n", height);
275+	
276+	while (running && (ev = xcb_wait_for_event(conn))) {
277+		switch (ev->response_type & ~0x80) {
278+		case XCB_CONFIGURE_NOTIFY: {
279+			xcb_configure_notify_event_t *cn = (xcb_configure_notify_event_t *)ev;
280+			if (cn->window != scr->root && !is_titlebar(cn->window)) {
281+				update_titlebar(cn->window);
282+			}
283+			break;
284+		}
285+		case XCB_DESTROY_NOTIFY: {
286+			xcb_destroy_notify_event_t *d = (xcb_destroy_notify_event_t *)ev;
287+			if (d->window != scr->root) {
288+				int idx = find_client(d->window);
289+				if (idx >= 0) {
290+					remove_client(idx);
291+				}
292+			}
293+			break;
294+		}
295+		case XCB_UNMAP_NOTIFY: {
296+			xcb_unmap_notify_event_t *u = (xcb_unmap_notify_event_t *)ev;
297+			if (u->window != scr->root && !is_titlebar(u->window)) {
298+				int idx = find_client(u->window);
299+				if (idx >= 0) {
300+					xcb_unmap_window(conn, clients[idx].title);
301+					xcb_flush(conn);
302+				}
303+			}
304+			break;
305+		}
306+		case XCB_MAP_NOTIFY: {
307+			xcb_map_notify_event_t *m = (xcb_map_notify_event_t *)ev;
308+			if (m->window != scr->root && !is_titlebar(m->window)) {
309+				int idx = find_client(m->window);
310+				if (idx >= 0) {
311+					xcb_map_window(conn, clients[idx].title);
312+					update_titlebar(m->window);
313+					xcb_flush(conn);
314+				} else {
315+					add_titlebar(m->window, height);
316+				}
317+			}
318+			break;
319+		}
320+		}
321+		free(ev);
322+	}
323+	
324+	return 0;
325+}
+101, -0
  1@@ -0,0 +1,101 @@
  2+#include <err.h>
  3+#include <stdlib.h>
  4+#include <xcb/xcb.h>
  5+
  6+#include "util.h"
  7+
  8+void
  9+init_xcb(xcb_connection_t **con)
 10+{
 11+	*con = xcb_connect(NULL, NULL);
 12+	if (xcb_connection_has_error(*con))
 13+		errx(1, "unable connect to the X server");
 14+}
 15+
 16+void
 17+kill_xcb(xcb_connection_t **con)
 18+{
 19+	if (*con)
 20+		xcb_disconnect(*con);
 21+}
 22+
 23+void
 24+get_screen(xcb_connection_t *con, xcb_screen_t **scr)
 25+{
 26+	*scr = xcb_setup_roots_iterator(xcb_get_setup(con)).data;
 27+	if (*scr == NULL)
 28+		errx(1, "unable to retrieve screen informations");
 29+}
 30+
 31+int
 32+exists(xcb_connection_t *con, xcb_window_t w)
 33+{
 34+	xcb_get_window_attributes_cookie_t c;
 35+	xcb_get_window_attributes_reply_t  *r;
 36+
 37+	c = xcb_get_window_attributes(con, w);
 38+	r = xcb_get_window_attributes_reply(con, c, NULL);
 39+
 40+	if (r == NULL)
 41+		return 0;
 42+
 43+	return 1;
 44+}
 45+
 46+int
 47+mapped(xcb_connection_t *con, xcb_window_t w)
 48+{
 49+	int ms;
 50+	xcb_get_window_attributes_cookie_t c;
 51+	xcb_get_window_attributes_reply_t  *r;
 52+
 53+	c = xcb_get_window_attributes(con, w);
 54+	r = xcb_get_window_attributes_reply(con, c, NULL);
 55+
 56+	if (r == NULL)
 57+		return 0;
 58+
 59+	ms = r->map_state;
 60+
 61+	free(r);
 62+	return ms == XCB_MAP_STATE_VIEWABLE;
 63+}
 64+
 65+int
 66+ignore(xcb_connection_t *con, xcb_window_t w)
 67+{
 68+	int or;
 69+	xcb_get_window_attributes_cookie_t c;
 70+	xcb_get_window_attributes_reply_t  *r;
 71+
 72+	c = xcb_get_window_attributes(con, w);
 73+	r = xcb_get_window_attributes_reply(con, c, NULL);
 74+
 75+	if (r == NULL)
 76+		return 0;
 77+
 78+	or = r->override_redirect;
 79+
 80+	free(r);
 81+	return or;
 82+}
 83+
 84+int
 85+get_windows(xcb_connection_t *con, xcb_window_t w, xcb_window_t **l)
 86+{
 87+	int childnum = 0;
 88+	xcb_query_tree_cookie_t c;
 89+	xcb_query_tree_reply_t *r;
 90+
 91+	c = xcb_query_tree(con, w);
 92+	r = xcb_query_tree_reply(con, c, NULL);
 93+	if (r == NULL)
 94+		errx(1, "0x%08x: no such window", w);
 95+
 96+	*l = xcb_query_tree_children(r);
 97+
 98+	childnum = r->children_len;
 99+	free(r);
100+
101+	return childnum;
102+}
+14, -0
 1@@ -0,0 +1,14 @@
 2+#ifndef UTIL_H__
 3+#define UTIL_H__
 4+
 5+void init_xcb(xcb_connection_t **);
 6+void kill_xcb(xcb_connection_t **);
 7+
 8+void get_screen(xcb_connection_t *, xcb_screen_t **);
 9+int get_windows(xcb_connection_t *, xcb_window_t, xcb_window_t **);
10+
11+int exists(xcb_connection_t *, xcb_window_t);
12+int mapped(xcb_connection_t *, xcb_window_t);
13+int ignore(xcb_connection_t *, xcb_window_t);
14+
15+#endif
+274, -0
  1@@ -0,0 +1,274 @@
  2+#include <stdio.h>
  3+#include <stdlib.h>
  4+#include <err.h>
  5+#include <getopt.h>
  6+#include <xcb/xcb.h>
  7+
  8+#include "util.h"
  9+#include "arg.h"
 10+
 11+void usage(char*);
 12+void list_events(void);
 13+void register_events(xcb_window_t, uint32_t);
 14+void print_event(xcb_generic_event_t*);
 15+
 16+static xcb_connection_t *conn;
 17+static xcb_screen_t *scr;
 18+static uint32_t mask = XCB_EVENT_MASK_NO_EVENT
 19+                     | XCB_EVENT_MASK_STRUCTURE_NOTIFY
 20+                     | XCB_EVENT_MASK_FOCUS_CHANGE
 21+                     | XCB_EVENT_MASK_ENTER_WINDOW
 22+                     /* | XCB_EVENT_MASK_LEAVE_WINDOW */
 23+                     /* | XCB_EVENT_MASK_KEY_PRESS */
 24+                     /* | XCB_EVENT_MASK_KEY_RELEASE */
 25+                     | XCB_EVENT_MASK_BUTTON_PRESS
 26+                     /* | XCB_EVENT_MASK_BUTTON_RELEASE */
 27+                     /* | XCB_EVENT_MASK_POINTER_MOTION */
 28+                     /* | XCB_EVENT_MASK_POINTER_MOTION_HINT */
 29+                     /* | XCB_EVENT_MASK_BUTTON_1_MOTION */
 30+                     /* | XCB_EVENT_MASK_BUTTON_2_MOTION */
 31+                     /* | XCB_EVENT_MASK_BUTTON_3_MOTION */
 32+                     /* | XCB_EVENT_MASK_BUTTON_4_MOTION */
 33+                     /* | XCB_EVENT_MASK_BUTTON_5_MOTION */
 34+                     /* | XCB_EVENT_MASK_BUTTON_MOTION */
 35+                     /* | XCB_EVENT_MASK_KEYMAP_STATE */
 36+                     /* | XCB_EVENT_MASK_EXPOSURE */
 37+                     /* | XCB_EVENT_MASK_VISIBILITY_CHANGE */
 38+                     /* | XCB_EVENT_MASK_RESIZE_REDIRECT */
 39+                     /* | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY */
 40+                     /* | XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT */
 41+                     /* | XCB_EVENT_MASK_PROPERTY_CHANGE */
 42+                     /* | XCB_EVENT_MASK_COLOR_MAP_CHANGE */
 43+                     /* | XCB_EVENT_MASK_OWNER_GRAB_BUTTON */
 44+                     ;
 45+static uint32_t rootmask = XCB_EVENT_MASK_NO_EVENT
 46+                         | XCB_EVENT_MASK_STRUCTURE_NOTIFY
 47+                         | XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY
 48+                         | XCB_EVENT_MASK_BUTTON_PRESS
 49+                         | XCB_EVENT_MASK_BUTTON_RELEASE
 50+                         ;
 51+
 52+static const char *evname[] = {
 53+        [0]                     = "EVENT_ERROR",
 54+        [XCB_CREATE_NOTIFY]     = "CREATE",
 55+        [XCB_DESTROY_NOTIFY]    = "DESTROY",
 56+        [XCB_BUTTON_PRESS]      = "BUTTON_PRESS",
 57+        [XCB_BUTTON_RELEASE]    = "BUTTON_RELEASE",
 58+        [XCB_MOTION_NOTIFY]     = "MOTION",
 59+        [XCB_ENTER_NOTIFY]      = "ENTER",
 60+        [XCB_LEAVE_NOTIFY]      = "LEAVE",
 61+        [XCB_CONFIGURE_NOTIFY]  = "CONFIGURE",
 62+        [XCB_KEY_PRESS]         = "KEY_PRESS",
 63+        [XCB_FOCUS_IN]          = "FOCUS_IN",
 64+        [XCB_FOCUS_OUT]         = "FOCUS_OUT",
 65+        [XCB_KEYMAP_NOTIFY]     = "KEYMAP",
 66+        [XCB_EXPOSE]            = "EXPOSE",
 67+        [XCB_GRAPHICS_EXPOSURE] = "GRAPHICS_EXPOSURE",
 68+        [XCB_NO_EXPOSURE]       = "NO_EXPOSURE",
 69+        [XCB_VISIBILITY_NOTIFY] = "VISIBILITY",
 70+        [XCB_UNMAP_NOTIFY]      = "UNMAP",
 71+        [XCB_MAP_NOTIFY]        = "MAP",
 72+        [XCB_MAP_REQUEST]       = "MAP_REQUEST",
 73+        [XCB_REPARENT_NOTIFY]   = "REPARENT",
 74+        [XCB_CONFIGURE_REQUEST] = "CONFIGURE_REQUEST",
 75+        [XCB_GRAVITY_NOTIFY]    = "GRAVITY",
 76+        [XCB_RESIZE_REQUEST]    = "RESIZE_REQUEST",
 77+        [XCB_CIRCULATE_NOTIFY]  = "CIRCULATE",
 78+        [XCB_PROPERTY_NOTIFY]   = "PROPERTY",
 79+        [XCB_SELECTION_CLEAR]   = "SELECTION_CLEAR",
 80+        [XCB_SELECTION_REQUEST] = "SELECTION_REQUEST",
 81+        [XCB_SELECTION_NOTIFY]  = "SELECTION",
 82+        [XCB_COLORMAP_NOTIFY]   = "COLORMAP",
 83+        [XCB_CLIENT_MESSAGE]    = "CLIENT_MESSAGE",
 84+        [XCB_MAPPING_NOTIFY]    = "MAPPING"
 85+};
 86+
 87+void
 88+usage(char *name)
 89+{
 90+	fprintf(stderr, "usage: %s [-l] [-rm <mask>]\n", name);
 91+	exit(1);
 92+}
 93+
 94+void
 95+list_events(void)
 96+{
 97+	printf(
 98+		"XCB_EVENT_MASK_NO_EVENT .............. 0\n"
 99+		"XCB_EVENT_MASK_KEY_PRESS ............. 1\n"
100+		"XCB_EVENT_MASK_KEY_RELEASE ........... 2\n"
101+		"XCB_EVENT_MASK_BUTTON_PRESS .......... 4\n"
102+		"XCB_EVENT_MASK_BUTTON_RELEASE ........ 8\n"
103+		"XCB_EVENT_MASK_ENTER_WINDOW .......... 16\n"
104+		"XCB_EVENT_MASK_LEAVE_WINDOW .......... 32\n"
105+		"XCB_EVENT_MASK_POINTER_MOTION ........ 64\n"
106+		"XCB_EVENT_MASK_POINTER_MOTION_HINT ... 128\n"
107+		"XCB_EVENT_MASK_BUTTON_1_MOTION ....... 256\n"
108+		"XCB_EVENT_MASK_BUTTON_2_MOTION ....... 512\n"
109+		"XCB_EVENT_MASK_BUTTON_3_MOTION ....... 1024\n"
110+		"XCB_EVENT_MASK_BUTTON_4_MOTION ....... 2048\n"
111+		"XCB_EVENT_MASK_BUTTON_5_MOTION ....... 4096\n"
112+		"XCB_EVENT_MASK_BUTTON_MOTION ......... 8192\n"
113+		"XCB_EVENT_MASK_KEYMAP_STATE .......... 16384\n"
114+		"XCB_EVENT_MASK_EXPOSURE .............. 32768\n"
115+		"XCB_EVENT_MASK_VISIBILITY_CHANGE ..... 65536\n"
116+		"XCB_EVENT_MASK_STRUCTURE_NOTIFY ...... 131072\n"
117+		"XCB_EVENT_MASK_RESIZE_REDIRECT ....... 262144\n"
118+		"XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY ... 524288\n"
119+		"XCB_EVENT_MASK_SUBSTRUCTURE_REDIRECT . 1048576\n"
120+		"XCB_EVENT_MASK_FOCUS_CHANGE .......... 2097152\n"
121+		"XCB_EVENT_MASK_PROPERTY_CHANGE ....... 4194304\n"
122+		"XCB_EVENT_MASK_COLOR_MAP_CHANGE ...... 8388608\n"
123+		"XCB_EVENT_MASK_OWNER_GRAB_BUTTON ..... 16777216\n"
124+		);
125+}
126+
127+void
128+register_events(xcb_window_t w, uint32_t m)
129+{
130+	uint32_t val[] = { m };
131+
132+	xcb_change_window_attributes(conn, w, XCB_CW_EVENT_MASK, val);
133+	xcb_flush(conn);
134+}
135+
136+void
137+print_event(xcb_generic_event_t *e)
138+{
139+	xcb_enter_notify_event_t *en;
140+	xcb_focus_in_event_t *ef;
141+
142+	switch (e->response_type & ~0x80) {
143+		case XCB_ENTER_NOTIFY:
144+		case XCB_LEAVE_NOTIFY:
145+			en = (xcb_enter_notify_event_t *)e;
146+			if (en->mode != XCB_NOTIFY_MODE_NORMAL)
147+				return;
148+			printf("%s\t0x%08x\n", evname[e->response_type], en->event);
149+			break;
150+
151+		case XCB_FOCUS_IN:
152+		case XCB_FOCUS_OUT:
153+			ef = (xcb_focus_in_event_t *)e;
154+			if (ef->mode != XCB_NOTIFY_MODE_NORMAL)
155+				return;
156+			printf("%s\t0x%08x\n", evname[e->response_type], ef->event);
157+			break;
158+
159+		case XCB_CREATE_NOTIFY:
160+		case XCB_DESTROY_NOTIFY:
161+			printf("%s\t0x%08x\n", evname[e->response_type],
162+				((xcb_create_notify_event_t*)e)->window);
163+			break;
164+
165+		case XCB_UNMAP_NOTIFY:
166+		case XCB_MAP_NOTIFY:
167+			printf("%s\t0x%08x\n", evname[e->response_type],
168+				((xcb_map_notify_event_t*)e)->window);
169+			break;
170+
171+		case XCB_BUTTON_PRESS:
172+		case XCB_BUTTON_RELEASE:
173+			printf("%s\t0x%08x %d\n", evname[e->response_type],
174+				((xcb_button_press_event_t*)e)->event,
175+				((xcb_button_press_event_t*)e)->detail);
176+			break;
177+
178+		/*
179+		 * MOTION_NOTIFY. Be careful with this one...
180+		 *         It triggers ALOT! 
181+		 *
182+		 *          |\.---./|_
183+	 	 *         (o)   (°) ''--._
184+	 	 *         / .A--.         '\
185+	 	 *         |'     `.         \
186+	 	 *         /                 \
187+		 *        /_;`|__\------(__/-\
188+		 */
189+		case XCB_MOTION_NOTIFY:
190+			printf("%s\t0x%08x\n", evname[e->response_type],
191+				((xcb_motion_notify_event_t*)e)->event);
192+			break;
193+		/* please... handle me ... ;_;
194+		case XCB_KEY_PRESS:
195+		case XCB_KEY_RELEASE:
196+		case XCB_KEYMAP_NOTIFY:
197+		case XCB_EXPOSE:
198+		case XCB_GRAPHICS_EXPOSURE:
199+		case XCB_NO_EXPOSURE:
200+		case XCB_VISIBILITY_NOTIFY:
201+		case XCB_MAP_REQUEST:
202+		case XCB_REPARENT_NOTIFY:
203+		case XCB_CONFIGURE_NOTIFY:
204+		case XCB_CONFIGURE_REQUEST:
205+		case XCB_GRAVITY_NOTIFY:
206+		case XCB_RESIZE_REQUEST:
207+		case XCB_CIRCULATE_NOTIFY:
208+		case XCB_CIRCULATE_REQUEST:
209+		case XCB_PROPERTY_NOTIFY:
210+		case XCB_SELECTION_CLEAR:
211+		case XCB_SELECTION_REQUEST:
212+		case XCB_SELECTION_NOTIFY:
213+		case XCB_COLORMAP_NOTIFY:
214+		case XCB_CLIENT_MESSAGE:
215+		case XCB_MAPPING_NOTIFY:
216+		*/
217+	}
218+}
219+
220+int
221+main (int argc, char **argv)
222+{
223+	int i, wn;
224+	char *argv0;
225+	xcb_window_t *wc;
226+	xcb_generic_event_t *e;
227+	xcb_create_notify_event_t *ec;
228+
229+	ARGBEGIN {
230+		case 'l':
231+			list_events();
232+			exit(0);
233+		case 'r':
234+			  rootmask = strtoul(EARGF(usage(argv0)), NULL, 10);
235+			  break;
236+		case 'm':
237+			  mask = strtoul(EARGF(usage(argv0)), NULL, 10);
238+			  break;
239+		default: usage(argv0);
240+	} ARGEND;
241+
242+	init_xcb(&conn);
243+	get_screen(conn, &scr);
244+
245+	/*
246+	 * We need to get notifed of window creations, no matter what, because
247+	 * we need to register the event mask on all newly created windows
248+	 */
249+	register_events(scr->root, rootmask);
250+
251+	/* register the events on all mapped windows */
252+	wn = get_windows(conn, scr->root, &wc);
253+	for (i=0; i<wn; i++)
254+		register_events(wc[i], mask);
255+
256+	while(xcb_flush(conn)) {
257+		e = xcb_wait_for_event(conn);
258+		switch (e->response_type & ~0x80)
259+		{
260+			/* register events for each new windows */
261+			case XCB_CREATE_NOTIFY:
262+				ec = (xcb_create_notify_event_t*)e;
263+				register_events(ec->window, mask);
264+				/* FALLTHROUGH */
265+		}
266+		print_event(e);
267+		fflush(stdout);
268+
269+		free(e);
270+	}
271+
272+	kill_xcb(&conn);
273+
274+	return 0;
275+}
+64, -0
 1@@ -0,0 +1,64 @@
 2+/* See LICENSE file for copyright and license details. */
 3+
 4+#include <stdio.h>
 5+#include <stdlib.h>
 6+#include <xcb/xcb.h>
 7+#include <err.h>
 8+
 9+#include "util.h"
10+
11+static xcb_connection_t *conn;
12+
13+static void usage(char *);
14+static int get_title(xcb_window_t);
15+
16+static void
17+usage(char *name)
18+{
19+	fprintf(stderr, "usage: %s <wid>\n", name);
20+	exit(1);
21+}
22+
23+static int
24+get_title(xcb_window_t win)
25+{
26+	int len = 0;
27+	xcb_get_property_cookie_t cookie;
28+	xcb_get_property_reply_t *r;
29+
30+	cookie = xcb_get_property(conn, 0, win,
31+			XCB_ATOM_WM_NAME, XCB_ATOM_ANY, 0L, 32L);
32+	r = xcb_get_property_reply(conn, cookie, NULL);
33+
34+	if (r) {
35+		len = xcb_get_property_value_length(r);
36+		if (!len)
37+			return 1;
38+
39+		printf("%.*s\n", len, (char *) xcb_get_property_value(r));
40+
41+		free(r);
42+		return 0;
43+	}
44+
45+	warnx("could not get window title");
46+	return 1;
47+}
48+
49+int
50+main(int argc, char **argv)
51+{
52+	int i, r = 0;
53+
54+	if (argc < 2)
55+		usage(argv[0]);
56+
57+	init_xcb(&conn);
58+
59+	for (i=1; i < argc; i++)
60+		r += get_title(strtoul(argv[i], NULL, 16));
61+
62+	kill_xcb(&conn);
63+
64+	return r;
65+}
+150, -0
  1@@ -0,0 +1,150 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <xcb/xcb.h>
  4+#include <stdlib.h>
  5+#include <stdio.h>
  6+#include <err.h>
  7+
  8+#include "util.h"
  9+
 10+#define CLEANMASK(m)	((m & ~0x80))
 11+
 12+static xcb_connection_t	*conn;
 13+static xcb_screen_t	*scr;
 14+
 15+static void usage(char *);
 16+static xcb_window_t get_focuswin(void);
 17+static void cleanup(void);
 18+
 19+static void
 20+cleanup(void)
 21+{
 22+	kill_xcb(&conn);
 23+}
 24+
 25+static void
 26+usage(char *name)
 27+{
 28+	fprintf(stderr, "usage: %s <wid>\n", name);
 29+	exit(1);
 30+}
 31+
 32+static xcb_window_t
 33+get_focuswin(void) {
 34+	xcb_window_t w = 0;
 35+
 36+	xcb_get_input_focus_cookie_t  c;
 37+	xcb_get_input_focus_reply_t  *r;
 38+
 39+	c = xcb_get_input_focus(conn);
 40+	r = xcb_get_input_focus_reply(conn, c, NULL);
 41+
 42+	if (r == NULL)
 43+		errx(1, "failed to get focused window");
 44+
 45+	w = r->focus;
 46+	free(r);
 47+	return w;
 48+}
 49+
 50+static void
 51+mmove(xcb_window_t win) {
 52+	uint32_t values[3];
 53+	xcb_get_geometry_reply_t *geom;
 54+	xcb_query_pointer_reply_t *ptr;
 55+	xcb_generic_event_t *ev = NULL;
 56+	int orig_x, orig_y;
 57+
 58+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 59+	xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
 60+			geom->width/2, geom->height/2);
 61+
 62+	if (!geom)
 63+		errx(1, "could not get window size");
 64+
 65+	orig_x = geom->x;
 66+	orig_y = geom->y;
 67+
 68+	if (!scr->root)
 69+		return;
 70+
 71+	xcb_grab_pointer(conn, 0, scr->root,
 72+			XCB_EVENT_MASK_BUTTON_RELEASE
 73+			| XCB_EVENT_MASK_BUTTON_PRESS,
 74+			XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
 75+			scr->root, XCB_NONE, XCB_CURRENT_TIME);
 76+
 77+	xcb_flush(conn);
 78+
 79+
 80+	for (;;) {
 81+		ev = xcb_poll_for_event(conn);
 82+
 83+		if (geom->x != orig_x || geom->y != orig_y)
 84+			if (ev != NULL) {
 85+				if (ev->response_type == XCB_MOTION_NOTIFY)
 86+					break;
 87+				exit(0);
 88+			}
 89+
 90+		geom = xcb_get_geometry_reply(conn,
 91+				xcb_get_geometry(conn, win), NULL);
 92+		if (!geom)
 93+			errx(1, "could not get window size");
 94+
 95+
 96+		ptr = xcb_query_pointer_reply(conn,
 97+				xcb_query_pointer(conn, scr->root), 0);
 98+
 99+		if (!ptr)
100+			errx(1, "could not get pointer location");
101+
102+		values[0] = ptr->root_x + geom->width/2;
103+		values[1] = ptr->root_y + geom->height/2;
104+
105+		values[0] = (ptr->root_x + geom->width / 2
106+			> scr->width_in_pixels
107+			- (geom->border_width*2))
108+			? scr->width_in_pixels - geom->width
109+			- (geom->border_width*2)
110+			: ptr->root_x - geom->width / 2;
111+		values[1] = (ptr->root_y + geom->height / 2
112+			> scr->height_in_pixels
113+			- (geom->border_width*2))
114+			? (scr->height_in_pixels - geom->height
115+			- (geom->border_width*2))
116+			: ptr->root_y - geom->height / 2;
117+
118+		if (ptr->root_x < geom->width/2)
119+			values[0] = 0;
120+		if (ptr->root_y < geom->height/2)
121+			values[1] = 0;
122+
123+		xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_X
124+				| XCB_CONFIG_WINDOW_Y, values);
125+		xcb_flush(conn);
126+	}
127+
128+	xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
129+}
130+
131+int
132+main(int argc, char **argv)
133+{
134+	xcb_window_t win;
135+
136+	if (argc > 2)
137+		usage(argv[0]);
138+	
139+	init_xcb(&conn);
140+	get_screen(conn, &scr);
141+	atexit(cleanup);
142+
143+	if (argc == 2)
144+		win = strtoul(argv[1], NULL, 16);
145+	else
146+		win = get_focuswin();
147+
148+	mmove(win);
149+
150+	return 0;
151+}
+135, -0
  1@@ -0,0 +1,135 @@
  2+/* See LICENSE file for copyright and license details. */
  3+#include <xcb/xcb.h>
  4+#include <stdlib.h>
  5+#include <stdio.h>
  6+#include <err.h>
  7+
  8+#include "util.h"
  9+
 10+#define CLEANMASK(m)	((m & ~0x80))
 11+#define MAX(a, b) (a > b ? a : b)
 12+
 13+static xcb_connection_t	*conn;
 14+static xcb_screen_t	*scr;
 15+
 16+static void usage(char *);
 17+static xcb_window_t get_focuswin(void);
 18+static void cleanup(void);
 19+
 20+static void
 21+cleanup(void)
 22+{
 23+	kill_xcb(&conn);
 24+}
 25+
 26+static void
 27+usage(char *name)
 28+{
 29+	fprintf(stderr, "usage: %s <wid>\n", name);
 30+	exit(1);
 31+}
 32+
 33+static xcb_window_t
 34+get_focuswin(void) {
 35+	xcb_window_t w = 0;
 36+
 37+	xcb_get_input_focus_cookie_t  c;
 38+	xcb_get_input_focus_reply_t  *r;
 39+
 40+	c = xcb_get_input_focus(conn);
 41+	r = xcb_get_input_focus_reply(conn, c, NULL);
 42+
 43+	if (r == NULL)
 44+		errx(1, "failed to get focused window");
 45+
 46+	w = r->focus;
 47+	free(r);
 48+	return w;
 49+}
 50+
 51+static void
 52+mresize(xcb_window_t win) {
 53+	uint32_t values[3];
 54+	xcb_get_geometry_reply_t *geom;
 55+	xcb_query_pointer_reply_t *ptr;
 56+	xcb_generic_event_t *ev = NULL;
 57+	int orig_width, orig_height;
 58+
 59+	geom = xcb_get_geometry_reply(conn, xcb_get_geometry(conn, win), NULL);
 60+	xcb_warp_pointer(conn, XCB_NONE, win, 0, 0, 0, 0,
 61+			geom->width, geom->height);
 62+
 63+	if (!geom)
 64+		errx(1, "could not get window size");
 65+
 66+	orig_width = geom->width;
 67+	orig_height = geom->height;
 68+
 69+	if (!scr->root)
 70+		return;
 71+
 72+	xcb_grab_pointer(conn, 0, scr->root,
 73+			XCB_EVENT_MASK_BUTTON_RELEASE
 74+			| XCB_EVENT_MASK_BUTTON_PRESS,
 75+			XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC,
 76+			scr->root, XCB_NONE, XCB_CURRENT_TIME);
 77+
 78+	xcb_flush(conn);
 79+
 80+
 81+	for (;;) {
 82+		ev = xcb_poll_for_event(conn);
 83+
 84+		if (geom->width != orig_width || geom->height != orig_height)
 85+			if (ev != NULL) {
 86+				if (ev->response_type == XCB_MOTION_NOTIFY)
 87+					break;
 88+				exit(0);
 89+			}
 90+
 91+		geom = xcb_get_geometry_reply(conn,
 92+				xcb_get_geometry(conn, win), NULL);
 93+		if (!geom)
 94+			errx(1, "could not get window size");
 95+
 96+
 97+		ptr = xcb_query_pointer_reply(conn,
 98+				xcb_query_pointer(conn, scr->root), 0);
 99+
100+		if (!ptr)
101+			errx(1, "could not get pointer location");
102+
103+		values[0] = MAX(1, ptr->root_x - geom->x - 2 * geom->border_width);
104+		values[1] = MAX(1, ptr->root_y - geom->y - 2 * geom->border_width);
105+
106+
107+		if (values[0] >= 0 && values[1] >= 0)
108+			xcb_configure_window(conn, win, XCB_CONFIG_WINDOW_WIDTH
109+					| XCB_CONFIG_WINDOW_HEIGHT, values);
110+		xcb_flush(conn);
111+	}
112+
113+	xcb_ungrab_pointer(conn, XCB_CURRENT_TIME);
114+}
115+
116+int
117+main(int argc, char **argv)
118+{
119+	xcb_window_t win;
120+
121+	if (argc > 2)
122+		usage(argv[0]);
123+
124+	init_xcb(&conn);
125+	get_screen(conn, &scr);
126+	atexit(cleanup);
127+
128+	if (argc == 2)
129+		win = strtoul(argv[1], NULL, 16);
130+	else
131+		win = get_focuswin();
132+
133+	mresize(win);
134+
135+	return 0;
136+}
+98, -0
 1@@ -0,0 +1,98 @@
 2+super + Escape
 3+    pkill -USR1 -x sxhkd
 4+
 5+super + shift + q
 6+    pkill rainbow.sh; pkill focus_watcher.sh; pkill x
 7+
 8+alt + shift + h
 9+    qutebrowser
10+
11+super + backslash
12+    slock
13+
14+super + a
15+    acme
16+
17+super + {_, shift} + e
18+    half.sh {right, left} $(pfw)
19+
20+super + shift + s
21+    xnap | convert ppm:- "$HOME/media/images/scrots/screenshot_$(date +%Y-%m-%d_%H-%M-%S).png"
22+
23+super + s
24+    xnap | convert ppm:- png:- | xclip -selection clipboard -t image/png -i
25+
26+super + p
27+    dmenu_run
28+
29+super + x
30+	toggle_bar
31+
32+super + shift + {plus, minus}
33+    brightness.sh {up, down}
34+
35+super + r
36+    toggle_rgb -I
37+
38+super + shift + r
39+    toggle_rgb -O
40+
41+super + ctrl + r
42+    toggle_rgb -1
43+
44+super + {_, shift} + Return
45+    {st -e mksh, spawnterm}
46+
47+super + {_, shift} +t
48+	{tile 200, tile.sh}
49+
50+super + shift + {h,j,k,l}
51+    move.sh {left,down,up,right}
52+
53+super + Tab
54+	focus.sh next
55+
56+super + f
57+	fullscreen.sh $(pfw)
58+
59+super + ctrl + {h,j,k,l}
60+	wrs {-20 0, 0 20, 0 -20, 20 0} $(pfw)
61+
62+super + {h,j,k,l}
63+	closest.sh {east,north,south,west} $(pfw)
64+
65+super + {1,2,3,4,5}
66+    workspace.sh -g {0,1,2,3,4}
67+
68+super + shift + {1,2,3,4,5}
69+    workspace.sh -m {0,1,2,3,4} && focus.sh $(lsw | head -1)
70+
71+super + q
72+	xdotool getwindowfocus windowclose && focus.sh $(lsw)
73+
74+super + c
75+	center.sh xy $(pfw)
76+
77+super + shift + c
78+	center.sh y $(pfw)
79+
80+super + ctrl + c
81+    center.sh x $(pfw)
82+
83+super + {u,i,shift+u,shift+i}
84+    mtc {lu,ru,ld,rd}
85+
86+super + w
87+    wtp 651 265 1258 910 $(pfw)
88+
89+super + shift + w
90+    wtp 878 466 804 508 $(pfw)
91+
92+super + ctrl + w
93+    wtp 334 116 1892 1207 $(pfw)
94+
95+@super + shift + {button1, button3}
96+    {spawnterm, resize.sh}
97+
98+super + button2	
99+	launchmenu
+29, -0
 1@@ -0,0 +1,29 @@
 2+#!/bin/bash
 3+
 4+. $HOME/.theme
 5+
 6+hsetroot -solid '#ededed'
 7+
 8+setxkbmap -layout us,ru -variant , -option grp:shift_caps_toggle
 9+
10+picom &
11+sxhkd &
12+mwmd &
13+
14+plumber &
15+pkill fontsrv
16+mkdir -p /tmp/fonts
17+fontsrv -m /tmp/fonts &
18+
19+$HOME/.wmutils/scripts/workspace.sh -i
20+$HOME/.wmutils/scripts/watcher.sh &
21+
22+wmname wmutils
23+
24+xsetroot -cursor_name left_ptr &
25+
26+xrdb -merge $HOME/.Xresources
27+
28+export SHELL=/bin/mksh
29+
30+exec sleep infinity