Mavericks read current desktop background filename?

Good stuff. BTW, scripts might error if the user has the changing of the desktop off. Just nit picking. Nice scripts.

Have a good day,
kel

This works nicely in osascript (this is how I plan to get this into geek tool and overlay over the desktop).

Thank you. The objective-C stuff was way over my head.

Is there a way to format output to strip the path?

Thanks!

Thanks for such a simple script! This is very much like what I was looking for, as the shell script I used in Lion doesn’t work in Mavericks.

The only thing missing is a way to produce the output for all work spaces. Is there a simple way to do more than “current desktop” in Mavericks?

Just wanted to share a technique related to the current topic that might be helpful. It returns the current desktop’s picture placement setting, which is not available through System Events. The three-step procedure consists of:

(1) relaunching the Dock to make current the com.apple.spaces plist file
(2) getting the uuid of the current desktop from the com.apple.spaces plist file
(3) getting the current picture placement setting of the current desktop from the com.apple.desktop plist file (located at “[current desktop’s uuid]” > default > Placement in the plist file)

do shell script "" & ¬
	"killall Dock ;" & ¬
	"sleep 1 ;" & ¬
	"u=$(defaults read com.apple.spaces | sed -En '/Current Space/,/uuid =/s/^.+uuid = ([\"][^\"]*[\"]).+$/\\1/p') ;" & ¬
	"defaults read com.apple.desktop | sed -En '/'\"$u\"'/,${/default =/,/Placement =/s/^.+Placement = ([a-zA-Z]+);$/\\1/p;}' | egrep -m 1 .+"

This will return one of the following signifying the current desktop’s picture placement setting:

“Crop” (= preference pane’s “Fill Screen”)
“SizeToFit” (= preference pane’s “Fit To Screen”)
“FillScreen” (= preference pane’s “Stretch To Fill Screen”)
“Centered” (= preference pane’s “Center”)
“Tiled” (= preference pane’s “Tile”)

(I suspect the sed/egrep scripts can be tidied up a bit.)

Regarding the original question of this post, further investigation revealed the following:

The current desktop image is saved in com.apple.desktop > Background > spaces > [current desktop uuid] > default. The tricky part was discovering that the image is saved in different properties depending on whether the desktop is static or dynamic:

Static desktop (i.e., set to never rotate):
The image path is saved in the ImageFilePath property.

Dynamic desktop (i.e., set to rotate at a time interval, at sleep, or at login):
The image container path is saved in the ChangePath property.
The image name is saved in the LastName property.

In the latter case, the image path can be reconstructed as: image path = image container path + “/” + image name

The following shell script adjusts for the current desktop rotation status and returns the current desktop image path. As described in my prior post, it also returns the current desktop picture placement setting (Crop, SizeToFit, FillScreen, Centered, or Tiled), which is also not accessible through System Events.

set {imagePath, imagePlacement} to paragraphs of (do shell script "" & ¬
	"killall Dock ; " & ¬
	"sleep 1 ; " & ¬
	"currUuid=$(defaults read com.apple.spaces | sed -En '/Current Space/,/uuid *=/s/^.+uuid *= *([\"][^\"]*[\"]).+$/\\1/p') ; " & ¬
	"currDesktopSettings=$(defaults read com.apple.desktop | sed -En '/'\"$currUuid\"' *= *[{]/,/\"[^\"]*\" *= *[{]/{/default *=/,/[}][;]/p;}') ; " & ¬
	"rotationType=$(echo \"$currDesktopSettings\" | sed -En 's/^ +Change *= *([a-zA-Z]+)[;]$/\\1/p') ; " & ¬
	"[ \"$rotationType\" = Never ] " & ¬
	"&& " & ¬
	"imagePath=$(echo \"$currDesktopSettings\" | sed -En 's/^ +ImageFilePath *= *[\"]([^\"]+)[\"][;]$/\\1/p') " & ¬
	"|| " & ¬
	"imagePath=$(echo \"$currDesktopSettings\" | sed -En 's/^ +( ChangePath|LastName) *= *[\"]([^\"]+)[\"][;]$/\\2/p' | tr '\\n' '/' | sed -E 's/[/]+$//') ; " & ¬
	"imagePlacement=$(echo \"$currDesktopSettings\" | sed -En 's/^ +Placement *= *([a-zA-Z]+)[;]$/\\1/p') ; " & ¬
	"echo \"$imagePath\\n$imagePlacement\"")

Killing the Dock is necessary at least in some circumstances to assure that the plist file remains up-to-date. A side-effect of killing the Dock is a rotation to the next image if the desktop is dynamic, although the script does return the proper image path of the newly displayed image. If there were a way to keep the plist file up-to-date without having to kill the Dock, this unfortunate side-effect would be avoided, but I am unaware of how to do this.

How does killing the Dock keep a plist file up-to-date? And why would it matter when you’re not reading a plist file?

The shell script approach I presented retrieves the current desktop image from the com.apple.desktop.plist file. The Dock application does appear to be a (the?) principle application controlling Mission Control and its desktops. I learned from a post from Nigel Garvey on another thread that rebooting the Dock (by killing it; it reboots immediately) does update the plist file, and my experience corroborates that.

I have been working on an ASObjC app that manages the desktop image. Something happens in the app that keeps the com.apple.desktop.plist file up to date without the need to reboot the Dock, but I haven’t isolated what that something is yet. If and when I do, I’ll certainly post it.

