How to automatically mirror screens when an HDMI cable is plugged in
In our school we have some computers, to which a projector is permanently connected. The projector is connected to an HDMI switch, so that you can switch easily between different inputs, e.g. your own laptop or document camera. Ubuntu extends the desktop by default when connecting a screen. But in our situation we want something different. The desktop of the computer should also be shown at the projector / TV. There are different ways to automatically mirror screens when an HDMI cable is plugged in. I would like to describe how you can use udev to solve this problem.
Mirror Screens Automatically
Potential possibilities
There are several places where you can start to mirror screens. I would like to list some of them briefly:
- no automation. The user (in our case the teacher) has to adjust the screen to his or her liking after each login.
- icon on the desktop. Another possibility would be to create a script that mirrors the screen and places a shortcut on the desktop. With one click you could then mirror the screens.
- Autostart of a script after logging in. That was our solution so far. A small script mirrors the screens after the user logs in.
- Configure LightDM / GDM so that it already mirrors the screens when the user wants to log in.
- In Gnome3 / Unity you can also use monitor.xml to save screen configurations.
- A script that checks if a screen is connected or not and mirrors the screens accordingly, even when the system is running.
Most of the possibilities here solve the problem that the screens are mirrored after logon / at logon. But we also had the problem that the screen settings were reset as soon as you plugged in your own device or selected another source on the HDMI switch. When you switched back, the desktop was extended again instead of mirrored.
The question is: Is there a way to trigger an action when an HDMI cable is plugged in or unplugged (physically or via the HDMI switch)?
udev
Yes! udev is a background service that takes care of that. It takes care of all entries below /dev/, i.e. hard disks, external media, USB devices and also graphics cards. When a cable is plugged in or unplugged, udev triggers an event to which you can respond with the help of an udev rule. But before we create such a rule, let’s take a look at what happens when a cable is plugged in or unplugged. We can use the udev management tool (udevadm) to do this.
$ udevadm monitor --environment --udev
If we now plug in or unplug the HDMI cable, we get the following output:
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 tells us here which device it is (“card0”), which action was triggered (“CHANGE”) and which subsystem is affected (“DRM”). We need this information immediately for our udev rule. We create these under /etc/udev/rules.d/95-hotplug-hdmi.rules:
$ nano /etc/udev/rules.d/95-hotplug-hdmi.rules
There we insert the following line:
ACTION=="change", SUBSYSTEM=="drm", RUN+="/bin/bash /usr/sbin/setHDMIStatus".
So we react to a “change” event in the subsystem “drm” and want to execute the script “/usr/sbin/setHDMIStatus” if this event occurs. The script writes the current state to a file. Actually you can write anything to the file, as long as the file changes when the status changes. Why? We will see in a moment. The script setHDMIStatus has the following content (change username, in case of linuxmuster.net you can use the account of the template user or local admin):
#!/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 is the path to the status of our HDMI port. In this case it is a DVI port.
Note: The script is a workaround because at the time of the udev event xrandr returns the status disconnected even though the cable was connected.
inotify
So far we have only managed to write the status (connected, disconnected) to a file. Now we want to monitor this file for changes and mirror the screens according to their status. For this we create the following script (e.g. with the name /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
For the script to work, the inotify-tools must be installed and the script must be made executable.
$ sudo apt install inotify-tools $ sudo chmod +x /usr/sbin/mirrorDisplays
The script monitors our created file (/home/user/.hdmi_status) and, if an HDMI cable is connected, triggers the xrandr command to mirror the screens.
Autostart
Now the script only has to be defined as an autostart program so that it is started with the login.
Conclusion
We now use this setup for all our computers with a projector attached. Thanks to linuxmuster.net we only use one single Ubuntu image for all our computers. Therefore we distribute the scripts listed above via postsync to the respective computers.
So far everything works quite reliably, even if we are still looking for a solution that is even more universal and doesn’t need a workaround with an extra file. If you have a suggestion, just give it to us 🙂
1 Comment
Mute Sound, Mouse Acceleration and Primary Screen - Command Line Tips | Open School Solutions · November 13, 2018 at 7:22 pm
[…] most rooms, the screen is mirrored by default when a projector or screen is connected via a HDMI switch. In this specific case the colleague uses […]