#!/bin/bash # This script is supposed to change the output display among the various possibilities. Basically: just the laptop, same on both with safe resolution (aka presentation mode) and maximum throughput (dual-screen). # This was made for i965. # At the time of this writing, xorg.conf still requires "Virtual 2560 2048" # name of the screen S1="LVDS1" S2="VGA1" # TODO: depending if the output is a screen or a beamer, the order of the outputs should be different # this could be detected by the on the display's name provided by the edid, or by the resolution provided # (prefered mode of beamer never has a 5/4 ratio for instance) # or it could just remember the last mode of each display according to their name # xrandr is quite slow and used several times, so cache its result xrand_output="$(mktemp)" xrandr > "$xrand_output" #xrand_output="xrandr.out2sc" # Watch out: the order will influence the order of selection but also how the mode are detected # When no state is match, the _second_ is applied # Declares the list of possible states for one screen one_screen_states="rotated preferred" # 1024 is not useful # Declares the list of possible states for two screens two_screen_states=" maxrotated presentation maximum 1024" # First output is minimized version of a huge display, second output follows the mouse at a normal resolution #xrandr --fb 3200x2000 --output $S1 --panning 0x0 --scale 2.5x2.5 --pos 0x0 --rotate normal --output VGA --pos 0x0 --panning 3200x2000+0+0/3200x2000+0+0/64/64/64/64 # one screen probe_preferred(){ # VGA disconnected but still displaying if grep -q "$S2 disconnected .*x.*+.*+.* (" $xrand_output; then # can't be this mode return 1 fi if grep -q "*+" $xrand_output; then # select = preferred if grep -q "$S1 connected .*x.*+0+0 (" $xrand_output; then # no rotation return 0 fi fi return 1 } apply_preferred(){ xrandr --auto --output $S1 --preferred --rotate normal } probe_rotated(){ # VGA disconnected but still displaying if grep -q "$S2 disconnected .*x.*+.*+.* (" $xrand_output; then # can't be this mode return 1 fi if grep -q "$S1 connected .*x.*+0+0 left (" $xrand_output; then # rotated to the left return 0 fi return 1 } apply_rotated(){ xrandr --output $S1 --auto --rotate left } probe_1024(){ # VGA disconnected but still displaying if grep -q "$S2 disconnected .*x.*+.*+.* (" $xrand_output; then # can't be this mode return 1 fi grep -q "1024x768.*\*" $xrand_output # selected = 1024x768 } apply_1024(){ xrandr --auto --output $S1 --mode 1024x768 --rotate normal } # two screens probe_maximum(){ if [ "$(grep -c "\*+" $xrand_output)" == 2 ]; then # select = preferred * 2 if grep -q "$S2 connected .*x.*+...*+0 (" $xrand_output; then # no rotation and shifted horizontally return 0 fi else # Maybe it failed just because the VGA has no preferred mode if [ "$(grep -c -E "^[[:blank:]]*[[:digit:]]+x[[:digit:]]+[[:blank:]]+[[:digit:]]+\.[[:digit:]]+.?\+" $xrand_output)" == 1 ]; then if [ "$(grep -c "\*+" $xrand_output)" == 1 ]; then if grep -q "$S2 connected .*x.*+...*+0 (" $xrand_output; then # no rotation return 0 fi fi fi fi return 1 } apply_maximum(){ xrandr --output $S1 --auto --rotate normal --pos 0x0 --output $S2 --auto --rotate normal --right-of $S1 } probe_maxrotated(){ if [ "$(grep -c "\*+" $xrand_output)" == 2 ]; then # select = preferred * 2 if grep -q "$S2 connected .*x.*+.*+0 left (" $xrand_output; then # rotated to the left return 0 fi else # Maybe it failed just because the VGA has no preferred mode if [ "$(grep -c -E "^[[:blank:]]*[[:digit:]]+x[[:digit:]]+[[:blank:]]+[[:digit:]]+\.[[:digit:]]+.?\+" $xrand_output)" == 1 ]; then if [ "$(grep -c "\*+" $xrand_output)" == 1 ]; then if grep -q "$S2 connected .*x.*+...*+0 left (" $xrand_output; then # no rotation return 0 fi fi fi fi return 1 } # we should put the LVDS at the bottom: dim1 of prefered VGA - dim 2 of prefered LVDS apply_maxrotated(){ xrandr --output $S1 --auto --rotate normal --pos 0x0 --output $S2 --auto --rotate left --right-of $S1 } probe_1024(){ if [ "$(grep -c "1024x768.*\*" $xrand_output)" == 2 ]; then # selected = 1024x768 return 0 fi return 1 } # TODO disable the screensaver? How to re-initialise it? D-BUS command? apply_1024(){ # note that PANEL_FITTING property is to force the black bars, better than deformation # TODO should be a "if the mode doesn't exist" xrandr --newmode "1024x768" 63.50 1024 1072 1176 1328 768 771 775 798 -hsync +vsync xrandr --addmode $S1 "1024x768" xrandr --output $S1 --mode 1024x768 --rotate normal --pos 0x0 --set PANEL_FITTING center --output $S2 --mode 1024x768 --rotate normal --same-as $S1 xbacklight -set 100 # in addition we make sure it's very visible' } # TODO: instead of using 1024x768 we sould use the prefered size of the VGA, which fits inside the prefered size of LVDS probe_presentation(){ if [ "$(grep -c "1024x768.*\*" $xrand_output)" == 2 ]; then # selected = 1024x768 return 0 fi return 1 } # TODO disable the screensaver? How to re-initialise it? D-BUS command? apply_presentation(){ # note that PANEL_FITTING property is to force the black bars, better than deformation xrandr --output $S1 --mode 1024x768 --rotate normal --pos 0x0 --set PANEL_FITTING center --output $S2 --mode 1024x768 --rotate normal --same-as $S1 xbacklight -set 100 # in addition we make sure it's very visible' } # XXX with panning apply_presentationpanning(){ # note that PANEL_FITTING property is to force the black bars, better than deformation xrandr --output $S1 --scale 0.8x0.8 --rotate normal --pos 0x0 --panning 1024x768 --output $S2 --mode 1024x768 --rotate normal --pos 0x0 xbacklight -set 100 # in addition we make sure it's very visible' } # returns as a string the state we are currently in # if no state matchs, returns the first possible state compatible # no arg get_current_state(){ for state in $(list_possible_states); do if probe_$state; then # found the current state! echo $state return fi done # no state found => return the first possible one list_possible_states | cut -d " " -f 1 } # set the new state # 1 arg: the name of the state as a string set_state(){ apply_$1 } # List all the possible (interesting) states according to the screens connected # no arg # returns a string space separated list_possible_states(){ # Two possibilities: with VGA screen connected or not if grep -q "$S2 disconnected" $xrand_output; then # one screen echo -n $one_screen_states else # two screens echo -n $two_screen_states fi } # Return the next state in the list, wrapin around # first arg is the current state # following args are the possible states # return the next state as a string name get_next_state(){ cur=$1 shift prev=$1 first=$prev shift for state in $*; do if [ $prev == $cur ]; then echo $state return fi prev=$state done echo $first } # Main currrent=$(get_current_state) list="$(list_possible_states)" #echo $currrent $list new=$(get_next_state $currrent $list) # no space protection set_state $new # Voila!