Switching the display quickly between a laptop monitor and an external monitor or projector in Linux

laptop_with_external_monitor_and_keyboardI connect my laptop to an external keyboard and an external monitor or projector in various offices and at home, and each of the monitors has a different resolution. Fn-F3 on my laptop keyboard allows me to toggle between monitors, but I want more control (including the ability to specify the resolution of the external display). Now, I find the GPU manufacturer’s application and the Desktop Environment’s GUI for switching monitors and changing screen resolution rather cumbersome, so I wanted an icon on the Desktop that I could double-click to switch monitors without having to enter the root user’s password and fiddle around too much. So I decided to create some simple Bash scripts and associated Desktop Config files with nice-looking icons on the desktop, which I can launch easily and quickly by double-clicking. Obviously the resolutions are limited to the range of resolutions supported by the GPU and external monitor.

The suite of Desktop Config files I created have self-explanatory names:

$ cd ~/Desktop
$ ls -1 Switch*
Switch_OFF_laptop_monitor_if_external_monitor_is_connected
Switch_OFF_laptop_monitor_if_external_monitor_is_connected_auto
Switch_ON_laptop_monitor_and_external_monitor
Switch_ON_laptop_monitor_and_switch_off_external_monitor
$ ls -1 Toggle*
Toggle_display

The difference between Switch_OFF_laptop_monitor_if_external_monitor_is_connected and Switch_OFF_laptop_monitor_if_external_monitor_is_connected_auto is that the former prompts for the resolution of the external monitor whereas the latter tries to find the resolution automatically. I have both because I have found that, for some external display devices (e.g. projectors), it is handy to have the ability to specify the resolution manually.

Switch off the laptop monitor if an external monitor is connected (find resolution automatically)

The Desktop Config file I double-click the most is ~/Desktop/Switch_OFF_laptop_monitor_if_external_monitor_is_connected_auto, and it contains the following text:

[Desktop Entry]
Comment[en_GB]=switch off laptop monitor if external monitor is connected auto
Comment=switch off laptop monitor if external monitor is connected auto
Exec=sh /home/fitzcarraldo/switch_off_laptop_monitor_if_external_monitor_is_connected_auto.sh
GenericName[en_GB]=Switch off laptop monitor if external monitor is connected auto
GenericName=Switch off laptop monitor if external monitor is connected auto
Icon=/home/fitzcarraldo/Pictures/Icons/display.png
MimeType=
Name[en_GB]=Switch_OFF_laptop_monitor_if_external_monitor_is_connected_auto
Name=Switch_OFF_laptop_monitor_if_external_monitor_is_connected_auto
Path=
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=

The Bash script it launches, ~/switch_off_laptop_monitor_if_external_monitor_is_connected_auto.sh, contains the following code:

#!/bin/bash
if xrandr -q | grep "CRT1 connected"; then
  xrandr --output LVDS --off
  xrandr --output CRT1 --off
  xrandr --output CRT1 --auto
else
  xrandr --output CRT1 --off
  xrandr --output LVDS --off
  xrandr --output LVDS --mode 1920x1080
# 1920x1080 is the native resolution of my laptop monitor
fi

Don’t forget to make them executable:

$ chmod +x /home/fitzcarraldo/Desktop/Switch_OFF_laptop_monitor_if_external_monitor_is_connected_auto
$ chmod +x /home/fitzcarraldo/switch_off_laptop_monitor_if_external_monitor_is_connected_auto.sh

If you’re wondering how I knew I had to specify ‘CRT1′ and ‘LVDS’ in the Bash script, I used the xrandr command to find out what names the GPU gives the monitors:

$ xrandr
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 1920 x 1920
LVDS connected (normal left inverted right x axis y axis)
1920x1080 60.0 +
1680x1050 60.0
1400x1050 60.0
1600x900 60.0
1280x1024 60.0
1440x900 60.0
1280x960 60.0
1280x768 60.0
1280x720 60.0
1024x768 60.0
1024x600 60.0
800x600 60.0
800x480 60.0
640x480 60.0
DFP1 disconnected (normal left inverted right x axis y axis)
CRT1 connected 1920x1080+0+0 (normal left inverted right x axis y axis) 476mm x 268mm
1920x1080 60.0*+
1280x1024 75.0 60.0
1280x960 60.0
1280x800 59.8
1152x864 75.0
1280x720 60.0
1024x768 75.0 70.1 60.0
800x600 72.2 75.0 60.3 56.2
640x480 75.0 72.8 67.0 59.9

