NetNewsFlix

February 27th, 2006

First let me say, I love Netflix. When I’m not programming, sleeping, or running, I’m usually watching Netflix. What a life!

A friend who also loves Netflix came to me with a puzzling problem. He’s coming out of a long term relationship, and among the other shared possessions to be carefully divided was the couple’s Netflix queue. The account isn’t in his name, but he wants to keep his share of the hard-accumulated queue. He gazed at the long list of 308 titles and searched the web page carefully for an “Export” button. Nowhere to be found. It seems that Netflix, despite it’s totally awesome domination over all competitors, is a little teeny bit scared of what might happen if you could easily export your queue to a text file and then, say, re-import it to Blockbuster.

NetNewsWire, RSS, and AppleScript to the rescue! Since Netflix is hip enough to provide several RSS feeds for its savvy customers, I just grabbed my friend’s Netflix queue RSS feed, and subscribed with NetNewsWire. Then, after selecting the subscription, I typed the following into Script Editor:

tell application "TextEdit"
	make new document
end tell

tell application "NetNewsWire"
	set myHeadlines to (headlines of selectedSubscription) as list
	repeat with myItem in myHeadlines
		set thisTitle to (title of myItem)
		tell application "TextEdit"
			set text of document 1 to (text of document 1) & thisTitle & return
		end tell
	end repeat
end tell

It doesn’t matter if it’s efficient, it just has to work once. And voila! Switch to TextEdit and observe a 308 line file with the names of each film in order. If the numbered lines are a problem, a little bit of extra script could take care of that in a jiffy.

It’s exactly these kind of unforeseen circumstances where easy, predictable scripting interfaces save the day.

Update: It wouldn’t have been the worst thing in the world to simply save the HTML page listing the entire queue, but this solution makes it much easier to manage the data and process it however the owner sees fit.

String Theory

February 26th, 2006

Every good API (or language) should have a fundamental, powerful, impossible to ignore encapsulation of a primary building block in computer programming: the string. Wikipedia defines a string as a “sequence of various simple objects.” Wow! That’s an indulgent definition, but kind of nice in its flexibility. When such a robustness is properly implemented in a string object or type, it facilitates effortless and worry-free manipulation by developers.

Even back when it was generally presumed that only white, English-speaking dudes with lab coats would ever need to make sense of the bits of text that went into and came out of a computer program, there was an alarming lack of consensus on how that data should be represented. I’m sure some of you are old enough (or just unlucky enough) that you’ve had to stare down a chunk of data, scratch your head and ask, “Is this an ASCII or EBCDIC string? Mac programmers with a history of Carbon programming are no doubt familiar with the ever-tedious task of converting strings between Pascal and C-style formats. As the de facto standard programming language of the Mac slowly shifted, the format expected by Apple APIs followed suit at varying paces. For those of you lucky enough to have been born into a world where strings are magical objects that handle Chinese characters as easily as Roman type: you should count your good 时运!

Cocoa programmers are among the luckiest programmers in the world. NSString is a comprehensive, powerful encapsulation of Unicode strings. It’s because of this encapsulation that I was able to copy the Chinese characters in the above paragraph out of Safari and paste them into MarsEdit without thinking twice about whether it would work. OK, that was a lie. I was a little bit concerned, but I didn’t need to be! It was an old-man paranoia, based on years of living under the repressive restrictions of a world without Unicode. Now, it just works! And the developers of Safari and MarsEdit probably didn’t think twice about it, either.

But the biggest winners here are the users. José and Aslög, who have spent their lives tweaking the spelling of their names to suit fussy computer programs and DMV clerks, are more and more likely to see their names pleasantly represented in-full by our electronic friends. And their sacrifice has been slight compared to those whose names require a complete reworking to satisfy the technical ineptitude of Western technology. While the Windows and Linux platforms have also made great strides in recent years, it continues to be my experience that the Mac “just works” in far more circumstances than on other platforms.

It was enough of a gift for Apple to take care of all the encoding, multi-byte issues, allocation, etc. But they also snuck NSString into nooks and crannies of the system where only a developer could appreciate them. The flexibility of NSString is shown off in a few unexpected ways that not all developers are familiar with.

I Can See You

