Bildschirme automatisch spiegeln

Wie man Bildschirme automatisch spiegelt, wenn ein HDMI-Kabel eingesteckt wird

In unserer Schule haben wir einige Rechner, an denen ein Beamer fest angeschlossen ist. Der Beamer wiederum hängt an einem HDMI-Switch, damit man bequem zwischen verschiedenen Eingängen umschalten kann, z.B. eigener Laptop oder Dokumentenkamera. Ubuntu erweitert standardmäßig den Desktop, wenn man einen Bildschirm anschließt. In unserer Situation wollen wir aber etwas anderes. Der Desktop des Rechners sollte ebenfalls am Beamer gezeigt werden. Es gibt verschiedene Wege, wie man Bildschirme automatisch spiegelt, wenn ein HDMI-Kabel eingesteckt wird. Ich möchte beschreiben, wie man udev verwenden kann, um dieses Problem zu lösen.

Bildschirme automatisch spiegeln

Potenzielle Möglichkeiten

Es gibt verschiedene Stellen, an denen man ansetzen kann, um Bildschirme zu spiegeln. Einige möchte ich kurz auflisten:

  • keine Automatisierung. Der Benutzer (in unserem Fall die Lehrkaft) muss sich nach jeder Anmeldung selbst den Bildschirm so einstellen, wie er/sie es haben will.
  • Symbol auf dem Desktop. Eine weitere Möglichkeit wäre, dass man ein Skript erstellt, welches den Bildschirm spiegelt und eine Verknüpfung auf den Desktop legt. Mit einem Klick könnte man dann die Bildschirme spiegeln.
  • Autostart eines Skripts nach dem Anmelden. Das war bisher unsere Lösung. Ein kleines Skript spiegelt die Bildschirme nach der Anmeldung des Benutzers.
  • LightDM / GDM so konfigurieren, dass es schon beim Anmeldeschirm die Bildschirme spiegelt
  • In Gnome3 / Unity kann man auch die monitor.xml verwenden, um Bildschirmkonfigurationen zu speichern.
  • Ein Skript, was überprüft, ob ein Bildschirm angeschlossen ist oder nicht und entsprechend die Bildschirme spiegelt, auch im laufenden Betrieb.

Die meisten Möglichkeiten hier lösen das Problem, dass die Bildschirme nach dem Anmelden / beim Anmelden gespiegelt sind. Bei uns trat aber zusätzlich das Problem auf, dass die Bildschirmeinstellungen zurückgesetzt wurden, sobald man ein eigenes Gerät eingesteckt oder eine andere Quelle am HDMI-Switch ausgewählt hatte. Wenn man dann zurückgeschaltet hat, war der Desktop wieder erweitert, statt gespiegelt.

Daraus folgt die Frage: Gibt es eine Möglichkeit, eine Aktion auszulösen, sobald ein HDMI-Kabel eingesteckt oder abgezogen (physisch oder über den HDMI-Switch) wird?

udev

Ja! udev ist ein Hintergrunddienst, der sich genau darum kümmert. Er kümmert sich um alle Einträge unterhalb von /dev/, d.h. Festplatten, externe Medien, USB-Geräte und auch Grafikkarten. Wenn ein Kabel angesteckt oder abgezogen wird, löst udev ein Ereignis („Event“) aus, auf das man mit Hilfe einer udev-Regel reagieren kann. Bevor wir jedoch so eine Regel erstellen, wollen wir uns anschauen, was passiert, wenn ein Kabel eingesteckt oder abgezogen wird. Dazu können wir das udev-Management-Tool (udevadm) verwenden.

$ udevadm monitor --environment --udev

Wenn wir jetzt das HDMI-Kabel einstecken oder abziehen, bekommen wir folgende Ausgabe:

UDEV  [2247.166677] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
ACTION=change
DEVNAME=/dev/dri/card0
DEVPATH=/devices/pci0000:00/0000:00:02.0/drm/card0
DEVTYPE=drm_minor
HOTPLUG=1
ID_FOR_SEAT=drm-pci-0000_00_02_0
ID_PATH=pci-0000:00:02.0
ID_PATH_TAG=pci-0000_00_02_0
MAJOR=226
MINOR=0
SEQNUM=2120
SUBSYSTEM=drm
TAGS=:seat:master-of-seat:uaccess:
USEC_INITIALIZED=15405142

udev sagt uns hier, um welches Gerät es sich handelt („card0“), welche Aktion ausgelöst wurde („CHANGE“) und welches Subsystem betroffen ist („DRM“). Diese Angaben brauchen wir gleich für unsere udev-Regel. Diese erstellen wir unter /etc/udev/rules.d/95-hotplug-hdmi.rules:

$ nano /etc/udev/rules.d/95-hotplug-hdmi.rules

Dort fügen wir folgende Zeile ein:

