Saturday, February 02, 2008

Rotate the Cube in Compiz with wmctrl


The Cube plugin in Compiz or Compiz-Fusion could change the desktop into a virtual cube, and each face of the cube is one of the virtual desktop. Normally, the "rotation" of the cube -- rotate the cube to swith to other virtual desktop on the face -- could be done by keyboard or mouse. However, what if I wanted to rotate it with some shell script?

There are many ways to control the rotation of the cube, such as doing so with the DBus objects provided by Compiz. Besides that, is it possible to rotate the cube with wmctrl, a useful command line tool that could interact with EWMH/NetWM compatible Window Manager? Although wmctrl does not directly support cube rotation in Compiz, the answer is still "YES!"

To control the cube rotation with wmctrl, first of all, we should find out how Cube plugin actually does when managing the virtual desktops. Take my laptop for example. I use the Compiz-Fusion came with Ubuntu 7.10, and the display resolution was set to 1024x768 due to the low hardware specification of my laptop. Let's see what we get with "wmctrl -d" when we are on the first face of the cube:

$ wmctrl -d
0 * DG: 4096x768 VP: 0,0 WA: 0,25 1024x718 N/A

The "DG" in the output is Desktop Geometry, "VP" is the coordinates of the Viewport Position, and "WA" is the coordinates and the geometry of the WorkArea. The last "N/A" is the desktop name, and, since I did not give specific name to the virtual desktop, it is "Not Available." From the output of wmctrl, we can assume that, the Cube is actually a very wide virtual desktop that wrap around the cube. In order to verify our assumption, let's rotate to the right hand side, and run "wmctrl -d" in the second face of the cube:

$ wmctrl -d
0 * DG: 4096x768 VP: 1024,0 WA: 0,25 1024x718 N/A

We can find that, the only difference between these two tests is that, the X coordinate of the VP is changed! With this result, we can conlude that, the Cube is actually a very wide desktop, and the virtual desktop we see on each face is actually a viewport to that desktop. This also explains that why the application windows could be shown across the boundary of two faces. Known that each face of the cube is actually a viewport, now we can achieve the rotation with wmctrl by simply changing the current viewport position!

I wrote a simple BASH script for this:

#!/bin/bash
#
# compiz-rotate-wmctrl - Rotate the cube using wmctrl
#
# Author: Shang-Feng Yang
# Released under GPLv3

VER="1.0"


function rotate() {
  # The target face number (begins with 0)
  TVPN=$(( $1 % ${NF} ))

  # The X coordinate of the target viewport
  TVPX=$(( ${TVPN} * ${WW} ))

  # Change to the target viewport
  wmctrl -o ${TVPX},0
}

function usage() {
  echo -e "$(basename $0) v${VER}\n"
  echo -e "Usage:\n"
  echo -e "\t$(basename $0) {left|right|#}\n"
  echo -e "\tWhere:\n"
  echo -e "\t\tleft - rotate the cube to the left"
  echo -e "\t\tright - rotate the cube to the right"
  echo -e "\t\t# - rotate to #th face (begins with 0)\n\n"
  echo -e "Author: Shang-Feng Yang <storm dot sfyang at gmail dot com>"
  echo -e "Released under GPLv3"
}

# The action to be performed. $ACT could be 'left' or 'right' to rotate
# left or right, accordingly. $ACT could also be the number of the face
# to rotate into.
ACT=$(echo $1 |tr '[A-Z]' '[a-z]')

[ "x$ACT" == "x" ] && { usage; exit 1; } || {
  case $ACT in
    left|right|[0-9]|[0-9][0-9])
      ;;
    *)
      usage
      exit 1
      ;;
  esac
}


# The informations about the desktop
INFO=$(wmctrl -d)
# The width of the desktop
DW=$(echo "${INFO}"| awk '{sub(/x[0-9]+/, "", $4); print $4}')
# The width of the workarea
WW=$(echo "${INFO}"| awk '{sub(/x[0-9]+/, "", $9); print $9}')
# The number of faces on the cube
NF=$(($DW/$WW))
# The X coordinate of the viewport
CVPX=$(echo "${INFO}" |awk '{sub(/,[0-9]+/, "", $6); print $6}')
# Current number of the face in all faces (begins with 0)
CVPN=$(( ${CVPX} / ${WW} ))

[ "$ACT" == "right" ] && {
  ACT=$(( ${CVPN} + 1 ))
} || {
  [ "$ACT" == "left" ] && {
    ACT=$(( ${CVPN} - 1 ))
  }
}

rotate ${ACT}


To use the script,

  • if you didn't specify the parameters, or gave wrong parameters, a short usage information would be shown:

    $ compiz-rotate-wmctrl
    compiz-rotate-wmctrl v1.0

    Usage:

    compiz-rotate-wmctrl {left|right|#}

    Where:

    left - rotate the cube to the left
    right - rotate the cube to the right
    # - rotate to #th face (begins with 0)


    Author: Shang-Feng Yang <storm dot sfyang at gmail dot com>
    Released under GPLv3


  • or you specify "left" to achive a left hand rotation:

    $ compiz-rotate-wmctrl left


  • or "right" for a right hand rotation:

    $ compiz-rotate-wmctrl right


  • or given a face number, begins with 0, to rotate to the specified face:

    $ compiz-rotate-wmctrl 3




Where could this script be used? Well, it would be much easier to use such a kind of script to control the rotation when you use touchscreen to control the computer, or when you remotely control the desktop through network or bluetooth PAN.

Read more ...