#
# Automatically select a display configuration based on connected devices
#
-# autorandr was originally written by Stefan Tomanek <stefan.tomanek@wertarbyte.de>
-# For licensing reasons, this version does not contain non-trivial code from the
-# original version and from authors that did not consent with OSS licensing this
-# program.
-#
-#
-#
-# THE FOLLOWING LICENCE AGREEMENT IS PRELIMINARY AND INVALID UNTIL ISSUE #7 AT
-# https://github.com/phillipberndt/autorandr/issues/7
-# HAS BEEN RESOLVED!
+# Copyright (c) 2013 Stefan Tomanek <stefan.tomanek@wertarbyte.de>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
+#
+#
+# How to use:
+#
+# Save your current display configuration and setup with:
+# $ autorandr --save mobile
+#
+# 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)
+#
+# 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
+# (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
+# 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 <profile>
+#
+# Another script called "postswitch "can be placed in the directory
+# ~/.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
RESERVED_PROFILE_NAMES=`cat <<EOF
DEFAULT_PROFILE=""
SAVE_PROFILE=""
-FP_METHODS="setup_fp_sysfs_edid setup_fp_xrandr_edid"
+FP_METHODS="setup_fp_xrandr_edid setup_fp_sysfs_edid"
CURRENT_CFG_METHOD="current_cfg_xrandr"
LOAD_METHOD="load_cfg_xrandr"
# 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
. $CONFIG
fi
+if ! which xxd 2>&1 >/dev/null; then
+ xxd() {
+ # xxd replacement for systems without vim. Ugly, but the only simple
+ # version that both Python 2 and 3 understand that I could come up with.
+ # awk can only do one direction, it has no ord() function.
+ if [ "$1" = "-r" ]; then
+ python -c "import binascii, sys; getattr(sys.stdout, 'buffer', sys.stdout).write(binascii.unhexlify(getattr(sys.stdin, 'buffer', sys.stdin).read()))"
+ else
+ python -c "import binascii, sys; getattr(sys.stdout, 'buffer', sys.stdout).write(binascii.hexlify(getattr(sys.stdin, 'buffer', sys.stdin).read()))"
+ echo
+ fi
+ }
+fi
+
setup_fp_xrandr_edid() {
$XRANDR -q --verbose | awk '
ORS="";
}
setup_fp_sysfs_edid() {
- which xxd >/dev/null 2>&1 || return
$XRANDR -q > /dev/null
for DEVICE in /sys/class/drm/card*-*; do
[ -e "${DEVICE}/status" ] && grep -q "^connected$" "${DEVICE}/status" || continue
echo -n "$(echo "${DEVICE}/edid" | sed -re 's#^.+card[0-9]+-([^/]+).+#\1#; s#-([A-Z]-)?##') "
- xxd -c 256 -ps "${DEVICE}/edid" | awk 'ORS=""; /.+/ { print; }'
+ cat "${DEVICE}/edid" | xxd -c 256 -ps | awk 'ORS=""; /.+/ { print; }'
echo
done
}
+setup_fp_disper() {
+ $DISPER -l | grep '^display '
+}
+
setup_fp() {
- FINGERPRINT=""
- for METHOD in $FP_METHODS; do
- FINGERPRINT="$($METHOD)"
- [ -n "$FINGERPRINT" ] && break
+ local FP="";
+ for M in $FP_METHODS; do
+ FP="$($M)"
+ if [ -n "$FP" ]; then
+ break
+ fi
done
- if [ -z "$FINGERPRINT" ]; then
- echo "Unable to fingerprint display configuration." >&2
- return 0
+ if [ -z "$FP" ]; then
+ echo "Unable to fingerprint display configuration" >&2
+ return
fi
- echo "$FINGERPRINT" | sort
+ echo "$FP" | sort
}
current_cfg_xrandr() {
- $XRANDR -q | awk '
+ 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 [^(]/ {
+ output=$1
print "output "$1;
if ($3 == "primary") {
print $3
}
else {
split($3, A, "+");
+ if (A[1] A[2] "," A[3] == primary_setup)
+ print "primary";
}
if (($4 == "left") || ($4 == "right")) {
split(A[1], B, "x");
}
next;
}
+ / [0-9]+x[0-9]+ .+/ {
+ if (output) {
+ for (n=1; n<10; n++) {
+ if($n ~ /[0-9]+\.[0-9]+\*/) {
+ print "rate " gensub(/(+|\*)/, "", "g", $n);
+ }
+ }
+ }
+ }
# disconnected or disabled displays
/^[^ ]+ (dis)?connected / ||
/^[^ ]+ unknown connection / {
+ output=""
print "output "$1;
print "off";
next;
}
blocked() {
- [ ! -x "$PROFILES/$1/block" ] && return 1
- "$PROFILES/$1/block" "$1"
+ local PROFILE="$1"
+ [ ! -x "$PROFILES/$PROFILE/block" ] && return 1
+
+ "$PROFILES/$PROFILE/block" "$PROFILE"
}
config_equal() {
- if [ "$(cat "$PROFILES/$1/config")" = "$(current_cfg)" ]; then
- echo "Config already loaded." >&2
+ local PROFILE="$1"
+ if [ "$(cat "$PROFILES/$PROFILE/config")" = "$(current_cfg)" ]; then
+ echo "Config already loaded"
return 0
+ else
+ return 1
fi
- return 1
}
load_cfg_xrandr() {
To change this behaviour and switch to a fallback configuration, specify
--default <profile>.
- Another script called "postswitch" can be placed in the directory
+ Another script called "postswitch "can be placed in the directory
~/.autorandr as well as in any profile directories: The scripts are executed
- after a mode switch has taken place and can notify window managers. The same
- goes for "preswitch", which will be executed before a mode switch.
+ 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 configure and save the display configuration.
+ instead of "xrandr" to detect, configure and save the display configuration.
If xrandr is used, the following virtual configurations are available:
${RESERVED_PROFILE_NAMES}
exit $?
fi
-for PROFILE_PATH in $PROFILES/*; do
- PROFILE="$(basename "$PROFILE_PATH")"
- SETUP_FILE="${PROFILE_PATH}/setup"
-
- [ -e $SETUP_FILE ] || continue
+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