Switch off the laptop monitor if an external monitor is connected (enter resolution)

The Desktop Config file I double-click is ~/Desktop/Switch_OFF_laptop_monitor_if_external_monitor_is_connected, and it contains the following text:

[Desktop Entry]
Comment[en_GB]=switch off laptop monitor if external monitor is connected
Comment=switch off laptop monitor if external monitor is connected
Exec=sh /home/fitzcarraldo/System_Administration/switch_off_laptop_monitor_if_external_monitor_is_connected.sh
GenericName[en_GB]=Switch off laptop monitor if external monitor is connected
GenericName=Switch off laptop monitor if external monitor is connected
Icon=/home/fitzcarraldo/Pictures/Icons/display.png
MimeType=
Name[en_GB]=Switch_OFF_laptop_monitor_if_external_monitor_is_connected
Name=Switch_OFF_laptop_monitor_if_external_monitor_is_connected
Path=
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=

The Bash script it launches, ~/switch_off_laptop_monitor_if_external_monitor_is_connected.sh, contains the following code:

#!/bin/bash
if xrandr -q | grep "CRT1 connected"; then
echo -n "Enter resolution width of external monitor (hint 1920 Doha, 1440 home): "
read EXTERNAL_WIDTH
echo -n "Enter resoluton height of external monitor (hint 1080 Doha, 900 home): "
read EXTERNAL_HEIGHT
  xrandr --output LVDS --off
  xrandr --output CRT1 --off
  xrandr --output CRT1 --mode $EXTERNAL_WIDTH"x"$EXTERNAL_HEIGHT
else
  xrandr --output CRT1 --off
  xrandr --output LVDS --off
  xrandr --output LVDS --mode 1920x1080
# 1920x1080 is the native resolution of my laptop monitor
fi

Don’t forget to make them executable:

$ chmod +x /home/fitzcarraldo/Desktop/Switch_OFF_laptop_monitor_if_external_monitor_is_connected
$ chmod +x /home/fitzcarraldo/switch_off_laptop_monitor_if_external_monitor_is_connected.sh

Switch on the laptop monitor and external monitor simultaneously

I don’t need to use this one much, only when I am using an external monitor but suddenly want to use the laptop’s built-in Webcam and so have to open fully the laptop’s lid. The file ~/Desktop/Switch_ON_laptop_monitor_and_external_monitor contains the following text:

[Desktop Entry]
Comment[en_GB]=switch_ON_laptop_monitor_and_external_monitor
Comment=switch_ON_laptop_monitor_and_external_monitor
Exec=sh /home/fitzcarraldo/switch_on_laptop_monitor_and_external_monitor.sh
GenericName[en_GB]=Switch_ON_laptop_monitor_and_external_monitor
GenericName=Switch_ON_laptop_monitor_and_external_monitor
Icon=/home/fitzcarraldo/Pictures/Icons/display.png
MimeType=
Name[en_GB]=Switch_ON_laptop_monitor_and_external_monitor
Name=Switch_ON_laptop_monitor_and_external_monitor
Path=
StartupNotify=true
Terminal=true
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=

and the Bash script it calls, ~/switch_on_laptop_monitor_and_external_monitor.sh, contains the following code:

#!/bin/bash
if xrandr -q | grep "CRT1 connected"; then
  echo "Note that the resolution specified must be the same for both monitors, and must be achievable on both monitors."
  echo -n "Enter resolution width of external monitor (hint 1920 office, 1440 home): "
  read EXTERNAL_WIDTH
  echo -n "Enter resoluton height of external monitor (hint 1080 office, 900 home): "
  read EXTERNAL_HEIGHT
  #xrandr --output LVDS --off
  xrandr --output LVDS --mode $EXTERNAL_WIDTH"x"$EXTERNAL_HEIGHT
  xrandr --output CRT1 --off
  xrandr --output CRT1 --mode $EXTERNAL_WIDTH"x"$EXTERNAL_HEIGHT
else
  xrandr --output CRT1 --off
  xrandr --output LVDS --off
  xrandr --output LVDS --mode 1920x1080
# 1920x1080 is the native resolution of my laptop monitor
fi

Don’t forget to make them executable:

