Archive for the 'Carbon' Category

The myth of Carbon’s 64-bit unavailability

Monday, January 18th, 2010

There’s a recurring myth going around, which goes something like this:

In fact, using Carbon locks you out of 64 bit.

No, it doesn’t.

The truth is that some APIs that are part of the Carbon sub-frameworks are not available in 64-bit. Merely linking against Carbon does not mean your app suddenly stops working in the 64-bit world.

Carbon itself is just an umbrella framework. It doesn’t have any APIs that it provides immediately; everything comes from either another framework or one of its sub-frameworks.

Examples of the first category include Core Foundation, Core Services (home of Launch Services), and Application Services (home of Core Graphics). Even these are not immune to the myth, as demonstrated by the comment I linked to above: It’s on an answer suggesting a Core Foundation function. The answerer referred to it as a “Carbon function” (true in a sense), and the commenter pounced.

Many things that were once explicitly considered part of Carbon, such as the File Manager and Resource Manager, are now part of Core Services. Note that they haven’t even been consigned to the Legacy Library!

In the other category, even some APIs that remain strongly identified with Carbon, by being in a direct sub-framework of Carbon, are still at least partially around. One of these is the Carbon Event Manager, which even has the word Carbon in its name. Try registering a hot-key with it in a 64-bit-only app—it’ll work. (That one is in the Legacy Library. I should probably file a bug on that.)

What is deprecated and not available in 64-bit, as you can see in the Carbon Event Manager Reference, is anything that you would need to build your application on Carbon. That’s what’s deprecated: the concept of a Carbon application. Only Cocoa apps remain.

But some parts of “Carbon” are useful for things other than building a Carbon application. You can use them from a Cocoa application, or from a command-line tool.

Those APIs are still around. They are not deprecated, they are still useful, and they are still available in 64-bit. Use them freely.

(Oh, and before anybody mentions it: No, those NSEvent class methods introduced in Snow Leopard are not direct replacements for Carbon Event Manager hot-keys. You’d have to sift through the events yourself, whereas Carbon Event Manager filters them for you and only calls your function when your key is pressed. The correct analogue would be CGEventTap.)

My documentation viewer

Wednesday, July 15th, 2009

This is what I use to view Apple’s documentation:

My web browser.
QuickTime/H.264, 960×538, 1.3 MiB

The application is OmniWeb. I have a series of entry points bookmarked in the (hidden) Favorites bar:

(Someday, Carbon will perish from the list, the ones after it will move up, and another framework—probably either QTKit or Core Animation—will become the new ⌘8.)

And yes, those are all file: links.* Your web browser is perfectly capable of displaying web pages stored locally, and that’s all the Apple documentation is: locally-stored web pages.

With this arrangement, I can get to the reference information I’m looking for faster, and I can have multiple references (even multiple definitions) open at once because OmniWeb supports tabbed browsing.

Here are some other pages worth bookmarking:

You can use these and other bookmarks with a nice feature of OmniWeb which has also, more recently, appeared in Google Chrome: You can type any substrings from your bookmarks’ names and URLs into the address bar, separated by whitespace, and it will know what you mean. So, for example, I can type “kt kit”, and OmniWeb knows I mean “QuickTime Kit”; I simply hit return, and it takes me to that framework reference.

UPDATE 2009-09-07: Updated links to Snow Leopard’s docset name (where possible).

* On Leopard, change the docset name to com.apple.ADC_Reference_Library.CoreReference.docset.

Manpage Monday: copyfile(3)

Monday, March 30th, 2009

copyfile(3) is an API for copying and moving files within the file-system:

DESCRIPTION

These functions are used to copy a file’s data and/or metadata. (Metadata consists of permissions, extended attributes, access control lists, and so forth.)

The copyfile() function can copy the named from file to the named to file; the fcopyfile() function does the same, but using the file descriptors of already-opened files.

The copyfile() and fcopyfile() functions can also have their behavior modified by the following flags:

COPYFILE_CHECK

Return a bitmask (corresponding to the flags argument) indicating which contents would be copied; no data are actually copied. (E.g., if flags was set to COPYFILE_CHECK|COPYFILE_METADATA, and the from file had extended attributes but no ACLs, the return value would be COPYFILE_XATTR.)

COPYFILE_PACK

Serialize the from file. The to file is an AppleDouble-format file.

COPYFILE_UNPACK

Unserialize the from file. The from file is an AppleDouble-format file; the to file will have the extended attributes, ACLs, resource fork, and FinderInfo data from the to file, regardless of the flags argument passed in.

File Manager also has APIs for copying files, in both asynchronous and synchronous flavors. Those APIs don’t provide as much control over management of metadata, but they do offer asynchronous operation, whereas the copyfile(3) APIs appear to be synchronous.

And, of course, I should mention NSWorkspace operations, which you use with the performFileOperation:source:destination:files:tag:
method
. Unlike the other two, this API has been around since 10.0. On the other hand, like copyfile(3), it’s synchronous only.

Report-an-Apple-Bug Friday! 75: NSUserDefaults and /Library/Preferences

Friday, November 14th, 2008

This bug is NSUserDefaults does not look in /Library/Preferences. It was filed on 2008-11-14 at 23:09 PST.

(more…)

List process start dates

Friday, February 8th, 2008

I just wrote a test app that prints the name and start-date of every process that the Process Manager will tell it about. Here it is:

File: ListProcessStartDates-r4.tbz

It’s a command-line tool, so you’ll need to run it from a terminal. Alternatively, you could wrap the executable in a service using ThisService, then use the service to insert the listing into a text document.

The code to convert the start-date of each process is ugly: Process Manager provides those dates as numbers of ticks since system startup, and I currently go through NSDate to convert those to numbers of seconds since 1970-01-01. I’m fairly sure that this answer is imprecise.

I’d prefer to get the startup time as a number of ticks since some epoch (probably 1904-01-01), so that I can do a more precise conversion. If you know of a way, please post a comment.

Why ASL?

Sunday, January 20th, 2008

It occurred to me just a few minutes ago that I should have discussed this first. So, I’m retroactively designating this post as the first in the ASL series. (I’m also forging the timestamp—I actually posted this at about 16:44 PST).


Most of us probably use NSLog when we want to log some information:

void NSLog(NSString *format, ...);

Those of us unlucky enough to not have access to Cocoa (e.g., working on a UNIX utility) probably use printf/fprintf instead:

int printf(const char *restrict format, ...);
int fprintf(FILE *restrict file, const char *restrict format, ...);

Both of these are fine, but they lack a couple of things.

First off, they lack any indication of a message’s importance. All messages are just lines in a file (especially with the *printf functions), and they’re all on equal footing.

That problem is solved by syslog(3):

void syslog(int priority, const char *format, ...);

syslog lets you specify any of eight different levels of priority for a message:

  • Emergency
  • Alert
  • Critical
  • Error
  • Warning
  • Notice
  • Info
  • Debug

And that’s great. syslog and the lesser functions NSLog and printf/fprintf have served all of us well for years.

But, for Mac OS X 10.4, Apple said “we can do better”.

And so they created the Apple System Logger.

ASL redefines a “message” to be more than just text. Now, it’s a bundle of key-value pairs—what Cocoa and CF call a dictionary. All the usual properties of a message (including the timestamp, the priority, the process that sent it, and the message itself) are now simply pairs in the dictionary. This is the other thing that NSLog and printf/fprintf lack.

This has two practical benefits:

  1. You can make up your own properties. You’re not limited to just the stock properties anymore; you can invent any properties you want.
  2. You can search the log more easily, now that messages are no longer just text. (This was improved in Leopard, which uses a real database for the log storage; Tiger used a text-based log file.)

And all this is very easy to use—barely more complex than using NSLog. Here’s a taste:

asl_log(NULL, NULL, ASL_LEVEL_NOTICE, "Hello %s!", "world");

I’ll tell more about the task of writing to the log (as well as list all nine of the standard properties) in the next post.

UPDATE 2009-04-24: Corrected use of syslog’s LOG_NOTICE to ASL’s ASL_LEVEL_NOTICE.

An invalid property list

Monday, October 1st, 2007

If you work on an [added: a document-based] app that uses a plist-based format, you should test your plist-reading code to see how it handles an invalid (e.g., eaten by the user’s dog) plist. Here’s one:

<plist>
<qux></qux>
</plist>

The binary plist parser won’t even touch it because it doesn’t have the bplist header, the XML parser will choke on it because it contains an element that it doesn’t recognize, and the OpenStep parser will choke on it because the first line doesn’t end with a semicolon or backslash.

When you feed this to your app, your app should present an error message. Anything else is a bug. (UPDATE 2007-10-02: OK, maybe not. There’s at least one circumstance where you can ignore it, as pointed out in the comments. I still think I’m right in most circumstances, just clearly not all.)

WWDC 2007 session videos are out

Monday, July 30th, 2007

If you attended WWDC, you can head over to ADC on iTunes and see what you missed.

How to make your app’s Dock tile highlight

Monday, July 23rd, 2007

So, no matter what you do, your Dock tile doesn’t highlight when you drag a document onto it. You’ve hexadecuple-checked your CFBundleDocumentTypes list, and everything looks correct, but Dock is not co-operating and you just want to kick it.

Finally, you decide to remove the LSItemContentTypes key, and it works just fine! How can this be?


Well, since Tiger, LSItemContentTypes shuts out all the other document-type tag keys. Your CFBundleTypeOSTypes, your CFBundleTypeExtensions—all of those are ignored when LSItemContentTypes is present; it looks at nothing but the LSItemContentTypes list. Taking out LSItemContentTypes forces LS to look at your OSTypes and extensions lists instead.

More to the point, your problem is that the set of UTIs you’ve specified does not contain the UTI of the would-be document that you’re dragging.

You could be forgiven for expecting that having com.apple.application in your set of UTIs would allow you to open applications as your documents. This is not true, because a standardly-constructed Mac OS X application is of type com.apple.application-bundle. That type does conform to com.apple.application, but it is not equal to com.apple.application, so the Dock refuses your drag with a dismissive wave of its kerchief bundle and an AIFF file of a sharp “hmph!”.

So how do you find out the true UTI of your document?

The easy way is mdls. Ask for the kMDItemContentType property:

% mdls -name kMDItemContentType Foo.app
Foo.app -------------
kMDItemContentType = "com.apple.application-bundle"

But this only works on a volume with a Spotlight index; for example, it doesn’t work on disk images or RAM disks (same thing). Another way is Nicholas Riley’s launch, with its -f option:

% launch -f Foo.app
Foo.app: Mac OS X application package 
        type: 'APPL'    creator: …
        architecture: PowerPC, Intel 80x86
        bundle ID: …
        version: …
        kind: Application
        content type ID: com.apple.application-bundle
        contents: 1 item
        created: 2007-07-23 07:12:31
        modified: 2007-07-23 07:12:31
        accessed: 2007-07-23 07:12:41 [only updated by Mac OS X]
        backed up: 1903-12-31 17:00:00

Either way, put that UTI into your list. Then drags will work.

In summary, the Dock checks for equality of the prospective document’s UTI to the UTIs listed under LSItemContentTypes, not conformity. You need to list every UTI you support in your Info.plist, including those that conform to the ones you expect. It’s either that or give up on UTIs entirely.

(Summary suggested by wootest.)

UPDATE 08:44: ssp suggested mdls instead of launch.

Apple Bug Friday! 65

Friday, July 6th, 2007

This bug is kIconServicesUpdateIfNeededFlag not documented. It was filed on 2007-05-25 at 02:02 PDT.

(more…)

Apple Bug Friday! 64

Friday, July 6th, 2007

This bug is kIconServicesNoBadgeFlag not documented. It was filed on 2007-05-25 at 02:00 PDT.

(more…)

Virtual key-codes

Tuesday, May 22nd, 2007

Anybody who’s ever needed to work with virtual key-codes—especially to program a hotkey—has had the problem of looking up the key-code for a specific key. The usual solution is to fire up Peter Maurer’s Key Codes.app and press the key, but wouldn’t it be nice to look it up in a handy table that you could print out?

There actually is such a table, but it’s well-hidden in the Apple documentation. Mac OS X uses the same virtual key-codes that it used for the legendary Apple Extended Keyboard. Thus, the table in Inside Macintosh: Text still applies.

The problem is the asstastic low-resolution JPEG scan of the table that Apple provides in the online version of IM:Tx:

Good luck with that!

So I did some poking. It turns out that there is a PDF version of IM:Tx on the ADC website—complete with a vector, rather than raster, table. Unfortunately, opening a PDF and jumping to figure C-2 is no easier than firing up Key Codes and pressing the key.

So here’s a handy-dandy crop of the PDF (with attribution added). Because it’s a vector image, the key codes in this version should be clearly readable at any resolution. Here’s what it looks like:

In case you’re wondering, I cropped it by copying the figure in Preview, then pasting into Lineform, which enabled me to add the attribution under the figure heading.

In a previous version of this post, I provided a 600 dpi PNG version of the key-codes table. In making that one, Lineform also enabled me to export to PNG at 600dpi rather than 72.

UPDATE 2008-11-29: Replaced the PNG image with a PDF document.

How do I swap thy bytes? Let me count the ways

