#!/bin/sh
#
-# Automatically select a display configuration based on connected devives
+# Automatically select a display configuration based on connected devices
#
# Stefan Tomanek <stefan.tomanek@wertarbyte.de>
#
# How to use:
#
-# Save your current display configuration and setup with
-# autorandr --save mobile
+# Save your current display configuration and setup with:
+# $ autorandr --save mobile
#
-# Connect an additional display, configure your setup and save it
-# autorand --save docked
+# Connect an additional display, configure your setup and save it:
+# $ autorandr --save docked
#
# Now autorandr can detect which hardware setup is active:
-# # autorandr
-# mobile
-# docked (detected)
+# $ 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 <profile> option.
#
# autorandr tries to avoid reloading an identical configuration. To force the
-# configuration, apply --force.
+# (re)configuration, apply --force.
#
# 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
# --default <profile>
#
# 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.
+# ~/.autorandr 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.
+#
+#
+# While the script uses xrandr by default, calling it by the name "autodisper"
+# or "auto-disper" forces it to use the "disper" utility, which is useful for
+# controlling nvidia chipsets. The formats for fingerprinting the current setup
+# and saving/loading the current configuration are adjusted accordingly.
XRANDR=/usr/bin/xrandr
+DISPER=/usr/bin/disper
+XDPYINFO=/usr/bin/xdpyinfo
PROFILES=~/.autorandr/
CONFIG=~/.autorandr.conf
DEFAULT_PROFILE=""
SAVE_PROFILE=""
-FP_METHODS="setup_fp_xrandr_edid setup_fp_sysfs_edid"
+FP_METHODS="setup_fp_sysfs_edid setup_fp_xrandr_edid"
+CURRENT_CFG_METHOD="current_cfg_xrandr"
+LOAD_METHOD="load_cfg_xrandr"
+
+SCRIPTNAME="$(basename $0)"
+# when called as autodisper/auto-disper, we assume different defaults
+if [ "$SCRIPTNAME" = "auto-disper" ] || [ "$SCRIPTNAME" = "autodisper" ]; then
+ echo "Assuming disper defaults..." >&2
+ FP_METHODS="setup_fp_disper"
+ CURRENT_CFG_METHOD="current_cfg_disper"
+ LOAD_METHOD="load_cfg_disper"
+fi
-test -f $CONFIG && . $CONFIG
+if [ -f $CONFIG ]; then
+ echo "Loading configuration from '$CONFIG'" >&2
+ . $CONFIG
+fi
setup_fp_xrandr_edid() {
$XRANDR -q --verbose | awk '
$XRANDR -q > /dev/null
# hash the EDIDs of all _connected_ devices
for P in /sys/class/drm/card*-*/; do
+ # nothing found
+ [ ! -d "$P" ] && continue
if grep -q "^connected$" < "${P}status"; then
echo -n "$(basename "$P") "
md5sum ${P}edid | awk '{print $1}'
done
}
+setup_fp_disper() {
+ $DISPER -l | grep '^display '
+}
+
setup_fp() {
local FP="";
for M in $FP_METHODS; do
FP="$($M)"
- [ -n "$FP" ] && break;
+ if [ -n "$FP" ]; then
+ break
+ fi
done
if [ -z "$FP" ]; then
echo "Unable to fingerprint display configuration" >&2
echo "$FP"
}
-
-current_cfg() {
- $XRANDR -q | awk '
- /^[^ ]+ disconnected / {
- print "output "$1;
- print "off";
- }
- /^[^ ]+ connected / {
- split($3, A, "+");
+current_cfg_xrandr() {
+ local PRIMARY_SETUP="";
+ if [ -x "$XDPYINFO" ]; then
+ PRIMARY_SETUP="$($XDPYINFO -ext XINERAMA | awk '/^ head #0:/ {printf $3 $5}')"
+ fi
+ $XRANDR -q | awk -v primary_setup="${PRIMARY_SETUP}" '
+ # display is connected and has a mode
+ /^[^ ]+ connected [^(]/ {
print "output "$1;
+ if ($3 == "primary") {
+ print $3
+ split($4, A, "+")
+ $4=$5
+ }
+ else {
+ split($3, A, "+");
+ if (A[1] A[2] "," A[3] == primary_setup)
+ print "primary";
+ }
print "mode "A[1];
print "pos "A[2]"x"A[3];
+ if ($4 !~ /^\(/) {
+ print "rotate "$4;
+ }
+ next;
+ }
+ # disconnected or disabled displays
+ /^[^ ]+ (dis)?connected / ||
+ /^[^ ]+ unknown connection / {
+ print "output "$1;
+ print "off";
+ next;
}'
}
+current_cfg_disper() {
+ $DISPER -p
+}
+
+current_cfg() {
+ $CURRENT_CFG_METHOD;
+}
+
blocked() {
local PROFILE="$1"
[ ! -x "$PROFILES/$PROFILE/block" ] && return 1
fi
}
+load_cfg_xrandr() {
+ # sed 1: Prefix arguments with "--"
+ # sed 2: Merge arguments into one line per output
+ # sed 3: Merge into two lines, all --off outputs in the first one
+ sed 's/^/--/' "$1" | sed -e '
+ :START
+ /\n--output/{P;D}
+ s/\n/ /
+ N;bSTART' | sed -e '
+ ### First line
+ / --off/{
+ G
+ # Merge if next line contains --off
+ s/\n\([^\n]* --off\)/ \1/
+ h
+ $!d;b
+ }
+ ### Last line
+ H;x
+ # Merge if previous line contains --mode
+ s/\(--mode [^\n]*\)\n/\1 /
+ h
+ $!d' | xargs -L 1 $XRANDR
+}
+
+load_cfg_disper() {
+ $DISPER -i < "$1"
+}
+
load() {
local PROFILE="$1"
- if [ -e "$PROFILES/$PROFILE/config" ] ; then
+ local CONF="$PROFILES/$PROFILE/config"
+ if [ -e "$CONF" ] ; then
echo " -> loading profile $PROFILE"
- sed 's!^!--!' "$PROFILES/$PROFILE/config" | xargs xrandr
+ $LOAD_METHOD "$CONF"
[ -x "$PROFILES/$PROFILE/postswitch" ] && \
"$PROFILES/$PROFILE/postswitch" "$PROFILE"
help() {
cat <<EOH
-Usage: autorandr [options]
+Usage: $SCRIPTNAME [options]
-h, --help get this small help
-c, --change reload current setup
-d, --default <profile> make profile <profile> the default profile
--force force (re)loading of a profile
--fingerprint fingerprint your current hardware setup
+--config dump your current xrandr setup
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
--default <profile>.
Another script called "postswitch "can be placed in the directory
- ~/.auto-disper as well as in any profile directories: The scripts are executed
+ ~/.autorandr as well as in any profile directories: The scripts are executed
after a mode switch has taken place and can notify window managers.
+ When called by the name "autodisper" or "auto-disper", the script uses "disper"
+ instead of "xrandr" to detect, configure and save the display configuration.
+
EOH
exit
}
# process parameters
-OPTS=$(getopt -n autorandr -o s:l:d:cfh --long change,default:,save:,load:,force,fingerprint,help -- "$@")
+OPTS=$(getopt -n autorandr -o s:l:d:cfh --long change,default:,save:,load:,force,fingerprint,config,help -- "$@")
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
eval set -- "$OPTS"
-h|--help) help ;;
--force) FORCE_LOAD=1; shift ;;
--fingerprint) setup_fp; exit 0;;
+ --config) current_cfg; exit 0;;
--) shift; break ;;
*) echo "Error: $1"; exit 1;;
esac
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"
+ $CURRENT_CFG_METHOD > "$PROFILES/$SAVE_PROFILE/config"
exit 0
fi