Of Laptops, Docking Stations and Changing Resolution
I've been setting up a new Lenovo X201 laptop at work. (Yes, work -- I've somehow fallen into an actual job where I go in to an actual office at least some of the time. How novel!)At the office I have a Lenovo docking station, attached to a monitor and keyboard. The monitor, naturally, has a different resolution from the laptop's own monitor.
Under Gnome and compiz, when I plugged in the monitor, I could either let the monitor mirror the laptop display -- in which case X would refuse to work at greater than 1024x768, much smaller than the native resolution of either the laptop screen or the external monitor -- or I could call up the classic two-monitor configuration dialog, where I could configure the external monitor to be its correct size and sit alongside the computer's monitor. I had to do this every time I plugged in.
If I wanted to work on the big screen, then when I undocked, I had to drag all the windows on all desktops back to the built-in LCD first, or they'd be lost. Using just the external monitor and turning off the laptop screen didn't seem to be an allowed option.
That all lasted for about two days. Gnome and I just don't get along. Pretty soon gdm was mysteriously refusing to let me log in (probably didn't like my under-1000 user id), and after wasting half a day fighting it I gave up and reverted with relief to my familiar Openbox desktop.
But now I'm in the Openbox world and don't have that dialog anyway. What are my options?
xrandr monitor detection
Fortunately, I already knew about using xrandr to send to a projector; it was only a little more complicated using it for the monitor in the docking station. Running xrandr with no arguments prints all the displays it currently sees, so you can tell whether an external display or projector is connected and even what resolutions it supports.
I used that for a code snippet in my .xinitrc:
# Check whether the external monitor is connected: returns 0 on success xrandr | grep VGA | grep " connected " if [ $? -eq 0 ]; then xrandr --output VGA1 --mode 1600x900; xrandr --output LVDS1 --off else xrandr --output VGA1 --off xrandr --output LVDS1 --mode 1280x800 fi
That worked nicely. When I start X it checks for an external monitor, and if it finds one it turns off the laptop display (so it's off when the laptop is sitting closed in the docking station) and sets the screen size for the external monitor.
Making it automatic
All well and good. I worked happily all day in the docking station, suspended the laptop and un-docked it, brought it home, woke it up -- and of course the display was still off. Oops.
Okay, so it also needs the same check when resuming from suspend. That used to be in /etc/acpi/resume.d, but in Lucid they've moved it (because we definitely wouldn't want users to get complacent and think they know how to configure things!) and now it lives in /etc/pm/sleep.d. I created a new file, /etc/pm/sleep.d/20_enable_display which looks like this:
#!/bin/sh case "$1" in resume) # Check whether the external monitor is connected: # returns 0 on success xrandr | grep VGA | grep " connected " if [ $? -eq 0 ]; then xrandr --output VGA1 --mode 1600x900 xrandr --output LVDS1 --off else xrandr --output VGA1 --off xrandr --output LVDS1 --mode 1280x800 fi hsetroot -center `find -L $HOME/Backgrounds -name "*.*" | $HOME/bin/randomline` ;; suspend|hibernate) ;; *) ;; esac exit $?
Neat! Now, every time I wake from suspend, the laptop checks whether an external monitor is connected and sets the resolution accordingly. And it re-sets the background (using my random wallpaper method) so I don't get a tiled background on the big monitor.
Update: hsetroot -fill works better than -center given that I'm displaying background images on two different resolutions. Of course, if I wanted to get fancy I could make separate background sets, one for each monitor, and choose images from the appropriate set.
We're almost done. Two more possible adjustments.
Detecting undocking
First, while poking around in /etc/acpi I noticed a script named undock.sh. In theory, I can put the same code snippet in there, and then if I un-dock the laptop without suspending it first, it will immediately change resolution. I haven't actually tried that yet.
Projectors
Second, this business of turning off the built-in display if there's anything plugged into the VGA port is going to break if I use this laptop for presentations, since a projector will also show up as VGA1. So the code may need to be a little smarter. For example:
xrandr | grep VGA | grep " connected " | grep 16.0x
The theory here is that an external monitor will be able to do 1680 or
1600, so it will have a line like
VGA1 connected 1680x1050+0+0 (normal left inverted right x axis y axis) 434mm x 270mm
.
The 1680x matches the 16.0x pattern in grep.
A projector isn't likely to do more than 1280, so it won't match the
pattern '16.0x'. However, that isn't very robust; it will probably
fail for one of those fancy new 1920x1080 monitors.
You could extend it with
xrandr | grep VGA | grep " connected " | egrep '16.0x|19.0x'but that's getting even more hacky ... and it might be time to start writing some more intelligent code.
Which doubtless I'll do if I ever get a 1920x1080 monitor.
[ 23:11 Sep 13, 2010 More linux/laptop | permalink to this entry | ]