- Add 20-dummy-headless.conf (Driver dummy, 1920x1080) - Remove 20-intel-virtual.conf (intel driver required HDMI at boot) - Update install.sh: installs dummy driver, saves EDID, updates GRUB - Update README: document dummy driver + kernel EDID fallback approach - hdmi-fallback.sh now detects DUMMY0 or VIRTUAL1 Rationale: intel VirtualHeads only worked when HDMI was connected at boot. Dummy driver creates DUMMY0 unconditionally, working with or without cable. Kernel EDID fallback (video=... drm.edid_firmware=...) is insurance if dummy fails.
275 lines
7.8 KiB
Bash
275 lines
7.8 KiB
Bash
#!/bin/bash
|
|
# RDtop Installer — RustDesk headless display setup (dummy driver)
|
|
# Usage: bash -c "$(curl -fsSL https://git.softuniq.eu/NW/RDtop/raw/branch/main/install.sh)"
|
|
set -euo pipefail
|
|
|
|
echo "=== RDtop Installer ==="
|
|
echo "Installing RustDesk headless display fallback..."
|
|
|
|
# Config paths
|
|
REPO_URL="https://git.softuniq.eu/NW/RDtop"
|
|
X11_CONF="/etc/X11/xorg.conf.d/20-dummy-headless.conf"
|
|
BIN_DST="$HOME/.local/bin/hdmi-fallback.sh"
|
|
SYSTEMD_DST="$HOME/.config/systemd/user/hdmi-fallback.service"
|
|
EDID_DST="/lib/firmware/edid/samsung.bin"
|
|
LOG="$HOME/.local/logs/rdtop-install.log"
|
|
|
|
mkdir -p "$(dirname "$LOG")"
|
|
log() { echo "$(date '+%F %T') $1" | tee -a "$LOG"; }
|
|
|
|
log "Start install"
|
|
|
|
# --- Check prerequisites ---
|
|
if [ "$EUID" -eq 0 ]; then
|
|
log "ERROR: Do not run as root. Run as regular user with sudo access."
|
|
exit 1
|
|
fi
|
|
|
|
# --- Check sudo works ---
|
|
if ! sudo -n true 2>/dev/null; then
|
|
echo "This script requires sudo privileges. Please enter your password when prompted."
|
|
fi
|
|
|
|
# --- Install dummy driver ---
|
|
if [ -f /usr/lib/xorg/modules/drivers/dummy_drv.so ]; then
|
|
log "Dummy driver already present"
|
|
else
|
|
log "Installing xserver-xorg-video-dummy..."
|
|
if command -v apt-get >/dev/null 2>&1; then
|
|
sudo apt-get update -qq && sudo apt-get install -y -qq xserver-xorg-video-dummy || true
|
|
else
|
|
log "WARNING: apt-get not found, cannot install dummy driver"
|
|
exit 1
|
|
fi
|
|
fi
|
|
|
|
# --- Remove old conflicting configs ---
|
|
log "Removing old Intel X11 configs"
|
|
sudo rm -f /etc/X11/xorg.conf.d/20-intel-virtual.conf
|
|
sudo rm -f /etc/X11/xorg.conf.d/90-fallback.conf
|
|
|
|
# --- Copy EDID firmware ---
|
|
log "Saving EDID firmware"
|
|
if [ -f /sys/class/drm/card0-HDMI-A-1/edid ]; then
|
|
sudo mkdir -p /lib/firmware/edid
|
|
sudo cp /sys/class/drm/card0-HDMI-A-1/edid "$EDID_DST"
|
|
sudo chmod 644 "$EDID_DST"
|
|
log "EDID saved to $EDID_DST"
|
|
else
|
|
log "WARNING: No EDID found at /sys/class/drm/card0-HDMI-A-1/edid"
|
|
fi
|
|
|
|
# --- Create dummy headless X11 config ---
|
|
log "Creating dummy headless X11 config at $X11_CONF"
|
|
cat <<'XORG' | sudo tee "$X11_CONF" >/dev/null
|
|
Section "Device"
|
|
Identifier "DummyHeadless"
|
|
Driver "dummy"
|
|
Option "ConstantDPI" "true"
|
|
VideoRam 256000
|
|
EndSection
|
|
|
|
Section "Monitor"
|
|
Identifier "DummyMonitor"
|
|
HorizSync 28-80
|
|
VertRefresh 48-75
|
|
EndSection
|
|
|
|
Section "Screen"
|
|
Identifier "DummyScreen"
|
|
Device "DummyHeadless"
|
|
Monitor "DummyMonitor"
|
|
DefaultDepth 24
|
|
SubSection "Display"
|
|
Depth 24
|
|
Modes "1920x1080" "1280x720"
|
|
EndSubSection
|
|
EndSection
|
|
XORG
|
|
sudo chmod 644 "$X11_CONF"
|
|
log "X11 config installed"
|
|
|
|
# --- Update GRUB for kernel EDID fallback ---
|
|
log "Updating GRUB cmdline for EDID fallback"
|
|
if [ -f /etc/default/grub ]; then
|
|
sudo sed -i 's|GRUB_CMDLINE_LINUX_DEFAULT=".*"|GRUB_CMDLINE_LINUX_DEFAULT="quiet splash video=HDMI-A-1:1920x1080@60 drm.edid_firmware=HDMI-A-1:edid/samsung.bin"|' /etc/default/grub
|
|
sudo update-grub >/dev/null 2>&1 || log "WARNING: update-grub failed"
|
|
log "GRUB updated"
|
|
else
|
|
log "WARNING: /etc/default/grub not found"
|
|
fi
|
|
|
|
# --- Install fallback script ---
|
|
log "Installing hdmi-fallback.sh to ~/.local/bin/"
|
|
mkdir -p "$HOME/.local/bin"
|
|
cat > "$BIN_DST" <<'SCRIPT'
|
|
#!/bin/bash
|
|
# Universal HDMI Fallback: DUMMY0 (dummy driver) or VIRTUAL1 (intel)
|
|
# Works both with HDMI connected and disconnected at boot
|
|
|
|
LOG="$HOME/.local/logs/drm-hotplug.log"
|
|
mkdir -p "$HOME/.local/logs"
|
|
export DISPLAY=:0
|
|
|
|
log() {
|
|
echo "$(date '+%Y-%m-%d %H:%M:%S') $1" | tee -a "$LOG" >/dev/null
|
|
}
|
|
|
|
# Find available primary output (DUMMY0 or VIRTUAL1)
|
|
find_primary_output() {
|
|
if xrandr 2>/dev/null | grep -q "^DUMMY0"; then
|
|
echo "DUMMY0"
|
|
elif xrandr 2>/dev/null | grep -q "^VIRTUAL1"; then
|
|
echo "VIRTUAL1"
|
|
else
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
# Find HDMI output name (HDMI-1, HDMI1, etc)
|
|
find_hdmi_output() {
|
|
xrandr 2>/dev/null | grep -E "^HDMI-[0-9] connected" | awk '{print $1}' | head -1
|
|
}
|
|
|
|
# Set up mode for virtual output
|
|
setup_mode() {
|
|
local OUTPUT="$1"
|
|
local MODE_NAME="1920x1080"
|
|
|
|
if [ "$OUTPUT" = "VIRTUAL1" ]; then
|
|
local MODELINE="1920x1080_60.00"
|
|
if ! xrandr 2>/dev/null | grep -q "$MODELINE"; then
|
|
xrandr --newmode "$MODELINE" 173.00 1920 2048 2248 2576 1080 1083 1088 1120 2>/dev/null || true
|
|
fi
|
|
xrandr --addmode VIRTUAL1 "$MODELINE" 2>/dev/null || true
|
|
MODE_NAME="$MODELINE"
|
|
fi
|
|
echo "$MODE_NAME"
|
|
}
|
|
|
|
log "Start monitor (user=$USER, display=$DISPLAY)"
|
|
|
|
CONNECTOR=""
|
|
for p in /sys/class/drm/card1-HDMI-A-1 /sys/class/drm/card0-HDMI-A-1; do
|
|
[ -e "$p/status" ] && { CONNECTOR="$p"; break; }
|
|
done
|
|
[ -z "$CONNECTOR" ] && CONNECTOR=$(find /sys/class/drm -maxdepth 1 -name "*HDMI-A-1" -type d | head -1)
|
|
|
|
if [ -z "$CONNECTOR" ] || [ ! -e "$CONNECTOR/status" ]; then
|
|
log "WARNING: No HDMI-A-1 connector found, running headless only"
|
|
fi
|
|
|
|
# Initial state
|
|
LAST_STATE=$(cat "$CONNECTOR/status" 2>/dev/null || echo unknown)
|
|
log "Initial HDMI: $LAST_STATE"
|
|
|
|
# Detect outputs
|
|
PRIMARY=$(find_primary_output)
|
|
HDMI=$(find_hdmi_output)
|
|
|
|
if [ -z "$PRIMARY" ]; then
|
|
log "ERROR: No virtual output found (DUMMY0 or VIRTUAL1)"
|
|
exit 1
|
|
fi
|
|
|
|
log "Primary: $PRIMARY, HDMI: ${HDMI:-none}"
|
|
|
|
MODE=$(setup_mode "$PRIMARY")
|
|
|
|
# Initial setup
|
|
if [ "$LAST_STATE" = "connected" ] && [ -n "$HDMI" ]; then
|
|
log "HDMI connected, setting clone: $PRIMARY primary + $HDMI same-as"
|
|
xrandr --output "$PRIMARY" --mode "$MODE" --primary 2>/dev/null || true
|
|
xrandr --output "$HDMI" --auto --same-as "$PRIMARY" 2>/dev/null || true
|
|
else
|
|
log "HDMI disconnected or not found, keeping $PRIMARY primary"
|
|
xrandr --output "$PRIMARY" --mode "$MODE" --primary 2>/dev/null || true
|
|
[ -n "$HDMI" ] && xrandr --output "$HDMI" --off 2>/dev/null || true
|
|
fi
|
|
|
|
log "Setup complete. Monitors:"
|
|
xrandr --listmonitors 2>/dev/null | while read -r line; do log " $line"; done
|
|
|
|
# Main loop
|
|
while true; do
|
|
CURRENT=$(cat "$CONNECTOR/status" 2>/dev/null || echo unknown)
|
|
|
|
if [ "$CURRENT" != "$LAST_STATE" ]; then
|
|
log "HDMI changed: $LAST_STATE -> $CURRENT"
|
|
|
|
# Re-detect
|
|
PRIMARY=$(find_primary_output)
|
|
HDMI=$(find_hdmi_output)
|
|
MODE=$(setup_mode "$PRIMARY")
|
|
|
|
if [ -z "$PRIMARY" ]; then
|
|
log "ERROR: No virtual output detected after HDMI change"
|
|
sleep 5
|
|
continue
|
|
fi
|
|
|
|
# Always make PRIMARY primary
|
|
xrandr --output "$PRIMARY" --mode "$MODE" --primary 2>/dev/null || true
|
|
|
|
if [ "$CURRENT" = "connected" ] && [ -n "$HDMI" ]; then
|
|
log "HDMI connected, cloning $HDMI to $PRIMARY"
|
|
xrandr --output "$HDMI" --auto --same-as "$PRIMARY" 2>/dev/null || true
|
|
else
|
|
log "HDMI disconnected, keeping $PRIMARY primary"
|
|
[ -n "$HDMI" ] && xrandr --output "$HDMI" --off 2>/dev/null || true
|
|
fi
|
|
|
|
LAST_STATE="$CURRENT"
|
|
fi
|
|
|
|
sleep 2
|
|
done
|
|
SCRIPT
|
|
|
|
chmod +x "$BIN_DST"
|
|
log "Script installed"
|
|
|
|
# --- Install systemd unit ---
|
|
log "Installing systemd user unit"
|
|
mkdir -p "$HOME/.config/systemd/user"
|
|
cat > "$SYSTEMD_DST" <<'UNIT'
|
|
[Unit]
|
|
Description=HDMI to Virtual Fallback Monitor
|
|
After=graphical-session.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=%h/.local/bin/hdmi-fallback.sh
|
|
Restart=always
|
|
RestartSec=5
|
|
Environment="DISPLAY=:0"
|
|
|
|
[Install]
|
|
WantedBy=graphical-session.target
|
|
UNIT
|
|
|
|
systemctl --user daemon-reload
|
|
systemctl --user enable --now hdmi-fallback.service 2>/dev/null || true
|
|
log "Systemd unit enabled"
|
|
|
|
# --- Summary ---
|
|
echo ""
|
|
echo "============================================"
|
|
echo "RDtop installation complete!"
|
|
echo "============================================"
|
|
echo ""
|
|
echo "Next steps:"
|
|
echo "1. REBOOT now for changes to take effect:"
|
|
echo " sudo reboot"
|
|
echo ""
|
|
echo "2. After reboot without HDMI, check:"
|
|
echo " xrandr --listmonitors"
|
|
echo ""
|
|
echo "3. Service status:"
|
|
echo " systemctl --user status hdmi-fallback.service"
|
|
echo ""
|
|
echo "4. View logs:"
|
|
echo " cat ~/.local/logs/drm-hotplug.log"
|
|
echo ""
|
|
log "Install complete"
|