Most Cocoa developers are very familiar with the handy NSLog function. This little beauty is the modern replacement for traditional “printf debugging.” Some circumstances call for “step by step” debugging, while at other times its faster to spew information out to the console, hoping to get a clue as to why your program is misbehaving. Like printf, NSLog takes a template string and a variable number of value parameters which are then formatted and inserted into the template as requested by the developer. In addition to the standard printf codes for converting things like long integers to text, the Objective-C runtime gives us a super-powerful code, “%@”, for converting an arbitrary object to text. So if you’re confused as to why your array of fruits is not showing up as expected, you can simply add a line to your program at an opportune point:

NSLog(@”My fruits: %@”, fruitArray);

When you run your program, you get this output conveniently displayed in the console (or Xcode run log):

2006-02-26 11:56:35.939 MyApplication[25666] My fruits: (Apple, Banana, Pear)

Aha! The strawberries are missing! This powerful “object inspection” facility is enabled by a simple message, “description,” which all Cocoa objects respond to by returning a human-readable representation of the object in NSString format. The quality of the description ranges from “not very useful” to “exceedingly informative,” depending on whether the particular object’s class has overridden the default implementation, which simply spits out the class and a hex-formatted representation of the object’s address in memory. The promise that something will be returned is powerful enough to make “printf debugging” of objects a lot easier than it otherwise would be.

String from What?

Once you become accustomed to NSLogging everything under the sun, it can come as quite a surprise that a few common Objective-C types don’t bend so easily as the rest. Examples of such types are NSRect, NSSize, and NSRange. These compromised “objects” are implemented as plain C-structs rather than as proper objects, presumably as a performance consideration. Since they’re not objects, there is no freebie “description” method enabling them to be effortlessly passed as arguments to NSLog. But these values are just as likely to run amok and cause bugs in your program, so what do you do when it’s time to spray their contents out to the log? Something I’ve witnessed developers doing on more than one occasion is to simply revert to printf-style inspection:

NSLog(@"My rectangle: origin = (%f, %f), size = (%f, %f)", 
	myRect.origin.x, myRect.origin.y, myRect.size.width, myRect.size.height);

Which yields:

My rectangle: origin = (0.000000, 0.000000), size = (300.000000, 500.000000)

Clearly, this works. And it’s a fine habit to get into if you’re training for the typing olympics, or you’re masochistic, or both. You might ask yourself why a group of engineers who designed such an elegant, introspective runtime environment would allow these essential building blocks to slip through the cracks. The answer? They didn’t. A number of handy utilities exist to not only convert these basic types to string format, but to then convert them back into their native struct format as you see fit. Using NSStringFromRect, we can replace the lengthy log statement above with this:

NSLog(@"My rectangle: %@", NSStringFromRect(myRect));

Which yields:

2006-02-26 12:19:45.578 MyApplication[29788] My rectangle: {{0, 0}, {300, 500}}

The developers at Apple acknowledge the universal usefulness of NSString, and therefore provide a number of these utilities, allowing you to “objectify” many fundamental types: NSStringFromRange, NSStringFromSize, NSStringFromClass, NSStringFromSelector, etc.

Not Just for Show

This objectification of basic types is very handy for logging purposes, and a great tool to keep in your belt for tackling everyday programming problems. Types like NSRect and NSSize can’t be tossed around willy-nilly in Cocoa’s collection classes, but NSString can! So when you find yourself needing to store a list of NSRanges in your Cocoa object, don’t revert to your old C ways of dynamically allocating an array of structs. Simply objectify the ranges and stick them in a mutable array:

[mRangesToWatch addObject:NSStringFromRange(newRange)];

When it comes time to examine a range, just convert it back to its native format:

NSRange oldRange = NSRangeFromString([mRangesToWatch objectAtIndex:0]);

This even works with nil values. NSRangeFromString(nil) produces an empty range.

Chris Liscio is a super, mega, ultra groovy Mac developer who points out that in some cases, this easy path to objectification is too inefficient for practical use. He recently authored a custom wrapper of NSRect, precisely so he could maintain an array of these objects. In his case, the array of rectangles needs to be constantly reviewed and compared with other rectangles, so the constant conversion to and from string format would have been ridiculous. But in many instances, taking advantage of the built in NSStringFromBlah functions will prove to be both an easier to implement and easier to maintain solution that writing your own custom wrapper.

