#!/bin/bash #---------------------------------------------------------------------------# # Script to switch screens using xrandr, working around a bug in the Intel # # driver for 945GME-type hardware which hangs the machine. # # # # NB, only the presence of compiz is worked around here. Having other # # OpenGL apps running while switching screens may still lead to a crash. # # # # Usage: rnr_switch [:x@] # # where is the device name as reported by xrandr (e.g. LVDS1, # # VGA1, etc). # # # # Uses zenity to report progress. # # # # This script is best used with a compiz keyboard shortcut to trigger it # # using the "Commands" plugin. E.g., I have: # # Ctrl-Shift-F1 : rnr_switch LVDS1 (laptop panel, auto) # # Ctrl-Shift-F2 : rnr_switch VGA1 (external monitor, auto) # # Ctrl-Shift-F3 : rnr_switch VGA1:1280x1024@75 (external monitor, manual) # # Ctrl-Shift-F4 : rnr_switch VGA1:1024x768@60 (external monitor, manual) # # # # To avoid problems: # # - Always wait for the "You can now close this window" message before # # attempting to run this script again. # # - Do not use this script to switch between different resolutions of the # # external monitor; instead, switch to the Panel first, then back to the # # external monitor. This script could be fixed to do this directly, but # # one thing at a time.. # # # # pablomme 12.2009 # # Public Domain. No Warranty. Etc. # #---------------------------------------------------------------------------# set +u get_mode() { # Get the modeline for mode $1 x $2 @ $3 local mode set -- $(cvt $1 $2 $3 | grep -vE "^#") shift 2 mode="" while (($#>0)) ; do case "$1" in -hsync) mode="$mode -HSync" ;; -vsync) mode="$mode -HSync" ;; +hsync) mode="$mode +VSync" ;; +vsync) mode="$mode +VSync" ;; *) mode="$mode $1" ;; esac shift done echo $mode } check_number_N() { # Check whether $1 is a positive integer local num="$1" size i=0 c size=${#num} ; ((size<1)) && return 1 while ((i&${COPROC[1]} } log() { # Log to stdout and to a text-info zenity window. # To stdout. echo "$*" # To zenity text-info window. logzenity "$*" } sleeplog() { # Sleep for $1 seconds and log it. log "- Waiting $1 seconds." sleep $1 } # Read command-line option. (($#==0)) && errstop\ "Usage: ${0##*/} [:x@] ." mode="$1" case "$mode" in *:*@*) m=$mode to=${m%%:*} ; m=${m#*:} x=${m%%x*} ; m=${m#*x} y=${m%%@*} ; m=${m#*@} r=$m check_number_N $x && check_number_N $y && check_number_R $r\ || errstop "Bad mode $mode." mode=${x}x${y}@$r ;; *) to=$mode ; mode=auto ;; esac # Read current configuration to determine 'from' from="" { output="" while read line ; do set -- $line [ "$2" = connected ] && { output=$1 ; continue ; } [ -z "$output" ] && continue [ "$6" = \*current ] || [ "$7" = \*current ]\ && { from=$output ; break ; } done } < <(xrandr -q --current --verbose) [ -z "$from" ] && errstop "xrandr: could not determine current output." [ "$from" = "$to" ] && errstop "Current output same as target, '$from'." log "Switching from '$from' to '$to' in mode '$mode'." # Disable compiz while switching screens. disabled_compiz=0 if (($(lspci | grep 945 | grep Intel | grep -c VGA)>0))\ && (($(ps -u $USER -o comm | grep -cw compiz)>0)) ; then disabled_compiz=1 log "- Switching from compiz to metacity." nohup metacity --replace >& /dev/null & disown sleeplog 4 fi # Find preferred video mode. if [ "$mode" = auto ] ; then log "- Autodetecting 'auto' mode." to_exists=0 x=0 ; y=0 ; r=0 output="" { while read line ; do set -- $line [ "$2" = connected ] && { output=$1 ; continue ; } [ "$output" = "$to" ] || continue to_exists=1 [ "$6" = +preferred ] || [ "$7" = +preferred ]\ && { x="${1%x*}" ; y="${1#*x}" ; continue ; } ((x>0)) || continue [ "$1" = v: ] || continue r=${11%Hz} ; break done } < <(xrandr -q --verbose) errmsg="" if ((to_exists==0)) ; then errmsg="Could not find output '$to'." elif [ "$r" = 0 ] ; then errmsg="Could not find preferred mode for '$to'." fi if [ ! -z "$errmsg" ] ; then if ((disabled_compiz==1)) ; then log "- Error detected, restarting compiz." nohup compiz --replace >& /dev/null & disown fi errstop "$errmsg" fi mode=${x}x${y}@$r log "- 'auto' mode resolves to '$mode'." fi mode=$(get_mode $x $y $r) modename=${x}x${y}at${r}hz_$$ log "- Defining mode '$modename'." xrandr --newmode $modename $mode log "- Adding mode to output '$to'." xrandr --addmode $to $modename log "- Turning output '$from' off." xrandr --output $from --off log "- Turning output '$to' on." xrandr --fb ${x}x${y} --output $to --mode $modename # Hack: reenable compiz. if ((disabled_compiz==1)) ; then sleeplog 4 log "- Re-enabling compiz." nohup compiz --replace >& /dev/null & disown sleeplog 4 log "- Restarting gnome-panel (in case it crashed)." nohup gnome-panel --replace >& /dev/null & disown fi log "Finished." logzenity "" logzenity "You can now close this window." wait