1 77230597 2020-10-28 xhr #!/usr/bin/env bash
3 0aa694e5 2014-05-29 xhr # Quick-n-dirty script to turn external/internal displays on/off with xrandr
5 6ee453d0 2022-01-04 xhr # 2013-14,2020,2022 by Matthias Schmidt <xhr giessen.ccc.de>
7 0aa694e5 2014-05-29 xhr # License GNU GPL
9 0aa694e5 2014-05-29 xhr function choose_profile()
11 0aa694e5 2014-05-29 xhr local PROFILE=$1
13 0aa694e5 2014-05-29 xhr # Use classic profile mode with -p
14 2ff6f616 2014-05-30 xhr if [ -n "${PROFILE}" ]; then
15 0aa694e5 2014-05-29 xhr case "$PROFILE" in
16 0aa694e5 2014-05-29 xhr # Home profile: Internal on, external extended
18 0aa694e5 2014-05-29 xhr INTERN="LVDS1"
19 0aa694e5 2014-05-29 xhr EXTERN[0]="HDMI1"
21 0aa694e5 2014-05-29 xhr # Work profile: Internal off, both external displays on
23 0aa694e5 2014-05-29 xhr INTERN="LVDS1"
24 0aa694e5 2014-05-29 xhr EXTERN[1]="HDMI3"
25 0aa694e5 2014-05-29 xhr EXTERN[0]="HDMI2"
27 0aa694e5 2014-05-29 xhr # Projector profile: Internal on, external VGA extended
29 0aa694e5 2014-05-29 xhr INTERN="LVDS1"
30 0aa694e5 2014-05-29 xhr EXTERN[0]="VGA1"
32 0aa694e5 2014-05-29 xhr # -----------------------------------------------------------------------
33 0aa694e5 2014-05-29 xhr # Add your own profiles here.
34 0aa694e5 2014-05-29 xhr # -----------------------------------------------------------------------
36 0aa694e5 2014-05-29 xhr # INTERN="LVDS1"
37 0aa694e5 2014-05-29 xhr # EXTERN[0]="VGA1"
39 0aa694e5 2014-05-29 xhr # EXTERN[n]="VGAn"
41 0aa694e5 2014-05-29 xhr # -----------------------------------------------------------------------
44 0aa694e5 2014-05-29 xhr pr "Profile $PROFILE not found"
48 0aa694e5 2014-05-29 xhr # No profiles, use the connected displays instead
50 0aa694e5 2014-05-29 xhr # Convert string with connected displays to array
51 0aa694e5 2014-05-29 xhr local DARRAY=( ${CONNDIS} )
52 0aa694e5 2014-05-29 xhr # Assume that the first display is the internal one
53 0aa694e5 2014-05-29 xhr INTERN=${DARRAY[0]}
55 0aa694e5 2014-05-29 xhr for d in "${DARRAY[@]:1}"; do
56 0aa694e5 2014-05-29 xhr EXTERN[$i]=$d
57 0aa694e5 2014-05-29 xhr i=$(($i + 1))
60 0aa694e5 2014-05-29 xhr [ $VERBOSE -eq 1 ] && {
61 0aa694e5 2014-05-29 xhr echo "Internal Display"
63 0aa694e5 2014-05-29 xhr pg "${INTERN}"
64 0aa694e5 2014-05-29 xhr echo "External Display(s)"
66 0aa694e5 2014-05-29 xhr pg ${EXTERN[@]}
70 0aa694e5 2014-05-29 xhr # Set options deliberatly if toogle mode is on
71 0aa694e5 2014-05-29 xhr if [ ${TFLAG} -eq 1 ]; then
74 0aa694e5 2014-05-29 xhr # 2 = internal only
75 0aa694e5 2014-05-29 xhr # 3 = external only
76 0aa694e5 2014-05-29 xhr case "${STATE}" in
78 0aa694e5 2014-05-29 xhr # Do nothing here
92 0aa694e5 2014-05-29 xhr # Only enable the internal display
93 0aa694e5 2014-05-29 xhr if [ $IFLAG -eq 1 ]; then
94 0aa694e5 2014-05-29 xhr build_xrandr_string "--auto" "--off"
95 0aa694e5 2014-05-29 xhr # Clone screen on all displays
96 0aa694e5 2014-05-29 xhr elif [ $CFLAG -eq 1 ]; then
97 0aa694e5 2014-05-29 xhr RES=`xrandr -q | egrep "^ *[0-9]*x[0-9]*" | awk {'print $1'} | sort | uniq -d | head -1`
98 0aa694e5 2014-05-29 xhr build_xrandr_string "--mode $RES" "--same-as $INTERN"
99 0aa694e5 2014-05-29 xhr # Turn internal display off
100 0aa694e5 2014-05-29 xhr elif [ $EFLAG -eq 1 ]; then
101 0aa694e5 2014-05-29 xhr if [ $RIGHTOF -eq 1 ]; then
102 0aa694e5 2014-05-29 xhr build_xrandr_string "--off" "--auto" "--right-of"
104 0aa694e5 2014-05-29 xhr build_xrandr_string "--off" "--auto" "--left-of"
106 0aa694e5 2014-05-29 xhr # Internal on and extend screen on all displays by default
108 0aa694e5 2014-05-29 xhr build_xrandr_string "--auto" "--auto" "--right-of"
112 0aa694e5 2014-05-29 xhr function build_xrandr_string()
114 0aa694e5 2014-05-29 xhr local DOINTERN=$1
115 0aa694e5 2014-05-29 xhr local DOEXTERN=$2
116 0aa694e5 2014-05-29 xhr local POSITION=$3
118 0aa694e5 2014-05-29 xhr CMD="xrandr --output $INTERN $DOINTERN "
122 0aa694e5 2014-05-29 xhr for d in ${EXTERN[*]}; do
123 0aa694e5 2014-05-29 xhr if [ $CFLAG -eq 1 ]; then
124 0aa694e5 2014-05-29 xhr CMDEXT="${CMDEXT} --output $d ${DOEXTERN} --mode ${RES}"
125 0aa694e5 2014-05-29 xhr elif [ ! -z $POSITION ]; then
126 0aa694e5 2014-05-29 xhr if [ $i -eq 0 ]; then
127 0aa694e5 2014-05-29 xhr CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION} $INTERN"
129 0aa694e5 2014-05-29 xhr CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION} ${EXTERN[i-1]}"
132 0aa694e5 2014-05-29 xhr CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION}"
134 0aa694e5 2014-05-29 xhr i=$(($i + 1))
137 0aa694e5 2014-05-29 xhr CMD="$CMD $CMDEXT"
138 0aa694e5 2014-05-29 xhr [ $VERBOSE -eq 1 ] && {
139 0aa694e5 2014-05-29 xhr echo "I'll run the following command:"
144 0aa694e5 2014-05-29 xhr function run_xrandr()
146 77230597 2020-10-28 xhr echo "$CMD $XRANDROPTS" | bash
149 0aa694e5 2014-05-29 xhr function read_config()
151 0aa694e5 2014-05-29 xhr if [ -f ${DTCONF} ]; then
156 0aa694e5 2014-05-29 xhr function get_last_option()
158 0aa694e5 2014-05-29 xhr # Check if dtoggle saved the last state
159 0aa694e5 2014-05-29 xhr if [ -f ${DTSTATE} ]; then
160 0aa694e5 2014-05-29 xhr . ${DTSTATE}
164 0aa694e5 2014-05-29 xhr function write_last_option()
166 0aa694e5 2014-05-29 xhr echo "STATE=${STATE}" > ${DTSTATE}
169 0aa694e5 2014-05-29 xhr function toggle_option()
171 0aa694e5 2014-05-29 xhr STATE=$(((${STATE} + 1) % 4))
174 0aa694e5 2014-05-29 xhr function usage()
176 2ff6f616 2014-05-30 xhr echo "`basename $0` [-ceix] [-hmntv] [-lr] [-p profile]"
178 0aa694e5 2014-05-29 xhr echo "Display Options:"
179 0aa694e5 2014-05-29 xhr echo " -c Mirror screen on all displays"
180 0aa694e5 2014-05-29 xhr echo " -e Enable external display(s) and disable internal"
181 0aa694e5 2014-05-29 xhr echo " -i Enable only the internal display"
182 0aa694e5 2014-05-29 xhr echo -n " -x Extend screen to all displays "
183 0aa694e5 2014-05-29 xhr pg "[default]"
185 0aa694e5 2014-05-29 xhr echo "General Options:"
186 0aa694e5 2014-05-29 xhr echo " -h Show this help"
187 0aa694e5 2014-05-29 xhr echo " -m Show all available modes"
188 0aa694e5 2014-05-29 xhr echo " -n Dry run. Do not run xrand. Implies -v"
189 0aa694e5 2014-05-29 xhr echo " -t Toggle different options"
190 0aa694e5 2014-05-29 xhr echo " -v Be more verbose"
192 0aa694e5 2014-05-29 xhr echo "Position:"
193 0aa694e5 2014-05-29 xhr echo " -l Display n is left of display (n+1)"
194 0aa694e5 2014-05-29 xhr echo -n " -r Display n is right of display (n+1) "
195 0aa694e5 2014-05-29 xhr pg "[default]"
197 0aa694e5 2014-05-29 xhr echo "Profile:"
198 0aa694e5 2014-05-29 xhr echo " -p profile Enable the specified profile"
202 0aa694e5 2014-05-29 xhr RED='\e[0;31m'
203 0aa694e5 2014-05-29 xhr GREEN='\e[0;32m'
204 0aa694e5 2014-05-29 xhr BLUE='\e[0;34m'
205 0aa694e5 2014-05-29 xhr NC="\e[0;37;40m"
207 0aa694e5 2014-05-29 xhr function pg()
209 0aa694e5 2014-05-29 xhr echo -e "${GREEN}${1}${NC}"
212 0aa694e5 2014-05-29 xhr function pr()
214 0aa694e5 2014-05-29 xhr echo -e "${RED}${1}${NC}"
226 0aa694e5 2014-05-29 xhr # Clone screen on all displays
228 0aa694e5 2014-05-29 xhr # Enable only external displays
230 0aa694e5 2014-05-29 xhr # Enable only the internal display
232 0aa694e5 2014-05-29 xhr # Toggle different modes
236 0aa694e5 2014-05-29 xhr # Display n is right of display (n+1) [default]
238 0aa694e5 2014-05-29 xhr # Additional options for xrandr
239 0aa694e5 2014-05-29 xhr XRANDROPTS=""
240 0aa694e5 2014-05-29 xhr # dtoggle state file
241 9583970e 2014-05-29 xhr DTSTATE=$HOME/.dtoggle
242 0aa694e5 2014-05-29 xhr # dtoggle state file
243 9583970e 2014-05-29 xhr DTCONF=$HOME/.dtoggle.conf
244 0aa694e5 2014-05-29 xhr # Default status
246 0aa694e5 2014-05-29 xhr # Connected displays. Stolen from ArchLinux wiki
247 6ee453d0 2022-01-04 xhr CONNDIS=$(xrandr | grep " connected" | awk '{ printf("%s ", $1) }')
249 2ff6f616 2014-05-30 xhr while getopts "ciehmnrlp:vxt" opt; do
250 0aa694e5 2014-05-29 xhr case $opt in
267 0aa694e5 2014-05-29 xhr XRANDROPTS="--dryrun"
277 0aa694e5 2014-05-29 xhr pg "Connected Displays"
279 0aa694e5 2014-05-29 xhr echo $CONNDIS
280 0aa694e5 2014-05-29 xhr pg "Available Modes"
282 0aa694e5 2014-05-29 xhr exec xrandr -q
285 0aa694e5 2014-05-29 xhr # Do nothing here since its the default
288 0aa694e5 2014-05-29 xhr [ ! -z "$OPTARG" ] && PROFILE=$OPTARG
296 0aa694e5 2014-05-29 xhr pr "Option not found"
302 0aa694e5 2014-05-29 xhr if [ $((CFLAG + $IFLAG + $EFLAG)) -gt 1 ]; then
304 0aa694e5 2014-05-29 xhr pr "Please specify either -c or -e or -i"
310 0aa694e5 2014-05-29 xhr if [ ${TFLAG} -eq 1 ]; then
311 0aa694e5 2014-05-29 xhr get_last_option
312 0aa694e5 2014-05-29 xhr toggle_option
313 0aa694e5 2014-05-29 xhr write_last_option
316 0aa694e5 2014-05-29 xhr choose_profile $PROFILE