39

How would I go about programmatically changing the desktop background in Mac OS X? I'd like to use python, but I'm interested in any way possible. Could I hook up to Terminal and call a certain command?

2
  • It is fine to do that on your own machine, or even to make it easy for others to set the background. However, do not write it as part of an application that automatically sets it; the desktop is for the user to choose, and never for an application to change without explicit permission from the user. Commented Jan 10, 2009 at 19:08
  • 3
    ...except in the case of office pranks. Commented Nov 5, 2013 at 20:41

13 Answers 13

45

From python, if you have appscript installed (sudo easy_install appscript), you can simply do

from appscript import app, mactypes
app('Finder').desktop_picture.set(mactypes.File('/your/filename.jpg'))

Otherwise, this applescript will change the desktop background

tell application "Finder"
    set desktop picture to POSIX file "/your/filename.jpg"
end tell

You can run it from the command line using osascript, or from Python using something like

import subprocess

SCRIPT = """/usr/bin/osascript<<END
tell application "Finder"
set desktop picture to POSIX file "%s"
end tell
END"""

def set_desktop_background(filename):
    subprocess.Popen(SCRIPT%filename, shell=True)
Sign up to request clarification or add additional context in comments.

8 Comments

Note that in Mac OS X 10.7 this will only change the desktop image of the current desktop, but not of all desktops!
Note also that it will only affect the desktop of the monitor that has the menu bar, not the desktops on the other monitor. Is there any way to make it affect the other desktop?
There is a one-line solution that works without wrapping osascript in a python script.
The AppleScript can be simplified to one line as tell application "Finder" to set desktop picture to POSIX file "/your/filename.jpg", and you can run it from a terminal with osascript -e 'tell application "Finder" to set desktop picture to POSIX file "/your/filename.jpg"'.
I used appscript , if my wallpaper name and location is same, the image doesn't refresh. I am using PIL to change the same image with different text, when I run it, nothing changes. But when I restart my laptop the latest changes reflect. I think something is missing in the appscript answer. I have to use killall Dock to refresh the wallpaper. Any ideas without using killall Dock
|
21

If you are doing this for the current user, you can run, from a shell:

defaults write com.apple.desktop Background '{default = {ImageFilePath = "/Library/Desktop Pictures/Black & White/Lightning.jpg"; };}'

Or, as root, for another user:

/usr/bin/defaults write /Users/joeuser/Library/Preferences/com.apple.desktop Background '{default = {ImageFilePath = "/Library/Desktop Pictures/Black & White/Lightning.jpg"; };}'
chown joeuser /Users/joeuser/Library/Preferences/com.apple.desktop.plist

You will of course want to replace the image filename and user name.

The new setting will take effect when the Dock starts up -- either at login, or, when you

killall Dock

