I ran into a line of posts the other day about customizing Mac desktops. There were quite a few interesting ideas but the ones that stuck out for me were the people making use of Geek Tool.

Geek Tool is an macOS preference pane that allows you to place pretty much anything on the desktop. And what it places on the desktop can be easily formatted. I took one of the designs and extended it slightly to create this:

This time/date/weather display is updated dynamically on the desktop and uses very little CPU.1

Each element in the display is a separate shell command. The elements are:

Element Shell Command Font Location Size Update Period (sec)
The day date +%A Helvetica, Regular, 27point with drop shadow 10x, 727y 200w x 40h 60
The month date +%B Helvetica, Regular, 36point with drop shadow 10x, 750y 200w x 50h 60
The day of the month date +%d Helvetica, Regular, 64point with drop shadow 210x, 720y 100w x 80h 60
The time date "+%I:%M" Helvetica, Bold, 72point with drop shadow 20x, 780y 200w x 80h 10
am/pm date +%p Helvetica, Regular, 48point with drop shadow 210x, 785y 100w x 70h 10
The temperature <bin>/weather.rb -t Helvetica, Bold, 18point 20x, 855y 70w x 25h 300
The weather <bin>/weather.rb -d | fmt -w 40 Helvetica, Regular, 10point 90x, 855y 210w x 38h 300
When the weather was updated <bin>/weather.rb -w Helvetica, Regular, 8point 35x, 878y 64w x 25h 300

The <bin> in the weather commands is the full path to the directory where you place the weather.rb script. That script is written in Ruby and calls the Weather Underground for the weather information. It needs to be modified so it’s location matches yours. You can download the script from here.

Download the script and replace <your-state> with your two character state, e.g., PA. Replace <your-city> with your Weather Underground recognized city, e.g., West_Chester. You’ll have to play with the Weather Underground site to find your city name. Save the altered script to your bin directory, e.g., /Users//bin. If you don’t have a bin directory, create one. Make the script executable by typing ‘chmod +x /Users/bin/weather.rb’. Test the script by running it - ‘/Users//bin/weather.rb -d’. Once you have it working, you can use it in Geek Tools.

#!/usr/bin/ruby
require 'rss/2.0'
require 'open-uri'
require 'optparse'
require 'fileutils'

summary = false
forecast = false
temperature = false
today = false
weatherdate = false

opts = OptionParser.new
opts.on("-s") { |val| summary = true }
opts.on("-f") { |val| forecast = true }
opts.on("-t") { |val| temperature = true }
opts.on("-d") { |val| today = true }
opts.on("-w") { |val| weatherdate = true }
opts.parse!

# Check if another process is downloading the weather and block until it's done
while File.file?('/tmp/weather.rb.tmp.lck')
  sleep(0.1)
end

# Download the weather if it's out of date
if !File.file?("/tmp/weather.rb.tmp") || ((Time.now - File.mtime("/tmp/weather.rb.tmp")) &gt; 1800)
  FileUtils.touch('/tmp/weather.rb.tmp.lck')
  `curl --silent -m 30 "http://rss.wunderground.com/auto/rss_full//.xml?units=english" &gt; /tmp/weather.rb.tmp`
  if File.size("/tmp/weather.rb.tmp") == 0
    FileUtils.rm("/tmp/weather.rb.tmp")
  end
  FileUtils.rm('/tmp/weather.rb.tmp.lck')
end

# Parse out the weather results
File.open('/tmp/weather.rb.tmp') do |f|
  response = f.read
  result = RSS::Parser.parse(response, false)
  result.items.each_with_index do |item, i|
    puts "#{item.title.gsub(/ - .*/, '')}"  if summary == true and i == 0
    puts "#{item.description.strip}\n\n" if forecast == true and i &gt; 0
    puts "#{item.title.gsub(/Current Conditions : /, '').gsub(/,.*/, '')}" if temperature == true and i == 0
    puts "#{item.description.gsub(/Today - /,'').gsub(/Tonight - /,'').gsub(/This Afternoon - /,'').gsub(/[\r\n\t]/, '')}" if today == true and i == 1
    hour = item.pubDate.hour()
    if hour &lt; 12
      ampm = "AM"
    else
      ampm = "PM"
    end
    if hour == 0
      hour = 12
    end
    if hour &gt; 12
      hour = hour - 12
    end
    puts "#{item.pubDate.mon()}/#{item.pubDate.day()} #{hour}:#{'%02d' % item.pubDate.min()} #{ampm}" if weatherdate == true and i == 0
  end
end

Again, the URL “http://rss.wunderground.com/auto/rss_full/<your-state>/<your-city>.xml?units=english” portion of the script will need to be modified to match your location. Test the URL in your browser to find the right one for your version of the script.

The weather script stores the information it pulls down for 30 minutes (1800 seconds). Defined on this line:

if !File.file?("/tmp/weather.rb.tmp") || ((Time.now - File.mtime("/tmp/weather.rb.tmp")) &gt; 1800)

The delay is necessary to keep from pulling the information down repeatedly for each element in the display. You don’t need to change this unless you want the delay to be different.

Update: I’ve posted about a new version of the weather script.


[1] There are some limits to Geek Tool formatting. You’ll notice that the weather font looks a little ragged. The only way to get Geek Tool to blend text is to give it a shadow. But a shadow on such a small font looks terrible.