Apple bug Friday! 44

This bug is PackageMaker's keyboard shortcuts are not consistent with Xcode's. It was filed on 2006-05-19 at 02:28 PDT.

The list in the Notes section is adapted from another blog post of mine, Know your Xcode.


PackageMaker's keyboard shortcuts for Build, Build Log, Run, and Run Log do not match up with Xcode's shortcuts for the same commands.

Steps to Reproduce:

  1. 1. Press ⇧⌘B.

Expected Results:

The Build Log appears.

Actual Results:



None known.


Xcode has a simple and elegant system for its keyboard shortcuts:

  • ⌘_ builds, then performs the action.
  • ⌘⌥_ performs the action without building. (Exception: Build's keyboard shortcut is ⌘B, presumably because it is impossible to build without building.)
  • ⇧⌘_ shows the log for the action.

PackageMaker should adopt the same schema, both for its elegance and for uniformity with Xcode.

Technorati tags: ,


About CPU Usage 0.3...

The version that I put up before was broken. I've hotfixed it, and also moved the downloads over to my folder on jkp's server. No more worrying about GeoCities' hourly transfer limit.

And I'll be posting it on VT within the hour.

Call to action

I want to see Mac OS X Tiger (or Leopard) running on a NeXT Cube. :)

And NeXTStations only count for half points. They're too modern. I want to see it on a NeXT Cube, grayscale and all.

If you make it happen, or find somebody who has made it happen, please post a link in the comments.

Technorati tags: , NeXT.


CPU Usage 0.3

An unobtrusive (unless it needs to be obtrusive) CPU usage meter.

CPU Usage meter, shown relative to a Finder window, indicating 40% CPU usage.

When your CPU usage is low, the floating window is nearly invisible. When your CPU usage is high, the floating window becomes more prominent, until it becomes completely opaque at 100% CPU usage.

Multiple-CPU-core machines, as you might expect, beget a version of the window that has multiple, connected CPU-usage cells. (If you have such a machine, feel free to send me a screenshot that I could put on the webpage. Let me know how to credit you, too.)

Though the first two versions are available to the public, this is the first public release. The previous versions had a large memory leak; this version fixes it, and therefore has no known bugs. (Still not 1.0 because it's not done. I have one or two features that I want to add in future versions.)

Plus and minus images, mark 2

I couldn't figure out why my images were so much bigger than Adium's.

du -b Frameworks/AIUtilities\ %~/Projects/@otherpeoplesprojects/adium(127) > \ Framework/Resources/{pl,min}us.png 85 Frameworks/AIUtilities Framework/Resources/plus.png 77 Frameworks/AIUtilities Framework/Resources/minus.png ___ cd ~/Dom*/plusminus %~/Projects/@otherpeoplesprojects/adium(0) ___ du -b {pl,min}us-8.png %~/Domain of the Bored/plusminus(0) 607 plus-8.png 601 minus-8.png

This annoyed me, because I wanted to move my images into Adium, but couldn't justify it with the size difference (Adium already weighs heavily on people's disks, so I'm reluctant to increase it even by a K).

Finally, it dawned on me. (I've said before how answers will just pop into my head randomly without me even thinking about it.) I fired up Photoshop, and sure enough, I had saved my images as RGB, not grayscale. Since there is no saturation anywhere in the image, there's no reason for me to use RGB, so I changed the images to grayscale and ran the latest versions of OptiPNG and pngcrush over them.

The new sizes:

du -b {pl,min}us-8.png %~/Domain of the Bored/plusminus(0) 82 plus-8.png 75 minus-8.png

I'll add them into Adium at some future time.

Technorati tags: , .

A math koan

One sheet of toilet paper is L long. The inner circumference of the roll is C1 and the outer circumference is C2. Each sheet is T thick.

How many sheets are there on a fully-loaded roll? Please post here if you have an answer.

And no cheating by peeking at the package. ;)

Technorati tags: , . (Did you expect to ever see those two tags together in one post?)


Image Shadow Adder

My newest application, Image Shadow Adder, adds a shadow to an image. I plan on using this instead of Photoshop to restore shadows to my window screenshots (OS X's window screenshot command, ⇪⇧⌘4, does not preserve the shadow).

Also, the source code (BSD license) demonstrates how to use Bindings (used to insert the original and shadowed images into the document window's image views), use NSShadow, and capture an NSImage to an NSBitmapImageRep. Few comments in the code, I'm sorry to say, as this is just a quick-and-dirty application that I wrote when it dawned on me that I could use NSShadow when drawing an NSImage, rather than emulating my old Photoshop technique.

For reference, that technique was:

  1. Take one regular window screenshot, and one rectangular screenshot of the window with shadow on a white background.
  2. Drag and drop the window screenshot into the rectangular screenshot. Position so that the two window images line up.
  3. Knock out the black corners on the window screenshot. These are masked out by the alpha channel in the PNG file, but Photoshop sucks at alpha channels.
  4. Create a new layer. Fill with black.
  5. Load the window screenshot as a selection.
  6. Add a layer mask (reveal selection) to the black layer.
  7. Copy Merged.
  8. Add an alpha channel. Paste into it, and invert it. The area of the window should be white, with the shadow fading to black.
  9. Return to the Layers list and disable or delete the layer mask. Move the black layer down beneath the window-screenshot layer.
  10. Export using SuperPNG.

The only disadvantage to the new way is that AppKit's PNG-interlacing setting is broken. The generated PNG data is not interlaced. I'll have to use OptiPNG to interlace it.

Technorati tags: , .


Another quickie

If you use -[NSAttributedString drawAtPoint:], you may be surprised to find that it doesn't respect NSParagraphStyles in the receiver's attributes. The documentation hints at why:

The width (height for vertical layout) of the rendering area is unlimited, unlike drawInRect:, which uses a bounding rectangle. As a result, this method renders the text in a single line.

Well, it will actually respect any newlines when measuring and drawing the text. You won't just get a single line. What it really means is that you don't get paragraph styles applied.

Solution: Use -[NSAttributedString drawInRect:] instead.

I imagine that the same rule applies to -[NSString drawAtPoint:withAttributes:] and -[NSString drawInRect:withAttributes:] as well, since the former method has the same note in its documentation (and is probably implemented using -[NSAttributedString drawAtPoint:]).

Technorati tags: , , , .


A quick IB tip

I just discovered this — you can use the numeric keypad to move views in a nib. The benefit of this is that you can perform atomic diagonal moves (as opposed to a rapid sequence of, for example, up followed by left).

Technorati tags:


Table view double-click actions

It used to be that when you wanted to receive a double-click notification from an NSTableView, you had to do this in your -awakeFromNib:

[tableView setTarget:self]; [tableView setDoubleAction:@selector(doMagicThings:)];

Now, with the power of Bindings, you can do this in IB!

  1. Create an NSObjectController. Set its class name to the class of the desired receiver, and its “content” outlet (not binding) to the desired receiver.
  2. Bind the table view's doubleClickTarget binding to the object controller. Controller key: content. Leave the model key path empty.
  3. Put the selector name in the field at the bottom of the binding view.

And a cheesy way that doesn't involve a controller:

  1. Add a method named -self to your receiver's class (or to NSObject) that simply returns self.
  2. Bind the table view's doubleClickTarget binding directly to the receiver. Model key path: self.
  3. Put the selector name in the field at the bottom of the binding view.

Technorati tags: Cocoa, NSTableView.


BlogZOT!: HoudahSpot

Saw this on durin42's blog: MacZOT is running another BlogZOT!, this time for Houdah Software's HoudahSpot. (Domain of the Bored: More hyperlinks per paragraph than any other blog, ever!)

HoudahSpot is a Spotlight-replacement app, as is NotLight. HoudahSpot takes a different approach, being more similar to Finder and Spotlight, but with the suck subtracted from their implementations. (NotLight is basically a front end on the Spotlight APIs.)

Screenshot of HoudahSpot's search window. HoudahSpot is instructed to search /Developer/SDKs, /usr/include, /usr/local/include, and /opt/local/include for files whose text content contains the word “NSAffineTransform” OR “readline”.

It's fast, but buggy. The query above, for example, didn't work as long as I had any folders other than /Developer/SDKs listed. Perhaps it's using AND rather than OR on the source files? No idea, but as long as I can't search all my header folders at once, I won't be abandoning my own header search tool. UPDATE 17:11 PDT: NotLight doesn't find anything either. Spotlight does, though. durin42 and I both searched for fprintf as well; I had the same results as with readline, whereas durin42 got a hit in HoudahSpot for readline but not for fprintf (and remarked that “spotlight behaves oddly”). Very, very strange.

Also, the search window's minimum size is unnecessarily large. The window as shown above is as small as I could make it. Wasted space is bad. In a quasi-related misfeature, the toolbar cannot be configured. The maximum extent to its configurability is that you can ⌘-click the pill button to switch between Icon & Text and Icon-only. Yaaay. My last nitpick is that it doesn't use pretty plus/minus images, like mine.

If it gets down to free, snap it up; it shows a lot of promise, and is very pretty. But I would not pay $15 (or $9, the current BlogZOT! price as of this writing) for it when there's NotLight. I look forward to some future version that fixes all the bugs.

Technorati tags: , .

First draft

I've been working on a header search tool in Python. You run the index tool, and it creates the database (using PostgreSQL and PyGreSQL); then you can use the search tool to look up headers either by name or by keyword:

python searchheaders.py name=NSAffineTransform.h  %~/Python/sql_headersearch(0)
NSAffineTransform.h     /System/Library/Frameworks/AppKit.framework/Headers/NSAffineTransform.h
NSAffineTransform.h     /System/Library/Frameworks/Foundation.framework/Headers/NSAffineTransform.h
python searchheaders.py symbol=NSAffineTransform  %~/Python/sql_headersearch(0)
NSAffineTransform       "/System/Library/Frameworks/AppKit.framework/Headers/NSFontDescriptor.h"
NSAffineTransform       "/System/Library/Frameworks/AppKit.framework/Headers/NSBezierPath.h"
NSAffineTransform       "/System/Library/Frameworks/AppKit.framework/Headers/NSAffineTransform.h"
NSAffineTransform       "/System/Library/Frameworks/AppKit.framework/Headers/NSFont.h"
NSAffineTransform       "/System/Library/Frameworks/Foundation.framework/Headers/NSAffineTransform.h"

It's not done yet, obviously (for one thing, I don't know why those quotes are in there), but it's coming along nicely. And it's quick, though not very:

time python searchheaders.py name=NSAffineTransform.h > /dev/null
python searchheaders.py name=NSAffineTransform.h > /dev/null  0.06s user 0.10s system 44% cpu 0.371 total
time python searchheaders.py symbol=NSAffineTransform > /dev/null  
python searchheaders.py symbol=NSAffineTransform > /dev/null  0.06s user 0.10s system 6% cpu 2.339 total

I want to see if there's anything I can do to fix that query time. Probably something involving PostgreSQL's array types, so that I can make the keyword column a primary key.

This, incidentally, is why I needed to parse the preprocessor.

Technorati tags: .


Parsing the preprocessor

If you've ever run GCC's preprocessor alone and looked at its output, you've seen lines like these:

# 1 "/usr/include/sys/types.h" # 1 "<built-in>" # 1 "<command line>" # 1 "/usr/include/sys/types.h" # 66 "/usr/include/sys/types.h" # 1 "/usr/include/sys/appleapiopts.h" 1 3 4 # 67 "/usr/include/sys/types.h" 2 # 1 "/usr/include/sys/cdefs.h" 1 3 4 # 70 "/usr/include/sys/types.h" 2

And you probably wondered what all that means. Here's your secret decoder ring.

First, these are called "line markers" in libcpp. The format of a line marker is:

  1. A line number
  2. The path to the relevant file
  3. Flags

The flag values are:

Push (enter) header
Pop (leave) header
This is a system header (determined by these rules with this modification)
Requires extern "C" protection (determined by the same rules as above); never found without 3

Note that a pop applies to the header above (in the include stack) the one referenced in the marker.


# 66 "/usr/include/sys/types.h" # 1 "/usr/include/sys/appleapiopts.h" 1 3 4 # 67 "/usr/include/sys/types.h" 2

  1. Fast-forward to line 66 of <sys/types.h> (nothing interesting occurs before this line).
  2. Enter <sys/appleapiopts.h>. Everything from this point until the next marker is from that header. Note that this header is a system header (3) and requires extern "C" protection (4).
  3. As it turns out, nothing interesting happened there. So the very next line is a pop marker: <sys/appleapiopts.h> is popped, so now we're back in <sys/types.h>, now on line 67 (the line after the #include <sys/appleapiopts.h>).

The relevant code in libcpp is in directives.c. The function that parses line markers (presumably used by the compiler rather than the preprocessor itself; the preprocessor generates them) is do_linemarker. Additional include-related code is in files.c.

UPDATE 23:24 PDT: Beware of pragmas. Seems obvious now, but I didn't think of it earlier: The preprocessor leaves #pragma directives untouched, being that they're for the compiler rather than the preprocessor. So if you're only looking for line markers, you may get tripped up if you don't properly handle/ignore a pragma.

Technorati tags: , , .


ISO 8601 unparser, version 0.3

Colin found some bugs in my ISO 8601 unparser when he added it to Adium. I've fixed these (as he has in the Adium copy) and released it as 0.3.

The parser is still unchanged.

Technorati tags: .


About Mac OS 9

No! Wait! Come back!

Simone Manganelli's -1st post references an AppleXnet article he wrote in response to an article that Matthew Paul Thomas wrote.

I agree with the AppleXnet article on the whole, but I do have some rebuttal to it.

Apple sanctions the use of "extensions", which modify the use of the operating system in unintended ways that often lead to conflicts with other applications and extensions, one of the worst usability problems of Mac OS 9. Troubleshooting extensions is one of the worst things to have to diagnose.

Trivia: Extensions were originally unsupported. They were only for Apple to use to patch the OS without requiring a full OS update. But third-party developers figured out how to do it. Apple made it supported so that they could set forth certain ground rules to help ameliorate the problem of extension conflicts.

For disabled users, there is no way in Mac OS 9 to click any menu item or drop down any menu without using the mouse or buying additional software. This makes using the operating system very difficult out of the box for many disabled Mac users.

OS 9's Easy Access control panel offered a feature called Mouse Keys. You use the numeric keypad to move the cursor, except for the 5 and 0 keys, which click the button. OS X has it too, since Jaguar.

Exercise for the reader: Figure out how Mouse Keys changed between OS 9 and OS X. (Yes, there is at least one change.)

While admittedly minor, some applications' menus are white colored, from the System 7 days, while other ones are gray colored, the new color scheme adopted by Mac OS 8 and later.

The applications with white menus used custom MDEFs (menu definitions), most commonly an old version of Mercutio. These custom MDEFs were usually employed to allow for exotic key combinations that Apple's MDEF didn't allow until 8.5.

Mac OS 8.5 and later, and OS X, allow any key combo.

A remnant from earlier systems from Mac OS 9 is the desk accessory, which violates many of the regular human interface guidelines (even though it's usually just a small application). For example, the Calculator has a black menu bar…

First, you mean title bar.

Second, its appearance is because it's a desk accessory. DAs didn't always behave like applications; before System 7, they floated on top of the active application. The reason is that DAs were the very first way in which you could do things that weren't actually part of the application you were in, invented because this was before MultiFinder allowed multiple applications to run at the same time.

Third (and irrelevantly to UI issues), DAs are not applications. They are device drivers. (Yes, really. That's how they were loaded when you could only have one application running at a time.)

Sounds a little like input managers, actually, now that I think about it…

The Apple menu and application menu under Mac OS 9 are curiously not located at the top-left and top-right corners of the screen, respectively. For some reason, Apple decided to put about 10 pixels between each menu and the side of the screen, violating Fitt's Law in the process.

But you could click on them anyway.

Immediately after startup after a crash, the Finder often places "rescued items" in the Trash. This is wrong for multiple reasons: …

Ostensibly, the application saved your unsaved work to a swap file that it would have cleaned up when you saved or closed the document, and you could recover this data from the Rescued Items folder after the restart. Unfortunately, even when there was such a swap file, I was never able to open one and recover anything.

Good idea, but it didn't work out.

OS X does have the same feature, but most applications do not use the Temporary Items folder anymore. I think developers figure that Macs have too much RAM for it to be worth anything anymore.

Pop-up windows violate most of the normal expectations that a user has when interacting with them.

Ah, but they were so handy. :)

It has not one but TWO resize widgets.

Clearly-defined resize widgets.

For no reason at all, the icons of desktop printers cannot be changed.

The reason is that the icon may change to reflect information. Most of these can be accomplished by badging, but what do you do for the black stroke that means “default printer”?

It's puzzling why an application called "Finder" doesn't contain a feature that does what it's name implies, instead relegating that to Sherlock. (Earlier versions of Mac OS X also carried over this problem, but it has since been rectified in Jaguar and improved in Panther.)

And ruined in Tiger. :(

Good thing there's NotLight.

Many diehard Mac OS 9 users that I've met seem to adopt an attitude of thinking that Mac OS 9 is perfect and should be Apple's current operating system, when Mac OS 9 was full of more usability problems than the current version of Mac OS X.

I was there. The first time I used OS X (10.1.3), I hated it for all the ways that it was different from OS 9. Eventually I went back. But I came to miss all the things that were good about OS X, and also wanted to start writing Mac applications (an expensive proposition on OS 9, except with MPW, the compiler in which was creaky; free on OS X). So, after getting a newer G3 (333 MHz; my previous one was 267 MHz), I installed OS X 10.1.5, and never looked back.

Technorati tags: , .


NSMovieView vs QTMovieView

I mentioned in my previous post that you should use QTMovieView rather than NSMovieView because QTMovieView is so much more efficient.

There is, however, one reason to use NSMovieView, and it's the controller thumb:

A window with an NSMovieView, showing off its hourglass-shaped controller thumb.

A MoviePlayer 2.5.1 window, showing off QuickTime 6.0.3's controller thumb.
MoviePlayer 2.5.1 with QuickTime 6.0.3.

A window with a QTMovieView, showing off its plain round controller thumb.

Does anyone know how I can get QTMovieView to use the same controller thumb that NSMovieView and QuickTime 6 use?

And no, the “Speed” field and progress bar are not part of the QTMovieView.

UPDATE 2006-06-10: wootest says that you the above is the editing controller, so you get it by making the movie editable. I've tried it and it works. The code is:

[movie setAttribute:[NSNumber numberWithBool:YES] forKey:QTMovieEditableAttribute];


Technorati tags: .

Enhancing QuickTime performance

I use a 450 MHz G4 Cube, so I tend to look hard at minimizing any large drains on my CPU. Such drains include playback of large video files (such as the 540p version of MacBreak). So I've been experimenting on and off with faster ways of playing back QuickTime movies. Here are my findings.

First, do not use NSMovieView. In my app, the NSMovieView used 50% of my CPU at all times — even when the movie was paused. Bad, bad, bad. And the frame rate sucked, too. (UPDATE 23:50 PDT: It seems like NSMovieView simply draws the entire frame periodically and unconditionally. The CPU usage changed based on the size of the window.) When I replaced it with QTMovieView, the CPU usage went way down, and the frame rate became watchable.

Second, Apple has a document called Enhancing Movie Playback Performance. Read it, learn it, live it.

Some of its information bears expanding-upon, though:

  • These are basic QuickTime functions, not QTKit. Both NSMovie and QTMovie allow you to get the raw QuickTime Movie, which you pass to these functions.

  • Prerolling actually involves two steps. First, call PrePrerollMovie. (No, I am not making this up.) Then, call PrerollMovie.

  • Remember MoviePlayer? It had two checkboxes for enhancing speed:

    Screenshot of MoviePlayer's Info window for a MacBreak episode, showing the “video_main” track, Preload options.

    Preload is obvious; it corresponds to LoadMovieIntoRam. Cache hint is not so obvious; what it does is keep movie data in RAM after it has been played (for looping). This corresponds to the keepInRam option to LoadMovieIntoRam.

    If you use keepInRam, be sure to call LoadMovieIntoRam with the unkeepInRam and flushFromRam options when you're done with the movie, so that the memory used will be freed.

    Note that in MoviePlayer, you could only set preload options per-track (there was a “Movie” category, but you could not set preload options for it). So this actually corresponds to LoadTrackIntoRam. I find LoadMovieIntoRam more useful for my situation; obviously, you should use whichever one of LoadMovieIntoRam, LoadTrackIntoRam, or LoadMediaIntoRam is appropriate for yours.

  • Preloading all of a movie is very expensive, especially if the movie is large (MacBreak takes about 20 seconds to load — that's forever in user time). Use it only if you have to, and show a progress indicator if you do. If you can, preload sections at a time — I might, for example, load 30 seconds every 1 second starting from file open.

Third, I suggest making sure that your QTMovieView is set to preserve aspect ratio. I don't know whether aspect ratio distortion has a negative effect on QT performance — especially if the movie is being scaled anyway — but having this turned on can't hurt.

Technorati tags: , .

Report-an-Apple-bug Friday! 43

This bug is CrashReporter dialog has “Close” button. It was filed on 2006-06-02 at 03:17 PDT.


The “unexpectedly quit” dialog has a “Close” button.

Steps to Reproduce:

  1. Crash an application.

Expected Results:

A dialog box comes up, saying that the application has unexpectedly quit, showing the backtrace, and offering me the option to either “Report” the crash or one of:

  • Quit [the application]
  • Cancel [reporting]
  • Don't Report

Actual Results:

A dialog box comes up, saying that the application has unexpectedly quit, showing the backtrace, and offering me the option to either “Report” the crash or “Close” something.


None known.


It is not clear what is being closed. I think the immediate guess is the application; only on further reflection does one realize that if the application has already quit, it must not be available to be “closed”. It could refer to the window, but isn't that what the red widget is for? But there is no red widget, because this is a dialog box.

The button's title should be changed, to one of the three names listed in Expected Results. Of those, my favorite is “Don't Report”.

The CrashReporter dialog box, with its “Close” button.

Technorati tags: ,

Separated at birth?

V for Vendetta is a great graphic novel. I couldn't put it down. So now, even more than before, I'm looking forward to the DVD of the movie.

I noticed when I picked it up, though, how much the Guy Fawkes mask resembles the image of Big Brother on the cover of my copy of 1984:

1984, with an rendition of Big Brother on the cover, next to V for Vendetta, with V in his Guy Fawkes mask on the cover.


ISO 8601 unparser

The unparser is finished. I've bundled it with the parser (which hasn't changed since 0.1) and released it as 0.2. Check it out.

I was working on my own algorithm for computing the week date, but couldn't get it to work correctly on every year, so I finally settled for implementing Rick McCarty's week date algorithm.

Technorati tags: .