Saturday, April 28th, 2007
  1. swab

    swab(3) is a function that copies some bytes from one location to another, swapping each pair of bytes during the copy. Handy for structures.

    It has a feature that isn’t mentioned in the Darwin manpage for swab: If you pass a negative size, it does not swap. I have no idea why this magic behavior was added; if you want a swab that doesn’t swap bytes, just use bcopy. I shake my head at this use of a magic argument.

  2. ntohs, htons, ntohl, htonl

    These four functions swap the bytes of a 16-bit (‘s’) or 32-bit (‘l’, in ignorance of LP64) integer and return the transformed value.

    They are mainly used in network-I/O contexts, as they transform between network byte order (big-endian) and host byte order (whatever you’re running). But there’s nothing stopping you from using them for any other 16-bit/32-bit integral byte-swapping.

  3. OSByteOrder (Darwin)

    The Darwin kernel provides a number of handy-dandy macros for byte-swapping:

    • OSSwap{Const}?Int{16,32,64}
    • OSSwap{Host,Big,Little}To{Host,Big,Little}{Const}?Int{16,32,64}

    The {Host,Big,Little}To{Host,Big,Little} functions swap conditionally; the others always swap.

    According to the Universal Binary Programming Guidelines, it is safe to use these in applications.

  4. Core Foundation

    CF’s Byte-Order Utilities provide the same facilities as OSByteOrder, with a couple of twists:

    • The implementation uses assembly language when the environment is GCC on either PowerPC or x86. This is theoretically faster than OSByteOrder’s pure-C implementation. (CF falls back on pure C in all other environments.)
    • CF adds support for byte-swapping 32-bit and 64-bit floating-point numbers.
  5. Foundation

    Foundation’s byte-order functions bear all the same capabilities as the CF Byte-Order Utilities. In fact, they are implemented with them.

  6. NeXT byte-order utilities

    These utilities are equivalent to the Foundation functions, except that they are implemented using the OSByteOrder utilities. They are declared in <architecture/byte_order.h>.

  7. Core Endian

    Core Endian logo that I made up.

    I think that the “Core Endian” name itself is new in Panther. Three functions in the API have a “CoreEndian” prefix, and are marked as new in Panther, whereas the others have simply “Endian”, and are marked as having existed since 10.0. This suggests to me that the entire API was branded “Core Endian” in 10.3, with the older functions subsumed by it.

    The new functions have to do with “flipper” callbacks, which you can install so that things like Apple Event Manager can DTRT with your custom data types. The older functions are plain byte-swapping utilities, just like all the other APIs described here, and exist mainly for the benefit of QuickTime users (they exist on Windows, too, through QuickTime).

Report-an-Apple-Bug Friday! 54

Friday, April 6th, 2007

This bug is iTunes should use real combo boxes in its Info dialogs. It was filed on 2007-04-06 at 23:48 PDT.

(more…)

Apple Bug Friday! 51

Friday, March 16th, 2007

This bug is System-wide AXUIElement’s role desc is “need to implement”. It was filed on 2007-03-09 at 13:39 PST.

(more…)

CFMutableData doesn’t hide its internal storage after all

Sunday, February 18th, 2007

From the 2005-12-06 definition of CFDataGetMutableBytePtr:

This function either returns the requested pointer immediately, with no memory allocations and no copying, or it returns NULL. If the latter is the result, call the CFDataGetBytes function to copy the byte contents to an external buffer. Note that if you subsequently call any mutating function on theData—including operations that may not appear to change the length of the data—this may invalidate the pointer.

Whether this function returns a valid pointer or NULL depends on many factors, all of which depend on how the object was created. In addition, the function result might change between different releases and on different platforms. So do not count on receiving a non-NULL result from this function under any circumstances.

From the 2007-02-08 definition of CFDataGetMutableBytePtr:

This function is guaranteed to return a pointer to a CFMutableData object’s internal bytes. CFData, unlike CFString, does not hide its internal storage.

Good to know.

What’s the resolution of your screen?

Sunday, February 4th, 2007

A few weeks ago, I installed Adobe Reader to view a particular PDF, and noticed something interesting in its Preferences:

Its Resolution setting is set by default to “System setting: 98 dpi”.

“Wow”, I thought, “I wonder how it knows that.” So I went looking through the Quartz Display Services documentation, and found it.

The function is CGDisplayScreenSize. It returns a struct CGSize containing the number of millimeters in each dimension of the physical size of the screen. Convert to inches and divide the number of pixels by it, and you’ve got DPI.

Not all displays support EDID (which is what the docs for CGDisplayScreenSize say it uses); if yours doesn’t, CGDisplayScreenSize will return CGSizeZero. Watch for this; failure to account for this possibility will lead to division-by-zero errors.

Here’s an app to demonstrate this technique:

ShowAllResolutions' main window: “Resolution from Quartz Display Services: 98.52×96.33 dpi. Resolution from NSScreen: 72 dpi.”

