#!/bin/bash 
# Thinkpad Display Script - Stuart Hopkins
# Version 0.4

## Variables - User Changeable ##
PROFDIR="/etc/disper"			# Your profile directory
DISPLOG="/tmp/`whoami`-disper.log"	# Disper logfile


###################################
## TOUCH NOTHING BELOW THIS LINE ##
###################################

## Global Variables ##
DISPDEV=""				# Global var for connected devices
DISPNUM=""				# Global var for num connected devices
DISPOUT=""				# Global var for raw disper output
LCDSTAT=""				# Global var for ACPI LCD status
CRTSTAT=""				# Global var for ACPI CRT status
DVISTAT=""				# Global var for ACPI DVI status

## Functions ##

function checkFILES() {
  # Check the required files are present on the system
  # Disper
  if [ "`which disper`" == "" ]; then
    echo "The program 'disper' is missing, please install it"
    exit 1
  fi
  # IBM ACPI Module
  if [ ! -f "/proc/acpi/ibm/video" ]; then
    echo "The IBM ACPI module doesn't appear to be loaded"
    exit 1
  fi
  # Profile directory
  if [ ! -d "$PROFDIR" ]; then
    echo "The profile directory does not exist, please create it"
    exit 1
  fi
}

function fixXORG() {
  # Fix the missing X.org environment variables (when ran from ACPID etc)
  if [ "$DISPLAY" == "" ]; then
    # X variable not found
    echo "  DISPLAY variable not found, working around"
    if [ -S "/tmp/.X11-unix/X0" ]; then
      export DISPLAY=":0.0"
    elif [ -S "/tmp/.X11-unix/X1" ]; then
      export DISPLAY=":1.0"
    else
      echo "  Unable to find the X Server"
      exit 1
    fi
  fi
  echo "    X DISPLAY=$DISPLAY"
  if [ "$XAUTHORITY" == "" ]; then
    # XAUTHORITY not found
    echo "  XAUTHORITY variable not found, working around"
    if [ -S "/tmp/.X11-unix/X0" ]; then
      curuser=`finger | grep -m1 ":0" | awk '{ print($1) }'`
      curhome=`getent passwd $curuser | cut -d: -f6`
      export XAUTHORITY=$curhome/.Xauthority
    elif [ -S "/tmp/.X11-unix/X1" ]; then
      curuser=`finger | grep -m1 ":1" | awk '{ print($1) }'`
      curhome=`getent passwd $curuser | cut -d: -f6`
      export XAUTHORITY=$curhome/.Xauthority
    else
      echo "  Unable to calculate XAUTHORITY"
      exit 1
    fi
  fi
  echo "    XAUTHORITY=$XAUTHORITY"
}

function haveDFP() {
  # Test if the DFP is enabled
  dfpstat=`cat /proc/acpi/ibm/video | grep "^lcd" | awk '{ print($2) }'`
  if [ "$dfpstat" == "enabled" ]; then
    return 1
  elif [ "$dfpstat" == "disabled" ]; then
    return 0
  else
    echo "  Unknown status value for dfpstat: $dfpstat"
    exit 1
  fi
}

function haveCRT() {
  # Test if a CRT screen is connected and enabled
  crtstat=`cat /proc/acpi/ibm/video | grep "^crt" | awk '{ print($2) }'`
  if [ "$crtstat" == "enabled" ]; then
    return 1
  elif [ "$crtstat" == "disabled" ]; then
    return 0
  else
    echo "  Unknown status value for crtstat: $crtstat"
    exit 1
  fi
}

function haveDVI() {
  # Test if a DVI screen is connected and enabled
  dvistat=`cat /proc/acpi/ibm/video | grep "^dvi" | awk '{ print($2) }'`
  if [ "$dvistat" == "enabled" ]; then
    return 1
  elif [ "$dvistat" == "disabled" ]; then
    return 0
  else
    echo "  Unknown status value for dvistat: $dvistat"
    exit 1
  fi
}

function connSCRN() {
  # Use disper to see how many active screens there are
  # Also to save the output, removes lag
  DISPOUT=`disper -l`
  DISPNUM=`echo "$DISPOUT" | grep -a '^display' | wc -l`
  DISPDEV=`echo "$DISPOUT" | grep -a '^display' | awk '{ print($2) }' | tr -d ':'`
}

function acpiSCRN() {
  # Check the proc folder to find out what screens are physically active
  acpilog=`cat /proc/acpi/ibm/video | tr -d '\t'`
  for devname in lcd crt dvi ; do
    newdevname=`echo ${devname}stat | tr [a-z] [A-Z]`
    if [[ "$acpilog" =~ "$devname:enabled" ]]; then
      # Device is currently enabled
      let $newdevname=1
    elif [[ "$acpilog" =~ "$devname:disabled" ]]; then
      # Device is currently disabled
      let $newdevname=0
    else
      # Shouldn't happen, but for sanity set it to disabled
      let $newdevname=0
    fi
  done
}

