]> git.donarmstrong.com Git - deb_pkgs/autorandr.git/blobdiff - autorandr
Enable xrandr outputs one-by-one, --pos 0x0 first
[deb_pkgs/autorandr.git] / autorandr
index 90d110831ba0a9efe1c3f2aeefdeb3aa1ae799e0..5937f8a2a8ad3ded1cd9dd27a3d9d7b3535b1bcf 100755 (executable)
--- a/autorandr
+++ b/autorandr
 XRANDR=/usr/bin/xrandr
 DISPER=/usr/bin/disper
 XDPYINFO=/usr/bin/xdpyinfo
-PROFILES=~/.autorandr/
+PROFILES=~/.autorandr
 CONFIG=~/.autorandr.conf
+RESERVED_PROFILE_NAMES=`cat <<EOF
+ common     Clone all connected outputs at the largest common resolution
+ horizontal Stack all connected outputs horizontally at their largest resolution
+ vertical   Stack all connected outputs vertically at their largest resolution
+EOF`
 
 CHANGE_PROFILE=0
 FORCE_LOAD=0
@@ -159,6 +164,95 @@ current_cfg_disper() {
        $DISPER -p
 }
 
+common_cfg_xrandr() {
+       $XRANDR -q | awk '
+       # variables:
+       #   output: current output
+       #   outputlist: space sep list of all outputs
+       #   outputarr: array of all connected outputs
+       #   outputarrsize: number of connected outputs
+       #   modelist[800x600]: space sep list of outputs supporting mode
+       # display is connected
+       /^[^ ]+ connected / {
+           output=$1;
+           outputlist=outputlist " " output
+           outputarr[outputarrsize++]=output
+       }
+       # disconnected or disabled displays
+       /^[^ ]+ disconnected / ||
+       /^[^ ]+ unknown connection / {
+           print "output " $1;
+           print "off";
+       }
+       # modes available on a screen
+       /^   [0-9]+x[0-9]+/ {
+           modelist[$1]=modelist[$1] " " output
+       }
+       END {
+           # find common mode with largest screen area
+           for (m in modelist) {
+               if (modelist[m] == outputlist) {
+                   # calculate area of resolution
+                   split(m, wh, "x");
+                   if (wh[1]*wh[2] >= maxdim) {
+                       maxdim=wh[1]*wh[2]
+                       maxmode=m
+                   }
+               }
+           }
+           if (maxmode) {
+               for (i in outputarr) {
+                   print "output " outputarr[i];
+                   print "mode " maxmode;
+                   print "pos 0x0";
+                   if (i > 0) {
+                       print "same-as " outputarr[0]
+                   }
+               }
+           }
+       }' \
+               | load_cfg_xrandr -
+}
+
+stack_cfg_xrandr() {
+       $XRANDR -q | awk -v stack="${STACK}" '
+       # variables:
+       #   stack: "horizontal" (anything except vertical) or "vertical"
+       #   output: current output
+       #   firstmode: pick first mode after output
+       #   posX,posY: position of the next output
+       BEGIN {
+           posX=posY=0
+       }
+       # display is connected
+       /^[^ ]+ connected / {
+           output=$1;
+           print "output " $1;
+           firstmode=1
+       }
+       # disconnected or disabled displays
+       /^[^ ]+ disconnected / ||
+       /^[^ ]+ unknown connection / {
+           print "output " $1;
+           print "off";
+       }
+       # modes available on a screen, but pick only the first
+       /^   [0-9]+x[0-9]+/ {
+           if (!firstmode) next;
+           firstmode=0
+           # output mode at current virtual desktop pos
+           print "mode " $1;
+           print "pos " posX "x" posY;
+           # calculate position of next output
+           split($1, wh, "x");
+           if (stack == "vertical")
+               posY += wh[2];
+           else
+               posX += wh[1];
+       }' \
+               | load_cfg_xrandr -
+}
+
 current_cfg() {
        $CURRENT_CFG_METHOD;
 }
