summaryrefslogtreecommitdiffstats
path: root/core/modules/beamergui/data/opt/openslx/scripts/beamergui-mode_setter
blob: c957c20d26814ee2c6a20791a701cd3e4859e6aa (plain) (blame)
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