Ubuntu - Monitors Position Lost in Dual Display Setup



If you are using a dual monitor display under Ubuntu Trusty 14.04 LTS or Ubuntu Xenial 16.04 LTS, you may have noticed that both screen position can be set without any glitch thru the system parameters, but that this configuration is lost after every reboot.

In fact, if your screen positions are not the default proposed one (laptop screen at the left and second monitor at the right), it will be reset to the default one after every reboot. And, this occurs even if your monitor.xml configuration file is fully configured.

This article explains how to circumvent this Ubuntu misbehavior. It allows you to set your dual monitor positions and to make it survive after every reboot.

It has been tested under Ubuntu Gnome 14.04 LTS and Ubuntu 16.04 LTS but it should be applicable under other Ubuntu flavours.

1. Setup a Clean Configuration

Under modern Ubuntu system, multiple monitors configuration is saved in ~/.config/monitors.xml.

In some cases, this file can become corrupted or include multiple definitions.

So first step is to suppress this file and to recreate a clean one with your specific monitors configuration.

# rm ~/.config/monitors.xml

You can now configure your monitors setup thru the menu Parameters / Displays.

Here is an example of my monitors setup :


Once you have applied your monitors configuration, you should get a newly generated ~/.config/monitors.xml file.

After next reboot

If you reboot your computer, your monitor's resolution should be applied, but you may have lost the specific positions you've just setup.

If you check ~/.config/monitors.xml, it still contains the full configuration, including monitors size, position, refresh rate and rotation :

      <output name="LVDS">
      <output name="DFP1">
      <output name="CRT1">

But Ubuntu 14.04 or 16.04 is not applying it correctly during login.

Hopefully, we can force this predefined position thru xrandr command line tool.

# xrandr --output LVDS --pos 1920x0 --output CRT1 --pos 0x0

Your monitors respective positions should be back to what you've just configured thru the Displays interface.

2. Automatic Script to Force Monitors Position

We now have all the keys to write a script that will analyse monitors.xml predefined positions and apply them thru xrand command.

This script will be in charge of few steps :

  1. get the first configuration defined in the file
  2. list all monitors
  3. get their respective parameters (position, size, refresh rate and rotation)
  4. apply them thru randr

It uses a command line XML parser called xmllint which is provided by libxml2-utils package.

As this script will be used during login process where a delay is needed, it takes a delay in seconds as parameter.

#!/usr/bin/env bash
# -------------------------------------------------
#  Get monitors configuration from monitor.xml and apply it for current user session.
#  In case of multiple definitions in monitor.xml only first one is used.
#  See
#  for instructions
#  Parameters :
#    $1 : waiting time in sec. before forcing configuration (optional)
#  Revision history :
#    19/04/2014, V1.0 - Creation by N. Bernaerts
#    10/07/2014, V1.1 - Wait 5 seconds for X to fully initialize
#    01/09/2014, V1.2 - Correct NULL file bug (thanks to Ivan Harmady) and handle rotation
#    07/10/2014, V1.3 - Add monitors size and rate handling (idea from jescalante)
#    08/10/2014, V1.4 - Handle primary display parameter
#    08/12/2014, V1.5 - Waiting time in seconds becomes a parameter
#    06/05/2020, V1.6 - Handle scale parameter
# -------------------------------------------------

esc() { printf "%s\n" "$1" | sed -e "s/'/'\"'\"'/g" -e "1s/^/'/" -e "\$s/\$/'/" }

# monitor.xml path

# get number of declared monitors
NUM=$(xmllint --xpath 'count(//monitors/configuration['1']/logicalmonitor)' "${MONITOR_XML}")

# loop thru declared monitors to create the command line parameters
for (( i=1; i<=$NUM; i++)); do
  # get attributes of current monitor (name and x & y positions)
  NAME=$(xmllint --xpath 'string(//monitors/configuration['1']/logicalmonitor['$i']/monitor/monitorspec/connector/text())' "${MONITOR_XML}" 2>/dev/null)
  POS_X=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/x/text()' "${MONITOR_XML}" 2>/dev/null)
  POS_Y=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/y/text()' "${MONITOR_XML}" 2>/dev/null)
  SCALE=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/scale/rate/text()' "${MONITOR_XML}" 2>/dev/null)
#   ROTATE=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/rotation/text()' $MONITOR_XML 2>/dev/null)
  WIDTH=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/monitor/mode/width/text()' "${MONITOR_XML}" 2>/dev/null)
  HEIGHT=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/monitor/mode/height/text()' "${MONITOR_XML}" 2>/dev/null)
  RATE=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/monitor/mode/rate/text()' "${MONITOR_XML}" 2>/dev/null)
  PRIMARY=$(xmllint --xpath '//monitors/configuration['1']/logicalmonitor['$i']/primary/text()' "${MONITOR_XML}" 2>/dev/null)

  MODELINE=$(cvt $(echo "${RES}") | grep -e "Modeline [^(]" | sed -r 's/.*Modeline (.*)/\1/')
  MODERES=$(echo "${MODELINE}" | grep -o -P '(?<=").*(?=")')

  # if position is defined for current monitor, add its position and orientation to command line parameters
  [ -n "${POS_X}" ] && PARAM_ARR=("${PARAM_ARR[@]}" "--output" "${NAME}" "--pos" "${POS_X}x${POS_Y}" "--mode" "${MODERES}" "--rate" "${RATE}")
  [ -n "${SCALE}" ] && PARAM_ARR=("${PARAM_ARR[@]}" "--scale" "${SCALE}")

  # addmodes before so they can set
  eval "xrandr" "--newmode ${MODELINE[@]}"
  xrandr "--addmode" "${NAME}" "${MODERES}"
  # if monitor is defined as primary, adds it to command line parameters
  [ "${PRIMARY}" = "yes" ] && PARAM_ARR=("${PARAM_ARR[@]}" "--primary")

# if needed, wait for some seconds (for X to finish initialisation)
[ -n "$1" ] && sleep $1

# position all monitors
xrandr "${PARAM_ARR[@]}"

[Desktop Entry]
Name[en_US]=Update Monitors Position
Name=Update Monitors Position
Comment[en_US]=Force monitors position from monitor.xml
Comment=Force monitors position from monitor.xml

With the help of this script, it is now very simple to force your specific monitors positions : Just launch Update Monitor Position application.

Your monitors should be back in place.

3. Declare Script at Startup

Now that script is installed and tested, last step is to execute it at every login.

This can be done easily by adding one entry in Startup Applications Preferences.

As login process takes some time, it's advisable to wait for some time before updating monitor position.
That's why a 5 seconds parameter is given to the script.

Entry should be :

  • Name : Update Monitors Position
  • Command : update-monitor-position 5
  • Comment : Force monitors position 5 seconds after login


4. Complete Installation

You can download and install all the needed files from my GitHub repository.

# wget
# chmod +x
# ./

You can now setup your monitor configuration, save it and reboot your computer.

Your monitors pre-defined positions should be applied at every login from what you've configured in the Displays configuration.

5. In Case of Trouble

In case proper configuration is not applied, first thing to do is :

  1. to remove ~/.config/monitors.xml
  2. to reconfigure your display settings
  3. to login again

In fact, for some unknown reasons, the <configuration> section may be duplicated in ~/.config/monitors.xml.


Hope it helps.

Signature Technoblog

This article is published "as is", without any warranty that it will work for your specific need.
If you think this article needs some complement, or simply if you think it saved you lots of time & trouble,
just let me know at This email address is being protected from spambots. You need JavaScript enabled to view it.. Cheers !

icon linux icon debian icon apache icon mysql icon php icon piwik icon googleplus