#!/bin/sh # # Automatically select a display configuration based on connected devives # # Stefan Tomanek # # How to use: # # Save your current display configuration and setup with # autorandr --save mobile # # Connect an additional display, configure your setup and save it # autorand --save docked # # Now autorandr can detect which hardware setup is active: # # autorandr # mobile # docked (detected) # # To automatically reload your setup, just append --change to the command line # # To manually load a profile, you can use the --load option. # # To prevent a profile from being loaded, place a script call "block" in its # directory. The script is evaluated before the screen setup is inspected, and # in case of it returning a value of 0 the profile is skipped. This can be used # to query the status of a docking station you are about to leave. # # If no suitable profile can be identified, the current configuration is kept. # To change this behaviour and switch to a fallback configuration, specify # --default # # Another script called "postswitch "can be placed in the directory # ~/.auto-disper as well as in all profile directories: The scripts are # executed after a mode switch has taken place and can notify window managers # or other applications about it. XRANDR=/usr/bin/xrandr PROFILES=~/.autorandr/ CHANGE_PROFILE=0 DEFAULT_PROFILE="" SAVE_PROFILE="" setup_fp_xrandr_edid() { $XRANDR -q --verbose | awk ' /^[^ ]+ (dis)?connected / { DEV=$1; } $1 ~ /^[a-f0-9]+$/ { ID[DEV] = ID[DEV] $1 } END { for (X in ID) { print X " " ID[X]; } }' } setup_fp_sysfs_edid() { # hash the EDIDs of all _connected_ devices for P in /sys/class/drm/card*-*/; do if grep -q "^connected$" < "${P}status"; then echo -n "$(basename "$P") " md5sum ${P}edid | awk '{print $1}' fi done } setup_fp() { local METHODS="setup_fp_xrandr_edid setup_fp_sysfs_edid" local FP=""; for M in $METHODS; do FP="$($M)" [ -n "$FP" ] && break; done if [ -z "$FP" ]; then echo "Unable to fingerprint display configuration" >&2 return fi echo "$FP" } current_cfg() { $XRANDR -q | awk ' /^[^ ]+ disconnected / { print "output "$1; print "off"; } /^[^ ]+ connected / { split($3, A, "+"); print "output "$1; print "mode "A[1]; print "pos "A[2]"x"A[3]; }' } blocked() { local PROFILE="$1" [ ! -x "$PROFILES/$PROFILE/block" ] && return 1 "$PROFILES/$PROFILE/block" "$PROFILE" } load() { local PROFILE="$1" if [ "$CHANGE_PROFILE" -eq 1 ] && [ -e "$PROFILES/$PROFILE/config" ] ; then echo " -> loading profile $PROFILE" sed 's!^!--!' "$PROFILES/$PROFILE/config" | xargs xrandr [ -x "$PROFILES/$PROFILE/postswitch" ] && \ "$PROFILES/$PROFILE/postswitch" "$PROFILE" [ -x "$PROFILES/postswitch" ] && \ "$PROFILES/postswitch" "$PROFILE" fi } # process parameters OPTS=$(getopt -n autorandr -o s:l:d:cf --long change,default:,save:,load:,fingerprint -- "$@") if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi eval set -- "$OPTS" while true; do case "$1" in -c|--change) CHANGE_PROFILE=1; shift ;; -d|--default) DEFAULT_PROFILE="$2"; shift 2 ;; -s|--save) SAVE_PROFILE="$2"; shift 2 ;; -l|--load) LOAD_PROFILE="$2"; shift 2 ;; --fingerprint) setup_fp; exit 0;; --) shift; break ;; *) echo "Error: $1"; exit 1;; esac done CURRENT_SETUP="$(setup_fp)" if [ -n "$SAVE_PROFILE" ]; then echo "Saving current configuration as profile '${SAVE_PROFILE}'" mkdir -p "$PROFILES/$SAVE_PROFILE" echo "$CURRENT_SETUP" > "$PROFILES/$SAVE_PROFILE/setup" current_cfg > "$PROFILES/$SAVE_PROFILE/config" exit 0 fi if [ -n "$LOAD_PROFILE" ]; then CHANGE_PROFILE=1 load "$LOAD_PROFILE" exit $? fi for SETUP_FILE in $PROFILES/*/setup; do if ! [ -e $SETUP_FILE ]; then break fi PROFILE="$(basename $(dirname "$SETUP_FILE"))" echo -n "$PROFILE" if blocked "$PROFILE"; then echo " (blocked)" continue fi FILE_SETUP="$(cat "$PROFILES/$PROFILE/setup")" if [ "$CURRENT_SETUP" = "$FILE_SETUP" ]; then echo " (detected)" load "$PROFILE" # found the profile, exit with success exit 0 else echo "" fi done # we did not find the profile, load default if [ -n "$DEFAULT_PROFILE" ]; then echo "No suitable profile detected, falling back to $DEFAULT_PROFILE" load "$DEFAULT_PROFILE" fi exit 1