External monitors

When I first started using Linux over a decade ago, dual screen was a pain to set up. When I got my first laptop four years ago, setting up an external monitor was also painful. Then came xrandr and life was good. Now there are nifty little monitor switching GTK apps that allow you to drag screens around just like in Windows or MacOS.

But that’s a lot of fiddling around. For the longest time, my use case has always been either:
a) I am using only my laptop
b) I am using my laptop with my 1920×1080 external monitor connected via VGA (It’s an old laptop)

To accommodate these two use cases, I had connected my “Switch Display” (fn+F7 on my thinkpad) key to the following simple script:

  #!/bin/bash
  if ! xrandr | grep VGA1 | grep disconnected  >/dev/null ; then
      xrandr --output LVDS1 --mode 1024x768 --output VGA1 --mode 1920x1080 --above LVDS1
  else
      xrandr --auto
  fi

Succinctly, if the external monitor is connected, enable it as “above” my laptop, otherwise, just enable the laptop monitor. All I have to do is plug in or unplug my monitor, hit Fn+F7, and my display would automatically adjust itself.

For the record, I used xbindkeys to connect the button to the script with the following .xbindkeysrc:

 .xbindkeysrc                                                                                                                
  "/home/dusty/bin/check_external"
      XF86Display

This served me well until I bought myself a new television that only operates at 1360×768 on the VGA port. Further, when I’m connecting my laptop to the tv, the television is usually below the laptop monitor rather than above, as my monitor is.

So now, my check_external script looks thusly:

  #!/usr/bin/python
  import subprocess
 
  positions = {
      "1920x1080": "--above", # Monitor
      "1360x768": "--below" # TV
  }
 
  output = subprocess.check_output("xrandr", shell=True).decode("utf-8")
 
  external_connected=resolution=False
  for line in output.split("\n"):
      if external_connected:
          if "+" in line: # + represents the default resolution for that monitor
              resolution = line.split()[0] # + the resolution is in the first column
              break
      if "VGA1 connected" in line:
          external_connected=True
 
  if external_connected:
      subprocess.call(
              "xrandr --output LVDS1 --mode 1024x768 --output VGA1 --mode {resolution} {position} LVDS1".format(
                  resolution=resolution, position=positions.get(resolution, "--above")), shell=True)
  else:
      subprocess.call("xrandr --auto", shell=True)

This is Python 3 code, and works delightfully on my Arch Linux running awesome setup. I still have to do custom xrandr commands if I ever connect to someone else’s projector or monitor (this happens so rarely that I don’t think I’ve done it since Archcon last year), but normally I can get away with a quick “xrandr –auto” in those cases, which usually just clones the display. There are dozens of ways to set up monitors, but this works great for me, and I can normally have my display up and running the way I want it with a couple keystrokes.

6 Comments

  1. PiX says:

    You should check disper: http://willem.engen.nl/projects/disper/ and auto-disper.

    auto-disper is a script that adds profile management to disper, including auto-detection. So you can have a bunch of setups that are chooser according to the names of the monitors.

  2. roentgen says:

    In KDE one gets a dialog to configure the external device. Haven’t seen easier than that.

    • dusty says:

      Why would I want to go to the trouble of opening a dialog, performing several drag and click sequences inside that dialog, and close it, when I can much more easily press a single key combination and be done with it?

      • Berseker says:

        well a normal OS simply could let the user associate a key combination to an action via the same GUI.. but sadly, in 2011 for doing so the user often is asked to learn “alien” language to do the easiest things ;)

  3. Peter says:

    This is fantastic! Thanks for sharing, I’m going to try this out on my new thinkpad

  4. Aaron Griffin says:

    The problem that I am still unable to solve is the “Virtual Size” part. You need to manually specify a virtual size large enough to cover both screens in order to use xrandr successfully. This cannot be changed at runtime, and as far as I know, cannot be detected outside of X.