According to Apple, widgets are “mini-applications that let you perform common tasks and provide you with fast access to information.” The cool thing for web developers and designers is that widgets are at their heart just web pages, bundled in a specific way. So, if you can make a useful web page, you can probably make a useful widget! All you need is a little information about their structure.

My desktop with Dashboard enabled

Widgets are simply bundles of text and image files. By adding the “.wdgt” extension to a folder, you turn the folder into a bundle which is treated by Mac OS X as one file. Conversely, you can explore the code and graphics for any widget by either removing the “.wdgt” extension or just control-clicking on the widget and choosing “Show Package Contents”.

When learning a new programming language, the first task is typically to write a trivial program to print “Hello World” on the screen. We will now take a look at the Dashboard equivalent!

Apple has been kind enough to post a “Hello World” widget on their Sample Dashboard Code page. I have mirrored it on my server in case they move or delete it for some reason. Here is a breakdown of the parts that make up HelloWorld.wdgt:

HelloWorld.html – the heart of our widget, this HTML file contains everything you’d normally see in a simple web page

Default.png – this image file is what users will see while the widget is initializing

Icon.png – this image file is what users will see in their widget bar (the place from which users load new widgets)

Info.plist – this XML file contains information used by Mac OS X to describe the widget

This image is what the user will see when s/he loads the widget, but is also used in this case as our backdrop. The image dimensions for your Default.png typically correspond to the size of your widget as specified in your Info.plist file.

This image is what the user will see when s/he opens the widget bar. It is analogous to a desktop application’s icon. According to Apple’s widget design guidelines, this image should be 85 x 85 pixels with the “content” of the image taking up 74 x 74 pixels, at most.

This XML file is used by Mac OS X. It describes the widget and controls whether the widget has access to particular system resources (internet connectivity, command-line applications, the filesystem, etc.). The plist (short for property list) for “Hello World” contains mostly just the essential items.

Hello World Screenshot

Now, making a widget that just sits there isn’t very useful. What makes a useful web page (and, by extension, a useful widget!) is interactivity. Widgets can do anything a web page can do, but they can also do some pretty nifty things a web page cannot.

System Access

Within the Dashboard environment, JavaScript has access to a special object called “widget”. This allows Apple to open up a host of functionality, including the ability to access the Mac OS X command-line within your widgets. Pretty much anything you can do from the command-line, you can do within a widget. Wow! How’s that for possibilities? I’ve used this feature to do the following in my widgets:

Save & Retrieve Preferences

The widget object can also be used to save and retrieve preferences unique to a widget, or even a particular instance of a widget. These are similar to cookies within a regular web browser. This allows you to maintain state across sessions and otherwise track a user’s settings. Here is an example from Make-A-Pass:

Asynchronous HTTP Requests

There has been much hype lately about Ajax. Ajax is the name given to the technique of tapping into modern web browsers’ ability to make and handle asynchronous HTTP requests. If that last sentence makes you go “Huh?” I’ll explain. Let’s take a look at the canonical example: Google Maps. No, really, take a look. Follow the link, zoom in, pan around. Get some driving directions. Pretty slick, eh? I won’t go into detail about how they do it (others already have), except for this: every time you change what you’re looking at, your web browser makes a request to Google’s servers and parses the XML response, all using some pretty clever JavaScript.

Well, guess what? Widgets can do the same thing! A common use of this capability is to grab RSS feeds and parse them. I did this in my Today in New Mexico widget. Here is the relevant code:

Quartz Methods

Quartz is Apple’s name for its graphics rendering framework. Desktop apps written in Java, Objective-C, REALbasic, etc. make calls to the Quartz API to draw stuff on the screen. Well, Apple has integrated into Safari the ability to access Quartz methods directly using JavaScript. This gives developers some awesome possibilities! I tapped some Quartz methods in my SlideShow widget to show the current slide reversed as the backside of the widget. Here is the relevant code:

// draw the current photo on the backside of the widget, flipped horizontally
function changeBackside() {
// get the source image
var img = new Image(400,300);
img.src = photoObjs[imgIdx].src;
// due to a bug in Safari, this needs to be here or this function won't work
// (within a widget, alert messages are written to the Console)
alert("Disregard");
// get the canvas object & context objects
canvas = document.getElementById("canvas");
context = canvas.getContext("2d");
// set the drawing context
context.clearRect(0,0,400,300); // erase the rectangle
// save the context for later restoration
context.save();
context.scale(-1,1); // flip horizontal
context.translate(-400,0); // move the canvas over to compensate for the flip
// draw the image
context.drawImage(img,0,0);
// restore the context so we start with a fresh slate next time
context.restore();
}

As you can see, the potential capabilities of widgets are virtually limitless!