Mac OS X Reference Library Apple Developer
Search
Document Generated: 2009-09-03 18:24:40 -0700
Mac OS X Release Notes Copyright © 2009 Apple Inc. All Rights Reserved.


Mac OS X SnowLeopard Release Notes
Cocoa Application Framework



The Cocoa Application Framework (also referred to as the Application Kit, or AppKit) is one of the core Cocoa frameworks. It provides functionality and associated APIs for applications, including objects for graphical user interfaces (GUIs), event-handling mechanisms, application services, and drawing and image composition facilities.

This document describes the changes in AppKit since Mac OS X release 10.5. Updates to the document since WWDC 2008, WWDC 2009, and various seeds are indicated in the section titles. AppKit release notes for 10.5 (aka Leopard) and earlier, please refer to the older release notes for AppKit.


Feedback

For feedback and comments about AppKit and Foundation APIs and features, you can email cocoa-feedback@group.apple.com. The intent of this address is to provide developers with a direct channel to the engineering team and the technology managers responsible for these technologies. We will read your input, and will try to acknowledge it, but we might not always have time for significant replies. Please use this address for feedback and comments on the APIs and features (for instance "please add Cocoa wrapper classes for such-and-such" or "I need API to do this and that"), but not for support type questions (for instance, "I can't install OS X" or "How does one create a new bundle in Xcode?") or comments in other areas (for instance, "why is the dock centered in Aqua?").




Backward Compatibility

One backward compatibility mechanism that is occasionally used in the frameworks is to check for the version of the system an application was built against, and if an older system, modify the behavior to be more compatible. This is done in cases where bad incompatibility problems are predicted or discovered; and most of these are listed below in these notes.

Typically we detect where an application was built by looking at the version of the System, Cocoa, AppKit, or Foundation frameworks the application was linked against. Thus, as a result of relinking your application on SnowLeopard, you might notice different behaviors, some of which might cause incompatibilities. In these cases because the application is being rebuilt, we expect you to address these issues at the same time as well. For this reason, if you are doing a small incremental update of your application to address a few bugs, it's usually best to continue building on the same build environment and libraries used originally.

In some cases, we provide defaults (preferences) settings which can be used to get the old or new behavior, independent of what system an application was built against. Often these preferences are provided for debugging purposes only; in some cases the preferences can be used to globally modify the behavior of an application by registering the values (do it somewhere very early, with -[NSUserDefaults registerDefaults]).


Marking new APIs in headers

New APIs in headers are marked with AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER or the construct:
#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6
...
#endif
The basic definitions for these come from AvailabilityMacros.h, a standard system header. This is included from Cocoa.h, AppKit.h, and Foundation.h imports.

If you do nothing, MAC_OS_X_VERSION_MAX_ALLOWED is assumed to be MAC_OS_X_VERSION_10_6. However, to see which post-10.3 (for instance) symbols your app is referencing, you can build specifying the compiler flag:
-DMAC_OS_X_VERSION_MAX_ALLOWED=MAC_OS_X_VERSION_10_3
and watch for the warnings.


Runtime Version Check

There are several ways to check for new features provided by the Cocoa frameworks at runtime. One is to look for a given new class or method dynamically, and not use it if not there. Another is to use the global variable NSAppKitVersionNumber (or, in Foundation, NSFoundationVersionNumber):
APPKIT_EXTERN double NSAppKitVersionNumber;
#define NSAppKitVersionNumber10_0 577
#define NSAppKitVersionNumber10_1 620
#define NSAppKitVersionNumber10_2 663
#define NSAppKitVersionNumber10_3 743
#define NSAppKitVersionNumber10_4 824
#define NSAppKitVersionNumber10_5 949
One typical use of this is to floor() the value, and check against the values provided in NSApplication.h:
if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_0) {
/* On a 10.0.x or earlier system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_1) {
/* On a 10.1 - 10.1.x system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_2) {
/* On a 10.2 - 10.2.x system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_3) {
/* On a 10.3 - 10.3.x system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_4) {
/* On a 10.4 - 10.4.x system */
} else if (floor(NSAppKitVersionNumber) <= NSAppKitVersionNumber10_5) {
/* On a 10.5 - 10.5.x system */
} else {
/* SnowLeopard or later system */
}
Special cases or situations for version checking are also discussed in the release notes as appropriate. For instance some individual headers may also declare the versions numbers for NSAppKitVersionNumber where some bug fix or functionality is available in a given update, for example:
#define NSAppKitVersionWithSuchAndSuchBadBugFix 582.1


NSApplication presentationOptions API (New since January 2009 seed)

New “presentationOptions” API on NSApplication provides a Cocoa replacement for the existing Carbon “SystemUIMode” API (whose usage was outlined in TN2062: "Guide to Creating Kiosks on Mac OS X"). Using this API, an application can request certain behaviors for system user interface elements (the Dock, menu bar, task switcher, etc.) that will apply when the application is the active application, and can also observe changes to these UI element behaviors that are made by other applications when they are active.

The supported set of options is expressed using a new NSApplicationPresentationOptions bitmask type declared in NSApplication.h:
/* Flags that comprise an application's presentationOptions */
enum {
NSApplicationPresentationDefault = 0,
NSApplicationPresentationAutoHideDock = (1 << 0), // Dock appears when moused to
NSApplicationPresentationHideDock = (1 << 1), // Dock is entirely unavailable
    NSApplicationPresentationAutoHideMenuBar            = (1 <<  2),    // Menu Bar appears when moused to
NSApplicationPresentationHideMenuBar = (1 << 3), // Menu Bar is entirely unavailable
    NSApplicationPresentationDisableAppleMenu           = (1 <<  4),    // all Apple menu items are disabled
NSApplicationPresentationDisableProcessSwitching = (1 << 5), // Cmd+Tab UI is disabled
NSApplicationPresentationDisableForceQuit = (1 << 6), // Cmd+Opt+Esc panel is disabled
NSApplicationPresentationDisableSessionTermination = (1 << 7), // PowerKey panel and Restart/Shut Down/Log Out disabled
NSApplicationPresentationDisableHideApplication = (1 << 8), // Application "Hide" menu item is disabled
NSApplicationPresentationDisableMenuBarTransparency = (1 << 9) // Menu Bar's transparent appearance is disabled
};
typedef NSUInteger NSApplicationPresentationOptions;
This type is used by the following new NSApplication API methods.

The following gets or sets the presentationOptions that should be in effect for the system when this application is the active application. Only certain combinations of NSApplicationPresentationOptions flags are allowed, as detailed in the AppKit Release Notes and the reference documentation for -setPresentationOptions:. When given an invalid combination of option flags, -setPresentationOptions: raises an exception.
- (NSApplicationPresentationOptions)presentationOptions;
- (void)setPresentationOptions:(NSApplicationPresentationOptions)newOptions;
Returns the set of application presentation options that are currently in effect for the system. These are the presentation options that have been put into effect by the currently active application.
- (NSApplicationPresentationOptions)currentSystemPresentationOptions;
For most applications, the initial value of presentationOptions is NSApplicationPresentationDefault. If an application’s Info.plist specifies a value for the LSUIElement key as described in TN2062, the application’s presentationOptions is initialized to an equivalent combination of NSApplicationPresentationOptions flags instead.

Both presentationOptions and currentSystemPresentationOptions are KVO-observable. A client that observes currentSystemPresentationOptions will receive notifications when (1) the client is the active application, and makes a change itself using either -setPresentationOptions: or SetSystemUIMode(), (2) another application is active, and makes such changes of its own, and (3) making a different application active causes the active set of presentation options to change. Notifications are not sent for non-changes (e.g. when a different application becomes active, but has the same set of presentation options as the previously active application).

The presentationOptions / currentSystemPresentationOptions API interoperates with the SystemUIMode API (both reflect the same underlying state). The combination of option flags that you pass to -setPresentationOptions: must satisfy the same set of requirements that apply to the SystemUI “Mode” and “Options” combinations as described in TN2062. Specifically:

NSApplicationPresentationAutoHideDock and NSApplicationPresentationHideDock are mutually exclusive: You may specify one or the other, but not both.

Likewise, NSApplicationPresentationAutoHideMenuBar and NSApplicationPresentationHideMenuBar are mutually exclusive: You may specify one or the other, but not both.

If you specify NSApplicationPresentationHideMenuBar, it must be accompanied by NSApplicationPresentationHideDock. If you specify NSApplicationPresentationAutoHideMenuBar, it must be accompanied by either NSApplicationPresentationHideDock or NSApplicationPresentationAutoHideDock.

If you specify any of NSApplicationPresentationDisableProcessSwitching, NSApplicationPresentationDisableForceQuit, NSApplicationPresentationDisableSessionTermination, or NSApplicationPresentationDisableMenuBarTransparency, it must be accompanied by either NSApplicationPresentationHideDock or NSApplicationPresentationAutoHideDock.

When -setPresentationOptions: receives a newOptions parameter that does not conform to these requirements, it raises an NSInvalidArgumentException.


NSApplicationPresentationOptions and FullScreen Mode (New since January 2009 seed)

On 10.6, NSView's -enterFullScreenMode:withOptions: API accepts a new option, whose value specifies the NSApplicationPresentationOptions to use while the view is operating in full-screen mode:
NSString *NSFullScreenModeApplicationPresentationOptions;  // NSNumber numberWithUnsignedInteger:(NSApplicationPresentationOptions flags)
Note that the presence or absence of this option affects whether entering full-screen mode for a view captures displays, and whether the NSFullScreenModeSetting option is permitted, as follows:

When the options dictionary you pass to -enterFullScreenMode:withOptions: does not contain a value for NSFullScreenModeApplicationPresentationOptions, AppKit does not alter the presentation options that were previously in effect when taking the view full-screen. AppKit also captures either the destination screen, or (if you specify YES for NSFullScreenModeAllScreens) all attached screens, consistent with the behavior on 10.5. ("Capturing" a screen takes exclusive control of it, in the same sense that is provided for by CGDisplayCapture() and related Core Graphics APIs.)

When the options dictionary you pass to -enterFullScreenMode:withOptions: does contain a value for NSFullScreenModeApplicationPresentationOptions, AppKit does not capture any displays, since doing so would prevent showing of presentationOptions-controlled UI elements such as the menu bar and Dock. (Because displays are not captured in this case, and the app therefore doesn’t hold exclusive ownership of them, the NSFullScreenModeSetting option is disallowed; specifying it when NSFullScreenModeApplicationPresentationOptions is also specified will cause -enterFullScreenMode:withOptions: to raise an exception.) AppKit puts the requested NSApplicationPresentationOptions value into effect when switching the view into full-screen mode, and will restore the previously active NSApplication presentationOptions setting when the view exits from full-screen mode via -exitFullScreenModeWithOptions:. Even if you don’t wish to change the NSApplication presentationOptions setting when entering full-screen mode, you can pass [NSApp presentationOptions] for the NSFullScreenModeApplicationPresentationOptions key as a means of preventing screen capture, if desired.


NSView -enterFullScreenMode:withOptions: API Changes (Updated since January 2009 seed)

On 10.5, NSView’s -enterFullScreenMode:withOptions: method would throw an exception if the receiving view wasn’t in a window, as might be the case for an offscreen view that’s created exclusively for the purpose of being presented fullscreen. This was an unintentional limitation. On 10.6, -enterFullScreenMode:withOptions: can now be sent to a view for which [view window] == nil. For applications that must also run on 10.5, a simple workaround is to place the view in an offscreen dummy window.


Implications of NSWindow and NSScreen Color Space support for NSViews (New since January 2009 seed)

Most views draw into their window’s backing store, and are therefore drawn in their window’s assigned NSColorSpace. A few kinds of views are instead drawn into a separate backing store called a “surface” that’s composited atop the window, to facilitate hardware (GPU) accelerated rendering. This includes OpenGL views, as well as other kinds of views that render via OpenGL as a detail of their implementation (currently, views that display a Core Animation CALayer tree, QuickTime QTMovieViews, Quartz Composer QCViews, and ImageKit IKImageBrowserViews, among others).

For surface-based views, AppKit sets the surface’s color space to match, and track changes to, the window’s color space. Applications should therefore look to NSWindow’s -setColorSpace: and -setDisplaysWhenScreenProfileChanges: APIs to determine the color space used for surface-based rendering in a given window.

Animation Support for Integer Values

On 10.6, integer-valued properties can now be animated using the CAAnimation-based “animator” proxy API. All integer types are supported: BOOL values as well as signed and unsigned variants of char, short, int, long, and long long may be animated. As with animating any custom property, be sure to associate a suitable CAAnimation with the property name key so that messaging through the target’s animator to set a new value will actually animate. For example, an NSImageView’s “imageFrameStyle” property can be configured to animate when changed through the ImageView’s animator like so:
    [imageView setAnimations:[NSDictionary dictionaryWithObject:[CABasicAnimation animation] forKey:@"imageFrameStyle"]];
Any new value set through the animator will then trigger animation:
    [imageView setImageFrameStyle:NSImageFramePhoto];
[[imageView animator] setImageFrameStyle:NSImageFrameButton];
As when animating integer-typed properties of Core Animation CALayers, the animation proceeds in discrete steps.


Animation Support for NSColor Values

The 10.5 AppKit Release Notes incorrectly stated that NSColor-valued properties could be animated. While applications that happened to link against the Quartz framework had the benefit of this capability, it was not provided as an intrinsic AppKit feature.

Support for animating NSColor-valued properties has been added to AppKit for 10.6, so the code example that was presented in the 10.5 AppKit Release Notes (under the heading “NSAnimatablePropertyContainer protocol”), will now work as intended on 10.6, irrespective of whether the application links against the Quartz framework.
@implementation MyView
+ (id)defaultAnimationForKey:(NSString *)key {
if ([key isEqualToString:@"borderColor"]) {
// By default, animate border color changes with simple linear interpolation to the new color value.
return [CABasicAnimation animation];
} else {
// Defer to super's implementation for any keys we don't specifically handle.
return [super defaultAnimationForKeyKey:key];
}
}
@end


Animation Evaluation Scheduling Changes (New since January 2009 seed)

On 10.5, NSView and NSWindow property animations that were scheduled through the view’s/window’s “animator”, and that were evaluated by AppKit (rather than being delegated to Core Animation for threaded asynchronous evaluation), were scheduled for updating in the NSDefaultRunLoopMode.

On 10.6, such animations are now evaluated in NSRunLoopCommonModes.

“animator”-initiated animations that are evaluated by AppKit include:

- all NSWindow property animations
- all NSView property animations, for views that aren’t layer-backed
- a view’s frameSize, for a layer-backed view whose layerContentsRedrawPolicy (new in 10.6) equals the default value of NSViewLayerContentsRedrawDuringViewResize
- animation of any custom property that’s added by an NSView or NSWindow subclass, or of any existing NSView property that doesn’t readily map to a corresponding CALayer property (and therefore cannot be delegated to Core Animation for evaluation)


Changes to AppKit’s CATransaction Usage (New since January 2009 seed)

AppKit’s NSAnimationContext “groupings” serve a very similar purpose to Core Animation’s CATransactions, and in fact invoking [NSAnimationContext beginGrouping] performs a [CATransaction begin] (in addition to doing other work), and invoking [NSAnimationContext endGrouping] performs a [CATransaction commit].

On 10.5, AppKit also began and committed CATransactions in the course of its own layer-tree management activities, notably during certain modal event tracking operations, and to suppress implicit animations during non-animated view backing layer property updates.

On 10.6, we’ve removed this automatic CATransaction usage to avoid interfering with a client’s own CATransaction management -- in particular, so that changes a client application makes expecting an implicit CATransaction will not be unexpectedly delayed. AppKit instead makes very sparing use of [CATransaction flush], flushing only before it initiates an explicit layer tree draw, and on each cycle through a modal event tracking loop. This change makes client application usage of [CATransaction flush] more reliable as a means to force layer tree changes to be committed to the render tree. The general philosophy now is to leave creation of explicit CATransactions for the exclusive use of client applications.


Concurrent View Drawing (Updated since January 2009 seed)

To help applications with especially high drawing loads to more effectively leverage multi-core hardware, while seeking to minimize adoption requirements for view code that conforms to AppKit’s established threading conventions, 10.6 introduces a simple model for concurrent view drawing, and accompanying control API. Our findings to date have indicated that concurrent view drawing is of benefit only in some circumstances, and applications may experience a net performance decrease in cases where parallelism gains do not outweigh the additional overhead involved, so use of concurrent view drawing should be accompanied by performance investigations to measure results. Forward-looking applications may want to consider the implications of the thread safety model, so as to make design decisions that are compatible with potentially leveraging this feature in the future.

While the new model’s requirements for safely concurrent -- meaning threaded -- view drawing are comparatively simple (see “Concurrent View Drawing - Thread Safety Implications” below), existing UIs cannot be assured of 100% thread safety out of the box, so we provide an API mechanism to enable clients to opt in to concurrent view drawing when desired.

1. Concurrent view drawing is enabled by default for NSWindow instances, but disabled by default for all NSView instances within those windows. (We might in a future release decide to enable canDrawConcurrently by default for instances of particular generally thread-safe classes, such as simple controls.)  From this initial state, clients can enable concurrent drawing for individual views, or use disabling at the NSWindow level as a master switch that can be thrown to suppress concurrent drawing in case problems precluding its use are encountered.

The view setting is not recursive in its effect; it specifies the threadability of drawing for a given view, not for the view’s entire subtree. The view’s descendants may have their threadability configured independently.

Our recommendation is that potential clients start by seeking out a handful of the more costly custom views in their UIs (typically those that draw complex content and/or cover large areas) and try enabling concurrent drawing for those.  Additional views can be marked as safe for concurrent drawing to give the view drawing system further scheduling flexibility (this may be particularly worthwhile for descendants of the primary threadable views, due to implicit back-to-front drawing order dependencies), but switching this on for even a few of a UI’s “heavier” leaf views is often sufficient to reap the bulk of the potential performance benefit, where such benefit exists.

To the NSWindow class, we’ve added a Boolean “allowsConcurrentViewDrawing” property with the following accessor methods:
/* Reports whether threading of view drawing is enabled for this window.  Defaults to YES.
*/
- (BOOL)allowsConcurrentViewDrawing;
/* Sets whether threading of view drawing should be enabled for this window.  Defaults to YES.  When this is set to YES,
AppKit's view system is allowed to perform -drawRect: activity for the window's views on threads other than the main thread,
for views that have canDrawConcurrently == YES. When this is set to NO, the window's views will be drawn serially as on 10.5
and earlier, even though some of the views may have canDrawConcurrently == YES.
*/
- (void)setAllowsConcurrentViewDrawing:(BOOL)flag;
To the NSView class, we’ve added a “canDrawConcurrently” property with the following accessor methods:
/* Reports whether AppKit may invoke the view's -drawRect: method on a background thread, where it would otherwise be invoked
on the main thread. Defaults to NO.
*/
- (BOOL)canDrawConcurrently;
/* Sets whether AppKit may invoke the view's -drawRect: method on a background thread, where it would otherwise be invoked
on the main thread. Defaults to NO for most kinds of views. May be set to YES to enable threaded drawing for a particular
view instance. The view's window must also have its "allowsConcurrentViewDrawing" property set to YES (the default) for
threading of view drawing to actually take place.
*/
- (void)setCanDrawConcurrently:(BOOL)flag;
2. The -viewWillDraw recursion that happens at the beginning of a “-display...” pass will still be executed on the main thread, and will complete serially as before.  This allows the potentially view-hierarchy-modifying on-demand layout activity for which -viewWillDraw is designed to complete in a safe and sane single-threaded environment, and is not expected to pose a significant limitation because -viewWillDraw activity is meant to be kept lightweight compared to drawing.

3. Any view instance that has canDrawConcurrently == YES, in a window that allowsConcurrentViewDrawing, is eligible to have its drawing automatically delegated to a background thread/operation at AppKit’s discretion.  AppKit sees to it that the concurrent view drawing operations it spawns have their completion serialized as needed, such that overlapping views (both siblings and ancestor/descendant chains) are rendered with correct results. (* In the current seed build, ancestor ordering is properly respected, but support for concurrent drawing of overlapping sibling views is not yet complete, so overlapping siblings may show drawing artifacts when allowed to draw concurrently. Enabling of concurrent view drawing is therefore not currently recommended in cases where sibling views may overlap.)

4. Servicing of normal view tree drawing (“-displayIfNeeded” activity) will still be initiated and managed by the main thread, which will seek to load-balance view drawing work by spawning background operations for certain eligible views.   Decisions about which views to spin off to background operations may be based in part on view draw measurements, among other potential factors.  The presence or absence of overlapping sibling views will influence the partitioning as well.  The main thread will complete remaining view tree drawing, and then block on completion of any background view drawing operations it spawned before flushing the window and returning control to the runloop.

Concurrent View Drawing - Thread Safety Implications

The simplifying implications of this last point are important: AppKit must force a synchronization point before the window flush anyway, to allow for all contributed drawing into the window to complete before the flush, but this has the added benefit that the runloop on the main thread is guaranteed to be blocked during a drawing pass, including during any background-thread drawing of views in the window.  So excepting side effects wherein the act of drawing a view may modify data it shares in common with another view that may be attempting to draw simultaneously on another thread (though hopefully relatively rare, this is the reason why both view- and window-level disabling API are provided), views that reference data outside themselves largely needn’t be any more concerned about the data changing out from under them than they have been with today’s primarily main-thread-based view drawing.  If view drawing is happening, then model data that the views reference can be relied on not to be changed by event-handling and other main thread activity while that’s happening. Background-thread changes to the model will need to be coordinated with views on the main thread as before, using available mechanisms such as locks, notification queues, -performSelectorOnMainThread:..., or the like.

Concurrent View Drawing - Testing Features and Additional Notes

To facilitate experimenting with this feature, some AppKit user defaults have been added. These are subject to changing or going away entirely, so as with other debug user defaults AppKit provides, do not rely on them in production code.

“NSEnableConcurrentViewDrawing” can be set to NO to disable concurrent view drawing entirely for a process, reverting to Leopard-and-earlier view drawing behavior regardless of the allowsConcurrentViewDrawing and canDrawConcurrently settings on individual windows and views. It defaults to YES otherwise.

“NSConcurrentViewClasses” can be set to a comma-delimited list of view class names to force canDrawConcurrently to be set to YES for all instances of those classes, allowing for preliminary testing of this feature with existing built app executables. Note that the class test used here is intentionally an exact equality test, not an isKindOfClass: test -- so including “NSButton” in the list would not cause instances of subclasses of NSButton to be enabled for concurrent drawing. To force enabling of concurrent drawing for both NSButton and NSPopUpButton instances, one would need to include both those class names in the list.

“NSShowConcurrentViewDrawing” can be set to YES, which frames every concurrently drawn view in green for visual confirmation that concurrent view drawing is operating.

“NSDebugConcurrentViewDrawing” can be set to YES to enable some basic diagnostic console log output related to concurrent view drawing.

“NSConcurrentViewDrawingMinCores” specifies the minimum number of CPU cores that must be available on the host system for AppKit to actually attempt concurrent view drawing. AppKit compares this value to [[NSProcessInfo processInfo] activeProcessorCount]. The default value is 2.

