Blob


1 #!/usr/bin/env bash
3 # Quick-n-dirty script to turn external/internal displays on/off with xrandr
4 #
5 # 2013-14,2020,2022 by Matthias Schmidt <xhr giessen.ccc.de>
6 #
7 # License GNU GPL
9 function choose_profile()
10 {
11 local PROFILE=$1
13 # Use classic profile mode with -p
14 if [ -n "${PROFILE}" ]; then
15 case "$PROFILE" in
16 # Home profile: Internal on, external extended
17 home)
18 INTERN="LVDS1"
19 EXTERN[0]="HDMI1"
20 ;;
21 # Work profile: Internal off, both external displays on
22 work)
23 INTERN="LVDS1"
24 EXTERN[1]="HDMI3"
25 EXTERN[0]="HDMI2"
26 ;;
27 # Projector profile: Internal on, external VGA extended
28 vga)
29 INTERN="LVDS1"
30 EXTERN[0]="VGA1"
31 ;;
32 # -----------------------------------------------------------------------
33 # Add your own profiles here.
34 # -----------------------------------------------------------------------
35 # name)
36 # INTERN="LVDS1"
37 # EXTERN[0]="VGA1"
38 # ...
39 # EXTERN[n]="VGAn"
40 # ;;
41 # -----------------------------------------------------------------------
42 *)
43 usage
44 pr "Profile $PROFILE not found"
45 exit 1
46 ;;
47 esac
48 # No profiles, use the connected displays instead
49 else
50 # Convert string with connected displays to array
51 local DARRAY=( ${CONNDIS} )
52 # Assume that the first display is the internal one
53 INTERN=${DARRAY[0]}
54 i=0
55 for d in "${DARRAY[@]:1}"; do
56 EXTERN[$i]=$d
57 i=$(($i + 1))
58 done
60 [ $VERBOSE -eq 1 ] && {
61 echo "Internal Display"
62 echo -n " "
63 pg "${INTERN}"
64 echo "External Display(s)"
65 echo -n " "
66 pg ${EXTERN[@]}
67 }
68 fi
70 # Set options deliberatly if toogle mode is on
71 if [ ${TFLAG} -eq 1 ]; then
72 # 0 = extend
73 # 1 = mirror
74 # 2 = internal only
75 # 3 = external only
76 case "${STATE}" in
77 0)
78 # Do nothing here
79 ;;
80 1)
81 CFLAG=1
82 ;;
83 2)
84 IFLAG=1
85 ;;
86 3)
87 EFLAG=1
88 ;;
89 esac
90 fi
92 # Only enable the internal display
93 if [ $IFLAG -eq 1 ]; then
94 build_xrandr_string "--auto" "--off"
95 # Clone screen on all displays
96 elif [ $CFLAG -eq 1 ]; then
97 RES=`xrandr -q | egrep "^ *[0-9]*x[0-9]*" | awk {'print $1'} | sort | uniq -d | head -1`
98 build_xrandr_string "--mode $RES" "--same-as $INTERN"
99 # Turn internal display off
100 elif [ $EFLAG -eq 1 ]; then
101 if [ $RIGHTOF -eq 1 ]; then
102 build_xrandr_string "--off" "--auto" "--right-of"
103 else
104 build_xrandr_string "--off" "--auto" "--left-of"
105 fi
106 # Internal on and extend screen on all displays by default
107 else
108 build_xrandr_string "--auto" "--auto" "--right-of"
109 fi
112 function build_xrandr_string()
114 local DOINTERN=$1
115 local DOEXTERN=$2
116 local POSITION=$3
118 CMD="xrandr --output $INTERN $DOINTERN "
120 CMDEXT=
121 i=0
122 for d in ${EXTERN[*]}; do
123 if [ $CFLAG -eq 1 ]; then
124 CMDEXT="${CMDEXT} --output $d ${DOEXTERN} --mode ${RES}"
125 elif [ ! -z $POSITION ]; then
126 if [ $i -eq 0 ]; then
127 CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION} $INTERN"
128 else
129 CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION} ${EXTERN[i-1]}"
130 fi
131 else
132 CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION}"
133 fi
134 i=$(($i + 1))
135 done
137 CMD="$CMD $CMDEXT"
138 [ $VERBOSE -eq 1 ] && {
139 echo "I'll run the following command:"
140 pg "$CMD"
144 function run_xrandr()
146 echo "$CMD $XRANDROPTS" | bash
149 function read_config()
151 if [ -f ${DTCONF} ]; then
152 . ${DTCONF}
153 fi
156 function get_last_option()
158 # Check if dtoggle saved the last state
159 if [ -f ${DTSTATE} ]; then
160 . ${DTSTATE}
161 fi
164 function write_last_option()
166 echo "STATE=${STATE}" > ${DTSTATE}
169 function toggle_option()
171 STATE=$(((${STATE} + 1) % 4))
174 function usage()
176 echo "`basename $0` [-ceix] [-hmntv] [-lr] [-p profile]"
177 echo
178 echo "Display Options:"
179 echo " -c Mirror screen on all displays"
180 echo " -e Enable external display(s) and disable internal"
181 echo " -i Enable only the internal display"
182 echo -n " -x Extend screen to all displays "
183 pg "[default]"
184 echo
185 echo "General Options:"
186 echo " -h Show this help"
187 echo " -m Show all available modes"
188 echo " -n Dry run. Do not run xrand. Implies -v"
189 echo " -t Toggle different options"
190 echo " -v Be more verbose"
191 echo
192 echo "Position:"
193 echo " -l Display n is left of display (n+1)"
194 echo -n " -r Display n is right of display (n+1) "
195 pg "[default]"
196 echo
197 echo "Profile:"
198 echo " -p profile Enable the specified profile"
199 echo
202 RED='\e[0;31m'
203 GREEN='\e[0;32m'
204 BLUE='\e[0;34m'
205 NC="\e[0;37;40m"
207 function pg()
209 echo -e "${GREEN}${1}${NC}"
212 function pr()
214 echo -e "${RED}${1}${NC}"
217 CMD=
218 PROFILE=
219 INTERN=
220 RES=
221 EXTERN[0]=
222 EXTERN[1]=
223 EXTERN[2]=
224 EXTERN[3]=
226 # Clone screen on all displays
227 CFLAG=0
228 # Enable only external displays
229 EFLAG=0
230 # Enable only the internal display
231 IFLAG=0
232 # Toggle different modes
233 TFLAG=0
234 # Verbosity
235 VERBOSE=0
236 # Display n is right of display (n+1) [default]
237 RIGHTOF=1
238 # Additional options for xrandr
239 XRANDROPTS=""
240 # dtoggle state file
241 DTSTATE=$HOME/.dtoggle
242 # dtoggle state file
243 DTCONF=$HOME/.dtoggle.conf
244 # Default status
245 STATE=0
246 # Connected displays. Stolen from ArchLinux wiki
247 CONNDIS=$(xrandr | grep " connected" | awk '{ printf("%s ", $1) }')
249 while getopts "ciehmnrlp:vxt" opt; do
250 case $opt in
251 c)
252 CFLAG=1
253 ;;
254 i)
255 IFLAG=1
256 ;;
257 e)
258 EFLAG=1
259 ;;
260 t)
261 TFLAG=1
262 ;;
263 v)
264 VERBOSE=1
265 ;;
266 n)
267 XRANDROPTS="--dryrun"
268 VERBOSE=1
269 ;;
270 r)
271 RIGHTOF=1
272 ;;
273 l)
274 RIGHTOF=0
275 ;;
276 m)
277 pg "Connected Displays"
278 echo -n " "
279 echo $CONNDIS
280 pg "Available Modes"
281 echo -n " "
282 exec xrandr -q
283 ;;
284 x)
285 # Do nothing here since its the default
286 ;;
287 p)
288 [ ! -z "$OPTARG" ] && PROFILE=$OPTARG
289 ;;
290 h)
291 usage
292 exit 1
293 ;;
294 *)
295 usage
296 pr "Option not found"
297 exit 1
298 ;;
299 esac
300 done
302 if [ $((CFLAG + $IFLAG + $EFLAG)) -gt 1 ]; then
303 usage
304 pr "Please specify either -c or -e or -i"
305 exit 1
306 fi
308 read_config
310 if [ ${TFLAG} -eq 1 ]; then
311 get_last_option
312 toggle_option
313 write_last_option
314 fi
316 choose_profile $PROFILE
317 run_xrandr
319 exit $?