How can I preserve the desktop's icon positions after reboot, on a dual monitor setup (Unity)?
Solution 1
The cause
Most likely, the issue is the result of a bug (related to the video driver). I assume the second screen is not remembered somehow, and "virtually" re- connected in a rather late stage in the start up (log in) process.
Work around
As often, even if it is a bug, it doesn't mean we cannot find a work around. If we:
- can make some kind of a snapshot of the current icon positions on log out
- restore the icon positions after the second screen appears correctly after restart (log in)
effectively the bug is worked around.
How to read the icon position on the desktop
You can get the position on the desktop of an icon by the command:
gvfs-info -a 'metadata::nautilus-icon-position' '<file>'
This will a.o. output the coordinates of the icon on your desktop, which we can save into a file. If we make a snapshot this way of your desktop before shutting down the computer, we can subsequently restore the icon's position afterwards, with the command:
gvfs-set-attribute -t string '<file>' 'metadata::nautilus-icon-position' '500,500'
(for example)
A script to take such a snapshot, and restore the icon layout (depending on the argument) would be:
#!/usr/bin/env python3
import subprocess
import os
import sys
# --- set your localized desktop name below:
dt_name = "Bureaublad"
# ---
# used strings & definitions
val = " 'metadata::nautilus-icon-position' "
search = "gvfs-info -a"+val
set_val = "gvfs-set-attribute -t string "
home = os.environ["HOME"]
dt_dir = home+"/"+dt_name
datafile = home+"/.desktop_items.txt"
arg = sys.argv[1]
get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def snapshot():
try:
os.remove(datafile)
except FileNotFoundError:
pass
dt_items = os.listdir(dt_dir)
dt_data = []
for f in [f for f in dt_items if all([not f.startswith("."), not f.endswith("~")])]:
f = '"'+f+'"' if f.count(" ") > 0 else f
file = dt_dir+"/"+f
cmd = search+file
try:
loc = [int(n) for n in get(cmd).split()[-1].split(",")]
# loc[0] = loc[0] - screen_pos[0]; loc[1] = loc[1] - screen_pos[1]
loc = (",").join([str(n) for n in loc])
open(datafile, "a+").write(file+"|||"+loc+"\n")
except:
pass
subprocess.Popen(["/bin/bash", "-c", "notify-send 'A snapshot was taken'"])
def restore():
items = [l.strip().split("|||") for l in open(datafile).readlines()]
for item in items:
try:
xy = [int(n) for n in item[1].split(",")]
move_to = (",").join(str(n) for n in [xy[0], xy[1]])
command = set_val+item[0]+val+move_to
subprocess.Popen(["/bin/bash", "-c", command])
except:
pass
subprocess.Popen(["/bin/bash", "-c", "notify-send 'Click on the desktop and press F5'"])
if arg == "snapshot":
snapshot()
elif arg == "restore":
restore()
To use it:
- Copy the script into an empty file, save it as
restore_desktop.py
-
In the head section of the script, in the line:
# --- set your localized desktop name below: dt_name = "Desktop" # ---
set the localized name of your desktop folder ("Bureaublad" in Dutch)
-
To take a snapshot of the current icon layout, run the command:
python3 /path/to/restore_desktop.py snapshot
-
To restore a previously taken snapshot:
python3 /path/to/restore_desktop.py restore
then click on the desktop and press F5 to refresh the desktop.
To use the script in our situation would however take a few additions
The desktop still needs to be refreshed from the command line to actually apply the restore of the icons. This can be done by either restarting
nautilus
, or press F5 with the desktop in front. Since we use it on startup, the first option might be the most elegant one.-
We need to take a snapshot on log out as the current user to make sure the last icon layout is recorded into a snapshot. So far, I could not find a way to do that. However, as always, there is a workaround. If we include the command
gnome-session-quit --poweroff
in our script, we can simply call the script (with the right arguments) to include the shutdown procedure and take the snapshot.
- Then to make sure the restored snapshot is applied we can include the restart of nautilus in the script.
The solution
The final script then becomes:
#!/usr/bin/env python3
import subprocess
import os
import sys
import time
# --- set your localized desktop name below:
dt_name = "Desktop"
# ---
# used strings & definitions
val = " 'metadata::nautilus-icon-position' "
search = "gvfs-info -a"+val
set_val = "gvfs-set-attribute -t string "
home = os.environ["HOME"]
dt_dir = home+"/"+dt_name
datafile = home+"/.desktop_items.txt"
arg = sys.argv[1]
get = lambda cmd: subprocess.check_output(["/bin/bash", "-c", cmd]).decode("utf-8")
def snapshot():
# remove the previous snapshot
try:
os.remove(datafile)
except FileNotFoundError:
pass
# list the items on the desktop, look up their positions
dt_items = os.listdir(dt_dir)
dt_data = []
for f in [f for f in dt_items if all([not f.startswith("."), not f.endswith("~")])]:
f = '"'+f+'"' if f.count(" ") > 0 else f
file = dt_dir+"/"+f
cmd = search+file
try:
loc = [int(n) for n in get(cmd).split()[-1].split(",")]
loc = (",").join([str(n) for n in loc])
open(datafile, "a+").write(file+"|||"+loc+"\n")
except:
pass
# notify that a snapshot was taken
subprocess.call(["/bin/bash", "-c", "notify-send 'A snapshot was taken'"])
# send the command to shutdown
subprocess.Popen(["gnome-session-quit", "--power-off"])
def restore():
# wait for 20 seconds for the desktop to be fully loaded and the screen to be found
time.sleep(20)
# read the snapshot file
items = [l.strip().split("|||") for l in open(datafile).readlines()]
for item in items:
try:
# place the icon(s) acoording to the remembered position(s)
xy = [int(n) for n in item[1].split(",")]
move_to = (",").join(str(n) for n in [xy[0], xy[1]])
command = set_val+item[0]+val+move_to
subprocess.Popen(["/bin/bash", "-c", command])
except:
pass
# restart nautilus
subprocess.call(["killall", "nautilus"])
subprocess.Popen(["nautilus"])
# send notification
subprocess.Popen(["/bin/bash", "-c", "notify-send 'Icon positions were restored'"])
if arg == "snapshot":
snapshot()
elif arg == "restore":
restore()
How to use
- Copy the script into an empty file, save it as
restore_icons.py
-
In the head section of the script, set the appropriate (localized) name of the
Desktop
folder:# --- set your localized desktop name below: dt_name = "Desktop" # ---
-
Test- run the script by running the command:
python3 /path/to/restore_icons.py snapshot
A snapshot of the current layout will be take. De shut down menu appears on your desktop, but cancel it by clicking outside the menu on your desktop.
Then deliberately mess around with your icons (positions) on your desktop.
Finaly, run the script again with another argument:python3 /path/to/restore_icons.py restore
Wait for 20 seconds (see Note at the bottom why that is included in the script) and your desktop icons will be restored to how it was before you took the snapshot.
-
If all works fine, add a shortut key: Choose: System Settings > "Keyboard" > "Shortcuts" > "Custom Shortcuts". Click the "+" and add the command:
python3 /path/to/restore_icons.py snapshot
This will be the shortcut you need to use, to shut down your computer.
-
Add the restore command to Startup Applications: Dash > Startup Applications > Add. Add the command:
python3 /path/to/restore_icons.py restore
Now 20 seconds after startup (log in), your icons will be exactly like you left them on shut down.
Note
The 20 seconds break is to make sure the second monitor is found and reconnected before the restore command runs.
Solution 2
I wrote iconic
to solve this problem by letting you save and load desktop icon settings. Additionally it will:
- Let you move icons to any one of three monitors
- Define a grid size to spread icons evenly across desktop as close or far apart as you prefer
- Not suffer the "lost icon syndrome" that occurs when monitors of multiple resolutions are used
- Sort icons alphabetically, alphabetically with "Link to" prefix ignored, sort by modified date ascending or date descending
- Allow different grid size (columns x rows) depending on monitor, EG more on 4K monitor than 2K monitor
- Instant Test button for quick experimentation on column x row changes or reserved space changes for monitor left, top, right or bottom areas
- Test button will last for x seconds defined by you, clear all windows before test and restore them after test
- Bash script for easy modifications
You can get the script on github.
Here's the main screen:
Visit the github page for iconic to see all the other screens, explanations and a copy of the script.
Solution 3
The Script works on Linux Mint 18.3 Cinnamon too, when i did the following little changes:
replace:
nautilus-icon-position -> nemo-icon-position gnome-session-quit ->cinnamon-session-quit "killall","nautilus" ->"killall","nemo-desktop" subprocess.Popen(["nautilus"]) -> subprocess.POpen(["nemo-desktop"])
thanks a lot for that great script
cinnamon
Related videos on Youtube
Andy
Full stack web developer. Breaking the mould. Read my blog: https://andypalmer.me Check out my GitHub projects: https://github.com/andyexeter
Updated on September 18, 2022Comments
-
Andy over 1 year
I have a dual monitor setup running Unity on Ubuntu 14.04
Whenever I boot the machine, the system appears to forget the positions of my desktop icons on the right-side display (Connected via VGA). The icons are all set out nicely on the right side of the screen but when I boot all of the icons are bunched up close to the top left underneath the launcher with some overlapping each other like so:
How can I fix this so the desktop icons appear in the same place every time I boot? The icons on the left-side display (connected via HDMI) are always fine and always stay in their same positions.
-
Jacob Vlijm over 8 yearsHi Andy. Your problem is most likely caused by a bug. That does not mean we can not work around, but it would require (as it is now) to shut down your computer by a shortcut key (or another alternative to the usual way). Would that be acceptable to you?
-
Andy over 8 yearsHey Jacob, that's fine it's just pain having to re-organise the icons every time I boot up. Could this be because of display drivers? I'm trying out using the AMD propietary drivers (fglrx) now instead of the open source ones to see if that makes a difference.
-
Jacob Vlijm over 8 yearsI think it is. I believe it is because on every boot, the second screen is re- connecting in a late stage after log, in as if it is the first time. Let me know if different driver nakes a difference. If not I will finish my solution and post it tomorrow.
-
Andy over 8 yearsI've tried a couple of boots with the different drivers and it seems ok so far, I wouldn't mind trying out something that would work with the open source drivers though. Look forward to seeing your solution tomorrow, thank you.
-
Jacob Vlijm over 8 yearsHi Andy, did you notice the answer? Please let me know if anything is unclear, and if it works with open source drivers :)
-
Andy over 8 yearsHi Jacob, I noticed the answer thank you. I've been a little bit busy myself the last couple of days so will accept and/or comment on it as soon as I get a chance to test. Thank you again!
-
-
Andy over 8 yearsThanks Jacob, this is a brilliant and very comprehensive answer. I've decided to stick with the proprietary drivers for now because it appears to resolve this issue and as an added bonus has stopped all the crashes that were happening! :)
-
Jacob Vlijm over 8 years@Andy Haha, I can imagine, and I am pretty sure I would do the same. Nevertheless is was nice to work on, and an altered version of the script might be useful in other situations in the future :).
-
Jacob Vlijm over 6 yearsYou're welcome. Your answer also means it works on nemo on Ubuntu most likely :)
-
sup over 3 yearsBut you cannot save positions with your script, can you?
-
WinEunuuchs2Unix over 3 yearsYes you can save positions under a profile name like
home
orwork
. @sup the option buttons are called Save Icons and Load Icons.