Like many other users, I find it convenient to connect an external monitor to my laptop sometimes. As I often do this, I expect this functionality to work flawlessly but, unfortunately, I experienced some problems when using LightDM on Arch Linux . By default, LightDM tries to mirror data on multiple displays, and it does not work well when you have monitors with different resolutions. In this post, I want to share my solution to this problem. I expect that this solution might be useful not only for laptop users but for the workstation users with multi-monitor setups as well. Moreover, if LightDM's user interface sometimes stops responding to your actions, this post might be useful for you.

In general, on a laptop with an external monitor, I expect the login screen to appear on it and have the laptop screen disabled in that case. If there are multiple external monitors connected to the system, I want only one of them used for a login screen.

Fortunately, these actions can be programmed using a UNIX shell script build around the functionality of the xrandr utility.

When used without any parameters it prints the list of monitor outputs alongside the information about the connected monitors:

artem@artbox:~$ xrandr 
Screen 0: minimum 8 x 8, current 1366 x 768, maximum 32767 x 32767
LVDS1 connected 1366x768+0+0 (normal left inverted right x axis y axis) 340mm x 190mm
   1366x768      60.03*+
   1280x720      59.74  
   1024x768      60.00  
   1024x576      60.00    59.90    59.82  
   960x540       60.00    59.63    59.82  
   800x600       60.32    56.25  
   864x486       60.00    59.92    59.57  
   640x480       59.94  
   720x405       59.51    60.00    58.99  
   680x384       60.00  
   640x360       59.84    59.32    60.00  
DP1 disconnected (normal left inverted right x axis y axis)
HDMI1 disconnected (normal left inverted right x axis y axis)
VGA1 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)

We could filter out the information about the available outputs using the UNIX tools:

artem@artbox:~$ xrandr | grep connected | cut -d ' ' -f 1-2
LVDS1 connected
DP1 disconnected
HDMI1 disconnected
VGA1 disconnected
VIRTUAL1 disconnected

Keeping in mind that an internal laptop screen is usually connected using the LVDS interface, we could use the information obtained from the xrandr tool to achieve what is required.

Let's outline the logic of the script using pseudo-code:

var primary_out = nil
var to_disable = nil

foreach monitor_out in list_monitor_outputs() do
    if is_connected(monitor_out) then
        if is_connected_via_LVDS(monitor_out) then
            to_disable = monitor_out
        else if primary_out == nil then
            primary_out = monitor_out
        else
            disable_monitor_output(monitor_out)
        endif
    endif
endfor

if primary_out != nil and to_disable != nil then
    set_as_primary_monitor_output(primary_out)
    disable_monitor_output(to_disable)
else if primary_out != nil then
    set_as_primary_monitor_output(primary_out)
endif

After translating the pseudo-code above into a shell script, I got the following code:

#!/bin/sh

# the script will not work if xrandr is not available
if [ -z "$(which xrandr)" ]; then
    exit 1
fi

DISABLE_SUBSTRING="LVDS"

TO_DISABLE=""
PRIMARY_OUT=""

old_IFS="${IFS}"
IFS=$'\n'
for out in `xrandr | grep connected | cut -d ' ' -f 1-2`; do
    name=`echo $out | cut -d ' ' -f 1`
    state=`echo $out | cut -d ' ' -f 2`
    if [ "$state" = "connected" ]; then
        case "$name" in
            # disable a monitor connected via LVDS
            ${DISABLE_SUBSTRING}*)
                if [ -z "$TO_DISABLE" ]; then
                    TO_DISABLE="$name"
                fi
                ;;
            *)
                # set the 'first' external monitor as the
                # primary one, disable the other external monitors
                if [ -z "$PRIMARY_OUT" ]; then
                    PRIMARY_OUT="$name"
                else
                    xrandr --output "$name" --off
                fi
                ;;
        esac
    fi
done
IFS="${old_IFS}"

# If there is an internal screen, as well as at least one external monitor, then
# disable the internal monitor and use the external monitor as the primary one.
# 
# Otherwise, if there are any external monitors, use the 'first' detected one
# as the primary monitor.
if [ -n "$TO_DISABLE" ] && [ -n "$PRIMARY_OUT" ]; then
    xrandr --output "$PRIMARY_OUT" --primary --auto --output "$TO_DISABLE" --off
elif [ -n "$PRIMARY_OUT" ]; then
    xrandr --output "$PRIMARY_OUT" --primary --auto
fi

exit 0

To use the script, one should save it into an executable file and alter the LightDM's settings to use it to configure the displays.

In order to accomplish this one should change the display-setup-script in the [Seat:*] section of the LightDM configuration file (/etc/lightdm/lightdm.conf):

[Seat:*]
...
display-setup-script=/path/to/the-script
...

To apply the new settings, please restart the LightDM daemon. The next LightDM session should use the script to configure monitors.