How to recover offscreen window after disconnecting second monitor?
Move all windows into the visible area
As proposed/requested in a comment, the script below will move all "normal" windows to the visible area on the current workspace.
The solution is a workaround; the screen info is updated correctly, given the difference in the output of xrandr
, before and and after disconnecting. The reason why the windows do not move by themselves is (currently) unknown, unless another answer solves the issue.
The script
#!/usr/bin/env python3
import subprocess
# get the resolution of the screen (+0+0)
res = [
int(n) for n in [
s.split("+")[0].split("x")\
for s in subprocess.check_output(["xrandr"]).decode("utf-8").split()\
if "+0+0" in s][0]
]
# create list of windows
w_list = [w.split() for w in subprocess.check_output(["wmctrl", "-lG"]).decode("utf-8").splitlines()]
# filter only "normal" ones
valid = [
w for w in w_list if "_NET_WM_WINDOW_TYPE_NORMAL" in\
subprocess.check_output(["xprop", "-id", w[0]]).decode("utf-8")
]
# get the number of valid windows and calculate a targeted position
# the targeted position is a hunch, it will be exact if the window fits completely inside the resolution
# it will work anyway
parts = len(valid)+2
positions = [(int(n*res[0]/parts), int(n*res[1]/parts)) for n in list(range(parts))[1:-1]]
# unmaximaize, move the windows to the visible area (current workspace)
for i, w in enumerate(valid):
subprocess.Popen(["wmctrl", "-ir", w[0], "-b", "remove,maximized_vert,remove,maximized_horz"])
# weird, but sometimes wmctrl refuses to move a window if it is not resized first (?)
subprocess.Popen(["wmctrl", "-ir", w[0], "-e", "0,200,200,200,200"])
subprocess.Popen(["wmctrl", "-ir", w[0], "-e", (",").join(["0", str(positions[i][0]), str(positions[i][1]),w[4],w[5]])])
How to use
The script needs
wmctrl
:sudo apt-get install wmctrl
Copy the script into an empty file, safe it as
move_windows.py
Test- run it: open a number of windows, place them on different workspaces etc., or try disconnecting the second monitor. Then run the command:
python3 /path/to/move_windows.py
All "normal" windows should move to the visible area of the current workspace.
If all works fine, add it to a shortcut key: choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:
python3 /path/to/move_windows.py
Now you should be able to move all windows into the visible area on the current workspace, with your shortcut key.