Update: Michael Tsai comments below about the speed of such a wrapper vs. NSValue – essentially bringing to light my obliviousness to using NSValue … the way it’s documented! I’d always just associated NSValue with NSNumber. It makes my recommendations above to use NSStrings for such a purpose sound kind of stupid. C’est la vie! Thanks Michael for reminding us of yet another elegant feature of the API.

It’s on the House

Apple deserves a standing ovation for their clever use of NSString throughout the Cocoa API. Just about every method that calls for text as input or output does so in the form of NSString. So long as we’re in the cozy confines of Cocoa, we can sit back and bask in the glow of our convenient, precious little class. But Apple really went the extra mile by “toll-free bridging” it to CFString, its leaner, procedural cousin in the CoreFoundation framework. What this means is that the utility of NSString essentially reaches not only across the Cocoa API, but across the vast number of Apple APIs that rely on the CoreFoundation framework, and therefore use CFStringRef as their basic unit of text manipulation. This makes it easy for Cocoa developers to take advantage of lower-level libraries without jumping through hoops to do so. If you see a CFStringRef and wish it were an NSString so you could easily copy it or add it to an array, “just cast it.” Casting a CFStringRef to an NSString* (from Cocoa code) feels dangerous and dirty, but it’s actually the right thing to do, and is a heck of a convenience. Casting the opposite direction is also handy and equally valid. Just be sure to manage your retain counts. The best things in life are free. Thanks, Apple.

Windows of Perception

February 11th, 2006

(Note: The title of this entry is an homage to Aldous Huxley’s classic Doors of Perception.)

Most Mac users and many developers don’t realize how extensively windows are used in the composition of the overall UI experience on Mac OS X. In the years since Mac OS X was first released, the basic “Quartz Window” has been increasingly used as the workhorse element in providing the glitzy UI features we take for granted. An average user looking at their desktop, with all Finder windows closed, would answer “none” to the question “how many windows are open?” But there are dozens if not hundreds of windows being displayed in part or full on a typical Mac user’s screen. They just don’t look like windows.

A fun and easy way to experiment with this phenomenon is to put the Mac’s built-in screen capture facility into “window grabber” mode.

  1. Press Cmd-Shift-4 (a shortcut whose history can be traced to FKEY resources, lightly documented in the old-ish Inside Macintosh books).
  2. Unless you’ve configured otherwise, press the space bar once to switch to “window grabber mode.” You’ll see the mouse cursor change into a clunky (definitely film, not digital) camera icon.
  3. Without clicking the mouse, simply move this camera icon around your Mac’s UI, watching as it highlights the various windows that it sees.

Move the cursor up to the menu bar and observe that most of the menu bar is a single window. While Spotlight’s icon gets its own window, all of Apple’s menu extras share a single window (within which you can cmd-drag such extras around to sort them). Any applications you’ve installed that use the NSStatusItem API will appear to the left of Apple’s menu extras, and each of these status items you will see also comes with a window.

The desktop? It’s a window. Every icon on the desktop? Windows. (Thanks to Will Koffel for pointing this out at the last Boston CocoaHeads).

With the Dock visible, cruise over to just touch its edge. Notice how it lights up? It’s a window. Every single icon in the dock is also a window, and if you bring up a dock item’s contextual menu, you’ll see that it’s a window, too. Not just contextual menus – click the menu bar and then invoke the camera icon. All menus are windows. And all submenus are windows.

While in screen capture mode, press Cmd-Tab to bring up the task switcher UI. It’s harder to observe here because the two modal tasks are competing with each other, but the task switcher UI is a window, as are each of the application icons included within it. Don’t believe me? Hold the screen capture camera over an item as you cmd-tab to it and release it. Screen grabber artifacts don’t lie!

A Top-Down Approach

When you get tired of the interactive method of browsing for the ever-present window object’s dominance of your computer, you might enjoy double-checking your work with the Quartz Debug application, installed as a default part of the Xcode tools. In my experience, even developers who have used Quartz Debug extensively are often unaware of the “Window List” feature hidden away in its “Tools” menu. There is much more than the simple “flash updates” type functionality you find in Quartz Debug’s main window. Check out the menus!

