How to recover offscreen window after disconnecting second monitor?
I use Ubuntu 14.04 on my laptop at my desk with a second monitor. When I disconnect from the second monitor---without fail---my window for Emacs moves off screen.
I can Alt-TAB to make Emacs the active window, and, working blindly, stop Emacs so I can restart it, which causes it to reappear on the screen. But, it seems to me there should be a way in Ubuntu to get an off-screen window back onto the screen. Is there?
Of course, a better solution would be to prevent the windows from going off screen in response to monitor disconnection, and I would accept a solution to that problem.
UPDATE:
The output of xrandr
while connected to a second monitor:
Screen 0: minimum 320 x 200, current 3200 x 1080, maximum 32767 x 32767
eDP1 connected primary 1920x1080+1280+0 (normal left inverted right x axis y axis) 382mm x 215mm
1920x1080 60.0*+ 59.9
1680x1050 60.0 59.9
1600x1024 60.2
1400x1050 60.0
1280x1024 60.0
1440x900 59.9
1280x960 60.0
1360x768 59.8 60.0
1152x864 60.0
1024x768 60.0
800x600 60.3 56.2
640x480 59.9
VGA1 connected 1280x1024+0+0 (normal left inverted right x axis y axis) 376mm x 301mm
1280x1024 60.0*+ 75.0
1280x960 60.0
1152x864 75.0
1024x768 75.1 70.1 60.0
832x624 74.6
800x600 72.2 75.0 60.3 56.2
640x480 75.0 72.8 66.7 60.0
720x400 70.1
HDMI1 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
The output of xrandr
after disconnecting from the second monitor:
Screen 0: minimum 320 x 200, current 1920 x 1080, maximum 32767 x 32767
eDP1 connected primary 1920x1080+0+0 (normal left inverted right x axis y axis) 382mm x 215mm
1920x1080 60.0*+ 59.9
1680x1050 60.0 59.9
1600x1024 60.2
1400x1050 60.0
1280x1024 60.0
1440x900 59.9
1280x960 60.0
1360x768 59.8 60.0
1152x864 60.0
1024x768 60.0
800x600 60.3 56.2
640x480 59.9
VGA1 disconnected (normal left inverted right x axis y axis)
HDMI1 disconnected (normal left inverted right x axis y axis)
VIRTUAL1 disconnected (normal left inverted right x axis y axis)
Also, I tried swapping the left-right positions of my Terminal window and my Emacs window and then disconnecting. This allows the Emacs window to remain on-screen after disconnecting from the second monitor. And the Terminal window survives in the position that eliminated Emacs. So, it seems as if the application has something to do with this.
Solution 1:
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.