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
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
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