An example of applying some of these defaults in launching TextEdit.app:
/Applications/TextEdit.app/Contents/MacOS/TextEdit -NSShowConcurrentViewDrawing YES -NSConcurrentViewClasses "NSScroller,NSPopUpButton,NSButton"
To assist developers in assessing typical drawing costs of various views, AppKit accumulates basic timing stats for views’ -drawRect: invocations, which are now shown as part of the -_subtreeDescription debug info. Printing a window’s view subtree description in gdb as below shows these stats appended to the line for each view, reporting a minimum, mean (average), and maximum draw time in milliseconds. Draw times of several milliseconds, and especially more than 10ms or so, typically indicate a good potential candidate view for concurrent drawing. Draw times of less than a hundredth of a millisecond show up as 0.00ms. This particular example (TextEdit with an empty document window) does not show any particularly strong candidates for concurrent view drawing.
(gdb) po [[[[[NSApplication sharedApplication] windows] objectAtIndex:0] _borderView] _subtreeDescription]
[ A O P ] h=--- v=--- NSThemeFrame 0x185650 "Untitled" f=(0,0,475,442) b=(-) TIME drawRect: min/mean/max 0.62/0.62/0.62 ms
[ AF ] h=--- v=--- _NSThemeCloseWidget 0x15e840 "Button" f=(8,422,14,16) b=(-) TIME drawRect: min/mean/max 0.04/0.05/0.06 ms
[ AF ] h=--- v=--- _NSThemeWidget 0x15fd00 "Button" f=(50,422,14,16) b=(-) TIME drawRect: min/mean/max 0.06/0.07/0.08 ms
[ AF ] h=--- v=--- _NSThemeWidget 0x15fe50 "Button" f=(29,422,14,16) b=(-) TIME drawRect: min/mean/max 0.04/0.04/0.04 ms
[ A ] h=--- v=--- NSView 0x187840 f=(0,0,475,420) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ AF O ] h=-&- v=-&- ScalingScrollView 0x13c680 f=(0,0,475,420) b=(-) TIME drawRect: min/mean/max 0.03/1.39/2.75 ms
[ AF OGP ] h=--- v=--- NSClipView 0x17c6b0 f=(0,55,460,365) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ AF OG ] h=-&- v=--- NSTextView 0x19db90 f=(0,0,460,365) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ AF O ] h=--- v=--- NSScroller 0x1a2aa0 f=(460,55,15,350) b=(-) TIME drawRect: min/mean/max 0.06/0.07/0.07 ms
[ AF O ] h=--- v=--- NSScroller 0x14c770 f=(-100,-100,479,15) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ AF O ] h=--- v=--- NSRulerView 0x15cf00 f=(0,0,475,55) b=(-) TIME drawRect: min/mean/max 1.51/1.51/1.51 ms
[ P ] h=--- v=--- NSStopTouchingMeBox 0x15a680 "Title" f=(0,0,475,24) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ ] h=--- v=--- NSView 0x1aaa70 f=(0,0,475,24) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ P ] h=--- v=--- NSBox 0x17bfc0 "Title" f=(0,-1,388,24) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ A ] h=--- v=--- NSView 0x14c700 f=(0,0,388,24) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ AF ] h=--- v=--- NSPopUpButton 0x1a9360 "Spacing" f=(194,-1,85,22) b=(-) TIME drawRect: min/mean/max 0.18/0.19/0.21 ms
[ AF ] h=--- v=--- NSPopUpButton 0x158b80 "Styles" f=(2,-1,85,22) b=(-) TIME drawRect: min/mean/max 0.08/0.10/0.11 ms
[ AF ] h=--- v=--- NSPopUpButton 0x162520 "Lists" f=(279,-1,85,22) b=(-) TIME drawRect: min/mean/max 0.08/0.09/0.10 ms
[ AF ] h=--- v=--- NSSegmentedControl 0x1807f0 f=(88,-3,105,25) b=(-) TIME drawRect: min/mean/max 0.40/0.46/0.52 ms
[ P ] h=--- v=--- NSBox 0x164830 "Title" f=(388,-1,88,24) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ ] h=--- v=--- NSView 0x1595a0 f=(0,0,88,24) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ P ] h=--- v=--- NSBox 0x188980 "Title" f=(0,0,79,20) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ A ] h=--- v=--- NSView 0x169af0 f=(0,0,79,20) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ P ] h=&-- v=--- NSBox 0x1b6370 "Title" f=(0,0,79,20) b=(-) TIME drawRect: min/mean/max 0.23/0.23/0.23 ms
[ ] h=--- v=--- NSView 0x1673c0 f=(3,3,73,14) b=(-) TIME drawRect: min/mean/max 0.00/0.00/0.00 ms
[ A ] h=--- v=--- NSTabWell 0x180330 f=(4,1,15,13) b=(-) TIME drawRect: min/mean/max 0.02/0.02/0.02 ms
[ A ] h=--- v=--- NSTabWell 0x1847b0 f=(20,1,15,13) b=(-) TIME drawRect: min/mean/max 0.02/0.02/0.02 ms
[ A ] h=--- v=--- NSTabWell 0x1b8bf0 f=(37,1,15,13) b=(-) TIME drawRect: min/mean/max 0.02/0.02/0.02 ms
[ A ] h=--- v=--- NSTabWell 0x1a7a70 f=(54,1,15,13) b=(-) TIME drawRect: min/mean/max 0.01/0.01/0.01 ms
A=autoresizesSubviews, C=canDrawConcurrently, D=needsDisplay, F=flipped, G=gstate, H=hidden (h=by ancestor),
O=opaque, P=preservesContentDuringLiveResize, S=scaled/rotated, W=wantsLayer (w=ancestor wantsLayer), #=has surface
To provide more meaningful data, only full redraws of a view will contribute to these timing stats. Resizing a view’s window is a good way to prompt full redraws so as
to gather draw time stats, for views that are not specifically optimized preserve content using the preservesContentDuringLiveResize mechanism.

Simple standard AppKit NSControls that don’t use dataSources, and don’t otherwise rely on data outside their own at draw time, are likely to be safe for canDrawConcurrently enabling, but have not all been formally vetted for concurrent drawing safety yet. For now, it is recommended that applications restrict enabling of canDrawConcurrently to their own custom view classes.

Layer-backed view drawing does not yet take advantage of the ability to draw views concurrently. This is a possible future direction.



NSView -setNeedsDisplay: and -setNeedsDisplayInRect: Activity During Drawing (New since WWDC 2008)

One Mac OS X 10.5, sending -setNeedsDisplay: or -setNeedsDisplayInRect: to a view might not produce the requested redraw if the view’s window is in the middle of a recursive view display operation when the request arrives. On 10.6, rectangles invalidated during display are accumulated in a side region that will be serviced in a subsequent window display cycle. This new behavior is on by default for applications linked on or after 10.6. For debugging purposes, it can be disabled by running with the “NSWindowsUseDeferredNeedsDisplayRegion” user default set to NO, or forced on by running with this user default set to YES. If you see a drawing glitch or drawing performance issue that goes away when running with “-NSWindowsUseDeferredNeedsDisplayRegion NO”, please file a Radar.



NSView -viewWillDraw and Offscreen Drawing

On Mac OS X 10.5, the newly introduced -viewWillDraw method was only invoked when views were drawn into their window. On 10.6, -viewWillDraw is also invoked when either -cacheDisplayInRect:toBitmapImageRep: or -displayRectIgnoringOpacity:inContext: is used to draw views to an alternate destination.

10.6 also fixes an issue that sometimes prevented -viewWillDraw messages from being sent to views that were being printed.


Layer-Backed NSOpenGLViews and Pixel Formats

On 10.6, the layer-backed operating mode of an NSOpenGLView now inherits pixel format attributes from the view’s existing OpenGL context. If the view does not have an existing OpenGL context (e.g. because the view begins life in layer-backed mode, without having first operated in conventional view compositing mode), AppKit checks whether the view provides a -pixelFormat method. If so, AppKit invokes the view’s -pixelFormat method and examines the result to construct a compatible OpenGL pixel format and context for use in layer-backed mode.

NSOpenGLLayer (New since WWDC 2009)

Mac OS X 10.6 introduces a new “NSOpenGLLayer” class, that supports fully generalized OpenGL usage in layer-backed mode.

On Mac OS X 10.5, AppKit supported OpenGL rendering in layer-backed mode only through the use of NSOpenGLView. When an app set wantsLayer to YES for an NSOpenGLView or one of its ancestor views, AppKit would automatically set up a suitable backing layer and OpenGL context for rendering, using the view’s existing, surface-backed OpenGL context (if any) as a “share” context (so that the same texture IDs and other OpenGL object references would carry over to layer-backed mode).

On Mac OS X 10.6, the addition of NSOpenGLLayer makes it possible for any arbitrary NSView (not necessarily derived from NSOpenGLView) to render via OpenGL in layer-backed mode -- much as an NSOpenGLContext can be bound to any arbitrary NSView in non-layer-backed mode. The essential requirements for enabling an arbitrary view to render via OpenGL in layer-backed mode are as follows:

1. Subclass NSOpenGLLayer.

2. In your NSOpenGLLayer subclass, override -openGLPixelFormatForDisplayMask: to return an autoreleased NSOpenGLPixelFormat suitable for the specified set of displays and the content you want to render.

3. If you need your context to share OpenGL objects with another, existing context, you may also want to override -openGLContextForPixelFormat: so that you can specify the desired “share” context when creating the new context. (You should return an autoreleased NSOpenGLContext.) Note that you can ask an NSOpenGLLayer for its associated view, which may help you to obtain a pointer to the desired “share” context.

4. In your view class, override -makeBackingLayer to return an autoreleased instance of your NSOpenGLLayer subclass. For example:
- (CALayer *)makeBackingLayer {
return [[[CubeViewOpenGLLayer alloc] init] autorelease];
}
5. In your view class, override -setFrameSize: to make your layer’s openGLContext current and -update it, and to re-specify the OpenGL viewport and GL_MODELVIEW / GL_PROJECTION transforms as you would normally do when an OpenGL view is resized. You can use this same technique to retrieve the layer’s openGLContext anytime you need to make it current or message it for any other reason:
- (void)setFrameSize:(NSSize)newSize {
[super setFrameSize:newSize];
    NSOpenGLContext *openGLContext = [(NSOpenGLLayer *)[self layer] openGLContext];
    [openGLContext makeCurrentContext];
[openGLContext update];
[self reshape]; // Assume we've defined a -reshape method that calls glViewport()
// and updates the GL_PROJECTION and GL_MODELVIEW matrices.
}
There are a number of additional issues involved in implementing a fully general OpenGL view -- one that can be switched into and out of layer-backed mode at will. The necessary techniques are likely to be illustrated by a future update to the LayerBackedOpenGLView code sample.



Layer Contents Placement and Redraw Policy API (New since WWDC 2008)

Mac OS X 10.6 introduces new API on NSView, that clients can use to dramatically improve the performance of layer-backed view resize animations. The new NSView methods are accessors for two new properties: layerContentsRedrawPolicy and layerContentsPlacement.
- (NSViewLayerContentsRedrawPolicy)layerContentsRedrawPolicy;
- (void)setLayerContentsRedrawPolicy:(NSViewLayerContentsRedrawPolicy)newPolicy;
- (NSViewLayerContentsPlacement)layerContentsPlacement;
- (void)setLayerContentsPlacement:(NSViewLayerContentsPlacement)newPlacement;
Prior to 10.6, AppKit did not provide any way for implementers or users of views to express how a view’s drawn content would be affected by resizing the view, and whether redrawing of the view’s content would be required. Without such information, AppKit has had to assume that a view’s content could change in arbitrary ways when the view was resized, and must be redrawn at each intermediate frame of an animated resize. In layer-backed mode, this forces AppKit to divert view resizing animations off of Core Animation’s asynchronous render+evaluation thread, and implement the resizing using timer-driven animation on AppKit’s main runloop -- yielding both reduced performance and sometimes visually unpleasant synchronization issues when AppKit-driven resize animations are combined with asynchronous, Core Animation-evaluated animations.

Using this new API, the implementation of a view class, or code that uses instances of a particular view type, can control how resizing is handled when the view is layer-backed. The primary enabler for this is the new layerContentsRedrawPolicy property, which has the following declaration and allowed values:
enum {
NSViewLayerContentsRedrawNever = 0,
NSViewLayerContentsRedrawOnSetNeedsDisplay = 1,
NSViewLayerContentsRedrawDuringViewResize = 2,
NSViewLayerContentsRedrawBeforeViewResize = 3
};
typedef NSInteger NSViewLayerContentsRedrawPolicy;
The semantics of these modes are:
NSViewLayerContentsRedrawNever—Leave the layer's contents alone. Never mark the layer as needing display, or draw the view's contents to the layer. This is the way AppKit treats developer-provided layers on both 10.5 and 10.6.
NSViewLayerContentsRedrawOnSetNeedsDisplay—Map view -setNeedsDisplay...: activity to the layer, and redraw affected layer parts by invoking the view's -drawRect:, but don't mark the view or layer as needing display when the view's size changes.
NSViewLayerContentsRedrawDuringViewResize—Resize the layer and redraw the view to the layer when the view's size changes. If the resize is animated, AppKit will drive the resize animation itself and will do this resize+redraw at each step of the animation. Affected parts of the layer will also be redrawn when the view is marked as needing display. (This mode is a superset of NSViewLayerContentsRedrawOnSetNeedsDisplay.) This is the way we treat AppKit-generated view backing layers today.
NSViewLayerContentsRedrawBeforeViewResize—Resize the layer and redraw the view to the layer when the view's size changes. This will be done just once at the beginning of a resize animation, not at each frame of the animation. Affected parts of the layer will also be redrawn when the view is marked as needing display. (This mode is a superset of NSViewLayerContentsRedrawOnSetNeedsDisplay.)


For a view that has no associated layer, or that has been assigned a developer-provided layer using NSView’s -setLayer: API, the default layerContentsRedrawPolicy is NSViewLayerContentsRedrawNever, with an accompanying layerContentsPlacement of NSViewLayerContentsPlacementScaleAxesIndependently. This instructs AppKit that it is not allowed to replace the layer’s content, and provides the same content placement as CALayer’s default contentsGravity setting of kCAGravityResize.

For a view that has acquired an AppKit-generated backing layer, AppKit sets the view’s layerContentsRedrawPolicy to a default of NSViewLayerContentsRedrawDuringViewResize, forcing the view’s content to be continually redrawn into the view’s backing layer during animated resizing of the view, which produces strictly correct but not optimally performant results.

If you know that redrawing at each animation frame is not necessary to produce correctly rendered results for a particular view, or are willing to accept an approximation of the view’s intermediate appearance during potentially brief animations in exchange for an animation performance and smoothness benefit, you can change the view’s layerContentsRedrawPolicy to one of the other supported values. When doing this, you should also specify the desired layerContentsPlacement for the view. The layerContentsPlacement determines how the backing layer’s existing cached content image will be mapped into the layer as the layer is resized. (It is analogous to, and underpinned by, CALayer’s contentsGravity property, as indicated by the comments below.)

The provided layerContentsPlacement values are as follows:
enum {
NSViewLayerContentsPlacementScaleAxesIndependently = 0, // equivalent to kCAGravityResize
NSViewLayerContentsPlacementScaleProportionallyToFit = 1, // equivalent to kCAGravityResizeAspect
NSViewLayerContentsPlacementScaleProportionallyToFill = 2, // equivalent to kCAGravityResizeAspectFill
NSViewLayerContentsPlacementCenter = 3,
NSViewLayerContentsPlacementTop = 4,
NSViewLayerContentsPlacementTopRight = 5,
NSViewLayerContentsPlacementRight = 6,
NSViewLayerContentsPlacementBottomRight = 7,
NSViewLayerContentsPlacementBottom = 8,
NSViewLayerContentsPlacementBottomLeft = 9,
NSViewLayerContentsPlacementLeft = 10,
NSViewLayerContentsPlacementTopLeft = 11
};
typedef NSInteger NSViewLayerContentsPlacement;
The first three values specify that the layer’s existing content should be displayed scaled in one of three supported ways when the layer is resized, while being kept centered within the layer’s bounds. The remaining nine values specify that instead of being scaled, the layer’s contents should be displayed at their existing size, and pinned to one of nine canonical positions relative to the layer’s new frame.


NSOpenGLView Minor Method Behavior Changes

On Mac OS X 10.5 and earlier, invoking NSOpenGLView’s -setPixelFormat: method with the view’s current pixelFormat object as its parameter could cause the pixelFormat to be deallocated, if nothing else had retained it. This has been fixed on 10.6.

The same applied to NSOpenGLView’s -setOpenGLContext: method and its context parameter. This has also been fixed on 10.6. Additionally, on 10.5 and earlier -setOpenGLContext: would invoke -clearGLContext, even when the given context was the same as the view’s existing openGLContext. To reduce the risk of compatibility breakage, this behavior has been preserved on 10.6, for application binaries that were linked on 10.5 and earlier. Applications linked on 10.6 and later will only see -setOpenGLContext: invoke -clearGLContext when the view is actually being switched to a different context.


New NSOpenGL-CGL Bridging Methods (New since WWDC 2008)

To provide improved interoperability between the NSOpenGL and CGL APIs, Mac OS X 10.6 completes the set of CGL-typed initializer and getter methods provided by the NSOpenGLContext, NSOpenGLPixelBuffer, and NSOpenGLPixelFormat classes. Using these methods, one can initialize an NSOpenGL object to wrap an object of the corresponding CGL type, and/or get the CGL object that’s wrapped by a corresponding NSOpenGL object.

Continuing the convention we've followed of avoiding explicit use of CGL argument types in AppKit API, the arguments and return values are typed as void *, and must be cast by clients to the appropriate underlying type (CGLContextObj, CGLPBufferObj, or CGLPixelFormatObj) when necessary.  Also following our existing convention, the -init... and getter methods listed here include the names of the underlying CGL types: CGLContextObj, CGLPixelFormatObj, and CGLPBufferObj.  The CGL objects are retained by their owning NSOpenGL wrapper for the NSOpenGL wrapper's lifetime.
@interface NSOpenGLContext
...
- (id)initWithCGLContextObj:(void *)context;
- (void *)CGLContextObj; // 10.3 and later
...
@end
@interface NSOpenGLPixelBuffer
...
- (id)initWithCGLPBufferObj:(void *)pbuffer;
- (void *)CGLPBufferObj;
...
@end
@interface NSOpenGLPixelFormat
...
- (id)initWithCGLPixelFormatObj:(void *)format;
- (void *)CGLPixelFormatObj; // 10.3 and later
...
@end

Layer Tree Rendering and Modal Windows

An issue that could cause flicker when using Core Animation layer tree rendering in a modal window has been fixed.


Printing Layer-Backed Views

On Mac OS X 10.5 through 10.5.2, attempting to print layer-backed views would produce empty output. This has been fixed for 10.5.3 and on 10.6, such that printing now proceeds in the same way as if the views were not layer-backed. (The views are drawn into the printing context.)

AppKit does not currently provide automatic printing support for standalone, developer provided layer trees. To generate printed output in such cases, it is necessary to use Core Animation’s CARenderer API together with OpenGL to render to a bitmapped image, and then print the resultant image.


Live toolbar layout during customization (New since WWDC 2008)

Prior to SnowLeopard, toolbars would not show the actual layout produced while rearranging, adding, or removing toolbar items. In SnowLeopard, toolbars should show their correct layout even during customization.

Toolbars no longer validate for some eventsAs an optimization, NSToolbar no longer validates for the following events: NSLeftMouseDragged, NSRightMouseDragged, NSOtherMouseDragged, NSMouseEntered, NSMouseExited, NSScrollWheel, NSCursorUpdate, NSKeyDown. In addition, validation for NSKeyUp and NSFlagsChanged events is deferred for up to .85 seconds in SnowLeopard, with the timer restarting for every new deferrable event. So a sequence of key events will not trigger any validation at all, until either a pause of .85 seconds, or an event other than NSKeyUp or NSFlagsChanged is processed.

To trigger validation for a single toolbar manually, call -[NSToolbar validateVisibleItems]. To trigger validation for all toolbars, call [NSApp setWindowsNeedUpdate:YES]

Flipped images in toolbars (New since January 2009 seed)

A common but incorrect practice is to call setFlipped:YES on an image that you plan to draw into a flipped graphics context. This is incorrect because if the image is later drawn into a normal unflipped context, the image will appear upside down. However, Leopard and earlier contained a bug in which images set on NSToolbarItem (via setImage:) would ignore their isFlipped property. SnowLeopard fixes this bug for apps compiled on SnowLeopard with the 10.6 SDK; as a result, some images which should have drawn upside down in Leopard, will begin doing so when your app is recompiled.

If you recompile your app on SnowLeopard and discover that your toolbar item images are drawing upside down, then it indicates that you are calling setFlipped:YES somewhere within your code. You should remove those calls and replace the image drawing with methods that correctly handle flipped contexts. See the discussion of setFlipped: in these Release Notes for more discussion.

Spell checkers must be in a Services directory

In SnowLeopard, spell checkers will only be recognized if they are in one of the standard Services directory (/Library/Services, ~/Library/Services, or /System/Library/Services). This is to prevent compatibility problems with spell checkers from previous versions of the OS.

setuid/setgid apps disallowed

As a security measure, SnowLeopard takes steps to prevent applications that use AppKit from running setuid or setgid. If AppKit detects that it is running issetugid(), the following will happen:

Under 64 bit, it will log a message and then exit(EXIT_FAILURE).

Under 32 bit, it will give the user a chance to authenticate as an administrator. If the attempt succeeds, the app will run as normal; if the user fails to authenticate, or cancels, it will exit(EXIT_FAILURE). If the attempt fails because the authentication dialog could not be shown, then it will perform a linked on or after check. Apps linked before SnowLeopard will be allowed to run; applications linked on or after SnowLeopard will be exited.

This only affects applications that have the setuid or setgid Unix permission bit set, or apps that inherit this bit from a fork() of a setugid app. This does not affect applications run via sudo, su, or normally as root.

Tool tips on NSTabViewItem

NSTabViewItem now supports custom tool tips on the tabs themselves. See the NSTabViewItem.h header for more information.

Underscore treated like minus key

Starting with Leopard, AppKit began interpreting ⌘= as ⌘+ if no menu item claims the key equivalent ⌘+ and the pressed = key also has a + on it. In SnowLeopard, this support has been extended to interpret ⌘_ as ⌘-, if the pressed key has both _ and -.

New NSWorkspace APIs (Updated since WWDC 2008)

NSWorkspace now contains APIs for gathering information about file labels, and for changing the desktop background. NSWorkspace also contains new APIs for duplicating files and moving them to the trash, which are more powerful and convenient than the older performFileOperation:. There are additional APIs not mentioned in these notes. See the NSWorkspace class header for more information.

NSWorkspace now posts notifications when apps are hidden, unhidden, activated, or deactivated. It also posts notifications when the name or mount location of a volume is changed. Lastly, there is a notification for when the available file colors or labels changes. The new app notifications fire for all apps, compared to the existing notifications which fire for only foreground apps.

NSRunningApplication

SnowLeopard includes a new class, NSRunningApplication, for inspecting and manipulating running applications on the system. See the NSRunningApplication header in AppKit for more information.

NSApplication setHelpMenu: (New since WWDC 2008)

The new setHelpMenu: API on NSApplication allows apps to determine which menu gets the Spotlight for Help search field. The default Main Menu nib, when created on SnowLeopard, will automatically set the Help menu in the same manner as the Window menu.

NSMenu validation (New since WWDC 2008)

The NSMenu method -performActionForItemAtIndex: no longer triggers menu validation. This is because validation is typically done during menu tracking or key equivalent matching, so the subsequent performActionForItemAtIndex: validation was redundant. To trigger validation explicitly, use the -[NSMenu update] method.

NSMenu Function Key Equivalents

NSF16FunctionKey through NSF19FunctionKey are now available as key equivalents in menu items.

NSMenu performActionForItemAtIndex: highlighting and accessibility (New since WWDC 2008)

The NSMenu method performActionForItemAtIndex:, when called, now triggers highlighting in the menu bar. It also sends out appropriate accessibility notifications indicating the item was selected.

NSMenu popUpMenuPositioningItem: atLocation: inView: (New since WWDC 2008)

NSMenu has a new method for popping up a menu as if it were a popup button. This is meant to be an replacement for the Carbon function PopUpMenuSelect(). See the NSMenu.h header for more information.

NSMenu confinementRectForMenu: (New since WWDC 2008)

NSMenu has a new delegate method confinementRectForMenu: onScreen: to allow some control over where a menu may pop up. See the NSMenu.h header for more information.

NSPopUpButtonCell supports NSImageOnly (New since WWDC 2008)

Popup buttons now support the NSImageOnly image position, which prevents the title from showing in the control.

NSMenu key equivalent matching is one per event (New since WWDC 2008)

In Leopard, the main menu may be queried for key equivalent matches multiple times within a particular event's lifecycle, if no menu item is found to match. This was a performance problem because a menus would be populated multiple times for a single event. In SnowLeopard, we only populate and search the menu once per key event.

It is possible, though unlikely, that apps depended on the old behavior. For example, if an override of -[NSApplication sendEvent:] changed key equivalents so that they match the event, then these key equivalents would no longer work in SnowLeopard. For this reason, the user default "NSAllowMultipleKeyEquivalentSearchesPerEvent" is available to restore the Leopard behavior on SnowLeopard.

Nibless apps and the application menu

In Leopard and earlier, apps that tried to construct a menu bar without a nib would get an undesirable stubby application menu that could not be removed. To work around this problem on Leopard, you can call the undocumented setAppleMenu: method and pass it the application menu, like so:
[NSApp setAppleMenu:[[[NSApp mainMenu] itemAtIndex:0] submenu]];
In SnowLeopard, this workaround is unnecessary and should not be used. Under SnowLeopard, the first menu is always identified as the application menu.

NSApplication application menu item title (New since WWDC 2008)

In Leopard, the first item in the main menu (the application menu) would have its title modified to the empty string. In SnowLeopard, this is only done for apps linked on Leopard or earlier: new apps will not see this title modified. The title of the this menu item is ignored for display purposes - the application menu always reflects the application name.

Main menu items no longer specially retained during tracking (New since WWDC 2008)

In Leopard, every menu item contained directly or indirectly within the main menu would be retained during menu tracking. This was an inefficiency, but some apps would message menu items after removing them within menuNeedsUpdate:. In SnowLeopard, menu items within the main menu are retained across calls to menuNeedsUpdate:, and then only for 32 bit apps compiled on Leopard or earlier. You should not depend on menu items being retained after they are removed from the main menu.


Services Menu visual changes (New since WWDC 2009)

The Services menu now categories Services based on their send and receive types, and shows icons for Services. The Services menu is also flattened - no more submenus. When updating your Service for SnowLeopard, make sure your Service has an icon and a descriptive title that makes it easy to identify your Service in the flattened menu. Also consider how your Service can be made contextual, as discussed under Services Contextuality. See the SysServices guide for more information.

