The script was patched/fixed on January 16 2017, fixing for a few applications of which the process name differs from the command to run the application. Possibly, this occurs occasionally on applications. If someone finds one, please leave a comment.
Script to remember and restore the window arrangement and their corresponding applications.
The script below can be run with two options. Let's say you have the window arrangement as below:
To read (remember) the current window arrangement and their applications, run the script with the option:
Then close all windows:
Then to set up the last remembered window arrangement, run it with the option:
and the last remembered window arrangement will be restored:
This will also work after a restart.
Putting the two commands under two different shortcut keys, you can "record" your window arrangement, shutdown your computer and recall the same window arrangement after (e.g.) a restart.
What the script does, and what it does not
Run with the option
- The script uses
wmctrl to list all windows, across all workspaces, their positions, their sizes, the applications they belong to
- The script then "converts" the window positions from relative (to the current workspace, as in the output of
wmctrl) to absolute positions, on your spanning workspaces. Therefore it does not matter if the windows you want to remember are on only one workspace or spread over different workspaces.
- The script then "remembers" the current window arrangement, writing it into an invisible file in your home directory.
Run with the option
- the script reads the last remembered window arrangement; it starts the corresponding applications, moves the windows to the remembered positions, also with the help of
The script does not remember the files that possibly might be opened in the windows, nor (e.g.) the websites that were opened in a browser window.
The combination of
Unity has some bugs, a few examples:
- the window coordinates, as read by
wmctrl differs slightly form the command to position the windows, as mentioned here. Therefore the recalled window positions might slightly differ from the original position.
wmctrl commands works a bit unpredictable if the edge of the window is very near either the
Unity Launcher or the panel.
- The "remembered" windows need to be completely inside a workspace borders for the
wmctrl placement command to work well.
Some applications open new windows by default in the same window in a new tab (like
gedit). I fixed it for
gedit, but please mention it if you find more exceptions.
wfile = os.environ["HOME"]+"/.windowlist"
arg = sys.argv
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
w_type = get("xprop -id "+w_id)
if " _NET_WM_WINDOW_TYPE_NORMAL" in w_type:
# get resolution and the workspace correction (vector)
xr = subprocess.check_output(["xrandr"]).decode("utf-8").split()
pos = xr.index("current")
res = [int(xr[pos+1]), int(xr[pos+3].replace(",", "") )]
vp_data = subprocess.check_output(["wmctrl", "-d"]).decode("utf-8").split()
curr_vpdata = [int(n) for n in vp_data.split(",")]
return [res, curr_vpdata]
app = lambda pid: subprocess.check_output(["ps", "-p", pid, "-o", "comm="]).decode("utf-8").strip()
res = get_res()
w_list = [l.split() for l in get("wmctrl -lpG").splitlines()]
relevant = [[w,[int(n) for n in w[3:7]]] for w in w_list if check_window(w) == True]
for i, r in enumerate(relevant):
relevant[i] = app(r)+" "+str((" ").join([str(n) for n in r]))
with open(wfile, "wt") as out:
for l in relevant:
def open_appwindow(app, x, y, w, h):
ws1 = get("wmctrl -lp"); t = 0
# fix command for certain apps that open in new tab by default
if app == "gedit":
option = " --new-window"
option = ""
# fix command if process name and command to run are different
if "gnome-terminal" in app:
app = "gnome-terminal"
elif "chrome" in app:
app = "/usr/bin/google-chrome-stable"
subprocess.Popen(["/bin/bash", "-c", app+option])
# fix exception for Chrome (command = google-chrome-stable, but processname = chrome)
app = "chrome" if "chrome" in app else app
while t < 30:
ws2 = [w.split()[0:3] for w in get("wmctrl -lp").splitlines() if not w in ws1]
procs = [[(p, w) for p in get("ps -e ww").splitlines() \
if app in p and w in p] for w in ws2]
if len(procs) > 0:
w_id = procs
cmd1 = "wmctrl -ir "+w_id+" -b remove,maximized_horz"
cmd2 = "wmctrl -ir "+w_id+" -b remove,maximized_vert"
cmd3 = "wmctrl -ir "+procs+" -e 0,"+x+","+y+","+w+","+h
for cmd in [cmd1, cmd2, cmd3]:
subprocess.call(["/bin/bash", "-c", cmd])
t = t+1
res = get_res()
lines = [l.split() for l in open(wfile).read().splitlines()]
for l in lines:
l = str(int(l) - res); l = str(int(l) - res - 24)
open_appwindow(l, l, l, l, l)
if arg == "-run":
elif arg == "-read":
How to set up
Before you start, make sure
wmctrl is installed:
sudo apt-get install wmctrl
- Copy the script into an empty file, save it as
~/bin. Create the directory if necessary. If the directory didn't exist yet, run either
source ~/.profile or log out/in after you created the directory. It will now be in
- Make the script executable (!).
Now open a few windows,
firefox or whatever, and test-run the script in a terminal by running the command (no path prefix needed):
close the windows. Now run in a terminal:
Your window setup should now be restored
If all works fine, add two commands to shortcut keys: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the commands:
to two different shortcut keys