Dynamic multi-headed Ubuntu laptop with NVIDIA

I've run Ubuntu desktop on a Thinkpad t61 for a number of years and moved on to a w520 maybe a year ago. I wanted to be able to support multiple monitors and change them out on the fly without a reboot. I also wanted a solution that would work with xmonad. While reading about Xorg and Nvidia I found the number of dead ends to be extremely frustrating. There is a ton of advice. Much of it is dated. Much of it is just plain wrong. My advice as of the date above is to use the "nvidia" driver with TwinView. This works for me today.

I'd highly suggest reading the Nvidia Manual before searching any further on the web for answers.

Figuring out what you have

$ dpkg -l | grep nvidia
ii  nvidia-common                                   0.2.30.1                                   Find obsolete NVIDIA drivers
ii  nvidia-current                                  270.41.06-0ubuntu1.1                       NVIDIA binary Xorg driver, kernel module and VDPAU library
ii  nvidia-settings                                 270.29-0ubuntu1                            Tool of configuring the NVIDIA graphics driver

$ sudo lshw -c video
  *-display               
        ...
       configuration: driver=nvidia latency=0
        ...

$ jockey-text -l
xorg:nvidia_current - NVIDIA accelerated graphics driver (Proprietary, Enabled, Not in use)

If you are not seeing similar results, you are probably running the nv or nouveau driver. See system > administration > additional drivers.

Behold the elusive dynamic xorg.conf!

You should use nvidia-settings to generate an xorg.conf that will work as a correct starting point. Ensure that you write it to disk. Have every monitor you plan to use plugged in before you generate it.

Then look below at the screen/metamodes line. It says I'm either going to have the default monitor to the left with a secondary monitor starting 1920 pixels to the right, or I'm going to have the default monitor and nothing else. Shuffling this around correctly should yield predictable results. I then use a script (see below) to alternate between them.

Option "metamodes" "DFP-0: nvidia-auto-select +0+0, DFP-1: nvidia-auto-select +1920+0; DFP-0: nvidia-auto-select +0+0, DFP-1: null"

$ sudo vi /etc/X11/xorg.conf

Section "Device"
    Identifier  "Default Device"
    Option  "NoLogo"    "True"
EndSection

# nvidia-settings: X configuration file generated by nvidia-settings
# nvidia-settings:  version 270.29  (buildd@allspice)  Sat Feb 26 14:42:07 UTC 2011

Section "ServerLayout"
    Identifier     "Layout0"
    Screen      0  "Screen0" 0 0
    InputDevice    "Keyboard0" "CoreKeyboard"
    InputDevice    "Mouse0" "CorePointer"
    Option         "Xinerama" "0"
EndSection

Section "Files"
EndSection

Section "InputDevice"
    # generated from default
    Identifier     "Mouse0"
    Driver         "mouse"
    Option         "Protocol" "auto"
    Option         "Device" "/dev/psaux"
    Option         "Emulate3Buttons" "no"
    Option         "ZAxisMapping" "4 5"
EndSection

Section "InputDevice"
    # generated from default
    Identifier     "Keyboard0"
    Driver         "kbd"
EndSection

Section "Monitor"
    # HorizSync source: edid, VertRefresh source: edid
    Identifier     "Monitor0"
    VendorName     "Unknown"
    ModelName      "LEN"
    HorizSync       56.5 - 67.8
    VertRefresh     40.0 - 60.0
    Option         "DPMS"
EndSection

Section "Device"
    Identifier     "Device0"
    Driver         "nvidia"
    VendorName     "NVIDIA Corporation"
    BoardName      "Quadro 1000M"
    Option         "RegistryDwords"    "EnableBrightnessControl=1"
EndSection

Section "Screen"
    Identifier     "Screen0"
    Device         "Device0"
    Monitor        "Monitor0"
    DefaultDepth    24
    Option         "TwinView" "1"
    Option         "metamodes" "DFP-0: nvidia-auto-select +0+0, DFP-1: nvidia-auto-select +1920+0; DFP-0: nvidia-auto-select +0+0, DFP-1: null"
    SubSection     "Display"
        Depth       24
    EndSubSection
EndSection

Making it dynamic

Switching from separate monitors to the default only is not handled in this setup; although, it could be done. Instead, just use the display and kbd scripts to make the switch. In my setup I'm using the apple keyboad with the separate monitor. The super key needs to be swapped as well for this setup, which is what the kbd script does. If you don't use an apple keyboard, remove that part.

display.rb

 1 def current_size
 2   data = `xrandr -q 2> /dev/null`
 3   data.match(/current (\d{1,4} x \d{1,4}),/)[1]
 4 end
 5 
 6 def multihead?
 7   current_size == '3840 x 1080'
 8 end
 9 
10 def standalone?
11   current_size == '1920 x 1080'
12 end
13 
14 if multihead?
15   `xrandr -s 1`
16   `kbd pc`
17 else
18   `xrandr -s 0`
19   `kbd apple`
20 end

kbd.rb

UPDATE 6/22/12: This will not work under unity 2d. See Unity 2D Keyboard Configuration with setxkbmap

 1 KEY = "/desktop/gnome/peripherals/keyboard/kbd/options"
 2 APPLE = "[grp\tgrp:shift_caps_toggle,altwin\taltwin:swap_lalt_lwin]" 
 3 PC = "[grp\tgrp:shift_caps_toggle]" 
 4 
 5 val = case ARGV[0]
 6 when 'apple'
 7   APPLE
 8 when 'pc' 
 9   PC
10 else
11   current = `gconftool-2 --get #{KEY}`
12   current =~ /lalt_lwin/ ? PC : APPLE
13 end
14 
15 `gconftool-2 --type=list --list-type=string --set #{KEY} "#{val}"`

Bonus info for synaptics mouse

sudo vi /usr/share/X11/xorg.conf.d/20-thinkpad.conf

Section "InputClass"
        Identifier      "Trackpoint Wheel Emulation"
        MatchProduct    "TPPS/2 IBM TrackPoint|DualPoint Stick|Synaptics Inc. Composite TouchPad / TrackPoint|ThinkPad USB Keyboard with TrackPoint"
        MatchDevicePath "/dev/input/event*"
        Option          "EmulateWheel"          "true"
        Option          "EmulateWheelButton"    "2"
        Option          "Emulate3Buttons"       "false"
        Option          "XAxisMapping"          "6 7"
        Option          "YAxisMapping"          "4 5"
        Option          "ButtonMapping"         "1 1 3 4 5"
EndSection
comments powered by Disqus