Desktop icons

Posting has been infrequent here at ANIAT because my real job has been busy. More work means more communication with clients, and in recent years a lot of that communication has been done through real-time screen sharing to discuss the particulars of drawings and photographs. I use GoToMeeting for this, but there are plenty of alternatives. This week, I learned a trick from Craig Hockenberry that will make screen sharing easier.

For me, the main annoyance with preparing for a screen sharing session is cleaning my Desktop. I don’t think I keep a particularly messy Desktop, but I do use it as a temporary staging area for files that I’m currently working with but don’t know the ultimate disposition of. Quite often, I need to have a GoToMeeting session on Project A when my Desktop is half filled with files from Projects B and C—files the Project A client shouldn’t see.

Messy Desktop

My habit has been to sweep them up and drop them into a new folder on the Desktop with an innocuous name like “other” or “refile.” This means I have to go back in after the GTM session and restore the Desktop to its previous state, which usually had some sort of spatial organization. Not the most onerous work in the world, but something I’d rather not do. In fact, because I usually end these GTM sessions with a list of action items for Project A that I have to think about and organize, I usually forget to restore my Desktop and then have to go hunting for the hidden files a day or two later, by which time I’ve lost track of how I had them previously positioned on the Desktop.

I’ve used Backdrop, which covers the Desktop with a solid color or a background image, but because it becomes part of the stack of apps running on my machine, it gets in my way as I shift from app to app in a GTM session. I’ve used it a lot for taking clean screenshots over the years, but it doesn’t fit in well with screen sharing.

A better solution comes from this tweet by Craig Hockenberry:

Just wrote a simple shell script to toggle the Finder’s desktop icons (for doing screenshots). Enjoy!…

Craig Hockenberry (@chockenberry) Apr 27 2016 5:30 PM

Craig’s script uses the Finder’s CreateDesktop setting to change (or report on) the visibility of the icons on the Desktop. This is a hidden setting that you won’t run across in the Finder’s Preferences; it’s available only through the defaults command. Before reading Craig’s source code, I’d never heard of it before. What the script does is check the CreateDesktop setting through defaults read and then either change the setting (through defaults write), eliminate the setting (through defaults delete), or tell you its status, depending on the argument you passed to the script.

It’s a good script, and I learned a lot from it, but it’s a little too verbose for my taste, especially since I expect to use it often. You have to pass it an argument (“on,” “off,” or “status”), and it always writes a response to Terminal. What I wanted was command that would toggle the visibility of the Desktop icons without requiring an argument and that would do its work silently—I figure I can tell what it did by looking at my screen.

In messing around with Craig’s script, I learned a lot about how defaults handles Boolean settings (very leniently) and how the CreateDesktop setting itself is treated. What I ended up with doesn’t look much like Craig’s script, but it’s heavily indebted to him.

Here’s the script, desktop:

 1:  #!/bin/bash
 3:  # Toggle the visibility of Desktop icons.
 5:  # Desktop icons are visible if the CreateDesktop setting is missing or
 6:  # if it exists and is set to 1, true, yes, or on (case insensitive).
 7:  # Desktop icons are hidden if the CreateDesktop setting exists and
 8:  # is set to any value other than 1, true, yes, or on.
10:  # The $icons variable is the value of CreateDesktop if it exists or is
11:  # the empty string if it doesn't.
13:  icons=`defaults read CreateDesktop 2> /dev/null`
15:  shopt -s nocasematch
16:  case "$icons" in
17:    "" | "1" | "true" | "yes" | "on" )
18:      defaults write CreateDesktop 0 && killall Finder;;
19:    * )
20:      defaults write CreateDesktop 1 && killall Finder;;
21:  esac

The way it works is simple, if your Desktop icons are currently visible, issuing desktop from the Terminal will make them invisible; if they’re currently invisible, desktop will make them visible again.

Clean Desktop

I think the comments in desktop do a decent job of explaining the script, but a few more words may be in order.

