Blame


1 77230597 2020-10-28 xhr #!/usr/bin/env bash
2 0aa694e5 2014-05-29 xhr
3 0aa694e5 2014-05-29 xhr # Quick-n-dirty script to turn external/internal displays on/off with xrandr
4 0aa694e5 2014-05-29 xhr #
5 6ee453d0 2022-01-04 xhr # 2013-14,2020,2022 by Matthias Schmidt <xhr giessen.ccc.de>
6 0aa694e5 2014-05-29 xhr #
7 0aa694e5 2014-05-29 xhr # License GNU GPL
8 0aa694e5 2014-05-29 xhr
9 0aa694e5 2014-05-29 xhr function choose_profile()
10 0aa694e5 2014-05-29 xhr {
11 0aa694e5 2014-05-29 xhr local PROFILE=$1
12 0aa694e5 2014-05-29 xhr
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
17 0aa694e5 2014-05-29 xhr home)
18 0aa694e5 2014-05-29 xhr INTERN="LVDS1"
19 0aa694e5 2014-05-29 xhr EXTERN[0]="HDMI1"
20 0aa694e5 2014-05-29 xhr ;;
21 0aa694e5 2014-05-29 xhr # Work profile: Internal off, both external displays on
22 0aa694e5 2014-05-29 xhr work)
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"
26 0aa694e5 2014-05-29 xhr ;;
27 0aa694e5 2014-05-29 xhr # Projector profile: Internal on, external VGA extended
28 0aa694e5 2014-05-29 xhr vga)
29 0aa694e5 2014-05-29 xhr INTERN="LVDS1"
30 0aa694e5 2014-05-29 xhr EXTERN[0]="VGA1"
31 0aa694e5 2014-05-29 xhr ;;
32 0aa694e5 2014-05-29 xhr # -----------------------------------------------------------------------
33 0aa694e5 2014-05-29 xhr # Add your own profiles here.
34 0aa694e5 2014-05-29 xhr # -----------------------------------------------------------------------
35 0aa694e5 2014-05-29 xhr # name)
36 0aa694e5 2014-05-29 xhr # INTERN="LVDS1"
37 0aa694e5 2014-05-29 xhr # EXTERN[0]="VGA1"
38 0aa694e5 2014-05-29 xhr # ...
39 0aa694e5 2014-05-29 xhr # EXTERN[n]="VGAn"
40 0aa694e5 2014-05-29 xhr # ;;
41 0aa694e5 2014-05-29 xhr # -----------------------------------------------------------------------
42 0aa694e5 2014-05-29 xhr *)
43 0aa694e5 2014-05-29 xhr usage
44 0aa694e5 2014-05-29 xhr pr "Profile $PROFILE not found"
45 0aa694e5 2014-05-29 xhr exit 1
46 0aa694e5 2014-05-29 xhr ;;
47 0aa694e5 2014-05-29 xhr esac
48 0aa694e5 2014-05-29 xhr # No profiles, use the connected displays instead
49 0aa694e5 2014-05-29 xhr else
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]}
54 0aa694e5 2014-05-29 xhr i=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))
58 0aa694e5 2014-05-29 xhr done
59 0aa694e5 2014-05-29 xhr
60 0aa694e5 2014-05-29 xhr [ $VERBOSE -eq 1 ] && {
61 0aa694e5 2014-05-29 xhr echo "Internal Display"
62 0aa694e5 2014-05-29 xhr echo -n " "
63 0aa694e5 2014-05-29 xhr pg "${INTERN}"
64 0aa694e5 2014-05-29 xhr echo "External Display(s)"
65 0aa694e5 2014-05-29 xhr echo -n " "
66 0aa694e5 2014-05-29 xhr pg ${EXTERN[@]}
67 0aa694e5 2014-05-29 xhr }
68 0aa694e5 2014-05-29 xhr fi
69 0aa694e5 2014-05-29 xhr
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
72 0aa694e5 2014-05-29 xhr # 0 = extend
73 0aa694e5 2014-05-29 xhr # 1 = mirror
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
77 0aa694e5 2014-05-29 xhr 0)
78 0aa694e5 2014-05-29 xhr # Do nothing here
79 0aa694e5 2014-05-29 xhr ;;
80 0aa694e5 2014-05-29 xhr 1)
81 0aa694e5 2014-05-29 xhr CFLAG=1
82 0aa694e5 2014-05-29 xhr ;;
83 0aa694e5 2014-05-29 xhr 2)
84 0aa694e5 2014-05-29 xhr IFLAG=1
85 0aa694e5 2014-05-29 xhr ;;
86 0aa694e5 2014-05-29 xhr 3)
87 0aa694e5 2014-05-29 xhr EFLAG=1
88 0aa694e5 2014-05-29 xhr ;;
89 0aa694e5 2014-05-29 xhr esac
90 0aa694e5 2014-05-29 xhr fi
91 0aa694e5 2014-05-29 xhr
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"
103 0aa694e5 2014-05-29 xhr else
104 0aa694e5 2014-05-29 xhr build_xrandr_string "--off" "--auto" "--left-of"
105 0aa694e5 2014-05-29 xhr fi
106 0aa694e5 2014-05-29 xhr # Internal on and extend screen on all displays by default
107 0aa694e5 2014-05-29 xhr else
108 0aa694e5 2014-05-29 xhr build_xrandr_string "--auto" "--auto" "--right-of"
109 0aa694e5 2014-05-29 xhr fi
110 0aa694e5 2014-05-29 xhr }
111 0aa694e5 2014-05-29 xhr
112 0aa694e5 2014-05-29 xhr function build_xrandr_string()
113 0aa694e5 2014-05-29 xhr {
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
117 0aa694e5 2014-05-29 xhr
118 0aa694e5 2014-05-29 xhr CMD="xrandr --output $INTERN $DOINTERN "
119 0aa694e5 2014-05-29 xhr
120 0aa694e5 2014-05-29 xhr CMDEXT=
121 0aa694e5 2014-05-29 xhr i=0
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"
128 0aa694e5 2014-05-29 xhr else
129 0aa694e5 2014-05-29 xhr CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION} ${EXTERN[i-1]}"
130 0aa694e5 2014-05-29 xhr fi
131 0aa694e5 2014-05-29 xhr else
132 0aa694e5 2014-05-29 xhr CMDEXT="${CMDEXT} --output $d ${DOEXTERN} ${POSITION}"
133 0aa694e5 2014-05-29 xhr fi
134 0aa694e5 2014-05-29 xhr i=$(($i + 1))
135 0aa694e5 2014-05-29 xhr done
136 0aa694e5 2014-05-29 xhr
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:"
140 0aa694e5 2014-05-29 xhr pg "$CMD"
141 0aa694e5 2014-05-29 xhr }
142 0aa694e5 2014-05-29 xhr }
143 0aa694e5 2014-05-29 xhr
144 0aa694e5 2014-05-29 xhr function run_xrandr()
145 0aa694e5 2014-05-29 xhr {
146 77230597 2020-10-28 xhr echo "$CMD $XRANDROPTS" | bash
147 0aa694e5 2014-05-29 xhr }
148 0aa694e5 2014-05-29 xhr
149 0aa694e5 2014-05-29 xhr function read_config()
150 0aa694e5 2014-05-29 xhr {
151 0aa694e5 2014-05-29 xhr if [ -f ${DTCONF} ]; then
152 0aa694e5 2014-05-29 xhr . ${DTCONF}
153 0aa694e5 2014-05-29 xhr fi
154 0aa694e5 2014-05-29 xhr }
155 0aa694e5 2014-05-29 xhr
156 0aa694e5 2014-05-29 xhr function get_last_option()
157 0aa694e5 2014-05-29 xhr {
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}
161 0aa694e5 2014-05-29 xhr fi
162 0aa694e5 2014-05-29 xhr }
163 0aa694e5 2014-05-29 xhr
164 0aa694e5 2014-05-29 xhr function write_last_option()
165 0aa694e5 2014-05-29 xhr {
166 0aa694e5 2014-05-29 xhr echo "STATE=${STATE}" > ${DTSTATE}
167 0aa694e5 2014-05-29 xhr }
168 0aa694e5 2014-05-29 xhr
169 0aa694e5 2014-05-29 xhr function toggle_option()
170 0aa694e5 2014-05-29 xhr {
171 0aa694e5 2014-05-29 xhr STATE=$(((${STATE} + 1) % 4))
172 0aa694e5 2014-05-29 xhr }
173 0aa694e5 2014-05-29 xhr
174 0aa694e5 2014-05-29 xhr function usage()
175 0aa694e5 2014-05-29 xhr {
176 2ff6f616 2014-05-30 xhr echo "`basename $0` [-ceix] [-hmntv] [-lr] [-p profile]"
177 0aa694e5 2014-05-29 xhr echo
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]"
184 0aa694e5 2014-05-29 xhr echo
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"
191 0aa694e5 2014-05-29 xhr echo
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]"
196 0aa694e5 2014-05-29 xhr echo
197 0aa694e5 2014-05-29 xhr echo "Profile:"
198 0aa694e5 2014-05-29 xhr echo " -p profile Enable the specified profile"
199 0aa694e5 2014-05-29 xhr echo
200 0aa694e5 2014-05-29 xhr }
201 0aa694e5 2014-05-29 xhr
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"
206 0aa694e5 2014-05-29 xhr
207 0aa694e5 2014-05-29 xhr function pg()
208 0aa694e5 2014-05-29 xhr {
209 0aa694e5 2014-05-29 xhr echo -e "${GREEN}${1}${NC}"
210 0aa694e5 2014-05-29 xhr }
211 0aa694e5 2014-05-29 xhr
212 0aa694e5 2014-05-29 xhr function pr()
213 0aa694e5 2014-05-29 xhr {
214 0aa694e5 2014-05-29 xhr echo -e "${RED}${1}${NC}"
215 0aa694e5 2014-05-29 xhr }
216 0aa694e5 2014-05-29 xhr
217 0aa694e5 2014-05-29 xhr CMD=
218 0aa694e5 2014-05-29 xhr PROFILE=
219 0aa694e5 2014-05-29 xhr INTERN=
220 0aa694e5 2014-05-29 xhr RES=
221 0aa694e5 2014-05-29 xhr EXTERN[0]=
222 0aa694e5 2014-05-29 xhr EXTERN[1]=
223 0aa694e5 2014-05-29 xhr EXTERN[2]=
224 0aa694e5 2014-05-29 xhr EXTERN[3]=
225 0aa694e5 2014-05-29 xhr
226 0aa694e5 2014-05-29 xhr # Clone screen on all displays
227 0aa694e5 2014-05-29 xhr CFLAG=0
228 0aa694e5 2014-05-29 xhr # Enable only external displays
229 0aa694e5 2014-05-29 xhr EFLAG=0
230 0aa694e5 2014-05-29 xhr # Enable only the internal display
231 0aa694e5 2014-05-29 xhr IFLAG=0
232 0aa694e5 2014-05-29 xhr # Toggle different modes
233 0aa694e5 2014-05-29 xhr TFLAG=0
234 0aa694e5 2014-05-29 xhr # Verbosity
235 0aa694e5 2014-05-29 xhr VERBOSE=0
236 0aa694e5 2014-05-29 xhr # Display n is right of display (n+1) [default]
237 0aa694e5 2014-05-29 xhr RIGHTOF=1
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
245 0aa694e5 2014-05-29 xhr STATE=0
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) }')
248 0aa694e5 2014-05-29 xhr
249 2ff6f616 2014-05-30 xhr while getopts "ciehmnrlp:vxt" opt; do
250 0aa694e5 2014-05-29 xhr case $opt in
251 0aa694e5 2014-05-29 xhr c)
252 0aa694e5 2014-05-29 xhr CFLAG=1
253 0aa694e5 2014-05-29 xhr ;;
254 0aa694e5 2014-05-29 xhr i)
255 0aa694e5 2014-05-29 xhr IFLAG=1
256 0aa694e5 2014-05-29 xhr ;;
257 0aa694e5 2014-05-29 xhr e)
258 0aa694e5 2014-05-29 xhr EFLAG=1
259 0aa694e5 2014-05-29 xhr ;;
260 0aa694e5 2014-05-29 xhr t)
261 0aa694e5 2014-05-29 xhr TFLAG=1
262 0aa694e5 2014-05-29 xhr ;;
263 0aa694e5 2014-05-29 xhr v)
264 0aa694e5 2014-05-29 xhr VERBOSE=1
265 0aa694e5 2014-05-29 xhr ;;
266 0aa694e5 2014-05-29 xhr n)
267 0aa694e5 2014-05-29 xhr XRANDROPTS="--dryrun"
268 0aa694e5 2014-05-29 xhr VERBOSE=1
269 0aa694e5 2014-05-29 xhr ;;
270 0aa694e5 2014-05-29 xhr r)
271 0aa694e5 2014-05-29 xhr RIGHTOF=1
272 0aa694e5 2014-05-29 xhr ;;
273 0aa694e5 2014-05-29 xhr l)
274 0aa694e5 2014-05-29 xhr RIGHTOF=0
275 0aa694e5 2014-05-29 xhr ;;
276 0aa694e5 2014-05-29 xhr m)
277 0aa694e5 2014-05-29 xhr pg "Connected Displays"
278 0aa694e5 2014-05-29 xhr echo -n " "
279 0aa694e5 2014-05-29 xhr echo $CONNDIS
280 0aa694e5 2014-05-29 xhr pg "Available Modes"
281 0aa694e5 2014-05-29 xhr echo -n " "
282 0aa694e5 2014-05-29 xhr exec xrandr -q
283 0aa694e5 2014-05-29 xhr ;;
284 0aa694e5 2014-05-29 xhr x)
285 0aa694e5 2014-05-29 xhr # Do nothing here since its the default
286 0aa694e5 2014-05-29 xhr ;;
287 0aa694e5 2014-05-29 xhr p)
288 0aa694e5 2014-05-29 xhr [ ! -z "$OPTARG" ] && PROFILE=$OPTARG
289 0aa694e5 2014-05-29 xhr ;;
290 0aa694e5 2014-05-29 xhr h)
291 0aa694e5 2014-05-29 xhr usage
292 0aa694e5 2014-05-29 xhr exit 1
293 0aa694e5 2014-05-29 xhr ;;
294 0aa694e5 2014-05-29 xhr *)
295 0aa694e5 2014-05-29 xhr usage
296 0aa694e5 2014-05-29 xhr pr "Option not found"
297 0aa694e5 2014-05-29 xhr exit 1
298 0aa694e5 2014-05-29 xhr ;;
299 0aa694e5 2014-05-29 xhr esac
300 0aa694e5 2014-05-29 xhr done
301 0aa694e5 2014-05-29 xhr
302 0aa694e5 2014-05-29 xhr if [ $((CFLAG + $IFLAG + $EFLAG)) -gt 1 ]; then
303 0aa694e5 2014-05-29 xhr usage
304 0aa694e5 2014-05-29 xhr pr "Please specify either -c or -e or -i"
305 0aa694e5 2014-05-29 xhr exit 1
306 0aa694e5 2014-05-29 xhr fi
307 0aa694e5 2014-05-29 xhr
308 0aa694e5 2014-05-29 xhr read_config
309 0aa694e5 2014-05-29 xhr
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
314 0aa694e5 2014-05-29 xhr fi
315 0aa694e5 2014-05-29 xhr
316 0aa694e5 2014-05-29 xhr choose_profile $PROFILE
317 0aa694e5 2014-05-29 xhr run_xrandr
318 0aa694e5 2014-05-29 xhr
319 0aa694e5 2014-05-29 xhr exit $?