I was working on a very bare-bones Cocoa application on friday, and stumbled across a most annoying window server bug. The application I was working on creates windows on demand, but without using NIBs. Instead, I used the code below to create a new window:
[[NSWindow alloc] initWithContentRect:rect styleMask:(NSTitledWindowMask | NSClosableWindowMask | NSMiniaturizableWindowMask | NSResizableWindowMask) backing:NSBackingStoreRetained defer:YES];
Once the window is ordered front and becomes visible, the entire window server hangs. The Mac stops responding to keyboard input, with only the pointer remaining functional. That is, functional in the sense that it continues to move, but you can't actually do anything.
So, what is the cause of this bug? To my luck, I was still able to log in to my computer from the command line. Everything appeared normal - no excessive CPU use, and no particular memory demand. Using the 'sample' utility and gdb, I discovered that my application was hung with the following backtrace:
_displayRectIgnoringOpacity:isVisibleRect:rectIsVisibleRectForView:] -[NSThemeFrame _recursiveDisplayRectIfNeededIgnoringOpacity... -[NSView _recursiveDisplayRectIfNeededIgnoringOpacity:... -[NSView _drawRect:clip:] -[NSThemeFrame drawRect:] -[NSFrameView drawRect:] -[NSThemeFrame drawFrame:] -[NSThemeFrame _drawFrameInterior:clip:] -[NSThemeFrame _drawTitleBar:] Draw3PartImage -[NSImage _compositeFlipped:atPoint:fromRect:operation:fraction:] -[NSImage _compositeFlipped:inRect:fromRect:operation:fraction:] -[NSImage drawInRect:fromRect:operation:fraction:] -[NSBitmapImageRep _drawFromRect:toRect:operation:alpha:compositing:flipped:ignoreContext:] CGContextDrawImage ripc_DrawImage ripc_RenderImage ripl_BltImage ripd_Lock CGSDeviceLock _CGSLockWindow _CGSSynchronizeWindowBackingStore mach_msg_trap mach_msg_trap
Notice the CGSSynchronizeWindowBackingStore call at the very end? I did too. It looks like the window server gets deadlocked in some way. If you wait long enough, the window server will come back in brief bursts, allowing you to give input to the application (for instance to quit it). The application can also be killed, but you won't see a response for the next thirty-or-so seconds before the window server collects its senses again.
Going back to my code, after commenting out nearly every part of the very small app, I narrowed it down to the way the window is created. More specifically, the problem is that I was attempting to create a so-called "retained" window, rather than a "buffered" window. Substituting NSBackingStoreRetained for NSBackingStoreBuffered completely solved my problems. (I had no good reason to choose one over the other when I wrote the code, so I picked the backing store constant more or less at random.)
A small example is available for download here. It creates a 128x128 sized window and displays it three seconds after being launched. It exhibits the bug on my MacBook Pro running 10.4.10. To experience the bug, you will need to move the window so that parts of it will be obscured by another application's window(s), or by the Dock's application switcher (Command-tab). You should be able to get out of the app by hitting Command-Q repeatedly, until the window server sees fit to respond. To be on the safe side, save your work before running the app.
Comments by Disqus
Spaces.. Spaces.. Spaces.. (Retired)
Jul 28: Running iTunes in a debugger (gdb)
Jul 25: The /Volumes/MobileBackups directory
Jul 20: FolderGlance 3.0.1 supports Lion
Mar 03: Quick tip: Speeding up Xcode compilations
Mar 02: FolderGlance 3.0
Jan 07: Making Universal Back Button work on 10.6.5 and later
Sep 03: Creating pthreads in C++ using pointers to member functions
May 31: Quickly open URLs in Terminal
May 31: Snow Leopard and automatically submitted Crash Reports
May 27: Universal Back Button released for Mac OS X
May 22: The 22 Megapixel Laptop
Feb 09: FolderGlance on MacUpdate Promo
Sep 28: FolderGlance 2.5.3 is out
Sep 21: FolderGlance 2.5.1 adds features and fixes bugs
Sep 16: FolderGlance 2.5 released!
Sep 10: Intriguing: Snow Leopard ships with the iPhone's multi-touch API built-in
Sep 03: FolderGlance and Snow Leopard
Mar 15: Fixing Keynote '08 and '09 to work with the Scripting Bridge
Feb 26: A website in an image
Feb 09: Display wall multi-touch
Feb 19: Spaces.. Spaces.. Spaces.. retires
Feb 08: How-to: Reverse engineering the Dock to fix Spaces
Jan 25: Interacting with wall-sized displays
Dec 20: Interesting Finder bug
Dec 06: Developing applications for the iPod touch (and the iPhone)
Nov 15: Spaces.. Spaces.. Spaces.. and 10.5.1
Nov 15: Thread creation using pthread_create() on Leopard
Nov 13: Spaces.. Spaces.. Spaces..
Nov 07: FolderGlance, Leopard and the More... menu
Nov 06: FolderGlance and Screen Sieve now also on Leopard!
Sep 16: Mysterious window server hangs