Last Monday a good friend who currently works abroad for an ad agency in New York city phoned me to ask if I could kindly write her a little AppleScript that creates and sets a wallpaper displaying the calendar of the last, current and next month on her desktop.
And as I still owed her a favour I quickly wrote a small script that did the trick. She loved it. But then her colleagues saw it and immediately flooded my inbox with new feature requets. Custom font and background color/image, positioning of the calendar and highlighting of the last and next month.
Well, I actually planned to spent my evenings reading a new and thrilling book (The Redeemer from Jo Nesbø), but then I found myself on the balcony writing a more elegant version of the initial script. And of course I am sharing my work with you and invite you to download and inspect the AppleScript below:
Lacurne - A customizable PDF wallpaper displaying the last, current & next month on your desktop (v0.6, ca. 153 KB)
The script was successfully tested on Intel and PowerPC based Macs running Mac OS X 10.5 Leopard.
Please note, that Lacurne requires Mac OS X 10.5 and does not support dual monitor setups.
To create and set a PDF wallpaper just open the script with a double click. If you want to open the configuration menu, then just drag and drop a Finder item onto the script’s icon:
In my opinion, Lacurne is yet another example for the great possibilities offered by the rich scripting environment in Mac OS X:
The calendar data is produced by the «cal» command, the PDF wallpaper is instantly(!) generated using Python and the desktop picture is finally updated with the Finder’s AppleScript dictionary. And all commands are glued together with our favourite language of automation, AppleScript, which also offers the basic GUI to create a convenient interface for the user. I just love this digital marble run!
All parts of the script can be viewed in Script Editor or a free text editor (Python script)!
Happy scripting!
Important: Opening and saving the below script code in Script Editor won’t result in a usable AppleScript! That is because Lacurne internally relies on several scripts, which are located inside its Script bundle. Therefor please download the complete script here.
-- created: 25.06.2008
-- modified: 05.07.2008
-- version: 0.6
-- tested on/with:
-- ¢ Intel- & PowerPC based Macs on Mac OS X 10.5.3 Leopard
-- requires:
-- ¢ Mac OS X 10.5 Leopard
-- note:
-- ¢ this does not work for dual monitor setups
-- history:
-- ¢ version 0.6
-- - added support for background images
-- ¢ version 0.5
-- - first public release
-- This AppleScript creates and sets a PDF wallpaper which displays a calendar for the last,
-- current and next month on your desktop.
-- It allows to adjust many of its settings, just drag a Finder item onto it to open the
-- configuration menu.
-- Lacurne? «La»st, «cur»rent and «ne»xt month!
property myname : "Lacurne"
-- I am called when the user drops Finder items onto the script's icon
-- I am used to display the configuration menu where the user can
-- easily customize the small desktop calendar
on open dropitems
-- the script responsible for displaying the configuration menu is saved
-- in a separate script file which must be loaded first
try
set cfscriptpath to (((path to me) as Unicode text) & "Contents:Resources:Scripts:config.scpt")
set config to load script (cfscriptpath as alias)
-- we need to pass our application path to the script object, so that
-- it can easily locate the preferences script and the PDF help document
-- inside the application bundle
config's init((path to me) as Unicode text)
config's start()
on error errmsg number errnum
my dsperrmsg(errmsg, errnum)
end try
end open
-- I am called when the user opens the script with a double click
on run
try
-- loading the preferences
set prefs to my loadprefs()
if prefs is missing value then
set errmsg to "Could not load the preferences from inside my application bundle (prefs.scpt)."
my dsperrmsg(errmsg, "--")
return
end if
-- path to the script's application support folder
set asfolderpath to (((path to application support folder from user domain) as Unicode text) & myname & ":")
-- creating the script's application support folder if it does not already exists
try
set asfolderalias to asfolderpath as alias
on error
set command to "mkdir -p " & quoted form of POSIX path of asfolderpath
do shell script command
end try
-- file path to the PDF wallpaper to be produced
set wpfilepath to asfolderpath & myname & ".pdf"
-- trying to delete an old PDF wallpaper file
try
do shell script "rm " & quoted form of (POSIX path of wpfilepath)
end try
-- getting the display resolution of the main monitor
set {dspwidth, dspheight} to my getdisplayresolution()
-- getting the current month and year as string values
set curdate to current date
set strmonth to ((month of curdate) as integer) as Unicode text
set stryear to ((year of curdate) as integer) as Unicode text
-- getting user chosen values from the preferences
-- we need to replace the comma with a point in some values,
-- as Python only accepts a point as the decimal separator, not a comma
set fontname to prefs's fontname
set fontsize to my searchnreplace(",", ".", (prefs's fontsize as Unicode text))
-- x, y position of the calendar on the desktop
set xpos to my searchnreplace(",", ".", (prefs's xpos as Unicode text))
set ypos to my searchnreplace(",", ".", (prefs's ypos as Unicode text))
-- creating the background color string, e.g. "0.9, 1.0, 0.8"
set {bgredval, bggreenval, bgblueval} to prefs's bgcolor
set bgredval to my searchnreplace(",", ".", (bgredval as Unicode text))
set bggreenval to my searchnreplace(",", ".", (bggreenval as Unicode text))
set bgblueval to my searchnreplace(",", ".", (bgblueval as Unicode text))
set bgcolor to bgredval & space & bggreenval & space & bgblueval
-- creating the font color string, e.g. "0.9, 1.0, 0.8"
set {ftredval, ftgreenval, ftblueval} to prefs's fontcolor
set ftredval to my searchnreplace(",", ".", (ftredval as Unicode text))
set ftgreenval to my searchnreplace(",", ".", (ftgreenval as Unicode text))
set ftblueval to my searchnreplace(",", ".", (ftblueval as Unicode text))
set fontcolor to ftredval & space & ftgreenval & space & ftblueval
-- tint value to highlight the last and next month
set fonttint to my searchnreplace(",", ".", (prefs's fonttint as Unicode text))
set bgimgpath to prefs's bgimgpath
-- in case the background image file is missing we display an error message
if bgimgpath is not missing value then
if not itempathexists(bgimgpath) then
set errmsg to "We could not locate the background image file supposed to be at:" & return & return & bgimgpath
my dsperrmsg(errmsg, "--")
return
end if
end if
-- finally creating the PDF wallpaper displaying last, current and next month
my crtwallpaper(dspwidth, dspheight, stryear, strmonth, fontname, fontsize, xpos, ypos, bgcolor, fontcolor, fonttint, bgimgpath, wpfilepath)
-- if the creation of the desktop wallpaper failed we display an error message
if not itempathexists(wpfilepath) then
set errmsg to "The creation of the desktop wallpaper simply failed. And I don't know exactly why."
my dsperrmsg(errmsg, "--")
return
end if
-- file path to the PNG image used as an update helper: if you try to update the desktop picture and
-- the file path of your new image is the same as the current one, you won't see
-- the new image. therefor we first «switch» to the small PNG image before updating
-- the wallpaper.
set switchpicpath to (((path to me) as Unicode text) & "Contents:Resources:switch.png")
tell application "Finder"
set desktop picture to (switchpicpath as alias)
end tell
tell application "Finder"
set desktop picture to (wpfilepath as alias)
end tell
on error errmsg number errnum
my dsperrmsg(errmsg, errnum)
end try
end run
-- I am loading the preferences script object and return it.
-- If it cannot be loaded I return «missing value» instead.
on loadprefs()
try
set pfscriptpath to (((path to me) as Unicode text) & "Contents:Resources:Scripts:prefs.scpt")
set prefs to load script (pfscriptpath as alias)
return prefs
on error
return missing value
end try
end loadprefs
-- I am returning the current display resolution of the main monitor
-- e.g. {800, 600}
on getdisplayresolution()
set shelloutput to do shell script "/usr/sbin/system_profiler SPDisplaysDataType | grep Resolution"
set {dspwidth, dspheight} to {(word 2 of shelloutput) div 1, (word 4 of shelloutput) div 1}
return {dspwidth, dspheight}
end getdisplayresolution
-- I am creating the PDF wallpaper by passing a big bunch of arguments over to a clever Python script
-- utilizing the CoreGraphics module available in Mac OS X :D
on crtwallpaper(dspwidth, dspheight, stryear, strmonth, fontname, fontsize, xpos, ypos, bgcolor, fontcolor, fonttint, bgimgpath, wpfilepath)
set scriptpath to (((path to me) as Unicode text) & "Contents:Resources:Scripts:lacurne.py")
set qtdscriptpath to quoted form of (POSIX path of scriptpath)
set qtdwpfilepath to quoted form of (POSIX path of wpfilepath)
set qtdfontname to quoted form of fontname
if bgimgpath is missing value then
set qtdbgimgpath to quoted form of "missing value"
else
set qtdbgimgpath to quoted form of (POSIX path of bgimgpath)
end if
set cmd to "/usr/bin/python " & qtdscriptpath & space & dspwidth & space & dspheight & space & stryear & space & strmonth & space & qtdfontname & space & fontsize & space & xpos & space & ypos & space & bgcolor & space & fontcolor & space & fonttint & space & qtdbgimgpath & space & qtdwpfilepath
do shell script cmd
end crtwallpaper
-- I am indicating if an item path exists or not
on itempathexists(itempath)
try
set itemalias to itempath as alias
return true
on error
return false
end try
end itempathexists
-- I am a very old search & replace function...
on searchnreplace(searchstr, replacestr, txt)
considering case, diacriticals and punctuation
if txt contains searchstr then
set olddelims to AppleScript's text item delimiters
set AppleScript's text item delimiters to {searchstr}
set txtitems to text items of txt
set AppleScript's text item delimiters to {replacestr}
set txt to txtitems as Unicode text
set AppleScript's text item delimiters to olddelims
end if
end considering
return txt
end searchnreplace
-- I am displaying error messages to the user
on dsperrmsg(errmsg, errnum)
tell me
activate
display dialog "Sorry, an error occured:" & return & return & errmsg & return & " (" & errnum & ")" buttons {"OK"} default button 1 with icon stop with title myname
end tell
end dsperrmsg