$ chmod +x /home/fitzcarraldo/Desktop/Switch_ON_laptop_monitor_and_external_monitor
$ chmod +x /home/fitzcarraldo/switch_on_laptop_monitor_and_external_monitor.sh

Switch on the laptop monitor and switch off an external monitor

I don’t need to use this one much either, given that the display mode reverts to the laptop monitor after I reboot or shutdown/power-up the laptop. The file ~/Desktop/Switch_ON_laptop_monitor_and_external_monitor contains the following text:

[Desktop Entry]
Comment[en_GB]=switch on laptop monitor and switch off external monitor
Comment=switch on laptop monitor and switch off external monitor
Exec=sh /home/fitzcarraldo/switch_on_laptop_monitor_and_switch_off_external_monitor.sh
GenericName[en_GB]=Switch on laptop monitor and switch off external monitor
GenericName=Switch on laptop monitor and switch off external monitor
Icon=computer-laptop
MimeType=
Name[en_GB]=Switch_ON_laptop_monitor_and_switch_off_external_monitor
Name=Switch_ON_laptop_monitor_and_switch_off_external_monitor
Path=
StartupNotify=true
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=
X-KDE-SubstituteUID=false
X-KDE-Username=

The Bash script it launches, ~/switch_on_laptop_monitor_and_switch_off_external_monitor.sh, contains the following code:

#!/bin/bash
xrandr --output CRT1 --off
xrandr --output LVDS --auto
xrandr --output LVDS --mode 1920x1080
# 1920x1080 is the native resolution of my laptop monitor

I did also create a fifth Desktop Config file and associated Bash script, to toggle between the three modes (laptop monitor only > both monitors > external monitor only) rather than having to double-click three different icons. But, to be honest, it’s quicker and easier to have the three icons and double-click on the one I want rather than toggling through three display modes. Anyway, in case you are interested, the Desktop Config file ~/Desktop/Toggle_Display contains the follow text:

[Desktop Entry]
Comment[en_GB]=Toggle between laptop monitor, external monitor and both
Comment=Toggle between laptop monitor, external monitor and both
Exec=sh /home/fitzcarraldo/toggle_display.sh
GenericName[en_GB]=Toggle between laptop monitor, external monitor and both
GenericName=Toggle between laptop monitor, external monitor and both
Icon=video-display
MimeType=
Name[en_GB]=Toggle_display
Name=Toggle_display
Path=
StartupNotify=false
Terminal=false
TerminalOptions=
Type=Application
X-DBUS-ServiceName=
X-DBUS-StartupType=none
X-KDE-SubstituteUID=false
X-KDE-Username=

and the Bash script it launches, ~/switch_on_laptop_monitor_and_external_monitor.sh, contains the following code:

#!/bin/sh

# Using the xrandr command I found that the two video outputs from my laptop are named LVDS
# (the internal display) and CRT1 (the external display driven by the laptop's VGA socket).
# My external monitor at home has a resolution of 1440x900.

CONNECTED=`xrandr | grep -i ' connected' | grep LVDS | awk '{print $1}'`
CONNECTED="${CONNECTED} `xrandr | grep -i ' connected' | grep CRT | awk '{print $1}'`"

ENABLED=`awk '{print;exit}' ~/displays_enabled 2>/dev/null`

if [ "$CONNECTED" = "LVDS" -o "$CONNECTED" = "LVDS " -o "$CONNECTED" = " LVDS" ]; then
        # Only the internal display is connected, so don't do anything.
        echo "LVDS" > ~/displays_enabled
        ENABLED="LVDS"
        xrandr --output CRT1 --off
        xrandr --output LVDS --off
        xrandr --output LVDS --auto
        exit 0
elif [ "$CONNECTED" = "LVDS CRT1" ]; then
        # Both the internal and external displays are connected, so let's toggle
        # LVDS > LVDS,CRT1 > CRT1

        EXTERNALRES=`xrandr | awk 'c&&c--;/ connected/{c=1}' | awk '{print $1}' | grep 1440x900`
        if [ "$ENABLED" = "LVDS" ]; then
        # Switching on both displays.
                xrandr --output LVDS --off
                if [ "$EXTERNALRES" = "1440x900" ]; then
                         xrandr --output LVDS --mode 1440x900
                         xrandr --output CRT1 --off
                         xrandr --output CRT1 --auto
                else
                         xrandr --output LVDS --auto
                         xrandr --output CRT1 --off
                         xrandr --output CRT1 --auto
                fi
                ENABLED="LVDS CRT1"
                echo "LVDS CRT1" > ~/displays_enabled
        elif [ "$ENABLED" = "LVDS CRT1" ]; then
        # Switching on only external display.
                xrandr --output LVDS --off
                xrandr --output CRT1 --off
                xrandr --output CRT1 --auto
                ENABLED="CRT1"
                echo "CRT1" > ~/displays_enabled
        else
        # Switching on only internal display.
                xrandr --output CRT1 --off
                xrandr --output LVDS --off
                xrandr --output LVDS --auto
                ENABLED="LVDS"
                echo "LVDS" > ~/displays_enabled
        fi