With the Window List open you can see every single Quartz window being employed by the system to deliver your smashing UI experience. This is great for simply gasping at the impressive speed with which all of these windows are (usually) being managed. It’s also a nice way to sneak up on surprising uses of windows in areas where you might not have thought to apply the screen capture trick. This window list includes all windows, whether they are currently visible or not. But if the window is visible, then selecting it in the Quartz Debug window list causes it to pulsate in a very unignorable way. Even better: the pulsing continues while Quartz Debug is in the background, so select a window in Quartz Debug and then switch to the owning application and try to figure out where the heck it is.

My curiosity was peaked just now when I noticed Omni Outliner Pro was sporting nine windows to accommodate my single open document. Two of them are somewhat obvious: I’ve got a document window and a drawer coming out of that window. Drawers are fairly commonly known to be windows. I’ve also got a single (or so I think) utility/inspector window:

(Update: While the UI above is overall very slick, notice how the jpg conversion reveals the shadow artifacts that result from sneaking several independent windows together. While this isn’t so noticeable in real-time, it’s an interesting flaw, and another example of why it’s tricky to get away with abusing the windowing system.)

This nifty little piece of UI work consists of a list of inspectors, each of which can be expanded or collapsed as the user sees fit. This is a familiar paradigm probably made popular by the use of just such a technique in the Finder’s “Get Info” window. I switched to OmniOutliner and turned on screen capture mode. Sure enough, each of those collapsible sections is its own, independent window! Well shoot howdy! I wondered what could have motivated the developers to do this. It’s true, dynamically growing and shrinking the subviews of a window and adjusting the overall window size at the same time isn’t exactly a newbie task, but I wouldn’t guess keeping the frames of several independent windows in sync and animating at the same time is either.

It became clear when I started playing around with this “Inpector Window” more carefully. I’m a pretty new user to OmniOutliner, and I don’t read many manuals. So it came as a complete surprise when I clicked and dragged one of these sections and effortlessly “tore it away” from the rest of the items. Each of the items is its own window because it truly is a window in a user sense, not just an implementation sense! As you drag these sections away from each other they take with them any sections attached beneath them. You can just as easily drag them back together and watch them snap into place. At any given time only the top-most section of a group of connected items contains a close box. This is just brilliant. I really must applaud the developers of Omni Outliner for this ingenious implementation, which provides a straight-forward single window metaphor for beginners while allowing power users to easily rearrange and compose their inspectors in a more suitable form. This is “window abuse” at its very best!

Windows, Damn Windows, and Broken Windows

Back in the old days (on the Mac), a window was a window was a window. The notion of a window to a user was the same as it was to a developer: a draggable chunk of screen real-estate, usually rectangular, usually containing a title bar, a close box, and a zoom box. A developer could go out of her way to design a window that defied the logical expectations of the user, but it would be a waste to do so, because the system (Mac Toolbox) would carry all the baggage of presuming that the window was a “real” window. You know, a “user window.”

As time has passed, and especially with the iterations of Mac OS X and the establishment of Quartz as the “base unit” of UI design on the Mac, the definition of “window” has been divided such that it means different things to different groups of people. To users, it still means “a moveable chunk of my screen with a title, a close box, etc.” To Carbon and Cocoa developers it generally means “the top-level container in which my ‘views’ are implanted.” While to Quartz developers it probably means little more than “a programatically moveable, layerable claim on screen real estate.” This lightweight Quartz interpretation of the concept makes for a much more reusable (and abusable) raw material.

At any given moment in time, the technical definition of a window may be the same or different from the user definition of a window. While they were more or less in sync in the past, we now have at least three distinct varieties:

  1. Windows – For the sake of sanity, let’s reserve the unqualified word for the highest-level concept of a window. This is the “user’s window.” You can talk about these objects in your documentation. Users know how to navigate with their mouse to the target of your description. Example: “Click the red bubble in the upper-left corner of the browser window to close the web-page document.”
  2. Damn Windows – Only a nerd could love these. They make you say, “Damn! That’s a window?” Unfortunately, you can’t call them windows to a user because they will have no idea what you are talking about. Damn windows are the bulk of what I’ve been discussing in this article: surprising uses of the low-level window object. For instance, you can’t ask a user to “move the mouse pointer to the menus window at the top of your screen, hover above the ‘File’ item and scroll down the File window to the ‘Close’ item.” In the case of OmniOutliner’s magic inspector. The five damn windows must be collectively referred to as a window, even though the developers know very well it’s not a single window! They have to bite their tongues and agree that it’s a window. The user may be asked to separate the coordinated group of damn windows into five separate, free-standing windows. Only then may they individually be referred to by the unqualified term.
  3. Broken Windows – These usually start out being classified as damn windows, but soon you learn that they violate some contract between any two of the system, developer, and user. While damn windows are good things – they provide enhanced user experience through creative use of the basic window object – broken windows are disastrous because they lead one party in the dance of window interactions to be deceived, and therefore to treat the window inappropriately.

Broken windows occur when the system or a developer attempts to use a (user level) window to achieve a tricky end, without taping up all the loose ends.

NSStatusItem’s Broken Window

An example of a broken window, and the motivation for this blog entry, is the NSWindow employed by NSStatusItem to display an application’s “menu item icon” in the upper-right corner of the Mac OS X UI. This implementation crosses the line from being a damn window to a broken window by assuming the convenience of NSWindow without responsibly managing the impact that such a decision has on unsuspecting developers and users. NSWindow is a high-level developer’s API. Although an NSWindow ultimately gets displayed by a low-level Quartz window, there are certain high-level expectations that an NSWindow in a Cocoa application must conform to.

When a developer installs an NSStatusItem into the system menu bar, they do so by either deferring to the system’s default icon view, or by installing their own custom NSView subclass to handle user interaction. This is where things must have gotten tricky for the Apple engineers. To give an application access to a piece of real estate in the upper-right corner of the screen, they needed to give it a low-level window. This means Quartz will have to cordon off a bit of space and allocate a window object. This will show up when you hover your mouse over any status items installed in your menu bar. But to facilitate easy adoption by Cocoa developers, a higher-level UI interface was needed, and NSView is the natural choice for such a thing. But NSView can’t be installed in a low-level Quartz window object. NSViews must, as a rule, be installed in other views. The exception to this rule is where the “top level view” for any particular group of UI gets connected to the lower-level window API. This conection happens by way of an NSWindow object. The NSWindow’s “content view” contains any number of NSViews, each of which may contain other NSViews. But without NSWindow, you’ve got no NSView.

So the Apple developers decided to sneak an NSWindow into the equation. While the API advertises the capacity for a developer to install an NSView in the menu bar, it says nothing of the ramifications this will have on the application’s window list, or on whether the installed status item will be vulnerable to strange attacks by virtue of its rather untruthful “status” as a full-fledged NSWindow.

As I said before, the difference between a damn window and a broken window has everything to do with maintaining contracts. If the user’s and developer’s vision of the state of “windows” in an application is never violated, then it’s a damn window. If a contract is broken, well … it’s a broken window.

By assuming the responsibilities of a Cocoa window, NSStatusItem breaks an important user contract. Cocoa windows mean something to the user. For example, AppleScript exports meaningful information about an application to the user space through System Events’ “windows” property. A user can ask for a particular window by index, where a lower index represents a “more frontmost” window. It’s entirely reasonable for users to expect that the focused document of an application can be referred to like this:

tell application "Adium"
	get window 1
end 

I’m running Adium right now, with a single chat window open and activated. Adium is configured to show its NSStatusItem-based window in the menu bar. The above script, instead of returning the focused chat window, returns the sneaky little NSStatusItem window! So a user who relies on the functionality of AppleScript now has to know that “for Cocoa applications with NSStatusItems installed, the secret status item window is window 1.” That’s total BS. This window is broken.

NSStatusItem also breaks a developer contract. It would be one thing to grimace and accept that control over a status item’s window might fall into the hands of the user, but once there, it must be bullet-proofed against harmful manipulation. I don’t really care how NSStatusItem implements its functionality, so long as it doesn’t destabilize my application.

