Difference between revisions of "Sample Fn-F7 script"

From ThinkWiki
Jump to: navigation, search
(coloured bash script)
Line 18: Line 18:
 
Create /etc/acpi/events/thinkpad.conf:
 
Create /etc/acpi/events/thinkpad.conf:
  
# fn-F7
 
 
  event=ibm/hotkey HKEY 00000080 00001007
 
  event=ibm/hotkey HKEY 00000080 00001007
 
  action=/usr/local/sbin/thinkpad-fn-f7
 
  action=/usr/local/sbin/thinkpad-fn-f7
Line 29: Line 28:
 
  '''VGA''' connected 1600x1200+0+0 (normal left inverted right x axis y axis) 432mm x 324mm
 
  '''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)
 
  '''LVDS''' connected (normal left inverted right x axis y axis)
<bash>#!/bin/bash
 
#@ seva sevatech.com
 
  
EXTERNAL_OUTPUT="VGA"
+
#!/bin/bash
INTERNAL_OUTPUT="LVDS"
+
EXTERNAL_LOCATION="left"
+
# External output may be "VGA" or "VGA-0" or "DVI-0"
 +
EXTERNAL_OUTPUT="'''VGA'''"
 +
INTERNAL_OUTPUT="'''LVDS'''"
 +
EXTERNAL_LOCATION="'''left'''"
 +
 +
# Figure out which user and X11 display to work on
 +
# TODO there has to be a better way to do this?
 +
X_USER=$(w -h -s | grep ":[0-9]" | head -1 | awk '{print $1}')
 +
export DISPLAY=$(w -h -s | grep ":[0-9]" | head -1 | awk '{print $3}')
 +
 +
# Switch to X user if necessary
 +
if [ "$X_USER" != "$USER" ]; then
 +
        SU="su $X_USER -c"
 +
fi
 +
 +
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
 +
 +
# Figure out current state
 +
INTERNAL_STATE=$($SU xrandr | grep ^$INTERNAL_OUTPUT | grep con | sed "s/.* connected //" | sed "s/(.*//")
 +
EXTERNAL_STATE=$($SU xrandr | grep ^$EXTERNAL_OUTPUT | grep con | sed "s/.* connected //" | sed "s/(.*//")
 +
 +
if [ -z "$INTERNAL_STATE" ]; then
 +
        STATE="external"
 +
elif [ -z "$EXTERNAL_STATE" ]; then
 +
        STATE="internal"
 +
else
 +
        INTERNAL_STATE=$(echo $INTERNAL_STATE | sed "s/[0-9]*x[0-9]*//")
 +
        EXTERNAL_STATE=$(echo $EXTERNAL_STATE | sed "s/[0-9]*x[0-9]*//")
 +
        if [ "$INTERNAL_STATE" = "$EXTERNAL_STATE" ]; then
 +
                STATE="mirror"
 +
        else
 +
                STATE="both"
 +
        fi
 +
fi
 +
 +
function screen_external(){
 +
        $SU "xrandr --output $INTERNAL_OUTPUT --off"
 +
        $SU "xrandr --output $EXTERNAL_OUTPUT --auto"
 +
}
 +
 +
function screen_internal(){
 +
        $SU "xrandr --output $EXTERNAL_OUTPUT --off"
 +
        $SU "xrandr --output $INTERNAL_OUTPUT --auto"
 +
}
 +
 +
function screen_mirror(){
 +
        $SU "xrandr --output $INTERNAL_OUTPUT --auto"
 +
        $SU "xrandr --output $EXTERNAL_OUTPUT --auto --same-as $INTERNAL_OUTPUT"
 +
}
 +
 +
function screen_both(){
 +
        $SU "xrandr --output $INTERNAL_OUTPUT --auto"
 +
        $SU "xrandr --output $EXTERNAL_OUTPUT --auto $EXTERNAL_LOCATION"
 +
}
 +
 +
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
 +
        if [ $(basename $0) = "thinkpad-fn-f7" ]; then
 +
                DO="toggle"
 +
        fi
 +
fi
 +
 +
case "$DO" in
 +
        toggle)
 +
                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
 +
                ;;
 +
esac
  
# 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
 
# TODO figure out the state from xrandr and xwininfo -root or something?
 
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</bash>
 
  
 
As root, run the following commands,
 
As root, run the following commands,
  
{{cmdroot|mkdir -p /var/lib/thinkpad}}
 
{{cmdroot|echo "internal" > /var/lib/thinkpad/screen.state}}
 
 
  {{cmdroot|chmod 755 /usr/local/sbin/thinkpad-fn-f7}}
 
  {{cmdroot|chmod 755 /usr/local/sbin/thinkpad-fn-f7}}
 
  {{cmdroot|service acpid restart}}
 
  {{cmdroot|service acpid restart}}
  
 
You should be ready to go, just press Fn-F7 to try.
 
You should be ready to go, just press Fn-F7 to try.

Revision as of 20:20, 13 November 2007

This guide will help you configure 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 if you have 1600x1200 monitor to the left of your internal 1024x768 monitor, your total max resolution is 2624x1200 (See Xorg RandR 1.2 for more details):

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

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

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

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/bash

# External output may be "VGA" or "VGA-0" or "DVI-0"
EXTERNAL_OUTPUT="VGA"
INTERNAL_OUTPUT="LVDS"
EXTERNAL_LOCATION="left"

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

# Switch to X user if necessary
if [ "$X_USER" != "$USER" ]; then
       SU="su $X_USER -c"
fi

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

# Figure out current state
INTERNAL_STATE=$($SU xrandr | grep ^$INTERNAL_OUTPUT | grep con | sed "s/.* connected //" | sed "s/(.*//")
EXTERNAL_STATE=$($SU xrandr | grep ^$EXTERNAL_OUTPUT | grep con | sed "s/.* connected //" | sed "s/(.*//")

if [ -z "$INTERNAL_STATE" ]; then
       STATE="external"
elif [ -z "$EXTERNAL_STATE" ]; then
       STATE="internal"
else
       INTERNAL_STATE=$(echo $INTERNAL_STATE | sed "s/[0-9]*x[0-9]*//")
       EXTERNAL_STATE=$(echo $EXTERNAL_STATE | sed "s/[0-9]*x[0-9]*//")
       if [ "$INTERNAL_STATE" = "$EXTERNAL_STATE" ]; then
               STATE="mirror"
       else
               STATE="both"
       fi
fi

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

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

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

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

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
       if [ $(basename $0) = "thinkpad-fn-f7" ]; then
               DO="toggle"
       fi
fi

case "$DO" in
       toggle)
               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
               ;;
esac


As root, run the following commands,

# chmod 755 /usr/local/sbin/thinkpad-fn-f7
# service acpid restart

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