fi

As I use KDE, I also used System Settings > Shortcuts and Gestures | Custom Shortcuts to create a keyboard shortcut which I named ‘Toggle display’, with Meta+P as Trigger and sh ~/toggle_display.sh as Action, but I tend to use the mouse rather than the keyboard in any case.

By the way, you might think some of the xrandr commands in the above Bash scripts are redundant. You would be correct in thinking that, but in practice I found that the displays did not switch if I didn’t include the additional commands shown (due to a bug in xrandr, perhaps?). Even then, when I switch to an external monitor, occasionally the screen resolution is slightly too big or too small, so I placed the icons at the top left of the desktop so that they are always accessible and I can just double-click on the same icon again if necessary. As I’m using KDE, I placed a Folder View Plasmoid for ~/Desktop/ at the top left of the desktop, as you can see in the screenshot.

Desktop showing icons for switching between monitors

Footnote

I’ve been using the above method of switching between displays for a couple of years now with an AMD ATI GPU. It works nicely and suits my needs perfectly. AMD has supported xrandr since 2008 (see Ref. 1), whereas NVIDIA only began to support xrandr last year (see Ref. 2) so I’m not sure how well these scripts would work with NVIDIA GPUs.

Ref. 1: AMD Catalyst 8.9 Gets WINE Fix, RandR 1.2 Support, September 18, 2008
Ref. 2: NVIDIA’s 302 Linux Driver Finally Has RandR 1.2/1.3, May 2, 2012

AMD Catalyst for Linux driver 12.2 fixes the XVideo bug that crashed X.Org Server 1.11.x

Just a brief ‘heads up’ for users of the closed-source FGLRX driver in Linux: In a previous blog post I mentioned a bug in the AMD Catalyst driver for Linux that caused X.Org Server 1.11.x to crash if you tried to play a video and your media player was configured to use XVideo (Xv) output. The bug also meant that people talking to you via Skype could not enable their Web cams or X.Org Server 1.11.x would crash on your machine, as Skype uses XVideo.

The problem occurred with versions 11.11, 11.12 and 12.1 of the FGLRX driver (the package x11-drivers/ati-drivers). Well, today I installed version 12.2 of the driver and am pleased to report that I can again set media players to use Xv output without causing the X.Org Server to crash (I’m currently using xorg-server-1.11.4). Likewise, other people who I am talking to via Skype can again enable their Web cams without causing the X.Org Server on my machine to crash.

Playing QuickTime videos in Firefox and Chromium + XVideo bug in AMD Catalyst 11.11 and 11.12 driver

Video problems seem to be perennial in Linux. The latest two to affect me were:

1) Firefox and Chromium could no longer play QuickTime videos on the Apple iTunes Movie Trailers Web site;

2) a bug in the latest two releases of the closed-source ATI FGLRX driver (AMD Catalyst 11.11 and 11.12 for Linux) that causes the X.Org Server to crash when I try to play .mov files using XVideo (Xv) output in media players such as SMPlayer, VLC, GNOME-MPlayer etc. (see e.g. Gentoo Bug Report No. 391193).

The reason I mention these two problems in the same breath is because I encountered the second whilst trying to fix the first. Anyway, below I explain what I did to resolve the two problems.

I first had a problem displaying QuickTime movie trailers in Firefox a couple of years ago. The solution then was to install the User Agent Switcher add-on for Firefox and create a user agent to fool the Apple Web site into thinking Firefox was using Apple’s QuickTime browser plugin instead of mplayerplug-in for Linux. But within a few days Firefox again could not play movie trailers on the Apple Web site. I had to uninstall mplayerplug-in and install the then latest version of its successor, gecko-mediaplayer (which uses gnome-mplayer). All was good again until…

