#!/bin/ksh

# window-ctrl - 2015-10-23
#
# manipulate geometry (position/size) of current/active window

# unit step
u=256

# margins of display (offset for panel, &c.)
dmt=0
dmb=23
dml=0
dmr=0

# width and height of display (0 = calculate each time)
dw=2560
dh=1440
#~ dw=0
#~ dh=0

# centre threshold (window is kept centred if offset is < cth)
cth=30

# frame "decoration" offsets to compentsate for difference
# between given geometry and actual/reported geometry

# xfce
#~ wfx=2
#~ wfy=36
#~ wfw=0
#~ wfh=20

# i3
wfx=2
wfy=0
wfw=0
wfh=0

############################################################

usage()
{
	cat <<- sss
		usage: $(basename -- "$0") [options] command

		options
		  -t   test: print command to stdout instead of evaluating it
		  
		commands
	sss
	{ typeset -f setgeometry; typeset -f modwindow; } | 
	sed -r '/^[ \t]*[a-zA-Z0-9_-]+[ \t]*\)/!d; s/[ \t]*([a-zA-Z0-9_-]+)[ \t]*\).*$/  \1/'
	exit 1
}

getgeometry()
{
	# set vars: WINDOW, X, Y, WIDTH, HEIGHT, SCREEN
	eval "$(xdotool getactivewindow getwindowgeometry --shell)"
	# apply offsets
	X=$(( X - wfx ))
	Y=$(( Y - wfy ))
	# width & height offsets have to be subtracted later 
	W=$WIDTH
	H=$HEIGHT
}

# used in wider/narrower to keep window centred (if it is already)
getoffset()
{
	n=$(( X - ((dw - W) / 2) ))
	printf '%s' "${n#-}"
}

setgeometry()
{
	# xrandr causes xruns in jack
	(( dw )) || dw=$(xrandr --current | awk -F'[ x]' '/\*/ {print $4}')
	(( dh )) || dh=$(xrandr --current | awk -F'[ x]' '/\*/ {print $5}')
	# sed is not farster than mawk (maybe mini-sed...?)
	#~ (( dh )) || dh="$(xrandr --current | sed -n -r '/\*/ {s/^.* ([0-9]+)x[0-9]+.*$/\1/p; q}')"
	#~ (( dh )) || dh="$(xrandr --current | sed -n -r '/\*/ {s/^.* [0-9]+x([0-9]+).*$/\1/p; q}')"
	getgeometry

	case $1 in
	top* )
		Y=$dmt
		case $1 in
		top )
			X=$(( (dw - W) / 2 )) ;;
		top-left )
			X=0 ;;
		top-right )
			X=$(( dw - W )) ;;
		* ) usage ;;
		esac
		;;
	left )
		X=$(( u < X - dml ? X - u : dml )) ;;
	right )
		X=$(( X + u + W > dw - dmr ? dw - W - dmr : X + u )) ;;
	up )
		Y=$(( u < Y - dmt ? Y - u : dmt )) ;;
	down )
		Y=$(( Y + u + H > dh - dmb ? dh - dmb - H - wfh : Y + u )) ;;

	wider )
		# keep window centred (if it is already)
		if (( $(getoffset) < cth )); then
			W=$(( W + u > dw - dml - dmr ? dw - dml - dmr : W + u ))
			X=$(( (dw - W) / 2 ))
		else
			W=$(( W + u > dw - dml - dmr - X ? dw - dml - dmr - X : W + u ))
		fi
		;;
	narrower )
		# get offset before W changes
		offset=$(getoffset)
		W=$(( W - u < 0 ? 0 : W - u ))
		# update window size and refresh geometry (in case window disobeyed width)
		xdotool getactivewindow windowsize --sync "$W" "$H"
		getgeometry
		# keep window centred (if it is already)
		(( offset < cth )) && X=$(( (dw - W) / 2 ))
		;;
	taller )
		H=$(( H + u > dh - dmt - dmb - Y ? dh - dmt - dmb - Y - wfh : H + u )) ;;
	shorter )
		H=$(( H - u < 0 ? 0 : H - u )) ;;
	toggle-fullscreen )
		wmctrl -r :ACTIVE: -b toggle,fullscreen ;;
	toggle-max )
		wmctrl -r :ACTIVE: -b toggle,maximized_vert,maximized_horz ;;
	toggle-max-height )
		wmctrl -r :ACTIVE: -b toggle,maximized_vert ;;
	toggle-max-width )
		wmctrl -r :ACTIVE: -b toggle,maximized_horz ;;
	* ) usage ;;
	esac

	#xdotool getactivewindow windowmove "$X" "$Y" windowsize "$W" "$H"
	wmctrl -r :ACTIVE: -e "0,$X,$Y,$W,$H"
	
	# note: both commands should not affect position
	# `xdotool getactivewindow windowmove x y` moves the window
	# `wmctrl -r :ACTIVE: -e 0,-1,-1,-1,-1` works
}

modwindow()
{
	case $1 in
	raise )
		wmctrl -r :ACTIVE: -b toggle,above ;;
	lower )
		wmctrl -r :ACTIVE: -b toggle,below ;;
	close )
		wmctrl -c :ACTIVE: ;;
	focus-workspace )
		wmctrl -s "$2" ;;
	move-to-workspace )
		wmctrl -r :ACTIVE: -t "$2" ;;
	search )
		: ;;
	* ) usage ;;
	esac
}

############################################################

#~ while getopts :t opt; do
	#~ case $opt in
		#~ t ) test=1 ;;
		#~ * ) usage ;;
	#~ esac
#~ done
#~ shift $(( OPTIND - 1 ))

(( $# == 1 )) || [[ $# == 2 && $2 =~ ^[0-9]+$ ]] || usage

setgeometry "$1"
