So far I wasn't able to find a solution to this, but at least a workaround. xrandr actually detects when a display is connected or disconnected while the greeter is displayed, but this alone is not perfectly reliable. For some reason, it only really picks up the full changes when SDDM is restarted, which also makes it enable the display. However, since there still is a change in xrandr's output, I'm using this to detect if anything changed, and if so, I restart SDDM. But only when the greeter is shown, as display disconnects and reconnects are already handled properly when somebody is actually logged into KDE Plasma.
The core of the functionality is this script, stored as /usr/local/bin/restart_sddm_on_connected_display.sh:
#!/bin/bash
Run this script (as root) when using sddm to ensure that a newly connected
display gets activated, instead of just staying blank. It does so by
checking the output of xrandr and if it changed (meaning that an output was
connected/disconnected or something else changed with the displays), it
restarts sddm iif the greeter is currently running.
DEBUG=0
Check if sddm-greeter is running; do nothing if not.
if ! pgrep -x sddm-greeter > /dev/null; then
[ $DEBUG -eq 1 ] && echo "sddm-greeter not running, exiting."
exit 0
fi
Guess XAUTHORITY if empty.
if [ -z "$XAUTHORITY" ]; then
# Prepare XAUTHORITY with the path of the first found file in
# /var/run/sddm/, fail if none found.
export XAUTHORITY=$(find /var/run/sddm/ -name 'xauth_*' | head -n 1)
if [ -z "$XAUTHORITY" ]; then
exit 1
fi
fi
[ $DEBUG -eq 1 ] && echo "XAUTHORITY: $XAUTHORITY"
Set DISPLAY if not already set.
if [ -z "$DISPLAY" ]; then
export DISPLAY=:0
fi
[ $DEBUG -eq 1 ] && echo "DISPLAY: $DISPLAY"
Run xrandr and save its output to a temporary file.
xrandr > /tmp/.xrandr_output || exit 1
Compare the output of xrandr to the previous output.
xrandr_output_change=$(diff -Nu100 /tmp/.xrandr_output_previous /tmp/.xrandr_output)
Store current output as previous output.
mv /tmp/.xrandr_output /tmp/.xrandr_output_previous
Restart sddm if the output changed.
if [ -n "$xrandr_output_change" ]; then
echo "xrandr output change detected:"
echo "$xrandr_output_change"
echo "Restarting sddm..."
systemctl restart sddm
sleep 5
# Restarting sddm may change the xrandr output, so store it to avoid
# restarting sddm again in the next run.
export XAUTHORITY=$(find /var/run/sddm/ -name 'xauth_*' | head -n 1)
xrandr > /tmp/.xrandr_output_previous
else
[ $DEBUG -eq 1 ] && echo "No change in xrandr output, exiting."
exit 0
fi
Then there's a simple helper script to run this again and again in a loop, so that changes can actually be detected when they happen (a cleaner solution would be to use some kind of notification system, but I don't know what is available to reliably detect such changes). So this is /usr/local/bin/loop_restart_sddm_on_connected_display.sh:
#!/bin/bash
Run this script (as root) in the background to pick up newly connected
displays and restart sddm to activate them when currently no output is active.
Set sleep time if empty.
if [ -z "$SLEEP_TIME" ]; then
SLEEP_TIME=10
fi
Set restarting script if empty.
if [ -z "$RESTART_SCRIPT" ]; then
RESTART_SCRIPT="/usr/local/bin/restart_sddm_on_connected_display.sh"
fi
while true; do
$RESTART_SCRIPT
sleep $SLEEP_TIME
done
And here's the systemd service file /etc/systemd/system/loop_restart_sddm_on_connected_display.service to have this run automatically:
[Unit]
Description=Restart sddm on connected display changes
After=network.target
[Service]
ExecStart=/usr/local/bin/loop_restart_sddm_on_connected_display.sh
Restart=always
Type=simple
KillSignal=SIGTERM
[Install]
WantedBy=multi-user.target
While my use case probably isn't that common, the workaround might still be of value for somebody else. And maybe SDDM will be able to handle such cases by itself some time in the future.