@@ -183,26 +277,34 @@ config_equal() {
 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 3:  * Merge all --off outputs into the first line
+       #         * Place the output with --pos 0x0 on the second line
+       #         * Remaining outputs are appended as they appear
+       #         * Keep everything in hold buffer until the last line
+       # sed 4: Remove empty lines caused by G and H on empty hold buffer
        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
+                               # Merge with next line if it 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
+                       / --pos 0x0/{
+                               G
+                               # Swap lines 1 and 2 if --off is found
+                               / --off/ s/^\([^\n]*\)\n\([^\n]*\)/\2\n\1/
+                               h
+                               $!d;b
+                       }
+                       H
+                       $!d
+                       x' | sed -e '
+                               /./ !d' | xargs -L 1 $XRANDR
 }
 
 load_cfg_disper() {
@@ -212,7 +314,13 @@ load_cfg_disper() {
 load() {
        local PROFILE="$1"
        local CONF="$PROFILES/$PROFILE/config"
-       [ -f "$CONF" ] || return 1
+       local IS_VIRTUAL_PROFILE=`echo "$RESERVED_PROFILE_NAMES" | grep -c "^ $PROFILE "`
+
+       if [ ! -f "$CONF" -a $IS_VIRTUAL_PROFILE -eq 0 ]; then
+               echo " -> Error: Profile '$PROFILE' does not exist." >&2
+               return
+       fi
+
        if [ -x "$PROFILES/preswitch" ]; then
                "$PROFILES/preswitch" "$PROFILE"
        fi
@@ -220,8 +328,25 @@ load() {
                "$PROFILES/$PROFILE/preswitch" "$PROFILE"
        fi
 
-       echo " -> loading profile $PROFILE"
-       $LOAD_METHOD "$CONF"
+       if [ -f "$CONF" ]; then
+               echo " -> loading profile $PROFILE"
+               if [ $IS_VIRTUAL_PROFILE -ne 0 ]; then
+                       echo " -> Warning: Existing profile overrides virtual profile with same name" >&2
+               fi
+               $LOAD_METHOD "$CONF"
+       else
+               # Virtual profiles
+               if [ $PROFILE = "common" ]; then
+                       echo " -> setting largest common mode in cloned mode"
+                       common_cfg_xrandr
+               elif [ $PROFILE = "horizontal" ]; then
+                       echo " -> stacking all outputs horizontally at their largest modes"
+                       STACK="horizontal" stack_cfg_xrandr
+               elif [ $PROFILE = "vertical" ]; then
+                       echo " -> stacking all outputs vertically at their largest modes"
+                       STACK="vertical" stack_cfg_xrandr
+               fi
+       fi
 
        if [ -x "$PROFILES/$PROFILE/postswitch" ]; then
                "$PROFILES/$PROFILE/postswitch" "$PROFILE"
@@ -260,6 +385,9 @@ Usage: $SCRIPTNAME [options]
  When called by the name "autodisper" or "auto-disper", the script uses "disper"
  instead of "xrandr" to detect, configure and save the display configuration.
 
+ If xrandr is used, the following virtual configurations are available:
+${RESERVED_PROFILE_NAMES}
+
 EOH
        exit
 }
@@ -286,6 +414,10 @@ done
 CURRENT_SETUP="$(setup_fp)"
 
 if [ -n "$SAVE_PROFILE" ]; then
+       if echo "$RESERVED_PROFILE_NAMES" | grep -q "^ $SAVE_PROFILE "; then
+               echo "Cannot save current configuration as profile '${SAVE_PROFILE}': This configuration name is a reserved virtual configuration."
+               exit 1
+       fi
        echo "Saving current configuration as profile '${SAVE_PROFILE}'"
        mkdir -p "$PROFILES/$SAVE_PROFILE"
        echo "$CURRENT_SETUP" > "$PROFILES/$SAVE_PROFILE/setup"
@@ -331,3 +463,10 @@ if [ -n "$DEFAULT_PROFILE" ]; then
        load "$DEFAULT_PROFILE"
 fi
 exit 1
+
+# Local Variables:
+# tab-width: 8
+# sh-basic-offset: 8
+# sh-indentation: 8
+# indent-tabs-mode: t
+# End: