How can I always keep the Desktop icons organised, and sorted by name?

Arrange desktop icons alphabetically by command

The script below will rearrange a desktop like:

enter image description here

...into an alphabetically ordered desktop like:

enter image description here

Ordered:

  • directories first, then files
  • from top to bottom, from left to right

Set the number of items vertically

Furthermore, you can set an arbitrary number of items vertically (rows); the horizontal spacing will be set automatically accordingly.

The script

#!/usr/bin/env python3
import subprocess
import os
import math
import time

# set the size of the squares (indirectly, by setting n- rows)
rows = 10
# set x/y offset of the matrix if you want
x_offs = -15
y_offs = -30

def get(cmd):
    return subprocess.check_output(cmd).decode("utf-8")

dt = get(["xdg-user-dir",  "DESKTOP"]).strip()         
# find size of the left screen
left = [int(n) for n in sum(
    [s.split("+")[0].split("x") for s in \
     get("xrandr").split() if "+0+" in s], [])]

# size of the squares (icon area)
sqr = int((left[1]/rows))

# number of cols, squares
cols = math.floor(left[0]/sqr)
n_sqrs = cols*rows

# define positions (matrix)
pos = list([[
    str(int((math.floor(n/rows)*sqr)+(sqr/2)+x_offs)),
    str(int(((n%rows)*sqr)+(sqr/2)+y_offs)),
    ] for n in range(n_sqrs)])

# list iconfiles, split into dirs and files, sort & combine
iconlist = [os.path.join(dt, item) for item in \
            sorted([item for item in os.listdir(dt) if not "~" in item])]
dirs = []; files = []
for it in iconlist:
    if os.path.isfile(it):
        files.append(it)
    else:
        dirs.append(it)
iconlist = dirs+files
# place icons in position(s)
for i, item in enumerate(iconlist):
    location = (",").join(pos[i])
    subprocess.call(["gvfs-set-attribute", "-t", "string", item,
                       'metadata::nautilus-icon-position', location])
# simulate F5 to refresh desktop, retry for max 20 secs if not in front
t = 0
while t < 40:
    w_id = [l.split()[-1] for l in get(["xprop", "-root"]).splitlines() \
        if "_NET_ACTIVE_WINDOW(WINDOW):" in l][0]
    if "desktop" in get(["xprop", "-id", w_id, "WM_CLASS"]):
        subprocess.Popen(["xdotool", "key", "F5"])
        break
    else:
        time.sleep(0.5)
        t += 1

How to use

  1. The script needs xdotool:

      sudo apt-get install xdotool
    
  2. Copy the script into an empty file, save it as arrange_dt.py

  3. Test- run it by the command:

    python3 /path/to/arrange_dt.py
    

    within 20 seconds click on the desktop, your new arrangement will be applied. If you run the script from a shortcut, while the desktop is in front, the arrangement will be applied immediately. If the desktop is not frontmost, the script waits for max 20 seconds. If time exceeds, simply press F5 to apply.

  4. 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/arrange_dt.py
    

Options

You can influence the arrangement of the icons in three ways:

  1. set the size of the "tiles"

    # set the size of the squares (indirectly, by setting n- rows)
    rows = 10
    

    This will set the (max) number of icons vertically. The size of the "tiles" will, be equal (x,y)

  2. set the horizontal offset

    x_offs = -15 
    

    This will set the x- deviation from the default position of the icon-matrix as a whole

  3. Set the vertical offset

    y_offs = -30
    

    This will set the y- deviation from the default position of the icon-matrix

    An example, using:

    # set the size of the squares (indirectly, by setting n- rows)
    rows = 6
    # set x/y offset of the matrix if you want
    x_offs = 50
    y_offs = 10
    

    enter image description here

Explanation

The explanation below is mostly an explanation on the concept rather than the coding

  • To position the icons alphabetically, we first list the items on the desktop, using python's os.listdir(Desktop)
  • Then we split the files into two sublists; files/folders, and sort both lists, join them again, folders first.
  • Then we create the matrix:

    • Since the number of rows is set in the head of the script, we divide the height of the screen by the number of rows. Thus we have the size of the "squares" the icons will be placed in (centered).
    • Since the icons are similarly spaced horizontally, we can then calculate the (max) number of columns by dividing the width of the screen by the width of the "squares" in which the icons will be placed (per icon), rounded down to the first integer below.
    • In the image below, these "virtual" squares are visible, the red dot is where the icon is placed.

      enter image description here

    • Then all we have to do is place the first icon on half of the size of a square, both horizontally and vertically.

    • To find the x-position of all other icons, we simply need to divide their index (starting with zero) by the number of rows, rounded down. The outcome will be added to the x position of the first icon (top left), for example:

      item 10 (index 9): 9/4 = 2,25, rounded down: 2
      x position = position of icon 0 + 2 x the width of a square
      
      item 17 (index 16): 16/4 = 4, rounded down: 4
      x position = position of icon 0 + 4 x the width of a square
      
    • To find the y-position of all other icons, we simply need the remainder of the index and the number of rows. The outcome x the width of a square will be added to the y position of the first icon (top left), for example:

      item 10 (index 9): 9%4 = 1
      y position = position of icon 0 + 1 x the height of a square
      
      item 17 (index 16): 16%4 = 0
      y position = position of icon 0 + 0 x the height of a square
      
  • Subsequently, we place the icons on the desktop, using the command:

    gvfs-set-attribute <path_to_dir_or_file> metadata::nautilus-icon-position x,y
    
  • Finally, we need to press F5 with the desktop in front, to apply the changed layout (refresh the desktop). If that is the case, it will be done immediately. If not, the script re- trys during 20 seconds if the desktop is in front, virtually presses F5 and breaks. If after 20 seconds the desktop still was not in front, you need to manually press F5.