First, there’s the way defaults works with Booleans. As best I can tell, defaults considers any one of these to be true:

The words can be spelled with any combination of upper and lower case letters. Therefore

defaults write CreateDesktop yEs

will make the Desktop icons visible, which seems a little weird. Anyway, that’s why the nocasematch option is turned on in Line 151 and why the first case condition in Line 17 has so many alternatives. Any value other than those four is taken to be false.

If you’re not used to i/o redirection, the 2> /dev/null in Line 13 may seem a little odd. What it does is take any standard error output from the defaults read command and get rid of it (/dev/null is the Unix memory hole). Normally, defaults read returns the value of whatever setting you’re inquiring about to standard output, but if that setting doesn’t exist it tells you so via standard error. The purpose of 2> /dev/null is to handle that case quietly. When Line 13 is done, the variable icon will have either the value of CreateDesktop or will be the empty string.

After changing the CreateDesktop setting, you have to restart the Finder to get that setting to “take.” Craig does that through an AppleScript one-liner and the open command. I prefer the killall command. I use it in combination with defaults write and the && construct in Lines 18 and 20 to restart the Finder after the defaults write command finishes, but only if defaults write was successful. This is a common Unix trick for running multiple commands dependently.

With desktop, I now have a quick and easily reversed command for hiding Desktop icons while screen sharing. Thanks to Craig for the instruction and inspiration.

Update April 30, 2016 at 10:49 AM
So many suggestions and alternatives, I don’t feel I can give them all a fair shake here. Look through the replies (and replies to replies) to this tweet to see the many ways to accomplish roughly the same thing. A couple of things should be addressed here, though.

First, there’s the safety issue. When writing this post in my head, I planned to include a few sentences on the relative safety of Craig Hockenberry’s choice to use

osascript -e 'tell application "Finder" to quit'
open -a Finder

to quit and restart the Finder as opposed to my choice to use

killall Finder

Craig’s choice is probably safer if the script is invoked when the Finder is in the middle of some action, but I haven’t been able to demonstrate a problem with using killall.

I’ve been using killall to restart the Finder for many years, and it’s never bitten me in the butt, but that may be because I’d never considered using it when the Finder was actively doing something. I decided to test what would happen if I ran my desktop script while the Finder was in the middle of copying a file.

I made a 2 GB file with the mkfile 2g bigfile command and option-dragged it to a new location to start a Finder copy. While the progress bar was moving, I switched to Terminal and ran desktop. The Finder went through its restart, which interrupted the copy, but the copy finished successfully when the Finder returned. I confirmed that the two files were identical by using cmp to compare them byte by byte. I repeated this test several times with different sized files and with files that weren’t all zeros (mkfile creates files that are all zeros). The copied files were always identical to the originals despite the interruption.

This is not absolute proof that killall is safe, but I feel comfortable with it, especially since I have no plans to use desktop when the Finder is in the middle of a file operation.

Finally, I want to explain why I made desktop act as a toggle. I could—and initially did—write two separate scripts or functions, one that turns the icons off

defaults write CreateDesktop 0 && killall Finder

and one that turns them back on

defaults write CreateDesktop 1 && killall Finder

I decided to put both commands into a single script that chooses which to run based on the current visibility of the icons. There are three advantages to this:

  • I’m never going to want to turn the icons on when they’re already on or off when they’re already off.
  • I don’t have to remember two command names.
  • I can bind the running of desktop to a keystroke using Keyboard Maestro. That keystroke will then act as a sort of pushbutton on/off switch, which is a very common device. Our TVs, radios, computers, and phones typically don’t have separate on and off buttons. Why should our software?

Toggles aren’t, of course, the answer to everything. But I thought this case, where the current visibility state is obvious and the only useful action is to switch from one visibility state to the other, was ideal for a toggle.

  1. Don’t worry about the nocasematch option infecting your later work—when the script is done, it gets turned back to whatever you had it set to.