By hiding the NSWindow implementation from me (the developer) but exposing it to the user (through AppleScript), the status item sets developers up to “play the fool” on behalf of any user script that ends up manipulating the wrong window. See, these fake little NSWindows are capable of doing the darned’est things. Apparently Apple didn’t realize just how much manipulation might be attempted through AppleScript. If I run the following script:

tell application "Adium"
	set zoomed of window 1 to true
end 

I end up with this little beauty of a UI artifact:

I’m pretty sure the Adium developers had no idea they had to guard against such disturbing UI manipulation. I’m using Adium as a convenient demonstration that this affects any scriptable Cocoa app with an NSStatusItem, but obviously my biggest concerns lie in my own products. So I follow the above script up with a similar tweak:

tell application "FastScripts"
	set visible of window 1 to false
end 

Which yields an altogether comically destroyed status bar:

To Apple’s credit, after just a little bit of mouse movement, the status items seem to regain their posture. Visually, at least. In the case of setting an application’s status bar window’s visibility to false, it ironically fixes the visibility but somehow in the process causes the corresponding NSView to be unclickable. In order to resume clickability of my FastScripts icon, I have to go back to AppleScript and manually set the visibility back to true. C’est la vie!

I suppose some of you might be thinking that these violations are minor because they only affect a relatively advanced group of users (AppleScript authors), but the fact that these flaws are exposed through AppleScript doesn’t mean they won’t also rear their ugly heads elsewhere. The problem is a careless abuse of the technology of windows objects to achieve goals that are contrary to the user’s vision of what a window is. Every time you choose to do this, you must consider carefully what the impact will be on the developers and users who rely on your software. In this case, AppleScript reveals at least two obvious problems with the NSStatusItem implementation. Let’s hope there aren’t more to be discovered!

Google Calculator

February 10th, 2006

I have become dependent over the past couple years on Google Calculator. This is the feature that allows you to type in queries like “X in Y” and get meaningful (not search results), immediate responses.

For example, even though I’m a technical person, I can’t seem to memorize anything metric to save my life. So I often end up looking at some programming API and thinking “hmm… ‘in ms’ … is that milliseconds or microseconds … and how much is a millisecond anyway?” It’s easy for at least this American to let the “milli” part of such words remind me of “million” more than of “thousand” (yes, even after learning much Spanish and a bit of French). So, never wanting to waste much time with trial and error when it comes to API navigation, I pop over to Google and type in:

“1ms in seconds”

Yielding the extremely concise and accurate:

“1 milliseconds = 0.001 seconds”

Not only have I confirmed that “ms” means milliseconds, but I know that yes, there are a thousand of them in a second. Phew! Glad I got that out of the way for the billionth time in my life. Metrislexia is hard!

It’s not just technical values that Google is good at converting. Take money, for instance (but not mine!). If you type in something reasonable like this:

“$1 in pesos”

You get:

US$ 1 = 10.5014991 Mexican pesos

Which not only tells me exactly what my leftover vacation money is worth, but also reminds me that I’m a big dummy for assuming that “$” means “US$”.

I have come to depend on the calculator so much that I seem to be good at discovering things that are not (yet?) covered. So what is missing? Just about everything! Off the top of my head:

  • Quickie word translations. Google has its obvious “Language Tools” section which allows you to translate a sentence or web page from one language to another as quickly as you can configure a complicated form and press “Submit.” Much better for everyday use would be a facility where I could type “english ‘happy’ in japanese” and have something meaningful appear.
  • Historical money. They’ve got a nice head-start in the currency department, but what we need now is expanded tools to deal with money in real terms. For instance, in the news and such you often hear explanations of money from times past: “The young painter earned about $30 a week, or around $650 in present-day dollars.” So if there’s anything close to a consensus on what money was worth historically, Google should be willing to do to the work for me. I want to type “13 dollars in 1983” and have the magic answer appear. Instead, I get close to 9 million results from across the entire, faulty spectrum of web content.

What have you found to be lacking? If you’ve been using Google Calculator for a while, what have its relatively magical qualities led you to believe should also be smartly handled? If you’ve never used it before, give it a spin and see what you’re inspired to expect. I look forward to seeing some brainstormed ideas for improving Google Calculator. Maybe if we get a good enough collection the Google people themselves will find this page through a Google search and start acting on our feedback!