Services Preferences (New since WWDC 2009)

SnowLeopard allows the users to enable or disable individual Services. The preference pane is accessible from the Services Preferences menu item within the Services menu, and also via System Preferences.

Services Contextuality (New since WWDC 2009)

In SnowLeopard, Services can appear only in certain contexts. For example, the Open URL Service appears only if the selected text contains a URL, the Reveal in Finder Service appears only if a file path is selected, and the Set Desktop Picture Service appears only if images are selected in Finder. The contextuality of a Service is specified within its Info.plist. For the full list of ways a Service can be made contextual, see the System Services guide in the developer documentation.

Non-contextual Services disabled by default (New since WWDC 2009)

In SnowLeopard, Services that are not contextual are disabled by default. They can be reenabled within the Services Preferences. Because the contextual Services feature is new in SnowLeoaprd, all existing non-Apple Services are disabled by default.

Services that are updated for SnowLeopard will appear enabled by default again. A Service indicates it is updated for SnowLeopard by adding the NSRequiredContext key to its Info.plist, as documented in the System Services guide. Services that cannot limit themselves to certain contexts, but still want to be enabled for SnowLeopard, can add an empty NSRequiredContext and will appear by default.

Services in context menus (New since WWDC 2009)

In SnowLeopard, Services may appear in context menus. Context menus will generally show a subset of those Services available in the Services menu.

The following Services will not show in context menus, even if they appear in the Services menu:

- Services that already have equivalent normal menu items in the context menu, such as Open URL or Look Up in Dictionary.
- Services that have neither a send or receive type.
- Services that will not operate on the selection (have no send type) when a selection is present. For example, Capture Selection from Screen does not appear in context menus if there is selected text.
- A fixed list of Services that cannot be made contextual and would appear everywhere, such as Make New Sticky Note or New Email With Attachment.

All other Services that appear in the Services menu should also appear in context menus.

Services can be Automator workflows (New since WWDC 2009)

In SnowLeopard, you can create a Service from an Automator workflow. To create an Automator workflow Service, start Automator and choose Service from the list of starting points. Workflow Services are first class citizens: they can accept and/or return data, and be made contextual via the same mechanism as regular Services.

Workflow Services must be in one of the Library/Services directories to be recognized. These Service directories are live: adding or removing a Workflow Service from ~/Library/Services/ or /Library/Services/ will cause the Services menu to be updated immediately.


Fetching the cursor set by any application

SnowLeopard adds an NSCursor method that returns a cursor whose image and hot spot match those of the currently-displayed cursor on the system, regardless of which application set that cursor, and regardless of whether Cocoa or Carbon APIs were used to set it: +[NSCursor currentSystemCursor]

This replaces the deprecated QDGetCursorData API.

(The existing +[NSCursor currentCursor] method only returns the cursor set by your application via NSCursor methods, but not cursors set by other applications or cursors set by your application using Carbon API.)

Displaying a Finder search results window

SnowLeopard adds an NSWorkspace method that displays a search results window in Finder for a specific query string: -[NSWorkspace showSearchResultsForQueryString:]

This is the programmatic equivalent of the user switching to Finder, creating a new window, and typing the search string into the search field.

This effectively replaces Carbon's HISearchWindowShow API.

NSEvent additions for event monitoring

There are new NSEvent class methods for monitoring events just in your own application, or events in all applications:
+ (id)addGlobalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(void (^)(NSEvent *))block;
+ (id)addLocalMonitorForEventsMatchingMask:(NSEventMask)mask handler:(NSEvent *(^)(NSEvent *))block;
+ (void)removeMonitor:(id)eventMonitor;
+addLocalMonitorForEventsMatchingMask allows monitoring and modification of all events that are dispatched via -[NSApp sendEvent:]. +addGlobalMonitorForEventsMatchingMask allows monitoring (but not modification) of user input events dispatched to other applications, such as mouse events and keyboard events.

Customizing Spotlight for Help

We introduced an API in AppKit to let developers implement searching their own custom Help Data.  In general, users find the Help search functionality very useful. However, many large applications don't use Apple Help API because of cross platform requirements. Hence, important Help topics are not presented as part of the Help menu. The new API will allow developers to incorporate their own Help topics and take full advantage of the Help feature.

In your application you implement the NSUserInterfaceItemSearching protocol and then register your object with -[NSApplication registerUserInterfaceItemSearchHandler:]. See NSUserInterfaceItemSearching.h for API.

NSObjects implements awakeFromNib

On Mac OS X 10.6 and later, NSObject provides an implementation of awakeFromNib. This means that you can safely call through to [super awakeFromNib] in an overridden implementation when running on Mac OS X 10.6 and later.


Advice for People who Are Looking for -viewWillLoad and -viewDidLoad Methods in NSViewController

Even though NSWindowController has -windowWillLoad and -windowDidLoad methods for you to override the NSViewController class introduced in Mac OS 10.5 does not have corresponding -viewWillLoad and -viewDidLoad methods. You can override -[NSViewController loadView] to customize what happens immediately before or immediately after nib loading done by a view controller.

New Support for Concurrent Document Opening in NSDocument

NSDocument now has the ability to read documents concurrently, using background threads. A new class method has been added to NSDocument to give you control over this:
+ (BOOL)canConcurrentlyReadDocumentsOfType:(NSString *)typeName;
Return whether instances of the receiving class can concurrently read documents of the specified type. The default implementation of this method returns NO. You can override it to return YES to enable concurrent opening of documents but you must make sure your document reading code can be safely executed concurrently, in non-main threads.

Note that NSUndoManager's mechanism for automatically creating one group per UI event doesn't coexist very well with NSUndoManager usage on non-main threads. You should disable undo registration during document reading, which is a good idea even in the absence of concurrency. See for example SKTDocument.m in /Developer/Examples/Sketch.

Note that code executed during the opening of a document triggered by an Apple event will not be able to get the current Apple event, because the event is suspended until all documents are read, to enable correct reporting of success or failure to the Apple event sender. If, for example, you are checking the current Apple event for a search string, you should not enable concurrent document opening unless you have another solution for getting the search string.

Advice for Overriders of -[NSDocumentController openDocumentWithContentsOfURL:display:error:] (New since November 2008 Seed)

Since the introduction of -[NSDocumentController openDocumentWithContentsOfURL:display:error:] in Mac OS 10.4 it has been easy to mask bugs, in either your application's code or its Info.plist file, that cause -[NSDocumentController typeForContentsOfURL:error:], also introduced in Mac OS 10.4, to return nil and an error inappropriately. The default implementation of -openDocumentWithContentsOfURL:display:error: was the only place in AppKit from which -typeForContentsOfURL:error: was frequently invoked so if you overrode the former method and did not invoke super or the latter method in your override you would not notice such bugs. With the introduction of support for concurrent document opening in Mac OS 10.6 there are now other places in AppKit from which -typeForContentsOfURL:error: is invoked. For backward binary compatibility with Mac OS 10.5 and earlier this is done only in applications linked against Mac OS 10.6. If you notice new document opening problems in your application when you start linking it against the Mac OS 10.6 SDK you might want to start debugging by seeing what -typeForContentsOfURL:error: is returning.

Advice for Overriders of -[NSDocument close] (New since WWDC 2008)

Merely overriding -[NSDocument close] is usually not sufficient for many purposes because it's often not invoked at application termination time. This is for performance and there are no plans to change this in the future. It's best to avoid requiring the sort of resource cleanup that must be done at document closing time but, if it's unavoidable in your application, try initiating such cleanup for documents that are still open in your application delegate's -applicationWillTerminate: method in addition to an override of -[NSDocument close]. Both -[NSDocument close] overrides and -applicationWillTerminate: application delegate methods are by the way at odds with the new "Fast Killing of Applications" mechanism that is described in the Foundation release notes and which we would like you to adopt.

New Opportunity for Customization of Save Panels Presented by NSDocument (New since WWDC 2008)

In earlier versions of Mac OS X there was no way for a subclass of NSDocument to customize the initial value of the file name field in presented save panels, not even by overriding -[NSDocument prepareSavePanel]. In Mac OS 10.6 NSDocument now uses the NSSavePanel methods added in Mac OS 10.6 so it can allow this kind of customization. If you override -prepareSavePanel and send a -setNameFieldStringValue: message to the save panel NSDocument will not overwrite the value that's set. It also doesn't overwrite any value set by sending -setDirectoryURL: to the save panel in your override of -[NSDocument prepareSavePanel].

New Support for "Save As PDF…" in NSDocument Printing (New since November 2008 Seed)

-[NSDocument printDocumentWithSettings:showPrintPanel:delegate:didPrintSelector:contextInfo:] has a new behavior in Mac OS 10.6: if the passed-in print settings dictionary has an NSPrintJobDisposition entry whose value is NSPrintSaveJob, indicating that the printed pages should be written to a PDF file, but no NSPrintJobSavingURL (new) or NSPrintSavePath (old, deprecated) entry indicating where the PDF file should be written, then NSDocument will present a save panel asking the user where the PDF file should be saved. See TextEdit's -[Document saveDocumentAsPDFTo:] for an example of using this.

Bug Fixes in NSDocumentController (New since WWDC 2008)

In earlier versions of Mac OS X -[NSDocumentController documents] simply returned a pointer to its internal array of documents, which could change as documents were opened or closed, requiring invokers to make a copy to enumerate while closing documents. This was a bug and has been fixed in Mac OS 10.6. A copy of the documents array (autoreleased of course) is now returned.

In Mac OS 10.5 -[NSDocument displayNameForType:], when passed a UTI for a type that conforms to another type for which the application also has a CFBundleDocumentTypes entry, could return the display name for that other type. This was a bug and has been fixed in Mac OS 10.6.

In Mac OS 10.5 -[NSDocument displayNameForType:], when passed a UTI for which the application has a CFBundleDocumentTypes entry that includes a CFBundleTypeName subentry, would return nil if there was no corresponding InfoPlist.strings entry. This was a bug and has been fixed in Mac OS 10.6. Now the unlocalized value of the CFBundleTypeName entry is returned if there is no corresponding InfoPlist.strings entry.

In Mac OS 10.5 -[NSDocument typeFromFileExtension:] would return unpredictable values when passed nil. This meant that -[NSDocumentController typeForContentsOfURL:error:] could also return unpredictable values, in apps in which not all of the Info.plist CFBundleDocumentTypes entries have LSItemContentTypes entries. (See the description of how -typeForContentsOfURL:error: works nowadays in the "Support for UTIs in NSDocumentController" section of the AppKit release notes for Mac OS 10.5.) This was a bug and has been fixed in Mac OS 10.6.

New Support for URLs and Good Error Reporting in NSFileWrapper

NSFileWrapper has been modernized in Mac OS 10.6 and now deals in URLs instead of paths, and reports errors using NSError. These old methods have been deprecated:
- (id)initWithPath:(NSString *)path;
- (id)initSymbolicLinkWithDestination:(NSString *)path;
- (NSString *)symbolicLinkDestination;
- (BOOL)writeToFile:(NSString *)path atomically:(BOOL)atomicFlag updateFilenames:(BOOL)updateFilenamesFlag;
- (BOOL)needsToBeUpdatedFromPath:(NSString *)path;
- (BOOL)updateFromPath:(NSString *)path;
- (NSString *)addFileWithPath:(NSString *)path;
- (NSString *)addSymbolicLinkWithDestination:(NSString *)path preferredFilename:(NSString *)filename;
These new methods have been published:
- (id)initWithURL:(NSURL *)url options:(NSFileWrapperReadingOptions)options error:(NSError **)outError;
- (id)initSymbolicLinkWithDestinationURL:(NSURL *)url;
- (NSURL *)symbolicLinkDestinationURL;
- (BOOL)writeToURL:(NSURL *)url options:(NSFileWrapperWritingOptions)options originalContentsURL:(NSURL *)originalContentsURL error:(NSError **)outError;
- (BOOL)matchesContentsOfURL:(NSURL *)url;
- (BOOL)readFromURL:(NSURL *)url options:(NSFileWrapperReadingOptions)options error:(NSError **)outError;
(We're not publishing new NSURL/NSError-using replacements for -addFileWithPath: and -addSymbolicLinkWithDestination: because the new methods would not actually be necessary and the old methods were so unpopular.)

New NSFileWrapperWritingAtomic and NSFileWrapperWritingWithNameUpdating options have been published for use with -writeToURL:options:originalContentsURL:error:. They correspond to the atomically: and updateFilenames: parameters, respectively, of -writeToFile:atomically:updateFilenames:, with the exception that NSFileWrapperWritingWithNameUpdating, unlike updateFilenames:YES, only causes -setFilename: to be sent to child file wrappers, not the receiver itself.

See the comments in <AppKit/NSFileWrapper.h> for more information.

New Support for Incremental Writing in NSFileWrapper

The new -writeToURL:options:originalContentsURL:error: method mentioned above differs from the now-deprecated -writeToFile:atomically:updateFilenames: method in that in has an additional parameter in which you can pass a URL that locates the previous revision of a file package being saved. When the value of that parameter is not nil NSFileWrapper attempts to avoid unnecessary I/O by merely writing hard links to files instead of actually writing out their contents.

New Reading Options in NSFileWrapper

The new -initWithURL:options:error: and -readFromURL:options:error: messages mentioned above have options: parameters. The possible options are:

NSFileWrapperReadingImmediate - This causes descendent file wrappers to be instantiated and their contents and attributes read immediately. It's good to use this when your application uses NSFileWrapper to represent new attachments.

NSFileWrapperReadingWithoutMapping - This causes NSFileWrapper to never use file mapping for regular file contents. NSFileWrapper does a good job of deciding when to use file mapping instead of nonlazily reading the entire contents of files into memory but you can use this if necessary to make sure your application is particularly robust against the user doing things like unplugging external hard disks without ejecting them first.

New Support for Preserving Metadata in NSFileWrapper (New since November 2008 Seed)

In earlier versions of Mac OS X the only file attributes that NSFileWrapper ever attempted to preserve when writing were the file modification date and the POSIX permissions. In Mac OS 10.6 it now reads and writes these attributes:
• Creation and modification dates
• File name extension hiding
• HFS creator and file type codes
• POSIX permissions
• Extended attributes
• The resource fork

Because NSFileWrapper deals in the same kind of attribute dictionaries as NSFileManager, you can specify the values of the first four kinds of attribute by invoking -setFileAttributes:, passing a dictionary with values for these keys:
• NSFileCreationDate and NSFileModificationDate
• NSFileExtensionHidden
• NSFileHFSCreatorCode and NSFileHFSTypeCode
• NSFilePosixPermissions
Be careful when using -setFileAttributes:. It doesn't add to the receiver's set of file attributes, it completely replaces it.

Bug Fixes in NSFileWrapper (New since November 2008 Seed)

In earlier versions of Mac OS X NSFileWrapper did not take into account the fact that two items whose names differ only by case can't both be written to the same directory in most file systems without one overwriting the other. This bug has been fixed in Mac OS 10.6. -[NSFileWrapper addFileWrapper:] for example will now create a new unique file name for a child whose preferred file name is @"TestyMCTest.test" if there is already a child whose unique file name is @"TestyMcTest.test".

In earlier versions of Mac OS X sending -writeToFile:atomically:updateFilenames: to an NSFileWrapper would do three things for updateFilenames:YES:
• Send -setFilename: to the receiver and its child file wrappers.
• Reread the file attributes of the receiver and its child wrappers from the file system items just written.
• Remap the contents of any regular file wrappers to the corresponding files just written.
The last two things were not right and in Mac OS 10.6 they are no longer done. The remapping of regular file contents in particular caused trouble with applications holding files open at surprising times (memory mapping a file effectively opens it). updateFilenames:YES now just causes -setFilename: to be sent to the receiver and its child file wrappers.

New Cursor Invalidation in -[NSSplitView adjustSubviews] (New since WWDC 2008)

In earlier versions of Mac OS X -[NSSplitView adjustSubviews] did not invalidate the split view's cursor. This made it difficult to correctly animate divider positioning by simply sending -setFrameSize: to the results of sending -animator to the two subviews on either side of the divider and letting -adjustSubviews get invoked repeatedly during the animation. In Mac OS 10.6 -[NSSplitView adjustSubviews] now invokes [[self window] invalidateCursorRectsForView:self] so the cursor over the divider is always correct after such an animation.

Bug Fix in -[NSSplitView minPossiblePositionOfDividerAtIndex:] (New since WWDC 2008)

Mac OS 10.5 added a new -minPossiblePositionOfDividerAtIndex: method to NSSplitView as well as the ability to hide dividers. -minPossiblePositionOfDividerAtIndex: when passed a divider index of 0 is supposed to return zero minus the divider thickness when that divider is hidable. (Conceptually the user can drag the topmost or leftmost divider right off the top or left edge of a split view if it is hidable, and the position of a divider is its top or left edge.) In Mac OS 10.5 it instead returned zero when the subview above or to the left of the divider was collapsed. This was a bug and has been fixed in Mac OS 10.6.

Change In Invocation of NSSplitView Delegate Constraint Methods For Hidden Dividers (New since WWDC 2008)

In Mac OS 10.5 an NSSplitView would pass the exact same value returned by -minPossiblePositionOfDividerAtIndex: or -maxPossiblePositionOfDividerAtIndex: when sending -splitView:constrainMinCoordinate:ofSubviewAt: or -splitView:constrainMaxCoordinate:ofSubviewAt:, respectively, to the split view's delegate. Because that value takes into account the fact that a hidden divider is effectively draggable off the edge of the split view it would be surprisingly small or large, respectively, for hidable dividers. This made it difficult to specify the minimum sizes of subviews using the relatively simple technique described in <AppKit/NSSplitView.h>. This has been changed in Mac OS 10.6. The value passed to -splitView:constrainMinCoordinate:ofSubviewAt: or -splitView:constrainMaxCoordinate:ofSubviewAt: is now the same regardless of whether the relevant divider is hidable. For backward binary compatibility this is only done in applications linked against Mac OS 10.6 or later.

NSPrintInfo Improvements (Updated since November 2008 Seed)

To let you easily take advantage of NSPrintInfo's KVO-compliance (without having to observe the NSPrintInfo's attributes dictionary), accessor methods have been published for the print scaling attribute:
- (void)setScalingFactor:(CGFloat)scalingFactor;
- (CGFloat)scalingFactor;
NSPrintInfo is now as KVO-compliant for "scalingFactor" as it is for "paperSize," "orientation," etc.

Because we're standardizing on NSURL as the representation of locations of files in Mac OS 10.6, a new key into the attributes dictionary has been published:
NSString *NSPrintJobSavingURL;
The value must be an NSURL containing the location to which the job file will be saved, for use when the job disposition is NSPrintSaveJob.

The NSPrintSavePath key has been deprecated.

In earlier versions of Mac OS X there was no way for you to specify that the name extension of the file being written for an NSPrintSaveJob job disposition should be hidden. A new key for that has been published:
NSString *NSPrintJobSavingFileNameExtensionHidden;
The value must be a boolean NSNumber. The default is NO.

New Job Style Hints in NSPrintPanel (New since WWDC 2008)

In Mac OS 10.6 two new job style hints have been published for use with -[NSPrintPanel setJobStyleHint:]. They correspond to Core Printing's new kPMPresetGraphicsTypeAll and kPMPresetGraphicsTypeNone graphics types, respectively. There's no new job style hint corresponding to Core Printing's kPMPresetGraphicsTypeGeneral. A nil job style hint still means the same thing as that.
NSString *const NSPrintAllPresetsJobStyleHint;
NSString *const NSPrintNoPresetsJobStyleHint;


Better Print Preview (New since WWDC 2008)

The Print Preview on the print panel now draws respecting Border, N-Up, Mirror, Reverse Page Orientation, and Page Range.

Also, the page range text/controls underneath the preview shows the physical pages to be printed after taking into consideration the user's settings for N-Up, Page Range, etc...


Printing just the selected content of a document (New since WWDC 2008)

