I have a solution using udev. It isn't robust, but good enough in my case.
Create a file /etc/udev/rules.d/99-monitor.rules
(the exact file name doesn't matter as long as it only contains letters, digits, _
and -
plus the .rules
extension):
KERNEL=="card0", SUBSYSTEM=="drm", ACTION=="change", RUN+="/usr/local/sbin/monitor-change.udev.sh"
Create a file /usr/local/sbin/monitor-change.udev.sh
and make it executable:
#!/bin/bash
set -e
start_logging () {
exec >/var/log/monitor-change.log 2>&1
echo
set -x
date
}
awaken_monitor () {
# Hack: the monitor stays blank, but forcing it off then on in software
# somehow turns it on.
xset dpms force off
xset dpms force on
}
detect_xorg () {
tty=/dev/tty$(fgconsole)
# Find Xorg running on the foreground console
pids=$(fuser "$tty" 2>/dev/null)
auth_regexp=' -auth ([^ ]*)'
for pid in $pids; do
args=$(ps -o args= -p $pid)
if [[ "$args" = /usr/lib/xorg/Xorg* ]] &&
[[ "$args" =~ $auth_regexp ]]
then
# Hard-code DISPLAY=:0 because it's hard to detect
export DISPLAY=":0" XAUTHORITY="${BASH_REMATCH[1]}"
return 0
fi
done
return 1
}
#start_logging
detect_xorg
awaken_monitor
It acts on any monitor change. This includes turning off the monitor as well as turning it on, and doesn't distinguish between multiple monitors, but this particular machine only ever has a single monitor so it's enough for me.
The udev script detects the X session (which normally runs on tty2 in this Ubuntu 18.04 default setup). There's only one user on this machine so I keep things simple. Note that the X invocation line assumes the Gdm way of invoking the X server; you may need to change this part if you don't use Gdm.
I would prefer a dbus-based solution but I don't know what event to react on.