Several months ago I found that, yet again, Firefox could not play movie trailers on the Apple Web site. I tried to view the trailers in Chromium instead but had the same problem. Both browsers just displayed a black box where the video should be playing. A little searching on the Web led me to the conclusion that the problem lay with the latest version of gecko-mediaplayer and gnome-mplayer that I was using at the time, so I gave up and decided to wait for new versions of gecko-mediaplayer and gnome-mplayer to be released.

Now, yesterday I wanted to watch a particular trailer on the Apple Web site, but, despite having installed the latest version of gecko-mediaplayer and gnome-mplayer anyway a few days ago, neither Firefox nor Chromium would display the trailer. A little searching on the Web suggested that I should try mozplugger instead of gecko-mediaplayer, so I uninstalled the latter, installed mozplugger and… the black box in the browser was replaced by a white box displaying the QuickTime ‘Q’ logo and a message that I needed to install QuickTime. Argghh!

So I uninstalled mozplugger and reinstalled gecko-mediaplayer and gnome-mplayer (the same versions that I installed recently, you inderstand). This time my attempts to watch trailers on the Apple Web site resulted in Firefox and Chromium displaying grey boxes and appearing to download the QuickTime videos, but then the X.Org Server crashed, restarted and the Desktop Environment’s login screen appeared. Furthermore, when I tried playing .mov videos in VLC, the same thing happened. Perhaps now you may understand why I mentioned above the bug with the FGLRX driver? It took me a few hours to realise there were two separate problems here.

The work-around to the second problem was to configure media players to use a different output driver rather than the XVideo (Xv) output driver. For example, in VLC this is done via Tools > Preferences > Video and selecting ‘GLX video output (XCB)’ as the Output under Video Settings. For SMPlayer this is done via Options > Preferences > General and selecting ‘gl (fast – ATI cards)’ as the Output driver under the Video tab.

And, most importantly, in order to enable gecko-mediaplayer to display those Apple QuickTime trailers in Firefox and Chromium I had to launch gnome-mplayer, select Edit > Preferences, click on the Player tab and select ‘gl’ as the Video Output under Adjust Output Settings. Actually, clicking on the MPlayer tab and entering “-vo gl” (without the quotes) in the ‘Extra Options to MPlayer:’ box achieves the same result. By the way, the tickboxes QuickTime Emulation, RealPlayer Emulation, Windows Media Player Emulation and DIVX Player Emulation were already ticked on the Plug-in tab.

So, there you have it. After several hours of searching and tinkering I can again watch movie trailers on the Apple Web site. Don’t you just love Linux?

For the sake of completeness, below I list the versions of the applicable packages currently installed on my main laptop:

firefox-9.0
chromium-16.0.912.63
gecko-mediaplayer-1.0.5_beta1_p20111207
gnome-mplayer-1.0.5_beta1
mplayer-1.0_rc4_p20111215
ffmpeg-0.9
libquicktime-1.2.3-r1
xorg-server-1.11.2-r2
ati-drivers-11.12

EDIT (January 2, 2012): I’ve just had a thought: When I used Skype for Linux a few days ago, my laptop rebooted spontaneously as soon as the person at the other end enabled her Webcam in Skype for Windows. This was reproducible consistently. However, I could enable my Webcam, she could see me in Skype on her PC, and I could also see video of me in Skype’s ‘myself preview’ on my laptop. Now, it could be a coincidence but I wonder if the reboot occurred because Skype for Linux uses XVideo? Skype’s Web page for Skype for Linux lists “Video card driver with Xv support” as one of the hardware requirements, which looks pretty conclusive to me. However, this leaves a couple of niggling questions: a) If Skype does indeed use XVideo, why didn’t the ‘myself preview’ video in the Skype for Linux window crash the X.Org Server?. b) If the FGLRX driver bug is the cause, why did my laptop reboot instead of just the X.Org Server crashing, restarting and displaying the Desktop Environment login screen? Furthermore, Skype’s Options > Video Devices > Test does work correctly on my laptop. So perhaps the rebooting problem is caused by a different bug. Suspicious, though. Unfortunately, as far as I know there is no way of switching Skype to use OpenGL instead of XVideo, so I cannot prove that XVideo is the cause of this particular problem I’m experiencing with Skype.

Follow

Get every new post delivered to your Inbox.

Join 25 other followers