Good question. A bit tricky to answer, but here is a try.
Basic Answer
There is actually a little reset possiblity included in X11. You can find it at /etc/X11/Xreset
. You could use the Xreset directory (Xreset.d
) to paste a script that runs automatically when a user logs out. The README file:
# Scripts in this directory are executed as root when a user log out from
# a display manager using /etc/X11/Xreset.
# The username of the user logging out is provided in the $USER environment
# variable.
You could thus a) add a reset script in /etc/X11/Xreset.d
and b) make a script attached to a launcher that sets your dual external displays up. As such, you would log off and everything would be back to normal, you would log on to your laptop, hit the launcher for the displays and enjoy life.
More information
You might want to look into sudo dpkg-reconfigure -phigh xserver-xorg
for resetting the xserver or (probably better look at the answer Mik suggested in the comments).
A SuSE guy wrote a nice article about X.
In a solved bugreport someone states:
admins can drop scripts in /etc/X11/Xreset.d/ to run after the user logs out.
This is the contents of the file:
You can find it on your own system.
#!/bin/sh
#
# /etc/X11/Xreset
#
# global Xreset file -- for use by display managers
# $Id: Xsession 967 2005-12-27 07:20:55Z dnusinow $
set -e
PROGNAME=Xreset
SYSSESSIONDIR=/etc/X11/Xreset.d
if [ ! -d "$SYSSESSIONDIR" ]; then
# Nothing to do, exiting
exit 0
fi
# use run-parts to source every file in the session directory; we source
# instead of executing so that the variables and functions defined above
# are available to the scripts, and so that they can pass variables to each
# other
SESSIONFILES=$(run-parts --list $SYSSESSIONDIR)
if [ -n "$SESSIONFILES" ]; then
set +e
for SESSIONFILE in $SESSIONFILES; do
. $SESSIONFILE
done
set -e
fi
exit 0
# vim:set ai et sts=2 sw=2 tw=80:
I did not find a "secret" setting to change the behaviour of the, as it seems, designed behaviour. It looks indeed as if the left screen is assumed to be the "base" screen.
It is however very well possible to create a workaround, with essentially the same result. You can create a script that, on the occasion of connecting a second screen, lists all windows. Subsequently, all windows that are moved initially to the left screen, are shifted back to the screen on the right, within a second or two. The size of all windows will be preserved.
That is what the script below does.
Two versions
You can restore your arranged windows in two ways:
- Occasionally, with a shortcut key to run after the second screen is connected.
- Automatically, running the script in the background, waiting for your screen to be connected.
How to use
preparations
Install wmctrl
sudo apt-get install wmctrl
Look up your two screens' names with the help of xrandr
, the names of the screens will be just before the word "connected".
Copy Either one of the scripts below, in the head section, replace in these two lines the screen names by the correct ones:
screen_1 = "LVDS1" # your main screen (laptop)
screen_2 = "VGA1" # secundary screen (on the left)
save the script as move_windows.py
Make sure in display settings your secondary screen is on the left. The top lines of the two screens need to be in line (like in the first image of your question).
Run the script
- If you use the one to run occasionally, run it after your second screen is connected.
python3 /path/to/move_windows.py
You might want to add it to a keyboard shortcut if you think it does what it should do, Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts".
Click the "+" and add the command:
If you use the one to run in the background, also run it by the command:
python3 /path/to/move_windows.py
If it acts as you intended, add it to your start-up applications: Dash > Startup Applications > Add
I tested the script with my laptop (on the right) and two different screens (on the left). The result was the same.
laptop screen
connecting without script
connecting with the script running
After the script did its job, windows will be "left alone" (of course), and you can arrange your windows your way.
The script(s)
1. "Manual" version, to run after the screen is connected
#!/usr/bin/env python3
import subprocess
import time
#--
screen_2 = "LVDS1" # replace with your internal screen (right)
screen_2 = "VGA1" # replace with your external screen (left)
#--
def get(cmd):
return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_shift(xr_output):
lines = [l for l in xr_output.splitlines() if " connected" in l][0].split()
return int([it for it in lines if "x" in it][0].split("x")[0])
def shift_windows(shift):
w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
relevant = []
for w in w_data:
props = get("xprop -id "+w[0])
if (int(w[2]) < shift, "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True) == 2:
command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), w[3], w[4], w[5]])
subprocess.Popen(["/bin/bash", "-c", command])
shift_windows(get_shift(get("xrandr")))
2. Automatic version, to run in the background
#!/usr/bin/env python3
import subprocess
import time
#--
screen_2 = "LVDS1" # replace with your internal screen (right)
screen_2 = "VGA1" # replace with your external screen (left)
#--
def get(cmd):
return subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def get_shift(xr_output):
lines = [l for l in xr_output.splitlines() if " connected" in l][0].split()
return int([it for it in lines if "x" in it][0].split("x")[0])
def shift_windows(shift):
w_data = [l.split() for l in get("wmctrl -lG").splitlines()]
relevant = []
for w in w_data:
props = get("xprop -id "+w[0])
if (int(w[2]) < shift, "_TYPE_NORMAL" in props, "TYPE_DIALOG" in props).count(True) == 2:
command = "wmctrl -ir "+w[0]+" -e 0,"+(",").join([str(int(w[2])+shift), w[3], w[4], w[5]])
subprocess.Popen(["/bin/bash", "-c", command])
while True:
try:
screen_info1 = get("xrandr")
time.sleep(5)
screen_info2 = get("xrandr")
check = screen_2+" connected"
if (check in screen_info1, check in screen_info2) == (False, True):
time.sleep(5)
shift_windows(get_shift(screen_info2))
except:
pass
Best Answer
I am providing you two shell scripts. It will help you to save your arrangement of windows positions and size. If somehow your desired windows arrangements get disturbed, you will be able to restore those arrangements with exact windows size and positions for all windows using these script.
You need to install
wmctrl
unless you already have it. Install via terminal,Script to save windows configuration
At execution the above script will save your windows position and size for all your open windows to a file named
.my_windows_config.txt
in your home directory. It is a hidden text file.Script to reload the windows configuration
When you execute the second script it will restore your windows position with exact size for all your windows.
Usage
Save these scripts in your
$HOME/bin/
directory. Add$HOME/bin/
in yourPATH
. For this add these lines at the end of your$HOME/.bashrc
It will enable you execute those scripts with their name only. Give the scripts execution permission,
To save the configuration in your
$HOME/.my_windows_config.txt
After you open and adjusted all your windows run in terminal,
To reload the configuration from your
$HOME/.my_windows_config.txt
Hope it will solve your problem. Here is a screen shot,