1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
|
#! /bin/bash
# This script needs bash for the arrays
# This script adds the common resolutions to the Xserver if and only if there
# is a beamer connected. Additionally, if the preferred resolution is known,
# (i.e. the Xserver received a proper EDID) the latter will be applied.
################################################################################
# Add or remove additional modes here.
declare -a MODES
MODES=("${MODES[@]}" "1024x768 63.50 1024 1072 1176 1328 768 771 775 798 -hsync +vsync")
MODES=("${MODES[@]}" "1152x864 81.75 1152 1216 1336 1520 864 867 871 897 -hsync +vsync")
MODES=("${MODES[@]}" "1280x720 74.50 1280 1344 1472 1664 720 723 728 748 -hsync +vsync")
MODES=("${MODES[@]}" "1280x800 83.50 1280 1352 1480 1680 800 803 809 831 -hsync +vsync")
MODES=("${MODES[@]}" "1280x1024 109.00 1280 1368 1496 1712 1024 1027 1034 1063 -hsync +vsync")
MODES=("${MODES[@]}" "1368x768 85.25 1368 1440 1576 1784 768 771 781 798 -hsync +vsync")
MODES=("${MODES[@]}" "1440x1050 106.50 1440 1528 1672 1904 900 903 909 934 -hsync +vsync")
MODES=("${MODES[@]}" "1600x900 118.25 1600 1696 1856 2112 900 903 908 934 -hsync +vsync")
MODES=("${MODES[@]}" "1680x1050 146.25 1680 1784 1960 2240 1050 1053 1059 1089 -hsync +vsync")
MODES=("${MODES[@]}" "1920x1080 173.00 1920 2048 2248 2576 1080 1083 1088 1120 -hsync +vsync")
MODES=("${MODES[@]}" "1920x1200 193.25 1920 2056 2256 2592 1200 1203 1209 1245 -hsync +vsync")
################################################################################
CONFIGFILE="/opt/openslx/beamergui/beamer.conf"
# Hard-code a few models known to be problematic
declare -a FORCE_BEAMER
FORCE_BEAMER=("AT-HDVS-RX")
################################################################################
#DRIVER=$(lspci -nnk | grep -i vga -A3 | grep 'in use'| awk '{ print $NF }')
XRANDR=$( xrandr )
XRANDRV=$( xrandr --verbose )
################################################################################
echo "$XRANDR"
#echo "$XRANDRV"
# Get the names of the connected outputs
# This is a rigid approach to determine the connected outputs
declare -a OUTPUTNAMES
while read -r line || [[ -n "$line" ]]; do
OUTPUTNAMES+=("$( <<<"$line" awk '{print $1}' )")
done < <( <<<"$XRANDR" grep -E "[[:digit:]]+mm x [[:digit:]]+mm" )
echo -e "Connected outputs: \e[32m${OUTPUTNAMES[@]}\e[0m"
# The goal is to add more modelines to the X server. While this is done the
# screen is flickering. Hence this is just necessary if there is a beamer. Do
# the flickering magic only if there are two outputs and one is a projector.
#Two outputs?
if [ ${#OUTPUTNAMES[@]} -eq 2 ]; then
echo "Two outputs detected."
if ! [ -f "$CONFIGFILE" ]; then
echo "No additional beamer file (${CONFIGFILE}) found."
elif ! [ -r "$CONFIGFILE" ]; then
echo "$CONFIGFILE found but not readable."
else
echo "beamer.conf found, contains the following beamer definitions:"
<"$CONFIGFILE" grep '=beamer$'
fi
# Either of them a projector?
B_INDEX=
MAYBEAMER=
SMALL=
TF=$(mktemp)
[ -z "$TF" ] && TF="/tmp/${RANDOM}-$$"
for i in 0 1; do
# See if we hard-coded the device as a beamer
# Use echo -e -n "" instead of piping the sed output into xargs printf, as xargs
# handles backslashes differently depending on the version.
echo -e -n "$( <<<"$XRANDRV" grep -Pzo "\n${OUTPUTNAMES[$i]}\N*connected\N*\n(\s+\N*\n)+" | grep -Eao '[0-9a-f]{32}' | sed -r ':a;N;$!ba;s/[^0-9a-f]//gI;s/([0-9a-f]{2})/\\x\1/gI' )" > "$TF"
EDID=$( < "$TF" parse-edid )
MODEL_NAME=$( <<<"$EDID" grep -m 1 -E '^\s*ModelName' | sed -r 's/^[^"]*"(.*)"[^"]*$/\1/;s/^\s+//;s/\s+$//' )
echo "'${OUTPUTNAMES[$i]}' is connected to device '$MODEL_NAME'"
# Have a name, do the checks
if [ -n "$MODEL_NAME" ]; then
FOUND=
# Try hard coded values from above
for model in "${FORCE_BEAMER[@]}"; do
if [ "x$model" = "x$MODEL_NAME" ]; then
echo "Model is hard-coded as beamer"
FOUND=ya
break
fi
done
# Now try user supplied config
if [ -z "$FOUND" ] && [ -f "$CONFIGFILE" ] && grep -Fxq "${MODEL_NAME}=beamer" "$CONFIGFILE"; then
echo "Model is defined as beamer in beamer.conf"
FOUND=ya
fi
# Set beamer if any match
if [ -n "$FOUND" ]; then
B_INDEX=$i
continue
fi
fi
# Classic test by what X(randr) figured out
WIDTH=$( <<<"$XRANDR" grep -m 1 -E "^${OUTPUTNAMES[$i]}.*[0-9]+mm x [0-9]+mm" | grep -o -E ' [0-9]+mm x' | grep -o -E '[0-9]+' )
if [ -z "$WIDTH" ] || [ "$WIDTH" -eq 0 ] || [ "$WIDTH" -gt 900 ]; then
echo "Screen $i is beamer, width is '$WIDTH'"
B_INDEX=$i
elif [ -n "$WIDTH" ] && [ "$WIDTH" -gt 700 ]; then
MAYBEAMER=$i
elif [ -n "$WIDTH" ] && [ "$WIDTH" -lt 550 ]; then
SMALL=yes
fi
done
rm -f -- "$TF"
if [ -z "$B_INDEX" ] && [ -n "$MAYBEAMER" ] && [ -n "$SMALL" ]; then
# This is a hack on top of the other hack; we already treat outputs reporting a sufficiently large width
# as beamers, as we have encountered such devices in the wild. However, we might have just a large TV connected
# that is intended to be used just like a beamer to present the screen to the audience. So if we have a screen
# that is at least 70cm wide and the other one is no wider than 55cm we treat this as a beamer setup aswell.
# The reasoning here is that if it were a dual screen setup, the screens should be roughly the same size.
echo "Treating $MAYBEAMER as beamer as size difference is big enough"
B_INDEX=$MAYBEAMER
fi
if [ -n "$B_INDEX" ]; then
BEAMER=${OUTPUTNAMES[$B_INDEX]}
OTHER=${OUTPUTNAMES[$(( 1 - B_INDEX ))]}
echo "$BEAMER is a beamer. "
# Create all modes, so that X knows them by name "<width>x<height>"
# Add the modes to the outputs, this means that, if this action is
# successful they can be applied to the screens.
for i in "${MODES[@]}"; do
if xrandr --current --newmode $i; then # No quotes around $i here!
echo -e "Created mode ${i%% *}."
else
echo -e "\e[31mFailed to create mode ${i%% *}!\e[0m"
fi
for j in "${OUTPUTNAMES[@]}"; do
if xrandr --current --addmode "$j" "${i%% *}"; then
echo -e "Added mode ${i%% *} to $j."
else
echo -e "\e[31mFailed to add mode ${i%% *} to $j!\e[0m"
fi
done
done
# Finally, if the EDID is present, apply a proper resolution.
# Find out whether the beamer transmits reliable EDID data.
# The data in xrandr should be reliable if the EDID is present.
SUCCESS=
# If the beamer transmits the EDID there shall be a preferred resolution.
OPTIMALRES=$( <<<"$XRANDRV" grep -Pzo "\n$BEAMER\N*\n(\s+\N*\n)+" | grep -m 1 -a preferred | awk '{print $1}' )
if [ -n "$OPTIMALRES" ] && <<<"$XRANDRV" grep -Pzo "\n$BEAMER\N*\n(\s+\N*\n)+" | grep -q EDID; then
echo "$BEAMER [Beamer] provides EDID, says $OPTIMALRES is optimal."
# (try to) make sure the display has the preferred mode of the beamer added to it, in case it wasn't in our list from above
xrandr --current --addmode "$OTHER" "$OPTIMALRES"
# Apply the optimal resolution tho either of the outputs. The beamer has
# to be the secondary output.
if xrandr \
--output "$OTHER" --mode "$OPTIMALRES" \
--primary \
--output "$BEAMER" --mode "$OPTIMALRES" \
--same-as "$OTHER"
then
echo "Applied optimal resolution successfully."
SUCCESS=1
fi
elif [[ -f "$CONFIGFILE" ]]; then
echo "Config file found."
# Get local ip
. /opt/openslx/config
# Try to get a forced mode from config
FORCED_MODE=$( <"$CONFIGFILE" grep -m 1 "^\\s*${SLX_PXE_CLIENT_IP}\\s*=" | cut -d '=' -f2 )
# If a mode was found, ..
if [[ -n "$FORCED_MODE" ]]; then
echo "Forced mode found in config file."
# Apply the probed mode from the config file
if xrandr \
--output "$OTHER" --mode "$FORCED_MODE" \
--primary \
--output "$BEAMER" --mode "$FORCED_MODE" \
--same-as "$OTHER"
then
echo "Applied forced mode $FORCED_MODE successfully."
SUCCESS=1
fi
else
echo -e "\e[31mERROR: Beamer provides no EDID and no probed mode given in $CONFIGFILE.\e[0m"
fi
fi
if [ -z "$SUCCESS" ]; then
# Apply a fallback mode
# Maybe the screen has EDID, use its preferred resolution
OPTIMALRES=$( <<<"$XRANDRV" grep -Pzo "\n$OTHER\N*\n(\s+\N*\n)+" \
| grep -m 1 -a preferred | awk '{print $1}' )
for res in "$OPTIMALRES" "1280x800" "1280x720" "1152x864" "1024x768"; do
[ -z "$res" ] && continue
echo -e "\e[31mERROR: Beamer provides no EDID and no config found in $CONFIGFILE. Falling back to ${res}.\e[0m"
xrandr \
--output "$OTHER" --mode "$res" \
--primary \
--output "$BEAMER" --mode "$res" \
--same-as "$OTHER" && break
done
fi
else # $B_INDEX is empty
# In case of two monitors just sort the outputs lexicographically and apply
# the preferred resolution
echo "Dualhead setup deteced. Sorting outputs lexicographically."
readarray -t OUTPUTNAMES \
< <(for a in "${OUTPUTNAMES[@]}"; do echo "$a"; done | sort)
echo "${OUTPUTNAMES[@]}"
if xrandr \
--output "${OUTPUTNAMES[0]}" --preferred \
--primary \
--output "${OUTPUTNAMES[1]}" --preferred \
--right-of "${OUTPUTNAMES[0]}"
then
echo "Successfully applied preferred modes on outputs in sorted order."
fi
fi
else
echo -e "\e[32mOther than two outputs.\e[0m"
fi
exit 0
|