I am using a large 4K monitor with multiple work spaces each having multiple applications. When rebooting Ubuntu 18.04, the locations of the application windows are lost and it takes me several minutes to reconfigure them. How can I save and recover the window positions within the work spaces?
The Gnome Extension "Auto Move Windows" will move applications to a specified workspace when they are opened. The location of the application windows within the workspace are also remembered. See, https://extensions.gnome.org/extension/16/auto-move-windows/
Note that there are solutions for prior versions of Ubuntu (w/ Unity) that use scripts. However, Ubuntu switched back to using Gnome in 18.04. (e.g., Saving and restoring window positions and How can I start up an application with a pre-defined window size and position?)
This does what you're looking for!
I just wrote this python script to open different applications and move them to specific workplaces on boot up. It works for me on Ubuntu 20. Only dependency besides python is
wmctrl (which might be installed by default on Ubuntu?). Have it run on startup - I put it in Startup Applications with
python3 /path/to/script.py in the Command field.
There are probably optimizations to make here but leaving it to be used/changed by anyone struggling with this. If using the script as is, change the
apps list to hold the programs you want. Only change the first 3 elements of each tuple in list - first is command to launch the program from a terminal, second is workspace number, third is string to identify program in output from
wmctrl -l - e.g. with line
0x02200005 8 fiona New Tab - Google Chrome in
wmctrl output, search term could be
import subprocess import time import datetime def run_command_in_background(command): # command is list of strings subprocess.Popen(command) def get_wmctrl_lines(): return subprocess.run(["wmctrl", "-l"], capture_output=True, text=True).stdout.splitlines() finito_ids = set() def get_running_app_window_id_desktop_nb(search_term): for line in get_wmctrl_lines(): if search_term in line.lower(): split = line.split() window_id = split if window_id not in finito_ids: return split, int(split) return None, None def move_window_to_desktop(window_id, desktop_number): # desktop = workspace?? run_command_in_background(["wmctrl", "-i", "-r", str(window_id), "-t", str(desktop_number)]) apps = [ # app_command, desktop_nb, search_term, should_be_full_screen, has_been_spawned, has_been_formatted (["vivaldi"],2,"vivaldi",False,False,False), (["terminator"],3,"/bin/bash",True,False,False), (["terminator"],4,"/bin/bash",True,False,False), (["terminator"],5,"/bin/bash",True,False,False), (["snap","run","spotify"],6,"spotify",False,False,False), (["google-chrome"],8,"chrome",False,False,False), ] # move apps while False in [a[-1] for a in apps]: new_apps =  for app in apps: app_command, desktop_nb, search_term, should_be_full_screen, has_been_spawned, has_been_formatted = app if not has_been_spawned: run_command_in_background(app_command) has_been_spawned = True else: app_window_id, current_desktop_nb = get_running_app_window_id_desktop_nb(search_term) if app_window_id is not None: run_command_in_background(["wmctrl", "-i", "-r", app_window_id, "-t", str(desktop_nb)]) if should_be_full_screen: run_command_in_background(["wmctrl", "-i", "-r", app_window_id, "-b", "toggle,fullscreen"]) has_been_formatted = True finito_ids.add(app_window_id) else: print("app %s still not running" % search_term) new_apps.append((app_command, desktop_nb, search_term, should_be_full_screen, has_been_spawned, has_been_formatted)) apps = new_apps time.sleep(1) # send notification that everything is ready run_command_in_background(["notify-send", "Hola we", "apps/workspaces are set up"])