Switch between xfwm4/metacity-compiz and keep windows in their working spaces
This is a script designed to switch between xfwm4 (xfce windows manager) and
compiz windows manager and restore the windows in the working spaces where they
were. I use to switch between these two windows managers in my laptop depending
whether I am using the battery or it is docked and lying on the table with an
external monitor plugged in. Unfortunately, if you type
F2 and execute
"compiz --replace" (or xfwm4 --replace), all windows are moved to the first
working space, which is very annoying. This script pretends to solve this. You
can easily modify it to use metacity instead of xfwm4.
#!/bin/bash
###Code partially taken from http://odyniec.net/
##Depends on: wmctrl, xdpyinfo, xprop, xwininfo, bc
##This script switches from xfwm4/metacity windwos manager to compiz and viceversa,
##and restores the windows in the working spaces where they were.
##By default it switches between xfwm4 (xfce4 windows manger) and compiz, but
##you can easily modify it to use metacity instead of xfwm4.
##TODO/improve: it would be worth to sort the windows by workin space.
## The script does not work un dual screen mode.
function compiz_mw2cwsp(){
###Moves back WINDOW_ID window to current workspace in compiz
# Calculate the new location of the window
NEW_WINDOW_X=`echo "($CURRENT_X + ($WINDOW_X)) % $WORKSPACE_WIDTH" | bc`
NEW_WINDOW_Y=`echo "($CURRENT_Y + ($WINDOW_Y)) % $WORKSPACE_HEIGHT" | bc`
# Move the window to the new location and raise it
wmctrl -i -r "$WINDOW_ID" -e 10,"$NEW_WINDOW_X","$NEW_WINDOW_Y",-1,-1
wmctrl -i -R "$WINDOW_ID"
}
##Number of desktops:
N=5
# We get the dimensions of a single workspace
XDPYINFO_OUT=`xdpyinfo | grep 'dimensions:'`
WORKSPACE_WIDTH=`echo "$XDPYINFO_OUT" | sed -r 's/.*:\s+([0-9]+)x.*/\1/'`
WORKSPACE_HEIGHT=`echo "$XDPYINFO_OUT" \
| sed -r 's/.*:\s+[0-9]+x([0-9]+).*/\1/'`
# Get the X and Y offset of the current workspace
XPROP_OUT=`xprop -root -notype _NET_DESKTOP_VIEWPORT`
CURRENT_X=`echo "$XPROP_OUT" | sed -r 's/.*= ([0-9]+),.*/\1/'`
CURRENT_Y=`echo "$XPROP_OUT" | sed -r 's/.*= [0-9]+,\s*([0-9]+).*/\1/'`
WINDOWS_FILE=$HOME/windows_list.tmp
WINDOWS_POS_FILE=$HOME/windows_pos_list.tmp
wmctrl -l -G > $WINDOWS_FILE
NWINDOWS=$(wc -l $WINDOWS_FILE | awk '{print $1}')
###We first get information about the current position of all windows
for i in `seq 1 1 $NWINDOWS`; do
WINDOW_ID=$(tail -n +$i $WINDOWS_FILE | head -n 1 | awk '{print $1}')
# Get the coordinates of the top left corner of WINDOW_ID window
XWININFO_OUT=`xwininfo -id "$WINDOW_ID"`
WINDOW_X=`echo "$XWININFO_OUT" | grep 'Absolute upper-left X' \
| sed -r 's/.*:\s+([0-9-]+).*/\1/'`
WINDOW_Y=`echo "$XWININFO_OUT" | grep 'Absolute upper-left Y' \
| sed -r 's/.*:\s+([0-9-]+).*/\1/'`
##We save them in a file
echo "$WINDOW_ID $WINDOW_X $WINDOW_Y" >> $WINDOWS_POS_FILE
done
##Windows Manager we are switching to:
WM=$(wmctrl -m | grep Name |awk '{print $2}')
if [ "$WM" == "compiz" ]; then
echo "Switching to xfwm4"
(xfwm4 --replace)&
sleep 3s
WM="xfwm4"
###When switching to xfwm4, there is a bug that sets the number of desktops to 1.
###We restore the number of desktops to N:
wmctrl -n $N
else
echo "Switching to compiz"
(compiz --replace)&
sleep 7s
WM="compiz"
fi
###We now restore windows position
for i in `seq 1 1 $NWINDOWS`; do
WINDOW_ID=$(tail -n +$i $WINDOWS_FILE | head -n 1 | awk '{print $1}')
DESKTOP_NUM=$(tail -n +$i $WINDOWS_FILE | head -n 1 | awk '{print $2}')
WINDOW_X=$(tail -n +$i $WINDOWS_POS_FILE | head -n 1 | awk '{print $2}')
WINDOW_Y=$(tail -n +$i $WINDOWS_POS_FILE | head -n 1 | awk '{print $3}')
if [ $DESKTOP_NUM -ne -1 ]; then ###To ignore sticky windows
if [ "$WM" == "compiz" ]; then ##We are switching to compiz
let DESKTOP_NUM=$DESKTOP_NUM+1
xaux=$(echo "$DESKTOP_NUM*($WORKSPACE_WIDTH-1)" | bc)
wmctrl -o $xaux,0
sleep 1.5s
compiz_mw2cwsp ##We move the window to the current viewport
else ##We are switching from compiz
DESKTOP_NUM=`echo "$WINDOW_X / $WORKSPACE_WIDTH" | bc`
wmctrl -s $DESKTOP_NUM
sleep 0.5s
wmctrl -i -R $WINDOW_ID
fi
fi
done
rm $WINDOWS_FILE
rm $WINDOWS_POS_FILE
exit 0