星期六, 2月 02, 2008

使用 wmctrl 來旋轉 compiz 的桌面方塊


Compiz 或 Compiz-Fusion 的 Cube plugin 是個相當有趣的特效 plugin,透過 Cube 以及 Rotate plugin,桌面可以虛擬成一個立體方塊,方塊四周的4個面變成 4 個虛擬桌面,這個我在『我也來貼圖 - Linux 的 3D 桌面』中有提過。旋轉立體方塊可以透過設定好的滑鼠或者鍵盤快速鍵來達成,這在一般的使用狀態下已經足夠了,但假設想要寫 script 來控制時,那該怎麼做呢?

要使用 script 來控制 Cube 的旋轉,方法其實很多,例如透過 Compiz 提供的 DBus 物件來達成。除此之外,方便好用的 wmctrl 雖然沒有直接支援 Cube 的旋轉,但透過一些分析,其實還是可以用 wmctrl 間接控制 Cube 的旋轉。


為了能夠用 wmctrl 控制 Cube 的旋轉,首先我們必須先看看到底 Compiz 是怎麼處理 Cube 的。以我的系統為例,我使用 Ubuntu 7.10 中的 Compiz-Fusion,螢幕解析度設定為 1024×768,先看看在 Cube 的第一個面時,使用 "wmctrl -d" 會看到怎樣的訊息:

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

wmctrl -d 輸出的資訊裡,"DG" 是桌面大小 (Desktop Geometry),"VP" 是 Viewport 座標 (Viewport Position),WA 則是工作區域 (WorkArea) 的座標及大小,最後則是 Desktop 的名稱。從上面的資訊看起來,Compiz 實際的 Cube 實際上只有管理一個寬度很寬的 Desktop 而已,那我們看到的各個面到底是怎麼回事呢?為了搞清楚狀況,將 Cube 向右旋轉到第二面以後,再次以 wmctrl 來看看 Desktop 資訊:

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

發現了嗎?切換到不同面時,wmctrl -d 顯示的資訊裡,唯一改變的是 Viewport 的位置!換句話說,Compiz 的 Cube 實際上只有管理一個很寬的桌面,然後各個面其實只是不同的 Viewport 而已!這也解釋了為何應用程式視窗可以跨過兩個相鄰面的邊界了!既然知道 Compiz 實際上是這樣管理 Cube 的,那要用 wmctrl 來達成 Cube 的旋轉,其實就只是使用 wmctrl 來切換 Viewport 位置即可!

我寫了個簡單的 BASH script 來做這件事情:

#!/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}


使用方式如下:

  • 不給任何參數,或者參數給錯時時,會顯示簡單的使用說明:

    $ 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


  • 使用 left 將 Cube 向左旋轉一個面:

    $ compiz-rotate-wmctrl left


  • 使用 right 將 Cube 向右旋轉一個面:

    $ compiz-rotate-wmctrl right


  • 直接給定某個面的編號時,會直接旋轉至該面,編號由 0 開始:

    $ compiz-rotate-wmctrl 3




這樣的 script 可以用在什麼地方呢?通常是用在一些特殊場合,例如透過非正規方式控制電腦時,像是透過網路遙控,或者使用觸控螢幕時,使用 script 會比較方便。

繼續閱讀全文