How to automatically mirror screens when an HDMI cable is plugged in

Published by Stephan on

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.

mirror displays

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 🙂

 


Stephan

I'm a teacher and IT system administrator in an international school. I love open source software and I used it over a decade in my private and work life. My passion is to solve problems with open source software!

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 […]

Leave a Reply

Avatar placeholder

Your email address will not be published. Required fields are marked *