3

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:

enter image description here

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.

  • 1
    Hi 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? – Jacob Vlijm Jan 14 '16 at 19:31
  • 1
    Hey 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. – Andy Jan 14 '16 at 19:44
  • 1
    I 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. – Jacob Vlijm Jan 14 '16 at 19:47
  • 1
    I'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. – Andy Jan 14 '16 at 20:23
  • 1
    Hi Andy, did you notice the answer? Please let me know if anything is unclear, and if it works with open source drivers :) – Jacob Vlijm Jan 18 '16 at 19:22
5

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

  1. Copy the script into an empty file, save it as restore_icons.py
  2. 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"
    # ---
    
  3. 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.

    <image_1>

    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.

  4. 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.

  5. 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.

  • Thanks 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! :) – Andy Jan 20 '16 at 22:56
  • @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 Jan 21 '16 at 6:08
1

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

  • You're welcome. Your answer also means it works on nemo on Ubuntu most likely :) – Jacob Vlijm Dec 10 '17 at 19:23
0

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:

iconic main menu.png

Visit the github page for iconic to see all the other screens, explanations and a copy of the script.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.