Script to change wallpaper

klykly
Posted:
in macOS edited January 2014
Could someone please PLEASE help! I've spent countless hours trying to get this single simple little thing to work (I've googled and tried applescripting so much my head's got a permanent migrain):



I need to change the wallpaper to a random picture in a given folder ON DEMAND.



When I was still using good old linux, this can be accomplished in 4 simple lines:

Code:


#!/bin/bash

dir=~/docs/pictures/

pics=(${dir}*)

numpics=${#pics[*]}

dcop kdesktop KBackgroundIface setWallpaper ${pics[$((RANDOM%numpics))]} 6







Now, it seems that (really unfortunately) the only thing that can talk to anything in OS X is the hideous applescript, no nice dcop interface that you can call from the command line or any other language (ala KDE), or nice bang commands that can be as easily used from anywhere (ala Litestep for Win32). So the choices were applescript, or things like osascript and ruby-cocoa in which case you have to write applescript anyways. I finally admitted defeat: I had to use applescript.



Now after lots of googling and hacking around, I finally came up with this:



Code:


tell application "Finder"

set pfiles to files of (folder "Pictures:Wallpapers" of home) as alias list

set desktop picture to some item of pfiles

end tell







(aside: why apple thinks that 'files "x" of folder "y" of folder "z" of folder "annoyed" of "the long label for my root drive"' is easier than "/annoyed/z/y/*" is beyond me)



This seemed to work. Joy!



However, it looks like this setting isn't saved across sessions If I reboot, I'm back to my old wallpaper again. I simply don't get why this isn't saved properly.



Then I tried the hacky method: if applescript and whatever facilities can't handle things properly, fine, I'll just do it in good old bash, at least hopefully, it can reload the current file that's already assigned to it.



Code:


#!/bin/bash

dir=~/Pictures/Wallpapers/



pics=(${dir}*)



numpics=${#pics[*]}



cd ~/Pictures

rm -f wallpaper.jpg

cp "${pics[$((RANDOM%numpics))]}" wallpaper.jpg



osascript -e "tell application \\"Finder\\"" -e "set desktop picture to file

\\"Pictures:wallpaper.jpg\\" of home" -e "end tell"







But no dice, the file copying and everything happens correctly, however the applescript just refuses to reload the file for display as the wallpaper.



Could someone please help? (I know there's a change wallpaper at intervals option-even other scripts I've seen online do this too-but this isn't what I want).



I bought a Macbook Pro with money I didn't have and starved myself because I believed in the superiority of OS X and the mac design, however I can't seem to get Mac OS to do this one simple little thing



Could someone please help?



Thanks!
«1

Comments

  • Reply 1 of 28
    lundylundy Posts: 4,466member
    1) It isn't "wallpaper", it's a "Desktop Picture".

    2) Applescript rules.

    3) If you read the documentation, you would see the Applescript commands "POSIX Path" and "POSIX File" which allow you to use the POSIX notation.

    4) The code you have is correct, except Desktop Pictures should be in the Desktop Pictures folder:



    Code:




    tell application "Finder"

    set desktop picture to (some file of (path to desktop pictures folder))

    end tell





  • Reply 2 of 28
    gene cleangene clean Posts: 3,481member
    Quote:

    Originally posted by lundy

    [B]1) It isn't "wallpaper", it's a "Desktop Picture".



    It isn't a Desktop Picture, because 90%+ of people using computers call it Wallpaper.
  • Reply 3 of 28
    klykly Posts: 21member
    Quote:

    4) The code you have is correct, except Desktop Pictures should be in the Desktop Pictures folder



    Isn't a large part of the Mac OS philosophy that the USER has control of where he wants his files, programs, pictures or anything for that matter? It's one of the beauties and purposes of things like appfolders: the user can quite simply manage his own software, and place programs where he wants them, and when he wants it deleted, he simply does just that. There's none of the nightmares of the Windoze registry and Windoze add/remove programs.



    The code you provided is correct, but it does exactly the same as what I tried in the previous script, that being it does exactly also what that didn't: save the state across sessions.



    Thanks
  • Reply 4 of 28
    klykly Posts: 21member
    Quote:

    3) If you read the documentation, you would see the Applescript commands "POSIX Path" and "POSIX File" which allow you to use the POSIX notation.



    Could you point me to some decent documentation? Thanks. Looking on the apple dev site gives only either very brief introductory material or antiquated Mac OS 8 stuff. Couldn't even find a list of predefined variables, I actually just guessed "home". Also, this of course isn't the apple way, you still have to convert it back to applescript (can't use it natively) using applescriptness of course:



    Code:


    set p to "/usr/local/bin/"

    set a to POSIX file p







    Quote:

    2) Applescript rules.



    Spend a few months with Python or Ruby and come back and tell me this. Though I haven't started this thread to start a religious war (I won't go into the reasons why I think applescript is the most inelegant and unpredictable language, possibly even worse than VB, since this isn't what the post is about--and I don't want to start flaming a moderator), the point is however that people's preferences differ quite drastically as can be seen here even just between you and me, but where in any other environment you'll have a whole slew of languages (and other ways such as just a simple comand line) to interact with other programs and libraries, in Mac OS you're stuck with Applescript. Learn to like it, you have no (easy) alternative. I guess that's why so many like it then, there isn't a choice not to.
  • Reply 5 of 28
    placeboplacebo Posts: 5,767member
    As I recall, the way desktop backgrounds work in Mac OS X is a bit strange, because it loads the image into some hidden cache when you set it as your background. Even if you set an image as your background and subsequently delete the image file, the background will remain until you restart or log out and back in.



    So essentially, there's no way of changing it in-session through manipulating files; you'll have to find a way of telling System Prefs or whatever handles the desktop background instead.
  • Reply 6 of 28
    lundylundy Posts: 4,466member
    The POSIX file and POSIX path commands are in the Dictionary of Standard Additions.



    POSIX file?n : A file object specified with a POSIX (slash)-style pathname.



    properties

    POSIX path (Unicode text, r/o) : the POSIX (slash)-style path of a file or alias object
  • Reply 7 of 28
    lundylundy Posts: 4,466member
    Quote:

    The code you provided is correct, but it does exactly the same as what I tried in the previous script, that being it does exactly also what that didn't: save the state across sessions.



    I can't reproduce that behavior here. I ran the above code that I posted:



    tell application "Finder" to set desktop picture to (some file of (path to desktop pictures folder))



    It selected a desktop picture from the files in the folder, and it persisted across 2 logouts/logins and across 2 restarts.



    You can try posting at http://bbs.applescript.net/viewforum.php?id=2 and see if anyone has seen this behavior.
  • Reply 8 of 28
    lundylundy Posts: 4,466member
    Quote:

    Originally posted by Gene Clean

    It isn't a Desktop Picture, because 90%+ of people using computers call it Wallpaper.



    He's coding in AppleScript, which calls it a "desktop picture". I don't see how you can say it's not.
  • Reply 9 of 28
    klykly Posts: 21member
    Hey



    It looks like what I said about saving session before was a bit simplistic. Here's what it does in detail:



    When the script is initially run it changes the wallpaper. Run it a few more times and it'll always do it. Reboot and this wallpaper (I'll call it wall1) will appear next time you log in. However, now run the script a few more times. Wallpaper changes. Reboot, and it'll revert to wall1. No matter how many times you run the script in future, it'll now always revert to wall1 on reboot. Only if you manually change the wallpaper by hand will it change. Then if you run script again it'll change again and save that one (wall2). Any subsequent changes are then lost and wall2 will always show up when logging in. And so on...



    Very peculiar behaviour :/ Not sure why it would be doing this.



    Thanks
  • Reply 10 of 28
    addaboxaddabox Posts: 12,665member
    Quote:

    Originally posted by Gene Clean

    It isn't a Desktop Picture, because 90%+ of people using computers call it Wallpaper.



    Which is why the dock is actually called "the task bar" and aliases are actually called "shortcuts.
  • Reply 11 of 28
    lundylundy Posts: 4,466member
    I didn't test that particular scenario, but it may be an obscure bug, or it could be some other extension you have installed. You can report it at bugreport.apple.com



    If you really want a workaround, you should keep a prefs file for your script and then have the script run at every login and reload the correct picture from the prefs file. This is pretty simple with Cocoa's defaults system.



    Here's how:



    1) Add a line after the desktop picture setting line that stores the current desktop picture in a prefs file.

    2) Add a second short script to your Login Items in the Accounts preference pane so that it runs at every login to reload the saved picture path.



    To store the path to the current desktop picture in your own private prefs file, first decide on a name for the file. This would by convention be "com.yourname.scriptname.plist" and will by default be stored in ~/Library/Preferences. So in your case we could have a pref file that is going to be named "com.kLy.desktopPicture.plist".



    The code to do this is

    Code:




    tell application "Finder"

    set desktop picture to some file of (path to desktop pictures folder)

    set x to desktop picture as alias as string

    do shell script "defaults write com.kLy.desktopPicture pathToPicture " & (quoted form of x)

    end tell









    This will generate a new random picture and save the path of the picture as a string in the file "~/Library/Preferences/com.kLy.desktopPicture.plist".



    All that is left is to write the brief script that runs at login and reads the value back in and resets the desktop picture (add this script to the list of Login Items in the Accounts Preference pane):



    Code:




    tell application "Finder"

    set desktop picture to (do shell script "defaults read com.kLy.desktopPicture pathToPicture") as alias

    end tell









    I tested these scripts and they work on my machine.
  • Reply 12 of 28
    gene cleangene clean Posts: 3,481member
    Quote:

    Originally posted by lundy

    He's coding in AppleScript, which calls it a "desktop picture". I don't see how you can say it's not.



    Because he's not calling the specific function in AppleScript, he's just calling the file he named



    Quote:

    wallpaper.jpg



    That's the name of the file. Calling that file as 'Desktop Picture.jpg' won't help him much.



    addabox:



    Quote:

    Which is why the dock is actually called "the task bar" and aliases are actually called "shortcuts.



    Maybe you should pay more attention to what we're talking about, no?
  • Reply 13 of 28
    klykly Posts: 21member
    Hey lundy



    Thanks. This does work however it's rather a workaround solution. The old wallpaper still gets loaded and after my other login items load and the applescript dock icon bounces around a bit, the wallpaper finally changes. I wasn't hoping for this as an elegant solution But thanks a lot for the effort!



    As for the whole desktop picture / wallpaper debate. People, please stop! Microsoft decided to call it one thing and Apple another. It's that simple. In terms of the physical metaphor for the GUI, Desktop Wallpaper makes a lot more sense (why the hell would you stick wallpaper on your desk?). But both Windoze and *nix GUI's (KDE, Gnome, blackbox, e16/17 etc) ALL call it wallpaper and so it has largely stuck. Besides, "Desktop Picture" is a lot more of a mouthful. However why does Desktop Pictures go in Library and not Pictures? I'd think the latter is more intuitive and more accesible to the general user.
  • Reply 14 of 28
    klykly Posts: 21member
    By the way, I was always wondering why the hell applescripts were SO dang slow, especially on startup, it feels like it tries to load up 20 JVM's for it to execute the script.



    When I was fiddling with this, I found out why: try compile an applescript to binary then do a "file bla.scpt". What do you get? A Mach-O PPC binary. If you check the binaries of any universal app, you'd get a listing for both PPC and i386 (or just i386 for an intel binary). This means it's getting run through Rosetta. No wonder a simple "hello world" in applescript takes way WAY longer than even the most complex bash / python scripts. It appears that a lot of the applescript underpinnings are still too heavily dependant on the original PPC architecture to make a successful transition to x86. Just an aside.
  • Reply 15 of 28
    lundylundy Posts: 4,466member
    Quote:

    Originally posted by kLy

    I found out why: try compile an applescript to binary then do a "file bla.scpt". What do you get? A Mach-O PPC binary. If you check the binaries of any universal app, you'd get a listing for both PPC and i386 (or just i386 for an intel binary). This means it's getting run through Rosetta.



    That's just the wrapper code.



    The script is never compiled to binary - only to bytecode. In fact, every time you open a "compiled" script, Script Editor decompiles it from the bytecode on the fly to display it for you.
  • Reply 16 of 28
    klykly Posts: 21member
    Yes I do realise the code isn't actually "compiled", but the thing is that it's still PPC wrapper code that gets run, and that gets run through Rosetta.
  • Reply 17 of 28
    chrisgchrisg Posts: 239member
    Quote:

    Originally posted by kLy

    Yes I do realise the code isn't actually "compiled", but the thing is that it's still PPC wrapper code that gets run, and that gets run through Rosetta.



    If you save it as an Application Bundle that is Universal and should open faster on intel machines.
  • Reply 18 of 28
    mynameheremynamehere Posts: 560member
    Quote:

    Originally posted by Gene Clean

    It isn't a Desktop Picture, because 90%+ of people using computers call it Wallpaper.



    Bear in mind that is the same demographic which can't find the US on a map...



    That having been said, thereis the ol' "Change Desktop" function in the System Prefs, which doesn't really answer the question, but is nonetheless an option.
  • Reply 19 of 28
    klykly Posts: 21member
    Quote:

    Originally posted by ChrisG

    If you save it as an Application Bundle that is Universal and should open faster on intel machines.



    Tried that, yes it does seem considerably faster, thanks



    One serious glitch I've noticed is that it uses the exact same random sequence each time (ie. the exact same sequence of "random" wallpapers get shown), or is there some way of seeding the RNG in Applescript?



    Thanks
  • Reply 20 of 28
    lundylundy Posts: 4,466member
    Code:




    tell application "Finder"

    set theList to files of (path to desktop pictures folder)

    set theNum to random number from 1 to (count theList) with seed (time of (current date))

    set desktop picture to item theNum of theList

    end tell















    Quote:

    Originally posted by kLy

    Tried that, yes it does seem considerably faster, thanks



    One serious glitch I've noticed is that it uses the exact same random sequence each time (ie. the exact same sequence of "random" wallpapers get shown), or is there some way of seeding the RNG in Applescript?



    Thanks




Sign In or Register to comment.