#!/bin/sh

# Usage:
#    switchresolution width height command args

# Depends:
#    bc, xwit

# I found mplayer too CPU hungry on my machine when it played DVD under X
# at 1280x1024. I switch to 640x512 temporarily for DVD watching with this.
# (It can only switch to modes you already have in xorg.conf, of course.)

# We switch to screen mode <width>x<height>, then execute <command args>, and
# then switch back. Resolution switching is done with xrandr, so some windows
# will get moved to stay inside the screen, and will not be moved back
# automatically. We call xwininfo before switching resolution, and save the
# positions of all the windows. After switching back we call xwininfo again
# and compare.
#
# Those windows that have been moved are moved back with the tool xwit from
# http://www.x.org/contrib/utilities/. But there is a problem: xwininfo gives
# the position of the window, but xwit handles the window as it is drawn by
# the window manager, with frames and titlebar, and that is a little larger
# than the window itself. So after calling xwit with the old position the
# window is still shifted a little. We call xwininfo again to see, how much
# we got shifted. From that we calculate the position we must give xwit to
# move us back where we were before the whole moving thing started.

test -z "`which xwit`" &&
    echo "$0 needs 'xwit' from http://www.x.org/contrib/utilities/" && exit 0
test -z "`which bc`" &&
    echo "$0 needs 'bc' which everyone has except you, why?" && exit 0

test -z "$3" && echo "Usage: $0 width height command args" && exit 1

FILE=$HOME/.switchresolution.tmp
xwininfo -root -tree -int \
    | grep '^     [0-9]' \
    | sed -e '1d' -e 's/(.*)//' -e 's/".*"//' -e 's/://' \
    | awk '{print $1" "$2}' \
    | tr 'x+' '  ' \
    > ${FILE}1
# saved: id w h x y

# We ask xrandr what screen mode we have now and what we can switch to:
OLD=`xrandr -q | grep '^\*' | cut -c 2`
NEW=`xrandr -q | grep "$1 x $2" | cut -c 2`
test -z "$NEW" && echo "$0: Resolution ${1}x${2} not available" && exit 2

# We check if the requested command is even there:
test -z "`which $3 2>/dev/null`" && echo "$0: No such program '$3'" && exit 3
shift ; shift
CMD=$@
# echo "$OLD $NEW '$CMD'"

# All went well until here, so we actually switch screen mode:
xrandr -s $NEW
test "$?" != "0" && echo "$0: error switching to ${1}x${2}" && exit 4
eval $CMD
xrandr -s $OLD
test "$?" != "0" && echo "$0: error switching resolution back" && exit 5

# We should be back by now, so let's collect window positions again:
xwininfo -root -tree -int \
    | grep '^     [0-9]' \
    | sed -e '1d' -e 's/(.*)//' -e 's/".*"//' -e 's/://' \
    | awk '{print $1" "$2}' \
    | tr 'x+' '  ' \
    > ${FILE}2

# and now let's look if there are any moved windows, and move them back:
cat ${FILE}1 \
| while read ID W H XOLD YOLD
do
    XNEW=`grep $ID ${FILE}2 | awk '{print $4}'`
    YNEW=`grep $ID ${FILE}2 | awk '{print $5}'`
    if [ "$XNEW" != "$XOLD" -o "$YNEW" != "$YOLD" ]
    then
	xwit -id $ID -move $XOLD $YOLD
	# now we are shifted one frame width to the right and one frame height
	# plus the height of the title bar down. Where are we now?
	XNEW=`xwininfo -id $ID | grep "Absolute upper-left X:" | awk '{print $4}'`
	YNEW=`xwininfo -id $ID | grep "Absolute upper-left Y:" | awk '{print $4}'`
	# now we know, what position we must give xwit:
	XWIT=`echo $XOLD'*2-'$XNEW | bc`
	YWIT=`echo $YOLD'*2-'$YNEW | bc`
	#xwit -id $ID -move $((XOLD+$XOLD-$XNEW)) $((YOLD+$YOLD-$YNEW))
	xwit -id $ID -move $XWIT $YWIT
	# debug:
	#echo "$ID $XOLD $YOLD - $XNEW $YNEW - $((XOLD+$XOLD-$XNEW)) $((YOLD+$YOLD-$YNEW))" >>${FILE}4

	# Some Programs still get moved wrong, let's see if you are one of them:
	XNEW=`xwininfo -id $ID | grep "Absolute upper-left X:" | awk '{print $4}'`
	YNEW=`xwininfo -id $ID | grep "Absolute upper-left Y:" | awk '{print $4}'`
	if [ "$XNEW" != "$XOLD" -o "$YNEW" != "$YOLD" ]
	then
	    # yes, you are, so let's just live with the flaw, can't help it:
	    xwit -id $ID -move $XOLD $YOLD
	fi
    fi
done

# for debugging:
#xwininfo -root -tree -int \
#    | grep '^     [0-9]' \
#    | sed -e '1d' -e 's/(.*)//' -e 's/".*"//' -e 's/://' \
#    | awk '{print $1" "$2}' \
#    | tr 'x+' '  ' \
#    > ${FILE}3

# clean up:
rm -f ${FILE}1
rm -f ${FILE}2
#rm -f ${FILE}3
#rm -f ${FILE}4