function doSTARTUP() {
  # Called from our WM, change to external screen if we have one
  echo "  Running in startup mode"
  echo "  DFP: $LCDSTAT  CRT: $CRTSTAT  DVI: $DVISTAT"
  if [ "$DISPNUM" == "1" ]; then
    # Single display connected, must be DFP
    echo "  Only the LCD was found to be connected, exiting"
    exit 0
  elif [ "$DISPNUM" == "2" ]; then
    # Two connected screens, see if we need to switch
    if [ $CRTSTAT -eq 0 -a $DVISTAT -eq 0 ]; then
      # All external screens are disabled, enable one
      echo "  All external screens currently disabled"
      if [[ "$DISPDEV" =~ "CRT-0" ]]; then
        # CRT connected, switch to it
	echo "  Switching to external CRT"
	disper -d CRT-0 -s >$DISPLOG 2>&1
      elif [[ "$DISPDEV" =~ "DFP-1" ]]; then
	# DVI connected, switch to it
	echo "  Switching to external DVI"
	disper -d DFP-1 -s >$DISPLOG 2>&1
      elif [[ "$DISPDEV" =~ "DVI-0" ]]; then
	# DVI connected, switch to it
	echo "  Switching to external DVI"
	disper -d DVI-0 -s >$DISPLOG 2>&1
      else
	# Nothing appears to be connected, shouldnt happen here
	echo "  Went from connected devices to none, exiting"
	exit 1
      fi
    else
      # An external device is already enabled
      echo "  An external display is already active, exiting"
      exit 0
    fi
  else
    # More than two screens, unsupported
    echo "  More than two screens were found, this is unsupported"
    exit 1
  fi
}

function doACPI() {
  # Called via ACPID (Fn+F7), toggle through displays
  echo "  Running in Fn+F7 mode"
  echo "  DFP: $LCDSTAT  CRT: $CRTSTAT  DVI: $DVISTAT"
  # Act based on what screens are active
  if [ $LCDSTAT -eq 1 ]; then
    # DFP active
    echo "  - DFP found to be active"
    if [ $CRTSTAT -eq 1 ]; then
      # CRT active as well as DFP, switch to CRT only
      echo "  - CRT found to be active, switching to CRT only"
      disper -v -d CRT-0 -s >$DISPLOG 2>&1
      return $?
    elif [ $DVISTAT -eq 1 ]; then
      # DVI active as well as DFP, switch to DVI only
      echo "  - DVI found to be active, switching to DVI only"
      # Check if we register as DVI or DFP
      if [ "`disper -l | grep 'DFP-1'`" != "" ]; then
	# We call it using DFP-1
        disper -v -d DFP-1 -s >$DISPLOG 2>&1
        return $?
      else
	# We call it using DVI-0
	disper -v -d DVI-0 -s >$DISPLOG 2>&1
	return $?
      fi
    else
      # Just the DFP active, switch to external device
      if [ "$DISPNUM" == "1" ]; then
        # No external screen connected, attempt fixup for broken screen
	echo "  No external screen detected, attempting screen fixup"
	disper -v -d DFP-0 -s >$DISPLOG 2>&1
	return $?
      elif [ "$DISPNUM" == "2" ]; then
	# One external screen found, switch to extended
	echo "  Unused external screen found, switching to extended mode"
	if [[ "$DISPDEV" =~ "CRT-0" ]]; then
	  # DFP and CRT
	  disper -v -d DFP-0,CRT-0 -e >$DISPLOG 2>&1
	  return $?
	elif [[ "$DISPDEV" =~ "DFP-1" ]]; then
	  # DFP and DVI
	  disper -v -d DFP-0,DFP-1 -e >$DISPLOG 2>&1
	  return $?
	elif [[ "$DISPDEV" =~ "DVI-0" ]]; then
	  # DFP and DVI
	  disper -v -d DFP-0,DVI-0 -e >$DISPLOG 2>&1
	  return $?
	else
	  # Shouldnt happen
	  echo "  Unused external disappeared in-process, exiting"
	  return 1
        fi
      else
	# More than two screens connected
	echo "  More than two screens is not currently supported"
	echo "  Found $DISPNUM screens"
	return 1
      fi
    fi
  else
    # DFP disabled
    echo "  - DFP found to be disabled"
    if [ $CRTSTAT -eq 1 ]; then
      # CRT active, switch back to DFP
      echo "  - CRT found to be active, switching to DFP only"
      disper -v -d DFP-0 -s >$DISPLOG 2>&1
      return $?
    elif [ $DVISTAT -eq 1 ]; then
      # DVI active, switch back to DFP
      echo "  - DVI found to be active, switching to DFP only"
      disper -v -d DFP-0 -s >$DISPLOG 2>&1
      return $?
    else
      # No screens active?
      echo "  No screens appear to be active, switching to DFP"
      disper -v -d DFP-0 -s >$DISPLOG 2>&1
      return $?
    fi
  fi 
}

## Main Code ##

# Check we were passed a profile/mode
if [ ! $1 ]; then
  echo "Thinkpad Display Script - Stuart Hopkins"
  echo "  You must provide a display profile or mode"
  exit 1
fi
PROF=$1

# Welcome message
echo "Thinkpad Display Script - Stuart Hopkins"
echo "Running as user: `whoami` on `date`"

# Check for missing DISPLAY/XAUTHORITY VARS (ACPID doesnt have these)
fixXORG

# Check for required programs
checkFILES

# Check if we were called by ACPID
if [ "$PROF" == "fnf7" ]; then
  connSCRN
  acpiSCRN
  doACPI
  if [ $? -eq 0 ]; then
    echo "Mode set successfully, exiting"
    exit 0
  else
    echo "Mode set failed with exit code $?, check log for more info"
    exit 1
  fi
fi

# Check if we were called as a startup script
if [ "$PROF" == "startup" ]; then
  connSCRN
  acpiSCRN
  doSTARTUP
  exit 0
fi

# Check if our ARG is a profile
if [ -f "$PROFDIR/$PROF" ]; then
  # It's a profile, load it
  echo "  Running in profile mode: $PROF"
  disper -v -i <$PROFDIR/$PROF >$DISPLOG 2>&1
  if [ $? -ne 0 ]; then
    echo "  Disper failed with the following output:"
    cat $DISPLOG
    exit 1
  fi
  exit 0
else
  # Non-existant profile name
  echo "  Non-existant profile specified, not doing anything"
  exit 1
fi

# All done
exit 0

