Saving and restoring window positions
I'm experiencing a bug where when the machine comes back from standby a monitor connected via displayport (MST) does not come back on, however the windows are still in the area it cover if it did come on.
The only way to recover from this short of a restart is to disable and reenable the display now I can do that via the command line just fine but when the display is disabled all the windows get rearranged onto the remaining screen.
Is there a way to persist the window positions and restore them so my script could do this sequence:-
- enumerate windows, store positions
- display off (messing up positions)
- display on (making the display work again, yay!)
- restore position of the windows
I can do step 2 and 3 just fine but I'm lost for step 1 and 4
I know I can force a position per app but that's not what I want as I could be doing different things and have the same apps in different positions, I also have multiple terminals open, I need the current positions storing somehow and restoring.
Any help would be appreciated!
Solution 1:
Take a "snapshot" of the window arrangement and restore it
The script below can be used to get the current window positions of all "normal" windows (run with the argument -get
), or restore the last window arrangement (run with the argument -restore
).
As explained here, using wmctrl
i.c.w. Unity has some issues. If it is satisfying in your situation is to decide.
How to use
The script uses wmctrl
:
sudo apt-get install wmctrl
Then:
- Copy the script into an empty file, save it as
window_arrange.py
-
Run it by:
python3 /path/to/window_arrange.py -get
to "record" the current window arrangement, and
python3 /path/to/window_arrange.py -restore
to restore the last "recorded" window arrangement
The script:
#!/usr/bin/env python3
import subprocess
import os
import sys
wfile = os.environ["HOME"]+"/.windowlist"
arg = sys.argv[1]
def get(command):
return subprocess.check_output(["/bin/bash", "-c", command]).decode("utf-8")
def check_window(w_id):
w_type = get("xprop -id "+w_id)
if " _NET_WM_WINDOW_TYPE_NORMAL" in w_type:
return True
else:
return False
def read_windows():
w_list = [l.split()[:6] for l in get("wmctrl -lG").splitlines()]
relevant = [(" ").join(w) for w in w_list if check_window(w[0]) == True]
with open(wfile, "wt") as out:
for item in relevant:
out.write(item+"\n")
def restore_windows():
try:
wlist = [l.split() for l in open(wfile).read().splitlines()]
except FileNotFoundError:
pass
else:
for w in wlist:
try:
cmd = "wmctrl -ir "+w[0]+" -e 0,"+(",").join(w[2:])
subprocess.Popen(["/bin/bash", "-c", cmd])
except:
pass
if arg == "-restore":
restore_windows()
elif arg == "-get":
read_windows()
Solution 2:
If you install wmctrl you can use "wmctrl -Gl" to get a listing of all windows with their current positions and sizes. You could then use this information in step 4 to call wmctrl with the -e option to restore the size and position. For example:
wmctrl -ir <id> -e 0,<x>,<y>,<w>,<h>
Solution 3:
If you prefer NodeJs: I wrote a little library/command line tool which allow saving and restoring sessions and has support for different monitors setups as well as virtual desktops. You might want to check out the implementation of the window related features: https://github.com/johannesjo/linux-window-session-manager/blob/master/lib/x11-wrapper.js
You can find the whole thing here: https://github.com/johannesjo/linux-window-session-manager