The NSPrintPanel can now optionally add a "Selection" radio option to the list of page range options (All, From:To:, Selection). To enable "Selection" as a user selectable page range in the print panel, Add NSPrintPanelShowsPrintSelection to the NSPrintPanel options when setting up the print operation.
- (NSPrintOperation *)printOperationWithSettings:(NSDictionary *)printSettings error:(NSError **)outError {
    ...
    NSPrintOperation *op = [NSPrintOperation printOperationWithView:...
    NSPrintPanel *printPanel = [op printPanel];
    [printPanel setOptions:[printPanel options] | NSPrintPanelShowsPrintSelection];
    ...
}
To print only the selection, the view supplied to the NSPrintOperation must check the isSelectionOnly property of the printInfo and adjust appropriately when determining the page range (knowsPageRange:) and drawing (drawRect:).
- (BOOL)knowsPageRange:(NSRangePointer)aRange {
    NSPrintOperation *curPrintOperation = [NSPrintOperation currentOperation];
    BOOL printSelectionOnly = [[curPrintOperation printInfo] isSelectionOnly];
    ...
}
- (void)drawRect:(NSRect)rect {
    BOOL printSelectionOnly = NO;
    if(![NSGraphicsContext currentContextDrawingToScreen]) {
        NSPrintOperation *curPrintOperation = [NSPrintOperation currentOperation];
        BOOL printSelectionOnly = [[curPrintOperation printInfo] isSelectionOnly];
    }
    ...
}

NSBrowser - Item Based only features (New since WWDC 2008)

NSBrowser no longer caches the contents of each column. Instead it depends on the data source to provide speedy results. One ability this enables is that the same object can now appear in multiple columns. A consequence of this is that the following new API have been removed:
- (NSIndexPath *)indexPathForItem:(id)item;
- (id)parentForItem:(id)item;
- (void)reloadItem:(id)item reloadChildren:(BOOL)flag;
The reloadItem:reloadChildren: method has been replaced with:
- (void)reloadDataForRowIndexes:(NSIndexSet *)rowIndexes inColumn:(NSInteger)column;
The following method:
- (id)itemAtRow:(NSInteger)row column:(NSInteger)column;
has been replaced with the following to provide better consistency with method names:
- (id)itemAtRow:(NSInteger)row inColumn:(NSInteger)column;
You can now specify the row height:
- (void)setRowHeight:(CGFloat)height;
- (CGFloat)rowHeight;
Also the delegate can specify variable row heights by implementing the following method:
- (CGFloat)browser:(NSBrowser *)browser heightOfRow:(NSInteger)row inColumn:(NSInteger)columnIndex;
The delegate should inform the NSBrowser of row height changes via this method:
- (void)noteHeightOfRowsWithIndexesChanged:(NSIndexSet *)indexSet inColumn:(NSInteger)columnIndex;

NSBrowser - General (New since WWDC 2008)

Updated the header comment for -browser:sizeToFitWidthOfColumn: to inform developers that they can opt out of supplying a column width for any particular column by returning -1. When NSBrowser gets a -1 return value, it will make its own column width determination as if the delegate did not implement this method.

New API to get the column/row at a point and one to get the frame.

Finds the row and column located at 'point', returning YES if both can be found. If a row does not exist at 'point', then -1 is set for the row. If a column does not exist at 'point', then -1 is set for the column. 'point' is expected to be in the NSBrowser's coordinate system. *row and *column may be NULL. The correct BOOL value is returned and the non NULL *row or *column (if any) are filled in.
- (BOOL)getRow:(NSInteger *)row column:(NSInteger *)column forPoint:(NSPoint)point;
Returns the frame of the row at 'row' / 'column' including the area for the expandable arrow. The returned NSRect is in the NSBrowser coordinate space.
- (NSRect)frameOfRow:(NSInteger)row inColumn:(NSInteger)column;

MultiTouch (New since November seed)

In addition to gestures, developers can now get individual touches on a multitouch trackpad. You must explicitly opt-in in order to receive the new touch responder methods. Touches may or may not move the cursor via separate mouse events. The mouse event may occur slightly before or after its associated touch event.

The same event that contains the touches may also contain a gesture. The gesture NSResponder methods are called in addition to the new touch NSResponder methods.


MultiTouch - NSView (New since November seed)

New methods on NSView allow an application to opt in to receive touches. By default, views do not accept touch events:
- (void)setAcceptsTouchEvents:(BOOL)flag;
- (BOOL)acceptsTouchEvents;
In some cases, the user may rest a thumb or other touch on the device. If the device can detect this (MacBooks with glass trackpad) then it will mark the touch as resting. By default, these touches are not delivered and are not included in the event's set of touches. Touches may transition in and out of resting at any time. Unless the view wants restingTouches, began / ended events are simulated as touches transition from resting to active and vice versa. In general resting touches should be ignored.
- (void)setWantsRestingTouches:(BOOL)flag;
- (BOOL)wantsRestingTouches;

MultiTouch - NSEvent (New since November seed)

There is a new method on NSEvent to extract the touches from the event.

This is only valid for gesture events (Gesture, Magnify, Swipe, Rotate, etc.). A view can get all of the touches associated with a gesture without overriding the touch responder methods. Touches that target view, or any of view's descendants, are returned. Pass nil as the view to get touches regardless of their targeted view.
- (NSSet *)touchesMatchingPhase:(NSTouchPhase)phase inView:(NSView *)view;

MultiTouch - NSTouch (New since November seed)

An NSTouch is a snapshot of a particular touch at some instance in time. That is quite different from an iPhone UITouch which persists for the life of the touch and is modified by the system during its life. The identity property is used to follow a specific touch across its lifetime.

Touches do not have a corresponding screen location. The first touch of a touch collection is latched to the view underlying the cursor using the same hit detection as mouse events. Additional touches on the same device are also latched to the same view as any other touching touches. A touch remains latched to its view until the touch has either ended or is cancelled.

NSTouchPhaseBegan:
A finger touched the device. Or, a resting touch transitioned to an active touch and resting touches are not wanted by the view hierarchy.

NSTouchPhaseMoved:
A finger moved on the device.

NSTouchPhaseStationary:
A finger is touching the device, but hasn't moved since the previous event.

NSTouchPhaseEnded:
A finger was lifted from the screen. Or, an active touch transitioned to a resting touch and resting touches are not wanted by the view hierarchy.

NSTouchPhaseCancelled:
The system cancelled tracking for the touch, as when (for example) the window associated with the touch resigns key or is deactivated.
enum {
    NSTouchPhaseBegan           = 1 << 0,
    NSTouchPhaseMoved           = 1 << 1,
    NSTouchPhaseStationary      = 1 << 2,
    NSTouchPhaseEnded           = 1 << 3,
    NSTouchPhaseCancelled       = 1 << 4,
    NSTouchPhaseTouching        = NSTouchPhaseBegan | NSTouchPhaseMoved | NSTouchPhaseStationary,
    NSTouchPhaseAny             = NSUIntegerMax
};
typedef NSUInteger NSTouchPhase;
Unlike the iPhone, NSTouch objects do not persist for the life of the touch.
@interface NSTouch : NSObject <NSCopying>
Use the identity property to track changes to a particular touch during the touch's life. While touch identities may be re-used, they are unique during the life of the touch, even when multiple devices are present. Note: identity objects implement the NSCopying protocol so that they may be used as keys in an NSDictionary. Use isEqual: to compare two touch identities.
@property(readonly) id<NSObject, NSCopying> identity;
@property(readonly) NSTouchPhase phase;
Normalized, absolute position [0,1] of the touch on the device where (0, 0) is the lower left of the device surface.
@property(readonly) NSPoint normalizedPosition;
@property(readonly) BOOL isResting;
The following are properties of an NSTouch, but they really describe properties of the underlying touch device.

The digitizer that generated the touch. Useful to distinguish touches emanating from multiple-device scenario:
@property(readonly) id device;
The range of the touch device in points (72ppi). Note: 0,0 is the lower left of the surface:
@property(readonly) NSSize deviceSize;

MultiTouch - NSResponder (New since November seed)

Once a view opts in to receive touches, the following new responder methods are called. Each touch event may have more than one touch in various phases. Each responder method corresponding to that phase is called. (Note: the order these methods are called is undefined.)

Note: It is possible for more than one of the following methods to be called for the same event. The order the methods are sent is not guaranteed.
/* A new set of touches has been recognized. To get the set of touches that began for this view (or descendants
of this view): [event touchesMatchingPhase:NSTouchPhaseBegan inView:self]; Note: this is not always the point
of contact with the touch device. A touch that transitions from resting to active may be part of a Began set.
*/
- (void)touchesBeganWithEvent:(NSEvent *)event;
/* One or more touches have moved. To get the set of touches that moved for this view (or descendants
of this view): [event touchesMatchingPhase:NSTouchPhaseMoved inView:self];
*/
- (void)touchesMovedWithEvent:(NSEvent *)event;
/* A set of touches have been removed. To get the set of touches that ended for this view (or descendants
of this view): [event touchesMatchingPhase:NSTouchPhaseEnded inView:self]; Note: this is not always the point
of removal with the touch device. A touch that transitions from active to resting may be part of an Ended set.
*/
- (void)touchesEndedWithEvent:(NSEvent *)event;
/* The System has cancelled the tracking of touches for any reason.
*/
- (void)touchesCancelledWithEvent:(NSEvent *)event;

NSDatePicker (New since January seed)

User editing of a text date picker has been vastly improved. Editing a date/time field now replaces the contents of the field with the new digits. After each digit change, there is a short amount of time where the user can append more or delete digits (reseting the time out for each change). Once the timeout has occurred, future edits to the field replace the current value of the field. The new value in progress is committed if the timer runs out or, if adding any more digits would result in a invalid value for that field. Note, if the new value is committed before the time out expires, new edits cannot occur until the timeout expires. Return commits current changes and cancels the time out. Esc reverts any non committed edit. Delete will remove a digit but effectively sets an infinite timer until another change or UI focus movement occurs. MultiTouch - NSEvent (New since January seed)

The subType of touch generated mouse events is now NSTouchEventSubtype. This is useful in when determining when to ignore mouse events in favor of touch events when they are both getting generated. This is not applicable to scrollWheel events.


Gesture support

We have added event types and responder methods for gestures as generated by the trackpad on the MacBook Air and the newest generation MacBook Pro.

NSEvent additions for gesture support

    NSEventTypeGesture = 29
    NSEventTypeMagnify = 30,
    NSEventTypeSwipe = 31,
    NSEventTypeRotate = 18,
    NSEventTypeBeginGesture = 19,
    NSEventTypeEndGesture = 20
An event of type NSEventTypeGesture is used for a gesture event that is not promoted to its own event type. An event of this type has additional information available in the CGEventRef.
An event of type NSEventTypeBeginGesture and an event of type NSEventTypeEndGesture will be generated by the parser at the start and end of a stream of gestures, somewhat analogous to NSMouseDown and NSMouseUp. Applications can use the NSEventTypeEndGesture to commit a change, for example to do more detailed drawing or to register an undo operation.

An event of type NSEventTypeMagnify, NSEventTypeRotate, NSEventTypeSwipe, NSEventTypeBeginGesture, or NSEventTypeEndGesture will be delivered to the view under the mouse in the key window via the responder methods described below.

You can ask for a particular event type using -nextEventMatchingMask: or -nextEventMatchingMask:untilDate:inMode:dequeue:.


These accessors are valid for all events. When a gesture event is delivered to -[NSApplication sendEvent:] or dequeued via -[NSApplication nextEventMatchingMask:], it does not yet have a window target. At this point, -window is nil and -windowNumber is 0, and -locationInWindow is in screen coordinates. Before dispatching to -[NSWindow sendEvent:], NSApplication sets the window target in the event.
- (NSEventType)type;
- (NSUInteger)modifierFlags;
- (NSTimeInterval)timestamp;
- (NSWindow *)window;
- (NSInteger)windowNumber;
- (NSGraphicsContext*)context;
- (NSPoint)locationInWindow;

There is a new accessor, -magnification, that will return the desired magnification for an NSEventTypeMagnify event as a fraction. A magnification of 1 should be interpreted as increasing the scale factor by 100%, eg. from 100% to 200%, and a negative magnification should decrease the scale factor, with some minimum scale enforced so that you can never get to 0, for example.
- (CGFloat)magnification;
The existing -rotation accessor is valid for NSEventTypeRotate events. The rotation is relative, and is measured in degrees, counterclockwise.

For NSEventTypeSwipe, the -deltaX and -deltaY accessors will return the swipe direction. A non-0 deltaX will represent a horizontal swipe, -1 for swipe right and 1 for swipe left. A non-0 deltaY will represent a vertical swipe, -1 for swipe down and 1 for swipe up.

Key equivalents (New since WWDC 2008)

The fix to prevent NSKeyUp events from being sent to performKeyEquivalent: has been extended to include all applications, not just those built on Leopard or later.

NSTrackingArea (New since WWDC 2008)

There has been a change to the return value of -[NSTrackingArea userInfo]. When the NSTrackingArea is installed by the implementation of -[NSView addTrackingRect:owner:userData:assumeInside:], -[NSTrackingArea userInfo] will return nil rather than the given userData, which is declared to be a pointer and not guaranteed to be an object. The use of NSTrackingArea for this method is an implementation detail, and applications typically get the userData from the mouseEntered: or mouseExited: event. Returning nil from -[NSTrackingArea userInfo] for this case allows implementations of mouseEntered: and mouseExited: to send messages to the userInfo to determine whether the event is meant for a particular object in a class hierarchy. Prior to this change, there was no guarantee that the return of userInfo was a valid object.

When setting the cursor for the current mouse location, for example after scrolling or when making a window key, NSWindow now sends cursorUpdate: through the responder chain. If no responder reponds to cursorUpdate:, a cursorRect added with addCursorRect:cursor: will be used if under the mouse. This change allows cursorUpdate: to coexist with addCursorRect:cursor:, but has binary compatibility implications. In particular, if a view calls invalidateCursorRectForView: from hitTest:, this can lead to a repeating pattern of invalidating cursor rects and hitTesting to set the current cursor. For this reason, the change to use cursorUpdate: is limited to applications linked on SnowLeopard or later.

NSResponder additions for gesture support

The following NSResponder methods have been added. The message will be sent to the view under the mouse in the key window.
- (void)magnifyWithEvent:(NSEvent *)event;
- (void)rotateWithEvent:(NSEvent *)event;
- (void)swipeWithEvent:(NSEvent *)event;
- (void)beginGestureWithEvent:(NSEvent *)event;
- (void)endGestureWithEvent:(NSEvent *)event;

NSEvent (Revised since WWDC 2008 seed)

There are now NSEvent class methods providing access to some system settings. Because these are accessors for system settings, overrides will have no effect.
/* the time in which a second click must occur in order to be considered a doubleClick */
+ (NSTimeInterval)doubleClickInterval;
/* the time for which a key must be held down in order to generate the first key repeat event */
+ (NSTimeInterval)keyRepeatDelay;
/* the time between subsequent key repeat events */
+ (NSTimeInterval)keyRepeatInterval;
There are also NSEvent class methods for getting the modifier flags and mouse button state outside of the event stream.
+ (NSUInteger)modifierFlags;
+ (NSUInteger)pressedMouseButtons;

NSWorkspace (Revised since WWDC 2008 seed)

We added NSWorkspace notifications for display wake and sleep. Few applications are likely to be interested in these notifications, but they may be useful for certain hardware-based drawing decisions, for example in OpenGL.
NSString * const NSWorkspaceScreensDidSleepNotification;
NSString * const NSWorkspaceScreensDidWakeNotification;
We also added an NSWorkspace notification for space switches. This notification is sent after a space switch has occurred.
NSString * const NSWorkspaceActiveSpaceDidChangeNotification;

NSWindow (Revised since February 2009 seed)

You can now ask if a window is on the active space. If the window is offscreen, due to being minimized or hidden for example, -isOnActiveSpace will return YES if ordering the window onscreen will order it on to the active space. - (BOOL)isOnActiveSpace;

There is an NSWindow class method, +windowNumbersWithOptions:, to retrieve window numbers for all onscreen windows. By default, +windowNumbersWithOptions: returns the window numbers for the visible windows belonging to the calling process on the active space. You can also request the window numbers for all visible windows, regardless of owner, and for windows on all spaces.
enum {
    NSWindowNumberListAllApplications = 1 << 0,
    NSWindowNumberListAllSpaces = 1 << 4
};
+ (NSArray *)windowNumbersWithOptions:(NSWindowNumberListOptions)options;
There is also a class method to get the window that would be hit by a mouseDown at a given screenPoint. Pass a non-0 windowNumber to start the search below that window in z-order. Because this method uses the same rules as mouseDown hitTesting, windows with transparency at the given point, and windows that ignore mouseEvents, will not be returned.
+(NSInteger)windowNumberAtPoint:(NSPoint)point belowWindowWithWindowNumber:(NSInteger)windowNumber;
There is new NSWindow API to override the default behavior where a sheet or modal panel disables application termination. - (BOOL)preventsApplicationTerminationWhenModal;
- (void)setPreventsApplicationTerminationWhenModal:(BOOL)flag;
We added a notification, delegate methods, and window accessor for live resize. The notification and corresponding delegate methods are sent when window live resize starts do to a mouseDown in the resize corner, and when it ends due to a mouseUp.
NSString * const NSWindowWillStartLiveResizeNotification;
NSString * const NSWindowDidEndLiveResizeNotification;
The window delegate can implement the desired methods below to get automatically registered for the corresponding notification on the window.
- (void)windowWillStartLiveResize:(NSNotification *)notification;
- (void)windowDidEndLiveResize:(NSNotification *)notification;
While the mouse is down in the resize corner, -inLiveResize will return YES.
- (BOOL)inLiveResize;
You can now call setFrame:display:animate: on a sheet to cause the sheet to resize while remaining correctly positioned on the document window. The document window will move if necessary to show the sheet completely onscreen. The animate flag must be YES to trigger this behavior. This is useful for expanding/collapsing a sheet, as we do for the save and print sheets, for example.
There is now API to disable windowServer moving of a window:
- (void)setMovable:(BOOL)flag;
- (BOOL)isMovable;
By default, windows can be dragged by their titlebar, toolbar, or bottom border, and by content if -isMovableByWindowBackground returns YES. The mouseDown/mouseDragged/mouseUp events that cause window moving are interpreted by the windowServer, and the window is moved in the windowServer process rather than in the application process. So, up until now, applications have not had a good way to disable or customize window moving. Calling setMovable:NO disables windowServer moving. If desired, you can implement application-controlled window moving by handling mouseDown/mouseDragged/mouseUp events in a window subclass. If a window is not movable, its relative screen position is also preserved in spaces F8 mode, but you can still drag the window to a different space in F8 mode.

We've also added a heuristic to trigger a space switch for a client side move of a window. The window must return NO for isMovable, and must have its origin changed while the mouse is down. One thing this heuristic does not address is the ability to pull a non-movable window to another space by clicking in its draggable area and switching spaces. Lastly, there is an attempt to preserve the origin of a non-movable window on display configuration change, but it will be moved if necessary to keep the window onscreen.

NSWindow's firstResponder is KVO-compliant. Note we don't generally guarantee KVO-compliance for NSWindow and NSView properties; you should not assume KVO-compliance unless specifically documented.

NSWindow autodisplay behavior (New since April 2009 seed)

NSWindow autodisplay is now throttled to occur no more frequently than the beam sync interval (about 1/60 second). On Leopard and previous, marking a view as dirty in an autodisplay window would cause window display to occur at the end of the event loop. On SnowLeopard, window display may be deferred until the beam sync time interval has elapsed. This is important for performance, since it avoids blocking the main thread in drawing operations.

NSWindow collection behavior (New since WWDC 2008 seed)

In Leopard, we introduced the concept of window collection behavior.  We added an enumeration to specify that a window could be visible on all spaces or that it would become visible on the current space when ordered front, or that it would get default behavior.  The default behavior is currently dependent on window level.

When a window has NSNormalWindowLevel, it gets these default behaviors:
- the window is visible and selectable in Exposé F9 and F10 modes
- the window is visible during Spaces F8 mode, and is associated with one space at a time.  Dragging the window to a space boundary triggers a space switch
- the window participates in window cycling (cmd-` and ctrl-F4)

When a window has any other window level, it gets these default behaviors:
- the window is hidden in Exposé F9 and F10 modes
- the window is hidden in Spaces F8 mode, and floats across space switches if offscreen during a switch.  Dragging the window to a space boundary does not trigger a space switch
- the window does not participate in window cycling

In order to provide additional application control, we've additional window collection behaviors to be used with -[NSWindow setCollectionBehavior:]
enum {
// participates in spaces, exposé.  Default behavior if windowLevel == NSNormalWindowLevel
 NSWindowCollectionBehaviorManaged = 1 << 2,
// floats in spaces, hidden by exposé.  Default behavior if windowLevel != NSNormalWindowLevel
NSWindowCollectionBehaviorTransient = 1 << 3,
// unaffected by exposé.  Stays visible and stationary, like desktop window
 NSWindowCollectionBehaviorStationary = 1 << 4,
};
enum {
  // default behavior if windowLevel == NSNormalWindowLevel
NSWindowCollectionBehaviorParticipatesInCycle = 1 << 5,
  // default behavior if windowLevel != NSNormalWindowLevel
NSWindowCollectionBehaviorIgnoresCycle = 1 << 6
};

NSWindowCollectionBehaviorManaged
- the window is visible and selectable in Exposé F9 and F10 modes
- the window is visible during Spaces F8 mode, and is associated with one space at a time.  Dragging the window to a space boundary triggers a space switch

NSWindowCollectionBehaviorTransient
- the window is hidden in Exposé F9 and F10 modes
- the window is hidden in Spaces F8 mode, and floats across space switches if offscreen during a switch.  Dragging the window to a space boundary does not trigger a space switch

NSWindowCollectionBehaviorStationary
- the window is unaffected by Exposé.  It stays in its current position and will most likely be covered by the Exposé shield window, just as the desktop is.

NSWindowCollectionBehaviorParticipatesInCycle
- the window participates in window cycling (cmd-` and ctrl-F4)

NSWindowCollectionBehaviorIgnoresCycle
- the window does not participate in window cycling

As in Leopard, -collectionBehavior will return only the behavior explicitly set via -setCollectionBehavior, or NSWindowCollectionBehaviorDefault if no behavior has been set explicitly.

The following examples illustrate how the new constants interact with the window-level-based default behavior.
[window setCollectionBehavior:NSWindowCollectionBehaviorDefault]
    - window will get behavior based on its window level, as described above under "Window collection behavior based on window level"
[window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces]
    - window will be visible on all spaces, and will have behavior based on its window level for exposé and window cycling
[window setCollectionBehavior:NSWindowCollectionBehaviorMoveToActiveSpace]
    - window will become visible on active space when ordered front, and will have behavior based on its window level for exposé and window cycling
[window setCollectionBehavior:NSWindowCollectionBehaviorCanJoinAllSpaces|NSWindowCollectionBehaviorManaged|NSWindowCollectionBehaviorIgnoresCycle]
    - window will be visible on all spaces, will be visible and selectable in exposé, and will not participate in window cycling
[window setCollectionBehavior:NSWindowCollectionBehaviorTransient|NSWindowCollectionBehaviorParticipatesInCycle]
    - will be hidden in spaces and exposé, and will participate in window cycling

NSWindow modal window level in LSUIElement applications (New since January 2009 seed)

Modal windows in LSUIElement applications get special window level treatment, where the window level is NSModalPanelWindowLevel whether or not the owning application is active. Modal windows belonging to regular applications are promoted to NSModalPanelWindowLevel when the application is active, but restored to NSNormalWindowLevel when the owning application is inactive, in order to prevent modal windows from floating above other applications. Since LSUIElement applications follow different activation rules, active status is not required in order to keep the modal window in front of other windows.

NSWindow and NSScreen Color Space support (Modified since WWDC 2009)

NSScreen has an accessor to get the colorSpace of a screen.
@interface NSScreen : NSObject
...
- (NSColorSpace *)colorSpace;
...
@end
There is also a notification sent when the colorSpace of a screen changes, NSScreenColorSpaceDidChangeNotification. The notification object is the screen whose color space has changed.

In applications built on Leopard and previous, a window will inherit the colorSpace of the main screen (that is, the screen containing the menu bar). If a window returns YES for displaysWhenScreenProfileChanges, it will instead inherit that colorSpace of the screen which contains the majority of the window. displaysWhenScreenProfileChanges:YES is the default for windows in applications built on SnowLeopard or later. Either of these inheritance behaviors can be overridden by explicitly setting the color space of the window, which can be desirable to display content with better accuracy.
@interface NSWindow : NSResponder
...
/* -setColorSpace: allows you to specify a colorSpace that matches custom content.   Calling -setColorSpace: with an unsupported colorSpace will raise an exception.
Typically, this would be called immediately after creating the window; changing the colorSpace of a window with backingStore will trigger redisplay
*/
- (void)setColorSpace:(NSColorSpace *)colorSpace;
- (NSColorSpace *)colorSpace;
...
@end

NSWindow Carbon/Cocoa Interaction (New since February 2009 seed)

Cocoa has a notion of a main window distinct from the key window. Historically, we have not supported Cocoa main windows in Carbon apps; a Cocoa window in a Carbon app has been either key or inactive. In SnowLeopard, we added support for Cocoa main windows in Carbon apps. This support is limited to apps linked on SnowLeopard or later since it has binary compatibility implications.

NSWindowDepth constants (New since November seed)

NSWindow has existing API to get/set a window depth limit:
- (void)setDepthLimit:(NSWindowDepth)limit;
- (NSWindowDepth)depthLimit;
We haven't previously published the possible values for NSWindowDepth. The way it's worked historically is that one would call NSBestDepth with parameters specifying characteristics of the window depth, and NSBestDepth would return a value suitable for passing to setDepthLimit:.
NSWindowDepth NSBestDepth (NSString *colorSpace, NSInteger bps, NSInteger bpp, BOOL planar, BOOL *exactMatch);
NSWindow now publishes the supported values for NSWindowDepth.  Note that this is a depth limit, which means that the window may use a lower depth depending on graphics capabilities.enum {
    NSWindowDepth32BitRGB = 0x208,
    NSWindowDepth64BitRGB = 0x210,
    NSWindowDepth128BitRGB = 0x220
};

Displaying dictionary contents (New since WWDC 2008 seed)

We added a facility to display a definition or other dictionary contents for a selection, similar to HIDictionaryWindowShow from Carbon.

Both -showDefinitionForAttributedString:atPoint: and -showDefinitionForAttributedString:range:options:baselineOriginProvider: show a window that displays the definition (or other subject depending on available dictionaries) of the specified attributed string.

showDefinitionForAttributedString:atPoint: takes an attributedString "attrString", and a baseline origin of that string in the receiver view coordinate system "textBaselineOrigin". This method can be used for implementing the same functionality as NSTextView's 'Look Up in Dictionary' contextual menu on a custom view.

-showDefinitionForAttributedString:range:options:baselineOriginProvider: takes an attributedString "attrString", a range in that string (normally the selected range) "targetRange", an options dictionary "options", and an origin provider "originProvider". If there is no selection, the "targetRange" should be zero-length to cause the appropriate range to be auto-detected around the given offset. "options" may be nil, or may contain a dictionary with presentation options. If a small overlay window is selected as default presentation (see NSDefinitionPresentationTypeKey option for details), the overlay text is rendered starting from the origin specified by the originProvider block. The originProvider block should return the baseline origin of the first character at proposed adjustedRange in the receiver view coordinate system. If the receiver is an NSTextView, both attrString and originProvider may be nil, in which case the text view will automatically supply values suitable for displaying definitions for the specified range within its text content.  This method does not cause scrolling, so clients should perform any necessary scrolling before calling this method.
@interface NSView(NSDefinition)
- (void)showDefinitionForAttributedString:(NSAttributedString *)attrString
atPoint:(NSPoint)textBaselineOrigin;
- (void)showDefinitionForAttributedString:(NSAttributedString *)attrString
range:(NSRange)targetRange
options:(NSDictionary *)options
baselineOriginProvider:(NSPoint (^)(NSRange adjustedRange))originProvider;
@end
NSDefinitionPresentationTypeKey is an optional key in '"options" dictionary that specifies the presentation type of the definition display.  The possible values are NSDefinitionPresentationTypeOverlay, which produces a small overlay window at the string location, or NSDefinitionPresentationTypeDictionaryApplication, which invokes the Dictionary application to display the definition.  Without this option, the definition will be shown in either of those presentation forms depending on 'Contextual Menu:' setting in Dictionary application preferences by default.
NSString * const NSDefinitionPresentationTypeKey;
NSString * const NSDefinitionPresentationTypeOverlay;
NSString * const NSDefinitionPresentationTypeDictionaryApplication;

NSApplication termination (New since November seed)

NSApplication now disables the terminate: action while waiting for the delegate to call replyToApplicationShouldTerminate: after returning NSTerminateLater from applicationShouldTerminate:. The purpose of this change is to avoid multiple calls to applicationShouldTerminate: while the application is doing termination-time cleanup. It has a side effect of disabling the Quit menu while waiting for the delegate. This should be desirable behavior, but is limited to applications linked on SnowLeopard or later to avoid preventing termination of applications whose delegates may not be calling replyToApplicationShouldTerminate: properly.

NSHelpManager (New since November seed)

In Leopard and previous releases, NSHelpManager has done automatic registration of help books in the main bundle in its implementations of showHelp:, openHelpAnchor:inBook:, and findString:inBook:.  In SnowLeopard,we have added API so a plugin can register its help book for later use in help lookup.

The following method registers one or more help books in the given bundle.  The main bundle is automatically registered by -openHelpAnchor:inBook: and -findString:inBook:.  You can use -registerBooksInBundle: to register help books in a plugin bundle, for example.  The Info.plist in the bundle should contain a help book directory path, which specifies one or more folders containing help books.  Returns NO if the bundle doesn't contain any help books or if registration fails.  Returns YES on successful registration.
- (BOOL)registerBooksInBundle:(NSBundle *)bundle;

NSDockTile plugin (Modified since WWDC 2009)

An application may customize its dock tile when not running via a plugin whose principal class implements the NSDockTilePlugIn protocol.  The name of the plugin is indicated by a NSDockTilePlugIn key in the application's Info.plist file, and the plugin should have an extension of .docktileplugin.  The plugin is loaded in a system process at login time or when the application tile is added to the Dock.  When the plugin is loaded, the principal class' implementation of -setDockTile: is invoked.  If the principal class implements -dockMenu, -dockMenu is invoked whenever the user causes the application's dock menu to be shown.  When the dock tile is no longer valid (eg. the application has been removed from the dock, -setDockTile: is invoked with a nil NSDockTile.

Note that the plugin needs to have its own copy of the application icon, unless it is completely overriding drawing by setting its own contentView in the dockTile.
@protocol NSDockTilePlugIn <NSObject>
@required
- (void)setDockTile:(NSDockTile*)dockTile;
@optional
- (NSMenu*)dockMenu;
@end

NSViewController-based NSCollectionViewItem (New since WWDC 2008)

In Mac OS 10.6, the superclass of NSCollectionViewItem was changed from NSObject to NSViewController. This was done to improve how the prototype view is replicated. The view replication method used previously in Mac OS 10.5 works for many simple views, but some connections and bindings may not be copied correctly.

With the new NSViewController-based NSCollectionViewItem, this limitation can be overcome by initializing the prototype NSCollectionViewItem with a nib name and bundle, from which the view can reliably replicated.

Converting your NSCollectionViewItem prototypes to using nibs is usually very simple. First, create a new empty nib in Interface Builder. Next, copy your prototype view into the new nib. Change the class of the File's Owner of the new nib to NSCollectionViewItem and connect the view to its 'view' outlet. In the new nib, reconnect any bindings from your view to the NSCollectionViewItem. Save the new nib. In your original nib, delete the prototype view and enter the name of your new nib (and the bundle identifier, if required—leaving it blank will search the main bundle) in the prototype NSCollectionViewItem's inspector and save the nib.

The new NSCollectionViewItem is completely compatible with existing ones. Using a nib-based prototype view is optional and NSCollectionViewItems archived in 10.5 will still be readable in 10.6.


NSCollectionView Drag and Drop (New since WWDC 2008)

In Mac OS 10.6, NSCollectionView has a new drag and drop API similar to the existing APIs for NSTableView, NSBrowser, etc. For an NSCollectionView to be a dragging source, it must have a delegate that implements and returns YES from collectionView:canDragItemsAtIndexes:withEvent: and collectionView:writeItemsAtIndexes:toPasteboard:. For an NSCollectionView to be a dragging destination, it must have a delegate that implements collectionView:validateDrop:proposedIndex:dropOperation: and collectionView:acceptDrop:index:dropOperation:. For more detail, see the comments in NSCollectionView.h.

Two methods have been added to NSCollectionView, which may be necessary within your drag and drop delegate method implementations. The first is itemAtIndex:, which returns the NSCollectionViewItem associated with the represented object at the given index. This is especially useful if you need to get a reference to specific subviews of the NSCollectionView. The second is frameForItemAtIndex:, which returns the frame that the receiver has calculated for the subview at the given index. You should always use this method instead of calling [[[collectionView itemAtIndex:index] view] frame]. Doing this would force the view to be created prematurely, if the collection view is trying to lazily load its items. This method is especially useful in the collectionView:draggingImageForItemsAtIndexes:withEvent:offset: delegate method to determine which views are in the visible area of the collection view.


NSCollectionView bug fixes (New since WWDC 2008)

Signficant bugs in NSCollectionView were fixed in Mac OS 10.6

When an NSCollectionView is resized, it will no longer cause its enclosing scroll view to scroll to the top.

Strange glitches in NSCollectionView's animations are fixed. Subviews will no longer jump unexpectedly, and will not stutter when their positions are animated. NSCollectionView will also work better together with NSScrollViews that autohide scrollers.

For NSCollectionViews that do not use the new nib-based prototype views, the view copying mechanism was made more reliable. In Mac OS 10.5, the views could potentially be copied before all their bindings or other connections had been loaded from the nib.

NSCollectionView will now correctly trigger KVO notifications for selectionIndexes when the selection is changed by mouse events.

NSCollectionView now ensures that its subviews are correctly positioned on pixel boundaries to avoid blurring or gaps between subviews.


NSSplitView appearance changes (New since WWDC 2008)

In Mac OS 10.5, the default value of -[NSSplitView dividerColor] for thin dividers was a gray color, regardless of the window's style. This created a usually undesirable appearance when drawn on textured windows. In applications linked on or after Mac OS 10.6, -dividerColor will now return [NSColor clearColor] by default for split views with thin dividers on textured windows.

Also, NSSplitView has stopped drawing different versions of the divider dimple. From now on, it will only draw the dimmed version, regardless of the containing window's key state.Formal Protocol Adoption (New since WWDC 2008)

In Mac OS 10.6, AppKit switched to using formal protocols for all delegates and data sources to provide better compile-time type checking. Required protocol methods are marked with @required, where possible. The rest are marked with @optional.

The affected classes are NSAlert, NSAnimation, NSApplication, NSBrowser, NSComboBox, NSComboBoxCell, NSControl, NSDatePicker, NSDatePickerCell, NSDrawer, NSImage, NSLayoutManager, NSMatrix, NSMenu, NSOutlineView, NSPathCell, NSPathControl, NSRuleEditor, NSSavePanel, NSSound, NSSpeechRecognizer, NSSpeechSynthesizer, NSSplitView, NSTableView, NSTabView, NSText, NSTextField, NSTextStorage, NSTextView, NSTokenField, NSTokenFieldCell, NSToolbar, and NSWindow

The changes will introduce new warnings in code using these classes' delegates. Fortunately, the changes needed to correct these warnings are fairly simple.

• Your delegate classes need to declare conformance to the new protocols. For example:
@interface MyDelegate : NSObject <NSApplicationDelegate> ... @end
• Sending messages to [foo delegate] or [foo dataSource] that are not in the delegate's protocol will generate a warning. This is not generally recommended since there are no guarantees about the delegate's class. However, you may work around this by casting the result of [foo delegate] or [foo dataSource] to id. Also, you should always perform a respondsToSelector: check before invoking a method on [foo delegate] or [foo dataSource] that is not an @required method in the protocol.

• If you have a subclass of one of these classes that adds additional delegate methods you must also create a subprotocol and override -delegate and -setDelegate:. For example:
@protocol MySplitViewDelegate;
@interface MySplitView : NSSplitView
- (id <MySplitViewDelegate)delegate;
- (void)setDelegate:(id <MySplitViewDelegate>)delegate;
@end
@protocol MySplitViewDelegate <NSStreamDelegate>
- (void)additionalDelegateMethod;
@end
@implementation MySplitView
- (id <MySplitViewDelegate)delegate {
    return (id <MySplitViewDelegate>)[super delegate];
}
- (void)setDelegate:(id <MySplitViewDelegate>)delegate {
    [super setDelegate:delegate];
}
@end
• If you need to target Leopard or Tiger with the same sources, you should conditionally declare empty protocols, or else the compiler will complain about missing protocols declarations. For example:
#if MAC_OS_X_VERSION_10_6 > MAC_OS_X_VERSION_MAX_ALLOWED
@protocol NSTableViewDelegate <NSObject> @end
#endif

New NSSplitView delegate method (New since January 2009 seed)

To make it easier for your application to maintain the size of given subviews of a split view while the split view is being resized, NSSplitView in Mac OS 10.6 has a new -splitView:shouldAdjustSizeOfSubview: delegate method you can implement. It controls how -adjustSubviews behaves so you don't have to rewrite so much of its default behavior in a -splitView:resizeSubviewsWithOldSize: delegate method.

By returning NO from this method, you can lock the size of a split view subview while the split view is resized. However, if the split view shrinks beyond the point that all of the resizable subviews are completely hidden, the subviews you returned NO for will start resizing as well to prevent -adjustSubviews from creating an invalid subview layout.

New NSSplitView pane splitter divider style

In Mac OS 10.6, NSSplitView has a new divider style called NSSplitViewPaneSplitterDividerStyle. This new style is significantly different than the "thick" style because it draws an opaque gradient along the entire length of the dividers and its width is slightly smaller. This style matches the appearance of the split view dividers in many of Apple-created applications.

Snow Leopard's Human Interface Guidelines strongly encourage you to migrate away from the "thick" style to this new style. Because of this, when you create a new NSSplitView instance in Interface Builder you will only be able to choose between the "thin" and "pane splitter" divider styles.

NSSplitView's paneSplitter and setPaneSplitter: methods are deprecated in Mac OS 10.6 in favor of the new divider style.



NSCell controlView property changes

The declarations for controlView and setControlView: are on NSCell, but until SnowLeopard the storage for the controlView property was at the NSActionCell level. -[NSCell controlView] always returned nil and -[NSCell setControlView:] did nothing. This caused a variety of unexpected behaviors.

For applications linked on or after SnowLeopard, the storage for this property is at the NSCell level, and the NSCell accessors behave as you might expect. The fix is limited to apps linked on or after SnowLeopard. This is because NSCell does not retain its controlView, so there are new opportunities for dangling pointers. If your app keeps a static NSCell instance that you use for drawing in many different contexts, for example, you may need to be careful to clear out the controlView between uses. This requirement was already in place for NSActionCell, so this is only an issue if you use something that doesn't descend from that class.

Also, prior to SnowLeopard, NSActionCell propagated its controlView to its copy in copyWithZone:. This is not correct and causes problems. The controlView is a transient property set just before a cell is drawn. As methods are invoked on the cell in the course of copying it, the original cell's control typically ends up dirtied and redrawn. Since a cell does not retain its controlView, this causes crashes if the original control view is deallocated.

For applications linked against the SnowLeopard SDK or later, the controlView is not propagated.

NSImageCell disabled images

In Leopard and previous, there is no out of the box view that displays an image that dims out when it is disabled. One can try to fake this with a button, but then the view accepts key focus when full keyboard access is enabled, has accessibility problems, darkens when pressed, etc.

One might expect NSImageView to do this, but NSImageView instead shows that it is disabled by drawing its frame differently. There are cases where you want this: When the image view is set up as an image well, the image may be user data that you are just presenting. It's odd to dim it out, especially when it suffices to dim the image well.

However, it seems unambiguous that if an image view has no frame, it is correct to show disabled by dimming the image.

This is the behavior for applications linked on or after SnowLeopard. The linkage check is here because some applications do disable image views without intending grayed out drawing. This could easily arise from experimenting with checkboxes in Interface Builder.

NSButton (New since April seed)

The disclosure triangle style of NSButton is now able to invert to white on dark backgrounds and such, by interpreting the backgroundStyle property of the cell.

A caveat is that unfortunately our art for the raised background style is not as widely suitable as would be nice. It's really drawn for a source list style table, and doesn't look good very on the window surface. This control isn't suitable directly on the window surface for now. We're sorry. To avoid making existing apps look worse in this case, we only interpret the background styles for apps that have linked on or after 10.6, though the 10.5-ish non-engraved art doesn't look very good here either.

NSImage, CGImage, and CoreGraphics impedance matching (Updated since WWDC 2008)

NSImage has changed substantially internally for SnowLeopard in ways that developers might want to be aware of. There is also some new API. AppKit imaging is now more closely aligned with CoreGraphics.

The basic change is to move to consistent use of CGImage internally. For example, in Leopard and previous, -[NSImage lockFocus] drew into a view in an offscreen window. Now it draws into a buffer, and a CGImage is extracted from the buffer in +unlockFocus. NSImage no longer uses windows at all in its implementation. We've entirely deprecated NSCachedImageRep, which is the NSImageRep subclass that represents drawing backed by a window. NSCachedImageRep does still work, but AppKit never instantiates it internally.

This has the potential to break clients. On Leopard and previous, +[NSView focusView] returned a view from within +[NSImage lockFocus]. Hopefully you were unaware of this! Now it returns nil. If you were looking at [[NSView focusView] isFlipped], you may wish to look at [[NSGraphicsContext currentContext] isFlipped] instead. The two coincide whenever focus is actually locked on a view.

Another issue we've seen is with clients calling -lockFocus on an image, then drawing the image elsewhere before calling -unlockFocus. This no longer works. The NSImage itself is not modified until -unlockFocus is called, as described above.

NSImage in Leopard and previous rounded destination rectangles to integral values in user-space, which was not so good for resolution independence, and not good for people who genuinely wanted images placed where they were put, with antialiasing. This rounding is out, but may mean that some images look blurry.

We've added a method of extracting CGImages from an NSImage, -[NSImage CGImageForProposedRect:context:hints:]. Why all the parameters? Well, an NSImage is potentially resolution independent, and may have multiple representations suited for different contexts.  For example, an NSImage may have a hand drawn 16x16 bitmap as well as a 512x512 bitmap. This allows the image to display well at large and very small sizes. A CGImage is more like a single pixel-based representation.   Think of -CGImageForProposedRect:context:hints: as producing a snapshot of how the NSImage would draw if it was asked to draw in *proposedDestRect in the passed context.

A snapshot is a good way to think of it, but may lead you to think the method is less efficient than it really is. There's nothing guaranteed about the characteristics of the returned CGImage (e.g., pixel size, colorspace) except that drawing it in the passed context produces the same results as drawing the original NSImage in the context. In particular, if an NSImage is backed by a single NSBitmapImageRep, then it will (probably) always return the one CGImage that backs the bitmap. That's a valid snapshot for the image for any destination rect, because in this case the CGImage _does_ capture all the drawing the NSImage is capable of.

The rect, context and hints are first used to select the best representation for the described destination using new API -[NSImage bestRepresentationForRect:context:hints:], then the image rep is asked for a CGImage using -[NSImageRep CGImageRepForProposedRect:context:hints:]. NSImage may cache the CGImage, same as it may cache for normal drawing and controlled in the same way, and the CGImage is returned.

The NSImageRep level method is intended as an override point for image rep subclasses that naturally have a CGImage available. For example, NSBitmapImageRep overrides it to return the CGImage that naturally backs the rep. You don't need to override the method except possibly for performance, though. The NSImageRep-level implementation will produce a CGImage by making a buffer and calling -[self draw]. That's likely to be the best possible implementation for reps that aren't naturally CGImage backed. -draw remains the only method of NSImageRep that a subclasser really needs to override.

One subtlety: The 'proposedRect' parameter passes a pointer to an NSRect. This is because a CGImage is necessarily pixel-integral, while an NSImage is not. In order to produce a CGImage for rect (0.5, 0.5, 4.0, 4.0) without distortion or double-antialiasing, we may have to produce a 5x5 CGImage, and also inflate the proposedRect. Drawing the CGImage in the out-value in proposed rect is the same as drawing the NSImage in the in-value of proposed rect.

For example, this block of code
- (void)drawRect {
NSRect dstRect = NSMakeRect(0.5, 0.5, 4.0, 4.0);
CGImageRef cgImage = [pdfBackedImage CGImageForProposedRect:&dstRect context:[NSGraphicsContext currentContext] hints:nil];
// dstRect might be something like {{0.0, 0.0}, {5.0, 5.0}} on return
CGContextDraw([[NSGraphicsContext currentContext] graphicsPort], NSRectToCGRect(dstRect), cgImage);
}
should produce drawing equivalent to (or at least very close to) this code:
- (void)drawRect {
NSRect dstRect = NSMakeRect(0.5, 0.5, 4.0, 4.0);
[pdfBackedImage drawInRect:dstRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0];
}
The latter code is better, though. Producing a snapshot CGImage may be more expensive than just drawing the NSImage (though we'll use an existing CGImage whenever possible), so prefer to just draw with -[NSImage drawInRect:fromRect:operation:fraction:] or related methods unless you truly require a CGImage.

There is also a method for conveniently and efficiently producing an NSImage from a CGImage, -[NSImage initWithCGImage:size:].

NSImage Behavior: Simplifying caching and related interfaces (New since WWDC 2008)

In Leopard and previous, NSImage has several methods that influence caching and related behavior, sometimes with important effects on how the image draws.  These important effects have sometimes been a source of confusion for clients.  For SnowLeopard, the intent is that caching should be handled more transparently, and that caching should affect only performance, not the basic meaning of how an image draws.

To support this, the following methods are deprecated without replacement:
    - (void)setCachedSeparately:(BOOL)flag;
    - (BOOL)isCachedSeparately;
    - (void)setCacheDepthMatchesImageDepth:(BOOL)flag;
    - (BOOL)cacheDepthMatchesImageDepth;
    - (void)setScalesWhenResized:(BOOL)flag;
    - (BOOL)scalesWhenResized;
    - (void)setDataRetained:(BOOL)flag;
    - (BOOL)isDataRetained;
Any call to set one of these properties can be removed.  Briefly:
isCachedSeparately:
    This controlled whether an image shared a cache window with other instances of NSImage.  NSImage no longer caches to windows.
cacheDepthMatchesImageDepth:
    This controlled the bit depth used in making cache windows.  NSImage no longer caches to windows.  A cache is now generated appropriate for the destination where an image is drawn, and it doesn't apply if the image is drawn into a context that doesn't match in some way that would have led to a different cache being created.
scalesWhenResized:
    One might think -scalesWhenResized would be a semantic property rather than a caching flag, but it really had to do with whether caches were invalidated when -[NSImage setSize:] was called.  The size of an image is no longer relevant for caching purposes - only the size of the rect where the image is drawn is important.  In SnowLeopard, NSImage caching should never have any obviously observable user effect like an image being drawn into a different size region of the screen.  Caching is about performance.

    The complete behavior when the property was set to NO was complex, but it did not reliably achieve keeping the image from scaling.  It did make the scaled image draw blocky, sometimes.
isDataRetained:
    When this was NO, which it was by default, an image was permitted to throw out its backing data when drawn and keep something only appropriate for the context it which it was first used.  For example, a PDF-backed image would typically be rasterized when first drawn, and the PDF data would be irrecoverably discarded.  In SnowLeopard, NSImage no longer throws out data in such a way that the original can no longer be reconstructed.

Please note that -[NSImage setCacheMode:] is not deprecated.  In particular, you can use NSImageCacheNever to disable all use of caches in NSImage.  Disabling caching may be an optimization if the image is known to be temporary, or if there is caching taking place elsewhere that would make a cache at this level wasted memory.

NSImage: deprecating -[NSImage setFlipped:], adding a drawing method that respects context flippedness (New since WWDC 2008)

The flipped attribute of NSImage is widely misunderstood.  We are deprecating it for SnowLeopard, and replacing its typical uses with less error-prone API.

The property describes the orientation of the internal coordinate system of the NSImage.  Just as a superview never cares about the flippedness of its subviews, a user of an NSImage should not care about its flippedness.

The typical (flawed) use case is to try to call [image setFlipped:[[NSGraphicsContext currentContext] isFlipped]] just prior to drawing, but this does not accomplish the intended goal.  If called before caching, then representations end up caching upside down, and the flip is absorbed into the cache.  If called after caching, it has no effect-the cached representation is already supposed to incorporate any necessary flipping.  In the former case, if the NSImage is drawn anywhere else later, it ends up upside down in _that_ place, which is also confusing because the bug and the expression of the bug are far apart.  Lack of understanding regarding flippedness is also frequently the source of poorly performing code, in which people make unnecessary intermediate buffers to work around perceived framework bugs.  The framework behaves according to design, but contrary to expectation, and the semantics are not all that useful. It's also difficult to change the semantics of -[NSImage isFlipped], because a lot of code is very closely dependent on the current behavior. Rather than attempt this, we have deprecated the property.

We are providing a simple and correct way to draw images in a flipped or unflipped context, which is a draw method that can account for context flippedness.  We are also adding a hints parameter matching the hints in -bestRepresentationForRect:context:hints:.
- (void)drawInRect:(NSRect)dstRect
fromRect:(NSRect)srcRect
operation:(NSCompositingOperation)op
fraction:(CGFloat)alpha
respectFlipped:(BOOL)respectContextIsFlipped
hints:(NSDictionary *)hints;
Pass YES for respectFlipped to get the fancy new behavior. One note for those that understand the CTM and worry that this method has an odd interaction, where modifying the CTM could fail to have any effect on image drawing: This is not the case. This method branches behavior based on [[NSGraphicsContext currentContext] isFlipped]. Modifying the CTM might turn your axes upside down, but it will not alter the result of -[NSGraphicsContext isFlipped]. They're completely orthogonal.

A second valid use of -[NSImage setFlipped:] was to specify the flippedness of the context obtained via -[NSImage lockFocus].  There are cases, for example drawing directly via NSLayoutManager, that require a flipped context.  To cover this case, we add
- (void)lockFocusFlipped:(BOOL)flipped;
This doesn't alter the state of the image itself, only the context on which focus is locked. It means that (0,0) is at the top left and positive along the Y-axis is down in the locked context.

NSImage: Breaking change to drawAtPoint:fromRect:operation:fraction: (New since WWDC 2008)

-[NSImage drawAtPoint:fromRect:operation:fraction:] has different behavior for applications linked on or after SnowLeopard than it did previously. We corrected a bug that has substantial impact on behavior, but it's weird enough, and easy enough to work around, that we think we can get away with fixing it. The natural thing to do if you ever encountered this bug was to switch to doing something else, not to depend on it.

Prior to SnowLeopard, -drawAtPoint:fromRect:... called -drawInRect:fromRect:... passing [image size] as the size of the destination rect. If 'image' was 100x10, then the snippet
    [image drawAtPoint:NSZeroPoint fromRect:NSMakeRect(0,0,10,10) operation:NSCompositeSourceOver fraction:1.0];
was equivalent to
    [image drawInRect:NSMakeRect(0,0,10,100) fromRect:NSMakeRect(0,0,10,10) operation:NSCompositeSourceOver fraction:1.0];
which makes little sense. This doesn't even preserve the aspect ratio of the source rect. In applications linked on SnowLeopard, the snippet is instead equivalent to
    [image drawInRect:NSMakeRect(0,0,10,10) fromRect:NSMakeRect(0,0,10,10) operation:NSCompositeSourceOver fraction:1.0];
This obviously may require changes when you recompile your code, so search your source for drawAtPoint. The change has no effect on applications that pass {{0,0}, [image size]} for the source rect, which is what most applications do. As with the other drawing methods that take source rects, NSZeroRect is treated as sentinel meaning 'the whole image'.

If you were passing a partial source rect on Leopard and earlier, and you need compatibility on Leopard and SnowLeopard, then replace your usage of -drawAtPoint:fromRect:operation:fraction: with -drawInRect:fromRect:operation:fraction:.

NSImage: Deprecating old drawing methods (New since WWDC 2008)

NSImage has a suite of drawing methods that start with "draw" and a suite of drawing methods that start with "dissolve" or "composite".
- (void)dissolveToPoint:(NSPoint)point fraction:(CGFloat)aFloat;
- (void)dissolveToPoint:(NSPoint)point fromRect:(NSRect)rect fraction:(CGFloat)aFloat;
- (void)compositeToPoint:(NSPoint)point operation:(NSCompositingOperation)op;
- (void)compositeToPoint:(NSPoint)point fromRect:(NSRect)rect operation:(NSCompositingOperation)op;
- (void)compositeToPoint:(NSPoint)point operation:(NSCompositingOperation)op fraction:(CGFloat)alpha;
- (void)compositeToPoint:(NSPoint)point fromRect:(NSRect)rect operation:(NSCompositingOperation)op fraction:(CGFloat)alpha;
The "draw" methods are newer, and are generally what you want to be using.

The "composite" methods have surprising semantics. They set the current transformation matrix of the graphics context to be the identity matrix (or more accurately, the identity scaled up by the default user space scale factor – think default window scaling with resolution independence) before drawing. That is, in a scaled or rotated view, composite methods draw as if the view is not scaled or rotated.

This isn't usually what one is really after. Often people use these methods because they seem to produce right-side-up drawing in flipped views. If that's what you're after, use the new method -[NSImage drawInRect:fromRect:operation:fraction:respectContextFlipped:hints:] passing YES for respectContextFlipped.

We are not currently providing a direct replacement, but if you do have a case that uses the composite methods for their intended purpose, you can reproduce the result by manipulating the graphics context before drawing.

NSImage: Deprecating -lockFocusOnRepresentation: (New since WWDC 2008)

The NSImage method:
- (void)lockFocusOnRepresentation:(NSImageRep *)imageRepresentation;
is deprecated because it is commonly misunderstood and easy to replicate. It does not set up the rep as a drawing destination, it sets the image up as a drawing destination, then draws the rep into it. You can replace usage with
[image lockFocus];
[rep drawInRect:NSMakeRect(0,0,[image size].width, [image size].height)];

NSImageRep: More flexible drawing (New since WWDC 2008)

This addition to NSImageRep provides drawing flexibility equivalent to NSImage's. Prior to SnowLeopard, one needed to wrap a rep up with an NSImage to draw with any operation other than NSCompositeCopy, for example. That's a pain since it's far more common to draw with NSCompositeSourceOver.
- (BOOL)drawInRect:(NSRect)dstRect
fromRect:(NSRect)srcRect
operation:(NSCompositingOperation)op
fraction:(CGFloat)alpha
respectFlipped:(BOOL)respectContextIsFlipped
hints:(NSDictionary *)hints;

NSImage: Hit testing for non-transparent regions (New since WWDC 2008)

NSImage has gained a method that tests whether clicks and drags hit an opaque part of an image.
- (BOOL)hitTestRect:(NSRect)testRectDestSpace
withImageDestinationRect:(NSRect)imageRectDestSpace
context:(NSGraphicsContext *)context
hints:(NSDictionary *)hints
flipped:(BOOL)flipped;
More precisely, this method answers the question, "If you were to draw the image in the passed destination rect in the passed context respecting the passed flippedness with the passed hints, would the test rect in the context intersect a non-transparent portion of the image?". The information about the drawing destination is necessary because an NSImage draws differently depending on where it's going. Consider a typical Mac OS X icon that has a 16x16, 32x32 and 256x256 pixel representations. The choice of representation to draw depends on the destination, so accurate hit testing also needs destination information.

However, the context and hints parameters can be omitted, and we'll assume the context is set up like a window context with default scaling. This is the same as in -[NSImage bestRepresentationForRect:context:hints:] and the other NSImage methods that take similar parameters. If you don't have an NSGraphicsContext handy but you know that when the image draws it is into a context that differs from the window's context in some respects, you can use the hints to describe that context.

The flipped parameter is called out separately rather than supplied as a hint because it's a critical parameter. It determines the orientation with which the image draws in the destination rect, and therefore which portion of the image you are hit testing. If you are passing a non-nil context, you probably want to pass [context isFlipped]. If you don't have a context handy, but you're are calling this from within a view and hit testing an image that you draw in drawRect:, then you should probably pass [view isFlipped] and the rect where you draw the image for imageRectDestSpace.

There is one special case behavior. If the test rect has {0,0} size, then this method instead tests whether the origin point hits something non-transparent in the image. You could think of this as testing a rect with infinitesimal size.

NSImage: New standard images (New since November seed)

We added a passel of new names for use with +[NSImage imageNamed:]. Search for AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER near the bottom of NSImage.h, or look at the "Media" tab in Interface Builder's library panel.

NSImage: Orientation metadata (e.g. exif) now respected by default (New since November seed)

Some image file formats, such as JPEG, contain metadata that describes the 'orientation' of the data backing the image.  A camera may tag its image data as rotated by 90 degrees counterclockwise relative to what the user should see.

NSImage has never interpreted this metadata.  For apps linked on or after SnowLeopard, we do.  Preview and ImageKit interpreted this information on 10.5.  WebKit currently does not.  ImageIO, the fundamental image reading framework, reports the information but does not account for it.

We interpret the data in a way that is transparent to clients.  Bitmap data, pixel size, and all other properties are reported with respect to the image after orientation correction.

This is a major behavior change in some ways, but we do not expect it to impact very much code in practice.  Still, there are some developers who will need to conditionally opt-out for compatibility.  We introduce a new piece of API on NSImage to support them.  This is a backward-looking method for opting out of the new behavior.
    - (id)initWithDataIgnoringOrientation:(NSData *)data;
Who needs this?  Consider a document format that references images.  If a document is saved on Leopard, it's usually correct for it to look as it did on Leopard when opened on SnowLeopard.  In a drawing program that includes images, the user may have manually rotated an image to compensate for ignored orientation information. The image would end up double rotated if the app began to interpret the embedded orientation.  See the end of this section for an example of how to handle this kind of compatibility constraint.

It's not all that common to need to change code, though. In Mac OS X, only AppKit needed to react to the change.  The difference is relevant to image loading, not to working with images, and is only relevant for images which are user data as opposed to embedded in a framework.  Images written out by, say, TIFFRepresentation or by archiving an NSImage are always in a normalized orientation, so no changes necessary when reading them.  Most apps _want_ to interpret image orientation data.  A big exception is existing documents that directly reference image files that came from the user untouched.

-[NSImage initWithDataIgnoringOrientation:] is really a convenience method.  Another way to ignore image orientation is to use ImageIO's CGImageSource to make a CGImage, and then -[NSImage initWithCGImage:size:] to represent it as an NSImage.  ImageIO reports orientation metadata, but does not automatically interpret it.

We also provide a global opt-out. If you set the user default NSBitmapImageRepRespectOrientation to NO, NSImage will behave the old way all of the time.  This is an option of last resort for developers who cannot update affected code used by their app for some reason.

Here's an example of the work that might be required when moving an app up to the 10.6 SDK:

AppKit itself reads and writes the RTFD format.  Here's what we had to do:  First, each image attachment in memory now has an internal 'noOrient' bit, and we added a /noorient tag in the on-disk file format.  If noOrient is set, then when the corresponding image is loaded from disk, it's loaded with -[NSImage initWithDataIgnoringOrientation:].  Each RTFD document on disk also has a global version tag.  For old versions, every image attachment is implicitly noOrient.  When a new image is added to a document in memory, the bit is not set.  Finally, when we save an RTFD in our current file format version, we write out the /noorient tag for any image attachment on which it is set.

NSImage: CALayer accepts NSImage as contents (New since March seed)

You may now call -[CALayer setContents:] with an NSImage as the contents object.  Previously you needed a CGImage.

There is one subtlety. CoreAnimation is built to work with a raster object, a bitmap.

If your image comes from a bitmap file like a TIFF then there is no issue, but a PDF, for example, will be rasterized.  The layer will not scale like a PDF. It will scale like a bitmap.   If the default way we produce the raster form doesn't meet your needs, you can exert more control using -[NSImage CGImageForRect:context:hints:].  This will produce a CGImage that you can set as the contents of the layer.

CALayer will also perform caching.  You should not modify your NSImage after setting it as the contents of a layer.  When or if your changes show up would be arbitrary.  This issue not specific to CALayer;  it is never a good idea to modify an NSImage unless you just created it and the modifications are part of the initial setup of the image.  If an NSImage has escaped to code you don't own, or an NSImage has been handed to you by code you don't own, you should not modify it.

Note: Even before this change, you could not call -[CALayer contents] and assume that the result was a CGImage.  The method is typed id, and the object returned could be one of several different private types in 10.5.

NSImage: Clarifying the contract for threading (New since March seed)

NSImage, NSImageRep, and all of its subclasses have the same threading contract as NSMutableDictionary, NSMutableArray, NSMutableString and company.

If you aren't calling mutating methods, an image can be safely used from arbitrary threads.

If you _are_ mutating an image, you need to guarantee that the image is not being accessed on any other threads while the mutation is occurring, or risk crashes. You need to have full knowledge of what references the image and be able to prevent, say, drawing on any other thread.

In practice, this often means that you may only modify an image as part of its initial setup, before it has escaped to the app at large. Copying an image and modifying the copy is valid and occasionally necessary. We try hard to make copies cheap. The backing data is shared whenever possible (without impairing thread safety).

By "mutating method" we mean those methods that do explicit mutation, like -setSize: or -addRepresentation:. We do _not_ mean methods like -drawInRect:fromRect:operation:fraction: that may modify the image's ivars as a side effect of caching and lazy faulting and such.  If an image has internal caching or laziness, it will be handled in a way that does not impair thread safety. Locking focus on an image and drawing in it is a mutation, however, as is modifying the bitmapData of an NSBitmapImageRep.

There's one notable exception to the above rule: Even though it's a mutation, you may call -[NSBitmapImageRep incrementalLoadFromData:complete:] while other threads are accessing the image.

Subclassers of NSImageRep take note: You need to adhere to this contract as well. Expect non-mutating methods to be called on arbitrary threads.

NSBitmapImageRep: CoreGraphics impedance matching and performance notes (New since WWDC 2008)

Release notes above detail core changes at the NSImage level for SnowLeopard. There are also substantial changes at the NSBitmapImageRep level, also for performance and to improve impedance matching with CoreGraphics.

NSImage is a fairly abstract representation of an image. It's pretty much just a thing-that-can-draw, though it's less abstract than NSView in that it should not behave differently based aspects of the context it's drawn into except for quality decisions. That's kind of an opaque statement, but it can be illustrated with an example: If you draw a button into a 100x22 region vs a 22x22 region, you can expect the button to stretch its middle but not its end caps. An image should not behave that way (and if you try it, you'll probably break!). An image should always linearly and uniformly scale to fill the rect in which its drawn, though it may choose representations and such to optimize quality for that region. Similarly, all the image representations in an NSImage should represent the same drawing. Don't pack some totally different image in as a rep.

That digression past us, an NSBitmapImageRep is a much more concrete object. An NSImage does not have pixels, an NSBitmapImageRep does. An NSBitmapImageRep is a chunk of data together with pixel format information and colorspace information that allows us to interpret the data as a rectangular array of color values.

That's the same, pretty much, as a CGImage. In SnowLeopard an NSBitmapImageRep is natively backed by a CGImageRef, as opposed to directly a chunk of data. The CGImageRef really has the chunk of data. While in Leopard an NSBitmapImageRep instantiated from a CGImage would unpack and possibly process the data (which happens when reading from a bitmap file format), in SnowLeopard we try hard to just hang onto the original CGImage.

This has some performance consequences. Most are good! You should see less encoding and decoding of bitmap data as CGImages. If you initialize a NSImage from a JPEG file, then draw it in a PDF, you should get a PDF of the same file size as the original JPEG. In Leopard you'd see a PDF the size of the decompressed image. To take another example, CoreGraphics caches, including uploads to the graphics card, are tied to CGImage instances, so the more the same instance can be used the better.

However: To some extent, the operations that are fast with NSBitmapImageRep have changed. CGImages are not mutable, NSBitmapImageRep is. If you modify an NSBitmapImageRep, internally it will likely have to copy the data out of a CGImage, incorporate your changes, and repack it as a new CGImage. So, basically, drawing NSBitmapImageRep is fast, looking at or modifying its pixel data is not. This was true in Leopard, but it's more true now.

The above steps do happen lazily: If you do something that causes NSBitmapImageRep to copy data out of its backing CGImageRef (like call bitmapData), the bitmap will not repack the data as a CGImageRef until it is drawn or until it needs a CGImage for some other reason. So, certainly accessing the data is not the end of the world, and is the right thing to do in some circumstances, but in general you should be thinking about drawing instead. If you think you want to work with pixels, take a look at CoreImage instead - that's the API in our system that is truly intended for pixel processing.

This coincides with safety. A problem we've seen with our SnowLeopard changes is that apps are rather fond of hardcoding bitmap formats. An NSBitmapImageRep could be 8, 32, or 128 bits per pixel, it could be floating point or not, it could be premultiplied or not, it might or might not have an alpha channel, etc. These aspects are specified with bitmap properties, like -bitmapFormat. Unfortunately, if someone wants to extract the bitmapData from an NSBitmapImageRep instance, they typically just call bitmapData, treat the data as (say) premultiplied 32 bit per pixel RGBA, and if it seems to work, call it a day.

Now that NSBitmapImageRep is not processing data as much as it used to, random bitmap image reps you may get ahold of may have different formats than they used to. Some of those hardcoded formats might be wrong.

The solution is _not_ to try to handle the complete range of formats that NSBitmapImageRep's data might be in, that's way too hard. Instead, draw the bitmap into something whose format you _know_, then look at that.

That looks like this:
NSBItmapImageRep *bitmapIGotFromAPIThatDidNotSpecifyFormat;
NSBitmapImageRep *bitmapWhoseFormatIKnow = [[NSBitmapImageRep alloc] initWithBitmapDataPlanes:NULL pixelsWide:width pixelsHigh:height
bitsPerSample:bps samplesPerPixel:spp hasAlpha:alpha isPlanar:isPlanar
colorSpaceName:colorSpaceName bitmapFormat:bitmapFormat bytesPerRow:rowBytes
bitsPerPixel:pixelBits];
[NSGraphicsContext saveGraphicsState];
[NSGraphicsContext setContext:[NSGraphicsContext graphicsContextWithBitmapImageRep:bitmapWhoseFormatIKnow]];
[bitmapIGotFromAPIThatDidNotSpecifyFormat draw];
[NSGraphicsContext restoreGraphicsState];
unsigned char *bitmapDataIUnderstand = [bitmapWhoseFormatIKnow bitmapData];
This produces no more copies of the data than just accessing bitmapData of bitmapIGotFromAPIThatDidNotSpecifyFormat, since that data would need to be copied out of a backing CGImage anyway. Also note that this doesn't depend on the source drawing being a bitmap. This is a way to get pixels in a known format for any drawing, or just to get a bitmap. This is a much better way to get a bitmap than calling -TIFFRepresentation, for example. It's also better than locking focus on an NSImage and using -[NSBitmapImageRep initWithFocusedViewRect:].

So, to sum up:
(1) Drawing is fast. Playing with pixels is not.
(2) If you think you need to play with pixels, (a) consider if there's a way to do it with drawing or (b) look into CoreImage.
(3) If you still want to get at the pixels, draw into a bitmap whose format you know and look at those pixels.

NSImage performance debugging: NSNewBitmapBackingStore (New since WWDC 2009)

The most fundamental rule to image performance on Mac OS X is this: If you see something drawing repeatedly on the screen, it should be drawn with the same identical image object each time.

In 10.6 there's a private function to help you notice if you aren't managing this. NSNewBitmapBackingStore is the funnel point in AppKit for making a new buffer of image data. New buffers of image data mean new images.

Thus, you don't want to see this function trip on every frame during repeated drawing situations like live resize. DTrace via Instruments is a nice way to see if this is happening. In Instruments, select "Build New Instrument…" from the Instrument menu. Fill in "AppKit" for the Library and NSNewBitmapBackingStore for the function. Now start recording in Instruments, and use your app as normal. You'll see a blip whenever the function is called. A smattering of calls is normal, but if you see it called furiously then you likely have a performance problem.

A few things to note:

(1) This is a private function. That means it won't necessarily be there in the future. You can use it to debug, but don't compile knowledge of it into your app.
(2) The goal is not to avoid seeing this function called, the goal is to make your app perform better. If you drop to Quartz level to make images, for example, you can bypass calling this function without making your app better. Rather, if you see this function being called a bunch, try to understand why new images are being created and address the cause. The other material in these release notes may help you understand.

NSBitmapImageRep notable bug fix: -[NSBitmapImageRep CGImage] safer now (New since WWDC 2008)

In Leopard, -[NSBitmapImageRep CGImage] would under most circumstances return a CGImage that was not retained by the bitmap rep, but which would cause a crash if its data was accessed (e.g., by drawing it) after the bitmap rep had been destroyed.

This is fixed in SnowLeopard.

NSBitmapImageRep: Expanded colorspace support (New since WWDC 2008)

Prior to SnowLeopard, NSBitmapImageRep supported specific colorspaces through a colorspace name property, and ICC profile data through -[NSBitmapImageRep valueForProperty:] with NSImageColorSyncProfileData property.

For SnowLeopard, we add support for working directly with colorspaces.
- (NSColorSpace *)colorSpace;
- (NSBitmapImageRep *)bitmapImageRepByConvertingToColorSpace:(NSColorSpace *)targetSpace renderingIntent:(NSColorRenderingIntent)renderingIntent;
- (NSBitmapImageRep *)bitmapImageRepByRetaggingWithColorSpace:(NSColorSpace *)newSpace;
Both -[NSBitmapImageRep bitmapImageRepByConvertingToColorSpace:renderingIntent:] and -[NSBitmapImageRep bitmapImageRepByRetaggingWithColorSpace:] may fail, in which case they will return nil. The latter definitely _will_ fail if you pass a colorspace that has a different color space model than the receiver. That is, if your original image is sRGB, you can only retag with some other RGB colorspace.

Both methods will return the original bitmap if it already has the requested colorspace.

NSComboBox (New since WWDC 2008)

For apps linked on or after SnowLeopard, if a combo box is configured to send action on enter only, then it will not send its action when a selection is made from the drop down, either with the mouse or the keyboard. Only enter in the text field part of the combo box will send the action.

NSDrawThreePartImage accepts nil caps (New since April 2009 seed)

As of 10.6, NSDrawThreePartImage can handle a nil for either the start cap or the end cap in NSDrawThreePartImage. If you pass nil for both, you'll be tiling the fill image either horizontally or vertically across the specified rect.



Support for EPS images (New since WWDC 2008)

EPS images can now be read without crashing, though images with the bounding box specified at the end of the file will probably still load with an incorrect bounding box.


Rotated PDFs in patterns (New since WWDC 2008)

PDFs with a /Rotate entry are now correctly displayed rotated when used in patterns (e.g. +[NSColor colorWithPatternImage:]).


NSPasteboard

Multiple Pasteboard Items (New since May 2009 seed)

Historically, NSPasteboard has been able to store multiple data representations of a single logical item. Each representation is data of a particular type, keyed by the type name. In SnowLeopard, NSPasteboard adds support for multiple pasteboard items. Each item represents a single logical item which can hold multiple data representations. Prior to multiple pasteboard items, plural pboard types were necessary to put multiple pieces of data onto the single logical item of the pasteboard. For example, the NSFilenamesPboardType consists of an array of file paths all combined into one serialized property list. Using multiple pasteboard items, the analogous operation would result in multiple pasteboard items, with each file URL represented by a single pasteboard item.

Interacting with NSPasteboard has always been data type-centric, centered around getting and setting data for particular types. The new NSPasteboard API also allows for higher-level class-centric operations, while still allowing type-centric interaction when necessary.

For instance, the following code writes the appropriate data from an NSAttributedString onto the general pasteboard:
    NSAttributedString *attString =...;
NSPasteboard *pboard = [NSPasteboard generalPasteboard];
[pboard clearContents];
[pboard writeObjects:[NSArray arrayWithObject:attString]];
The following code reads data from each pasteboard item and creates an NSAttributedString instance from each item that contains data an attributed string can be initialized with:
    NSPasteboard *pboard = [NSPasteboard generalPasteboard];
NSArray *desiredClasses = [NSArray arrayWithObject:[NSAttributedString class];
NSArray *attributedStrings = [pboard readObjectsForClasses:desiredClasses] options:nil];
And, for things such as menu item validation, the following code checks if at least one NSAttributedString instance can be created from the contents of the pasteboard:
    NSPasteboard *pboard = [NSPasteboard generalPasteboard];
NSArray *desiredClasses = [NSArray arrayWithObject:[NSAttributedString class];
BOOL canRead = [pboard canReadObjectForClasses:desiredClasses] options:nil];
This functionality is supported by two new protocols, NSPasteboardWriting and NSPasteboardReading. These protocols respectively allow a class to specify which data types its instances can provide to the pasteboard, and which data types its instances can be created from. The Cocoa classes NSAttributedString, NSImage, NSColor, NSURL, NSString, and NSSound implement this protocol so that common pasteboard types can be easily written and read. Other classes, such as an application's model classes, can also implement these protocols and be used in the same fashion.

See NSPasteboard.h for more information and examples of using multiple pasteboard items.

NSPasteboardItem(New since May 2009 seed)

Although the class-centric APIs are a convenient abstraction from the details of data types, there are times when it is necessary to interact with the contents of the pasteboard by data type. The NSPasteboardItem class, introduced in SnowLeopard, represents a single pasteboard item and can hold multiple data representations. The NSPasteboardItem API is very similar to the original NSPasteboard API, with facilities for getting and setting data by type, as well as adding a data provider to provide data lazily.

NSPasteboardItem implements the NSPasteboardWriting and NSPasteboardReading protocols. As such, you add pasteboard items to the pasteboard by calling -writeObjects: and you can read pasteboard items from the pasteboard by calling -readObjectsForClasses:options: and specifying the NSPasteboardItem class. As a convenience, the NSPasteboard method -pasteboardItems method will return the array of all pasteboard items. The NSPasteboard validation method -canReadItemWithDataConformingToTypes: will check if any pasteboard item contains data conforming to the specified types. This supports writing validation code without asking for and iterating through all pasteboard items.

Some cases where you may need to use a pasteboard item directly:
1. When the set of types you wish to write to the pasteboard does not map well to a particular class. For instance, you may have a custom pasteboard type which is a property list that does not map directly to a class in your application. In this case, you might create a pasteboard item, set the property list for your custom type, and then write the pasteboard item to the pasteboard.

2. When you implement a delegate method or subclass a method that receives a pasteboard. In this case the superclass or class you are the delegate of has already written to the pasteboard. In your delegate or overridden method, you might get the pasteboard items, see what data has already been provided, and then call methods on the NSPasteboardItem instances to set additional or replacement data for particular types.

3. When reading the pasteboard and the destination of the data is not an object. For instance, if your application commonly used CGImages, you might get the array of pasteboard items, and iterate through it looking for image data, getting the data for an image type, and creating the CGImages.

An NSPasteboardItem instance can be associated with a single pasteboard. When you first create a pasteboard item, it can be written to any pasteboard. When you pass in a pasteboard item to -writeObjects:, that pasteboard item becomes bound to the pasteboard it was written to. When you retrieve pasteboard items using -pasteboardItems or -readObjectsForClasses:options:, the returned pasteboard items are associated with the messaged pasteboard. Passing a pasteboard item that is already associated with a pasteboard into -writeObjects: causes an exception to be raised. Note that as long as a pasteboard item is associated with a pasteboard, all methods to set data take affect on the pasteboard.

Pasteboard items are intended to be transient objects, used during a single pasteboard interaction, not held onto and used repeatedly. A pasteboard item is only valid until the owner of the pasteboard changes. If a pasteboard item is stale because the pasteboard owner has changed, it will return nil or NO values from its methods.

NSPasteboardItem instances are created only when necessary. In the code example above, an attributed string is both written to and read from the pasteboard without an NSPasteboardItem instance being created. The class-centric approach should be used when possible, and the type-centric approach of NSPasteboardItem should be used when necessary.

See NSPasteboardItem.h for more information.

Additional NSPasteboard Notes (New since May 2009 seed)

- By historical convention, absolute URLs have always been expected on the pasteboard. The NSURL implementation of the NSPasteboardWriting protocol formalizes this by not providing types or data to be written to the pasteboard unless the URL is an absolute URL.

- In SnowLeopard, filtering pasteboards only operate and are valid on the first item on the pasteboard.

- In SnowLeopard, none of the Cocoa classes that implement NSPasteboardWriting and NSPasteboardReading write or read the types used on the NSFontPboard and NSRulerPboard pasteboards.

UTIs on the Pasteboard (New since May 2009 seed)

All NSPasteboard APIs introduced in Snow Leopard accept UTIs only and do not accept NSPboardType strings. The new APIs will accept an informally defined UTI string. This is any string which follows the naming convention for UTIs, but is not formally declared in an Info.plist. These informal UTI strings are useful for declaring pasteboard types which are for internal use within an application, since it may not be desirable to formally declare those types. If you do formally declare UTIs for use on the pasteboard, the UTIs should conform to the public.data type.

Migrating from pboard types to UTIs (New since May 2009 seed)

Use of pboard types should be replaced with the use of UTIs. Pboard types will be deprecated in a future release. For all pboard types declared in AppKit, see NSPasteboard.h for the migration path for each pboard type. In almost all cases, migration consists of substituting the pboard type constant for an analogous UTI-based constant. The main exception is the NSFilenamesPboard type, where the migration path is to use the new multiple pasteboard item API to read and write file URLs on the pasteboard. For custom pboard types, the migration path is either to create a constant that follows UTI naming conventions and use it as an undeclared informal UTI, or to formally declare that constant. See below for additional information if other applications rely on your existing custom pboard types.

Moving public pboard types to UTIs (New since May 2009 seed)

For applications that currently define a public pboard type that other applications rely on, the following is necessary to ensure that existing applications will continue to see your pboard type even after your application has moved from pboard types to UTIs:

1. Formally declare the new pasteboard type UTI as an exported type declaration.
2. Ensure the declared UTI conforms to the public.data type.
3. Add a tag specification for the 'com.apple.nspboard-type' tag to the type declaration. Note that the value you provide should be the literal string value of the pboard type, not the name of the constant. An example tag specification to associate a UTI with a pboard type:
    <key>UTTypeTagSpecification</key>
    <dict>
        <key>com.apple.nspboard-type</key>
        <string>MyCustomPboardType</string>
    </dict>

Deprecating PICTPboardType (New since WWDC 2008)

NSPICTPboardType is deprecated in SnowLeopard. The PICT format was formally deprecated in Tiger along with QuickDraw. Applications should not be explicitly providing or looking for PICT data on the pasteboard.

To aid in this deprecation, if PICT is the only image type on the pasteboard, as is sometimes the case when copying images from 32-bit Carbon applications, a translated image type will be automatically reported and provided by NSPasteboard. The translated type is added to the types array ahead of PICT so that the deprecated PICT format is not the preferred format.

Although NSPICTPboardType and its UTI equivalent kUTTypePICT will appear in a pasteboard's type array retrieved from the existing NSPasteboard API, it may cease to be reported in future releases.

Reading image types from the pasteboard (New since WWDC 2008)

Historically, TIFF has been the single commonly used pasteboard type for image data. With the introduction of NSPasteboard support of UTIs, it is possible to put image data of any format onto the pasteboard.

This means that when retrieving image data from the pasteboard that you should be certain to use the array of types returned by [NSImage imageTypes], not just the NSTIFFPboardType.

For backwards compatibility for applications linked before SnowLeopard, if we find image data UTIs on the pasteboard, but no TIFF data present, NSPasteboard will automatically promise and translate to TIFF. For applications linked on SnowLeopard, you should update your pasteboard code to look for and accept any image type, rather than just TIFF. Using the new writeObjects: / readObjectsForClasses:options: methods with NSImage will handle this automatically.

Promised data and Sudden Termination (New since March 2009 seed)

When an application promises to provide data lazily to a pasteboard, sudden termination is disabled to prevent the application from terminating without having the opportunity to provide the promised data at application quit. Sudden termination is re-enabled when either all of promised data is provided or the ownership of the pasteboard changes.

Pasteboard types that predate Mac OS X (New since March 2009 seed)

NSPasteboard no longer promises deprecated pasteboard types that predate Mac OS X, and have never been public in Mac OS X: "NeXT plain ascii pasteboard type", "NXColor pasteboard type", "NeXT filename pasteboard type", "NXTypedFilenamePboardType".

Using pbcopy and pbpaste with different encodings (New since March 2009 seed)

The command line tools pbcopy and pbpaste now use standard locale environment variables to determine the character encoding used for reading and writing string data. See man pages for details.

Accessibility

NSImage Accessibility Description

-accessibilityDescription Property

In SnowLeopard, NSImage adds an -accessibilityDescription property. The string should be a localized accessibility description. If an NSImage has an accessibility description, Cocoa interface elements that display images will report the description to accessibility. This functionality is currently supported by NSImageCell, NSButtonCell, and NSSegmentedCell.

This makes it easier for a single user interface element to report different AXDescriptions depending on which image is shown. For instance, in a chat application, different images might be used to report status such as "online", "offline", "away". Now, you can set the accessibility description for each image. As you change which image is displayed, the image cell will report the description of the currently set image.

Default accessibility description strings for named system images

In Leopard, constants were introduced in NSImage.h for named system images. In SnowLeopard, these images now have a default accessibility description, providing an additional amount of default accessibility for commonly used images.

AccessibilityImageDescriptions.strings file

In applications, most images used in the interface are named resources loaded using NSImage's +imageNamed: method. If you provide a .strings file called 'AccessibilityImageDescriptions.strings', it will be checked for an accessibility description. The keys in the .strings file are the names of the images as provided to +imageNamed:. The values are the accessibility description.

Image Description Search Path

When an image is asked for its accessibility description, if an accessibility description string has been set programmatically using -setAccessibilityDescription: that string will be returned. If no string has been set programatically, the string value for that image in the application's AccessibilityImageDescriptions.strings file, if present, will be returned. Finally, if AppKit provides a default value for the image, that value will be returned.

Additional Accessibility Description Notes

Note that calling +imageNamed: repeatedly with the same name returns the same instance of NSImage. If you change the accessibility description on a named image, the description will change everywhere that named image instance is being used. If you need different descriptions for the same image, when used in different places in the UI, use an accessibility overridden attribute to provide the description on the UI element itself.

Note also that setting an overridden AXDescription attribute on an element will override the value provided by the element itself, including the accessibility description of the displayed image.


NSMenu and NSMenuItem Accessibility


In SnowLeopard, both NSMenu and NSMenuItem support the NSAccessibilityAdditions method accessibilitySetOverrideValue:forAttribute:. The support is only for values of type NSString, and is intended to allow adding an AXDescription to a menu or menu item that contains an image instead of text.

NSLevelIndicator role changes

In SnowLeopard, NSLevelIndicator reports new accessibility roles and subroles.
The discrete and continuous capacity styles report the new NSAccessibilityLevelIndicatorRole as their role. They also report the new NSAccessibilityWarningValueAttribute and NSAccessibilityCriticalValueAttribute attributes.
The relevancy indicator style now reports the NSAccessibilityRelevanceIndicatorRole as its role.
The rating indicator style continues to report its role as a slider, but with the NSAccessibilityRatingIndicatorSubrole.

Changes in setting AXValue of a text view or text field (New since March 2009 seed)

Setting the AXValue of a text view or focused text field now behaves like the user entering text, including triggering bindings. For text fields it is recommended to set the AXFocus of the text field to true before setting its AXValue. In the future, text fields may require focus before having their value set through accessibility, to more closely mirror direct user interaction.

New outline view accessibility notifications (New since March 2009 seed)

NSOutlineView supports the new NSAccessibilityRowExpandedNotification and NSAccessibilityRowCollapsedNotification notifications. Assistive applications register to receive the notification from the outline element. The element reported with the notification is the outline row that expanded or collapsed.

Optional array attribute methods (New since May 2009 seed)

Accessibility clients such as VoiceOver have long had the ability to get a count or a subarray for any accessibility attribute whose value is an array. In addition, various internal accessibility operations rely on getting the index of an element's child. The default framework implementation for each of these operations calls -accessibilityAttributeValue: to retrieve the entire array of values, and then performs the appropriate operation. If these new methods are implemented, they will be used instead. For accessibility objects with many children, or many values in any array attribute, the results to these methods can sometimes be calculated without generating the entire array of values, which can improve performance.
/* Given an accessibility child of an object, return the index of that child in the parent.
*/
- (NSUInteger)accessibilityIndexOfChild:(id)child;
/* Return the count of an accessibility array attribute.
*/
- (NSUInteger)accessibilityArrayAttributeCount:(NSString *)attribute;
/* Return a subarray of values of an accessibility array attribute.  Note this method does not take a range.
The max count is the maximum desired number of items requested by an accessibility client.
This number may be beyond the bounds of your array.
*/
- (NSArray *)accessibilityArrayAttributeValues:(NSString *)attribute index:(NSUInteger)index maxCount:(NSUInteger)maxCount;

Miscellaneous Accessibility Changes

- NSTableView and subclasses now correctly return the selected columns to accessibility, not selected column indexes.

- For a table view with hidden columns, AXColumn now reports the correct AXIndex.

- NSProgressIndicator no longer erroneously reports an AXChildren attribute to accessibility.

- NSScroller no longer reports its AXChildren attribute twice.

- Sort buttons now correctly report their role as AXButton with AXSortButton as a subrole.

- The NSAccessibilitySortButtonRole constant has been deprecated and the NSAccessibilitySortButtonSubrole constant added.

- NSAccessibilityUnknownOrientationValue constant added to match AX API.

- Circular sliders now report their AXOrientation as AXUnknownOrientation.

- AXBusyIndicators and AXProgressIndicators now have an AXOrientation attribute. The bar style reports AXHorizontalOrientation, the spinning style reports AXUnknownOrientation.

- NSAccessibilityPlaceHolderValueAttribute added. Interface elements with placeholder strings report the value of the placeholder using this attribute.

Miscellaneous Accessibility Changes (New since March 2009 seed)

- Setting AXFrontmost to true on a Cocoa app now brings all windows to the front as happens in Carbon apps.



Text Checking (Updated since January 2009 seed)

Snow Leopard includes a new facility known as text checking, which provides a unified interface for a variety of types of checking, including spell checking, grammar checking, URL detection, smart quotes, date and address detection via Data Detectors, and others. Among other things, this facility allows for the automatic identification of the languages used in a piece of text, so that spellchecking can proceed without the user having to label text as to language.

The basic interface for this facility is available in NSSpellChecker, in the form of the methods
- (NSArray *)checkString:(NSString *)stringToCheck
range:(NSRange)range
types:(NSTextCheckingTypes)checkingTypes
options:(NSDictionary *)options
inSpellDocumentWithTag:(NSInteger)tag
orthography:(NSOrthography **)orthography
wordCount:(NSInteger *)wordCount;
- (NSInteger)requestCheckingOfString:(NSString *)stringToCheck
range:(NSRange)range
types:(NSTextCheckingTypes)checkingTypes
options:(NSDictionary *)options
inSpellDocumentWithTag:(NSInteger)tag
completionHandler:(void (^)(NSInteger seqNumber, NSArray *results, NSOrthography *orthography, NSInteger wordCount))block;
which request unified text checking for the given range of the given string. The checkingTypes should be a bitmask of checking types from the Foundation header NSTextCheckingResult.h, describing which types of checking are desired. The options dictionary allows clients to pass in options for certain types of checking. The orthography and wordCount arguments return these two attributes of the range as a whole, while the return value is an array of NSTextCheckingResult objects describing particular items found during checking and their individual ranges. The first method here invokes checking synchronously and returns results immediately; the second requests checking in the background, and returns results at some later point to a completion handler block. The completion handler block will be invoked in an arbitrary context; if completion work needs to be performed on the main thread, the client will need to arrange for that via a performSelector method or the equivalent. The return value of the second method is a monotonically increasing sequence number, which can be used to keep track of requests in flight, and which will be supplied as an argument to the completion block.

NSTextCheckingResult and NSOrthography are two new classes defined in Foundation for use with text checking. An instance of NSTextCheckingResult represents something that has been found during checking--a misspelled word, a sentence with grammatical issues, a detected URL, a straight quote to be replaced with curly quotes, and so forth. NSOrthography is a class used to describe the linguistic content of a piece of text, especially for the purposes of spelling and grammar checking. It describes (a) which scripts the text contains, (b) a dominant language and possibly other languages for each of these scripts, and (c) a dominant script and language for the text as a whole. The results of automatic language identification are described using NSOrthography. See the Foundation release notes for more details on these two classes.

NSSpellChecker has the additional methods
- (NSArray *)userPreferredLanguages;
- (BOOL)automaticallyIdentifiesLanguages;
- (void)setAutomaticallyIdentifiesLanguages:(BOOL)flag;
- (NSArray *)guessesForWordRange:(NSRange)range inString:(NSString *)string language:(NSString *)language inSpellDocumentWithTag:(NSInteger)tag;
- (NSArray *)userQuotesArrayForLanguage:(NSString *)language;
- (NSDictionary *)userReplacementsDictionary;
to facilitate the use of text checking and automatic language identification. Entries in the availableLanguages list are all available spellchecking languages in user preference order, as described in the spellchecker's info dictionary, usually language abbreviations such as en_US. The userPreferredLanguages will be a subset of the availableLanguages, as selected by the user for use with spellchecking, in preference order. If automaticallyIdentifiesLanguages is YES, then text checking will automatically use these as appropriate; otherwise, it will use the language set by setLanguage:. The older checkSpellingOfString:... and checkGrammarOfString:... methods will use the language set by setLanguage:, if they are called with a nil language argument.

There are also the following methods to support the user interface associated with text checking:
- (NSPanel *)substitutionsPanel;
- (NSViewController *)substitutionsPanelAccessoryViewController;
- (void)setSubstitutionsPanelAccessoryViewController:(NSViewController *)accessoryController;
- (void)updatePanels;
- (NSMenu *)menuForResult:(NSTextCheckingResult *)result
string:(NSString *)string
options:(NSDictionary *)options
atLocation:(NSPoint)location
inView:(NSView *)view;
along with the constants
NSString *NSTextCheckingOrthographyKey;
NSString *NSTextCheckingQuotesKey;
NSString *NSTextCheckingReplacementsKey;
NSString *NSTextCheckingReferenceDateKey;
NSString *NSTextCheckingReferenceTimeZoneKey;
NSString *NSTextCheckingDocumentURLKey;
NSString *NSTextCheckingDocumentTitleKey;
NSString *NSTextCheckingDocumentAuthorKey;
to be used as keys in the options dictionaries for the checkString:..., requestCheckingOfString:..., and menuForResult:... methods described above. All of these keys are optional.

The substitutions panel provides an interface for various auxiliary functionality associated with text checking. It may have an accessory view if an accessory view controller is set for it. The updatePanels method is one that clients should call when any of their state changes with respect to spelling, grammar, or text checking, that might affect the spelling or substitutions panel; for example, if a client changes whether one of the text checking features is turned on, it should call this method on the shared spellchecker. The menuForResult:string:options:atLocation:inView: method returns a menu containing contextual menu items suitable for certain kinds of detected results (notably date/time/address results). The string argument is optional; if supplied, it should be the string contents of the range detected by the result. The location in the view will be used if an action eventually calls for putting up a temporary window.

NSTextCheckingOrthographyKey may be used to supply an NSOrthography indicating an orthography to be used as a starting point for orthography checking, or as the orthography if orthography checking is not enabled. The value for NSTextCheckingQuotesKey should be an NSArray containing four strings to be used with NSTextCheckingTypeQuotes (opening double quote, closing double quote, opening single quote, and closing single quote in that order). The default value used if this key is not present is taken from user preferences, and may be determined via the -userQuotesArrayForLanguage: method. The value for NSTextCheckingReplacementsKey should be an NSDictionary containing replacements to be used with NSTextCheckingTypeReplacement; if this is not specified, values will be taken from user's preferences, and these default values may be obtained via the -userReplacementsDictionary method.

The NSTextCheckingReferenceDateKey, NSTextCheckingReferenceTimeZoneKey, NSTextCheckingDocumentURLKey, NSTextCheckingDocumentTitleKey, and NSTextCheckingDocumentAuthorKey keys may be used to specify metadata associated with the current document for use with NSTextCheckingTypeDate, NSTextCheckingTypeAddress, and NSTextCheckingTypeLink. NSTextCheckingReferenceDateKey can be used to supply an NSDate to be used as a referent for relative dates, and NSTextCheckingReferenceTimeZoneKey can be used to supply an NSTimeZone to be used as a referent for dates without time zones; the current date and time zone will be used if these are not specified. These keys may be used if specific information is available about the document--for example, the date and time zone of its composition, for something like an email document. NSTextCheckingDocumentURLKey can be used to specify an NSURL associated with the document, NSTextCheckingDocumentTitleKey an NSString representing a title associated with the document, and NSTextCheckingDocumentAuthorKey an NSString representing a name of an author associated with the document. These are especially useful with the -menuForResult:string:options:atLocation:inView: method, which supplies menu items appropriate for a contextual menu to be displayed for a detected item at the given location in a view.


Text Checking in NSTextView

In addition, there are methods on NSTextView to support its use of text checking.
- (void)setAutomaticDataDetectionEnabled:(BOOL)flag;
- (BOOL)isAutomaticDataDetectionEnabled;
- (void)toggleAutomaticDataDetection:(id)sender;
- (void)setAutomaticDashSubstitutionEnabled:(BOOL)flag;
- (BOOL)isAutomaticDashSubstitutionEnabled;
- (void)toggleAutomaticDashSubstitution:(id)sender;
- (void)setAutomaticTextReplacementEnabled:(BOOL)flag;
- (BOOL)isAutomaticTextReplacementEnabled;
- (void)toggleAutomaticTextReplacement:(id)sender;
- (void)setAutomaticSpellingCorrectionEnabled:(BOOL)flag;
- (BOOL)isAutomaticSpellingCorrectionEnabled;
- (void)toggleAutomaticSpellingCorrection:(id)sender;
- (NSTextCheckingTypes)enabledTextCheckingTypes;
- (void)setEnabledTextCheckingTypes:(NSTextCheckingTypes)checkingTypes;
Turning on automatic data detection enables detection of both date and address/phone number items; turning on automatic dash substitution enables automatic conversion of sequences of ASCII '-' to typographic dashes; turning on automatic text replacement enables automatic substitution of a variety of static text items based on user preferences; and turning on automatic spelling correction enables autocorrection of certain misspellings. In addition, text checking is now used for continuous spelling and grammar checking, automatic link detection, and automatic quote substitution. The -enabledTextCheckingTypes and -setEnabledTextCheckingTypes: methods allow the state of all of these forms of checking to be retrieved or set at once.
- (void)orderFrontSubstitutionsPanel:(id)sender;
- (void)checkTextInSelection:(id)sender;
- (void)checkTextInDocument:(id)sender;
The -orderFrontSubstitutionsPanel: method brings forward a panel provided by NSSpellChecker that allows control over the various enabled substitution types. For example, it provides the user the ability to use the -checkTextInSelection: and -checkTextInDocument: action methods. Ordinarily text checking occurs in the background, and results that replace text are applied only to text that has been typed by the user, but these two methods cause the currently enabled text checking types to be applied immediately to the selection or to the document, respectively, and results that replace text are applied regardless of the origin of the text.
- (void)checkTextInRange:(NSRange)range types:(NSTextCheckingTypes)checkingTypes options:(NSDictionary *)opts;
- (void)handleTextCheckingResults:(NSArray *)results
forRange:(NSRange)range
types:(NSTextCheckingTypes)checkingTypes
options:(NSDictionary *)options
orthography:(NSOrthography *)orthography
wordCount:(NSInteger)wordCount;
The checkTextInRange:types:options: and handleTextCheckingResults:forRange:orthography:wordCount: methods will be called by NSTextView as appropriate when text checking is started and when results are received, respectively. They are not intended to be called by clients, but can be overridden to observe or modify text checking behavior. The same sort of observation or modification will also be available to the delegate, using the two new NSTextView delegate methods
- (NSDictionary *)textView:(NSTextView *)view
willCheckTextInRange:(NSRange)range
options:(NSDictionary *)options
types:(NSTextCheckingTypes *)checkingTypes;
- (NSArray *)textView:(NSTextView *)view
didCheckTextInRange:(NSRange)range
types:(NSTextCheckingTypes)checkingTypes
options:(NSDictionary *)options
results:(NSArray *)results
orthography:(NSOrthography *)orthography
wordCount:(NSInteger)wordCount;
that will be called by checkTextInRange:types:options: and handleTextCheckingResults:forRange:orthography:wordCount: respectively.


Bidirectional Text (New since WWDC 2008)

Snow Leopard includes a number of new facilities to support the entry and editing of bidirectional text, such as Hebrew or Arabic. First, there is a new attributed string attribute, NSWritingDirectionAttributeName, intended to provide a higher-level alternative to the inclusion of explicit bidirectional control characters such as LRE, RLE, LRO, RLO, and PDF in text. This gives an attributed string equivalent to what in HTML would be expressed by such constructs as <span dir="ltr"></span>, <span dir="rtl"></span>, <bdo dir="ltr"></span>, and <bdo dir="rtl"></span>..

The value of this attribute should be an array of NSNumbers, each of which should have a value of 0, 1, 2, or 3, considered as consisting of either NSWritingDirectionLeftToRight (= 0) or NSWritingDirectionRightToLeft (= 1) plus one of the new constants NSTextWritingDirectionEmbedding (= 0) or NSTextWritingDirectionOverride (= 2). This array represents a sequence of nested bidirectional embeddings or overrides, in order from outermost to innermost, with 0 (NSWritingDirectionLeftToRight | NSTextWritingDirectionEmbedding) corresponding to a LRE/PDF pair in plain text or <span dir="ltr"></span> in HTML, 1 (NSWritingDirectionRightToLeft | NSTextWritingDirectionEmbedding) corresponding to a RLE/PDF pair in plain text or a <span dir="rtl"></span>, 2 (NSWritingDirectionLeftToRight | NSTextWritingDirectionOverride) corresponding to a LRO/PDF pair in plain text or <bdo dir="ltr"></span>, and 3 (NSWritingDirectionRightToLeft | NSTextWritingDirectionOverride) corresponding to a RLO/PDF pair in plain text or <bdo dir="rtl"></span> in HTML.

In general, there should be very few situations that require the use of more than one level of bidirectional embeddings or overrides, but where necessary NSWritingDirectionAttributeName will support nesting, up to the maximum nesting depth provided for by the Unicode bidirectional algorithm. To determine the value for this attribute for a given character, note all of the embeddings or overrides that should apply to that character, in the order of their nesting from outermost to innermost, and for each one add an NSNumber to the array whose value specifies the type of the embedding or override as described above.

The intent is that the new attribute should be used in preference to inserting explicit bidirectional control characters in text, whenever text is being edited, even if rich text is not being used; that is, these attributes are considered to be useful even with plain text, because of the difficulties of editing text containing explicit control characters. When the contents of a text storage are actually converted into a plain-text file format for storage or interchange, then the attribute would need to be replaced by explicit bidirectional control characters, and likewise when loading plain text into a text storage for editing, explicit bidirectional control characters would need to be replaced by suitable values of the attribute. NSTextView will do this automatically on copy and paste, and NSAttributedString on conversion to and from external formats. In some cases, NSTextView may automatically apply this attribute to text that is typed in bidirectional contexts, where this is necessary to resolve ambiguities in directionality. Users of purely left-to-right text should never encounter this attribute.

In addition, there are new action methods defined on NSResponder and implemented in NSTextView for setting the values of both NSWritingDirectionAttributeName and the existing paragraph-level base writing direction defined on NSParagraphStyle.
- (void)makeBaseWritingDirectionNatural:(id)sender;
- (void)makeBaseWritingDirectionLeftToRight:(id)sender;
- (void)makeBaseWritingDirectionRightToLeft:(id)sender;
- (void)makeTextWritingDirectionNatural:(id)sender;
- (void)makeTextWritingDirectionLeftToRight:(id)sender;
- (void)makeTextWritingDirectionRightToLeft:(id)sender;
The first three of these set the paragraph-level base writing direction on NSParagraphStyle to NSWritingDirectionNatural, NSWritingDirectionLeftToRight, or NSWritingDirectionRightToLeft respectively. The latter three of these set the new character-level NSWritingDirectionAttributeName. Specifically, makeTextWritingDirectionNatural: removes NSWritingDirectionAttributeName, and makeTextWritingDirectionLeftToRight: and makeTextWritingDirectionRightToLeft: set it to a single left-to-right or right-to-left embedding respectively. (No action methods are provided to set bidirectional overrides, or to nest embeddings or overrides.)

These action methods are intended to be used both as the targets of menu items and for key bindings. The intent is that the base writing direction methods should be the target of three menu items, and the text writing directions should be the target of three similar menu items, within the Writing Direction menu. This menu will be provided in the context menu when appropriate, and applications that are concerned with editing text should also supply it in their main menu. TextEdit has been updated to follow these guidelines. Default key bindings are also provided for these methods, but they are enabled only for users of Hebrew or Arabic, or those who have otherwise enabled a suitable preference in the Text tab of the Language & Text preferences.

The previous public action method for writing direction, -toggleBaseWritingDirection:, is no longer recommended for use, and will be formally deprecated in the future.


Additional Key Binding Methods (New since WWDC 2008)

There are four new additional key binding methods, defined on NSResponder and implemented in NSTextView,
- (void)moveToLeftEndOfLine:(id)sender;
- (void)moveToRightEndOfLine:(id)sender;
- (void)moveToLeftEndOfLineAndModifySelection:(id)sender;
- (void)moveToRightEndOfLineAndModifySelection:(id)sender;
intended for binding to cmd- and cmd-shift-left/right arrow, in order to disambiguate the former similar methods expressed in terms of the beginning and end of the line in cases of bidirectional text.

There are also a number of other key binding methods, also defined on NSResponder and implemented in NSTextView, that have been present and bound to keys for some time, but not explicitly public:
- (void)moveToBeginningOfLineAndModifySelection:(id)sender;
- (void)moveToEndOfLineAndModifySelection:(id)sender;
- (void)moveToBeginningOfParagraphAndModifySelection:(id)sender;
- (void)moveToEndOfParagraphAndModifySelection:(id)sender;
- (void)moveToEndOfDocumentAndModifySelection:(id)sender;
- (void)moveToBeginningOfDocumentAndModifySelection:(id)sender;
- (void)pageDownAndModifySelection:(id)sender;
- (void)pageUpAndModifySelection:(id)sender;
- (void)moveParagraphForwardAndModifySelection:(id)sender;
- (void)moveParagraphBackwardAndModifySelection:(id)sender;
- (void)scrollToBeginningOfDocument:(id)sender;
- (void)scrollToEndOfDocument:(id)sender;
- (void)insertSingleQuoteIgnoringSubstitution:(id)sender;
- (void)insertDoubleQuoteIgnoringSubstitution:(id)sender;
These methods have now been made public.


NSLayoutManager Methods (Updated since WWDC 2008)

NSLayoutManager now has a method
- (NSUInteger)characterIndexForPoint:(NSPoint)point
inTextContainer:(NSTextContainer *)container
fractionOfDistanceBetweenInsertionPoints:(CGFloat *)partialFraction;
analogous to glyphIndexForPoint:inTextContainer:fractionOfDistanceThroughGlyph:, but expressed in character index terms. The method returns the index of the character falling under the given point, expressed in the given container's coordinate system; if no character is under the point, the nearest character is returned, where nearest is defined according to the requirements of selection by mouse. However, this is not simply equivalent to taking the result of the corresponding glyph index method and converting it to a character index, because in some cases a single glyph represents more than one selectable character, for example an fi ligature glyph. In that case, there will be an insertion point within the glyph, and this method will return one character or the other, depending on whether the specified point lies to the left or the right of that insertion point. In general, this method will return only character indexes for which there is an insertion point. The partial fraction is a fraction of the distance from the insertion point logically before the given character to the next one, which may be either to the right or to the left depending on directionality.

In addition, there is a new method
- (void)fillBackgroundRectArray:(NSRectArray)rectArray count:(NSUInteger)rectCount forCharacterRange:(NSRange)charRange color:(NSColor *)color;
used as a primitive for rect drawing by -drawBackgroundForGlyphRange:atPoint: for actually filling rects with a particular background color, whether due to a background color attribute, a selected or marked range highlight, a block decoration, or any other rect fill needed by that method. As with -showPackedGlyphs:..., the character range and color are merely for informational purposes; the color will already be set in the graphics state. If for any reason you modify it, you must restore it before returning from this method. You should never call this method, but you might override it. The default implementation will simply fill the specified rect array. The graphics operation used for this fill is controlled by a link check; for compatibility reasons, it will be NSCompositeCopy for applications linked prior to Snow Leopard, and NSCompositeSourceOver for applications linked on Snow Leopard or later. Applications can control the operation used, or modify the drawing, by overriding this method in an NSLayoutManager subclass.


NSTextView Undo Coalescing

NSTextView now has a method
- (BOOL)isCoalescingUndo;
to go along with the previous -breakUndoCoalescing. The new method permits clients to determine when undo coalescing is in progress.


NSTextList Starting Item Number

NSTextList now has two methods
- (void)setStartingItemNumber:(NSInteger)itemNum;
- (NSInteger)startingItemNumber;
for supplying a starting item number for a given list. The default value is 1. This value will be used only for ordered lists, and ignored in other cases.


NSAttributedString Constants

The existing NSDocumentTypeDocumentAttribute and NSDocumentTypeDocumentOption express document types in terms of a set of constants particular to NSAttributedString. In Snow Leopard, there are new constants, NSFileTypeDocumentAttribute and NSFileTypeDocumentOption, that express the same information in terms of system-wide UTIs. Where these are used for output, in expressing the type of a document that has been read, both file type and document type will be provided; as input, however, when indicating the type to be written or the type to be forced on loading, the two are mutually exclusive.

NSAttributed string also has two new metadata attributes, NSManagerDocumentAttribute and NSCategoryDocumentAttribute.



NSTableView / NSOutlineView - General updates (Updated since WWDC 2008)

NSTableView and NSOutlineView now support autosizing of table columns when you double click on the resize divider that is directly to the right of a given column. By default, NSTableView iterates every row in the table, accesses a cell via preparedCellAtRow:column:, and requests the -cellSize to find the appropriate largest width to use. For performance, it is recommended that the programmer implement a new delegate method (-tableView:sizeToFitWidthOfColumn: or -outlineView:sizeToFitWidthOfColumn:) to quickly determine the size.

The indentationPerLevel property on NSOutlineView now works better for applications linked on SnowLeopard or higher. Previously, it would indent every level by indentationPerLevel -- including the items at level 0. This has the undesired side effect of indenting too much when the value was large, and not enough to show a disclosure triangle when the value was small. In SnowLeopard-linked applications, if the indentationPerLevel is greater than 0, level-0 will have a specific width that contains enough room for the disclosure triangle based on the current selectionHighlightStyle. All other levels will properly be indented by 'indentationPerLevel'.

NSTableView now has a method to correctly invalidate cells for redrawing: -reloadDataForRowIndexes:columnIndexes:. The method will effeciently redisplay only the row/columns that are actually visible.

NSTableView now supports restricting the reordering of particular columns with a new delegate method: -tableView:shouldReorderColumn:toColumn:.

For applications linked on SnowLeopard and later, -cellSizeForBounds: (and subsequently -cellSize) will return the correct width for NSTableHeaderCells. Previously, it would not return a size large enough for the sort indicator, if the associated NSTableColumn had a sortDescriptorPrototype set.

Mac OS 10.5 Leopard introduced sub-cell focusing. SnowLeopard now allows developer control over the sub-cell focusing with several methods. -shouldFocusCell:atColumn:row: can be overridden to control whether or not a cell can be focused. -focusedColumn is the particular column that has focus. Note that the focus is only shown for the -selectedRow (if available). Finally, focused cells allow clicking via the space bar, and a method is provided for developers to call or override: -performClickOnCellAtColumn:row:.

Leopard introduced custom menu highlighting when a menu is assigned to an NSTableView instance. Subclassers that override -menuForEvent: and return a new menu instance would cause NSTableView to incorrectly highlight. Previously, it would watch NSMenuDidEndTrackingNotification for just one menu, and now it watches for all menus to correct this problem. For Leopard compatibility, it is recommended that you don't create a new menu instance, and instead use the current one as shown in the DragNDropOutlineView demo application.

On Leopard, NSOutlineView's expandItem: method started allowing 'nil' as an option to expand all items from the root. Before Leopard, this would cause an assertion. If you are deploying your application on a release before Leopard, you should not use expandItem:nil, as it will assert.

NSTableViewSelectionHighlightStyle updates: There is now a highlight style that draws no highlighting at all, but still allows rows to be selected: NSTableViewSelectionHighlightStyleNone. The NSTableViewSelectionHighlightStyleSourceList has also been updated to no longer de-select all rows when clicking on empty space in the table view.

New since WWDC 2008: For applications linked on SnowLeopard or later, the NSTableHeaderCell will always draw the sort indicator on the right side, even if the alignment for the cell is set to the right side. Previously, it would draw it on the left when the alignment was set to the right.

For applications linked on SnowLeopard or later, -rowAtPoint: will correctly return -1 if the point passed is outside of the horizontal bounds of the view. Previously, only the vertical bounds was checked.

New since November seed: NSTableView now has a new draggingDestinationFeedbackStyle property. One of the NSTableViewDraggingDestinationFeedbackStyle values is acceptable for it. The NSTableViewDraggingDestinationFeedbackStyleSourceList option is appropriate for source lists, or things that appear as source lists but don't use the source list highlighting style (such as AddressBook). NSTableViewDraggingDestinationFeedbackStyleRegular is now the standard default look, which differs from Leopard by drawing a solid round-rect blue background around drop target rows. For compatibility, this style will be the default for applications that link on SnowLeopard or later. Other applications will use NSTableViewDraggingDestinationFeedbackStyleSourceList, which was the default look for Leopard. Applications that target Leopard can still get the SnowLeopard look by first doing a [tableView respondsToSelector:@selector(setDraggingDestinationFeedbackStyle:)] check before calling the method. There is also a NSTableViewDraggingDestinationFeedbackStyleNone option to show "no drop feedback". This style is appropriate for subclasses that which to control the drawing themselves and disable the default NSTableView drawing.

New since November seed: Prior to SnowLeopard, NSTableView and NSOutlineView would always attempt to enable live-resize content caching, even if a subclass overrode preservesContentDuringLiveResize and returned NO. On SnowLeopard, it now works to return NO from preservesContentDuringLiveResize to avoid live-resize image caching. Prior to SnowLeopard, one could disable it by overriding -drawRect: and doing nothing but calling [super drawRect:rect]. It is recommended to do both if your application is targeting prior releases.

New since November seed: For applications that link on SnowLeopard and higher, NSOutlineView will correctly set the "isItemExpanded:item" bit for item to YES only AFTER sending the outlineViewItemWillExpand: notification. Similarly, NSOutlineView will correctly set the "isItemExpanded:item" bit for item to NO only AFTER sending the outlineViewItemWillCollapse: notification. For applications that link against an OS prior to SnowLeopard, the bit will be incorrectly set before sending the notification.

New since November seed: It has always been incorrect to return a negative row count from NSTableView and NSOutlineView delegate methods. For applications that link on SnowLeopard and higher, returning a negative count will now assert to assist the developer in debugging such problems.

For applications linked on SnowLeopard and later, the disclosure triangle (outline cell) in an NSOutlineView will correctly be white when the row is selected. It is possible to override this behavior by implementing -willDisplayOutlineCell: to explicitly set the backgroundStyle of the outline cell to NSBackgroundStyleLight. IE:
- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell
forTableColumn:(NSTableColumn *)tableColumn item:(id)item {
// This explicitly makes the disclosure triangles always be dark
[cell setBackgroundStyle:NSBackgroundStyleLight];
}
NSTableView and NSOutlineView will automatically add attributes to plain text for the source list (NSTableViewSelectionHighlightStyleSourceList) highlight style (selectionHighlightStyle). On Leopard, these attributes were added before the backgroundStyle was set on the cell, sometimes producing incorrectly colored cells on rows that immediately followed a group-row cell. This has been fixed on SnowLeopard, and can be worked around on Leopard with the following delegate method:
- (NSCell *)outlineView:(NSOutlineView *)outlineView
dataCellForTableColumn:(NSTableColumn *)tableColumn item:(id)item {
NSCell *result = tableColumn != nil ? [tableColumn dataCell] : nil;
if (result != nil) {
[result setBackgroundStyle:NSBackgroundStyleLight];
}
return result;
}
On Leopard when you right click on a row in NSTableView that is a "group row" (ie: the column is -1, indicating it spans across all the rows), it will incorrectly call preparedCellAtColumn:row: with a column value that is not -1. This has been fixed on SnowLeopard to properly call it with -1, but applications that need to target Leoaprd will need to take this change into consideration and be prepared for the incorrect call.

NSSavePanel / NSOpenPanel - NSURL and Blocks (New since WWDC 2008)

The NSSavePanel and NSOpenPanel now have NSURL properties, delegate methods. In addition, new block-based methods are available for displaying the panels. These versions should be used instead of the non-NSURL versions, which will be deprecated in a future release. The old versions and their replacements:
    NSSavePanel:
        filename -> URL
        directory -> directoryURL
        requiredFileType -> Always the first item in allowedFileTypes

        panel:isValidFilename: -> panel:validateURL:error:
        panel:directoryDidChange: -> panel:didChangeToDirectoryURL
        panel:compareFilename:width:caseSensitive: -> Deprecated and should not be used for performance reasons
        panel:shouldShowFilename: -> panel:shouldEnableURL:

        beginSheetForDirectory:file:modalForWindow:modalDelegate:didEndSelector:contextInfo: -> beginSheetModalForWindow:completionHandler:
        runModalForDirectory:file: -> runModal

    NSOpenPanel:
        filenames -> URLS
        beginSheetForDirectory:file:types:modalForWindow:modalDelegate:didEndSelector:contextInfo: -> beginSheetModalForWindow:completionHandler:
        beginForDirectory:file:types::modelessDelegate:didEndSelector:contextInfo: -> beginSheetModalForWindow:completionHandler:
        runModalForDirectory:file:types: -> runModal
        runModalForTypes: -> runModal

You'll notice that there are now three acceptable ways to show the open or save panel:
  - (NSInteger)runModal;
- (void)beginSheetModalForWindow:(NSWindow *)window completionHandler:(void (^)(NSInteger result))handler;
- (void)beginWithCompletionHandler:(void (^)(NSInteger result))handler;
The methods no longer take a directory or initial file type. Instead, the properties can be set prior invoking the above methods. Prior to SnowLeopard, there was no way to set the initial filename; this can now be done with:
  - (NSString *)nameFieldStringValue;
- (void)setNameFieldStringValue:(NSString *)value;
Calling setNameFieldStringValue: will cause the 'value' to be processed slightly to be an acceptable file name, possibly including hiding the extension based if -isExtensionHidden is set to YES.

You'll notice that the NSOpenPanel version has no way to show the enabled "fileTypes". Applications that link on SnowLeopard can now use allowedFileTypes/setAllowedFileTypes:, which was previously not used for the NSOpenPanel. Please refer to the header comments for more information.

Example use of the new block based methods:
    // Run a modeless open panel for pdf file types:
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
openPanel.allowedFileTypes = [NSArray arrayWithObject:@"com.adobe.pdf"];
[openPanel beginWithCompletionHandler:^(NSInteger result) {
if (result) {
NSLog(@"Picked: %@", openPanel.URLs);
}
}];
    // Run a sheet modal for 'window' that allows saving as a jpeg
NSSavePanel *savePanel = [NSSavePanel savePanel];
savePanel.allowedFileTypes = [NSArray arrayWithObject:@"jpg"];
savePanel.nameFieldStringValue = @"foo.jpg";
[savePanel beginSheetModalForWindow:window completionHandler:^(NSInteger result) {
if (result) {
NSLog(@"Save as: %@", savePanel.URL);
}
}];
Compatibility notes: If a delegate implements both the old and new delegate methods, the new delegate methods will be used on SnowLeopard, while the older delegate methods will be used on older versions of the OS.

NSSavePanel / NSOpenPanel - General Updates (Updated since WWDC 2008)

The NSSavePanel and NSOpenPanel now have a keyboard shortcut to show hidden files: cmd-shift-period. Hidden files will be shown only while that instance is open.

New since WWDC 2008: Using only UTIs to enable application file types in the open panel was not working on Leopard (com.apple.application-bundle, com.apple.application-bundle, com.apple.application-file). The work around was to include the "app" extension in the enabled file types. On SnowLeopard, all the UTIs work correctly, but for applications targeting Leopard as the minimum operating system, the "app" extension should also be included.
New since WWDC 2008: The NSOpenPanel now supports Quick Look. Select any files and press the space bar to invoke Quick Look.

The list view mode for the open and save panels now allow multiple columns to be viewed. Right click on the column header to show or hide them.

The open and save panel now allows connecting to shared servers. The sidebar also now contains a SEARCH FOR section.

The save panel now respects the Finder option for "Show all file extensions". If it is set, then the "Hide Extension" checkbox will be hidden and the extension will always be shown by always returning YES from -isExtensionHidden.

New since November Seed: For applications that link on SnowLeopard and higher: NSSavePanel now tracks the accessoryView's frame. The programmer can dynamically make changes to the frame and the panel will properly layout. In addition, animated changes can be done using the animator proxy, such as: [[accessoryView animator] setFrame:frame].

NSPathControl / NSPathCell (Updated since WWDC 2008)

The NSPathCell would incorrectly call [openPanel setCanChooseDirectories:YES] when about to show the NSOpenPanel. On 10.6, it will correctly set the value to YES only if the allowedTypes contains 'public.folder' or is nil.

New since WWDC 2008: For SnowLeopard linked applications, NSPathCell will correctly return an appropriate height from - (NSSize)cellSizeForBounds:(NSRect)bounds for NSPathStyleStandard and NSPathStyleNavigationBar.

New since WWDC 2008: NSPathComponentCell (and subsequently NSPathCell and NSPathControl) no longer encodes the image property when the URL property is a file URL. Instead, it grabs the appropriate image from NSWorkspace. Previously, if the file didn't exist, the previously set images would show up. Now, the appropriate current images will be used from the file system, and if the file at URL no longer exists, it will show a generic image. You must re-save nibs on SnowLeopard for the new encoding to take effect.

New since WWDC 2008: NSPathCell will now properly highlight the NSPathComponentCell that is clicked upon when a context menu is shown. Correctly setting a menu can be done in one of two ways: set the -menu property for the NSPathCell (or the NSPathControl - it forwards the setMenu: to the cell). In the menu's delegate, one can access the clickedPathComponentCell and update the menu based on the cell that was clicked. In the menu's action, one can access the clickedPathComponentCell and process the action based on the item that was initially clicked. Alternatively, each NSPathComponentCell can have the -menu property set, and the appropriate menu will be returned from NSPathCell via -menuForEvent:inRect:ofView:. Subclasses of NSPathControl, NSPathCell, and NSPathComponentCell should not override -menuForEvent: / -menuForEvent:inRect:ofView: if they wish to opt into this behavior. Note that this behavior should only be used on applications that target SnowLeopard or higher, as it will not work properly on Leopard.

NSBrowser

NSBrowser now goes through the public methods -moveLeft: and -moveRight: when changing columns in response to a left/right keyboard arrow.

On SnowLeopard linked applications, -scrollColumnToVisible: will now always attempt to scroll the start of the column to the visible rect. Previously, it would do nothing if part of the column was already visible.

On SnowLeopard linked applications, NSBrowser will return YES from -acceptsFirstResponder, unless the browser has been set to refuse first responder status with: -[browser setRefusesFirstResponder:YES]. Previously, it would only accept first responder status if it had at least one column that accepted first responder status. This made it impossible to set an NSBrowser as the first responder in IB.

On SnowLeopard linked applications, NSBrowser will correctly accept an empty index set to selectRowIndexes:inColumn: to allow deselection of all indexes in a given column. Previously an empty index set would be ignored.


NSBrowser - Context Menu

NSBrowser now properly supports the menu property. -[NSBrowser setMenu:] is propagated to subviews of NSBrowser matrices where appropriate to ensure the menu is available at all locations. Customizing -[NSBrowser menuForEvent:] will have no effect, as the individual subviews handle the menu. If you need to customize the menu, consider using a NSMenu delegate instead.

While the contextual menu is displayed, you may call -[NSBrowser clickedRow] and -[NSBrowser clickedColumn] to determine which cell was underneath the mouse when the context menu was displayed. The return value of both these functions will be -1 if no cell was clicked.

NSBrowser - Convenience methods

In Leopard and earlier releases, the default column width of an NSBrowser was set by passing the column index -1 to -[NSBrowser setWidth:ofColumn:], and retrieved by passing -1 to -[NSBrowser widthOfColumn:]. There are now first-class methods for accessing this property: -[NSBrowser setDefaultColumnWidth:] and -[NSBrowser defaultColumnWidth].

NSBrowser - Appearance

Browsers no longer leave a white gap at the bottom right side of the scroll bar unless it is necessary to do so, such as when displaying a window resize corner.

When targeting a drop at the entire browser by setting the drop column to -1, the a highlight rectangle will be drawn around the entire control.

NSApplication - Full keyboard access

When implementing compound controls such as NSTableView, it can be useful to get the current state of full keyboard access to determine what your control’s Tab behavior should be. NSApplication now has a -isFullKeyboardAccessEnabled method which will return the current state of the setting from the Keyboard system preference pane.



Bindings and Processing KVO Notifications (Updated since WWDC 2008)

NSBindingDebugLogLevel

The Binding debug log level now recognizes values greater than 1. With the user default set to 2, Cocoa Bindings will log whenever a KVO notification gets processed. The result looks like:

    "Cocoa Bindings: <YourBoundView: 0x101ed6930> binding 'isIndeterminate' processing observer notification from object YourObservedObject 0x101ebed90 for keyPath your.observed.keyPath."


Cocoa Java (New since November Seed)

The Java runtime for running Cocoa applications has been removed in SnowLeopard.


NSColorSpace (New since WWDC 2008)

This new method returns the list of color spaces available on the system that are displayed by the color panel, in the order they are displayed in the color panel. Doesn't return arbitrary color spaces which may have been created on the fly, or spaces without user displayable names. Pass model==NSUnknownColorSpaceModel to get all color spaces. Empty array is returned if no color spaces are available for the specified model.
+ (NSArray *)availableColorSpacesWithModel;

NSColorSpace (New since November seed)

This new method returns a gray color space with 2.2 gamma. It mirrors the kCGColorSpaceGenericGrayGamma2_2 added in Quartz:
+ (NSColorSpace *)genericGamma22GrayColorSpace;

NSColor (New since November seed)

NSColors will now always properly compare isEqual: (and return the same hash) after archiving/unarchiving. Previously in some cases (and more often in 64-bit), a color would not compare isEqual: with its unarchived counterpart.

Note that the individual component values will not all compare exactly the same after unarchiving, but they should compare the same if cast to float.


64-bit Conversion

There is now an improved tool for converting Cocoa applications to 64-bit:

    /Developer/Extras/64BitConversion/ConvertCocoa64

The underlying functionality is very similar to the tops script that shipped with Leopard; however, this is a Ruby script that will run tops for you on the specified source files, and also clean up some of the unnecessary warnings that tops inserts in your code.

Use of this (or some customized variant appropriate for your needs, or just some other automated tool of your choice) is highly recommended for the first-pass bulk conversion of Cocoa sources to 64-bit. In our experience, one-by-one manual conversion attempts can lead to errors stemming from copy/paste or oversight, and automated conversions avoid these sorts of problems.


NSApplication

-userInterfaceLayoutDirection is a new NSApplication interface that returns the default layout directionality of general user interface flow for the running application. The method returns NSUserInterfaceLayoutDirectionRightToLeft when running with localizations such as Arabic or Hebrew that should have the user interface layout origin on the right edge of the coordinate system.


NSBezierPath

-cachesBezierPath and -setCachesBezierPath: methods are now officially declared to be deprecated.


NSCell (Updated since WWDC 2008)

NSCell now has -userInterfaceLayoutDirection and -setUserInterfaceLayoutDirection:. This new property describes the in-cell layout directionality. For NSCell subclasses that have multiple visual components in a single cell instance, this property should specify the directionality or flow of components.

A new NSCell method, -fieldEditorForView:, is now invoked by -[NSWindow fieldEditor:forObject:] method allowing NSCell subclasses to easily provide a custom field editor object. If -fieldEditorFoView: returns a non-nil value, it's used for the cell object editing. The default implmentation returns nil.

A new NSCell property, -usesSingleLineMode, determines the layout behavior for text cells. When -usesSingleLineMode == YES, the Cocoa Text System forces to the text in a single line by ignoring line/paragraph separators and treating wrapping line breaking modes as the clipping mode. The field editor object is expected to filter line/paragraph separator characters entering into the cell value from user actions. Also, the baseline position for the text becomes fixed.


NSFontManager

The -changeAttributes: action message is now targeted to [NSFontManager target].


NSGraphicsContext

-focusStack and -setFocusStack: methods are deprecated.
There is a new NSImageInterpolation type, NSImageInterpolationMedium, added.


NSProgressIndicator

-animationDelay, -setAnimationDelay:, and -animate: methods are deprecated.


NSSearchFieldCell (New since November seed)

All new NSSearchFieldCell instances use single-line mode. NSSearchFieldCell instances unarchived from nib files created on pre-10.6 systems with the clipping line break mode are interpreted to use single-line mode.


NSSecureTextField (New since November seed)

NSSecureTextField accepts input from various non-keyboard input sources such as Character Palette.


NSRulerView (New since January 2009 seed)

NSRulerView now layout markers from the right when attached to a right-to-left wirting direction paragraph style.


NSTextFieldCell

NSTextFieldCell now fills its background with NSCompositeSourceOver instead of NSCompositeCopy.


NSTextInputClient (New since WWDC 2008)

There is a new optional method, -drawsVerticallyForCharacterAtIndex:, that can inform the Text Input system whether the protocol conforming client renders the character at index vertically.


NSTextInputContext (New since WWDC 2008)

The new NSTextInputContext class represents the interface to the Cocoa Text Input system. It represents a state or context unique to its client object such as the key binding state, input method communication session, etc. Each NSTextInputClient compliant object (typically an NSView subclass) carries its own NSTextInputContext instance. The default implementation of -[NSView inputContext] manages an instance automatically if the view subclass conforms to the NSTextInputClient protocol.

The client object needs to interact with its NSTextInputContext in order to handle text inputs. The clients are expected to send -handleEvent: message for all key/mouse events received. The -[NSView interpretKeyEvents:] method sends the message for key events. Also, -invalidateCharacterCoordinates should be send whenever the visual location of the client changes (i.e. window frame change, view scrolling, etc).


The original Text Input system classes and protocol (New since WWDC 2008)

The original Cocoa Text Input system introduced in Mac OS X 10.0 is now deprecated. NSInputServer is replaced by the Input Method Kit framework. NSInputManager functionalities are integrated into the NSTextInputContext class. The NSTextInput protocol is replaced by the NSTextInputClient protocol introduced in Mac OS X 10.5 Leopard.

Mappings for deprecated NSInputManager methods:
+cycleToNextInputLanguage: and +cycleToNextInputServerInLanguage: are covered by more direct input source APIs such as the selectedKeyboardInputSource property.
-markedTextAbandoned: is replaced by -discardMarkedText
-handleMouseEvent: is replaced by -handleEvent:.

-markedTextSelectionChanged:client:, -wantsToInterpretAllKeystrokes, -wantsToHandleMouseEvents, and -wantsToDelayTextChangeNotifications are no longer necessary.


NSTextTab (New since January 2009 seed)

NSDecimalTabStopType tab stops returns NSNaturalTextAlignment from -alignment for applications linked against Mac OS X 10.6 SnowLeopard libraries. This allows correct decimal tab layout in right-to-left paragraph style. Applications can specify NSDecimalTabUsesNaturalAlignment == YES using NSUserDefaults to force the new behavior.


NSTokenField

The behavior for handling whitespace characters such as space, tab, etc between tokens and tokenizing characters have changed in Mac OS X 10.5 Leopard. In 10.4, those characters were silently trimmed before tokenizing. With 10.5, those characters are left untouched and included into tokens. If the whitespace trimming behavior is desirable, the delegate could implement -tokenField:representedObjectForEditingString: and perform the trimming in the method.
In order to preserve binary compatibility with Tiger, the first post-Leopard AppKit now performs the trimming unless -tokenField:representedObjectForEditingString: is implemented by its delegate or the binary is linked against pre-Leopard releases.