[Based on a posting elsewhere, and based on information from Matt Miller's answer.]

1 Comment

this solution no longer works as of Mavericks which has another one-liner that will do the trick.
12

I had this same question, except that I wanted to change the wallpaper on all attached monitors. Here's a Python script using appscript (mentioned above; sudo easy_install appscript) which does just that.

#!/usr/bin/python

from appscript import *
import argparse

def __main__():
  parser = argparse.ArgumentParser(description='Set desktop wallpaper.')
  parser.add_argument('file', type=file, help='File to use as wallpaper.')
  args = parser.parse_args()
  f = args.file
  se = app('System Events')
  desktops = se.desktops.display_name.get()
  for d in desktops:
    desk = se.desktops[its.display_name == d]
    desk.picture.set(mactypes.File(f.name))


__main__()

Comments

6

Building on dF.'s answer, you could do it with Apple Script without Finder and you can do it for multiple desktops.

To set the wallpaper for desktop i (desktop numbers start at 1):

tell application "System Events"
    set currDesktop to item i of desktop
    set currDesktop's picture to "image_path"
end tell

This is what I ended up doing (in Python):

SET_DESKTOP_IMAGE_WRAPPER = """/usr/bin/osascript<<END
tell application "System Events"
{}
end tell
END"""

SET_DESKTOP_IMAGE = """
set currDesktop to item {idx} of desktops
set currDesktop's picture to "{image_path}"
"""

def set_wallpapers(images):
    """ images is an array of file paths of desktops """

    script_contents = ""
    for i, img in enumerate(images):
        idx = i+1
        script_contents += SET_DESKTOP_IMAGE.format(idx=idx, image_path=img)

    script = SET_DESKTOP_IMAGE_WRAPPER.format(script_contents)
    subprocess.check_call(script, shell=True)

Sometimes, the desktop images don't appear immediately. I don't know why this happens, but restarting the dock fixes it. To do that from python:

subprocess.check_call("killall Dock", shell=True)

By the way, you can get the number of desktops on the system using this AppleScript code:

tell application "System Events"
    get the number of desktops
end tell

you can use that with subprocess.check_output to get the output

Comments

4

You can call "defaults write com.apple.Desktop Background ..." as described in this article: http://thingsthatwork.net/index.php/2008/02/07/fun-with-os-x-defaults-and-launchd/

The article also goes into scripting this to run automatically, but the first little bit should get you started.

You might also be interested in the defaults man pages: http://developer.apple.com/documentation/Darwin/Reference/ManPages/man1/defaults.1.html

1 Comment

The "thingsthatwork.net" link isn't active anymore
3

The one-line solution for Mavericks is:

osascript -e 'tell application "Finder" to set desktop picture to POSIX file "/Library/Desktop Pictures/Earth Horizon.jpg"'

1 Comment

Like so many other answers, this does nothing if I run it from a fullscreen app.
2

There are a default collection of quality images in:

/Library/Desktop Pictures/

To automate the selection of one of these across all desktops, without a 3rd party dependency:

osascript -e 'tell application "System Events" to set picture of every desktop to "/Library/Desktop Pictures/Solid Colors/Stone.png"'

Comments

2

Put the following in your ~/.bashrc

function wallpaper() {
    wallpaper_script="tell application \"Finder\" to set desktop picture to POSIX file \"$HOME/$1\""
    osascript -e $wallpaper_script 
}

Use like so:

wallpaper /path/to/image.png

1 Comment

Combine your answer with @0xADADA above and finally there is a way to rotate all desktop backgrounds when using multiple monitors to the same image. Yay!
2

You can do this without killall Dock by running a Swift script from your Python script.

Create a chwall.swift file with the following code:

#!/usr/bin/env swift

import Cocoa

do {
    // get the main (currently active) screen
    if let screen = NSScreen.main {
        // get path to wallpaper file from first command line argument
        let url = URL(fileURLWithPath: CommandLine.arguments[1])
        // set the desktop wallpaper
        try NSWorkspace.shared.setDesktopImageURL(url, for: screen, options: [:])
    }
} catch {
    print(error)
}

Now run the above chwall.swift file with subprocess in Python.

import subprocess

subprocess.run(["./chwall.swift", "/path/to/your/wallpaper/file.png"])

1 Comment

This does nothing if I run it from a fullscreen app.
1

To add to Matt Miller's response: you can use subprocess.call() to execute a shell command as so:

import subprocess
subprocess.call(["defaults", "write", "com.apple.Desktop", "background", ...])

Comments

1

I found this to work (need to import subprocess). This changes every desktop background so you can run the code at fullscreen.

SCRIPT = """/usr/bin/osascript<<END
tell application "System Events"
tell every desktop
 set picture to "%s"
end tell
end tell
END"""

def set_desktop_background(filename):
    subprocess.Popen(SCRIPT%filename, shell=True)

Built upon dF.'s answer

Comments

0

You could also use py-appscript instead of Popening osascript or use ScriptingBridge with pyobjc which is included in 10.5 but a bit more cumbersome to use.

Comments

0

Another way to programmatically change the desktop wallpaper is to simply point the wallpaper setting at a file. Use your program to overwrite the file with the new design, then restart the dock: killall Dock.

The following depends on Xcode, lynx and wget, but here's how I automatically download and install a monthly wallpaper on Mountain Lion (shamelessly stolen and adapted from http://ubuntuforums.org/showthread.php?t=1409827) :

#!/bin/bash
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/opt/local/bin
size=1440
dest="/usr/local/share/backgrounds/wallpaperEAA.jpg"
read -r baseurl < <(lynx -nonumbers -listonly -dump 'http://www.eaa.org/en/eaa/aviation-education-and-resources/airplane-desktop-wallpaper' | grep $size) &&
wget -q "$baseurl" -O "$dest"
killall Dock

Dump it into /etc/periodic/monthly/ and baby, you got a stew goin!

4 Comments

Will killing the dock cause problems if the user is in the middle of something?
Not that I've noticed. It just refreshes the background and dock items.
is there a way of doing this without killing the dock. I have written a script to refresh wallpaper every 5 seconds, killall Dock in that case will refresh my items every 5 seconds.
@thenakulchawla I added an answer to do this without killall Dock.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.