Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts in Development

Mike Ash recently posted about code signing. We’d talked about the subject a few days before and that is a great summary of Mike’s thoughts about it.

Code signing on Mac OS X is still evolving, but with the release of the iPhone SDK, the subject is suddenly being thrust into the limelight. To quote the Wikipedia article:

Code signing is the process of digitally signing executables and scripts to confirm the software author and guarantee that the code has not been altered or corrupted since it was signed by use of a cryptographic hash.

In the past, code signing has been used on several platforms with differing intents and implementations; Microsoft, for instance, has a driver signing program that lets only Microsoft-certified device drivers run without warnings on Vista. In contrast, here’s a statement from an Apple engineer on the apple-cdsa mailing list:

Windows “code signing” is not only completely different in design and implementation, it also has a completely different *intent*. The Windows version tries to determine whether *Microsoft* thinks your program (or driver etc.) should be used. Mac OS X Code Signing is a general medium to let the manufacturer and user negotiate as to whether/how they want to trust each other, with the system providing the infrastructure to make this possible.

From what I’ve learned about the subject so far, the Mac OS X implementation seems indeed to be aimed in this direction – there’s very little documentation available. Even less is, of course, available for the iPhone OS implementation, and details are under NDA. But let me try to explain what I learned so far.

Mac OS X code signing is an implementation of the X.509 standard public key infrastructure. It depends on a cryptographical algorithm which gives reasonable assurance that signatures cannot be forged with currently wide-available technology. Of course that’s a rapidly moving target, and the twiddly mathematical details are beyond the scope of this post (and, in parts, of my poor brain too).

So, you can have signed executables (single binary files) and signed bundles (which can applications, frameworks, plug-ins and so forth). A signed bundle is easily distinguished by the presence of an extra “CodeResources” file inside the bundle’s Contents folder. This file is a XML file containing, among other data, a dictionary that contains a hash code for every file inside a bundle. It also has a list of “optional” files or folders; this allows you to remove things like unwanted localizations from an application without invalidating the signature. Of course, if you later re-add a localization its hash codes must match the one inside the file. Additionally, a signature is added to the bundle’s executable.

If you check Mac OS X’s system folder and applications, you’ll find that, beginning with Leopard, every framework, application and command-line tool is signed. This signature, by various convoluted means, is checkable (currently only by Apple’s codesign command-line tool). It also points back at Apple’s “root certificate“. This certificate is is a component in X.509’s chain of trust tree, which basically tells you which authorities certify that a particular signature is valid; in effect, when you reach the root of such a tree you have to decide whether the root certificate can be trusted. (X.509 also can be used for distributed, or peer-to-peer, trust networks.) Let’s see how you can check this in practice. Open Terminal and try this:

$ codesign -vvvv /Applications/Safari.app
/Applications/Safari.app: valid on disk
/Applications/Safari.app: satisfies its Designated Requirement

(as usual, type the line after the $ prompt and you should see the resulting lines.)

So this means that the Safari application is signed and its signature is intact. Otherwise, you’d get either a “code object is not signed” message, or if the signature has been tampered with, a “code or signature modified” message. Now let’s try a small variation on the command:

$ codesign -dvvvv /Applications/Safari.app
Executable=/Applications/Safari.app/Contents/MacOS/Safari
Identifier=com.apple.Safari
Format=bundle with Mach-O universal (i386 ppc7400)
CodeDirectory v=20001 size=7621 flags=0x0(none) hashes=375+3 location=embedded
Signature size=4064
Authority=Software Signing
Authority=Apple Code Signing Certification Authority
Authority=Apple Root CA
Info.plist entries=23
Sealed Resources rules=9 files=283
Internal requirements count=1 size=68

This gives more information. Specifically, we see that there are 3 “certification authorities” included into the signature, and that there is one “internal requirement”. To see this requirement, try:

$ codesign -dr- /Applications/Safari.app
Executable=/Applications/Safari.app/Contents/MacOS/Safari
host => anchor apple and identifier "com.apple.translate"
# designated => identifier "com.apple.Safari" and anchor apple

This is admittedly hard to wrap your neurons around. From what I understood, the “requirements” are actually a little language that establishes what conditions the signed bundle should satisfy. But satisfy to able to… what? Now there’s where everything is (on purpose) still a little vague. “anchor apple” apparently means that the basic requirement is that Apple’s root certificates be present and trusted. Open the Keychain Access utility, click on “certificates”, and you’ll see somewhere in the list a certificate called “Apple Root Certificate Authority”. You can double-click on it to see details.

But what is all this useful for? Your proverbial “Aunt Tillie” will certainly not be interested in typing commands into Terminal, following certificate chains, and reading up on trust audit procedures. Apple’s keychain software tries to make all that as transparent as possible. Simply logging into Mac OS X can open parts of the keychain, and when Aunt Tillie goes to her banking site, the bank’s certificate should be checked against the keychain’s certificates and with the issuing certification authority, and everything should “just work”. For that to be reliable, Safari’s code signature should also be checked – otherwise it could be hacked by some malicious entity to say that the bank’s site checks out OK even when it’s some phishing site masquerading as that bank!

Signatures and certificates are also checked by the parental control preference panel, by Mail when it receives signed e-mail, and so forth. You may be familiar with the dialog asking if a recently-updated application may access the keychain to store or retrieve passwords; for signed applications, this dialog will be issued only once. If a newly-installed update has the same signature as the previous version, which had already been authorized to access the keychain, it’s assumed to also be trusted to do so.

A similar scenario applies to critical code such as the codesign executable itself. Ideally, such code should refuse to run if it’s modified; Apple has some facilities already in place to do so, and even to detect if an executable ihas been modified while it’s already running by some malicious code injection. However, that sort of thing isn’t widely used yet; mostly because it would break certain facilities, like Input Managers, that people currently rely on.

One aspect I haven’t touched upon yet is the so-called “self-signed certificate”. This is a certificate which is its own root certificate, like the top certificates of the various ‘big” authorities. The difference is that these authorities are large companies that undergo serious auditions and verifications. As an example, Quay is currently self-signed; I’m still evaluating how to publish my certificate in a way that easily allows my users to check if new versions have indeed been signed by myself. Let’s run one of the same verifications on Quay:

$ codesign -dvvvv -r- /Applications/Quay.app
Executable=/Applications/Quay.app/Contents/MacOS/Quay
Identifier=net.brockerhoff.Quay
Format=bundle with Mach-O universal (i386 ppc)
CodeDirectory v=20001 size=245 flags=0x300(kill,hard) hashes=6+3 location=embedded
Signature size=1671
Authority=Rainer Brockerhoff
Signed Time=Mar 8, 2008 08/03 22:28:09
Info.plist entries=14
Sealed Resources rules=4 files=18
host => anchor apple and identifier "com.apple.translate"
# designated => identifier "net.brockerhoff.Quay" and anchor leaf = H"4cbb97c74336f7ee6aa566122a5e7688e1c725dc"

See the difference? It shows only my name as authority, and a SHA1 hashcode at the end. I could publish this hashcode on my site and it would be not too difficult for a technically knowledgeable user to verify that his copy of Quay matches that.

What does this really mean? Actually, not too much. It means that two versions of Quay that give identical names and hashcodes, which additionally match the ones published on this site, giving reasonable assurance that the author of both versions and of the site are the same; but nothing at all beyond that. However, there are ways around that – SHA1 hashcodes can be duplicated with some effort, though perhaps not yet for certificates, and this site doesn’t have a secure (https) variant. A malicious person could easily strip away my code signatures, resign everything with a new self-signed certificate using my name, make a phishing site that looks like mine, and so forth, and to a normal user everything would appear to be OK. Would someone do that for a €7 utility program? Very probably not worth the trouble, but you can’t be sure.

Then again, I could invest in a secure site, an official certificate signed by a trusted authority – perhaps even by Apple itself – and all that would just make the code signature itself more reliable; it wouldn’t necessarily correspond to what extent the code itself can be trusted to always “do the right thing”.

As Mike points out, there’s a huge gap between “signed” and “trusted”. Ultimately you have to trust somebody, or you would be too scared to buy a box at a computer store and open it, much less connect that computer to the Internet or let your children touch it. If I buy a certificate from Apple, and use that to sign my code, you have to trust someone in the certificate chain even if my code seems to “just work”… it wouldn’t necessarily mean that Apple has audited and quadruple-checked my source code. Indeed, it doesn’t even touch the question of whether Apple as a company can be trusted!

All that is still largely theoretical; Mac OS X still runs unsigned code with no problem, even though with some small restrictions regarding use of the keychain, the firewall, and internet access as I mentioned above. But Apple engineers say that in the future code signing will become mandatory. In the next post, I’ll try to discuss the implications of that – especially regarding the upcoming iPhone OS 2.0, where it will be mandatory from the outset.

Forgot to link to Macworld’s iPhone FAQ, which also tries to answer many questions about the business aspect.

To sum up, anyone can register as a developer and run applications on the included “Aspen” simulator. However, to run your app on an actual iPhone or iPod Touch, you need to invest $99. This gives you a code signing certificate that will be attached to your applications. I’ll post more about code signing later, but in essence this certificate is a code that uniquely identifies you (the developer) and is tied to Apple’s master certificate. It’s not counterfeitable by current technology. Whenever some software is executed by the iPhone, the system first checks its signature. If it’s not signed, it won’t run at all. If it is signed, the certificate will be either Apple’s own – in which case the software presumably will have full access to all system functions – or it will be a “normal” developer certificate. In that case, the application will be allowed to run with restrictions inside a sandbox – a separate folder contain the application and its data.

Once your application is tested, you must send it to Apple to be considered for inclusion into the App Store. This is a central marketplace that will be accessible directly from the iPhone or from iTunes. Apple may not approve your application; some broad guidelines were mentioned, and hopefully will be clarified before the store goes online by the end of June (after WWDC). In any event, approved or not, you’ll have no alternative way of distributing; both iTunes and the iPhone OS will only load new applications from the App Store. Presumably approved applications will have a stronger certificate which is checked at installation time, and which can be remotely revoked by Apple if your application is latter deemed to be “untrusted”.

One particular “forbidden” application type is one that downloads and runs plugins, interpretable or executable code from elsewhere. Of course that can’t be taken too literally, or it would exclude (for instance) JavaScript on a web page. Still, it would at first glance forbid Java; even so, Sun has announced intentions to produce a free Java virtual machine for the iPhone. No word yet from Apple about that, but you can presume that all those rules will have exceptions whenever Apple considers it convenient to make them.

For “indie” developers like myself, the App Store seems to be a good idea. You get 70% of the sales price. Free apps are allowed, too. In comparison, I get 85 to 90% of the sales price in my current arrangements for Mac software – but I spend some of that difference on bandwidth, site maintenance, and customer support. I personally spend almost nothing on marketing and advertising, but some developers do spend more. The App Store idea is that Apple takes care of all the business details for you, and it’s not an unreasonable deal.

Many people are discussing the implications of consenting to Apple’s rules in order to being allowed to publish iPhone applications. Personally, I’m not too bothered. Like any finite game, you can consent to play or not, but once you do, you have to play within the rules.

Speaking of rules, some of them are none too clear yet. It seems that publishing a free version that is unlocked by a serial number, as we’re used to, is not allowed as such; I suppose you’ll have to do a free version and a paid update. How would I send my app to another user for beta-testing? Unless that user also has the SDK and a certificate, and if I’m willing to send over my source, that seems to be impossible. For now, I suppose you can compile a simulator version and send the object code to some other SDK user; good for checking out the user interface maybe, but not a real-world test.

Support is also tricky. Will Apple do support for all the apps? I doubt it. If someone emails you with a support request, how can you, since there are no serial numbers, check that the request comes from a legitimate user? And you can’t send out a special version for testing, either. Hopefully Apple will explain this soon.

Next: code signing.

Update: forgot to explain the $99. This appears to be an annual fee, much like the $500 I pay now every year for the “ADC Select” program. Does this mean that the developer certificates expire after a year? Well possible, but will that also affect applications already on the App Store? More questions…

Well, there’s little actual information to add to Gruber‘s and TidBITS usual comprehensive write-up, but maybe I can explain some parts in more detail, or provide an opinion on how this will impact developers in the future.

Regarding SDK details as such, most of it is under NDA, which I signed yesterday; but some details have been published already. It’s common knowledge that it includes Xcode 3.1, which will very soon be available as an independent (and free) download, and of course included on installation DVDs with any Mac as soon as it gets out of beta. It also includes Interface Builder 3.1 but not the special objects to directly build iPhone windows; this will no doubt follow in the next release.

I was looking forward to getting my hands on the iPhone UI – to date, I haven’t seen one in the flesh (same for the iPod Touch). But fortunately the simulator includes Safari, so at least I can check how this site looks; some pages come in too wide, and I’ll tweak them as soon as I find time. Still, the UI for the few included apps looks great and it’s useful to get a feel for all the animations. Speaking of the simulator, it’s not a hardware-level simulator; it seems to run x86 code, no doubt an easy way to make it even harder for hackers to glean information about the actual iPhone OS implementation.

I suppose this would also explain why the current SDK is Intel-only; the PowerPC version might not have made it in time, or may be too slow, or whatever. Still, it’s a bad precedent. Intel Macs seem to be about 50% of the installed base by now, a year before I thought that would happen, but it’s still too soon for people to stop doing Universal applications. For what it’s worth, I had to install everything on the only Intel Mac I have – a Core Solo mini with 512MB RAM – but it seems to run quite well despite the cramped hardware.

This “iPhone OS” name now seems to be the new “OS X” and it’s… clumsy. Not a good way to indicate a new platform that already includes the Touch and before the end of this year (or so I think) will get new members. Indeed, there are hints that both “mobile” and “touch” were at one time or another the platform name du jour, and hopefully this will prove to be just a beta name.

Certainly nobody in the Mac developer community was surprised that the SDK is based on Xcode, Cocoa and Objective-C; doing otherwise would mean a complete rewrite of the current 1.1.x firmware, and Apple hasn’t enough manpower to pull such a thing off. Besides, it’s certainly a good way to get Macs into the hands of new developers. Still, no doubt some people are miffed or surprised that the SDK doesn’t run in Visual Studio, or that there’s no Java or .NET support; I can imagine them complaining to Microsoft about this (hey, Microsoft owns a good chunk of Apple, or so they probably believe).

Next: the business part. That’s where it gets interesting.

I pushed Quay 1.1b3 out a few days ago and immediately had to quick-fix and slip in a new build (same version number) because of an endian issue on Intel Macs.

Yes, I should have tested this; for some reason, all people I asked to run preliminary builds also were on PowerPC Macs – including two I’d have sworn were on Intel. Murphy never sleeps. My own solitary Intel machine – a rock-bottom mini (Core Solo, 512MB) – had been down for almost a month, having had some indigestion with one of the last Leopard betas, and I finally spent an afternoon wiping it and reinstalling 10.5.1 on it (also seizing the opportunity to confirm that Qay still runs well, and with almost all features, on that version).

Curiously enough, this made me notice that two steps in my build chain (utilities that generate intermediary files) are still PowerPC-only and break when I build the project on an Intel machine. Must fix that because pretty soon I’ll have an Intel laptop available, and it must be able to do full builds.

I hope to have the next version out in the middle of next week. I’ve already fixed one issue – an oversight in the last rewrite made it stop working for folder aliases dragged directly into the Dock. There are a smaller bugs outstanding, but nothing too serious. Unless something turns up that requires serious testing in the field, the next release will (I hope) be 1.1 final.

Quay is the first software I wrote from the outset to be localized. Once you take some precautions this is relatively easy to do in a Cocoa application, and I’m talking to Ronald Leroux, a well-known localizer for French, to see whether we can get a pilot French version in time for 1.1. There are a few obstacles; I’m used to fiddling around with text right until the last minute; current localization software isn’t quite working yet for the new-fangles nib files used by Leopard/Xcode3; and code signing proves to be an unexpected puzzle.

Well, of course I can put all the current localization into the application bundle and sign it, and everything will “just work”. However, 99.9% of users will use only one of the included languages and some of those would be happy if no others were present. Code signing (at least the standard way which I’m using) doesn’t like files or folders removed from the application, nor does it like added items. It would indeed be nice if the various languages were present on the installation disk image but the user should be able to opt only for the currently enabled language, for instance. And it would also be nice be able to download additional or new languages as they become available.

I do have some ideas for workarounds to that issue, but I’m not sure they’ll work in time for next week’s release – be it 1.1b4 or 1.1 final. In any event I’m very anxious to finish off 1.1, as I’ve got serious plans for 1.2; a new GUI is only one aspect of that. Stay tuned.

Update: regarding localizations and signing, Mike Ash just reminded me that you can remove localizations without messing up the signature, but you can’t add new ones. I found out, however, that you can put a new localization somewhere outside the application bundle and then add a symlink from the resources folder from there. Interesting.

Design snowball

No comments

Interesting how some design choices you make early on cause a “snowball effect” – many product details end up depending on these choices. Sometimes you have to go back and change the initial direction of the snowball, so to speak, because some of those end effects turns out to be unacceptable.

When I started rewriting Quay for the first 1.1 public beta, I decided to change the way the background application (QuayMenu) was run. In 1.0, a Quay icon in the Dock was a file hidden away inside the Quay database package. When the user clicked on the icon, QuayMenu started up (if it wasn’t running already), and presented the menu. This simple scheme interfered not at all with the Dock itself but depended on several tricks to find out, approximately, the on-screen location of the clicked icon – something that a normal application doesn’t need to know. (It also didn’t work at all if you accessed the Dock over keyboard navigation.)

For 1.1, I decided to convert QuayMenu into a LaunchAgent: a per-user background application that runs constantly and is restarted by the system if it fails. I also worked out a way to have QuayMenu monitor click and keyboard events for the Dock, and use the Accessibility APIs to work out exact locations and details of a clicked Dock icon. So when the user clicks on a Dock icon, QuayMenu checks out if it ought to handle that click and pass it on if not.

This design decision had immediate consequences. It’s much easier to control (and update) a LaunchAgent if it’s in a fixed, known place. I decided to store the main Quay application inside the Quay database itself (which is in ~/Library/Application Support), both to prevent the user from moving it and to have a single known location for updating. The idea of having everything inside ~/Library stems from complaints I had about XRay storing stuff inside /Library, years before. So there was an a priori concern to make Quay a simple, no-hassle, per-user application; nothing stored outside the user’s home folder, no administrator password needed, no security concerns.

However, this immediately conflicted with the need of using the Accessibility API. Basically, if you use this API to ask other applications about their user interface, you have two options. You can wimp out and ask the user to turn on “Enable access for assistive devices” in the Universal Access preference panel, or you can run a “trusted” accessibility client. The first option means that you depend on the user having this turned on all the time; if it gets turned off, things stop working and you have to show a dialog asking for it to be turned on again; clumsy. Also, some people (including myself) don’t like turning this on because it changes the way tabbing between text fields behaves – it then tabs over buttons too.

The second option – running as a trusted client – was the better one, then. However, it too comes with a trade-off. A trusted accessibility client runs “setgid 90”, meaning the executable is forced to run from the special “accessibility” group. This is a tamer version of the tricky, all-powerful and potentially unsafe “setuid root” executable; its only advantage over a plain vanilla executable is that it can see (and affect) other applications’ user interface elements. However, there’s one common aspect; to turn the setgid bit on, you need to ask for an administrator password. As a side-effect, copying the executable to another place turns the bit off again, and it’s ignored altogether if run from an external volume or a disk image.

All this meant that I would have to write an installer to move the applications into their place, ask for an administrator password and turn on the setgid bit. Apple’s guidelines say that in such a case you should do a standard Apple Installer package and have all this accomplished by scripts inside the package. I decided against that for several reasons.

One, it’s harder to check an installer package against unauthorized modifications, while an installer application can use code signing to prevent those. Personally, after some bad experiences with badly-written install scripts, I distrust installer packages a bit more than separate installers – although I know people who distrust installers even more. The third option, of writing a self-checking, self-repairing application that could be drop-installed anywhere – as Quay 1.0x was – I reluctantly discarded. Some people prefer to have multiple copies of applications available, some use weird separate application folders (as was usual in the Classic days), and if you back up your applications with Time Machine, you’d have copies right there which shouldn’t be accessed except when restoring from the backup volume.

So the decision of writing a suitably self-explanatory and “just works”-type installer appears to be the right one. It’s actually working pretty well in the current (1.1b2) beta… except that I’d forgotten one important thing. FileVault (on the list of system features I don’t use myself) is based on a special “sparse” disk image that is mounted in place of your home folder. Meaning that, if you use FileVault, you can’t have setuid or setgid executables inside your home folder – and certainly not inside ~/Library.

OK, so I’m dutifully rewriting my installer to move everything into /Library which has no such limitations. An added advantage is that now there’s a single copy of Quay installed for all users; but should the serial number, then, also be valid for all users? That means the added hassle of separating the preferences into yet another file, installed into /Library/Preferences; one more thing to uninstall. An added disadvantage is that, now, the uninstaller – which I’m building into the Quay application itself – will need to ask for an administrator password, too. Or maybe I should have a setuid root uninstaller tool inside the application; I don’t like that either, but having such a tool would also mean an easy way of adding extra functionality to the Quay popups.

Well, all these are trade-offs, and I hope that when 1.1 (final) comes out, that the net effect will be positive. If all goes well, 1.1b3 should be out sometime next week, and you’ll have the chance to comment. Stay tuned.

Re: Quay vs. 10.5.2

No comments

First post! This year, that is. Wow, time flies.

I’m glad to report that my back is all cleared up and I’ve been working away at the upcoming Quay update. And yes, it’s another complete rewrite, at least where the background application is concerned. So far it looks like I’ll have either a beta or an intermediate version out over the weekend.

The main feature on this will be that, for normal Stacks, the whole drag-to-window/then-drag-to-dock procedure will be gone. Quay will work automagically (but optionally) on your Stacks! The positive side-effect is that you’ll also be able to drag stuff to them; the negative side-effect is that, for now, you won’t have custom icons. You can of course still build the old-style Quay dock items, with not much new for those.

The final version of this must await the launch of Mac OX 10.5.2. Not that I can comment on what exactly is changing on Apple’s side, but I’d like to reassure all Quay users that Quay will continue to offer significant extra functionality. In fact, I’ll be repositioning Quay as “the Leopard Dock enhancer utility”.

However, this raises the usual question: what do you do when you have some shareware on the market and suddenly someone – either Apple or a third party – comes out with a free solution to the same problem? There are some freeware utilities out that purport to do more or less what Quay 1.0 does, and there are 10.5.2’s rumored capabilities, but of course I’m confident that the new version will be sufficiently more powerful and polished to merit wide adoption by the market.

Something similar just happened in another segment of the Mac market: Newsgator’s NetNewsWire, the premier RSS reader for the Mac, is now free. There are some interesting comments out there. I do know a few developers that have RSS readers in the works, and no doubt they’ll have to rethink if they should continue or not. I don’t know if free RSS readers have had any impact on NetNewsWire sales in the past, and of course they’ve always had their own free “lite” version. It also seems that Newsgator’s decision was based more on their network business than on the Mac shareware market as such, so this probably isn’t a canonical example.

Still, developers entering the Mac shareware market nowadays should really think twice about such a possibility. If something seems easy or obvious to do, better to release it outright as freeware; it may not help the bottom line, but it helps build experience and buzz around your name.

So, somewhere around the beginning of this month I was resting a bit from writing my book (which I’ve mentioned in passing here), and it struck me that the complaints about Leopard’s Stacks weren’t dying down – if anything, they were growing more numerous. I hadn’t really used Tiger’s Dock popup menus much, but I really thought someone would find out a way around it soon.

But when I searched – not too intensely at first – for such a solution, I found that the existing ones were really quite (searching for a charitable word here)… feeble. They all depended on something outside the Dock itself. And this struck me as what Apple likes to call a “third-party opportunity”.

So while I was testing out some sample code for the book, a few days later, I thought I could play around with it and find out what could be done with the Dock. I immediately noticed that putting a proxy icon in the Dock might be doable, and popping up a menu from there might be too. In a few days I had a primitive version of the menu itself working – I decided it had to be a background/foreground application pair.

Up to then I hadn’t put much time in but when I tried to do the foreground application I began hitting some snags. On November 10 – 20 days ago – I decided to throw everything I’d done so far away and start over from zero. Two days later I had a working alpha to show to some friends, and on Nov.15 I decided it was good enough for a public beta. It took a day to make the necessary changes to my site, prepare listings on the various software sites, write a press release and so forth.

Response to the first beta was so good I decided to keep at it full-time; I also figured that, now that people could see how it might be done, competitors would soon appear. Anyway, on Nov.27 – version 1.0 came out, and today, exact 20 days after restarting the project, 99% of known bugs are fixed in 1.0.1. (In case you’re curious, double-clicking still doesn’t work satisfactorily.) And I still haven’t heard of any full-featured competitor… yes, the principle is easy, but the details aren’t.

So far I’m quite satisfied with the responses. One thing I hadn’t foreseen was the number of people not content with popups – many also want to drag & drop files on the Dock folders. And this didn’t crop up in the complaints I read, because you can drop files on Stacks! But I rarely or never did that, so it was a surprise to me.

The problem is, to the current Dock, every type of item is handled differently. An application goes into the left side. Files and folders go into the right side; folders become Stacks, and can receive drops; files can’t. On the other hand, files can be clicked on – that is, the application that “owns” them is notified – but for folders, nothing happens. I tried various combinations of packages and bundles to get a folder that could be both clicked and dropped on, but no luck.

Compounding the difficulties was my resolution to “use no magic”. I knew this would be a powerful positive factor; users are tired of side effects caused by applications hacking the system. However, this meant that the Dock would never know I was doing something around its functionality, and, since there’s no public API to get information into and out of the Dock, I was quite restricted in what I could do.

I was also surprised that, despite my explaining all that on the product page, and repeatedly in response to questions in the support forum, people kept writing in with suggestions that showed that, for them, Quay did hack the Dock somehow – or even was a plugin for it. That’s the downside of when your technology “just works”: people’s mental models of what you’re doing can often diverge severely from reality.

Speaking of which, here’s my favorite review:

Just been playing with Quay. Rainer is a mad man. It takes true insanity to hack the dock without actually hacking the dock.

None of this would have been possible without Cocoa; I can’t imagine writing such a complex (internally, that is) pair of applications in anything else in 20 days. Many of the pieces – regarding registration and serial number handling, especially – came from my work on XRay II. Some of the icon and file handling routines were also adapted from there. The flipping “About” window is straight from my Flipr code; as soon as I find time, I’ll rewrite that for CoreAnimation.

Looking over the code today I was struck by the diversity. The main Quay app uses mostly NSWorkspace and NSFileManager, but then suddenly dips into Carbon to handle icons and some menu aspects. The background app (QuayMenu) uses mostly FSRefs and some BSD stuff for file handling, but it’s of course written in Cocoa, too.

A great side-effect of Cocoa is that, once your infrastructure is in place and coded properly, adding most new features is just a matter of a few lines; when it requires more, it shows that the original design wasn’t powerful enough. A good learning experience.

In line with others detailing goodies (Matt Legend Gemmell and Blake C. are two I remember), here’s a new Leopard API that appears to eliminate an entire page of my old code:

FSRef ref;
// now point FSRef at some file or folder

IconRef iconRef = NULL;
GetIconRefFromFileInfo(&ref,0,NULL,0,NULL,kIconServicesNormalUsageFlag,&iconRef,NULL);
NSImage* image = [[NSImage alloc] initWithIconRef:iconRef];

Then you can do setSize: if you want a particular icon size for that file or folder.

True, if you had a path to the file, you could always do:

NSImage* image = [[NSWorkspace sharedWorkspace] iconForFile:somePath];

but if you’re already handling FSRefs, getting a path back from it is slower and also suffers from the PATH_MAX limitation (1024 bytes maximum path size).

I also seem to remember that NSWorkspace fails for certain types of file system items, but I can’t quite recall which ones right now. It does work for run-of-the-mill folders, apps, and files though.

Photos licensed by Creative Commons license. Unless otherwise noted, content © 2002-2025 by Rainer Brockerhoff. Iravan child theme by Rainer Brockerhoff, based on Arjuna-X, a WordPress Theme by SRS Solutions. jQuery UI based on Aristo.