mabox-tools/bin/snapwin
2022-02-24 17:40:54 +01:00

213 lines
9.7 KiB
Bash
Executable File

#!/bin/bash
#: snapwin - click on the appropriate area of the window to snap it in a given direction.
#: Works with active and inactive windows.
#: Same actions are available for kebindings: topleft, top, topright, left, center, right,
#: bottomleft, bottom and bottomright.
# Copyright (C) Daniel Napora <napcok@gmail.com> 2021
# https://maboxlinux.org
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
_config() {
CONFIG_DIR="$HOME/.config/deskgrid"
CONFIG_FILE="$CONFIG_DIR/deskgrid.cfg"
mkdir -p $CONFIG_DIR
if [ ! -f $CONFIG_FILE ]; then
cat <<EOF > ${CONFIG_FILE}
# Gap between windows in pixels (reasonable values: 0 8 16 24)
gap=16
# Grid columns (12 16 24)
columns=12
# Grid rows (6 12 16)
rows=12
#Notifications true or false
notifications=true
# Outer gap (disable if you use WM margins)
show_outer_gap=true
# Only for clicksnap action
activate_window=false
EOF
fi
source <(grep = $CONFIG_FILE)
GAP=${gap:-16}
## OUTER GAP
if [[ "$show_outer_gap" == "true" ]]; then OUT_GAP=$((GAP/2)) ; else OUT_GAP="0" ; fi
OFFSET=$(wmctrl -d |grep "*" | awk -F' ' '{print $8}')
REALSIZE=$(wmctrl -d |grep "*" | awk -F' ' '{print $9}')
AVAIL_X="${REALSIZE%x*}"
AVAIL_Y="${REALSIZE#*x}"
OFF_X="${OFFSET%,*}"
OFF_Y="${OFFSET#*,}"
}
_movewin() {
echo "AVAIL_X: $AVAIL_X | OFF_X: $OFF_X | OUT_GAP: $OUT_GAP | GAP: $GAP | \n BORDERCOMP_X: $BORDERCOMP_X BORDERCOMP_Y: $BORDERCOMP_Y"
WIDTH_FULL=$((AVAIL_X-OUT_GAP*2-BORDERCOMP_X))
WIDTH_HALF=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X))
WIDTH_SMALL=$((AVAIL_X/3-OUT_GAP-GAP/2-BORDERCOMP_X))
WIDTH_WIDE=$((WIDTH_SMALL*2+GAP+BORDERCOMP_X))
HEIGHT_FULL=$((AVAIL_Y-OUT_GAP*2-BORDERCOMP_Y))
HEIGHT_HALF=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2))
echo "HEIGHT_HALF $HEIGHT_HALF"
echo "Width FULL: $WIDTH_FULL"
echo "Width HALF: $WIDTH_HALF"
echo "Width SMALL: $WIDTH_SMALL"
echo "Width WIDE: $WIDTH_WIDE"
case $POS_CODE in
00|"topleft") # top-left
#echo "xdotool getwindowgeometry --shell $WINDOW"
eval xdotool getwindowgeometry --shell "$WINDOW"
W=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X)) H=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2)) XPOS=$((OFF_X+OUT_GAP)) YPOS=$((OFF_Y+OUT_GAP));
#echo -e "XPOS: $XPOS \nYPOS: $YPOS \nW: $W \nWINDOW $WINDOW"
#echo "W+BORDERCOMP_X: $((W+BORDERCOMP_X))"
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$((W+BORDERCOMP_X))" && "$HEIGHT" -eq "$((HEIGHT_HALF+BORDERCOMP_Y))" ]] && W=$WIDTH_SMALL
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -lt "$WIDTH_HALF+BORDERCOMP_X" && "$HEIGHT" -eq "$((HEIGHT_HALF+BORDERCOMP_Y))" ]] && W=$WIDTH_WIDE
;;
10|top) # top
W=$WIDTH_FULL H=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2)) XPOS=$((0+OFF_X+OUT_GAP)) YPOS=$((0+OFF_Y+OUT_GAP))
[[ "$X" -eq "$XPOS" && "$WIDTH" -eq "$WIDTH_FULL+$BORDERCOMP_X" ]] && W=$WIDTH_SMALL XPOS=$((OFF_X+AVAIL_X/2-WIDTH_SMALL/2-BORDERCOMP_X/2))
;;
20|topright) # top-right
W=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X)) H=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2)) XPOS=$((AVAIL_X/2+OFF_X+GAP/2)) YPOS=$((OFF_Y+OUT_GAP))
eval xdotool getwindowgeometry --shell "$WINDOW"
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$((W+BORDERCOMP_X))" && "$HEIGHT" -eq "$((HEIGHT_HALF+BORDERCOMP_Y))" ]] && W="$WIDTH_SMALL" XPOS=$((OFF_X+AVAIL_X-WIDTH_SMALL-OUT_GAP-BORDERCOMP_X))
# echo -e "XPOS: $XPOS \nYPOS: $YPOS \nW: $W \nWINDOW $WINDOW"
[[ "$X" -eq "$((AVAIL_X-WIDTH_SMALL+OFF_X-OUT_GAP-BORDERCOMP_X))" && "$Y" -eq "$YPOS" && "$WIDTH" -lt "$((WIDTH_HALF+BORDERCOMP_X))" && "$HEIGHT" -eq "$((HEIGHT_HALF+BORDERCOMP_Y))" ]] && W=$WIDTH_WIDE XPOS=$((AVAIL_X-WIDTH_WIDE+OFF_X-OUT_GAP-BORDERCOMP_X))
;;
01|left) # left
eval xdotool getwindowgeometry --shell "$WINDOW"
W=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X)) H=$((AVAIL_Y-BORDERCOMP_Y-OUT_GAP*2)) XPOS=$((0+OFF_X+OUT_GAP)) YPOS=$((0+OFF_Y+OUT_GAP))
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$((W+BORDERCOMP_X))" && "$HEIGHT" -eq "$((HEIGHT_FULL+BORDERCOMP_Y))" ]] && W=$WIDTH_SMALL
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -lt "$WIDTH_HALF+BORDERCOMP_X" && "$HEIGHT" -eq "$((HEIGHT_FULL+BORDERCOMP_Y))" ]] && W=$WIDTH_WIDE;;
11|center) # center
HEIGHT_SMALL=$((AVAIL_Y/3-OUT_GAP-GAP/2-BORDERCOMP_Y))
W=$WIDTH_FULL H=$HEIGHT_FULL XPOS=$((OFF_X+OUT_GAP)) YPOS=$((OFF_Y+OUT_GAP))
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$WIDTH_FULL+BORDERCOMP_X" ]] && W=$WIDTH_SMALL XPOS=$((OFF_X+AVAIL_X/2-WIDTH_SMALL/2-BORDERCOMP_X/2))
;;
21|right) # right
W=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X)) H=$((AVAIL_Y-BORDERCOMP_Y-OUT_GAP*2)) XPOS=$((AVAIL_X/2+OFF_X+GAP/2)) YPOS=$((0+OFF_Y+OUT_GAP))
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$((W+BORDERCOMP_X))" && "$HEIGHT" -eq "$((HEIGHT_FULL+BORDERCOMP_Y))" ]] && W="$WIDTH_SMALL" XPOS=$((OFF_X+AVAIL_X-WIDTH_SMALL-OUT_GAP-BORDERCOMP_X))
[[ "$X" -eq "$((AVAIL_X-WIDTH_SMALL+OFF_X-OUT_GAP-BORDERCOMP_X))" && "$Y" -eq "$YPOS" && "$WIDTH" -lt "$((WIDTH_HALF+BORDERCOMP_X))" && "$HEIGHT" -eq "$((HEIGHT_FULL+BORDERCOMP_Y))" ]] && W=$WIDTH_WIDE XPOS=$((AVAIL_X-WIDTH_WIDE+OFF_X-OUT_GAP-BORDERCOMP_X))
;;
02|bottomleft) # bottom-left
W=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X)) H=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2)) XPOS=$((0+OFF_X+OUT_GAP)) YPOS=$((AVAIL_Y/2+OFF_Y+GAP/2))
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$((W+BORDERCOMP_X))" ]] && W=$WIDTH_SMALL
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -lt "$WIDTH_HALF+BORDERCOMP_X" ]] && W=$WIDTH_WIDE
;;
12|bottom) # bottom
W=$WIDTH_FULL H=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2)) XPOS=$((0+OFF_X+OUT_GAP)) YPOS=$((AVAIL_Y/2+OFF_Y+GAP/2))
[[ "$X" -eq "$XPOS" && "$WIDTH" -eq "$WIDTH_FULL+$BORDERCOMP_X" ]] && W=$WIDTH_SMALL XPOS=$((OFF_X+AVAIL_X/2-WIDTH_SMALL/2-BORDERCOMP_X/2))
;;
22|bottomright) # bottom-right
W=$((AVAIL_X/2-OUT_GAP-GAP/2-BORDERCOMP_X)) H=$((AVAIL_Y/2-BORDERCOMP_Y-OUT_GAP-GAP/2)) XPOS=$((AVAIL_X/2+OFF_X+GAP/2)) YPOS=$((AVAIL_Y/2+OFF_Y+GAP/2))
[[ "$X" -eq "$XPOS" && "$Y" -eq "$YPOS" && "$WIDTH" -eq "$((W+BORDERCOMP_X))" ]] && W="$WIDTH_SMALL" XPOS=$((OFF_X+AVAIL_X-WIDTH_SMALL-OUT_GAP-BORDERCOMP_X))
[[ "$X" -eq "$((AVAIL_X-WIDTH_SMALL+OFF_X-OUT_GAP-BORDERCOMP_X))" && "$Y" -eq "$YPOS" && "$WIDTH" -lt "$((WIDTH_HALF+BORDERCOMP_X))" ]] && W=$WIDTH_WIDE XPOS=$((AVAIL_X-WIDTH_WIDE+OFF_X-OUT_GAP-BORDERCOMP_X));;
esac
xdotool windowsize $WINDOW $W $H
xdotool windowmove $WINDOW $XPOS $YPOS
#echo "Po akcji =============="
#eval xdotool getwindowgeometry --shell "$WINDOW"
if [ $activate_window == "true" ]; then xdotool windowactivate $WINDOW; fi
}
_getwin() { #get active window (only when invoked by keyboard)
_config
WIN=$(xdotool getactivewindow)
#echo "Win: $WIN"
HEX_ID=$(printf '0x%x\n' $WIN)
#echo $HEX_ID
#####echo "$HEX_ID"
wmctrl -i -r $HEX_ID -b remove,maximized_vert,maximized_horz
WINDOW=$(xwininfo -id $(xdotool getactivewindow) -int -tree | awk '/^ *Parent/ {print $4}')
#echo "WINDOW: $WINDOW"
#WINDOW=$(xwininfo -id $WIN -int -tree | awk '/^ *Parent/ {print $4}')
#WINDOW=$WIN
winFRAME=$(xprop -id $WIN _NET_FRAME_EXTENTS | awk ' {gsub(/,/,"");print $3,$4,$5,$6}')
read BORDER_L BORDER_R BORDER_T BORDER_B <<< "$winFRAME"
#echo "winFRAME: $winFRAME"
BORDERCOMP_X=$((BORDER_L+BORDER_R))
BORDERCOMP_Y=$((BORDER_T+BORDER_B))
#echo "BORDERCOMP_X $BORDERCOMP_X"
#echo "Przekazuję ID OKNA: $WINDOW"
_movewin
}
clicksnap() {
_config
#xdotool windowactivate $WINDOW
### Clicksnap mouse action start
eval $(xdotool getmouselocation --shell)
Mouse_x="$X"
Mouse_y="$Y"
HEX_ID=$(printf '0x%x\n' $WINDOW)
wmctrl -i -r $HEX_ID -b remove,maximized_vert,maximized_horz
CHILD_ID=$(xwininfo -id $HEX_ID -children|grep "\"" | awk '{print $1}')
if xwininfo -id $CHILD_ID -wm |grep Dock ; then exit 0 ;fi # Ignore Dock eg. tint2
eval $(xdotool getwindowgeometry --shell $WINDOW)
Win_x="$X"
Win_y="$Y"
Win_width="$WIDTH"
Win_height="$HEIGHT"
if [[ $Mouse_x -gt $Win_x && $Mouse_x -lt $((Win_x+WIDTH)) && $Mouse_y -gt $Win_y && $Mouse_y -lt $((Win_y+HEIGHT)) ]];then
pos_x="$(((Mouse_x-Win_x)/(Win_width/3)))"
pos_y="$(((Mouse_y-Win_y)/(Win_height/3)))"
POS_CODE="$pos_x$pos_y"
else
pos_x="$((Mouse_x*3/AVAIL_X))"
pos_y="$((Mouse_y*3/AVAIL_Y))"
POS_CODE="$pos_x$pos_y"
fi
CHILD=$(printf %i $CHILD_ID)
#echo "CHILD Potrzebny dla FRAME: $CHILD"
read BORDER_L BORDER_R BORDER_T BORDER_B <<< "$(xprop -id $CHILD _NET_FRAME_EXTENTS | awk ' {gsub(/,/,"");print $3,$4,$5,$6}')"
BORDERCOMP_X=$((BORDER_L+BORDER_R))
BORDERCOMP_Y=$((BORDER_T+BORDER_B))
#echo "BORDERCOMP_X $BORDERCOMP_X"
#echo "BORDERCOMP_Y $BORDERCOMP_Y"
#echo "Przekazuję ID OKNA: $WINDOW"
_movewin
}
moveto() {
POS_CODE="$1"
_getwin
}
usage() {
grep "^#:" $0 | while read DOC; do printf '%s\n' "${DOC###:}"; done
exit
}
case "$1" in
"") clicksnap ;;
topleft|top|topright|left|center|right|bottomleft|bottom|bottomright) moveto "$1" ;;
-h|--help) usage ;;
esac