Archive for February, 2008

NSScrollView in a key view loop (or Fembot in a wet T-shirt)

Wednesday, February 20th, 2008

Now that the Pats have won the Super Bowl, Rudy has won the GOP nomination, and the Jedi have won the Clone Wars, all is right with the world (and the galaxy), so we can focus again on our lives, on our families, and most important, on Cocoa. If you’re a Cocoa developer, you are morally required to open System Preferences, Keyboard & Mouse, Keyboard Shortcuts and select All controls in Full keyboard access. This is not optional. If you do not comply, you will be driven out of the Continuum and forced to spend the rest of your pitiful mortal existence writing kernel extensions.

With the mandatory preference setting, you will observe the full Cocoa key view loop. Actually, it doesn’t have to be a loop: it could be a key view cul-de-sac. Anyway, Apple clearly wants developers to “leave the driving to us”, i.e.,

-[NSWindow setAutorecalculatesKeyViewLoop:YES]

because configuring and updating the key view loop can be a pita — like training a cat. The docs make it sound oh so easy, but that’s only because the docs don’t cover the complex or problematic cases. Suppose, for example, that you have a scroll view enclosing a view that contains multiple controls. You want the key view loop to follow a particular route both outside and inside the scroll view. How should you hook up the views in Interface Builder? (Or in code, when you’re working without a nib.)

I believe that the proper way to handle an NSScrollView in a key view loop is to ignore it. Walk by quickly without making eye contact. Whatever you do, don’t engage in conversation! Otherwise you’ll get invited to coffee or lunch. The reason you can ignore NSScrollView is that it never actually becomes the firstResponder of an NSWindow. The scroll view returns YES from acceptsFirstResponder if its documentView does, but if you then call -[NSWindow makeFirstResponder:] with the scroll view as argument, the window’s first responder will end up being not the scroll view itself but rather its document view.

This behavior is adequate if the document view is a single control such as an NSTableView or an NSTextView (though maddeningly, an NSTextView tends to interpret the tab key as, well, a tab). In the window nib, you can simply include the scroll view in the window’s key view loop, ignoring the document view, and when the window loads, the scroll view will automatically rearrange the key view loop to make its NSClipView the nextKeyView, followed by the document view and then the scroll view’s original nextKeyView. The scroll view and the clip view are superfluous in the key view loop, however, because only the document view becomes the first responder when tabbing through the window.

This behind-the-curtain key-view wizardry may seem impressive, but the scroll view is really deaf, dumb, and blind. It has no idea about any loop you’ve defined within the document view. There is no way to inform the scroll view of the beginning and end points of the ‘sub-loop’. If you attempt to insert the scroll view containing your sub-loop into the window’s key view loop, it will turn into either a key view dead end within the scroll view or a key view overpass, depending on the configuration.

To avoid these problems, simply connect your views together in the key view loop as if the scroll view did not even exist. You know, like Mac OS X Tiger. (Of course the keyboard firmware update requires Quick Look and Time Machine!) Only the views that become first responder — as opposed to becomeFirstResponder — need to be hooked up. When a cat is lying on the trackpad, you will be thankful for setting the key view loops in your app, and so will your users. Cat-friendliness is in fact the most crucial consideration for designing both software and hardware.

I am saying that I will neither aspire to nor accept — I repeat, I will neither aspire to nor accept — the positions of President of the State Council and Commander in Chief. I will, on the other hand, host the Tonight Show if asked. Hasta la vista!

FUD from Rixstep: NSDocumentController in Leopard

Saturday, February 2nd, 2008

At the risk of provoking their ire and being branded a moron, I wish to dispute a claim that has been made several times by Rixstep about a supposed security vulnerability in Leopard’s NSDocumentController: Cocoa’s document controller overrides file system permissions without authentication. As far as I can tell, this claim is false.

I should note at the outset that I have nothing personal against Rixstep. Their syndicated feed has long been among my (numerous) favorites that I subscribe to in Vienna, as you can see by downloading the exported opml from my blog. I welcome legitimate criticism of Apple, and I have found Rixstep’s articles entertaining in the past, though of late they have become overly juvenile. As far as the whole ‘Cross-Platform Bait & Switch’ incident is concerned, I can’t comment on the legality of reproducing the quotations, because I’m not a lawyer, but I don’t think that Rixstep can be accused of misquoting or quoting out of context in this case.

Anyway, I’ve included the full text below of the email I sent to Rixstep a month ago. Retraction was perhaps too much to hope for, but I thought they would at least stop making the false claim after reading my email. They haven’t, which is why I’m now ‘going public’. (This should knock Britney off the front page.)

Hi. I read your article at <http://rixstep.com/2/1/20071227,00.shtml>, and it got me a little worried, so I did some testing. My results are that NSDocumentController in Leopard does not allow you to override Unix permissions. In fact, NSDocumentController in Leopard is more strict than the Unix permissions: it won’t allow you to save a writable document when you don’t have write permissions for the enclosing directory.

You are correct that saving a document always deletes the existing file and creates a new one with a different inode, and you are also correct that some of the user-visible NSDocumentController warning messages are misleading. However, if you don’t have write permissions for a directory, then NSDocumentController won’t let you delete or add a file, and even if you do have write permissions for the directory, NSDocumentController won’t let you delete someone else’s file or add a file with the same name if the sticky bit is set.

Thus, I believe that the ramifications for system administrators are negligible. With certain Unix permissions, it has always been possible to delete a file in a directory and replace it with a new file of the same name. Leopard has not changed that at all, so system administrators should take the same precautions against this scenario that they have always taken.

-Jeff

You don’t have to take my conclusions for granted, though. In a matter of minutes, you should be able to throw together a bare-bones document-based application suitable for testing the behavior yourself.

I have no desire to discourage criticism of Apple or Leopard. There are major problems in Leopard, and I don’t yet find it acceptable for use as my primary operating system. I just think that this spurious security issue obscures the real issue of whether the new Leopard NSDocumentController behavior is desirable.

P.S. If you really want to talk about a waste of precious disk space, /Applications/Mail.app/Contents/Resources is an astounding 277 MB on Leopard.