Really, it doesn’t. There’s a common misconception that applications write their preferences to a plist file in the Preferences folder, and that the shell command defaults reads these files. That’s not actually what happens.

The plist files are read/written by a separate process. Applications and the defaults command actually communicate with that process, and not the files on disk (which, if the app is sandboxed or uses iCloud, can be stored elsewhere anyway).

This separate process caches the values and decides when to write to file, and as of Mavericks, it appears to be in no hurry after a change is made. And there’s no great need to, other than the fact that a complete system crash might mean something never gets written, because nothing else reads those files.

But the state of that file really only matters if you are trying to read it directly – it doesn’t matter if you are using defaults, which should give you the latest values.

I appreciate very much those insights into the inner workings of the defaults system.

I know from observation that the defaults read com.apple.desktop command in my shell script does return up-to-date desktop image data, but only if the Dock is rebooted by killing it. From your explanation of the intermediate defaults process to which the defaults read command is presumably talking, it would seem that defaults read should give me up-to-date data without any external interventions, and yet it doesn’t. Why isn’t it returning up-to-date data?

I’m not sure. It may something to do with the app and defaults having access to different domains, or there may be some quarantining to stop defaults-written values being used by a running app.

Actually, this might explain it:

“At runtime, you use an NSUserDefaults object to read the defaults that your application uses from a user’s defaults database. NSUserDefaults caches the information to avoid having to open the user’s defaults database each time you need a default value. The synchronize method, which is automatically invoked at periodic intervals, keeps the in-memory cache in sync with a user’s defaults database.”

Sorry for any misleading information. I don’t actually recall saying it. The only post of mine I can find here containing ‘killall Dock’ is one from three years ago where I used it to update the Dock from the plist file, not vice versa. It was common practice at the time to kill a process after modifying its plist file so that it (the process) would adopt the changes when it restarted. It worked with that particular script in Snow Leopard, but I’ve not had enough time to fool around with it in Mavericks.

Nigel, sorry for the incorrect reference! I had flipped it around in my mind.

Shane, In concert with your description of the defaults system, I’ve noticed that NSUserDefaults’s standardUserDefaults object is always immediately up to date within a running application. It behaves just like an NSDictionary (perhaps it is a dictionary?) The caching problem seems to arise when an outside application wants to access the standardUserDefaults object’s data.

Would that not suggest that the defaults read command does not get direct access to the standardUserDefaults object but rather to the synched data that standardUserDefaults writes sporadically?

One of the thing people testing sandboxed apps used to do was kill their prefs plist files to reset things. When Mavericks came out, they were told not to do this, because the stuff might not be written to disk as promptly as before. There was also a hint of surprise that this was happening, so it wouldn’t be unexpected if the system was, or even has been already, tweaked some more.

All of which means you probably shouldn’t assume the results under one OS will match those on other versions.

Is this is an intentional effort to keep an application’s defaults data out of the reach of other applications or simply a side-effect of the way the system is being implemented?

I suspect the latter, although that’s just a guess. There are ways sandboxed apps can share prefs, even on iOS. I think the problem they were trying to address was performance, and trying to improve it by hitting the disk less often.

I wanted to share some info since this thread helped me. The code to get the path to the current desktop picture in Mavericks when you have it set to change at an interval is inspired. I couldn’t figure it out in Mavericks so thanks everyone.

Anyway, I also wanted to know how I could be automatically notified when the desktop picture changes. I figured out that you can watch a certain folder for changes because changes in that folder correspond to the desktop picture being changed. That folder is ~/Library/Application Support/Dock. It seems there’s some database files in there and one of those files is being updated when the desktop pic changes.

So now I’ve setup a launch agent to watch that folder and run an applescript when something in that folder changes. It’s working perfectly in sync as the desktop changes.

I hope this helps someone else as much as the applescript code to find the current desktop picture has helped me.

NOTE: I tried briefly to read the db files in the Dock folder because they must hold the path to the desktop picture… but I wasn’t able to access it. Maybe someone else will have better luck. Please post how you did it if anyone figures it out.

I have a folder with 3000 images that contain all my desktop images, I’ve set them to rotate every 15 minutes. Sometimes I want to identify the file name of the current desktop image so I can delete it or identify it as a favorite.

Does anyone have an apple script that will find the location of the current desktop image in OS X Yosemite (10.10)? All the solutions I’ve found in forums only apply for earlier (sometimes much earlier) operating systems.

Operating system 10.11 is not in the list.
Anyone got an idea how to write this for El Capitan?

I realize this is a very old thread, but I had a script working perfectly (based on Nigel Garvey’s) to display the name and path of the current desktop image under several MacOS versions…until Big Sur. Now, the script result is correctly identifying the path, but not the correct image file. The heart of the script is
To identify the current image folder:
tell application “System Events” to set pFldr to pictures folder of current desktop
To identify the current image name:
set picturePath to pFldr & “/” & paragraph 1 of (do shell script "ls -tu " & quoted form of pFldr)

I’m definitely not anything approaching an expert, but pFldr is still providing the correct folder name.
As best as I can tell, the “ls -tu” command is no longer returning the correct file name, but I don’t know why. Did the bash shell change or did the MacOS behavior change with 11.6?

Any solution? I’d appreciate hearing from anyone more knowledgeable than me (which is pretty much everyone). TIA!