Sample Fn-F7 script

From ThinkWiki
Revision as of 22:38, 12 November 2007 by Seva (Talk | contribs)

Jump to: navigation, search

This guide will let you use Fn-F7 key combination to toggle between internal, mirror, external, or both screens. This was tested on ThinkPad X60s running Fedora 8, please comment if it works or does not work for you.

Add a "Virtual" statement to your /etc/X11/xorg.conf, the total resolution should be large enough to fit all your screens in the configuration you want, for example I have 1600x1200 monitor to the left of my internal 1024x768 monitor for a total max resolution of 2624x1200:

Section "Screen"
       Identifier "Screen0"
       Device     "Videocard0"
       DefaultDepth     24
       SubSection "Display"
               Viewport   0 0
               Depth     24
               Virtual   2624 1200
       EndSubSection
EndSection

Note that for some drivers, including intel 945, the maximum is 2048x2048, see Xorg RandR 1.2 for more details.

Restart X server at this point (i.e. logout and login).

Create /etc/acpi/events/thinkpad.conf:

# fn-F7
event=ibm/hotkey HKEY 00000080 00001007
action=/usr/local/sbin/thinkpad-fn-f7

Create /usr/local/sbin/thinkpad-fn-f7:

Note: you will have change EXTERNAL_OUTPUT and INTERNAL_OUTPUT to what xrandr shows, for example VGA and LVDS in this case:

xrandr | grep connected
VGA connected 1600x1200+0+0 (normal left inverted right x axis y axis) 432mm x 324mm
LVDS connected (normal left inverted right x axis y axis)

#!/bin/sh
#@ seva sevatech.com

EXTERNAL_OUTPUT="VGA"
INTERNAL_OUTPUT="LVDS"
EXTERNAL_LOCATION="left"

# This is to figure out which user and X11 display to work on
# TODO there has to be a better way to do this?
SU="su $(w -h -s | grep ":[0-9]" | head -1 | awk '{print $1}') -c"
export DISPLAY=$(w -h -s | grep ":[0-9]" | head -1 | awk '{print $3}')

case "$EXTERNAL_LOCATION" in
       left|LEFT)
               EXTERNAL_LOCATION="--left-of $INTERNAL_OUTPUT"
               ;;
       right|RIGHT)
               EXTERNAL_LOCATION="--right-of $INTERNAL_OUTPUT"
               ;;
       top|TOP|above|ABOVE)
               EXTERNAL_LOCATION="--above $INTERNAL_OUTPUT"
               ;;
       bottom|BOTTOM|below|BELOW)
               EXTERNAL_LOCATION="--below $INTERNAL_OUTPUT"
               ;;
       *)
               EXTERNAL_LOCATION="--left-of $INTERNAL_OUTPUT"
               ;;
esac

# Save the state to the file until we can figure it out by running xrandr
STATE_FILE=/var/lib/thinkpad/screen.state;
if [ ! -e $STATE_FILE ]; then
       echo "internal" > $STATE_FILE
fi

STATE=$(cat $STATE_FILE)

function screen_external(){
       $SU "xrandr --output $INTERNAL_OUTPUT --off"
       $SU "xrandr --output $EXTERNAL_OUTPUT --auto"
       echo "external" > $STATE_FILE
}

function screen_internal(){
       $SU "xrandr --output $EXTERNAL_OUTPUT --off"
       $SU "xrandr --output $INTERNAL_OUTPUT --auto"
       echo "internal" > $STATE_FILE
}

function screen_mirror(){
       $SU "xrandr --output $INTERNAL_OUTPUT --auto"
       $SU "xrandr --output $EXTERNAL_OUTPUT --auto --same-as $INTERNAL_OUTPUT"
       echo "mirror" > $STATE_FILE
}

function screen_both(){
       $SU "xrandr --output $INTERNAL_OUTPUT --auto"
       $SU "xrandr --output $EXTERNAL_OUTPUT --auto $EXTERNAL_LOCATION"
       echo "both" > $STATE_FILE
}

function screen_toggle(){
       case "$STATE" in
               internal)
                       screen_mirror
                       ;;
               mirror)
                       screen_external
                       ;;
               external)
                       screen_both
                       ;;
               both)
                       screen_internal
                       ;;
               *)
                       screen_internal
                       ;;
       esac
}

# What should we do?
DO="$1"
if [ -z "$DO" ]; then
       DO=$(basename $0)
fi
if [ -z "$DO" ]; then
       DO="internal"
fi

case "$DO" in
       toggle|thinkpad-fn-f7)
               screen_toggle
               ;;
       internal)
               screen_internal
               ;;
       external)
               screen_external
               ;;
       mirror)
               screen_mirror
               ;;
       both)
               screen_both
               ;;
       status)
               echo "Current Fn-F7 state is: $STATE"
               echo
               echo "Attached monitors:"
               xrandr | grep connected | sed "s/^/ /"
               ;;
       *)
               echo "usage: $0 <command>" >&2
               echo >&2
               echo "  commands:" >&2
               echo "          status" >&2
               echo "          internal" >&2
               echo "          external" >&2
               echo "          mirror" >&2
               echo "          both" >&2
               echo "          toggle" >&2
               echo >&2
               echo "  If no command is given default is internal" >&2
               ;;
esac

As root, run the following commands,

mkdir -p /var/lib/thinkpad
echo "internal" > /var/lib/thinkpad/screen.state
chmod 755 /usr/local/sbin/thinkpad-fn-f7
service acpid restart

You should be ready to go, just press Fn-F7 to try.