ACTION=="change", SUBSYSTEM=="drm", RUN+="/bin/bash /usr/sbin/setHDMIStatus"

Wir reagieren also auf ein „change“ Ereignis im Subsystem „drm“ und wollen, falls dieses Event eintritt das Skript „/usr/sbin/setHDMIStatus“ ausführen. Das Skript schreibt den aktuellen Status in eine Datei. Es kann auch irgendetwas anderes in die Datei geschrieben werden, Hauptsache, die Datei verändert sich, wenn der Status sich ändert. Warum werden wir gleich noch sehen. Das Skript setHDMIStatus hat folgenden Inhalt (Benutzernamen anpassen, im Falle von linuxmuster.net kann man den Account des Vorlagenbenutzers bzw. lokalen Admins nehmen):

#!/bin/bash

STATUS="$(/bin/cat /sys/class/drm/card0-DVI-D-1/status)"
/bin/echo $STATUS > /home/user/.hdmi_status

/sys/class/drm/card0-DVI-D-1/status ist der Pfad zum Status unseres HDMI-Anschlusses. In diesem Fall ist es ein DVI-Anschluss.

Hinweis: Das Skript ist ein Workaround, da zum Zeitpunkt des udev-Ereignisses xrandr den Status disconnected liefert, obwohl das Kabel angeschlossen war.

inotify

Bis jetzt haben wir lediglich erreicht, dass der Status (connected, disconnected) in eine Datei geschrieben wird. Wir wollen jetzt diese Datei auf Änderungen überwachen und je nach Status die Bildschirme spiegeln. Dazu erstellen wir folgendes Skript (z.B. mit dem Namen /usr/sbin/mirrorDisplays):

#!/bin/bash

HDMI_STATUS=/home/user/.hdmi_status
PROJECTOR=/sys/class/drm/card0-DVI-D-1/status
touch $HDMI_STATUS
dmode="$(cat $PROJECTOR)"

function mirror {
    xrandr --output DVI1 --mode "1280x1024" --same-as VGA1 --output VGA1 --mode "1280x1024"
}

#Initial Login (Spiegeln beim Anmelden)
if [ "${dmode}" = connected ];then
    mirror
fi

# watch HDMI connected status and setup screens
while inotifywait -q -e modify,create,delete,open,close,close_write,access $HDMI_STATUS &> /dev/null;
dmode="$(cat $PROJECTOR)"
do
    if [ "${dmode}" = connected ];then
     sleep .5s
     mirror
    fi
done

Damit das Skript auch funktioniert, müssen die inotify-tools installiert sein und das Skript ausführbar gemacht werden.

$ sudo apt install inotify-tools
$ sudo chmod +x /usr/sbin/mirrorDisplays

Das Skript überwacht unserer angelegte Datei (/home/user/.hdmi_status) und löst, wenn ein HDMI-Kabel angeschlossen ist, den xrandr-Befehl zum Spiegeln der Bildschirme aus.

Autostart

Nun muss das Skript nur noch als Startprogramm festgelegt werden, damit es bei der Anmeldung mit gestartet wird.

Autostart einrichten

 

Fazit

Wir nutzen dieses Setup nun für alle unsere Rechner, an denen ein Beamer hängt. Da wir dank linuxmuster.net nur ein einziges Ubuntu-Image für alle unsere Rechner verwenden, verteilen wir die oben aufgeführten Skripte per postsync an die entsprechenden Rechner.

Bisher funktioniert alles recht zuverlässig, auch wenn wir weiterhin auf der Suche nach einer Lösung sind, die noch etwas universeller ist und keinen Umweg mit einer extra Datei braucht. Wer einen Vorschlag hat, nur her damit 🙂

 

 

4 Comments:

  1. badgerhill

    hi,
    ob es eine lösung ist weiß ich nicht – hab’s nicht probiert.
    aus meiner sicht aber ein timing issue – daher die frage, ob es nicht reicht im setHDMIStatus script ein sleep einzubauen.
    z.b:

    STATUS="$(/bin/cat /sys/class/drm/card0-DVI-D-1/status)"
    if [ "${STATUS}" = connected ];then
    sleep 2s
    xrandr --output DVI1 --mode "1280x1024" --same-as VGA1 --output VGA1 --mode "1280x1024"
    fi

  2. badgerhill

    nachtrag:
    vermutlich fehlt noch
    export DISPLAY=:0.0
    sowie
    export XAUTHORITY=/home/$USERNAME/.Xauthority
    fehlt noch, dann sollte es klappen.

  3. zefanja

    Ja, das habe ich auch schon probiert, aber selbst das Timing mit sleep hat nichts gebracht. xrandr hat da ebenfalls gewartet. Irgendwie scheint da udev am schnellsten zu sein und der Status unter /sys/… scheint erst danach aktualisiert zu werden.

Leave a Reply:

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert