Solipsism Gradient

Rainer Brockerhoff’s blog

Browsing Posts tagged Cocoa

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.

Re: Flipr out

No comments

Some time ago I published Flipr source code:
Rainer Brockerhoff wrote:

…a category on NSWindow to flip from some window to another window.

I’m not sure how many people adopted it, but the nice Karelia folks are using it in the upcoming iMedia browser. A few days ago they asked me to look into a “hesitation” effect which could be seen in the first frames of the animation in certain circumstances, and it’s now fixed… so if you used it somewhere, download it again (and tell me).

One of the salient points repeated at the WWDC keynote was Leopard‘s support for “64 bits top to bottom“. However, a close peek at the slide shown this year showed a subtle difference to last year’s – the word “Carbon” was missing. Of course a storm of confusion soon ensued, with the usual wailing and gnashing of teeth from some quarters and polite shrugging from others. Apple stock fell and rose again, some developers professed bliss while others threatened to leave the platform, non-developers wrote learned analyses about obscure technical points, not to speak of reports of raining frogs or even an unconfirmed Elvis sighting in a Moscone restroom. Allow me to try to explain all (well, Elvis excepted).

First of all, there are a few implications in moving an operating system to 64 bits. I hear that Windows Vista comes in distinct 32-bit and 64-bit versions and that the latter is able to run 32-bit applications (with some restrictions) inside a compatibility box. In contrast, Leopard uses Apple’s experience with architectural migrations to support 32 and 64 bit applications natively on both PowerPC and x86 architectures – not so easy in the second case, but necessary since nearly all currently shipping Macs use Intel’s Core 2 Duo, which is 64-bit capable.

For this, Apple took advantage of Mach-O’s support for “fat binaries” – in this instance called “obese”. Obese binaries contain four different executables: PowerPC 32, PowerPC 64, x86 32 and x86 64. When running one of these applications, the system selects the best supported architecture and links the application to the corresponding (and equally obese) system libraries.

Enter the Carbon vs. Cocoa question. Cocoa APIs are derived from NeXT’s software and are called, usually, from Objective-C. Carbon APIs, to be called indistinctly from C, ++ or Objective-C, were first introduced in Mac OS 8.5 or thereabouts and were, themselves, a much-needed simplification of the “Classic” Mac APIs. Carbon was thereafter positioned as the way to port existing applications to Mac OS X, while Cocoa was supposed to be the right way to write new applications for the new system. No doubt the old NeXTies inside Apple pressed for Carbon being excluded from the start, but Microsoft, Adobe and Macromedia (to quote just the big companies) didn’t want to recode everything on short notice.

A necessary sidenote: the exact definition of “Carbon” is surprisingly hard to pin down, even among experienced developers. Here’s my own (although I’ve never written a Carbon app myself). There are Carbon APIs and Carbon applications. A Carbon application, for me, uses the Carbon Event Model – calling Carbon APIs to get events from the system. Until recently, a Carbon application would also, necessarily, use Carbon windows and the GUI widgets for those, mostly contained in the HIToolbox framework. Starting with Tiger it’s possible for Carbon applications to use Cocoa windows containing Cocoa GUI widgets, with some contortions of course. Other Carbon APIs – like the File Manager, or QuickTime – can be called indistinctly from Carbon or Cocoa applications.

Here’s where things started going awry, from the standpoint of established or multiplatform developers. Apple has always been of several minds about Carbon policy – it was often dismissed as a temporary “transition” technology, while people who interfaced with those developers had to reassure them that Carbon was not going away anytime soon and was not a second-class citizen. Porting software from the Classic Mac OS to Carbon wasn’t always easy; some larger applications took over a year. At the same time, it was seen as being much easier than tossing the whole codebase and recoding in Objective-C/Cocoa.

Now, a few years after Mac OS X was introduced Microsoft, Adobe and so forth had a substantial investment in maintaining parallel codebases for their Carbon applications and, understandably, began dragging their feet about converting to Cocoa at any time soon, or even at all. Due to pressure from these developers the Carbon GUI APIs began to incorporate new elements present only in Cocoa until then, and to all appearances Carbon and Cocoa were now positioned as equal and parallel APIs. In secret, of course, Apple hoped that “those people” would sooner or later see the light and begin doing their next x.0 version in Cocoa. In turn, “those people” harbored serious doubts about Objective-C (seeing it as a dead language with an unreadable syntax) and secretly hoped Apple would “recode Cocoa in C++”. Here’s a significant e-mail from an Apple engineer to the carbon-dev list:

No one reading this list should be under any illusions about Apple’s use of Objective C. Apple really likes Objective C. There are a lot of third-party developers who are using Objective C to program for Mac OS X and who really like it. Apple is not going to stop using Objective C. I’m not making a value judgement here, just stating a simple reality that everyone needs to understand. Do not think that someday Apple will “wake up” and realize that it would be better to recast all of our APIs in C++. That’s not going to happen.

So then came the PowerPC/Intel transition. Cocoa developers already were using Xcode, while many Carbon developers still were using the defunct Metrowerks CodeWarrior; transitioning large codebases to Xcode proved to be cumbersome. Still, people threw in more person-years to bring their apps up to the new standard. Then, at last year’s WWDC, Apple announced the migration to 64 bits, taking the opportunity to remove all legacy, obsolete or deprecated APIs from the new frameworks. Some Cocoa APIs were removed but, again, Carbon developers had more work to do. So once again, more person-years of work were invested.

It now seems that someone in Apple engineering management decided that they couldn’t afford to keep supporting two separate-but-equal APIs anymore, and the “transition” policy was revived regarding 64-bit Carbon applications. From what transpired during WWDC I deduce that some more of the Carbon APIs were taken off the “supported for 64-bit” list, most notably the part of the HIToolbox that concerns Carbon windows and GUI widgets. Therefore, 64-bit Carbon applications would seem to be either not supported at all, or supported only in a transition mode that used Cocoa windows and GUI widgets.

Naturally, Carbon developers were very bitter about this, while some Cocoa developers were asking if their 64-bit Cocoa apps would be able to call normal Carbon APIs (the answer is yes). So far, the most complete explanation I could find is this one (from the same engineer):

Fundamentally, Apple engineering is focused on Cocoa much more than Carbon, and Apple’s engineering management made the decision to un-support 64-bit Carbon to emphasize that fact.

So there you have it. Summary: 32-bit Carbon stays where it is and works fine until further notice – I don’t think they’ll be “deprecated” any time soon. The Leopard Finder itself is still a 32-bit Carbon application! Not until Mac OS 10.6 (LOLCAT, or whatever they’ll call it) comes out, which may take 3-4 years at least, and probably not even then. But 64-bit pure-Carbon apps may be unsupported, or even not run properly, when Leopard comes out in October. Cocoa isn’t going away, and is the future. Has been the future since Mac OS X 10.0 came out, in fact. On the other hand, there’s a migration path – use the Cocoa GUI, then later convert to a Cocoa app. People who have invested a lot of time in Carbon feel really bad about this, and I agree Apple mishandled this badly from a PR standpoint. On the other hand, investing a lot of time in Carbon is now revealed to have been a throw-good-money-after-bad move; some people say “I told you so”.

The final question is, how come neither Microsoft nor Adobe are screaming their heads off about this? While I was wondering about this, I realized that, for normal Mac users, Microsoft Office really doesn’t handle data sets big enough to need 64 bits; they can stay on 32 bit as long as it exists. As for Adobe, at first glance, Photoshop at the very least is just begging for 64 bits… really? Here’s what one Adobe engineer says:

I could have spent this whole cycle moving us to 64 bit rather than working on startup time, but would that give you more of what you want? Add 20 seconds to the startup time you are seeing for the beta for all versions/platforms of Photoshop and compare the value of that version to one where the histogram would be 10% faster on 64 bit machines (and most of the rest of Photoshop being 5% slower). It is true, there are some things, like histogram, that would be 10% faster, I wrote the code to verify this. But, the rest of the product would have been slower without a few people spending the whole cycle going over all of the slow parts and bringing them back to where they were on 32 bit. Most operations on a 64 bit application like Photoshop are actually slower by a small amount if time isn’t spent optimizing them.

Read the excellent comments on that post, especially the more recent ones, for much more discussion of the details on the Photoshop side – I suppose many of those would apply equally to other large Adobe/Macromedia apps.

So there you have it.. the big guys don’t need to move up for now. The small guys are mostly in Cocoa already. Unfortunately, the intermediate cases have fallen into the crack for now – think multiplatform CAD software for instance. It’d be very sad to see them leaving the platform in a huff about this; I sincerely hope Apple will contact all of them privately and smooth things over for now, somehow, though I can’t really imagine how. Maybe they’ll even re-add support in October, now that the point has been made.

Update: fixed a misconception about the PowerPC->Intel migration, see explanation above.

OK, here’s what I wrote a few days ago, regarding the Mac OS X transition to Intel:
Rainer Brockerhoff wrote:

…Most Cocoa developers that didn’t call Carbon frameworks to any great extent, or that didn’t have to deal with complex binary files, were able to recompile their apps into the Universal (“fat binary”) format in a few hours or days. In contrast, most developers of Carbon apps of any complexity faced months or years of conversion.

I invited comments on Apple’s carbon-dev mailing list, and some people objected to the paragraph quoted above. In particular, Apple engineer Eric Albert wrote:

I’d probably moved more Mac OS X code to Intel than anyone else before the announcement — some of the iApps and a bunch of other apps, plus a ton of work in the OS — and of the code I’d worked on, the Cocoa apps happened to take more work than the Carbon ones. That was really nothing more than coincidence because the Carbon apps I was working on dealt with structured data better than the Cocoa ones, but there’s nothing inherently more complex about the Intel transition for Carbon than there is for Cocoa. Mathematica, which is most assuredly a complex Carbon app, took four hours to get up and running on Intel, faster than any other app I’ve seen.

The primary reason for some Carbon apps taking a long time to move to Intel was that they weren’t using Mach-O or Xcode at the time the transition was announced and both were required for Intel support.

Carbon apps already using Mach-O and Xcode came over to Intel fairly easily.

Well, that’s quite definite; I was wrong there. I was wondering why, though, and here’s what I found: the RDF is to blame… icon_wink.gif

Here’s what Steve Jobs said at the WWDC 2005 keynote, where I was physically present, and quite near the front too:

So, let’s take a look at this again: Widgets, Scripts and Java just work. Cocoa apps, literally a few days and your Cocoa app’s going to be running with an Intel version. Carbon apps, it’s to be a few weeks, a few more tweaks, although there are exceptions to that although we maybe overstating it here, which we’ll see in a minute. And and in Metrowerks we don’t know, you’ve got to get to Xcode. So the key here is getting to Xcode.

And I distinctly remember the same point being made later in the reserved “state of the union” sessions: click a checkbox in Xcode, “boom” for Cocoa… not that easy with Carbon.

There it is then. I don’t have any Carbon apps myself, and didn’t have to migrate anything from Metrowerks CodeWarrior either, so I thought Carbon was to blame for stuff like the Adobe Photoshop delay. I’ll update my original post below; thanks to everybody who sent in comments.

Posted by Stefan Tilkov’s Random St:
Stefan Tilkov’s Random Stuff linked to this post

64-bits, Carbon, and Cocoa

Excellent analysis on Rainer Brockerhoff’s Weblog: One of the salient points repeated at the WWDC keynote was Leopard’s support for “64 bits top to bottom”. However, a close peek at the slide shown this year showed a subtle difference to last year’s – the word “Carbon” was missing. Of course a storm of confusion soon ensued, with the usual wailing…

Rosyna asked on the carbon-dev list:

But it makes me wonder, is there anyway on Mac OS X to generate a”fast path” from an FSRef? That is, a path that is just the supershort volfs version of the path?

I need to use this myself now and then, so here’s a code snippet that does that:

#import <Carbon/Carbon.h>
#include <sys/mount.h>
const char* shortPath(FSRef* ref) {
   FSCatalogInfo info;
   if (FSGetCatalogInfo(ref,kFSCatInfoVolume|kFSCatInfoNodeID,&info,NULL,NULL,NULL)==noErr) {
      FSRef root;
      if (FSGetVolumeInfo(info.volume,0,NULL,0,NULL,NULL,&root)==noErr) {
         char* path = calloc(1,PATH_MAX+1);
         if (FSRefMakePath(&root,(UInt8*)path,PATH_MAX)==noErr) {
            struct statfs fs;
            if (!statfs(path,&fs)&&(fs.f_flags&MNT_DOVOLFS)) {
               snprintf(path,PATH_MAX,"/.vol/%lu/%lu",fs.f_fsid.val[0],info.nodeID);
               return path;
            }
         }
         if (FSRefMakePath(ref,(UInt8*)path,PATH_MAX)==noErr) {
            return path;
         }
         free(path);
      }
   }
   return NULL;
}

To use it, pass in your FSRef and you’ll get one of these back:

  • A short volfs path, if the volume supports volfs, or
  • A normal path if the volume doesn’t support volfs and the path is shorter than PATH_MAX, or
  • NULL.

If the return value is not NULL you’re responsible for freeing the path buffer after you’re done with it.

There are some issues with volfs paths you need to be aware of. The canonical reference here is Technical Q&A QA1113: The “/.vol” directory and “volfs”, which says:

WARNING:

Under no circumstances should your application construct paths within “/.vol”. This area of the file system is reserved strictly for the Carbon File Manager. The structure of the “volfs” file system is likely to change in a future releases of Mac OS X. You must use the following description of the “volfs” path structure for debugging and performance analysis only.

If you pass the path generated by my code snippet to any BSD routine it should work. You should however treat the path as opaque and not rely on its contents. About the only thing that also works is, if your FSRef points at a directory, you can concatenate the UTF8 name of a contained file (preceded by a slash) onto that path – you can’t add more than one though.

The snippet relies on one non-documented feature of the statfs call, namely, that the volfs volumeID is returned in the f_fsid.val[0] field. Needless to say this can break anytime in the future, and you may not want to rely on this for shipping applications. That said, it would certainly be useful to have the File Manager return a guaranteed short opaque path that could be passed to BSD calls. I plan to file a bug requesting this.

As QA1113 says, this could break in any future version of Mac OS X – I’m sure it works from 10.1.5 up to 10.4.9 though. You might want to insert a stat() call before returning the volfs path, if you’re really concerned about that… this is left as an exercise for the student.

Folks on the #macsb IRC channel were talking about testing if an application was being run from a disk image, and it occurred to me that some code from XRay (already being adapted into XRay II) would be suitable for that. They suggested making a category on NSWorkspace, so here it is.

So the sample app project has a category on NSWorkspace which takes a path argument and returns a NSDictionary with some details about the volume and device. The app shows the attributes for its own path first, then you can check any others. Easy to test if the path points into a disk image or network drive, too. Please read the “ReadMe” file for details and caveats.

Suggestions are welcome. Please test this on your system and on any weird disk images, external drives or network volumes, and send me the results if they don’t look OK.

Cocoa quickie

No comments

Borkware Quickies is a highly recommended collection of small, useful code snippets. Mark Dalrymple has been so kind to post one of my own there: “Making naked memory autoreleased”. Here’s a shorter and even more useful, though sometimes slower, version:

static void* tempCopyOf(void* data,UInt32 size) {
   void* buffer = calloc(1,size);
   if (buffer) {
      if (data) bcopy(data,buffer,size);
      [NSData dataWithBytesNoCopy:buffer length:size freeWhenDone:YES];
   }
   return buffer;
}

So, you can call this as:

void* thing = tempCopyOf(&myStructure,sizeof(myStructure));

which will give you a temporary copy of myStructure, or as

void* thing = tempCopyOf(NULL,someSize);

which will return a zero-filled buffer of someSize for you to fill in as you want.

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