ShowAllResolutions will show one of these windows on each display on your computer, and it should update if your display configuration changes (e.g. you change resolution or plug/unplug a display). If CGDisplayScreenSize comes back with CGZeroSize, ShowAllResolutions will state its resolution as 0 dpi both ways.

The practical usage of this is for things like Adobe Reader and Preview (note: Preview doesn’t do this), and their photographic equivalents. If you’re writing an image editor of any kind, you should consider using the screen resolution to correct the magnification factor so that a 8.5×11″ image takes up exactly 8.5″ across (and 11″ down, if possible).

“Ah,”, you say, “but what about Resolution Independence?”.

The theory of Resolution Independence is that in some future version of Mac OS X (possibly Leopard), the OS will automatically set the UI scale factor so that the interface objects will be some fixed number of (meters|inches) in size, rather than some absolute number of pixels. So in my case, it would set the UI scale factor to roughly 98/72, or about 1+⅓.

This is a great idea, but it screws up the Adobe Reader theory of automatic magnification. With its setting that asks you what resolution your display is, it inherently assumes that your virtual display is 72 dpi—that is, that your UI is not scaled. Multiplying by 98/72 is not appropriate when the entire UI has already been multiplied by this same factor; you would essentially be doing the multiplication twice (the OS does it once, and then you do it again).

The solution to that is in the bottom half of that window. While I was working on ShowAllResolutions, I noticed that NSScreen also has a means to ascertain the screen’s resolution: [[[myScreen deviceDescription] objectForKey:NSDeviceResolution] sizeValue]. It’s not the same as the Quartz Display Services function, as you can see; it seemingly returns { 72, 72 } constantly.

Except it doesn’t.

In fact, the size that it returns is premultiplied by the UI scale factor; if you set your scale factor to 2 in Quartz Debug and launch ShowAllResolutions, you’ll see that NSScreen now returns { 144, 144 }.

The Resolution-Independent version of Mac OS X will probably use CGDisplayScreenSize to set the scale factor automatically, so that on that version of Mac OS X, NSScreen will probably return { 98.52, 98.52 }, { 96.33, 96.33 }, or { 98.52, 96.33 } for me. At that point, dividing the resolution you derived from CGDisplayScreenSize by the resolution you got from NSScreen will be a no-op, and the PDF view will not be doubly-magnified after all. It will be magnified by 133+⅓% by the UI scale factor, and then magnified again by 100% (CGDisplayScreenSize divided by NSDeviceResolution) by the app.

Obviously, that’s assuming that the app actually uses NSScreen to get the virtual resolution, or corrects for HIGetScaleFactor() itself. Adobe Reader doesn’t do that, unfortunately, so it suffers the double-multiplication problem.

So, the summary:

  • To scale your drawing so that its size matches up to real-world measurements, scale by NSDeviceResolution divided by { 72.0f, 72.0f }. For example, in my case, you would scale by { 98.52, 96.33 } / { 72.0, 72.0 } (that is, the x-axis by 98.52/72 and the y-axis by 96.33/72). The correct screen to ask for its resolution is generally [[self window] screen] (where self is a kind of NSView).
  • You do not need to worry about HIGetScaleFactor most of the time. It is only useful for things like -[NSStatusBar thickness], which return a number of pixels rather than points (which is inconvenient in, say, your status item’s content view).

The Cocoa Memory Management Regular Expression

Thursday, January 11th, 2007

Any method whose selector matches this regular expression gives you a reference to its return value, which you must later release.

/^retain$|^(alloc|new)|[cC]opy/

As an added extra bonus, here’s the CF equivalent.

/Create|Copy|Retain/

Carbon adds several exceptions, such as GetControlData (which returns a reference to CF things like the string value of a text field). Use Cocoa instead and your memory-management life will be simpler. ;)

How to detect a click

Sunday, January 7th, 2007

If you’ve ever written something that needs to simulate menu behavior, you’ve probably noticed that it would be nice to know, portably to future OS versions, how long you should wait before rejecting a mouse-down/mouse-up pair as not a click, as well as how far the user must move the mouse for it to not be a click.

The way to do this is:

EventTime clickTimeout;
HISize clickMaxDistance;
OSStatus err = HIMouseTrackingGetParameters(kMouseParamsSticky, &clickTimeout, &clickMaxDistance);

There is no Cocoa API for this.

GestaltPeeker

Wednesday, November 29th, 2006

My newest product is a front-end to the Gestalt Manager, the Carbon API for system introspection. Examples and the app on the GestaltPeeker webpage.

It’s actually quite old, but just now is when I got around to rubbing it shiny, ironing out the bugs when running on Intel systems, and releasing it. :)