Linux user notes -- dual monitor hot plug

As a long time Linux user, I have to admit sometimes it is not easy to achieve some of the things that can be easily done in other OS (like macOS or Windows), but that one of the things I enjoy about Linux as well -- you need to force yourself to learn something, and once you've achieved it, you will learn from it and then realize how powerful Linux is. Anyway, for me, this had been one of the problems that had me troubled for a while -- using dual monitors, and have Linux automatically detect and extend desktops automatically.

Problem

I use bspwm as my tiling window manager, and polybar as the 'bar'. The problem I'm trying to solve here is to have the laptop automatically detect monitor hot-plug and then extend the bars with different layout to the new monitor. And when I unplugged the external monitor, the system revert back to single monitor layout.

Solution

The easiest way to achieve this is using udev. Based on my understanding, udev is similar to device manager in Windows. To solve this problem with udev, all you need to do is to create a new udev rule.

The first step is to find out which events are being triggered when the monitors are plugged/unplugged. To achieve this, you can use the udev monitor: udevadm monitor --environment --udev. Plugin your monitor, and you will be able to see the events that are being triggered, as an example, here's what I got, when I plugged in my external monitor:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
UDEV  [5012.844939] change   /devices/pci0000:00/0000:00:02.0/drm/card0 (drm)
ACTION=change
DEVPATH=/devices/pci0000:00/0000:00:02.0/drm/card0
SUBSYSTEM=drm
HOTPLUG=1
DEVNAME=/dev/dri/card0
DEVTYPE=drm_minor
SEQNUM=4288
USEC_INITIALIZED=184807912
ID_PATH=pci-0000:00:02.0
ID_PATH_TAG=pci-0000_00_02_0
ID_FOR_SEAT=drm-pci-0000_00_02_0
DISPLAY=:0
XAUTHORITY=/home/user/.Xauthority
MAJOR=226
MINOR=0
DEVLINKS=/dev/dri/by-path/pci-0000:00:02.0-card
TAGS=:master-of-seat:seat:uaccess:mutter-device-disable-kms-modifiers:
CURRENT_TAGS=:master-of-seat:seat:uaccess:mutter-device-disable-kms-modifiers:

Next, we are going to create the rules for this udev event. So we create a new file under /etc/udev/rules.d folder, in this case I will call this file /etc/udev/rules.d/95-hdmi-plug.rules, and here's the content of the file

1
ACTION=="change", SUBSYSTEM=="drm", KERNEL=="card0" ENV{DISPLAY}=":0", ENV{XAUTHORITY}="/home/kevin/.Xauthority", RUN+="/home/user/.monitor-hot-plug.sh"

Notice how I matched the event: I used ACTION=="change", SUBSYSTEM=="drm", KERNEL=="card0", this is what comes directly from the monitoring after plugging in the external monitor. The ENV part is just setting some environment variables, which is necessary for X11. For the run part, I put in a script that is tailored to my need, it is quite short and simple, just telling xrandr to set the monitor positioning (probably not a best practice to hard code the positioning though):

1
2
3
4
5
6
7
8
9
10
11
12
#! /usr/bin/bash
function connect(){
xrandr --output eDP1 --mode 1920x1080 --pos 0x1080 --rotate normal --output HDMI1 --primary --mode 1920x1080 --pos 0x0 --rotate normal
}

function disconnect(){
xrandr --output HDMI1 --off
}

xrandr | grep "HDMI1 connected" &> /dev/null && connect || disconnect

/bin/bspc wm -r & disown

At this point, we can start testing. You can definitely plug and remove the HDMI cable multiple times to test if it works, but that is a bit time consuming. We can use sudo udevadm test /sys/class/drm/card0 to see if the config file is correct.

Once you have done the necessary testing, it is important to reload the udev rules into the running system sudo udevadm control --reload-rules

Conclusion

This article explore how udev rules can be utilized to manage hot plug of external monitors. There are also some other different uses for this tool, such as detecting external mouse, external video cam etc. Use the references below to know more.

References

  • Arch Linux Wiki on Udev