Use nVidia to enable external screen without X restart
OK. This has been quite a big thing for me.
I often startup and use my laptop around the house. However, I have a replication port, and I like to dock my computer and then use the laptop's internal screen and an external screen sitting side by side. If I start up Ubuntu undocked, it is impossible to then dock my laptop and enable the external screen without mucking around in nvidia-settings and manually detecting and enabling the monitor and switching it on through the GUI.
But now I have worked out how to simplify this process using a bash script, and would be delighted if others benefited from my hard work late the other night!
This only works for laptops using the nvidia drivers... so all you Dell latitude owners might be interested.
Staying clear of the xorg.conf
My xorg.conf is pretty pristine. It allows the nvidia driver to do all the configuration. My Intrepid upgrade cleaned it up for me, but you could do the same by typing:
sudo cp /etc/X11/xorg.conf xorg.conf.backup
sudo dpkg-reconfigure -phigh xserver-xorg
sudo nvidia-xconfig
This basically backs up your xorg and then allows nvidia-xconfig to update a fresh version with the directives needed to use the nvidia driver etc.
Building nv-control-dpy
nvidia-settings is a cool GUI which allows you to control many aspects of your displays. In fact, you can save your settings and then request that they be executed at the start of every session with a simple bash command:
nvidia-settings --load-config-only
Unfortunately, this technique does not load any external screen enabling you've done. nVidia have listed this in their TODO section. Perhaps the next version of nvidia-settings will render my script obsolete.
Currently, you'll need to build an application available from nvidia to do the work for you. Redmoskito did all the hard work in working this out, so kudos to him. Follow his instructions at:
http://ubuntuforums.org/showthread.php?p=5809670
And stop once nv-control-dpy is built and placed in a convenient place.
Rather than use his PHP script, I wrote bash script which does the hard work. This is my first ever bash script, so apologies if it could be done a much easier way!
#!/bin/sh
# Set the display we are looking for here.
# I am interested in a CRT monitor being attached, but this could be TV-0 or something
DISPLAY_TARGET="CRT-0"
# Ensure that desired display is attached by probing the currently connected displays
# and seeing if GREP has failed or not
nv-control-dpy --probe-dpys | grep $DISPLAY_TARGET > /dev/null 2>&1
if [ $? -gt 0 ] ; then
echo 1>&2 'Error: Could not discover the display "'$DISPLAY_TARGET'"'
exit 1
fi
# Since display exists, we need to build the modepool for all displays, if this has not been done already
nv-control-dpy --build-modepool > /dev/null 2>&1
if [ $? -gt 0 ] ; then
echo 1>&2 'Error: Could not build modepools'
exit 1
fi
# See if device is currently enabled
# nv-control-dpy basically returns a list of the associated displays as bitwise values
# Then outputs a final device mask which indicates which of those displays are being used
# So if my CRT-0 has a value of 0x00000001 and internal display DFP-0 is 0x00010000
# then a device mask of 0x00010000 would indicate the CRT is not enabled, but 0x00010001
# means they're both enabled.
NVOUTPUT=`nv-control-dpy --get-associated-dpys`
DISPLAY_TARGET_BITMASK=`expr "$NVOUTPUT" : ".*$DISPLAY_TARGET (\(..........\)"`
DISPLAY_ALLOLD_BITMASK=`expr "$NVOUTPUT" : ".*device mask: \(..........\)"`
DISPLAY_ALLNEW_BITMASK=$(($DISPLAY_ALLOLD_BITMASK | $DISPLAY_TARGET_BITMASK))
if [ $DISPLAY_ALLNEW_BITMASK = $(($DISPLAY_ALLOLD_BITMASK)) ] ; then
echo 1>&2 'Error: The display is already enabled'
exit 1
fi
nv-control-dpy --set-associated-dpys $DISPLAY_ALLNEW_BITMASK > /dev/null 2>&1
if [ $? -gt 0 ] ; then
echo 1>&2 'Error: There was a problem enabling the display'
exit 1
fi
# I have my laptop display (DFP-0) on the left, and I want it to be the 'primary' display
# then CRT, then TV. This way, when I enable the screen, the gnome panel won't jump over to the CRT
# as a new primary monitor
nv-control-dpy --assign-twinview-xinerama-info-order 'DFP,CRT,TV' > /dev/null 2>&1
# The way we can enable the screen is to add the display as a metamode and get xrandr to switch to it
# Any display with a value of 'nvidia-auto-select' means it is part of the mode
# Any display set to NULL means it is not part of the mode
# This line needs to be modified for every user's particular needs,
# especially the coordinates.
NVOUTPUT=`nv-control-dpy --add-metamode "DFP: nvidia-auto-select +0+0, $DISPLAY_TARGET: nvidia-auto-select +1680+0"`
if [ $? -gt 0 ] ; then
echo 1>&2 'Error: Could not add metamode'
exit 1
fi
# The output from nv-control-dpy includes the refresh rate of the new mode.
# This acts as a kind of unique id for the entry
REFRESHID=`expr "$NVOUTPUT" : ".*$id=\([0-9]*\)"`
# Now we have the id, we just need to get the list of available modes from xrandr
# and extract the new resolution of all of the enabled displays which can be identified alongside the refresh rate
MODES=`xrandr`
RESOLUTION=`expr "$MODES" : ".* \([0-9]*x[0-9]*\)[ ]*$REFRESHID"`
# Now activate it!
xrandr -s "$RESOLUTION@$REFRESHID"
I don't understand the script!
Actually, have a play around with the nv-control-dpy command until you're happy you understand it. Then alter my script accordingly. A brilliant introduction is here:
http://www.stuvel.eu/archive/75/sele...on-commandline
Automating the script
I saved the script above as ~/.script/detect-external-monitor.sh after making it executable with chmod 755 <filename>
Now I have it loading up by adding it to my startup progs in sessions. However, you could call it from within, say /etc/X11/xinit/xinitrc so that when X starts, it automatically enables the screen when plugged in.
But, the most important thing I did was bind it to the WINDOWS+D key combination on my keyboard. Now if I dock, I just press this, and my screen turns on. Plenty of tutorials around showing you how to do this!
What next?
Well, I could learn to write a daemon that checks every second or so to see if my laptop has docked, or rig the script up some other way to respond to the dock action. If anyone out there knows how to do this, let me know... or I'll investigate myself.

