A tool for automatically applying RandR configuration when external display is plugged in

Regarding a tool which can store monitor configuration profiles on a per-user and per-display basis, autorandr will do exactly that.

My laptop has an NVIDIA card, so I use the disper backend instead of xrandr. Autorandr will use disper as the backend to manage your monitors if you call it as autodisper. For the rest of this post though, I'll refer to it as autorandr for consistency.

You can save profiles with autorandr --save profile_name. Running autorandr by itself will then give you a list of profiles, and identify which one is detected as the current configuration.

For instance:

$ autorandr
laptop
syncmaster19 (detected)

You can tell it to automatically load the appropriate profile for the current configuration with autorandr --change. This command, paired with a udev rule to run it when it is hotplugged, would do what you requested.

As an added precaution I've appended --default laptop to that command, which will make it default to the laptop's display if there is no saved profile that matches the current configuration. So the full command I use to switch displays is:

autorandr --change --default laptop

Unfortunately my machine doesn't give any udev output when I hotplug my monitor. I'm using the NVIDIA proprietary drivers, so that isn't surprising. So I have bound it to the XF68Display key (Fn-F8) for now, which is almost as good.


I'm using this simple (homemade) script that keeps polling RandR and switches between LVDS1 and VGA1 when VGA gets connected/disconnected. (For HDMI outputs, in the following script file, change all the VGA1 to HDMI1)

It's a dirty solution, yet it's working just fine.

It's customized for my setup: you'll most likely need to change RandR output names (LVDS1 and VGA1) and unlike me you'll probably be fine with your RandR default mode for VGA.

#!/bin/bash

# setting up new mode for my VGA
xrandr --newmode "1920x1080" 148.5 1920 2008 2052 2200 1080 1089 1095 1125 +hsync +vsync
xrandr --addmode VGA1 1920x1080

# default monitor is LVDS1
MONITOR=LVDS1

# functions to switch from LVDS1 to VGA and vice versa
function ActivateVGA {
    echo "Switching to VGA1"
    xrandr --output VGA1 --mode 1920x1080 --dpi 160 --output LVDS1 --off
    MONITOR=VGA1
}
function DeactivateVGA {
    echo "Switching to LVDS1"
    xrandr --output VGA1 --off --output LVDS1 --auto
    MONITOR=LVDS1
}

# functions to check if VGA is connected and in use
function VGAActive {
    [ $MONITOR = "VGA1" ]
}
function VGAConnected {
    ! xrandr | grep "^VGA1" | grep disconnected
}

# actual script
while true
do
    if ! VGAActive && VGAConnected
    then
        ActivateVGA
    fi

    if VGAActive && ! VGAConnected
    then
        DeactivateVGA
    fi

    sleep 1s
done

Full Steps:

  1. Put above script (homemadeMonitor.sh) into you preferred directory

  2. Make the .sh file executable by typing the following command in the terminal

    chmod +x homemadeMonitor.sh

  3. Run the .sh file

    ./homemadeMonitor.sh


Responding to the "[a] way to tell that a monitor has been plugged in" part of the question:

The support still varies quite a bit, but with recent kernels there is some support for generating udev events when a display hotplug occurs. With kernel 2.6.38 and ATI X1400 hardware, I get an event the first time I connect a VGA display but no events on subsequent disconnects or reconnects of the display. Intel hardware may have better support. The NVIDIA proprietary driver does not currently support KMS; I haven't tried looking for hotplug events on NVIDIA hardware, but I'm doubtful it would work.

If you want to experiment with udev you could try the following steps:

  • update to the newest kernel
  • make sure that kernel mode setting (KMS) is enabled. If enabled, it should be reported in your kernel output. Mine says [drm] radeon kernel modesetting enabled and [drm] initializing kernel modesetting
  • run udevadm monitor --property and see if events are reported when you (dis-)connect displays

If you are getting udev events on display hotplug, you can trigger a script with a udev rule like:

ACTION=="change", SUBSYSTEM=="drm", HOTPLUG=="1", RUN+="/path/to/hotplug.sh"

Note: This will not work if you use an nVIDIA GPU with the proprietary binary driver, since it does not use KMS. You will not get any udev events.