6

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:-

  1. enumerate windows, store positions
  2. display off (messing up positions)
  3. display on (making the display work again, yay!)
  4. 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!

Jacob Vlijm
  • 83,767
  • Could be done very well (and interesting) , but in my case... it would be in python :) would that disturb you? – Jacob Vlijm Jun 02 '15 at 16:49
  • 1
    Python is absolutely fine, I guess it'd be good if saving and restoring could be called separately though then I can call the python scripts from my existing bash scripts – Anthony Graham Jun 02 '15 at 17:04
  • Posted my answer. Really curious if it is sufficient in your situation. You can also use it to store the arrangement before going on standby, and restore after wake up (but that may be what you meant:) ). You can even make two key shortcut keys to do that. – Jacob Vlijm Jun 02 '15 at 19:08

3 Answers3

7

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:

  1. Copy the script into an empty file, save it as window_arrange.py
  2. 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()
Jacob Vlijm
  • 83,767
  • Sir, that is amazing work! – Anthony Graham Jun 02 '15 at 19:12
  • @AnthonyGraham Thanks. As mentioned, this is the kind of question that ineterests me a lot. Thanks for the nice question :) – Jacob Vlijm Jun 02 '15 at 19:13
  • 1
    @JacobVlijm the follow up to this would be how to make a script that would execute all desired apps and then set the window positions. Thanks for the good work above. – ylluminate Mar 21 '16 at 18:41
  • This is great, but it's got two problems: 1. It tries to restore windows by ID, which aren't stable across restarts - of the OS, or the App. 2. Doesn't tell the window which workspace to restore to. – Duncan Lock Apr 20 '17 at 22:34
  • You can make this restore windows to the desktop/workspace they were on by changing line 38 to this: cmd = "wmctrl -ir " + w[0] + " -e 0," + (",").join(w[2:] + "-t " + w[1]) – Duncan Lock Apr 20 '17 at 22:55
  • 1
    @DuncanLock Thanks for mentioning, however, the question was on when the machine comes back from standby. Your suggestion does not work on Unity, Which is the tag on this question :). Unity has viewports on one big workspace. – Jacob Vlijm Apr 21 '17 at 06:00
  • work mostly. but all the windows positions slightly changed. don't know why, – Jake Jun 24 '21 at 10:50
3

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>
jholtrop
  • 133
2

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