Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

is there a tool which enables one to:

  • remember current RandR configuration (position, orientation, resolution etc) on per-monitor basis,
  • automatically apply last known good configuration as soon as the display is plugged in, with no need to muck around with applets or xrandr(1)?

The configurations would have to be applied on a per-user, per-display basis.

If there is no such tool in the wild, I'd like to throw together one myself, but as far as I can see, there's no way to tell that a monitor has been plugged in. Do I have to poll with xrandr -q once in a while to figure out that an output was connected or disconnected, or is there a more efficient way to do it? Can udev be tuned to do just that?

share|improve this question
    
Are you sure there is no way to tell that a monitor has been plugged in with your card. Try running udevadm monitor --property from the terminal and plugging the monitor in. With my card, I see an event when it is plugged in. You may be able to use a +RUN rule in udev and some bash scripting to get what you want. However, I'm not sure how you would be able to implement this on a per user basis using udev. –  Steven D Dec 3 '10 at 1:58
    
@Steven: Your comment should be an answer. It's not a complete answer, but it does make significant progress. If udev does see a hardware event, it should notify hal which sends a dbus event which can be seen by user code. –  Gilles Dec 3 '10 at 19:39

9 Answers 9

up vote 9 down vote accepted
+50

I'm using this simple (homemade) script that keeps polling RandR and switches between LVDS1 and VGA1 when VGA gets connected/disconnected.

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
share|improve this answer
    
Good script! Thanks, I needed something like this. I just copied it and set it up to run automatically. Thanks! –  Linuxios Jan 31 '12 at 23:20

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.

share|improve this answer

Regarding a tool which can store monitor configuration profiles on a per-user and per-display basis, autorandr will do exactly that. https://github.com/wertarbyte/autorandr.

My laptop has an NVIDIA card, so I use the disper backend instead of xrandr: http://willem.engen.nl/projects/disper/. 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.

share|improve this answer
    
autorandr was a waste of time, bad documented, random monitor blinks, no install/uninstall instructions. Could solve it using udev –  Leo Gallucci Jan 26 at 15:38

I used the udev rule suggested above along with a shell script that looks like

#!/bin/sh                                                               

dmode="$(cat /sys/class/drm/card0-VGA-1/status)"                        
export DISPLAY=:0                                                       
export XAUTHORITY=/home/yourusername/.Xauthority                              

if [ "${dmode}" = disconnected ]; then                                  
     /usr/bin/xrandr --auto                                              
elif [ "${dmode}" = connected ];then                                    
     /usr/bin/xrandr --output VGA1 --auto --right-of LVDS1               
else /usr/bin/xrandr --auto                                             

fi

The Xauthority part is essential as well as the export DISPLAY, you can use echo $DISPLAY to see which number it's equal to. Use xrandr -q to see the external monitors you have. The last else statement is just to make sure that you're never stuck without a display.

share|improve this answer

I am not aware of such a tool and I guess that not a lot of hardware support the generation of such events (an Intel related discussion).

And polling would not be a very elegant solution - would waste CPU cycles and energy.

share|improve this answer
    
Polling once in two seconds or so to be a big waste? Usually, what you need is not an instantaneous reaction, 2-3 seconds delay is perfectly ok. By the way, ATAPI CD-ROM drivers do just that in all OSes. –  Yaroslav Fedevych Dec 2 '10 at 23:05
3  
No need to poll. Just use a udev rule like this one: DEVPATH=="/devices/pci0000:00/0000:00:02.0/drm/card0", ACTION=="change", RUN="/usr/local/sbin/triggerscreen" –  Paul de Vrieze Nov 7 '13 at 10:22

A small program that waits for the X server to notify it about changed monitor configuration, and then executes a given command (e.g. the autorandr mentioned in another answer) is available at: https://bitbucket.org/portix/srandrd/overview

This seems to be a cleaner solution that using udev (where you have to worry about finding the right X server etc.)

share|improve this answer

When using peoro's solution, I got some extra output from xrandr, so I used the -c option for grep which counts the number of matches. I adapted it for HDMI and added audio switch as well:

#!/bin/bash
# adapted from http://unix.stackexchange.com/questions/4489/

# default monitor is LVDS1
MONITOR=LVDS1

# functions to switch from LVDS1 to HDMI1
function ActivateHDMI {
    xrandr --output HDMI1 --mode 1920x1080 --dpi 160 --output LVDS1 --off
    pactl set-card-profile 0 output:hdmi-stereo-extra1
    MONITOR=HDMI1
}
function DeactivateHDMI {
    xrandr --output HDMI1 --off --output LVDS1 --auto
    pactl set-card-profile 0 output:analog-stereo
    MONITOR=LVDS1
}

# functions to check if HDMI is connected and in use
function HDMIActive {
    [ $MONITOR = "HDMI1" ]
}
function HDMIConnected {
    [[ `xrandr | grep "^HDMI1" | grep -c disconnected` -eq 0 ]]
}

# actual script
while true
do
    if ! HDMIActive && HDMIConnected
    then
        ActivateHDMI
    fi

    if HDMIActive && ! HDMIConnected
    then
        DeactivateHDMI
    fi

    sleep 1s
done
share|improve this answer

I guess people looking at this question are not those that want to use GNOME, and those that use GNOME wouldn’t have to look at this question, but in the interest of completeness:

GNOME has this functionality built-in. If you change the setup via gnome-control-center, gnome-settings-daemon remembers it (in .config/monitors.xml) and automatically applies it when a monitor is plugged in or out.

share|improve this answer

If you must have it automatically detect the display when it is plugged in, it seems that the cleanest solution is to add a UDEV rule to run a script containing your xrandr commands. Here is an example from one user's solution1:

Monitor (output) UDEV events with udevadm
This step will be most important for each user. Run udevadm monitor --environment --udev. Then connect your HDMI cable.

UDEV rule
Based on the output from the above command, the user created this UDEV rule at /etc/udev/rules.d/95-monitor-hotplug.rules.

KERNEL=="card0", SUBSYSTEM=="drm", ENV{DISPLAY}=":0", ENV{XAUTHORITY}="/home/dan/.Xauthority", RUN+="/usr/local/bin/hotplug_monitor.sh"

Note the environment variables used so xrandr will be run under the user profile.

xrandr script hotplug_monitor.sh

You may want to adjust the xrandr options to suit your needs.

#! /usr/bin/bash

export DISPLAY=:0
export XAUTHORITY=/home/dan/.Xauthority

function connect(){
    xrandr --output HDMI1 --right-of LVDS1 --preferred --primary --output LVDS1 --preferred 
}

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

xrandr | grep "HDMI1 connected" &> /dev/null && connect || disconnect
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.